Skip to content

fix: tool approval deny flow breaks subsequent messages#1493

Open
sAkuraOfficial wants to merge 2 commits into
vercel:mainfrom
sAkuraOfficial:main
Open

fix: tool approval deny flow breaks subsequent messages#1493
sAkuraOfficial wants to merge 2 commits into
vercel:mainfrom
sAkuraOfficial:main

Conversation

@sAkuraOfficial
Copy link
Copy Markdown

fix: tool approval deny flow breaks subsequent messages

Fixes two related bugs in the tool approval flow that cause user messages to be silently dropped after denying a tool call.

When a user denies a tool approval (e.g., clicks "Deny" on ``), two issues occur:

  1. The deny action never reaches the serversendAutomaticallyWhen only triggers when approved === true, so denials are silently swallowed on the client.

  2. All subsequent user messages are lost — After a denial, any new message the user types is incorrectly treated as a tool approval continuation. The message is never sent to the model, never saved to the database, and disappears on page refresh.

before fix bug

error.example.mp4

After fix bug

success.example.mp4

Root Cause

Issue 1: sendAutomaticallyWhen ignores denials

 sendAutomaticallyWhen: ({ messages: currentMessages }) => {
   const lastMessage = currentMessages.at(-1);
   return (
     lastMessage?.parts?.some(
       (part) =>
         "state" in part &&
         part.state === "approval-responded" &&
-        "approval" in part &&
-        (part.approval as { approved?: boolean })?.approved === true
+        "approval" in part
     ) ?? false
   );
 },

The approved === true check means only approvals trigger auto-send. Denials update the local state to approval-responded but never send a request to the server.

Issue 2: || in prepareSendMessagesRequest corrupts subsequent requests

 const isToolApprovalContinuation =
-  lastMessage?.role !== "user" ||
+  lastMessage?.role !== "user" &&
   request.messages.some((msg) =>
     msg.parts?.some((part) => {
       const state = (part as { state?: string }).state;
       return (
         state === "approval-responded" || state === "output-denied"
       );
     })
   );

With ||, the condition evaluates as:

  • Condition A: lastMessage?.role !== "user"false (it IS a user message)
  • Condition B: request.messages.some(...)true (history contains approval-responded from the earlier deny)
  • false || true = trueincorrectly enters approval mode

This causes the request body to send { messages: allMessages } instead of { message: lastMessage }. The backend then enters the tool approval branch (Boolean(messages) = true), which only performs approval state merging and completely ignores the user's new message.
image

Result: The user's message is never sent to the model, never persisted to the database, and the model only sees the old denial — responding with "user denied" repeatedly.

With &&, a new user message (lastMessage.role === "user") always takes the normal path regardless of historical approval states, which is the correct behavior.

Steps to Reproduce and video

  1. Send a message that triggers a tool requiring approval (e.g., decryptSkaKey)
  2. Click Deny on the approval prompt
  3. Type a new message (e.g., "please try again")
  4. Observe: The model responds with "user has denied the operation" instead of processing the new message
  5. Refresh the page: The new message you typed has disappeared, but the AI's denial response remains

Changes

  • sendAutomaticallyWhen: Remove approved === true filter so denials also trigger a server request
  • prepareSendMessagesRequest: Change || to && so new user messages are never misclassified as tool approval continuations

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 9, 2026

@sAkuraOfficial is attempting to deploy a commit to the Templates Test vtest314 Team on Vercel.

A member of the Team first needs to authorize it.

@sAkuraOfficial
Copy link
Copy Markdown
Author

da2e118 fix: error when continuing conversation without handling approval

before fix:

before.fix.mp4

after fix:

after.fix.mp4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant