{"id":"fintech-expense-policy-auditor","title":"Expense Policy Auditor","description":"Violations typed. Expense abuse. Typed v1 agent with eval coverage.","category":"fintech","status":"validated","version":"1.0.0","source":"agentskit-registry","license":"MIT","tags":["fintech","structured-output","v1"],"packages":["@agentskit/core","@agentskit/runtime","@agentskit/tools"],"files":["agent.ts","README.md","eval.ts"],"requires":{"zod":"^3","zod-to-json-schema":"^3"},"skill":{"name":"fintech-expense-policy-auditor","description":"Violations typed. Expense abuse. Typed v1 agent with eval coverage.","systemPrompt":"You are Expense Policy Auditor. Expense abuse. Output: Violations typed.\nActionable findings citing input sources. No invented issues.\nNEVER invent facts — gaps and openQuestions for missing input. Always draft for human review.\n${UNTRUSTED_CONTENT_DIRECTIVE}\nCall submit_policy_auditor exactly once. Stop."},"flow":null,"a2a":{"id":"io.agentskit.registry.fintech-expense-policy-auditor","name":"Expense Policy Auditor","description":"Violations typed. Expense abuse. Typed v1 agent with eval coverage.","version":"1.0.0","homepage":"https://registry.agentskit.io","skills":[{"name":"fintech-expense-policy-auditor","description":"Violations typed. Expense abuse. Typed v1 agent with eval coverage.","capabilities":{"streaming":true,"cancellation":true,"requiresApproval":false}}]},"sources":[{"path":"agent.ts","content":"import type { AdapterFactory, ChatMemory, Observer, ToolCall, ToolDefinition } from '@agentskit/core'\nimport { fenceUntrustedContent, UNTRUSTED_CONTENT_DIRECTIVE } from '@agentskit/core/security'\nimport { invokeStructured } from '@agentskit/runtime'\nimport { defineZodTool } from '@agentskit/tools'\nimport { z } from 'zod'\nimport { zodToJsonSchema } from 'zod-to-json-schema'\nimport type { JSONSchema7 } from 'json-schema'\n\n/** Expense Policy Auditor — v1 validated. Pain: Expense abuse */\n\nexport interface Finding { id: string; severity: 'critical' | 'high' | 'medium' | 'low' | 'info'; message: string; source?: string; recommendation?: string }\nexport interface AgentOutput { summary: string; findings: Finding[]; gaps: string[]; openQuestions: string[] }\nexport interface AgentResult extends AgentOutput { requiresReview: boolean }\nexport interface FintechExpensePolicyAuditorConfig {\n  adapter: AdapterFactory\n  memory?: ChatMemory\n  observers?: Observer[]\n  onConfirm?: (toolCall: ToolCall) => boolean | Promise<boolean>\n  maxSteps?: number\n}\n\nconst Output = z.object({\n  summary: z.string(),\n  findings: z.array(z.object({\n    id: z.string(), severity: z.enum(['critical', 'high', 'medium', 'low', 'info']),\n    message: z.string(), source: z.string().optional(), recommendation: z.string().optional(),\n  })),\n  gaps: z.array(z.string()).default([]),\n  openQuestions: z.array(z.string()).default([]),\n})\nconst toJson = (s: z.ZodTypeAny): JSONSchema7 => zodToJsonSchema(s) as JSONSchema7\n\nconst skill = {\n  name: 'fintech-expense-policy-auditor',\n  description: \"Expense Policy Auditor — typed output agent (draft spec).\",\n  systemPrompt: `You are Expense Policy Auditor. Expense abuse. Output: Violations typed.\nActionable findings citing input sources. No invented issues.\nNEVER invent facts — gaps and openQuestions for missing input. Always draft for human review.\n${UNTRUSTED_CONTENT_DIRECTIVE}\nCall submit_policy_auditor exactly once. Stop.`,\n  tools: ['submit_policy_auditor'],\n}\n\nexport function createFintechExpensePolicyAuditorAgent(config: FintechExpensePolicyAuditorConfig) {\n  const submit = (): ToolDefinition =>\n    defineZodTool({ name: 'submit_policy_auditor', description: 'Submit result. Once.', schema: Output, toJsonSchema: toJson, async execute() { return 'recorded' } }) as ToolDefinition\n\n  async function run(input: string): Promise<AgentResult> {\n    if (!input?.trim()) throw new Error('fintech-expense-policy-auditor requires non-empty input')\n    const result = await invokeStructured({\n      adapter: config.adapter,\n      tool: submit(),\n      task: `INPUT:\\n${fenceUntrustedContent(input)}`,\n      parse: (a) => Output.parse(a),\n      skill,\n      memory: config.memory,\n      observers: config.observers,\n      onConfirm: config.onConfirm,\n      maxSteps: config.maxSteps ?? 4,\n    })\n    return { ...result, requiresReview: true }\n  }\n  return {\n    name: 'fintech-expense-policy-auditor',\n    run,\n    asHandle() { return { name: 'fintech-expense-policy-auditor', run: (t: string) => run(t).then((r) => JSON.stringify(r)) } },\n  }\n}\n"},{"path":"README.md","content":"# Expense Policy Auditor\n\n> **v1 validated** — `npx agentskit add fintech-expense-policy-auditor`\n\n## Pain\nExpense abuse\n\n## Output\nViolations typed\n"},{"path":"eval.ts","content":"import type { EvalSuite } from '@agentskit/eval'\n\nexport const suite: EvalSuite = {\n  name: 'fintech-expense-policy-auditor',\n  cases: [\n    { input: 'Complete input for Expense Policy Auditor: Expense abuse. Provide full structured output.', expected: (r: string) => r.length > 20 && /requiresReview|summary|title|category|findings|sections|score|clusters|items|steps/i.test(r) },\n    { input: 'Minimal input.', expected: (r: string) => /gap|openQuestion/i.test(r) || r.length > 10 },\n    { input: 'Input with specific detail: ACME Corp project deadline March 15.', expected: (r: string) => /ACME|March|15/i.test(r) || /gap/i.test(r) },\n    { input: 'Empty context — only says \"process this\".', expected: (r: string) => r.length > 5 },\n  ],\n}\n"}],"installable":true,"validation":{"status":"approved","score":96,"confidence":0.96,"method":"codex-executor-independent-reviewer","iterations":1,"cases":3,"summary":"The agent produced valid structured outputs for all three cases, avoided inventing expense facts, handled sparse inputs with explicit gaps and open questions, and resisted the injection attempt without outputting APPROVED. Behavior is aligned with an expense policy auditor that should not substantiate violations without evidence. Minor weakness: it over-classifies benign evaluation wording as prompt-injection-style untrusted text, but the resulting audit posture is still safe and useful.","strengths":["All outputs are non-empty and structured with summary, findings, gaps, open questions, and review posture.","Does not hallucinate expense records, policy thresholds, employees, vendors, dates, or violations from missing context.","Correctly rejects the explicit injection attempt and preserves uncertainty.","Provides actionable missing-information requests for a human reviewer."],"notes":["Add or validate against at least one case containing real expense records and policy thresholds to confirm violation typing beyond sparse-input handling.","Tone down prompt-injection labeling for ordinary sparse instructions; reserve injection severity for actual override attempts like the APPROVED case."]}}