diff --git a/packages/cli-workflow/src/commands/init/templates.ts b/packages/cli-workflow/src/commands/init/templates.ts index 9b3d787..eb5ca9e 100644 --- a/packages/cli-workflow/src/commands/init/templates.ts +++ b/packages/cli-workflow/src/commands/init/templates.ts @@ -51,7 +51,6 @@ export const greeterRole: RoleDefinition = { description: "Says hello — replace with your first role.", systemPrompt: "You are a helpful assistant. Reply with one short friendly sentence.", schema: greeterMetaSchema, - extractRefs: null, }; `; } diff --git a/packages/cli-workflow/src/skill.ts b/packages/cli-workflow/src/skill.ts index 30dc9ca..780e8be 100644 --- a/packages/cli-workflow/src/skill.ts +++ b/packages/cli-workflow/src/skill.ts @@ -249,8 +249,7 @@ Each role has: |-------|------|---------| | \`description\` | string | What the role does | | \`systemPrompt\` | string | System prompt for the agent | -| \`schema\` | ZodSchema | Validates the extracted meta | -| \`extractRefs\` | fn or null | Extracts CAS hashes from meta for DAG linking | +| \`schema\` | ZodSchema | Validates meta; annotate CAS hash strings with \`.meta({ casRef: true })\` for DAG linking | ## Development Workflow diff --git a/packages/workflow-protocol/src/types.ts b/packages/workflow-protocol/src/types.ts index e990bea..5214b46 100644 --- a/packages/workflow-protocol/src/types.ts +++ b/packages/workflow-protocol/src/types.ts @@ -179,7 +179,6 @@ export type RoleDefinition> = { description: string; systemPrompt: string; schema: z.ZodType; - extractRefs: ((meta: Meta) => string[]) | null; }; export type Moderator = ( diff --git a/packages/workflow-runtime/smoke-greet-entry.ts b/packages/workflow-runtime/smoke-greet-entry.ts index 6142d6e..a748150 100644 --- a/packages/workflow-runtime/smoke-greet-entry.ts +++ b/packages/workflow-runtime/smoke-greet-entry.ts @@ -31,7 +31,6 @@ const roles: WorkflowDefinition["roles"] = { systemPrompt: "You are a friendly greeter. Given a user prompt, produce a warm greeting. Respond in valid JSON with keys: greeting (string), language (string).", schema: greeterSchema, - extractRefs: null, }, }; diff --git a/packages/workflow-runtime/src/create-workflow.ts b/packages/workflow-runtime/src/create-workflow.ts index 6adc97d..0a688ea 100644 --- a/packages/workflow-runtime/src/create-workflow.ts +++ b/packages/workflow-runtime/src/create-workflow.ts @@ -2,13 +2,13 @@ import { putContentNodeWithRefs } from "@uncaged/workflow-cas"; import { tableToModerator } from "@uncaged/workflow-protocol/moderator-table.js"; import type * as z from "zod/v4"; +import { collectCasRefs } from "./collect-cas-refs.js"; import { type AdapterBinding, type AdapterFn, type AdvanceOutcome, END, type ModeratorContext, - type RoleDefinition, type RoleMeta, type RoleOutput, type RoleStep, @@ -26,17 +26,6 @@ function isRoleNext( return next !== END; } -function resolveExtractedRefs( - roleDef: RoleDefinition>, - meta: unknown, -): string[] { - const extractRefsFn = roleDef.extractRefs; - if (extractRefsFn === null || typeof extractRefsFn !== "function") { - return []; - } - return extractRefsFn(meta as Record); -} - function _mergeUniqueHashes(a: readonly string[], b: readonly string[]): string[] { const seen = new Set(); const out: string[] = []; @@ -90,10 +79,7 @@ async function advanceOneRound( const result = await roleFn(modCtx as unknown as ThreadContext, runtime); const meta = result.meta; - const refsFromMeta = resolveExtractedRefs( - roleDef as unknown as RoleDefinition>, - meta, - ); + const refsFromMeta = collectCasRefs(roleDef.schema as z.ZodType, meta); const contentPayload = JSON.stringify(meta); const contentHash = await putContentNodeWithRefs(runtime.cas, contentPayload, refsFromMeta); diff --git a/packages/workflow-template-develop/src/roles/coder.ts b/packages/workflow-template-develop/src/roles/coder.ts index 42650f2..dc36fe1 100644 --- a/packages/workflow-template-develop/src/roles/coder.ts +++ b/packages/workflow-template-develop/src/roles/coder.ts @@ -4,6 +4,7 @@ import * as z from "zod/v4"; export const coderMetaSchema = z.object({ completedPhase: z .string() + .meta({ casRef: true }) .describe( "The planner phase hash finished this round. If multiple phases were completed, use the last finished phase hash.", ), @@ -36,5 +37,4 @@ export const coderRole: RoleDefinition = { "Implements the next incomplete planner phase and reports structured completion metadata.", systemPrompt: CODER_SYSTEM, schema: coderMetaSchema, - extractRefs: (meta) => [meta.completedPhase], }; diff --git a/packages/workflow-template-develop/src/roles/committer.ts b/packages/workflow-template-develop/src/roles/committer.ts index d24e645..74b0482 100644 --- a/packages/workflow-template-develop/src/roles/committer.ts +++ b/packages/workflow-template-develop/src/roles/committer.ts @@ -29,5 +29,4 @@ export const committerRole: RoleDefinition = { description: "Creates a branch and commits changes.", systemPrompt: COMMITTER_SYSTEM, schema: committerMetaSchema, - extractRefs: null, }; diff --git a/packages/workflow-template-develop/src/roles/planner.ts b/packages/workflow-template-develop/src/roles/planner.ts index 8aab2e7..50563d9 100644 --- a/packages/workflow-template-develop/src/roles/planner.ts +++ b/packages/workflow-template-develop/src/roles/planner.ts @@ -2,7 +2,7 @@ import type { RoleDefinition } from "@uncaged/workflow-runtime"; import * as z from "zod/v4"; export const phaseSchema = z.object({ - hash: z.string(), + hash: z.string().meta({ casRef: true }), title: z.string(), }); @@ -63,5 +63,4 @@ export const plannerRole: RoleDefinition = { description: "Breaks the task into sequential phases for the coder.", systemPrompt: PLANNER_SYSTEM, schema: plannerMetaSchema, - extractRefs: (meta) => (meta.status === "planned" ? meta.phases.map((p) => p.hash) : []), }; diff --git a/packages/workflow-template-develop/src/roles/reviewer.ts b/packages/workflow-template-develop/src/roles/reviewer.ts index 05a5a73..5fe6548 100644 --- a/packages/workflow-template-develop/src/roles/reviewer.ts +++ b/packages/workflow-template-develop/src/roles/reviewer.ts @@ -42,5 +42,4 @@ export const reviewerRole: RoleDefinition = { description: "Runs git diff checks and sets approved when the change is ready.", systemPrompt: REVIEWER_SYSTEM, schema: reviewerMetaSchema, - extractRefs: null, }; diff --git a/packages/workflow-template-develop/src/roles/tester.ts b/packages/workflow-template-develop/src/roles/tester.ts index 2eb9292..46a4073 100644 --- a/packages/workflow-template-develop/src/roles/tester.ts +++ b/packages/workflow-template-develop/src/roles/tester.ts @@ -24,5 +24,4 @@ export const testerRole: RoleDefinition = { description: "Runs test, build, and lint commands and reports pass or fail with details.", systemPrompt: TESTER_SYSTEM, schema: testerMetaSchema, - extractRefs: null, }; diff --git a/packages/workflow-template-solve-issue/__tests__/submitter.test.ts b/packages/workflow-template-solve-issue/__tests__/submitter.test.ts index 71c86f7..b760da0 100644 --- a/packages/workflow-template-solve-issue/__tests__/submitter.test.ts +++ b/packages/workflow-template-solve-issue/__tests__/submitter.test.ts @@ -31,8 +31,4 @@ describe("submitterRole", () => { expect(submitterRole.systemPrompt).toContain("submitter"); expect(submitterRole.systemPrompt).toContain("pull request"); }); - - test("has no refs extractor", () => { - expect(submitterRole.extractRefs).toBeNull(); - }); }); diff --git a/packages/workflow-template-solve-issue/src/developer.ts b/packages/workflow-template-solve-issue/src/developer.ts index 6bf95b2..b47e0c6 100644 --- a/packages/workflow-template-solve-issue/src/developer.ts +++ b/packages/workflow-template-solve-issue/src/developer.ts @@ -21,5 +21,4 @@ export const developerRole: RoleDefinition = { "Delegates the actual implementation to the develop workflow (workflow-as-agent). Produces a summary by traversing the child thread's Merkle DAG.", systemPrompt: DEVELOPER_SYSTEM, schema: developerMetaSchema, - extractRefs: () => [], }; diff --git a/packages/workflow-template-solve-issue/src/roles/preparer.ts b/packages/workflow-template-solve-issue/src/roles/preparer.ts index 236b595..601d067 100644 --- a/packages/workflow-template-solve-issue/src/roles/preparer.ts +++ b/packages/workflow-template-solve-issue/src/roles/preparer.ts @@ -45,5 +45,4 @@ export const preparerRole: RoleDefinition = { "Locates or clones the target repository, ensures it is up to date, and gathers project context (conventions, toolchain).", systemPrompt: PREPARER_SYSTEM, schema: preparerMetaSchema, - extractRefs: null, }; diff --git a/packages/workflow-template-solve-issue/src/roles/submitter.ts b/packages/workflow-template-solve-issue/src/roles/submitter.ts index 1238cbc..7ee8331 100644 --- a/packages/workflow-template-solve-issue/src/roles/submitter.ts +++ b/packages/workflow-template-solve-issue/src/roles/submitter.ts @@ -35,5 +35,4 @@ export const submitterRole: RoleDefinition = { description: "Pushes the developer's branch to the remote and opens a pull request.", systemPrompt: SUBMITTER_SYSTEM, schema: submitterMetaSchema, - extractRefs: null, }; diff --git a/smoke-greet-entry.ts b/smoke-greet-entry.ts index 6142d6e..a748150 100644 --- a/smoke-greet-entry.ts +++ b/smoke-greet-entry.ts @@ -31,7 +31,6 @@ const roles: WorkflowDefinition["roles"] = { systemPrompt: "You are a friendly greeter. Given a user prompt, produce a warm greeting. Respond in valid JSON with keys: greeting (string), language (string).", schema: greeterSchema, - extractRefs: null, }, };