Confirmations
The browser decides what runs. Model output is a request, not a command.
A model can be wrong, and a page can carry text that tries to steer it. So the bridge treats every tool call as a request that must pass a check before the handler runs.
When the assistant asks
| Tool annotation | Result |
|---|---|
consequentialHint: true | Always asks. No policy can skip it. |
readOnlyHint: true | Runs without asking. |
| No annotation | Asks. Unknown means unsafe. |
A name is not a classification. A tool called getUser that writes to a database still needs readOnlyHint: false. The assistant reads the annotation you set, not the word you chose.
TIP
Annotate every tool you register. A missing annotation is treated as unsafe, so read-only tools without one make the assistant ask more than it needs to.
What the prompt shows
The prompt names the tool and, when the call has a string name argument, the target. Delete actions use a Delete button and the line "This action cannot be undone." Other tools use Confirm.
Cancel denies the call. The tool result is CONFIRMATION_DENIED and the handler never runs. Escape does the same when a prompt is open. With no prompt open, Escape closes the panel.
Approval expires
Approval is bound to the call id, the arguments, the tool id, and the revision of the tool list at the moment the prompt appeared.
If the page registers or removes a tool while the prompt is on screen, the revision moves. Execution then fails with STALE_TOOLS and the handler does not run. The assistant does not fall back to another tool with the same name.
This closes a real gap. Without it, a page could swap a harmless tool for a destructive one between the moment a person reads the prompt and the moment they select Confirm.
Adding your own rule
requiresConfirmation runs in addition to the built-in rules:
createAssistant({
model,
requiresConfirmation: (tool, call) =>
tool.name === 'transferFunds' || Number(call.arguments.amount) > 1000,
}).mount();It can only add checks. Returning false for a consequential tool does not skip its prompt.
What confirmation does not do
cancel() stops the assistant from dispatching more calls. It cannot undo an application action that already finished. If a handler deleted a row, the row is gone. Design destructive handlers so the confirmation is the last gate.
Your application authorization is still the real boundary. The assistant runs as the signed-in person, so a tool must refuse work that person may not do, whatever the model asked for.