Fix: Codex→chat/completions translator drops custom_tool_call (breaks Cursor ApplyPatch / any custom tool)#4079
Conversation
…nses. Mirror existing function_call handling for custom_tool_call output items and custom_tool_call_input stream events so clients receive tool_calls and finish_reason tool_calls for OpenAI custom tools like Cursor ApplyPatch. Co-authored-by: Cursor <cursoragent@cursor.com>
|
This pull request targeted The base branch has been automatically changed to |
There was a problem hiding this comment.
Code Review
This pull request introduces support for custom_tool_call alongside the existing function_call handling in the Codex-to-OpenAI response translator. It refactors the tool call processing logic into reusable helper functions (such as isCodexToolCallItemType, resolveToolCallName, and toolCallArgumentsFromCodexItem) to handle both streaming and non-streaming responses cleanly. Additionally, comprehensive unit tests have been added to verify the streaming, fallback, and non-streaming behaviors of custom tool calls. There are no review comments to address.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e1ec1e5493
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| } | ||
| case "function_call": | ||
| // Handle function call content | ||
| case "function_call", "custom_tool_call": |
There was a problem hiding this comment.
Preserve custom tool-call type across the chat round trip
When this branch exposes a custom_tool_call as a Chat Completions tool_calls[].type:"function", the next client turn has no way to indicate that the tool result belongs to a custom Responses call; the existing request translator still hard-codes every role:"tool" message to function_call_output in internal/translator/codex/openai/chat-completions/codex_openai_request.go:122-128. In the ApplyPatch/custom-tool flow, the model call is now surfaced to the client, but the result is sent back upstream as a function output instead of custom_tool_call_output, so the custom call cannot be continued correctly unless the call_id/type is preserved and used on the request side.
Useful? React with 👍 / 👎.
Summary
custom_tool_calloutput items (e.g. CursorApplyPatch/ any OpenAItype:"custom"tool).function_callstreaming path forcustom_tool_call:output_item.added/.done,custom_tool_call_input.delta/.done, and non-streamresponse.completedoutput.custom_tool_call.inputinto chat/completionstool_calls[].function.argumentsand setfinish_reason: "tool_calls"when a custom tool call is present.Context
Reproduced on v7.2.45 and v7.2.48. Standard
type:"function"tools were unaffected; only thecustom_tool_callreturn path was broken. The request translator already forwardstype:"custom"tools upstream — the model invokes them — but the response translator only handledfunction_call.Root cause: hard guards in
internal/translator/codex/openai/chat-completions/codex_openai_response.gothat returned empty chunks for anything other thanfunction_call.Test plan
go test ./internal/translator/codex/openai/chat-completions/...custom_tool_callannouncement,custom_tool_call_input.delta, suppressedoutput_item.done, andfinish_reason:"tool_calls"custom_tool_call_input.donewhen no deltas were streamedcustom_tool_callinresponse.completedoutputgo build -o cli-proxy-api ./cmd/serverMade with Cursor