Docs
Tool Approval
Gate risky tools so a human — or your own code — confirms before they run. The stream pauses with an approval request and resumes exactly where it left off once you answer.
Declaring what needs approval#
NodeAgent({
model,
// A name list: these tools always require approval.
needsApproval: ['Write', 'Edit', 'Delete'],
// …or a predicate for finer control:
// needsApproval: (toolName) => toolName === 'Bash' ? true : undefined,
})Answering a request#
When a gated tool is about to run, the stream emits a tool-approval-request chunk. Respond by pushing a tool-approval-response message and continuing the turn:
messages.push({
role: 'tool',
content: [{ type: 'tool-approval-response', approvalId, approved: true }],
})
const next = await agent.stream({ messages }) // resumes from the decisionDenials are graceful: the model is told the tool was declined and adapts — usually by proposing an alternative or asking what you'd prefer.
The self-governing shell#
The Node Bash tool has its own escalation rule independent of your config: sandboxed commands run freely, but escalating to the host shell (host: true) always requires approval. You can't configure that away — it's the floor.
Approval is a security boundary only if your UI treats it as one. Render the exact tool input in the approval prompt — path, command, diff — not just the tool name.