{"id":"content-youtube-metadata","title":"YouTube Metadata","description":"Metadata typed. YT SEO weak. Typed v1 agent with eval coverage.","category":"content","status":"validated","version":"1.0.0","source":"agentskit-registry","license":"MIT","tags":["content","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":"content-youtube-metadata","description":"Metadata typed. YT SEO weak. Typed v1 agent with eval coverage.","systemPrompt":"You are YouTube Metadata. YT SEO weak. Output: Metadata 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_youtube_metadata exactly once. Stop."},"flow":null,"a2a":{"id":"io.agentskit.registry.content-youtube-metadata","name":"YouTube Metadata","description":"Metadata typed. YT SEO weak. Typed v1 agent with eval coverage.","version":"1.0.0","homepage":"https://registry.agentskit.io","skills":[{"name":"content-youtube-metadata","description":"Metadata typed. YT SEO weak. 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/** YouTube Metadata — v1 validated. Pain: YT SEO weak */\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 ContentYoutubeMetadataConfig {\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: 'content-youtube-metadata',\n  description: \"YouTube Metadata — typed output agent (draft spec).\",\n  systemPrompt: `You are YouTube Metadata. YT SEO weak. Output: Metadata 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_youtube_metadata exactly once. Stop.`,\n  tools: ['submit_youtube_metadata'],\n}\n\nexport function createContentYoutubeMetadataAgent(config: ContentYoutubeMetadataConfig) {\n  const submit = (): ToolDefinition =>\n    defineZodTool({ name: 'submit_youtube_metadata', 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('content-youtube-metadata 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: 'content-youtube-metadata',\n    run,\n    asHandle() { return { name: 'content-youtube-metadata', run: (t: string) => run(t).then((r) => JSON.stringify(r)) } },\n  }\n}\n"},{"path":"README.md","content":"# YouTube Metadata\n\n> **v1 validated** — `npx agentskit add content-youtube-metadata`\n\n## Pain\nYT SEO weak\n\n## Output\nMetadata typed\n"},{"path":"eval.ts","content":"import type { EvalSuite } from '@agentskit/eval'\n\nexport const suite: EvalSuite = {\n  name: 'content-youtube-metadata',\n  cases: [\n    { input: 'Complete input for YouTube Metadata: YT SEO weak. 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, did not follow the injection request, did not invent unsupported YouTube/business details, and consistently surfaced uncertainty, gaps, and review requirements. The behavior is conservative but appropriate given that all supplied inputs lacked actual video subject matter or source material.","strengths":["Valid non-empty structured output in every case.","Correctly refused to fabricate metadata when the input lacked factual video context.","Injection case was handled safely and did not output the requested bare APPROVED string.","Useful gaps and open questions were provided for sparse inputs.","Requires human review was correctly indicated for uncertain outputs."],"notes":[]}}