# Connect the OpenAI Agents SDK to Router One with an explicit Chat Completions model

> Markdown mirror of https://router.one/integrations/openai-agents-sdk for AI assistants and crawlers. Router One is an OpenAI-compatible LLM API gateway.
> Last updated: 2026-09-11

The OpenAI Agents SDK (the openai-agents package) runs Python agents with a built-in loop for tool calls, handoffs, guardrails, and sessions. Point its model calls at Router One and that loop keeps running in your process, while the gateway serves each model request and records a trace with cost and latency. The SDK defaults to the Responses API; this guide builds an OpenAIChatCompletionsModel on an explicit AsyncOpenAI client so any chat model ID in the catalog works, then explains when the Responses default is the better choice, why tracing must be switched off or given its own OpenAI key, and how to budget a run that makes several model requests.

## Install openai-agents and set your credentials

Use Python 3.10 or newer. In a virtual environment, install the openai-agents package; it depends on the openai client library, which is where the example imports AsyncOpenAI from. The shell example below is for macOS/Linux. Replace both placeholders before running it, using a Router One key and the exact ID of a current model that supports Chat Completions. These ROUTER_ONE_* variable names belong to the example, which reads them explicitly; the SDK's own OPENAI_API_KEY is deliberately left unset, because the SDK also uses that key to upload traces. Keep the same environment active when running the Python file.

`terminal`

```bash
python -m pip install openai-agents
export ROUTER_ONE_API_KEY="sk-your-router-one-key"
export ROUTER_ONE_MODEL_ID="<exact-model-id-from-/models>"
```

## Configure OpenAI Agents SDK to use the Router One base URL

Save this as agents_sdk_router_one.py and run python agents_sdk_router_one.py. AsyncOpenAI receives the /v1 base URL and your key, so no request depends on OPENAI_API_KEY or OPENAI_BASE_URL from the environment. OpenAIChatCompletionsModel wraps that client and selects /v1/chat/completions explicitly; the catalog model ID is passed unchanged, including any provider prefix that is part of the ID. set_tracing_disabled(True) turns off the SDK's built-in tracing, which is enabled by default and uploads traces to OpenAI's servers with an OpenAI key. Runner.run_sync runs the agent loop in a plain script; max_turns=3 caps this run at three model invocations and raises MaxTurnsExceeded beyond that. result.final_output is the plain-text reply.

`agents_sdk_router_one.py`

```python
import os

from openai import AsyncOpenAI
from agents import Agent, OpenAIChatCompletionsModel, Runner, set_tracing_disabled

# Tracing uploads to OpenAI's servers with an OpenAI key; there is none here.
set_tracing_disabled(True)

client = AsyncOpenAI(
    base_url="https://api.router.one/v1",
    api_key=os.environ["ROUTER_ONE_API_KEY"],
)
model = OpenAIChatCompletionsModel(
    model=os.environ["ROUTER_ONE_MODEL_ID"],
    openai_client=client,
)
agent = Agent(
    name="Assistant",
    instructions="Answer in one short sentence.",
    model=model,
)
result = Runner.run_sync(
    agent,
    "Reply with one short greeting.",
    max_turns=3,
)
print(result.final_output)
```

## Which SDK setting selects which endpoint

The SDK resolves string model names through its default OpenAI provider on the Responses API. On Router One that path is served natively for the currently listed GPT-family and DeepSeek IDs, while /v1/chat/completions serves every chat model in the catalog; an ID sent to an endpoint that does not serve it returns HTTP 400 invalid_request_error with the message model '<id>' must be called via … before any model is called. Match the row to how you configure the SDK, then check the endpoint on the model detail page:

