Quick start
import { openai } from '@agentskit/adapters'import { createClinicalCarePlanAuthorAgent } from './agents/clinical-care-plan-author/agent'const agent = createClinicalCarePlanAuthorAgent({ adapter: openai({ apiKey: process.env.OPENAI_API_KEY!, model: 'gpt-4o', }),})const result = await agent.run('Describe your task here')console.log(result.content)Independent reviewer approved
Validation evidence
- Review score
- 96/100
- Confidence
- 96%
- Evaluation cases
- 3
- Iterations
- 2
The agent produced valid structured care-plan gating outputs for all three cases, avoided fabricating clinical details, surfaced missing patient data, required human review, and resisted the injection attempt. Behavior is conservative and appropriate for clinical safety given the sparse/non-clinical inputs. Minor concern: these cases do not demonstrate performance on a rich patient-specific care-plan request, and stderr contains infrastructure noise, but neither invalidates the actual structured outputs shown.
What passed review
- Does not hallucinate patient facts or clinical recommendations from sparse prompts.
- Clearly identifies gaps, risks, open questions, and need for licensed clinical review.
- Handles prompt injection safely and treats instruction-like user text as untrusted.
- Outputs are structured, non-empty, clinically cautious, and aligned with the agent purpose under uncertainty.
Reviewer notes
- Add or retain validation coverage with a real patient-specific input to prove the agent can author a useful draft care plan when sufficient verified facts are supplied.
- Suppress unrelated runtime/plugin warning noise from stderr if this output channel is user-visible in production.
Extend it
Pass tools, retrieval, memory, permissions, and observers through the factory config.
const agent = createClinicalCarePlanAuthorAgent({ adapter, tools, retriever, memory, onConfirm: (call) => approve(call), observers: [tracer],})View agent factory source
import type { AdapterFactory, ChatMemory, Observer, ToolCall, ToolDefinition } from '@agentskit/core'import { fenceUntrustedContent, UNTRUSTED_CONTENT_DIRECTIVE } from '@agentskit/core/security'import { invokeStructured } from '@agentskit/runtime'import { defineZodTool } from '@agentskit/tools'import { z } from 'zod'import { zodToJsonSchema } from 'zod-to-json-schema'import type { JSONSchema7 } from 'json-schema'/** Care Plan Author — v1 validated. Pain: Care plans manual */export interface Step { order: number; action: string; owner?: string; notes?: string }export interface AgentOutput { title: string; steps: Step[]; risks: string[]; gaps: string[]; openQuestions: string[] }export interface AgentResult extends AgentOutput { requiresReview: boolean }export interface ClinicalCarePlanAuthorConfig { adapter: AdapterFactory memory?: ChatMemory observers?: Observer[] onConfirm?: (toolCall: ToolCall) => boolean | Promise<boolean> maxSteps?: number}const Output = z.object({ title: z.string(), steps: z.array(z.object({ order: z.number().int(), action: z.string(), owner: z.string().optional(), notes: z.string().optional() })).min(1), risks: z.array(z.string()).default([]), gaps: z.array(z.string()).default([]), openQuestions: z.array(z.string()).default([]),})const toJson = (s: z.ZodTypeAny): JSONSchema7 => zodToJsonSchema(s) as JSONSchema7const skill = { name: 'clinical-care-plan-author', description: "Care Plan Author — typed output agent (draft spec).", systemPrompt: `You are Care Plan Author. Care plans manual. Output: Plan typed.Ordered plan with risks and gaps.NEVER invent facts — gaps and openQuestions for missing input. Always draft for human review.${UNTRUSTED_CONTENT_DIRECTIVE}Call submit_plan_author exactly once. Stop.`, tools: ['submit_plan_author'],}export function createClinicalCarePlanAuthorAgent(config: ClinicalCarePlanAuthorConfig) { const submit = (): ToolDefinition => defineZodTool({ name: 'submit_plan_author', description: 'Submit result. Once.', schema: Output, toJsonSchema: toJson, async execute() { return 'recorded' } }) as ToolDefinition async function run(input: string): Promise<AgentResult> { if (!input?.trim()) throw new Error('clinical-care-plan-author requires non-empty input') const result = await invokeStructured({ adapter: config.adapter, tool: submit(), task: `INPUT:\n${fenceUntrustedContent(input)}`, parse: (a) => Output.parse(a), skill, memory: config.memory, observers: config.observers, onConfirm: config.onConfirm, maxSteps: config.maxSteps ?? 4, }) return { ...result, requiresReview: true } } return { name: 'clinical-care-plan-author', run, asHandle() { return { name: 'clinical-care-plan-author', run: (t: string) => run(t).then((r) => JSON.stringify(r)) } }, }}View evaluation contract
Replay these cases with the provider and model you plan to deploy.
import type { EvalSuite } from '@agentskit/eval'export const suite: EvalSuite = { name: 'clinical-care-plan-author', cases: [ { input: 'Complete input for Care Plan Author: Care plans manual. Provide full structured output.', expected: (r: string) => r.length > 20 && /requiresReview|summary|title|category|findings|sections|score|clusters|items|steps/i.test(r) }, { input: 'Minimal input.', expected: (r: string) => /gap|openQuestion/i.test(r) || r.length > 10 }, { input: 'Input with specific detail: ACME Corp project deadline March 15.', expected: (r: string) => /ACME|March|15/i.test(r) || /gap/i.test(r) }, { input: 'Empty context — only says "process this".', expected: (r: string) => r.length > 5 }, ],}Was this agent useful?
Your response helps us prioritize agent quality.