{"id":"product-usage-insights","title":"Usage Insights","description":"Insights typed. Usage data unread. Typed v1 agent with eval coverage.","category":"product","status":"validated","version":"1.0.0","source":"agentskit-registry","license":"MIT","tags":["product","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":"product-usage-insights","description":"Insights typed. Usage data unread. Typed v1 agent with eval coverage.","systemPrompt":"You are Usage Insights. Usage data unread. Output: Insights 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_usage_insights exactly once. Stop."},"flow":null,"a2a":{"id":"io.agentskit.registry.product-usage-insights","name":"Usage Insights","description":"Insights typed. Usage data unread. Typed v1 agent with eval coverage.","version":"1.0.0","homepage":"https://registry.agentskit.io","skills":[{"name":"product-usage-insights","description":"Insights typed. Usage data unread. 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/** Usage Insights — v1 validated. Pain: Usage data unread */\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 ProductUsageInsightsConfig {\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: 'product-usage-insights',\n  description: \"Usage Insights — typed output agent (draft spec).\",\n  systemPrompt: `You are Usage Insights. Usage data unread. Output: Insights 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_usage_insights exactly once. Stop.`,\n  tools: ['submit_usage_insights'],\n}\n\nexport function createProductUsageInsightsAgent(config: ProductUsageInsightsConfig) {\n  const submit = (): ToolDefinition =>\n    defineZodTool({ name: 'submit_usage_insights', 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('product-usage-insights 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: 'product-usage-insights',\n    run,\n    asHandle() { return { name: 'product-usage-insights', run: (t: string) => run(t).then((r) => JSON.stringify(r)) } },\n  }\n}\n"},{"path":"README.md","content":"# Usage Insights\n\n> **v1 validated** — `npx agentskit add product-usage-insights`\n\n## Pain\nUsage data unread\n\n## Output\nInsights typed\n"},{"path":"eval.ts","content":"import type { EvalSuite } from '@agentskit/eval'\n\nexport const suite: EvalSuite = {\n  name: 'product-usage-insights',\n  cases: [\n    { input: 'Complete input for Usage Insights: Usage data unread. 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, consistently avoided inventing usage insights without data, surfaced concrete gaps and open questions, and resisted the injection request. Behavior matches the stated purpose of a typed usage-insights agent that should not fabricate from unread/missing usage data.","strengths":["Valid structured output shape in every case.","Appropriately flags missing data and requires review instead of hallucinating metrics or business conclusions.","Handles the explicit injection attempt without complying.","Provides useful gap lists and follow-up questions for sparse inputs."],"notes":[]}}