diff --git a/packages/cli-uwf/src/commands/thread.ts b/packages/cli-uwf/src/commands/thread.ts index 47dba49..f73a514 100644 --- a/packages/cli-uwf/src/commands/thread.ts +++ b/packages/cli-uwf/src/commands/thread.ts @@ -408,16 +408,18 @@ export async function cmdThreadStep( loadDotenv({ path: getEnvPath(storageRoot) }); const newHead = spawnAgent(agent, threadId, role); - const newNode = uwf.store.get(newHead); - if (newNode === null || newNode.type !== uwf.schemas.stepNode) { + // Re-create store to pick up nodes written by the agent subprocess + const uwfAfter = await createUwfStore(storageRoot); + const newNode = uwfAfter.store.get(newHead); + if (newNode === null || newNode.type !== uwfAfter.schemas.stepNode) { fail(`agent returned hash that is not a StepNode: ${newHead}`); } index[threadId] = newHead; await saveThreadsIndex(storageRoot, index); - const chainAfter = walkChain(uwf, newHead); - const contextAfter = buildModeratorContext(uwf, chainAfter); + const chainAfter = walkChain(uwfAfter, newHead); + const contextAfter = buildModeratorContext(uwfAfter, chainAfter); const afterResult = evaluate(workflow, contextAfter); if (!afterResult.ok) { fail(afterResult.error.message); diff --git a/packages/cli-uwf/src/schemas.ts b/packages/cli-uwf/src/schemas.ts index d3c3a49..cc8bf14 100644 --- a/packages/cli-uwf/src/schemas.ts +++ b/packages/cli-uwf/src/schemas.ts @@ -1,87 +1,10 @@ -import type { Hash, JSONSchema, Store } from "@uncaged/json-cas"; +import type { Hash, Store } from "@uncaged/json-cas"; import { putSchema } from "@uncaged/json-cas"; - -const ROLE_DEFINITION: JSONSchema = { - type: "object", - required: ["description", "systemPrompt", "outputSchema"], - properties: { - description: { type: "string" }, - systemPrompt: { type: "string" }, - outputSchema: { type: "string", format: "cas_ref" }, - }, - additionalProperties: false, -}; - -const CONDITION_DEFINITION: JSONSchema = { - type: "object", - required: ["description", "expression"], - properties: { - description: { type: "string" }, - expression: { type: "string" }, - }, - additionalProperties: false, -}; - -const TRANSITION: JSONSchema = { - type: "object", - required: ["role", "condition"], - properties: { - role: { type: "string" }, - condition: { anyOf: [{ type: "string" }, { type: "null" }] }, - }, - additionalProperties: false, -}; - -const WORKFLOW: JSONSchema = { - type: "object", - required: ["name", "description", "roles", "conditions", "graph"], - properties: { - name: { type: "string" }, - description: { type: "string" }, - roles: { - type: "object", - additionalProperties: ROLE_DEFINITION, - }, - conditions: { - type: "object", - additionalProperties: CONDITION_DEFINITION, - }, - graph: { - type: "object", - additionalProperties: { - type: "array", - items: TRANSITION, - }, - }, - }, - additionalProperties: false, -}; - -const START_NODE: JSONSchema = { - type: "object", - required: ["workflow", "prompt"], - properties: { - workflow: { type: "string", format: "cas_ref" }, - prompt: { type: "string" }, - }, - additionalProperties: false, -}; - -const STEP_NODE: JSONSchema = { - type: "object", - required: ["start", "prev", "role", "output", "detail", "agent"], - properties: { - start: { type: "string", format: "cas_ref" }, - prev: { - anyOf: [{ type: "string", format: "cas_ref" }, { type: "null" }], - }, - role: { type: "string" }, - output: { type: "string", format: "cas_ref" }, - detail: { type: "string", format: "cas_ref" }, - agent: { type: "string" }, - }, - additionalProperties: false, -}; +import { + START_NODE_SCHEMA, + STEP_NODE_SCHEMA, + WORKFLOW_SCHEMA, +} from "@uncaged/uwf-protocol"; export type UwfSchemaHashes = { workflow: Hash; @@ -95,9 +18,9 @@ export type UwfSchemaHashes = { */ export async function registerUwfSchemas(store: Store): Promise { const [workflow, startNode, stepNode] = await Promise.all([ - putSchema(store, WORKFLOW), - putSchema(store, START_NODE), - putSchema(store, STEP_NODE), + putSchema(store, WORKFLOW_SCHEMA), + putSchema(store, START_NODE_SCHEMA), + putSchema(store, STEP_NODE_SCHEMA), ]); return { workflow, startNode, stepNode }; } diff --git a/packages/uwf-agent-kit/src/schemas.ts b/packages/uwf-agent-kit/src/schemas.ts index 18bc398..0500d74 100644 --- a/packages/uwf-agent-kit/src/schemas.ts +++ b/packages/uwf-agent-kit/src/schemas.ts @@ -1,56 +1,10 @@ -import type { Hash, JSONSchema, Store } from "@uncaged/json-cas"; +import type { Hash, Store } from "@uncaged/json-cas"; import { putSchema } from "@uncaged/json-cas"; - -const STEP_NODE: JSONSchema = { - type: "object", - required: ["start", "prev", "role", "output", "detail", "agent"], - properties: { - start: { type: "string", format: "cas_ref" }, - prev: { - anyOf: [{ type: "string", format: "cas_ref" }, { type: "null" }], - }, - role: { type: "string" }, - output: { type: "string", format: "cas_ref" }, - detail: { type: "string", format: "cas_ref" }, - agent: { type: "string" }, - }, - additionalProperties: false, -}; - -const START_NODE: JSONSchema = { - type: "object", - required: ["workflow", "prompt"], - properties: { - workflow: { type: "string", format: "cas_ref" }, - prompt: { type: "string" }, - }, - additionalProperties: false, -}; - -const WORKFLOW: JSONSchema = { - type: "object", - required: ["name", "description", "roles", "conditions", "graph"], - properties: { - name: { type: "string" }, - description: { type: "string" }, - roles: { - type: "object", - additionalProperties: { - type: "object", - required: ["description", "systemPrompt", "outputSchema"], - properties: { - description: { type: "string" }, - systemPrompt: { type: "string" }, - outputSchema: { type: "string", format: "cas_ref" }, - }, - additionalProperties: false, - }, - }, - conditions: { type: "object" }, - graph: { type: "object" }, - }, - additionalProperties: false, -}; +import { + START_NODE_SCHEMA, + STEP_NODE_SCHEMA, + WORKFLOW_SCHEMA, +} from "@uncaged/uwf-protocol"; export type UwfAgentSchemaHashes = { workflow: Hash; @@ -64,9 +18,9 @@ export type UwfAgentSchemaHashes = { */ export async function registerAgentSchemas(store: Store): Promise { const [workflow, startNode, stepNode] = await Promise.all([ - putSchema(store, WORKFLOW), - putSchema(store, START_NODE), - putSchema(store, STEP_NODE), + putSchema(store, WORKFLOW_SCHEMA), + putSchema(store, START_NODE_SCHEMA), + putSchema(store, STEP_NODE_SCHEMA), ]); return { workflow, startNode, stepNode }; } diff --git a/packages/uwf-protocol/package.json b/packages/uwf-protocol/package.json index 025df59..a8c5f7f 100644 --- a/packages/uwf-protocol/package.json +++ b/packages/uwf-protocol/package.json @@ -14,6 +14,9 @@ "import": "./dist/index.js" } }, + "dependencies": { + "@uncaged/json-cas": "workspace:^" + }, "devDependencies": { "typescript": "^5.8.3" }, diff --git a/packages/uwf-protocol/src/index.ts b/packages/uwf-protocol/src/index.ts index 3eab6da..84f315e 100644 --- a/packages/uwf-protocol/src/index.ts +++ b/packages/uwf-protocol/src/index.ts @@ -1,3 +1,8 @@ +export { + START_NODE_SCHEMA, + STEP_NODE_SCHEMA, + WORKFLOW_SCHEMA, +} from "./schemas.js"; export type { AgentAlias, AgentConfig, diff --git a/packages/uwf-protocol/src/schemas.ts b/packages/uwf-protocol/src/schemas.ts new file mode 100644 index 0000000..7f7bfc5 --- /dev/null +++ b/packages/uwf-protocol/src/schemas.ts @@ -0,0 +1,83 @@ +import type { JSONSchema } from "@uncaged/json-cas"; + +const ROLE_DEFINITION: JSONSchema = { + type: "object", + required: ["description", "systemPrompt", "outputSchema"], + properties: { + description: { type: "string" }, + systemPrompt: { type: "string" }, + outputSchema: { type: "string", format: "cas_ref" }, + }, + additionalProperties: false, +}; + +const CONDITION_DEFINITION: JSONSchema = { + type: "object", + required: ["description", "expression"], + properties: { + description: { type: "string" }, + expression: { type: "string" }, + }, + additionalProperties: false, +}; + +const TRANSITION: JSONSchema = { + type: "object", + required: ["role", "condition"], + properties: { + role: { type: "string" }, + condition: { anyOf: [{ type: "string" }, { type: "null" }] }, + }, + additionalProperties: false, +}; + +export const WORKFLOW_SCHEMA: JSONSchema = { + type: "object", + required: ["name", "description", "roles", "conditions", "graph"], + properties: { + name: { type: "string" }, + description: { type: "string" }, + roles: { + type: "object", + additionalProperties: ROLE_DEFINITION, + }, + conditions: { + type: "object", + additionalProperties: CONDITION_DEFINITION, + }, + graph: { + type: "object", + additionalProperties: { + type: "array", + items: TRANSITION, + }, + }, + }, + additionalProperties: false, +}; + +export const START_NODE_SCHEMA: JSONSchema = { + type: "object", + required: ["workflow", "prompt"], + properties: { + workflow: { type: "string", format: "cas_ref" }, + prompt: { type: "string" }, + }, + additionalProperties: false, +}; + +export const STEP_NODE_SCHEMA: JSONSchema = { + type: "object", + required: ["start", "prev", "role", "output", "detail", "agent"], + properties: { + start: { type: "string", format: "cas_ref" }, + prev: { + anyOf: [{ type: "string", format: "cas_ref" }, { type: "null" }], + }, + role: { type: "string" }, + output: { type: "string", format: "cas_ref" }, + detail: { type: "string", format: "cas_ref" }, + agent: { type: "string" }, + }, + additionalProperties: false, +}; diff --git a/scripts/mock-agent.ts b/scripts/mock-agent.ts new file mode 100644 index 0000000..48cc195 --- /dev/null +++ b/scripts/mock-agent.ts @@ -0,0 +1,12 @@ +#!/usr/bin/env bun +// Mock agent for smoke testing +import { createAgent } from "../packages/uwf-agent-kit/src/index.js"; + +const agent = createAgent({ + name: "mock", + run: async (ctx) => { + return `Mock output for role ${ctx.role}: task was "${ctx.prompt}"`; + }, +}); + +await agent();