| SDK setting | Endpoint or where it runs | What to verify |
| --- | --- | --- |
| OpenAIChatCompletionsModel(model=…, openai_client=client), as in the example | POST /v1/chat/completions | Any chat model ID from /models; tool calling and streaming on that ID |
| Agent(model="<id>") through the default provider, or set_default_openai_client(client) alone | POST /v1/responses (the SDK default, OpenAIResponsesModel) | The ID's detail page lists /v1/responses; other families return 400 must be called via |
| set_default_openai_api("chat_completions") with set_default_openai_client(client) or OPENAI_BASE_URL | POST /v1/chat/completions for every string model name | Disable tracing or set set_tracing_export_api_key, and pass use_for_tracing=False to set_default_openai_client; otherwise that key is used to upload traces |
| Hosted tools: WebSearchTool, FileSearchTool, CodeInterpreterTool, HostedMCPTool, ImageGenerationTool; ComputerTool as a local harness | Responses path only; the SDK documents them as built-in tools when using OpenAIResponsesModel | Responses support for the ID and the tool type on one real request; FileSearchTool needs OpenAI Vector Stores, and the gateway has no file storage API |
| previous_response_id, conversation_id | Responses only; silently dropped on Chat Completions unless OpenAIProvider(use_responses=False, strict_feature_validation=True) | Whether the ID's detail page lists /v1/responses before relying on server-side conversation state |

## Budget the run and reconcile its model requests

One run is a loop: each turn is one model invocation, and tool calls and handoffs add turns. max_turns is the SDK's loop bound (10 unless you pass a value; None disables it) and raises MaxTurnsExceeded when exceeded; it is not a billing cap, and it does not count client-side retries. Per the SDK documentation the runner does not retry model requests unless you opt in with ModelSettings(retry=...), and every attempt that reaches the gateway is its own request with its own trace and charge. Give the application a dedicated Router One key with maxSpend, then match the run in Dashboard → Logs by that key, time, exact model, and request_id, and reconcile with the gateway's recorded charges; an SDK-side usage or cost figure need not match your Router One rate. Router One serves the model requests and records their traces. Function tools (@tool / function_tool), handoffs, guardrails, sessions, and the SDK's own tracing run in your process on either path: a handoff is a tool call to the model, and a session stores history on your side; none of them is a gateway feature.

## Which model ID should OpenAI Agents SDK send?

Copy the exact model ID from /models, preserving case, hyphens, and version suffixes; do not substitute a display name. Open its detail page and match the supported API endpoints, context window, and capabilities such as tool calling to the provider and features selected in OpenAI Agents SDK. A catalog listing does not mean the client can use every feature of that model. Give each tool a dedicated API key with a maxSpend cap.

## Which API protocol is OpenAI Agents SDK using?

OpenAI-compatible describes an interface format; it does not make Chat Completions (/v1/chat/completions), Responses (/v1/responses), and Anthropic Messages (/v1/messages) interchangeable. Check the installed client version, provider configuration, and actual request path against the model detail page and API compatibility fact sheet. A successful plain-text chat does not establish support for hosted tools, conversation state, or file-editing features.

## Verify the OpenAI Agents SDK call in your request trace

Send a simple text request from OpenAI Agents SDK, then match its trace in Dashboard → Logs by time, model, and request_id: tokens, cost, latency, and status. Next, test streaming, tool calls, and multi-turn history separately. For failures, retain the actual request path, full error message, and request_id. If there is no matching log, check client configuration and connectivity before attributing the error to the gateway or upstream.

## FAQ

### Why build OpenAIChatCompletionsModel instead of passing a model name to Agent?

A model name string is resolved by the SDK's default OpenAI provider, and the SDK documentation states that it uses the Responses API by default while many other providers still do not support it. On Router One, /v1/responses is served natively for the currently listed GPT-family and DeepSeek IDs; a Claude, Gemini, or Grok ID sent there is rejected with HTTP 400 invalid_request_error, model '<id>' must be called via …, before any model is called. The explicit OpenAIChatCompletionsModel stays on /v1/chat/completions, which serves every chat model in the catalog, so the same file works for any ID you export. Keep the Responses default when your agents only use IDs whose detail page lists /v1/responses and you want that path's features, such as hosted tools; the SDK also recommends one model shape per workflow, because the two shapes support different features and tools.

### Tracing fails with a 401, or I do not want prompts uploaded anywhere. What do I set?

