fix(codex): keep parallel_tool_calls:false on translated Responses Lite path (#11707) - #11984
Merged
diegosouzapw merged 1 commit intoAug 29, 2026
Conversation
…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.
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #11707
Root cause
enforceCodexResponsesLiteParallelToolCalls()correctly forcesparallel_tool_calls: falseat the top ofCodexExecutor.execute()when a client's request carries theX-OpenAI-Internal-Codex-Responses-Liteheader. That forced value then flows intotransformRequest(), which only skips its field filter (RESPONSES_API_ALLOWLIST) whenbody._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, sotransformRequest()falls through to the allowlist filter, which did not include"parallel_tool_calls"— silently deleting the value that was just forced tofalse, right before the request is sent tochatgpt.com/backend-api/codex/responses. This reproduced the exact reported upstream rejection ("X-OpenAI-Internal-Codex-Responses-Lite requiresparallel_tool_callsto be false") for every model, since the deletion was unconditional on the translated path.Fix
Add
"parallel_tool_calls"toRESPONSES_API_ALLOWLISTinopen-sse/executors/codex.tsso 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 carriesparallel_tool_calls: false. Confirmed RED against unfixed code, GREEN after the fix.Also updated
tests/unit/executor-codex.test.ts(#2608allowlist test): it previously assertedparallel_tool_callsgets stripped alongside genuine Chat-Completions-only fields (temperature, top_p, etc.) — that assertion encoded the bug.parallel_tool_callsis 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 passnode scripts/check/check-file-size.mjs— OKnode 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— OKnpm run typecheck:core— clean, exit 0npx 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 0Diff is scoped to the allowlist fix, the new regression test, the corrected sibling assertion, and the changelog fragment.