Description
Claude Code requests routed through an openai/* model work for text-only turns, but tool calls do not round-trip through the Messages/Responses bridge. When Codex returns a function_call, the bridge drops it and Claude Code receives an empty response with stop_reason: "end_turn".
Multi-turn tool transcripts also use invalid Responses input shapes: function_call and function_call_output are nested inside message content, and assistant text is encoded as input_text.
Steps to reproduce
- Configure an OpenAI subscription account and an
openai/* model.
- Ask Claude Code to perform a task that requires a tool, such as reading a file.
- Let the request continue into the tool-result turn.
Expected behaviour
- Codex
function_call output is returned to Claude Code as an Anthropic tool_use block.
- The following
tool_result is sent back as a top-level Responses function_call_output item using the same call_id.
- Streaming and non-streaming responses preserve text/tool ordering and return
stop_reason: "tool_use" when a tool is requested.
Actual behaviour
The response mapper keeps text items only, so function calls disappear. On the next turn, the request converter nests call/result items inside message content; the Codex backend rejects that shape with HTTP 400.
Environment
- OS: macOS 26.5
- Node.js version: v26.4.0
- cc-router version: 0.6.2 (
main)
- Mode: standalone
Logs
No proxy error is emitted for the dropped response item. The invalid follow-up request is rejected by the Codex backend with HTTP 400 invalid_value.
Description
Claude Code requests routed through an
openai/*model work for text-only turns, but tool calls do not round-trip through the Messages/Responses bridge. When Codex returns afunction_call, the bridge drops it and Claude Code receives an empty response withstop_reason: "end_turn".Multi-turn tool transcripts also use invalid Responses input shapes:
function_callandfunction_call_outputare nested inside message content, and assistant text is encoded asinput_text.Steps to reproduce
openai/*model.Expected behaviour
function_calloutput is returned to Claude Code as an Anthropictool_useblock.tool_resultis sent back as a top-level Responsesfunction_call_outputitem using the samecall_id.stop_reason: "tool_use"when a tool is requested.Actual behaviour
The response mapper keeps text items only, so function calls disappear. On the next turn, the request converter nests call/result items inside message content; the Codex backend rejects that shape with HTTP 400.
Environment
main)Logs
No proxy error is emitted for the dropped response item. The invalid follow-up request is rejected by the Codex backend with HTTP 400
invalid_value.