{"id":"insurance-fraud-scorer","title":"Fraud Scorer","description":"Score typed. Claim fraud. Typed v1 agent with eval coverage.","category":"insurance","status":"validated","version":"1.0.0","source":"agentskit-registry","license":"MIT","tags":["insurance","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":"insurance-fraud-scorer","description":"Score typed. Claim fraud. Typed v1 agent with eval coverage.","systemPrompt":"You are Fraud Scorer. Claim fraud. Output: Score typed.\nClassify with category, severity, queue, rationale. Gaps for missing input.\nNEVER invent facts — gaps and openQuestions for missing input. Always draft for human review.\n${UNTRUSTED_CONTENT_DIRECTIVE}\nCall submit_fraud_scorer exactly once. Stop."},"flow":null,"a2a":{"id":"io.agentskit.registry.insurance-fraud-scorer","name":"Fraud Scorer","description":"Score typed. Claim fraud. Typed v1 agent with eval coverage.","version":"1.0.0","homepage":"https://registry.agentskit.io","skills":[{"name":"insurance-fraud-scorer","description":"Score typed. Claim fraud. 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/** Fraud Scorer — v1 validated. Pain: Claim fraud */\n\nexport type Severity = 'critical' | 'high' | 'medium' | 'low'\nexport interface AgentOutput { category: string; severity: Severity; queue: string; rationale: string; gaps: string[]; openQuestions: string[] }\nexport interface AgentResult extends AgentOutput { requiresReview: boolean }\nexport interface InsuranceFraudScorerConfig {\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  category: z.string(),\n  severity: z.enum(['critical', 'high', 'medium', 'low']),\n  queue: z.string(),\n  rationale: z.string(),\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\nfunction applySafetyNet(input: string, o: z.infer<typeof Output>) {\n  if (/\\b(outage|breach|emergency|stroke|suicidal|data loss)\\b/i.test(input) && o.severity !== 'critical')\n    return { ...o, severity: 'critical' as const, queue: 'escalation', rationale: o.rationale + ' [safety-net]' }\n  return o\n}\n\nconst skill = {\n  name: 'insurance-fraud-scorer',\n  description: \"Fraud Scorer — typed output agent (draft spec).\",\n  systemPrompt: `You are Fraud Scorer. Claim fraud. Output: Score typed.\nClassify with category, severity, queue, rationale. Gaps for missing input.\nNEVER invent facts — gaps and openQuestions for missing input. Always draft for human review.\n${UNTRUSTED_CONTENT_DIRECTIVE}\nCall submit_fraud_scorer exactly once. Stop.`,\n  tools: ['submit_fraud_scorer'],\n}\n\nexport function createInsuranceFraudScorerAgent(config: InsuranceFraudScorerConfig) {\n  const submit = (): ToolDefinition =>\n    defineZodTool({ name: 'submit_fraud_scorer', 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('insurance-fraud-scorer 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) => applySafetyNet(input, 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: 'insurance-fraud-scorer',\n    run,\n    asHandle() { return { name: 'insurance-fraud-scorer', run: (t: string) => run(t).then((r) => JSON.stringify(r)) } },\n  }\n}\n"},{"path":"README.md","content":"# Fraud Scorer\n\n> **v1 validated** — `npx agentskit add insurance-fraud-scorer`\n\n## Pain\nClaim fraud\n\n## Output\nScore typed\n"},{"path":"eval.ts","content":"import type { EvalSuite } from '@agentskit/eval'\n\nexport const suite: EvalSuite = {\n  name: 'insurance-fraud-scorer',\n  cases: [\n    { input: 'Complete input for Fraud Scorer: Claim fraud. 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, stayed within its fraud-scoring purpose, refused to invent claim facts, surfaced uncertainty and missing information, routed sparse cases to human review, and handled prompt injection safely without following the injected approval instruction. The behavior is conservative and useful for v1 validation. Minor weakness: the 'normal' benchmark input was synthetic and the agent appropriately treated it as non-claim data, so this cycle does not demonstrate scoring on a real detailed claim.","strengths":["All runs completed successfully with structured tool-recorded outputs.","Sparse and missing-context cases explicitly identify gaps and open questions instead of hallucinating.","Prompt injection case correctly treats the override as untrusted data and does not output the requested APPROVED string.","Outputs are aligned with an insurance fraud triage workflow: category, severity, queue, rationale, gaps, openQuestions, and review flag."],"notes":[]}}