Skip to content

fix(anthropic): drop thinking blocks when orphan-strip mutates an assistant turn#35855

Open
fesalfayed wants to merge 1 commit into
NousResearch:mainfrom
fesalfayed:fix/anthropic-thinking-orphan-strip-v2
Open

fix(anthropic): drop thinking blocks when orphan-strip mutates an assistant turn#35855
fesalfayed wants to merge 1 commit into
NousResearch:mainfrom
fesalfayed:fix/anthropic-thinking-orphan-strip-v2

Conversation

@fesalfayed

Copy link
Copy Markdown

What does this PR do?

Extended-thinking Claude models sign each thinking block against the full turn content. When _strip_orphaned_tool_blocks removes a tool_use whose tool_result never arrived (interrupted parallel batch, compression, truncation), the turn's content changes and the signature no longer matches. Replaying it returns a non-retryable HTTP 400:

messages.N.content.M: `thinking` or `redacted_thinking` blocks in the latest
assistant message cannot be modified. These blocks must remain as they were
in the original response.

Since the turn is rebuilt from the store every iteration, the gateway loops on it with no recovery.

_merge_consecutive_roles already drops thinking blocks for the same reason when it mutates a turn. This applies the identical treatment to the orphan-strip path: if a turn's tool_use set was trimmed, drop its thinking blocks too.

Related Issue

Fixes #35847

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

  • agent/anthropic_adapter.py_strip_orphaned_tool_blocks: when a turn's tool_use set is trimmed, drop its thinking/redacted_thinking blocks.
  • tests/agent/test_anthropic_adapter.py — test covering a partially-answered parallel tool batch.

How to Test

pytest tests/agent/test_anthropic_adapter.py -k "thinking or signature or orphan or merge" -q

Checklist

Code

  • My commit messages follow Conventional Commits
  • My PR contains only changes related to this fix
  • Tests pass
  • I've added tests for my changes
  • Tested on macOS 26.4, Python 3.11.15

Documentation & Housekeeping

  • N/A — behavior fix, no config/doc/schema changes.

…istant turn

Stripping an orphaned tool_use invalidates the thinking-block signature on
that turn (it was signed against the original content), so replaying it
returns a non-retryable HTTP 400. Drop the now-stale thinking blocks from
any turn whose tool_use set was trimmed.
@fesalfayed fesalfayed closed this May 31, 2026
@fesalfayed fesalfayed reopened this May 31, 2026
@alt-glitch alt-glitch added type/bug Something isn't working P1 High — major feature broken, no workaround comp/agent Core agent loop, run_agent.py, prompt builder provider/anthropic Anthropic native Messages API labels May 31, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Competing with #35859 (salvage by teknium1) which takes a different approach: demotes dead thinking blocks to plain text (preserving reasoning) instead of dropping them entirely. Both fix #35847.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent loop, run_agent.py, prompt builder P1 High — major feature broken, no workaround provider/anthropic Anthropic native Messages API type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: extended-thinking + interrupted parallel tool batch → non-retryable HTTP 400 crash-loop (stale thinking signature)

2 participants