Repository navigation
fix(gateway): replay a Responses text + tool-call turn as one assistant message - #60
ScottLiao920 wants to merge 1 commit into
Conversation
…nt message A Responses history stores a model turn that has text followed by a tool call as a `message` item plus a `function_call` item. _convert_input_items_to_messages emitted two consecutive assistant chat messages for it (text only, then tool_calls only). Merge a text-only assistant message that is directly followed by an assistant message carrying only tool calls into one message (reasoning_content of both is joined). Text-only assistant messages not followed by tool calls stay separate. Adds two tests. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Liao Chang <35758766+ScottLiao920@users.noreply.github.com>
47866d2 to
d5c8c33
Compare
|
The merge only fires when the previous message has truthy content, but openai_responses.py lines 643 to 648 append an assistant message even when content is empty. A turn with an empty-text message item plus a function_call would still replay as two consecutive assistant messages after this fix. Do you see this case in practice with codex? |
|
Thanks for pointing this out. You're right: the current I did not observe that empty-message case in the real Codex run below: neither arm had a request containing an empty assistant message item. That is an observation from this sample, not a claim that Codex can never send one. This experiment validates the non-empty text + tool-call fix; it does not validate coverage of the empty-text edge case. I have now also tested this with the actual Codex CLI and this repository's native Polar gateway/converter, rather than only the separate gateway mentioned in #59:
All upstream episodes stopped after one environment action. Text + tool-call replies occurred naturally in both arms; no commentary or synthetic history was injected. The PR's six unsuccessful episodes were three action-limit failures, two context-limit failures, and one early stop. All remain in the denominator; no episode was retried or excluded. To distinguish the two cases: a tool-call-only Chat message with Setup: unmodified official Codex CLI 0.115.0, Qwen3.5-4B (revision Version caveat: I first tried 0.125.0, but its MCP tools arrived as All 20 outcomes and action counts were checked against the environment logs; CLI events/native sessions and raw request/response logs were also retained and audited. This is a small full-CLI/native-gateway pilot, not the full Polar Docker rollout orchestration or SWE-bench, so I would treat it as evidence that preserving the original message structure matters here—not a general benchmark-gain claim. |
Fixes #59.
What
_convert_input_items_to_messagesnow post-processes the converted messages: a text-only assistant message directly followed by an assistant message that carries only tool calls is merged into that message (reasoning_contentof both is joined). Text-only assistant messages not followed by tool calls stay separate.Why
See the issue: a model turn that has text followed by a tool call is stored in the Responses history as a
messageitem plus afunction_callitem, and was replayed as two consecutive assistant chat messages.Tests
Two tests added to
tests/gateway/test_transform_openai_responses.py: the merge case, and separate text-only assistant turns staying separate.Status: I could not run the repository's test suite in my environment; I checked the merge function in isolation (cases: merge, separate text-only turns, reasoning joined, tool-call message with content not merged, parallel calls merged together, idempotence). Please run the test file in CI before merging.
🤖 Generated with Claude Code