Custom baseURL + Responses API sends max_output_tokens unconditionally, breaking OpenAI-compatible gateways

Open 💬 1 comment Opened Jul 5, 2026 by its-How

Summary

Configuring a custom provider with @ai-sdk/openai and a custom baseURL that targets the Responses API path causes 400 Bad Request: Unsupported parameter: max_output_tokens on some OpenAI-compatible gateways. The same gateway works when using @ai-sdk/openai-compatible (chat-completions path, max_tokens) and when using Codex CLI's native wire_api = "responses" provider configuration, suggesting Codex's own request construction omits the problematic field.

Environment

  • opencode version: 1.15.10
  • provider npm: @ai-sdk/openai
  • model: gpt-5.5
  • OS: (observed across platforms)
  • Install method: npx opencode@latest / bundled runtime
  • Relevant config: custom provider block with "npm": "@ai-sdk/openai", "options": { "baseURL": "<custom-openai-compatible-gateway>/v1", "apiKey": "..." }, and a model entry such as "gpt-5.5": { "name": "GPT-5.5" }

Repository Decision

  • Target repository: openai/codex
  • Why this belongs there: The user-visible failure occurs when an external provider (@ai-sdk/openai) is wired into the execution path used by Codex-based tooling. Codex CLI's own wire_api = "responses" implementation demonstrates that a gateway-compatible request body is possible (it does not serialize max_output_tokens). The requested fix is for the Codex provider contract / custom-provider configuration to support Responses-API-style custom gateways without unconditionally emitting max_output_tokens, either by omitting the field, by allowing the chat-completions path, or by exposing a provider option to send max_tokens instead.
  • LazyCodex evidence (runtime + $LAZYCODEX_SOURCE_ROOT/lazycodex-source):
  • src/src/plugin/chat-params.ts (lines 169–183): the harness normalizes and always emits a positive maxOutputTokens value as part of chat parameters.
  • src/src/shared/session-prompt-params-helpers.ts (line 28): maxOutputTokens is forwarded into the prompt request body when model.maxTokens is set.
  • tests/hashline/headless.ts (line 6): LazyCodex/OmO code uses @ai-sdk/openai-compatible (createOpenAICompatible) for chat-completions-style integrations, which sends max_tokens rather than max_output_tokens.
  • Upstream Codex source evidence from $LAZYCODEX_SOURCE_ROOT/openai-codex-source:
  • codex-rs/codex-api/src/common.rs (lines 198–220): the native ResponsesApiRequest struct has no max_output_tokens field, so Codex CLI's own Responses-API request body never includes it.
  • codex-rs/core/src/client.rs (lines 812–892): build_responses_request constructs the request without assigning any output-token limit field.
  • sdk/typescript/tests/testCodex.ts (lines 26–31, 66–71) and codex-rs/mcp-server/tests/suite/codex_tool.rs (lines 515–520): Codex CLI supports custom providers via model_providers.<id>.base_url + wire_api = "responses", and that native path works with the same gateway.

Reproduction

  1. Configure a custom provider with:

``json
{
"provider": {
"my-gateway": {
"npm": "@ai-sdk/openai",
"options": {
"baseURL": "<custom-openai-compatible-gateway>/v1",
"apiKey": "..."
},
"models": {
"gpt-5.5": { "name": "GPT-5.5" }
}
}
}
}
``

  1. Run opencode run --model my-gateway/gpt-5.5 'hello'.
  2. Observe a 400 Bad Request response whose error text includes Unsupported parameter: max_output_tokens.

Expected Behavior

Custom baseURL + Responses API should either work out of the box with gateways that only accept the OpenAI Responses API subset, or be configurable to send max_tokens instead of max_output_tokens for gateways that do not support the latter.

Actual Behavior

The request fails with 400 Bad Request because max_output_tokens is sent unconditionally by the @ai-sdk/openai Responses-API code path.

Evidence

  • Source inspection of openai-codex-source/codex-rs/codex-api/src/common.rs shows the native ResponsesApiRequest body lacks max_output_tokens, matching the observed behavior that Codex CLI's wire_api = "responses" works against the gateway.
  • Source inspection of lazycodex-source/src/src/plugin/chat-params.ts and lazycodex-source/src/src/shared/session-prompt-params-helpers.ts shows the LazyCodex/OmO harness always materializes maxOutputTokens into the request, which downstream Vercel AI SDK provider code maps to max_output_tokens for the Responses API.
  • Runtime reproduction was performed with the steps above against an OpenAI-compatible gateway at <custom-openai-compatible-gateway>; the gateway returned 400 Unsupported parameter: max_output_tokens. The gateway accepted the identical model via @ai-sdk/openai-compatible (chat completions, max_tokens) and via Codex CLI's native wire_api = "responses" TOML provider block.

Root Cause

The @ai-sdk/openai Responses-API implementation serializes max_output_tokens unconditionally when an output-token limit is supplied. Some OpenAI-compatible gateways implement only the chat-completions-style max_tokens field (or omit both) and therefore reject the request. Codex CLI's native wire_api = "responses" path avoids this by not sending any output-token limit field at all, but Codex-based configurations that route through @ai-sdk/openai inherit the Vercel SDK behavior and cannot currently override it.

Proposed Fix

Introduce a Codex-side provider option (for example under model_providers.<id> or in the npm-provider wrapper) that:

  1. Omits max_output_tokens from the Responses API request body when the provider is flagged as an OpenAI-compatible gateway, or
  2. Allows the provider to use the chat-completions path (max_tokens) instead of the Responses API path for custom baseURL configurations, or
  3. Exposes a per-provider toggle such as use_max_tokens: true that the request builder consults before serializing the output-token limit.

Likely files / components to touch:

  • codex-rs/model-provider-info or codex-rs/core/src/client.rs for native provider request construction.
  • The TypeScript SDK's provider wrapping layer (sdk/typescript/src/exec.ts and related config plumbing) if the custom npm provider path is handled there.
  • Config schema in codex-rs/config/src/profile_toml.rs / codex-rs/config/src/thread_config/remote.rs to accept the new option.

Verification Plan

  • [ ] Configure a custom provider with @ai-sdk/openai and a custom baseURL pointing to a mock OpenAI-compatible gateway that rejects max_output_tokens; confirm the request fails before the fix.
  • [ ] Apply the fix and confirm the same mock gateway receives a request without max_output_tokens (or with max_tokens when using the chat-completions path) and returns a successful response.
  • [ ] Regression check: ensure native OpenAI wire_api = "responses" providers continue to work unchanged.
  • [ ] Regression check: ensure @ai-sdk/openai-compatible chat-completions providers continue to work unchanged.

---
This issue or PR was generated by LazyCodex.
Tag: lazycodex-generated

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