Skip to content

fix(compression): dedup duplicate tool_call_ids to prevent HTTP 400 on strict providers - #60398

Closed
isheng-eqi wants to merge 3 commits into
NousResearch:mainfrom
isheng-eqi:clean/compression-dedup
Closed

isheng-eqi wants to merge 3 commits into
NousResearch:mainfrom
isheng-eqi:clean/compression-dedup

Conversation

@isheng-eqi

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes a context compression bug where duplicate tool_call_id values survive into the post-compression message list, causing strict providers (DeepSeek) to reject the API call with HTTP 400 and abort the session.

Related Issue

Fixes #58327

Type of Change

  • Bug fix

Changes Made

  • agent/context_compressor.py: Add dedup pass to _sanitize_tool_pairs() that removes duplicate tool results sharing the same tool_call_id, keeping only the last occurrence
  • tests/agent/test_context_compressor_tool_dedup.py: 6 tests covering duplicates, no-op, dedup+orphan interaction

How to Test

  1. Run a long session with many tool calls on DeepSeek
  2. Trigger context compression
  3. Verify session continues normally instead of aborting with HTTP 400

…n strict providers

After context compression, a single tool_call_id can appear in multiple
tool messages (original result survives in the tail while the summary
re-inserts a back-reference). Strict providers like DeepSeek reject this
with HTTP 400 'Duplicate value for tool_call_id', aborting the session.

Extend _sanitize_tool_pairs() with a dedup pass that keeps only the last
occurrence of each tool_call_id. Walks the message list in reverse so the
most recent result (closest to the tail) is always preserved.

Fixes NousResearch#58327
…n strict providers

After context compression, a single tool_call_id can appear in multiple
tool messages (original result survives in the tail while the summary
re-inserts a back-reference). Strict providers like DeepSeek reject this
with HTTP 400 'Duplicate value for tool_call_id', aborting the session.

Extend _sanitize_tool_pairs() with a dedup pass that keeps only the last
occurrence of each tool_call_id. Walks the message list in reverse so the
most recent result (closest to the tail) is always preserved.

Fixes NousResearch#58327
@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 sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state P2 Medium — degraded but workaround exists labels Jul 7, 2026
@teknium1

Copy link
Copy Markdown
Collaborator

Thanks for the focused compression investigation.

Automated hermes-sweeper review found this behavior is already implemented on main:

Closing as implemented on main.

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 P2 Medium — degraded but workaround exists sweeper:implemented-on-main Sweeper: behavior already present on current main sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/bug Something isn't working

Projects

None yet

3 participants