Tool Approval
Require user approval before executing sensitive tool operations
Tool Approval is a feature that allows you to require explicit user confirmation before a tool executes. This is useful for tools that perform sensitive operations like making purchases, sending emails, or accessing private data.
How It Works
When a tool has needsApproval: true, the AI will pause execution and display an approval UI to the user. The user can then choose to approve or deny the tool execution. If approved, the tool runs and returns results. If denied, the model receives feedback that the user declined.
Enabling Tool Approval
To enable tool approval for a tool, add the needsApproval property to your tool definition:
import { tool } from "ai";
import { z } from "zod";
export const getWeather = tool({
description: "Get the current weather at a location",
inputSchema: z.object({
city: z.string().describe("City name"),
}),
needsApproval: true,
execute: async ({ city }) => {
// Fetch weather data...
return { temperature: 72, condition: "sunny" };
},
});Handling Approval in the UI
The Chat SDK automatically handles tool approval states in the message component. When a tool requests approval, it renders with "Deny" and "Allow" buttons:
if (state === "approval-requested" && approvalId) {
return (
<div className="flex gap-2">
<button
onClick={() => {
addToolApprovalResponse({
id: approvalId,
approved: false,
reason: "User denied",
});
}}
>
Deny
</button>
<button
onClick={() => {
addToolApprovalResponse({
id: approvalId,
approved: true,
});
}}
>
Allow
</button>
</div>
);
}Tool States
Tools with approval go through the following states:
| State | Description |
|---|---|
input-streaming | Tool input is being streamed |
input-available | Tool input is ready |
approval-requested | Waiting for user approval |
approval-responded | User has approved/denied |
output-available | Tool executed successfully |
output-denied | User denied the tool |
output-error | Tool execution failed |
Automatic Continuation
The Chat SDK uses sendAutomaticallyWhen to automatically continue the conversation after approval:
const { addToolApprovalResponse } = useChat({
sendAutomaticallyWhen: ({ messages }) => {
const lastMessage = messages.at(-1);
return lastMessage?.parts?.some(
(part) =>
"state" in part &&
part.state === "approval-responded" &&
"approval" in part &&
part.approval?.approved === true
) ?? false;
},
});Best Practices
- Only require approval for tools that perform sensitive operations
- Provide clear descriptions so users understand what they're approving
- Handle denied tools gracefully in your UI
- Consider logging approval decisions for audit purposes