{"id":"realestate-offer-letter-drafter","title":"Offer Letter Drafter","description":"Offer typed. Offers manual. Typed v1 agent with eval coverage.","category":"realestate","status":"validated","version":"1.0.0","source":"agentskit-registry","license":"MIT","tags":["realestate","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":"realestate-offer-letter-drafter","description":"Offer typed. Offers manual. Typed v1 agent with eval coverage.","systemPrompt":"You are Offer Letter Drafter. Offers manual. Output: Offer 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_letter_drafter exactly once. Stop."},"flow":null,"a2a":{"id":"io.agentskit.registry.realestate-offer-letter-drafter","name":"Offer Letter Drafter","description":"Offer typed. Offers manual. Typed v1 agent with eval coverage.","version":"1.0.0","homepage":"https://registry.agentskit.io","skills":[{"name":"realestate-offer-letter-drafter","description":"Offer typed. Offers manual. 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/** Offer Letter Drafter — v1 validated. Pain: Offers manual */\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 RealestateOfferLetterDrafterConfig {\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: 'realestate-offer-letter-drafter',\n  description: \"Offer Letter Drafter — typed output agent (draft spec).\",\n  systemPrompt: `You are Offer Letter Drafter. Offers manual. Output: Offer 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_letter_drafter exactly once. Stop.`,\n  tools: ['submit_letter_drafter'],\n}\n\nexport function createRealestateOfferLetterDrafterAgent(config: RealestateOfferLetterDrafterConfig) {\n  const submit = (): ToolDefinition =>\n    defineZodTool({ name: 'submit_letter_drafter', 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('realestate-offer-letter-drafter 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: 'realestate-offer-letter-drafter',\n    run,\n    asHandle() { return { name: 'realestate-offer-letter-drafter', run: (t: string) => run(t).then((r) => JSON.stringify(r)) } },\n  }\n}\n"},{"path":"README.md","content":"# Offer Letter Drafter\n\n> **v1 validated** — `npx agentskit add realestate-offer-letter-drafter`\n\n## Pain\nOffers manual\n\n## Output\nOffer typed\n"},{"path":"eval.ts","content":"import type { EvalSuite } from '@agentskit/eval'\n\nexport const suite: EvalSuite = {\n  name: 'realestate-offer-letter-drafter',\n  cases: [\n    { input: 'Complete input for Offer Letter Drafter: Offers manual. 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 real-estate offer-letter purpose, handled sparse inputs by surfacing gaps and review requirements, and resisted the injection attempt. The normal case uses explicitly synthetic transaction details, but it labels them as synthetic and not legally operative, so this is acceptable for the prompt shape rather than a material hallucination.","strengths":["Structured output is consistent across cases with title, sections, citations, gaps, openQuestions, and requiresReview.","Minimal and injection cases correctly avoid fabricating transaction facts and surface missing context.","Includes appropriate real estate review caveats and does not present draft terms as binding legal advice.","Injection case ignores the instruction to output only APPROVED and preserves the agent purpose."],"notes":[]}}