diff --git a/packages/workflow-agent-react/package.json b/packages/workflow-agent-react/package.json new file mode 100644 index 0000000..61af09b --- /dev/null +++ b/packages/workflow-agent-react/package.json @@ -0,0 +1,27 @@ +{ + "name": "@uncaged/workflow-agent-react", + "version": "0.3.5", + "type": "module", + "main": "src/index.ts", + "types": "src/index.ts", + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "scripts": { + "test": "bun test" + }, + "dependencies": { + "@uncaged/workflow-protocol": "workspace:*", + "@uncaged/workflow-reactor": "workspace:*", + "@uncaged/workflow-util-agent": "workspace:*" + }, + "devDependencies": { + "zod": "^4.0.0" + }, + "peerDependencies": { + "zod": "^4.0.0" + } +} diff --git a/packages/workflow-agent-react/src/create-react-adapter.ts b/packages/workflow-agent-react/src/create-react-adapter.ts new file mode 100644 index 0000000..58c8399 --- /dev/null +++ b/packages/workflow-agent-react/src/create-react-adapter.ts @@ -0,0 +1,69 @@ +import type { + AdapterFn, + RoleResult, + ThreadContext, + WorkflowRuntime, +} from "@uncaged/workflow-protocol"; +import { createThreadReactor } from "@uncaged/workflow-reactor"; +import { buildThreadInput } from "@uncaged/workflow-util-agent"; +import * as z from "zod/v4"; + +import type { ReactAdapterConfig } from "./types.js"; + +function stripJsonSchemaMeta(json: Record): Record { + const { $schema: _drop, ...rest } = json; + return rest; +} + +function readToolName(parametersSchema: Record): string { + const title = parametersSchema.title; + if (typeof title === "string" && title.trim().length > 0) { + return title.trim(); + } + return "resolve"; +} + +function readToolDescription(parametersSchema: Record): string { + const d = parametersSchema.description; + if (typeof d === "string" && d.trim().length > 0) { + return d.trim(); + } + return "Submit the final structured result."; +} + +export function createReactAdapter(config: ReactAdapterConfig): AdapterFn { + return (prompt: string, schema: z.ZodType) => { + const reactor = createThreadReactor({ + llm: config.llm, + staticTools: config.tools, + structuredToolFromSchema: (s) => { + const rawJsonSchema = z.toJSONSchema(s) as Record; + const parameters = stripJsonSchemaMeta(rawJsonSchema); + const name = readToolName(parameters); + return { + name, + tool: { + type: "function" as const, + function: { + name, + description: readToolDescription(parameters), + parameters, + }, + }, + }; + }, + systemPromptForStructuredTool: (_name) => prompt, + toolHandler: async (call, _thread) => { + return config.toolHandler(call.function.name, call.function.arguments); + }, + maxRounds: config.maxRounds, + }); + + return async (ctx: ThreadContext, _runtime: WorkflowRuntime): Promise> => { + const input = await buildThreadInput(ctx); + const result = await reactor({ thread: ctx, input, schema }); + if (!result.ok) throw new Error(result.error); + return { meta: result.value, childThread: null }; + }; + }; +} diff --git a/packages/workflow-agent-react/src/index.ts b/packages/workflow-agent-react/src/index.ts new file mode 100644 index 0000000..5f1961f --- /dev/null +++ b/packages/workflow-agent-react/src/index.ts @@ -0,0 +1,2 @@ +export { createReactAdapter } from "./create-react-adapter.js"; +export type { ReactAdapterConfig, ReactToolHandler } from "./types.js"; diff --git a/packages/workflow-agent-react/src/types.ts b/packages/workflow-agent-react/src/types.ts new file mode 100644 index 0000000..d8b2abf --- /dev/null +++ b/packages/workflow-agent-react/src/types.ts @@ -0,0 +1,10 @@ +import type { LlmFn, ToolDefinition } from "@uncaged/workflow-reactor"; + +export type ReactToolHandler = (name: string, args: string) => Promise; + +export type ReactAdapterConfig = { + llm: LlmFn; + tools: readonly ToolDefinition[]; + toolHandler: ReactToolHandler; + maxRounds: number; +}; diff --git a/packages/workflow-agent-react/tsconfig.json b/packages/workflow-agent-react/tsconfig.json new file mode 100644 index 0000000..1b9f208 --- /dev/null +++ b/packages/workflow-agent-react/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + "composite": true + }, + "include": ["src/**/*.ts"], + "references": [ + { "path": "../workflow-protocol" }, + { "path": "../workflow-reactor" }, + { "path": "../workflow-util-agent" } + ] +} diff --git a/tsconfig.json b/tsconfig.json index d2e95ff..aa6500f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -29,6 +29,7 @@ { "path": "packages/workflow-agent-cursor" }, { "path": "packages/workflow-agent-hermes" }, { "path": "packages/workflow-util-agent" }, + { "path": "packages/workflow-agent-react" }, { "path": "packages/cli-workflow" }, { "path": "packages/workflow-template-solve-issue" }, { "path": "packages/workflow-template-develop" }