Summary
With the model router pointed at anthropic/claude-opus-4-8 and adaptive extended thinking, multi-turn conversations backed by Memory fail on the Anthropic API with a 400:
messages.1.content.8: `thinking` or `redacted_thinking` blocks in the latest assistant message
cannot be modified. These blocks must remain as they were in the original response.
(invalid_request_error, HTTP 400, from AnthropicMessagesLanguageModel.doStream)
Root cause (observed)
When a prior assistant turn is replayed from Memory on a follow-up request, its thinking blocks are sent back with an empty thinking text but the original signature retained:
{ "type": "thinking", "thinking": "", "signature": "EtcDCmMIDhgC…<truncated>==" }
Anthropic re-validates the signature against the (now empty) text and rejects the block as "modified". This only triggers on a continuation — a follow-up message into a thread that already contains a signed-thinking assistant turn. Fresh single-shot runs are fine.
Versions
@mastra/core 1.37.0
@mastra/memory 1.20.0 (PostgresStore via @mastra/pg)
ai 6.0.x
- model:
anthropic/claude-opus-4-8 (model router)
providerOptions.anthropic: { thinking: { type: "adaptive" }, effort: "high" } → serialized to thinking: { type: "adaptive" } + output_config: { effort: "high" }
Repro
Agent with Memory (Postgres), tools enabled, and the adaptive-thinking provider options above on claude-opus-4-8.
- Run a turn that produces thinking + tool calls; let it complete and persist to the thread.
- Send a follow-up message in the same thread.
- The next request 400s as above.
Notes
Expected
Persisted Anthropic thinking blocks should round-trip verbatim (text and signature), or be safely stripped from completed prior turns before send so the signature/text invariant can't break.
Summary
With the model router pointed at
anthropic/claude-opus-4-8and adaptive extended thinking, multi-turn conversations backed byMemoryfail on the Anthropic API with a 400:(
invalid_request_error, HTTP 400, fromAnthropicMessagesLanguageModel.doStream)Root cause (observed)
When a prior assistant turn is replayed from Memory on a follow-up request, its thinking blocks are sent back with an empty
thinkingtext but the originalsignatureretained:{ "type": "thinking", "thinking": "", "signature": "EtcDCmMIDhgC…<truncated>==" }Anthropic re-validates the signature against the (now empty) text and rejects the block as "modified". This only triggers on a continuation — a follow-up message into a thread that already contains a signed-thinking assistant turn. Fresh single-shot runs are fine.
Versions
@mastra/core1.37.0@mastra/memory1.20.0 (PostgresStore via@mastra/pg)ai6.0.xanthropic/claude-opus-4-8(model router)providerOptions.anthropic:{ thinking: { type: "adaptive" }, effort: "high" }→ serialized tothinking: { type: "adaptive" }+output_config: { effort: "high" }Repro
AgentwithMemory(Postgres), tools enabled, and the adaptive-thinking provider options above onclaude-opus-4-8.Notes
claude-opus-4-6withthinking: { type: "enabled", budgetTokens: 10000 }does not reproduce — multi-turn works fine. The regression appeared only after switching model + thinking mode to 4.8/adaptive.thoughtSignatureround-trip fixes (fix(core): preserve providerMetadata on assistant file parts for Gemini round-trips #14972, fix(core): forward providerMetadata on tool-call events in generate-to-stream #14900), but for Anthropic-native thinking signatures:ProviderHistoryCompatpreserves the block, but the reasoning text is dropped on persist→replay while the signature is kept.opus-4-8/ adaptive thinking in any changelog through1.38.0-alpha.6.Expected
Persisted Anthropic thinking blocks should round-trip verbatim (text and signature), or be safely stripped from completed prior turns before send so the signature/text invariant can't break.