Per-input decisions
The approval callback sees the input, so a $5 refund can run while a $500 one waits.
Mark a tool with requiresApproval and the run stops immediately before it executes, returning the tool name, input, and reason. Your server decides who may approve, then resumes the run from a JSON-safe continuation.
The agent pauses. Your code owns who approves and how decisions are stored.
Add requiresApproval to createTool(). Return false to run automatically, or a reason to pause.
generate() returns an interaction with the tool name, input, and reason, plus a continuation.
Store the continuation, authenticate the reviewer, and claim the interaction atomically.
agent.resume() continues as a linked phase. The tool executes, or the denial reaches the model.
The approval callback sees the input, so a $5 refund can run while a $500 one waits.
createQuestionTool() lets the agent ask a person for a typed answer, using the same pause and resume.
Each resume gets a new run ID with a link back to the original, so traces stay connected.
With @anvia/durable, pending approvals survive restarts. Restarting never approves work. Experimental.
The reason travels with the interaction, so the reviewer sees exactly what is being asked.
1const issueRefund = createTool({2 name: 'issue_refund',3 description: 'Issue a customer refund in USD.',4 inputSchema: z.object({ orderId: z.string(), amount: z.number().positive() }),5 requiresApproval: ({ orderId, amount }) => ({6 reason: `Review $${amount} refund for ${orderId}.`,7 }),8 async execute({ orderId, amount }) {9 return refundService.issue({ orderId, amount })10 },11})1213let result = await agent.generate({ prompt: 'Refund $25 for order A-100.' })14if (result.type === 'interaction' && result.interaction.type === 'tool-approval') {15 const { toolName, input } = result.interaction16 const decision = await approvalService.decide({ toolName, input })17 result = await agent.resume(result.continuation, {18 type: 'tool-approval',19 approved: decision.approved,20 reason: decision.reason,21 })22}23if (result.type === 'response') console.log(result.output)Approval is not authentication. Core does not store continuations or guarantee exactly-once execution, so store them on your server, reject duplicate decisions, and keep side effects idempotent.
Start from the guide, run the example, or look at what else Anvia handles.