Documentation menu

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 decision

Denials 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.