fix(console): emit complete Responses-API SSE lifecycle for converted streams - #40210
fix(console): emit complete Responses-API SSE lifecycle for converted streams#40210Yuxin-Qiao wants to merge 2 commits into
Conversation
|
Thanks for working on this! I am a Codex CLI user with an OpenCode Go subscription, and I am hitting exactly the failure described in #40171: with This fix looks like exactly what the gateway needs: completing the SSE lifecycle for the chat-to-responses conversion that is already happening. It would unblock a lot of Codex users on OpenCode Go, and I would be happy to test it end-to-end once it is merged. One heads-up: the issue-compliance bot flagged that the PR description is missing the required template sections and said it would auto-close within 2 hours unless updated. @Yuxin-Qiao, could you fill in the PR description template so this stays open while it waits for review? Maintainers, this one would be great to prioritize if you have a moment. |
|
Thanks for updating your PR! It now meets our contributing guidelines. 👍 |
|
Thanks for the heads-up and the offer to test! I updated the PR description to follow the template, and the bot confirmed it now meets the contributing guidelines. Appreciate the context on how the missing lifecycle events break Codex CLI turns end to end. |
|
Just pushed a second fix to this branch (3189c93): the gateway was mapping every tool in the request - including Codex's |
Issue for this PR
Closes #40171
Type of change
What does this PR do?
Two gateway fixes for the Zen/Go
/v1/responsesendpoint when the upstream speaks chat completions (oa-compat):Complete Responses-API SSE lifecycle. The stream converter only emitted
response.output_text.deltaandresponse.completed, so Responses-API clients (e.g. the Codex CLI) never sawresponse.created,response.in_progress,response.output_item.added,response.content_part.addedorresponse.output_item.doneand could not complete a turn. The converter is now stateful (createToOpenaiChunk) and emits the full sequence in order:created->in_progress->output_item.added(message) ->content_part.added->output_text.delta->output_item.done(with accumulated text) ->completed(withoutput,stop_reason,usage). Tool-call streams additionally getfunction_call_arguments.doneandoutput_item.done.Drop unsupported tool types when converting to chat completions. Codex always sends a
web_searchtool;toOaCompatibleRequestmapped every tool into{"type":"function","function":{...}}, producing an undefinednamethat upstream serde rejects withtools[N].function: missing field "name", 400ing the whole request. Non-function tools are now filtered out (chat-completions upstreams have no equivalent), and function tools keep their nestedfunction.name.Verified live before the fix:
deepseek-v4-flashonzen/go/v1streamed onlyoutput_text.delta->completed->[DONE]->ping;deepseek-v4-flash-freeonzen/v1rejects aweb_searchtool with the serde error above. Note that the paid tier has since been switched server-side to DeepSeek's native/v1/responses(full lifecycle observed live on 2026-08-05), but the free tier and any remaining oa-compat-backed models still hit both issues.How did you verify your code works?
packages/console/app/test/openaiResponsesStream.test.ts: text-stream lifecycle ordering with a singleresponse.created, accumulated text inoutput_item.done/completed, tool-call lifecycle (function_call_arguments.done,output_item.done), stream with no visible text,[DONE]passthrough.packages/console/app/test/openaiCompatibleRequest.test.ts:web_searchdropped while function tools are kept with their nested name, chat-completions tools pass through, no-tools staysundefined.Screenshots / recordings
N/A (server-side gateway change).
Checklist