Skip to content

fix(agents): stripThoughtSignatures modifies Anthropic thinking blocks, causing API rejection #29618

@iamhitarth

Description

@iamhitarth

Bug

stripThoughtSignatures in src/agents/pi-embedded-helpers/bootstrap.ts removes thought_signature fields from content blocks for cross-provider compatibility. However, it also modifies type: "thinking" and type: "redacted_thinking" blocks by spreading them into new objects and deleting properties.

Anthropic's API requires thinking/redacted_thinking blocks in the latest assistant message to be identical to the original response. When these modified blocks are replayed in a multi-turn session, the API rejects with:

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.

Reproduction

  1. Use Anthropic provider with extended thinking enabled (e.g. claude-opus-4-5)
  2. Have a multi-turn conversation where thinking blocks are stored in the session file
  3. On a subsequent turn, sanitizeSessionHistorysanitizeSessionMessagesImagesstripThoughtSignatures modifies the thinking blocks
  4. API rejects the request

Root Cause

In stripThoughtSignatures (bootstrap.ts:64), the .map() callback processes ALL content blocks including thinking blocks. When a thinking block has a thought_signature starting with "msg_", it gets spread into a new object with the signature deleted:

const next = { ...rec };
if (stripSnake) {
  delete next.thought_signature;
}
return next;

This produces a structurally different object that Anthropic's API detects as modified.

Fix

Skip type: "thinking" and type: "redacted_thinking" blocks in stripThoughtSignatures:

const blockType = (block as { type?: unknown }).type;
if (blockType === "thinking" || blockType === "redacted_thinking") {
  return block;
}

These blocks should never have their signatures stripped since they must be preserved verbatim for Anthropic. The signature stripping is only needed for cross-provider compatibility with Google/Gemini, which doesn't use thinking/redacted_thinking block types.

Environment

  • OpenClaw v2026.2.25+
  • Anthropic provider with claude-opus-4-5
  • Discord channel sessions with extended thinking

Metadata

Metadata

Assignees

No one assigned

    Labels

    staleMarked as stale due to inactivity

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions