fix(agent): match tool results on call_id||id in pre-request repair (#58168) - #58179
Merged
kshitijk4poor merged 1 commit intoJul 4, 2026
Merged
Conversation
…ousResearch#58168) repair_message_sequence Pass 1 registered only tc.get("id") when building the set of known assistant tool_call ids, then matched tool results against it by tool_call_id. In the Codex Responses format an assistant tool_call carries both id (fc_...) and a distinct call_id (call_...); a tool result's tool_call_id may be keyed on either depending on which builder produced it. Registering only id made a valid tool result whose tool_call_id matched call_id look orphaned, so the pass dropped it and left the assistant tool_call unanswered -- producing HTTP 400 on strict providers (DeepSeek, Kimi): 'Messages with role tool must be a response to a preceding message with tool_calls'. Long-running sessions that persisted such a sequence were permanently broken, re-sending the orphan every turn. Register both id and call_id for each assistant tool_call so a result matching either key is recognized, consistent with AIAgent._get_tool_call_id_static and the compressor's _sanitize_tool_pairs. Apply the same call_id||id precedence to the corrupted-args sanitizer's existing-result scan / stub insertion, which had the identical mismatch. Adds 3 regression tests covering the codex id!=call_id case (match on call_id, match on only call_id, match on id when both present).
kshitijk4poor
force-pushed
the
fix/58168-orphan-tool-compaction
branch
from
July 4, 2026 09:39
83b7dad to
12083e4
Compare
kshitijk4poor
enabled auto-merge (rebase)
July 4, 2026 09:40
This was referenced Aug 3, 2026
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.
Summary
Valid tool results are no longer dropped as false orphans by the pre-request repair pass when the assistant tool_call uses the Codex Responses
id != call_idformat — closing the HTTP 400 that permanently wedged long-running sessions (#58168).Root cause:
repair_message_sequencePass 1 built its known-id set from onlytc.get("id"), then matched tool results bytool_call_id. In Codex Responses format an assistant tool_call carries bothid(fc_...) and a distinctcall_id(call_...), and a tool result'stool_call_idmay be keyed on either depending on which builder produced it. A result keyed oncall_idlooked orphaned, so the pass dropped it — leaving the assistant tool_call unanswered and triggering, on strict providers (DeepSeek, Kimi):Messages with role 'tool' must be a response to a preceding message with 'tool_calls'. Sessions that persisted such a sequence re-sent the orphan every turn and could never recover.Changes
agent/agent_runtime_helpers.py:repair_message_sequencePass 1 now registers bothidandcall_idfor every assistant tool_call, so a tool result matching either key is recognized — consistent withAIAgent._get_tool_call_id_staticand the compressor's_sanitize_tool_pairs._sanitize_tool_call_arguments(corrupted-args repair) now uses the samecall_id || idprecedence for its existing-result scan and stub insertion — it had the identical mismatch and would insert a duplicate stub that itself became an orphan.tests/run_agent/test_message_sequence_repair.py: 3 regression tests for the codexid != call_idcase (match oncall_id; match on onlycall_id; match onidwhen both present).Validation
id=fc_1 call_id=call_1, tooltool_call_id=call_1repairs=0call_id, tool matchescall_idid+call_id, tool matchesidid==tool_call_idrepairs=0)test_message_sequence_repair,test_tool_call_args_sanitizer,test_strict_api_validation,test_provider_parity,test_context_compressor).HERMES_HOME.ruff check: clean.Fixes #58168