Skip to content

fix: drop thinking blocks for Anthropic to prevent session corruption#27142

Closed
slatem wants to merge 1 commit intoopenclaw:mainfrom
slatem:fix/drop-thinking-blocks-anthropic
Closed

fix: drop thinking blocks for Anthropic to prevent session corruption#27142
slatem wants to merge 1 commit intoopenclaw:mainfrom
slatem:fix/drop-thinking-blocks-anthropic

Conversation

@slatem
Copy link
Copy Markdown

@slatem slatem commented Feb 26, 2026

Problem

When extended thinking is enabled (thinking=low/high) on Anthropic models, session compaction or gateway restart can modify thinking/redacted_thinking blocks in the stored transcript. Anthropic's API requires these blocks to be byte-for-byte identical to the original response — any modification causes a permanent 400 invalid_request_error:

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

The session is bricked until /reset, losing all conversation context.

Root Cause

resolveTranscriptPolicy in src/agents/transcript-policy.ts only enables dropThinkingBlocks for GitHub Copilot Claude endpoints. For Anthropic's own API (anthropic-messages) and Bedrock (bedrock-converse-stream), thinking blocks are preserved in the transcript but can get corrupted during compaction or session reconstruction.

Fix

Enable dropThinkingBlocks for all Anthropic-compatible providers (isAnthropic), not just GitHub Copilot Claude. Anthropic's API accepts omitted thinking blocks — it only rejects modified ones. This is the minimal, safe fix:

- const dropThinkingBlocks = isCopilotClaude;
+ const dropThinkingBlocks = isAnthropic || isCopilotClaude;

Trade-off

The model loses thinking context from prior assistant turns. This is minor — thinking blocks are internal reasoning and don't significantly affect multi-turn coherence. The alternative (sessions permanently bricking) is far worse.

Tests

Added 5 new test cases covering:

  • Anthropic provider → dropThinkingBlocks: true
  • Bedrock Anthropic → dropThinkingBlocks: true
  • GitHub Copilot Claude → dropThinkingBlocks: true (existing behavior preserved)
  • OpenAI → dropThinkingBlocks: false
  • Google → dropThinkingBlocks: false

All 12 tests pass.

Fixes #19524
Fixes #25194

@openclaw-barnacle openclaw-barnacle bot added agents Agent runtime and tooling size: S labels Feb 26, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Feb 26, 2026

Greptile Summary

Fixes critical session corruption bug in Anthropic models by extending dropThinkingBlocks to all Anthropic-compatible providers.

  • Root cause: Anthropic's API requires thinking/redacted_thinking blocks to be byte-for-byte identical to original response; session compaction or gateway restart can modify these blocks, causing permanent 400 errors that brick the session
  • Fix: Changed dropThinkingBlocks = isCopilotClaude to dropThinkingBlocks = isAnthropic || isCopilotClaude in src/agents/transcript-policy.ts:108
  • Coverage: Applies to anthropic-messages API, bedrock-converse-stream API, and GitHub Copilot Claude
  • Trade-off: Model loses thinking context from prior assistant turns, but this is acceptable since Anthropic accepts omitted thinking blocks (only rejects modified ones)
  • Tests: Added 5 new test cases covering Anthropic, Bedrock, GitHub Copilot Claude, and negative tests for OpenAI/Google

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The fix is minimal (one line change), addresses a critical bug (permanent session corruption), reuses existing proven functionality (dropThinkingBlocks), includes comprehensive test coverage (5 new tests for positive and negative cases), and is well-documented with clear comments explaining the issue and solution. The change is defensive and does not affect other providers (OpenAI, Google, etc.).
  • No files require special attention

Last reviewed commit: d3035de

The Anthropic API rejects `thinking` and `redacted_thinking` blocks in
historical assistant messages when those blocks have been modified from
the original response (e.g. after session serialization round-trips).

Changes:
- Enable dropThinkingBlocks for Anthropic (was only Copilot Claude)
- Also strip `redacted_thinking` blocks (was only `thinking`)
- Add test coverage for redacted_thinking block handling
@slatem slatem force-pushed the fix/drop-thinking-blocks-anthropic branch from 9b76595 to 804fa2f Compare March 4, 2026 00:52
Copy link
Copy Markdown
Contributor

@xiaoyaner0201 xiaoyaner0201 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Duplicate PR Group: Anthropic Thinking Block Compaction

This PR is one of 7 open PRs addressing the same issue: Anthropic thinking/redacted_thinking blocks from older assistant messages cause API errors during context compaction.

Related PRs

PR Author Date Approach Preserves latest redacted_thinking Compaction path Tests Clean diff
#24261 @Vaibhavee89 02-23 Guard functions + logging N/A (no actual strip) Detect only Medium
#25381 @Nipurn123 02-24 Modify dropThinkingBlocks skip latest Good ❌ (bundles sendDice)
#27142 @slatem 02-26 Extend dropThinkingBlocks to Anthropic ❌ (strips all) Limited
#39919 @taw0002 03-08 New strip function in sanitizeSessionHistory Good
#39940 @liangruochong44-ui 03-08 Policy flag for Anthropic ❌ (strips all) Medium ❌ (bundles cron/SQLite/UI)
#43783 @coletoncodes 03-12 New stripThinkingFromNonLatestAssistant + compact path Best
#44650 @rikisann 03-13 Runtime monkey-patch of node_modules None ⚠️ Fragile approach

Analysis

After reading all 7 diffs:

#43783 is the strongest candidate. It:

  1. Creates a standalone stripThinkingFromNonLatestAssistant() without changing dropThinkingBlocks semantics (preserves Copilot behavior)
  2. Integrates via existing policy.preserveSignatures flag (proper transcript policy mechanism)
  3. Only PR that also fixes the compaction path (compact.ts) — others only fix sanitizeSessionHistory
  4. Handles both thinking and redacted_thinking block types
  5. Clean diff with comprehensive tests (toolResult interleaving, empty blocks, reference equality)

#39919 is a close second (same core function, clean diff, good tests) but misses the compaction path.

Notable discovery from #44650: sanitizeSurrogates may corrupt thinking block signatures — worth investigating separately even though the monkey-patch approach is not viable.

Not recommended: #27142 and #39940 strip thinking from ALL messages including latest (breaks multi-turn quality). #25381 and #39940 bundle unrelated changes.

Similarities identified via embedding-based clustering (cosine > 0.82). Maintainers: #43783 appears ready for review.

@openclaw-barnacle
Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle bot added the stale Marked as stale due to inactivity label Mar 30, 2026
@openclaw-barnacle
Copy link
Copy Markdown

Closing due to inactivity.
If you believe this PR should be revived, post in #pr-thunderdome-dangerzone on Discord to talk to a maintainer.
That channel is the escape hatch for high-quality PRs that get auto-closed.

@openclaw-barnacle openclaw-barnacle bot closed this Apr 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling size: S stale Marked as stale due to inactivity

Projects

None yet

2 participants