The SDK's tracing is enabled by default and, in the documentation's words, uploads traces to OpenAI servers using the same OpenAI API key as your model requests; the Tracing client error 401 entry in its troubleshooting section is the case of running without a platform.openai.com key, and a Router One key cannot serve that purpose. Disable tracing with set_tracing_disabled(True) as in the example, with OPENAI_AGENTS_DISABLE_TRACING=1 in the environment, or per run with RunConfig(tracing_disabled=True). If you want the OpenAI Traces dashboard anyway, give the exporter its own OpenAI key with set_tracing_export_api_key(...) and, when you register the Router One client globally, pass use_for_tracing=False to set_default_openai_client; generation spans then include request input and response output unless trace_include_sensitive_data is False. Your per-request record of model, tokens, cost, and latency is the Router One trace in Dashboard → Logs, which does not depend on this setting.

### Does the TypeScript SDK (@openai/agents) need the same changes?

Yes, and the switches have the same names. The TypeScript SDK's OpenAI provider also defaults to the Responses API: setOpenAIAPI('chat_completions') moves string model names to Chat Completions, setDefaultOpenAIClient(new OpenAI({ baseURL: 'https://api.router.one/v1', apiKey: ... })) supplies the Router One client (or pass baseURL and apiKey to OpenAIProvider), and setTracingDisabled(true) or OPENAI_AGENTS_DISABLE_TRACING=1 stops trace export, which by default uses the same OpenAI key; setTracingExportApiKey(...) gives it a separate one. Verify the same two things: the endpoint on the model detail page, and one plain request in Dashboard → Logs.

### Which models can OpenAI Agents SDK use through the gateway?

Choose a current catalog model that supports both the endpoint and the features OpenAI Agents SDK uses. Check /models and the model detail page for the exact ID, current rates, and capabilities; a family name such as GPT or Claude is not a compatibility guarantee. Seeing a model in the picker confirms discovery, so verify an actual request too.

### Models are listed, but requests fail with 400 or 404. What should I check?

Record the actual request path and error message, then check the exact model ID. A 400 can indicate invalid parameters, unsupported tools, or a model/endpoint mismatch; a 404 can indicate an incorrect path or missing resource, so it does not by itself establish that a model was retired. If the error says must be called via, use the named endpoint or select a model supported on the current endpoint. Do not add or remove /v1 or /chat/completions across all clients indiscriminately.

### Does this work from Mainland China?

Yes. The gateway is reachable from Mainland China without a VPN, and the configuration is identical to the global setup.

### How do I debug a 401/402/403/429?

Match the request and error message in Dashboard → Logs. For 401, check whether the key was sent and is valid; for 402, check wallet balance and maxSpend; for 403, check key permissions and access restrictions. For 429, distinguish request/token limits from upstream throttling using the error details. Keep the request_id and follow the error-codes reference.

## See also

- All integration guides: https://router.one/integrations
- Debug API errors in OpenAI Agents SDK: https://router.one/llm-api-error-codes
- API compatibility: endpoints and supported features: https://router.one/facts/api-compatibility.md
- Responses API setup and limits: https://router.one/codex-responses-api
- Claude Agent SDK setup: https://router.one/integrations/claude-agent-sdk
- Haystack setup: https://router.one/integrations/haystack
- OpenAI Python SDK setup: https://router.one/integrations/openai-sdk
- Tool-calling API requirements: https://router.one/llm-tool-calling
- Per-key model cost tracking: https://router.one/llm-cost-tracking
- OpenAI Agents SDK: models and non-OpenAI providers: https://openai.github.io/openai-agents-python/models/
- OpenAI Agents SDK: configuration and tracing switches: https://openai.github.io/openai-agents-python/config/
- OpenAI Agents SDK: tools: https://openai.github.io/openai-agents-python/tools/
- What the gateway layer does: https://router.one/llm-api-gateway
- OpenAI-compatible API: https://router.one/openai-compatible-api
- API docs: https://router.one/docs
- Canonical page: https://router.one/integrations/openai-agents-sdk
- Models and per-model token rates: https://router.one/models (markdown: https://router.one/models.md)
- Pricing: https://router.one/pricing
- API docs (markdown): https://router.one/docs.md
- Company facts: https://router.one/facts/company.md
