fix(apicompat): repair codex Responses<->Anthropic/ChatCompletions conversion#2916
Open
hanyunsushi wants to merge 2 commits into
Open
fix(apicompat): repair codex Responses<->Anthropic/ChatCompletions conversion#2916hanyunsushi wants to merge 2 commits into
hanyunsushi wants to merge 2 commits into
Conversation
…nversion Several bugs in the OpenAI Responses API conversion layer caused requests from codex (and other Responses clients) to fail or render blank when routed through Anthropic upstreams or chat/completions-only upstreams. Request direction (ResponsesInputItem): - Arguments/Output were typed string but clients send object/array, causing 502 (Anthropic path) or silent data loss (chat/completions path). Both are now json.RawMessage with normalization helpers. - Tools with no parameters (e.g. namespace/web_search) produced a null input_schema -> Anthropic 422. Now backfilled with an empty object schema. - web_search was emitted as the Anthropic server tool web_search_20250305, which some Anthropic-compatible upstreams do not implement (422). It is now a plain function tool. - Top-level instructions and developer-role items were dropped instead of mapped to the Anthropic system field; empty/whitespace system is omitted. - system is now emitted in array form, which some upstreams require when tools are present. - reasoning_effort 'xhigh' is normalized to 'high' for chat/completions upstreams that only accept low/medium/high. Response direction (streaming -> Responses events): - Emit response.content_part.added/done around output_text so strict clients (codex) have a content part to attach text to. - output_item.done for message items now carries the full content, and for function_call items carries call_id/name/arguments, since codex collects final output and tool calls from OutputItemDone items. - Skip empty-string content/reasoning deltas that produced ghost output_text.delta events and a blank render. Adds polymorphic/tools/system/streaming test coverage.
Contributor
|
All contributors have signed the CLA. ✅ |
…ponses path
The ChatCompletions->Responses streaming bridge emitted output_item.added and
function_call_arguments.delta per tool call but never the terminal
function_call_arguments.done / output_item.done. codex collects tool calls
from OutputItemDone items, so an unterminated tool call left it stalled with a
blank render (observed when asking mimo-v2.5-pro to e.g. open a browser).
FinalizeChatCompletionsResponsesStream now emits both terminal events with
call_id/name/arguments.
Also fixes argument duplication: a tool call whose first chunk carried both
name and arguments had its arguments counted twice (copyCall already held them
and the accumulator appended them again), producing invalid JSON like
{...}{...}. New tool-call state now starts with empty arguments.
Author
|
I have read the CLA Document and I hereby sign the CLA |
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.
Problem
When a Responses API client (e.g. codex) is routed through an Anthropic upstream or a chat/completions-only upstream, requests fail or render blank due to several bugs in the
apicompatconversion layer. Account "test connection" passes because it uses a self-constructed simple request that never exercises the Responses input parsing, masking these issues.Related: #2913
Root causes & fixes
Request direction (
ResponsesInputItem)Arguments/Outputtyped asstring— codex sendsfunction_call.argumentsas a JSON object andfunction_call_output.outputas an array. The strictstringtype causedjson.Unmarshalto fail (502 on the Anthropic path) orrawStringto silently drop the content (chat/completions path). Both are nowjson.RawMessagewith normalization helpers (normalizeResponsesArguments,extractResponsesOutputText,responsesArgumentsToChatString); reverse-direction builders wrap strings withjsonRawStringto preserve the OpenAI wire format.Tools without
parametersproduced a nullinput_schema— codexnamespacetools (MCP/agent) and bareweb_searchcarry no parameters; Anthropic 422s on a null schema. Now backfilled with an empty object schema.web_searchemitted as the Anthropic server toolweb_search_20250305— some Anthropic-compatible upstreams don't implement server tools (422). Now emitted as a plain function tool.Top-level
instructionsanddeveloper-role items were dropped — codex puts its primary system prompt ininstructions; the old code only readsystem-role items, leaving the model with no instructions and (worse) leaking developerinput_textblocks into a user message. Both now map to the Anthropic system field.Empty/whitespace system + string-form system — an empty system 422s; and a string-form system combined with tools 422s on some upstreams. System is now omitted when empty and emitted in array form (
[{"type":"text","text":...}]), which is spec-valid and what the official Claude Code client uses.reasoning_effort: "xhigh"— codex sendsxhighfor top-tier models; chat/completions upstreams only accept low/medium/high and 400 on xhigh. Now normalized tohigh.Response direction (streaming → Responses events)
Missing
response.content_part.added/.done— strict clients (codex) need a content part beforeoutput_text.delta; without it text deltas have nothing to attach to and the client renders nothing. Now emitted around the text block on both conversion paths.output_item.donelacked content/tool-call fields — codex collects the final output and tool calls fromOutputItemDoneitems, not from delta events. Message items now carry their fullcontent, and function_call items carrycall_id/name/arguments.Ghost empty deltas — some upstreams send a leading
{"content":""}chunk; emitting it produced an emptyoutput_text.deltaand a premature message item, leaving codex stuck on "thinking" with no output. Empty content/reasoning deltas are now skipped.Tests
Adds coverage for all of the above: polymorphic arguments/output (string/object/array), tool schema backfill, web_search as function tool, instructions/developer → system, empty-system omission, xhigh normalization, content_part event ordering, output_item content/tool-call fields, and empty-delta skipping. All existing
apicompattests pass;gofmt/go vetclean.