fix(anthropic): degrade thinking replay before the turn is rejected - #4172
Open
probepark wants to merge 1 commit into
Open
fix(anthropic): degrade thinking replay before the turn is rejected#4172probepark wants to merge 1 commit into
probepark wants to merge 1 commit into
Conversation
probepark
force-pushed
the
fix/anthropic-unreplayable-latest-thinking
branch
from
August 10, 2026 08:43
471b8ad to
b8c00d8
Compare
probepark
force-pushed
the
fix/anthropic-unreplayable-latest-thinking
branch
2 times, most recently
from
August 10, 2026 12:54
e7b2a3a to
75c2bcb
Compare
Anthropic opens and closes a thinking block without sending any delta when it withholds reasoning. That block lands in history empty and unsigned, the message converter drops it, and the assistant turn goes back carrying only its tool_use. Anthropic checks the latest assistant message against the turn it produced and rejects the missing block, so the request dies before a token streams. The rejection was recoverable but cost a full round trip to discover. The block is inspectable locally, so the replay degrades during the first build instead. Captured production evidence: 1214 messages, 29 signed-but-empty thinking blocks forwarded intact, latest assistant turn reduced to a bare tool_use, and headroom proven not to have emptied any of them. Lore-id: 4b83fe10 Constraint: only the latest assistant turn is checked -- Anthropic validates that turn against its own output Rejected: send the hollow block back | no signature, Anthropic rejects the shape Rejected: drop thinking always | throws away valid reasoning replay on healthy turns Confidence: high Scope-risk: narrow Reversibility: easy Tested: hollow latest turn degrades, healthy latest turn preserved, older hollow turn ignored Not-tested: live long-session request against api.anthropic.com
probepark
force-pushed
the
fix/anthropic-unreplayable-latest-thinking
branch
from
August 10, 2026 13:26
75c2bcb to
4ddac2e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Detect locally that the latest assistant turn cannot replay its thinking block, and degrade the replay during the first build — instead of sending the request, being rejected, and repairing afterwards.
Why
Anthropic opens and closes a
thinkingblock with nothinking_deltaand nosignature_deltawhen it withholds reasoning. The block lands in history with empty text and no signature,convertAnthropicMessagesdrops it, and the assistant turn goes back carrying only itstool_use. Anthropic validates the latest assistant message against the turn it produced and rejects the missing block:Captured from a live rejected request (headroom
HEADROOM_DEBUG_DUMP=full):claude-opus-5,stream=true['tool_use(bash)']— no thinking blockThe rejection was already recoverable through the existing replay repair, but only after a full round trip. This makes the degradation happen before the request is sent.
Scope is deliberately the latest assistant turn only, because that is the turn Anthropic validates against its own output; an older hollow block must not cost the rest of the replay.
Testing
New
packages/ai/test/anthropic-unreplayable-thinking.test.ts:Expected 0, Received 1)Also:
bun test packages/ai/test: 2293 pass / 337 skip / 4 fail — the same 4 failures a clean checkout has (buildAnthropicAuthConfigbase URL, 3xopenai-responses cache affinity), confirmed by stashing this diffbun --cwd=packages/ai run check: biome + tsc cleanartifacts/issue-3670-anthropic-cache-eval.jsonregenerated (it pins the sha256 ofproviders/anthropic.ts)Related: #4159 stops the same rejection from recurring every turn; this one stops it from being paid at all.
GJC verdict
devbun checkpasses