Reference Implementationsintermediate
Business
invoice-processor
Extract line items, validate totals, categorize expenses, escalate on mismatch.
APIs Used
ctx.filesctx.llmctx.dbctx.provenancectx.escalate()ctx.telemetry.emitCapabilities Required
finance/invoice/processWhat this demonstrates
- 1ctx.files.readText() to load documents from file storage
- 2ctx.llm.complete() with a structured JSON extraction prompt
- 3Fourth Law (P10): ctx.escalate() escalation when computed total ≠ expected total
- 4ctx.db.insert() for persisting structured invoice records
- 5ctx.provenance.log() on both success and rejection paths — full audit trail
- 6ctx.telemetry.emit via emitReferenceAuthorSignal on LLM JSON parse recovery (telemetry.author.reference.*)
Source
View on GitHubtypescript
/** * Invoice Processor - Production Reference Agent * * Canon alignment: KB 105 (Agent SDK), KB 22 (HumanOS) * Demonstrates: ctx.files, ctx.llm, ctx.db, ctx.provenance, ctx.escalate() * * Real use case: Extract line items from invoices, validate totals, categorize * expenses. Escalates to human when totals don't match (Fourth Law). */
import { handler, withProvenanceContext } from '@human/agent-sdk';import type { ExecutionContext } from '@human/agent-sdk';import { emitReferenceAuthorSignal } from '../../lib/reference-author-telemetry.js';
export const AGENT_ID = 'invoice-processor';export const VERSION = '1.0.0';export const CAPABILITIES = ['finance/invoice/process'];
export interface InvoiceProcessorInput { /** File path to invoice (text or path in file storage) */ invoicePath: string; /** Expected total for validation (optional) */ expectedTotal?: number;}
export interface LineItem { description: string; quantity: number; unit_price: number; amount: number;}
export interface InvoiceProcessorOutput { success: boolean; line_items: LineItem[]; total: number; vendor?: string; date?: string; escalation_reason?: string; provenance_id: string;}
const execute = async ( ctx: ExecutionContext, input: InvoiceProcessorInput): Promise<InvoiceProcessorOutput> => { ctx.log.info('Processing invoice', { path: input.invoicePath });
// Load invoice from file storage (ctx.files) const invoiceContent = await ctx.files.readText(input.invoicePath);
// Extract line items using LLM (ctx.llm) const extractionResult = await ctx.llm.complete({ prompt: [ { role: 'system', content: `Extract invoice line items as JSON. Return format: { "lineItems": [{"description":"","quantity":1,"unit_price":0,"amount":0}], "vendor":"", "total":0, "date":"" }. Only return valid JSON.`, }, { role: 'user', content: `Extract line items from this invoice:\n\n${invoiceContent}`, }, ], temperature: 0.2, maxTokens: 2000, });
let lineItems: LineItem[]; let total: number; let vendor: string | undefined; let date: string | undefined;
try { const parsed = JSON.parse(extractionResult.content) as { lineItems?: LineItem[]; total?: number; vendor?: string; date?: string; }; lineItems = parsed.lineItems ?? []; total = parsed.total ?? 0; vendor = parsed.vendor; date = parsed.date; } catch { await emitReferenceAuthorSignal(ctx, 'invoice_llm_json_parse_recovery', { invoice_path: input.invoicePath, }); lineItems = []; total = 0; }
// Validate totals - escalate to human on mismatch (Fourth Law, P5 Human-in-Loop) const computedTotal = lineItems.reduce((sum, item) => sum + item.amount, 0); const tolerance = 0.01;
if (input.expectedTotal != null && Math.abs(computedTotal - input.expectedTotal) > tolerance) { const decision = await ctx.escalate({ reason: 'Invoice total mismatch - requires human verification', context: { invoice_path: input.invoicePath, expected_total: input.expectedTotal, computed_total: computedTotal, line_items: lineItems, }, requiredCapability: 'finance/approve', });
if (!decision.approved) { const provenanceId = await ctx.provenance.log( withProvenanceContext(ctx, { type: 'invoice:escalation_rejected', status: 'success', metadata: { input: { invoicePath: input.invoicePath, reason: decision.reason } }, }) ); return { success: false, line_items: lineItems, total: computedTotal, vendor, date, escalation_reason: decision.reason, provenance_id: provenanceId, }; } }
// Store in database (ctx.db()) const db = await ctx.db(); const { id } = await db.insert('invoices', { invoice_path: input.invoicePath, total: total, line_items: JSON.stringify(lineItems), vendor: vendor ?? null, date: date ?? null, processed_at: new Date().toISOString(), });
// Log to provenance (ctx.provenance) const provenanceId = await ctx.provenance.log( withProvenanceContext(ctx, { type: 'invoice:processed', status: 'success', metadata: { input: { invoicePath: input.invoicePath }, output: { invoice_id: id, total, line_item_count: lineItems.length }, }, }) );
return { success: true, line_items: lineItems, total, vendor, date, provenance_id: provenanceId, };};
export default handler({ name: AGENT_ID, id: AGENT_ID, version: VERSION, capabilities: CAPABILITIES, manifest: { operations: [ { name: 'process', description: 'Extract line items from an invoice, validate totals, and escalate on mismatch', paramsSchema: { invoicePath: { type: 'string', required: true, description: 'File path to invoice' }, expectedTotal: { type: 'number', description: 'Expected total for validation' }, }, resultKind: 'agent.invoice-processor.result', }, ], }, execute,});Run the tests
From monorepo root
$ pnpm test:agents:reference
$ pnpm test:agents:reference:verbose
The reference suite runs all 23 agents with createMockExecutionContext(), verifying every ctx.* API call and output shape.
See Also
SDK Reference
Patterns