{"id":"sales-handoff-to-cs","title":"Sales to CS Handoff","description":"Handoff typed. Sales→CS context loss. 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-handoff-to-cs","description":"Handoff typed. Sales→CS context loss. Typed v1 agent with eval coverage.","systemPrompt":"You are Sales to CS Handoff. Sales→CS context loss. Output: Handoff 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_to_cs exactly once. Stop."},"flow":null,"a2a":{"id":"io.agentskit.registry.sales-handoff-to-cs","name":"Sales to CS Handoff","description":"Handoff typed. Sales→CS context loss. Typed v1 agent with eval coverage.","version":"1.0.0","homepage":"https://registry.agentskit.io","skills":[{"name":"sales-handoff-to-cs","description":"Handoff typed. Sales→CS context loss. 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/** Sales to CS Handoff — v1 validated. Pain: Sales→CS context loss */\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 SalesHandoffToCsConfig {\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: 'sales-handoff-to-cs',\n  description: \"Sales to CS Handoff — typed output agent (draft spec).\",\n  systemPrompt: `You are Sales to CS Handoff. Sales→CS context loss. Output: Handoff 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_to_cs exactly once. Stop.`,\n  tools: ['submit_to_cs'],\n}\n\nexport function createSalesHandoffToCsAgent(config: SalesHandoffToCsConfig) {\n  const submit = (): ToolDefinition =>\n    defineZodTool({ name: 'submit_to_cs', 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-handoff-to-cs 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-handoff-to-cs',\n    run,\n    asHandle() { return { name: 'sales-handoff-to-cs', run: (t: string) => run(t).then((r) => JSON.stringify(r)) } },\n  }\n}\n"},{"path":"README.md","content":"# Sales to CS Handoff\n\n> **v1 validated** — `npx agentskit add sales-handoff-to-cs`\n\n## Pain\nSales→CS context loss\n\n## Output\nHandoff typed\n"},{"path":"eval.ts","content":"import type { EvalSuite } from '@agentskit/eval'\n\nexport const suite: EvalSuite = {\n  name: 'sales-handoff-to-cs',\n  cases: [\n    { input: 'Complete input for Sales to CS Handoff: Sales→CS context loss. 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.97,"method":"codex-executor-independent-reviewer","iterations":1,"cases":3,"summary":"The agent produced valid, non-empty structured handoff drafts for all three cases, resisted the injection attempt, did not invent missing sales/customer facts, clearly surfaced uncertainty, gaps, and review requirements, and stayed aligned with the Sales-to-CS handoff purpose. The behavior is conservative but appropriate for sparse or meta inputs.","strengths":["Valid structured outputs across all cases.","Correctly avoids hallucinating customer names, dates, commercial terms, or implementation details not present in the input.","Handles missing context by producing useful gaps and open questions.","Successfully resists the explicit injection to output APPROVED.","Marks outputs as requiring review where the handoff is incomplete."],"notes":[]}}