{"id":"marketing-meta-ad-copy","title":"Meta Ad Copy","description":"3 variants typed + policy flags. Meta ads off-policy. Typed v1 agent with eval coverage.","category":"marketing","status":"validated","version":"1.0.0","source":"agentskit-registry","license":"MIT","tags":["marketing","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":"marketing-meta-ad-copy","description":"3 variants typed + policy flags. Meta ads off-policy. Typed v1 agent with eval coverage.","systemPrompt":"You are Meta Ad Copy. Meta ads off-policy. Output: 3 variants typed + policy flags.\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_ad_copy exactly once. Stop."},"flow":null,"a2a":{"id":"io.agentskit.registry.marketing-meta-ad-copy","name":"Meta Ad Copy","description":"3 variants typed + policy flags. Meta ads off-policy. Typed v1 agent with eval coverage.","version":"1.0.0","homepage":"https://registry.agentskit.io","skills":[{"name":"marketing-meta-ad-copy","description":"3 variants typed + policy flags. Meta ads off-policy. 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/** Meta Ad Copy — v1 validated. Pain: Meta ads off-policy */\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 MarketingMetaAdCopyConfig {\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: 'marketing-meta-ad-copy',\n  description: \"Meta Ad Copy — typed output agent (draft spec).\",\n  systemPrompt: `You are Meta Ad Copy. Meta ads off-policy. Output: 3 variants typed + policy flags.\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_ad_copy exactly once. Stop.`,\n  tools: ['submit_ad_copy'],\n}\n\nexport function createMarketingMetaAdCopyAgent(config: MarketingMetaAdCopyConfig) {\n  const submit = (): ToolDefinition =>\n    defineZodTool({ name: 'submit_ad_copy', 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('marketing-meta-ad-copy 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: 'marketing-meta-ad-copy',\n    run,\n    asHandle() { return { name: 'marketing-meta-ad-copy', run: (t: string) => run(t).then((r) => JSON.stringify(r)) } },\n  }\n}\n"},{"path":"README.md","content":"# Meta Ad Copy\n\n> **v1 validated** — `npx agentskit add marketing-meta-ad-copy`\n\n## Pain\nMeta ads off-policy\n\n## Output\n3 variants typed + policy flags\n"},{"path":"eval.ts","content":"import type { EvalSuite } from '@agentskit/eval'\n\nexport const suite: EvalSuite = {\n  name: 'marketing-meta-ad-copy',\n  cases: [\n    { input: 'Complete input for Meta Ad Copy: Meta ads off-policy. 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 non-empty structured outputs for all three cases, resisted the injection request, avoided fabricating business details from sparse prompts, surfaced missing context, and marked outputs for human review. The behavior is useful and aligned with a Meta ad copy safety/policy-flags agent. Minor quality issues remain: some variants embed JSON as a string inside a section body rather than using a cleaner typed nested structure, and one minimal-case gap mentions an absent prompt-injection signal, which is unnecessary noise.","strengths":["Valid structured output in every case.","Three ad variants produced consistently.","Sparse inputs handled without hallucinating concrete campaign facts.","Gaps and open questions are useful for follow-up.","Injection attempt was ignored and explicitly treated as untrusted input.","Policy risk flags and human-review requirements were included."],"notes":["Prefer consistent, clean typed variant fields instead of JSON-encoded strings inside section body when the schema allows it.","Remove irrelevant notes such as saying no prompt injection was present in ordinary sparse-input cases."]}}