Human Approval for Tools
medium10 minapprovals.ts
Small refunds can go through automatically, but anything over $100 needs a person to approve it — without blocking a server thread while they decide.
What it shows
- Mark a tool with
requiresApproval(a boolean or a function of the arguments) - Get
status: 'paused'andpendingApprovalsfrom the run - Continue later with
cog.resume()— approve per call or decline all
The code
approvals.ts
import { Agent, Cogitator, tool } from '@cogitator-ai/core';
import { z } from 'zod';
const apiKey = process.env.GOOGLE_API_KEY;
if (!apiKey) throw new Error('Set GOOGLE_API_KEY');
const orders: Record<string, { total: number; refunded: number }> = {
'A-1001': { total: 340, refunded: 0 },
'A-1002': { total: 25, refunded: 0 },
};
const refund = tool({
name: 'refund_order',
description: 'Refund part or all of an order to the customer.',
parameters: z.object({
order: z.string().describe('Order id, e.g. "A-1001"'),
amount: z.number().positive().describe('Amount in dollars'),
}),
requiresApproval: ({ amount }) => amount > 100,
sideEffects: ['external'],
execute: async ({ order, amount }) => {
const record = orders[order];
if (!record) throw new Error(`No order ${order}`);
record.refunded += amount;
return { order, refunded: amount, totalRefunded: record.refunded };
},
});
const cog = new Cogitator({
llm: { providers: { google: { apiKey } } },
memory: { adapter: 'memory' },
});
const support = new Agent({
name: 'support',
model: 'google/gemini-3.5-flash-lite',
instructions: 'You are a support agent. Refund orders with refund_order when asked. Answer briefly.',
tools: [refund],
temperature: 0.2,
});
const threadId = 'ticket-7731';
const paused = await cog.run(support, {
input: 'Order A-1001 arrived broken, please refund all $340.',
threadId,
});
console.log(paused.status);
for (const call of paused.pendingApprovals ?? []) {
console.log(`waiting: ${call.toolName}(${JSON.stringify(call.arguments)})`);
}
if (paused.status === 'paused') {
const approved = await cog.resume(support, threadId, {
decisions: Object.fromEntries(
(paused.pendingApprovals ?? []).map((call) => [call.toolCallId, { approved: true as const }])
),
});
console.log(approved.status, approved.output);
}
const declinedRun = await cog.run(support, {
input: 'Also refund $200 of order A-1001 for shipping.',
threadId,
});
if (declinedRun.status === 'paused') {
const declined = await cog.resume(support, threadId, {
defaultDecision: { approved: false, reason: 'refunds over $100 need photos of the damage' },
});
console.log(declined.output);
}
await cog.close();Run it
install · bash
pnpm add @cogitator-ai/core zodEnvironment
GOOGLE_API_KEYrun · bash
GOOGLE_API_KEY=your-key npx tsx approvals.tsOr run the full example from a clone of the repository (keys in .env):
repository · bash
npx tsx examples/core/14-approvals.ts