Skip to content

fix(anthropic): validate thinking block requirement and prevent silent reasoning drop#12931

Open
giulio-leone wants to merge 2 commits intovercel:mainfrom
giulio-leone:fix/anthropic-thinking-tool-use-multi-step
Open

fix(anthropic): validate thinking block requirement and prevent silent reasoning drop#12931
giulio-leone wants to merge 2 commits intovercel:mainfrom
giulio-leone:fix/anthropic-thinking-tool-use-multi-step

Conversation

@giulio-leone
Copy link

Summary

Three targeted fixes for Anthropic extended thinking + multi-step tool use (#7729).

Problem

When using Anthropic models with extended thinking enabled and multi-step tool use, several failure modes exist:

  1. Cryptic API errors: If the last assistant message doesn't start with a thinking block (Anthropic API requirement), the API returns a vague error. This commonly happens when messages round-trip through the UI layer without preserving providerOptions.

  2. Silent reasoning drop: When reasoning parts lack providerOptions/signature metadata, the converter silently drops them with a generic warning — leaving developers confused about why their multi-step calls fail.

  3. Ghost reasoning parts: When sendReasoning: false is set, reasoning-start and reasoning-end events were still emitted to the UI stream (only reasoning-delta was gated), creating empty ReasoningUIPart objects on the client.

Root Cause Analysis

Through exhaustive tracing of the entire reasoning/thinking block lifecycle:

  • Streaming path: signature_deltareasoning-delta (with providerMetadata.anthropic.signature) → accumulated in stream-text.ts → toResponseMessages() → converter
  • UI round-trip: toUIMessageStreamprocess-ui-message-streamconvertToModelMessages → converter

The standard multi-step flow actually preserves signatures correctly through all layers. The issues are situational:

  • Message storage/retrieval losing providerOptions metadata
  • prepareStep slicing modifying message order
  • sendReasoning: false creating malformed UI parts

Fixes

  1. Pre-flight validation (anthropic-messages-language-model.ts): After prompt conversion, if thinking is enabled, validates that the last assistant message starts with a thinking or redacted_thinking block. Throws a clear, actionable error instead of a cryptic Anthropic API error.

  2. Improved drop warnings (convert-to-anthropic-messages-prompt.ts): Warning messages now explain the Anthropic API requirement and suggest preserving providerOptions through the message round-trip.

  3. Ghost reasoning prevention (stream-text.ts): All three reasoning events (reasoning-start, reasoning-delta, reasoning-end) are now consistently gated behind sendReasoning, preventing empty reasoning parts on the client.

Tests

  • 3 new tests for thinking block validation (enabled + text first → throw, enabled + thinking first → pass, disabled + text first → pass)
  • 1 new test for sendReasoning: false ghost reasoning prevention
  • Updated snapshot for improved warning message
  • 2 consecutive clean passes: 1980 AI tests + 314 Anthropic tests = 2294 total, 0 failures, 0 type errors

Related

Fixes #7729 (14 👍, reported by multiple users including framework contributors)

@tigent tigent bot added ai/core core functions like generateText, streamText, etc. Provider utils, and provider spec. ai/provider related to a provider package. Must be assigned together with at least one `provider/*` label ai/ui anything UI related bug Something isn't working as documented provider/anthropic labels Feb 27, 2026
@giulio-leone giulio-leone force-pushed the fix/anthropic-thinking-tool-use-multi-step branch 2 times, most recently from f8220d0 to 3978add Compare February 28, 2026 14:48
@giulio-leone
Copy link
Author

Intervention note for this PR:

Current blocker appears to be Vercel deployment authorization, not code/test correctness.

Observed pattern:

  • Vercel check fails with: "Authorization required to deploy."
  • Other checks (e.g., Socket Security / Vercel Agent Review) are passing.

Recommended unblock sequence:

  1. Complete the Vercel Git authorization flow from the failing check link.
  2. Re-run checks on this PR.
  3. If Vercel passes, this PR should move forward with normal review.

If useful, I can follow up with a PR-by-PR status sweep after authorization is completed.

@giulio-leone
Copy link
Author

This PR is ready for review — all CI checks pass, no merge conflicts, and all review threads have been resolved. Ready to merge when approved. 🚀

Giulio Leone added 2 commits March 5, 2026 21:43
…t reasoning drop

Three targeted fixes for Anthropic extended thinking + multi-step tool use:

1. **Thinking block validation**: When thinking is enabled, validate that the
   last assistant message starts with a thinking/redacted_thinking block before
   sending to the Anthropic API. Throws a clear SDK error instead of getting
   a cryptic API error.

2. **Improved drop warnings**: When reasoning parts are dropped due to missing
   providerOptions/signature metadata, the warning message now explains the
   Anthropic API requirement and suggests preserving providerOptions through
   the message round-trip.

3. **Ghost reasoning prevention**: When sendReasoning is false, reasoning-start
   and reasoning-end events are now properly suppressed (previously only
   reasoning-delta was gated), preventing empty ReasoningUIPart objects on
   the client.

Fixes vercel#7729
@giulio-leone giulio-leone force-pushed the fix/anthropic-thinking-tool-use-multi-step branch from 3978add to abd5e80 Compare March 5, 2026 20:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai/core core functions like generateText, streamText, etc. Provider utils, and provider spec. ai/provider related to a provider package. Must be assigned together with at least one `provider/*` label ai/ui anything UI related bug Something isn't working as documented provider/anthropic

Projects

None yet

Development

Successfully merging this pull request may close these issues.

claude sonnet 4 extended thinking requires thinking block on final message

1 participant