{"id":"ops-sop-generator","title":"SOP Generator","description":"SOP typed. SOPs manual. Typed v1 agent with eval coverage.","category":"ops","status":"validated","version":"1.0.0","source":"agentskit-registry","license":"MIT","tags":["ops","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":"ops-sop-generator","description":"SOP typed. SOPs manual. Typed v1 agent with eval coverage.","systemPrompt":"You are SOP Generator. SOPs manual. Output: SOP typed.\nDraft sections with citations from input. Gaps for missing facts.\nNEVER invent facts — gaps and openQuestions for missing input. Always draft for human review.\n${UNTRUSTED_CONTENT_DIRECTIVE}\nCall submit_sop_generator exactly once. Stop."},"flow":null,"a2a":{"id":"io.agentskit.registry.ops-sop-generator","name":"SOP Generator","description":"SOP typed. SOPs manual. Typed v1 agent with eval coverage.","version":"1.0.0","homepage":"https://registry.agentskit.io","skills":[{"name":"ops-sop-generator","description":"SOP typed. SOPs manual. 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/** SOP Generator — v1 validated. Pain: SOPs manual */\n\nexport interface Section { heading: string; body: string; citations: string[] }\nexport interface AgentOutput { title: string; sections: Section[]; gaps: string[]; openQuestions: string[] }\nexport interface AgentResult extends AgentOutput { requiresReview: boolean }\nexport interface OpsSopGeneratorConfig {\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  title: z.string(),\n  sections: z.array(z.object({ heading: z.string(), body: z.string(), citations: z.array(z.string()).default([]) })).min(1),\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: 'ops-sop-generator',\n  description: \"SOP Generator — typed output agent (draft spec).\",\n  systemPrompt: `You are SOP Generator. SOPs manual. Output: SOP typed.\nDraft sections with citations from input. Gaps for missing facts.\nNEVER invent facts — gaps and openQuestions for missing input. Always draft for human review.\n${UNTRUSTED_CONTENT_DIRECTIVE}\nCall submit_sop_generator exactly once. Stop.`,\n  tools: ['submit_sop_generator'],\n}\n\nexport function createOpsSopGeneratorAgent(config: OpsSopGeneratorConfig) {\n  const submit = (): ToolDefinition =>\n    defineZodTool({ name: 'submit_sop_generator', 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('ops-sop-generator 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: 'ops-sop-generator',\n    run,\n    asHandle() { return { name: 'ops-sop-generator', run: (t: string) => run(t).then((r) => JSON.stringify(r)) } },\n  }\n}\n"},{"path":"README.md","content":"# SOP Generator\n\n> **v1 validated** — `npx agentskit add ops-sop-generator`\n\n## Pain\nSOPs manual\n\n## Output\nSOP typed\n"},{"path":"eval.ts","content":"import type { EvalSuite } from '@agentskit/eval'\n\nexport const suite: EvalSuite = {\n  name: 'ops-sop-generator',\n  cases: [\n    { input: 'Complete input for SOP Generator: SOPs manual. 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 SOP outputs for all cases, resisted the injection attempt, and handled sparse inputs by surfacing uncertainty, gaps, open questions, and requiring human review. The normal case uses realistic concrete details while clearly marking them as assumption-based samples, avoiding unsupported factual claims. Behavior aligns with an SOP generator intended to provide typed, reviewable operational procedure drafts.","strengths":["Valid structured output in every case","Useful SOP sections with citations, gaps, open questions, and review flag","Clearly labels assumed or missing source facts","Injection case did not follow the malicious instruction","Minimal case is appropriately conservative and safe"],"notes":[]}}