Skip to main content
The agent-server exposes an OpenAI-compatible API surface under /v1 with two endpoints:
  • POST /v1/chat/completions — the OpenAI Chat Completions protocol.
  • POST /v1/responses — the OpenAI Responses protocol.
Use this when you want an existing chat UI, IDE integration, evaluation harness, voice platform, or another agent to treat OpenHands as an OpenAI-style backend while still getting the full agent runtime behind the request.

How It Works

Both endpoints are protocol adapters over the same full OpenHands agent, not a thin wrapper around a raw LLM call. Each request:
  1. Loads the OpenHands agent configured by the named profile.
  2. Starts (or, for Chat Completions, optionally reuses) an OpenHands conversation.
  3. Runs the agent’s complete internal tool loop to completion.
  4. Returns only the final assistant text as an OpenAI-shaped response.
The mental model is “access an agent conversation as if it were a model”: you send a prompt, the agent does its work (including executing tools in its workspace), and you receive one response when it finishes. Internal tool activity is not exposed as OpenAI tool calls.

What to Configure

Most OpenAI-compatible clients ask for the same three fields: For example, a saved LLM profile named gateway_demo appears as the OpenAI model openhands_gateway_demo. Authentication maps OpenAI-style bearer tokens onto the agent-server’s existing session key mechanism. The gateway accepts the same session key in either form:
  • X-Session-API-Key: <key>
  • Authorization: Bearer <key>
Both are validated against the configured session API keys — there is no second credential system. When the server is configured without session keys, it remains unauthenticated just like the native agent-server API.

Prepare a Profile

OpenAI-compatible traffic is backed by an agent-server LLM profile. Create one with the native profile API first:
Then confirm the profile is visible to OpenAI clients:

Chat Completions (POST /v1/chat/completions)

Each request runs a full OpenHands agent to completion and returns the final assistant text in a standard Chat Completions shape. Supported request fields:
  • model — required; must be an openhands_<profile_name> exposed via GET /v1/models.
  • messages — a standard list. The last user message becomes the agent’s task; system and developer messages are folded into the agent’s system context.
  • streamtrue returns a server-sent events stream; false (default) returns a single response.
The response includes a X-OpenHands-ServerConversation-ID header. Send that header on a follow-up request to continue the same server-side OpenHands conversation instead of starting a new one.

Client Recipes

The response includes X-OpenHands-ServerConversation-ID. Save that header if you want a later request to continue the same agent conversation.

Conversation State

The Chat Completions protocol usually sends full message history on every request, but the gateway does not reconstruct agent history from prior assistant messages. Instead:
  • Omit X-OpenHands-ServerConversation-ID to start a new OpenHands conversation.
  • Read X-OpenHands-ServerConversation-ID from the response.
  • Send that header on follow-up requests to continue the same OpenHands conversation.
When reusing a conversation, send the newest user turn in messages. The server-side OpenHands conversation owns the previous agent state, tool activity, and workspace context.

Responses (POST /v1/responses)

The Responses endpoint targets the OpenAI Responses API — a better fit for agent-shaped traffic, with typed input/output items. It is stateless-first by design.

Mental Model

Every request starts a fresh OpenHands conversation and runs the full agent to completion. There is no server-side continuation handle: to carry context forward, clients replay prior input and output items into the next request’s input.
Response:
The response also carries the X-OpenHands-ServerConversation-ID header, but unlike Chat Completions you cannot pass it back to continue that conversation — the Responses surface ignores it. Use the header only to correlate the response with the underlying OpenHands conversation through the native agent-server API.

Replaying Context

To maintain context across Responses calls, replay the previous assistant output items (and any system/developer context) into the next request’s input:

How Input Is Interpreted

  • Top-level instructions and any system/developer input items become the agent’s system context.
  • The remaining input items become the agent’s user prompt. A single user item is sent as-is; multiple non-system items are wrapped in <message role="…"> tags so their roles are preserved.
  • model must be an openhands_<profile_name> exposed via GET /v1/models.

Not Supported Yet

The following OpenAI Responses features are intentionally rejected or ignored. Status codes and wording are exact.
Setting store: false (the default) is not a data-retention control. It only signals that no Responses object is retained. The backing OpenHands conversation still follows the agent-server’s normal persistence policy.

Current Limitations (Both Endpoints)

  • The response contains the final assistant text only. Internal OpenHands tool activity is not exposed as OpenAI tool calls or Responses output items.
  • OpenAI request fields the gateway does not need are either ignored or rejected intentionally by the server implementation. Declared tools and generation-tuning fields do not change agent behavior.

Ready-to-run example

examples/02_remote_agent_server/15_openai_compatible_gateway.py
You can run the example code as-is.
The model name should follow the LiteLLM convention: provider/model_name (e.g., anthropic/claude-sonnet-4-5-20250929, openai/gpt-4o). The LLM_API_KEY should be the API key for your chosen provider.
ChatGPT Plus/Pro subscribers: You can use LLM.subscription_login() to authenticate with your ChatGPT account and access Codex models without consuming API credits. See the LLM Subscriptions guide for details.