Skip to content

fix(proxy/openai): translate max_tokens -> max_completion_tokens on chat path#1774

Open
chopratejas wants to merge 1 commit into
mainfrom
tejas/openai-max-completion-tokens
Open

fix(proxy/openai): translate max_tokens -> max_completion_tokens on chat path#1774
chopratejas wants to merge 1 commit into
mainfrom
tejas/openai-max-completion-tokens

Conversation

@chopratejas

Copy link
Copy Markdown
Collaborator

Description

GPT-5 / o-series chat models reject the legacy max_tokensAI_APICallError: Unsupported parameter: 'max_tokens' is not supported with this model. Use 'max_completion_tokens' instead. — while gpt-4o/4.1 accept max_completion_tokens too. openai-compatible clients (opencode via @ai-sdk/openai-compatible, older SDKs) still send max_tokens, so requests for GPT-5 models fail at the proxy's OpenAI upstream. This is a blocker for any such client pointed at a GPT-5 model through Headroom.

The proxy already owns the outbound /v1/chat/completions body (it rewrites messages to compress them), so translate the token param there: rename max_tokensmax_completion_tokens when the newer form isn't already set, then drop the rejected legacy key. One-way, safe for current OpenAI models; no-op when the client already sends max_completion_tokens. The Responses path (max_output_tokens) is unaffected.

Closes #

Type of Change

  • Bug fix (non-breaking change that fixes an issue)

Changes Made

  • New _normalize_openai_max_tokens(body) helper + call in handle_openai_chat after body finalization, before upstream forward.

Testing

  • Unit tests pass (pytest)
  • Linting passes (ruff check)
  • Type checking passes (mypy headroom)
  • New tests added

Test Output

tests/test_openai_max_completion_tokens.py .... 6 passed
ruff check ... All checks passed!
mypy headroom/proxy/handlers/openai.py ... Success: no issues found

Real Behavior Proof

  • Environment: local worktree, Python 3.12.
  • Exact command / steps: reproduced live — opencode (@ai-sdk/openai-compatible → Headroom proxy) targeting gpt-5.3-chat-latest failed with Unsupported parameter: 'max_tokens' ... Use 'max_completion_tokens' in the DEBUG stream log. The shim renames the param on the outbound body.
  • Observed result: unit tests confirm the rename/drop/no-op cases.
  • Not tested: full live opencode completion (its headless run stalls for unrelated reasons in this env — separate from this param fix).

Review Readiness

  • I have performed a self-review
  • This PR is ready for human review

Additional Notes

Discovered while debugging why opencode wouldn't run through the proxy: three layered blockers — (1) missing models map in the injected provider config [PR #1716], (2) no apiKey in the injected config / HTTP path doesn't inject OPENAI_API_KEY like the WS path does, (3) this max_tokens vs max_completion_tokens mismatch. This PR addresses (3).

…hat path

GPT-5 / o-series chat models reject the legacy `max_tokens` ("Unsupported
parameter: 'max_tokens' is not supported with this model. Use
'max_completion_tokens' instead."); gpt-4o/4.1 accept `max_completion_tokens`
too. openai-compatible clients (opencode via @ai-sdk/openai-compatible, older
SDKs) still send `max_tokens`, so requests for GPT-5 models fail at the proxy's
OpenAI upstream — which is exactly what blocked a live opencode run.

The proxy already owns the outbound chat/completions body (it rewrites messages
to compress them), so translate the token param there: rename `max_tokens` ->
`max_completion_tokens` when the newer form isn't already set, then drop the
rejected legacy key. Safe one-way shim for current OpenAI models; no-op when the
client already sends max_completion_tokens. Responses path (max_output_tokens)
is unaffected.
@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

PR governance

This PR follows the template and is marked ready for human review.

@github-actions github-actions Bot added the status: ready for review Pull request body is complete and the author marked it ready for human review label Jul 3, 2026

@JerrettDavis JerrettDavis left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the chat-path shim and tests. The normalization is scoped to the outbound OpenAI chat body, preserves an explicit max_completion_tokens value, drops the unsupported legacy key, and has focused coverage for the edge cases. CI is green and this looks ready to merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: ready for review Pull request body is complete and the author marked it ready for human review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants