Skip to content

fix: prevent orphaned tool_use blocks from needsApproval tools#12914

Open
ferdousbhai wants to merge 1 commit intovercel:mainfrom
ferdousbhai:fix/orphaned-tool-use-blocks
Open

fix: prevent orphaned tool_use blocks from needsApproval tools#12914
ferdousbhai wants to merge 1 commit intovercel:mainfrom
ferdousbhai:fix/orphaned-tool-use-blocks

Conversation

@ferdousbhai
Copy link
Copy Markdown

Summary

Fixes #10980. Also related to #12709.

When a needsApproval tool is approved but not yet executed, convertToModelMessages produces a tool-call without a matching tool-result. Providers like Anthropic reject these orphaned tool_use blocks with:

tool_use ids were found without tool_result blocks immediately after

Three interacting gaps in the tool approval pipeline:

Fix 1: ignoreIncompleteToolCalls filter (convert-to-model-messages.ts)

Added approval-requested to the filter. A tool awaiting user decision is incomplete — same as input-streaming or input-available. This also addresses #12709 where sending a new user message while a tool is in approval-requested state causes errors.

Fix 2: approval-responded switch case (convert-to-model-messages.ts)

The switch statement at line 281 had no approval-responded case — it fell through silently, producing no tool-result. Now:

  • approved: false → emits a denied tool-result (same pattern as output-denied)
  • approved: true → no result (execution handled by streamText's collectToolApprovals)

Fix 3: Strip unresolved approved tool-calls (convert-to-language-model-prompt.ts)

For code paths that don't use streamText (e.g., generateText, custom code), approved tool-calls may never get executed. The validation already exempted these from MissingToolResultsError, but still sent them to the provider. Now tracks unresolvedApprovedToolCallIds and strips them from assistant messages before serialization.

How it works end-to-end

With streamText (normal flow):

  1. convertToModelMessagestool-call + tool-approval-response (no result)
  2. collectToolApprovals → finds approval, executes tool
  3. Tool result appended to responseMessages
  4. convertToLanguageModelPrompt → tool-call has matching result → kept
  5. Provider sees matched tool_use + tool_result

Without streamText (custom code / generateText):

  1. convertToModelMessagestool-call + tool-approval-response (no result)
  2. No execution happens
  3. convertToLanguageModelPrompt → tool-call has no result → stripped
  4. Provider doesn't see orphaned tool_use

Test plan

  • ignoreIncompleteToolCalls filters approval-requested parts
  • approval-responded + approved: false produces denied tool-result
  • approval-responded + approved: true emits tool-approval-response but no tool-result
  • Approved tool-call with no result is stripped from assistant message
  • Approved tool-call WITH result is preserved
  • Existing tests updated for new behavior (denied approvals now produce results)
  • collect-tool-approvals.test passes (no regressions)
  • All 1113 tests pass

🤖 Generated with Claude Code

When a needsApproval tool is approved but not yet executed,
convertToModelMessages produces a tool-call without a matching
tool-result. Providers like Anthropic reject these orphaned tool_use
blocks.

Three fixes:

1. ignoreIncompleteToolCalls now filters approval-requested state
   (a tool awaiting user decision is incomplete)

2. approval-responded case added to convertToModelMessages switch:
   - approved=false → emit denied tool-result (prevents orphan)
   - approved=true → no result (streamText handles execution)

3. convertToLanguageModelPrompt strips unresolved approved tool-calls
   from assistant messages before sending to the provider, preventing
   orphaned tool_use blocks in generateText and custom code paths.

Fixes vercel#10980

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@tigent tigent bot added ai/core core functions like generateText, streamText, etc. Provider utils, and provider spec. bug Something isn't working as documented labels Feb 27, 2026
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. bug Something isn't working as documented

Projects

None yet

Development

Successfully merging this pull request may close these issues.

needsApproval tools not returning a tool_result block

1 participant