Skip to content

fix: drop empty tool_calls arrays on assistant messages (strict providers 400) - #82252

Closed
prateekranka wants to merge 1 commit into
NousResearch:mainfrom
prateekranka:fix/empty-tool-calls-strict-providers
Closed

fix: drop empty tool_calls arrays on assistant messages (strict providers 400)#82252
prateekranka wants to merge 1 commit into
NousResearch:mainfrom
prateekranka:fix/empty-tool-calls-strict-providers

Conversation

@prateekranka

Copy link
Copy Markdown

Problem

DeepSeek (and other strict OpenAI-compatible providers) rejects assistant messages carrying tool_calls: [] with an HTTP 400 (tool_calls must be a non-empty array or absent).

This happens in sanitize_api_messages: the pre-call sanitizer dedups duplicate tool_call_ids across assistant/tool pairs. When every tool call in a turn was a duplicate id, the dedup left tool_calls: [] on the assistant message — and the earlier sanitizer pass that drops empty arrays had already run, so the empty array reached the wire.

Fix

  • When dedup removes all calls from a message, drop the tool_calls key entirely instead of leaving [].
  • Add a final pass before send that strips any surviving tool_calls: [] on assistant messages (belt-and-braces for other paths that can produce the same shape).

Verification

Reproduced locally with DeepSeek as the primary provider: 400 on tool_calls: [] before the change; long-running sessions with duplicate-id turns proceed cleanly after. Existing sanitizer behavior for non-empty calls is unchanged.

…ders 400)

DeepSeek and other strict providers reject assistant messages carrying
tool_calls: [] as a 400 error. The pre-call sanitizer dedups duplicate
tool_call_ids; when every call in a turn was a duplicate, the result was
an empty tool_calls array that the early sanitizer pass had already run
on. Drop the key entirely in that case, and add a final pass that
removes any surviving empty tool_calls arrays before send.
@spfcraze

spfcraze commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

This was generated by AI during triage.

Summary:
This PR re-implements a fix already open in #64345 and #77377 — both change the identical kept_tcs branch of sanitize_api_messages to drop the tool_calls key when dedup removes every call — and the root cause is tracked in #74101, #64335 and #76862.

Problems:

Solution:
Link #64345 and #77377 in the description so the three open implementations of this fix are visible together.


Checked against 8c70072 — the PR head when this was written — and 2446c8b, main at the moment this comment was posted.

@alt-glitch alt-glitch added type/bug Something isn't working comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint provider/deepseek DeepSeek API P2 Medium — degraded but workaround exists sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state duplicate This issue or pull request already exists labels Aug 9, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Duplicate of #64345: both remove tool_calls after dedup empties an assistant turn, preventing strict-provider empty-array HTTP 400s.

@teknium1

Copy link
Copy Markdown
Contributor

The empty-tool_calls 400 class this PR targets is now fixed on main via #86654, which closes all three chokepoints: the sanitize_api_messages dedup pass drops the key instead of writing [] (salvaged from #64345 by @liuhao1024, earliest fix for that site), the repair_message_sequence merge pops the stale key at the source (salvaged from #77944 by @webtecnica), and ChatCompletionsTransport.convert_messages() strips empty/null tool_calls at the wire boundary (salvaged from #72591 by @TurgutKural, earliest fix for that site). Your analysis matched the merged approach — thank you for the contribution; closing in favor of the merged class fix with credit to the earliest filer per site.

@teknium1 teknium1 closed this Aug 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint duplicate This issue or pull request already exists P2 Medium — degraded but workaround exists provider/deepseek DeepSeek API sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants