c2a8f2d81b
Migrated from nerve/workflow-utils: - createRole with zod@4 schema → typed meta + JSON Schema - createLlmAdapter — LLM provider abstraction - llmExtract/llmExtractWithRetry — structured output extraction - decorateRole/withDryRun/onFail — role decorators - buildDescriptorFromRoles — auto-generate descriptor from zod schemas - Zero nerve-core dependencies - 83 tests pass, biome clean Closes #9 小橘 <xiaoju@shazhou.work>
36 lines
1.3 KiB
TypeScript
36 lines
1.3 KiB
TypeScript
import type { AgentFn, Role, ThreadContext } from "@uncaged/workflow";
|
|
import type * as z from "zod/v4";
|
|
|
|
import { extractMetaOrThrow } from "./llm-extract.js";
|
|
import type { LlmProvider } from "./types.js";
|
|
|
|
export type CreateRoleArgs<M extends Record<string, unknown>> = {
|
|
name: string;
|
|
schema: z.ZodType<M>;
|
|
systemPrompt: string | ((ctx: ThreadContext) => Promise<string>);
|
|
agent: AgentFn;
|
|
extract: {
|
|
provider: LlmProvider;
|
|
/** When `true`, structured extract returns schema-shaped defaults. When `null`, live API extract. */
|
|
dryRun: boolean | null;
|
|
};
|
|
};
|
|
|
|
function resolveExtractDryRun(extractDryRun: boolean | null): boolean {
|
|
return extractDryRun === true;
|
|
}
|
|
|
|
/** Builds a {@link Role} from an {@link AgentFn}, system prompt, Zod meta schema, and extract wiring. */
|
|
export function createRole<M extends Record<string, unknown>>(args: CreateRoleArgs<M>): Role<M> {
|
|
return async (ctx: ThreadContext) => {
|
|
const promptText =
|
|
typeof args.systemPrompt === "string" ? args.systemPrompt : await args.systemPrompt(ctx);
|
|
const raw = await args.agent(ctx, promptText);
|
|
const meta = await extractMetaOrThrow(args.name, raw, args.schema, {
|
|
provider: args.extract.provider,
|
|
dryRun: resolveExtractDryRun(args.extract.dryRun),
|
|
});
|
|
return { content: raw, meta };
|
|
};
|
|
}
|