Conversation
The pre-API sanitizer's tool_call_id dedup pass wrote `tool_calls: []` back onto an assistant message whose calls were all duplicates of ids seen earlier in the transcript (crash/resume glitch or a compression window re-emitting a tool result). Strict OpenAI-compatible providers (DeepSeek) reject an empty array with HTTP 400 "Invalid 'messages[N].tool_calls': empty array" and the request falls through the fallback chain. Drop the key entirely instead — same semantics as the empty-array pass from NousResearch#58755.
Contributor
Duplicate of #64345: it implements the same all-deduped tool_calls cleanup in sanitize_api_messages, with the same strict-provider empty-array failure mechanism. |
Author
|
Closing as redundant: upstream's general empty/invalid tool_calls sanitizer (agent/agent_runtime_helpers.py, follow-up to #58755) covers this case class — it drops the tool_calls key for any empty or non-list value, including the dedup-empties case this PR addressed. Verified present in v0.20.0. Thanks for reviewing. |
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.
Why
Long-lived Hermes sessions intermittently 400 on strict providers (DeepSeek):
The pre-API sanitizer (
sanitize_api_messages) dropstool_calls: []onassistant messages (#58755), but its own tool_call_id dedup pass can
re-create it: when an assistant message's calls are ALL duplicates of ids
already seen earlier in the transcript (crash/resume glitch, retry, or a
compression window re-emitting a tool result),
kept_tcsends up empty andthe pass writes
msg["tool_calls"] = []back onto the message — after theempty-array pass already ran.
DeepSeek rejects the empty array outright, the request fails, and because
the fallback chain's first leg resolves to the same backend, the failure
falls through to the next provider. The poisoned session 400s the same way
every subsequent turn.
Fix
When dedup empties the array, drop the
tool_callskey entirely — the samesemantics the empty-array pass already applies (empty array ≡ no tool
calls):
The pre-existing empty-array case still cleans up as before; healthy
transcripts are untouched; partial dedup keeps the surviving (first)
calls.
Test
tests/run_agent/test_sanitize_dedup_empty_tool_calls.py— 3 tests:[](this one fails on the old code)
Verified:
scripts/run_tests.sh tests/run_agent/test_sanitize_dedup_empty_tool_calls.py tests/run_agent/test_message_sequence_repair.py tests/run_agent/test_tool_call_args_sanitizer.py tests/run_agent/test_thinking_only_sanitizer.py -q— all pass.