Skip to content

fix(codex): keep parallel_tool_calls:false on translated Responses Lite path (#11707) - #11984

Merged
diegosouzapw merged 1 commit into
release/v3.8.51from
fix/11707-codex-responses-lite-parallel-tool-calls
Aug 29, 2026
Merged

diegosouzapw merged 1 commit into
release/v3.8.51from
fix/11707-codex-responses-lite-parallel-tool-calls

Conversation

@diegosouzapw

Copy link
Copy Markdown
Owner

Closes #11707

Root cause

enforceCodexResponsesLiteParallelToolCalls() correctly forces parallel_tool_calls: false at the top of CodexExecutor.execute() when a client's request carries the X-OpenAI-Internal-Codex-Responses-Lite header. That forced value then flows into transformRequest(), which only skips its field filter (RESPONSES_API_ALLOWLIST) when body._nativeCodexPassthrough === true — i.e. only when the client's own request was detected as native OpenAI Responses-API-shaped input. Any request that reaches the codex executor via the translated path (e.g. a manually configured client sending Chat-Completions-shaped input) never gets that flag, so transformRequest() falls through to the allowlist filter, which did not include "parallel_tool_calls" — silently deleting the value that was just forced to false, right before the request is sent to chatgpt.com/backend-api/codex/responses. This reproduced the exact reported upstream rejection ("X-OpenAI-Internal-Codex-Responses-Lite requires parallel_tool_calls to be false") for every model, since the deletion was unconditional on the translated path.

Fix

Add "parallel_tool_calls" to RESPONSES_API_ALLOWLIST in open-sse/executors/codex.ts so the field survives the translated path too (it was already forwarded unfiltered on the native-passthrough path).

Regression test

New: tests/unit/executor-codex-responses-lite-translated-path.test.ts — reproduces the translated (non-_nativeCodexPassthrough) path and asserts the outbound Codex request body carries parallel_tool_calls: false. Confirmed RED against unfixed code, GREEN after the fix.

Also updated tests/unit/executor-codex.test.ts (#2608 allowlist test): it previously asserted parallel_tool_calls gets stripped alongside genuine Chat-Completions-only fields (temperature, top_p, etc.) — that assertion encoded the bug. parallel_tool_calls is a legitimate Responses API field (already forwarded on the native-passthrough path) so it must now survive the filter; the test body/assertions were aligned to that corrected contract.

Gates run (all green)

  • node --import tsx/esm --test tests/unit/executor-codex-responses-lite-translated-path.test.ts tests/unit/executor-codex.test.ts tests/unit/executor-codex-gpt56.test.ts tests/unit/executor-codex-gpt56-lite-ultra.test.ts — 55/55 pass
  • node scripts/check/check-file-size.mjs — OK
  • node scripts/check/check-complexity.mjs — OK (2672 violations, baseline 2774)
  • node scripts/check/check-cognitive-complexity.mjs — OK (1192 violations, baseline 1223)
  • node scripts/check/check-changelog-integrity.mjs — OK
  • npm run typecheck:core — clean, exit 0
  • npx eslint --suppressions-location config/quality/eslint-suppressions.json open-sse/executors/codex.ts tests/unit/executor-codex.test.ts tests/unit/executor-codex-responses-lite-translated-path.test.ts — exit 0

Diff is scoped to the allowlist fix, the new regression test, the corrected sibling assertion, and the changelog fragment.

…te path (#11707)

enforceCodexResponsesLiteParallelToolCalls() forces parallel_tool_calls:false
at the top of CodexExecutor.execute(), but transformRequest() early-returns
the body before its RESPONSES_API_ALLOWLIST field filter only when
_nativeCodexPassthrough is set. Any request that reaches the codex
executor via the translated (non-native-passthrough) path never gets that
flag, so the allowlist filter silently deleted parallel_tool_calls right
before the fetch body was sent, reproducing the reported upstream
rejection ('X-OpenAI-Internal-Codex-Responses-Lite requires
parallel_tool_calls to be false') for every model.

Add parallel_tool_calls to RESPONSES_API_ALLOWLIST so the value survives
the translated path too. Update the sibling #2608 allowlist test that
previously asserted parallel_tool_calls gets stripped like other Chat
Completions-only fields -- it is a legitimate Responses API field that
must now survive.
@diegosouzapw
diegosouzapw merged commit 71093ed into release/v3.8.51 Aug 29, 2026
20 checks passed
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…te path (diegosouzapw#11707) (diegosouzapw#11984)

enforceCodexResponsesLiteParallelToolCalls() forces parallel_tool_calls:false
at the top of CodexExecutor.execute(), but transformRequest() early-returns
the body before its RESPONSES_API_ALLOWLIST field filter only when
_nativeCodexPassthrough is set. Any request that reaches the codex
executor via the translated (non-native-passthrough) path never gets that
flag, so the allowlist filter silently deleted parallel_tool_calls right
before the fetch body was sent, reproducing the reported upstream
rejection ('X-OpenAI-Internal-Codex-Responses-Lite requires
parallel_tool_calls to be false') for every model.

Add parallel_tool_calls to RESPONSES_API_ALLOWLIST so the value survives
the translated path too. Update the sibling diegosouzapw#2608 allowlist test that
previously asserted parallel_tool_calls gets stripped like other Chat
Completions-only fields -- it is a legitimate Responses API field that
must now survive.

Co-authored-by: Markus Hartung <mail@hartmark.se>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Codex Responses Lite error persists in OmniRoute v3.8.49: parallel_tool_calls must be false BUG]

2 participants