fix: prevent orphaned tool_use blocks from needsApproval tools#12914
Open
ferdousbhai wants to merge 1 commit intovercel:mainfrom
Open
fix: prevent orphaned tool_use blocks from needsApproval tools#12914ferdousbhai wants to merge 1 commit intovercel:mainfrom
ferdousbhai wants to merge 1 commit intovercel:mainfrom
Conversation
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>
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.
Summary
Fixes #10980. Also related to #12709.
When a
needsApprovaltool is approved but not yet executed,convertToModelMessagesproduces atool-callwithout a matchingtool-result. Providers like Anthropic reject these orphanedtool_useblocks with:Three interacting gaps in the tool approval pipeline:
Fix 1:
ignoreIncompleteToolCallsfilter (convert-to-model-messages.ts)Added
approval-requestedto the filter. A tool awaiting user decision is incomplete — same asinput-streamingorinput-available. This also addresses #12709 where sending a new user message while a tool is inapproval-requestedstate causes errors.Fix 2:
approval-respondedswitch case (convert-to-model-messages.ts)The switch statement at line 281 had no
approval-respondedcase — it fell through silently, producing notool-result. Now:approved: false→ emits a deniedtool-result(same pattern asoutput-denied)approved: true→ no result (execution handled bystreamText'scollectToolApprovals)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 fromMissingToolResultsError, but still sent them to the provider. Now tracksunresolvedApprovedToolCallIdsand strips them from assistant messages before serialization.How it works end-to-end
With
streamText(normal flow):convertToModelMessages→tool-call+tool-approval-response(no result)collectToolApprovals→ finds approval, executes toolresponseMessagesconvertToLanguageModelPrompt→ tool-call has matching result → kepttool_use+tool_result✓Without
streamText(custom code /generateText):convertToModelMessages→tool-call+tool-approval-response(no result)convertToLanguageModelPrompt→ tool-call has no result → strippedtool_use✓Test plan
ignoreIncompleteToolCallsfiltersapproval-requestedpartsapproval-responded+approved: falseproduces deniedtool-resultapproval-responded+approved: trueemitstool-approval-responsebut notool-resultcollect-tool-approvals.testpasses (no regressions)🤖 Generated with Claude Code