examples/approval-gated-agent.mjs
Rama main · réplica de lectura del repositorio original.
#!/usr/bin/env node
// Example Impri agent — no dependencies, Node 18+.
//
// It demonstrates the loop every Impri-integrated agent follows:
// 1. propose an action POST /v1/actions
// 2. wait for a human poll GET /v1/actions/:id
// 3. act only if approved then POST /v1/actions/:id/result
//
// Run it:
// IMPRI_API_KEY=im_xxx IMPRI_BASE_URL=https://api.impri.dev node approval-gated-agent.mjs
//
// Then open your Impri inbox and Approve or Reject the request that appears.
const API_KEY = process.env.IMPRI_API_KEY;
const BASE = (process.env.IMPRI_BASE_URL ?? 'http://localhost:8484').replace(/\/+$/, '');
if (!API_KEY) {
console.error('Set IMPRI_API_KEY (it starts with im_).');
process.exit(1);
}
async function api(path, method = 'GET', body) {
const res = await fetch(`${BASE}/v1${path}`, {
method,
headers: { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
body: body ? JSON.stringify(body) : undefined,
});
const json = await res.json().catch(() => ({}));
if (!res.ok) throw new Error(`${method} ${path} -> ${res.status}: ${json.message ?? json.error ?? ''}`);
return json;
}
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
// --- The task this agent wants to do. Edit freely. ---
const task = {
kind: 'email.send',
title: 'Send welcome email to jane@acme.com',
preview: {
format: 'markdown',
body:
'**To:** jane@acme.com\n**Subject:** Welcome to Acme 👋\n\n' +
'Hi Jane, thanks for signing up! Reply if you need anything.',
},
};
// The real side effect. Swap this for your email / deploy / refund / API call.
async function performAction() {
console.log(' -> running the action (this is where your real code goes)...');
// await sendEmail(...)
return 'message queued';
}
async function main() {
console.log(`\nProposing an action to Impri at ${BASE} ...`);
const action = await api('/actions', 'POST', task);
console.log(` - created ${action.id} (status: ${action.status})`);
console.log(' - open your Impri inbox and Approve or Reject it.\n');
let current = action;
while (current.status === 'pending') {
await sleep(3000);
current = await api(`/actions/${action.id}`);
process.stdout.write(` - waiting for a human... (${current.status}) \r`);
}
console.log(`\n - decision: ${current.status.toUpperCase()}`);
if (current.status === 'approved') {
try {
const detail = await performAction();
await api(`/actions/${action.id}/result`, 'POST', { status: 'executed', detail });
console.log(' OK approved -> action performed and reported back to Impri.');
} catch (err) {
await api(`/actions/${action.id}/result`, 'POST', {
status: 'execute_failed',
detail: String(err),
});
console.log(' approved but the action failed -> reported as execute_failed.');
}
} else {
console.log(' not approved -> the agent did nothing. That is the whole point.');
}
}
main().catch((e) => {
console.error('agent error:', e.message);
process.exit(1);
});