fix(agent): drop tool_calls key when dedup removes every call - #67933
fix(agent): drop tool_calls key when dedup removes every call#67933LiangYang666 wants to merge 1 commit into
Conversation
sanitize_api_messages Step 3 deduplicates tool_call_ids across the
message sequence. When every tool_call in an assistant turn had already
been seen, the code assigned tool_calls: [] to the assistant message.
Strict OpenAI-compatible providers such as Alibaba Qwen reject empty
tool_calls arrays with:
Empty tool_calls is not supported in message.
Drop the key entirely instead of leaving an empty array. Add a regression
test covering cross-assistant duplicate tool_call_id deduplication.
|
Thanks for triaging @alt-glitch — noted that #64345 targets the same bug. A few points that may help with prioritization:
Happy to rebase or adjust if the maintainers prefer a different approach, but given that v0.18.2 is affected and Qwen is a commonly used model family, getting this regression fixed quickly would help a lot of users. |
|
@alt-glitch @teknium1 — could you please reconsider the priority of this regression? This is not a niche edge case. Since #58327 shipped in v2026.7.7 / v0.18.2, every user running Qwen models through Alibaba Cloud (and other strict OpenAI-compatible providers) can hit a deterministic HTTP 400 once the conversation contains a repeated tool_call_id:
Once the bad message is in the session, every subsequent turn fails until the session is reset. We are seeing this in production right now on qwen3.7-max. Given the impact surface — Qwen is one of the most commonly used model families, especially in Asia-Pacific deployments — I would respectfully suggest raising this from P2 to P1. The fix is a one-line defensive change (drop the key instead of writing an empty array), and this PR is a minimal, clean patch ready to merge. If the team prefers to land #64345 instead, that is fine, but please prioritize getting either fix into main and the next release. The current v0.18.2 release is effectively broken for Qwen tool-calling sessions. |
|
Thanks for the focused regression fix. The premise is confirmed on current main: Automated hermes-sweeper review. |
|
Re-verified against current main (dd600d1, 2026-08-02) since the sweeper's line refs have drifted.
Green-light: minimal, correct, ready to merge as-is. #64345 covers the same dedup branch; consolidating on this one keeps the patch focused. |
|
Rebase resolution for the GitHub-reported conflict (verified against current main 75901a2, 2026-08-03): The conflict is test-file placement only — the source change merges cleanly. On current main, To rebase:
Verification on the rebased form: |
Summary
sanitize_api_messages()Step 3 (tool_call_id deduplication, added in #58327) can leave an assistant message withtool_calls: []when every tool_call in that turn is a duplicate of an already-seen id. Strict OpenAI-compatible providers such as Alibaba Cloud Qwen reject the empty array with:This PR drops the
tool_callskey entirely in that case.Root cause
Commit
dba585c17/ PR #58327 introduced cross-message deduplication oftool_call_idto satisfy DeepSeek's strict duplicate-id validation. The dedup loop buildskept_tcsand, when its length differs from the original list, unconditionally assigns:If all tool_calls in the assistant turn were duplicates,
kept_tcs == [], so the message ends up withtool_calls: []. Step 1 of the same sanitizer already drops pre-existing empty arrays, but it runs before Step 3, so it cannot catch arrays produced by deduplication.Reproduction
A session where a later assistant turn re-uses a previously-seen
tool_call_id(e.g. retry, crash-resume, or context compression re-emitting a call) hits the bug:Before this PR the second assistant message becomes
{..., "tool_calls": []}; after this PR thetool_callskey is removed.Fix
In
agent/agent_runtime_helpers.py, when deduplication changed the tool_calls list but none survived, delete the key instead of assigning an empty list:Test
Added
test_sanitize_dedup_across_assistants_drops_empty_tool_callsintests/run_agent/test_message_sequence_repair.pyto cover the cross-assistant duplicate-id case.uv run pytest tests/run_agent/test_message_sequence_repair.py -q→ 38 passed.Affected versions
Bug introduced in
v2026.7.7by #58327 and present inv2026.7.7.2(v0.18.2). Earlier releases such asv2026.7.1are not affected.Related