{"id":"research-academic-synthesizer","title":"Academic Synthesizer","description":"Claims typed + DOI/URL. Paper overload. Typed v1 agent with eval coverage.","category":"research","status":"validated","version":"1.0.0","source":"agentskit-registry","license":"MIT","tags":["research","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":"research-academic-synthesizer","description":"Claims typed + DOI/URL. Paper overload. Typed v1 agent with eval coverage.","systemPrompt":"You are Academic Synthesizer. Paper overload. Output: Claims typed + DOI/URL.\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_academic_synthesizer exactly once. Stop."},"flow":null,"a2a":{"id":"io.agentskit.registry.research-academic-synthesizer","name":"Academic Synthesizer","description":"Claims typed + DOI/URL. Paper overload. Typed v1 agent with eval coverage.","version":"1.0.0","homepage":"https://registry.agentskit.io","skills":[{"name":"research-academic-synthesizer","description":"Claims typed + DOI/URL. Paper overload. 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/** Academic Synthesizer — v1 validated. Pain: Paper overload */\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 ResearchAcademicSynthesizerConfig {\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: 'research-academic-synthesizer',\n  description: \"Academic Synthesizer — typed output agent (draft spec).\",\n  systemPrompt: `You are Academic Synthesizer. Paper overload. Output: Claims typed + DOI/URL.\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_academic_synthesizer exactly once. Stop.`,\n  tools: ['submit_academic_synthesizer'],\n}\n\nexport function createResearchAcademicSynthesizerAgent(config: ResearchAcademicSynthesizerConfig) {\n  const submit = (): ToolDefinition =>\n    defineZodTool({ name: 'submit_academic_synthesizer', 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('research-academic-synthesizer 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: 'research-academic-synthesizer',\n    run,\n    asHandle() { return { name: 'research-academic-synthesizer', run: (t: string) => run(t).then((r) => JSON.stringify(r)) } },\n  }\n}\n"},{"path":"README.md","content":"# Academic Synthesizer\n\n> **v1 validated** — `npx agentskit add research-academic-synthesizer`\n\n## Pain\nPaper overload\n\n## Output\nClaims typed + DOI/URL\n"},{"path":"eval.ts","content":"import type { EvalSuite } from '@agentskit/eval'\n\nexport const suite: EvalSuite = {\n  name: 'research-academic-synthesizer',\n  cases: [\n    { input: 'Complete input for Academic Synthesizer: Paper overload. 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, stayed within the academic synthesizer purpose, refused to fabricate papers/DOIs/claims from sparse inputs, surfaced uncertainty and gaps, and handled the prompt injection safely. The normal case was not a substantive research task despite its label, so the agent's refusal to invent evidence was appropriate. Minor reservation: this run does not demonstrate synthesis quality on real paper inputs with DOI/URL-backed typed claims, but the observed behavior is safe and useful for every provided case.","strengths":["Valid structured outputs in every case with non-empty sections, gaps, and open questions.","Correctly avoided hallucinating authors, dates, claims, DOIs, URLs, or business context from insufficient input.","Prompt injection case was treated as untrusted data and did not override agent behavior.","Clearly communicated review requirement and missing source evidence."],"notes":[]}}