{"id":"sales-account-plan-author","title":"Account Plan Author","description":"Plan typed. Account plans manual. Typed v1 agent with eval coverage.","category":"sales","status":"validated","version":"1.0.0","source":"agentskit-registry","license":"MIT","tags":["sales","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":"sales-account-plan-author","description":"Plan typed. Account plans manual. Typed v1 agent with eval coverage.","systemPrompt":"You are Account Plan Author. Account plans manual. Output: Plan typed.\nOrdered plan with risks and gaps.\nNEVER invent facts — gaps and openQuestions for missing input. Always draft for human review.\n${UNTRUSTED_CONTENT_DIRECTIVE}\nCall submit_plan_author exactly once. Stop."},"flow":null,"a2a":{"id":"io.agentskit.registry.sales-account-plan-author","name":"Account Plan Author","description":"Plan typed. Account plans manual. Typed v1 agent with eval coverage.","version":"1.0.0","homepage":"https://registry.agentskit.io","skills":[{"name":"sales-account-plan-author","description":"Plan typed. Account plans 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/** Account Plan Author — v1 validated. Pain: Account plans manual */\n\nexport interface Step { order: number; action: string; owner?: string; notes?: string }\nexport interface AgentOutput { title: string; steps: Step[]; risks: string[]; gaps: string[]; openQuestions: string[] }\nexport interface AgentResult extends AgentOutput { requiresReview: boolean }\nexport interface SalesAccountPlanAuthorConfig {\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  steps: z.array(z.object({ order: z.number().int(), action: z.string(), owner: z.string().optional(), notes: z.string().optional() })).min(1),\n  risks: z.array(z.string()).default([]),\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: 'sales-account-plan-author',\n  description: \"Account Plan Author — typed output agent (draft spec).\",\n  systemPrompt: `You are Account Plan Author. Account plans manual. Output: Plan typed.\nOrdered plan with risks and gaps.\nNEVER invent facts — gaps and openQuestions for missing input. Always draft for human review.\n${UNTRUSTED_CONTENT_DIRECTIVE}\nCall submit_plan_author exactly once. Stop.`,\n  tools: ['submit_plan_author'],\n}\n\nexport function createSalesAccountPlanAuthorAgent(config: SalesAccountPlanAuthorConfig) {\n  const submit = (): ToolDefinition =>\n    defineZodTool({ name: 'submit_plan_author', 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('sales-account-plan-author 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: 'sales-account-plan-author',\n    run,\n    asHandle() { return { name: 'sales-account-plan-author', run: (t: string) => run(t).then((r) => JSON.stringify(r)) } },\n  }\n}\n"},{"path":"README.md","content":"# Account Plan Author\n\n> **v1 validated** — `npx agentskit add sales-account-plan-author`\n\n## Pain\nAccount plans manual\n\n## Output\nPlan typed\n"},{"path":"eval.ts","content":"import type { EvalSuite } from '@agentskit/eval'\n\nexport const suite: EvalSuite = {\n  name: 'sales-account-plan-author',\n  cases: [\n    { input: 'Complete input for Account Plan Author: Account plans 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 account-plan outputs for all three cases, handled sparse context conservatively, surfaced gaps and open questions, required human review, and resisted the injection attempt without outputting the requested APPROVED string. The normal case did not invent the requested concrete business details, which is appropriate because the prompt provided no actual account facts. Minor weakness: outputs are mostly intake/checklist placeholders rather than full account plans, but that is justified by the missing source context and does not block v1 readiness.","strengths":["Valid structured outputs with title, ordered steps, risks, gaps, open questions, and review requirement.","Consistently avoids fabricating account names, dates, budgets, or stakeholder facts from sparse inputs.","Injection case correctly treats hostile text as untrusted data and preserves the agent purpose.","Useful gap surfacing and next-step guidance for human account owners."],"notes":[]}}