Skip to content

fix(ai): fix providerExecuted tool approvals being passed to language model twice#14289

Merged
felixarntz merged 2 commits intomainfrom
fa/fix-double-provider-executed-tool-approvals
Apr 10, 2026
Merged

fix(ai): fix providerExecuted tool approvals being passed to language model twice#14289
felixarntz merged 2 commits intomainfrom
fa/fix-double-provider-executed-tool-approvals

Conversation

@felixarntz
Copy link
Copy Markdown
Collaborator

@felixarntz felixarntz commented Apr 9, 2026

Background

When a UI message history contains an approved providerExecuted tool invocation and the server does the standard pattern:

const modelMessages = await convertToModelMessages(messages);
return streamText({ model, messages: modelMessages });

the provider receives the same tool-approval-response twice for the same approvalId in one tool message. This can cause downstream providers to reject the prompt as invalid (one approval request must produce exactly one response).

Summary

collectToolApprovals finds approval responses by reading the last tool message of initialMessages. Those responses are already present in initialMessages because convertToModelMessages placed them there. Both generateText and streamText then redundantly pushed the same responses into responseMessages/initialResponseMessages. When the step computed stepInputMessages = [...initialMessages, ...responseMessages], the approval appeared twice, and convertToLanguageModelPrompt surfaced both copies inside a single merged tool message.

  • Removed the redundant providerExecutedToolApprovals push in generateText
  • Removed the same block in streamText
  • Updated the four existing snapshots that already documented the bug (approved + denied cases for each function)

Manual Verification

In examples/ai-e2e-next, navigate to /chat/test-openai-responses-mcp-approval and send "Shorten the link https://ai-sdk.dev/". After approving the MCP tool call, the conversation should complete successfully.

To compare before/after, add a console.log of the prompt passed to the model in the mock or in the route handler. In generateText/streamText, you can log stepInputMessages (the variable at the top of the do loop / streamStep body) immediately before the language model call and confirm the tool message contains exactly one tool-approval-response entry after the fix.

Checklist

  • Tests have been added / updated (for bug fixes / features)
  • Documentation has been added / updated (for bug fixes / features)
  • A patch changeset for relevant packages has been added (for bug fixes / features - run pnpm changeset in the project root)
  • I have reviewed this pull request (self-review)

@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 Apr 9, 2026
@lgrammel lgrammel added the backport Admins only: add this label to a pull request in order to backport it to the prior version label Apr 10, 2026
@felixarntz felixarntz merged commit f372547 into main Apr 10, 2026
29 checks passed
@felixarntz felixarntz deleted the fa/fix-double-provider-executed-tool-approvals branch April 10, 2026 13:51
ghost pushed a commit that referenced this pull request Apr 10, 2026
@ghost ghost removed the backport Admins only: add this label to a pull request in order to backport it to the prior version label Apr 10, 2026
@ghost
Copy link
Copy Markdown

ghost commented Apr 10, 2026

⚠️ Backport to release-v6.0 created but has conflicts: #14319

@ghost
Copy link
Copy Markdown

ghost commented Apr 10, 2026

🚀 Published in:

Package Version
ai 7.0.0-beta.78
@ai-sdk/angular 3.0.0-beta.78
@ai-sdk/gateway 4.0.0-beta.44
@ai-sdk/langchain 3.0.0-beta.78
@ai-sdk/llamaindex 3.0.0-beta.78
@ai-sdk/otel 1.0.0-beta.24
@ai-sdk/react 4.0.0-beta.78
@ai-sdk/rsc 3.0.0-beta.79
@ai-sdk/svelte 5.0.0-beta.78
@ai-sdk/vue 4.0.0-beta.78

felixarntz added a commit that referenced this pull request Apr 10, 2026
felixarntz added a commit that referenced this pull request Apr 10, 2026
… to language model twice (#14319)

This is an automated backport of #14289 to the release-v6.0 branch. FYI
@felixarntz
~~This backport has conflicts that need to be resolved manually.~~
Conflicts resolved.

### `git cherry-pick` output

```
Auto-merging packages/ai/src/generate-text/generate-text.test.ts
Auto-merging packages/ai/src/generate-text/generate-text.ts
CONFLICT (content): Merge conflict in packages/ai/src/generate-text/generate-text.ts
Auto-merging packages/ai/src/generate-text/stream-text.test.ts
Auto-merging packages/ai/src/generate-text/stream-text.ts
CONFLICT (content): Merge conflict in packages/ai/src/generate-text/stream-text.ts
error: could not apply f372547... fix(ai): fix `providerExecuted` tool approvals being passed to language model twice (#14289)
hint: After resolving the conflicts, mark them with
hint: "git add/rm <pathspec>", then run
hint: "git cherry-pick --continue".
hint: You can instead skip this commit with "git cherry-pick --skip".
hint: To abort and get back to the state before "git cherry-pick",
hint: run "git cherry-pick --abort".
hint: Disable this message with "git config set advice.mergeConflict false"
```

---------

Co-authored-by: Felix Arntz <felix.arntz@vercel.com>
felixarntz added a commit that referenced this pull request Apr 10, 2026
… no longer ignore `providerExecuted` tool approvals (#14323)

## Summary

`lastAssistantMessageIsCompleteWithApprovalResponses()` so far ignores
`providerExecuted` tools. There's no good reason for that, and we
already had to work around it in one of the Next.js E2E examples.

This PR removes the condition so that `providerExecuted` tools are also
considered.

## Manual Verification

run the modified example, where the custom workaround helper was
replaced with the function from `ai`

## Checklist

- [x] Tests have been added / updated (for bug fixes / features)
- [ ] Documentation has been added / updated (for bug fixes / features)
- [x] A _patch_ changeset for relevant packages has been added (for bug
fixes / features - run `pnpm changeset` in the project root)
- [x] I have reviewed this pull request (self-review)

## Related Issues

includes a follow-up cleanup of an unused variable from #14289 (which
for some reason wasn't flagged by CI in that PR)
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.

2 participants