refactor: replace extractRefs with schema casRef annotations
Migrate all templates to use .meta({ casRef: true }) on Zod schema
fields instead of manual extractRefs functions. Remove extractRefs
from RoleDefinition type entirely.
- develop: planner phases[].hash, coder completedPhase annotated
- solve-issue, smoke, init templates: extractRefs removed
- create-workflow.ts: uses collectCasRefs(schema, meta)
- RoleDefinition: extractRefs field removed (breaking)
218 tests pass, 0 fail.
Fixes #289, Refs #285
This commit is contained in:
@@ -51,7 +51,6 @@ export const greeterRole: RoleDefinition<HelloTemplateMeta["greeter"]> = {
|
||||
description: "Says hello — replace with your first role.",
|
||||
systemPrompt: "You are a helpful assistant. Reply with one short friendly sentence.",
|
||||
schema: greeterMetaSchema,
|
||||
extractRefs: null,
|
||||
};
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -179,7 +179,6 @@ export type RoleDefinition<Meta extends Record<string, unknown>> = {
|
||||
description: string;
|
||||
systemPrompt: string;
|
||||
schema: z.ZodType<Meta>;
|
||||
extractRefs: ((meta: Meta) => string[]) | null;
|
||||
};
|
||||
|
||||
export type Moderator<M extends RoleMeta> = (
|
||||
|
||||
@@ -31,7 +31,6 @@ const roles: WorkflowDefinition<GreetMeta>["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,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -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<M extends RoleMeta>(
|
||||
return next !== END;
|
||||
}
|
||||
|
||||
function resolveExtractedRefs(
|
||||
roleDef: RoleDefinition<Record<string, unknown>>,
|
||||
meta: unknown,
|
||||
): string[] {
|
||||
const extractRefsFn = roleDef.extractRefs;
|
||||
if (extractRefsFn === null || typeof extractRefsFn !== "function") {
|
||||
return [];
|
||||
}
|
||||
return extractRefsFn(meta as Record<string, unknown>);
|
||||
}
|
||||
|
||||
function _mergeUniqueHashes(a: readonly string[], b: readonly string[]): string[] {
|
||||
const seen = new Set<string>();
|
||||
const out: string[] = [];
|
||||
@@ -90,10 +79,7 @@ async function advanceOneRound<M extends RoleMeta>(
|
||||
const result = await roleFn(modCtx as unknown as ThreadContext, runtime);
|
||||
const meta = result.meta;
|
||||
|
||||
const refsFromMeta = resolveExtractedRefs(
|
||||
roleDef as unknown as RoleDefinition<Record<string, unknown>>,
|
||||
meta,
|
||||
);
|
||||
const refsFromMeta = collectCasRefs(roleDef.schema as z.ZodType, meta);
|
||||
|
||||
const contentPayload = JSON.stringify(meta);
|
||||
const contentHash = await putContentNodeWithRefs(runtime.cas, contentPayload, refsFromMeta);
|
||||
|
||||
@@ -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<CoderMeta> = {
|
||||
"Implements the next incomplete planner phase and reports structured completion metadata.",
|
||||
systemPrompt: CODER_SYSTEM,
|
||||
schema: coderMetaSchema,
|
||||
extractRefs: (meta) => [meta.completedPhase],
|
||||
};
|
||||
|
||||
@@ -29,5 +29,4 @@ export const committerRole: RoleDefinition<CommitterMeta> = {
|
||||
description: "Creates a branch and commits changes.",
|
||||
systemPrompt: COMMITTER_SYSTEM,
|
||||
schema: committerMetaSchema,
|
||||
extractRefs: null,
|
||||
};
|
||||
|
||||
@@ -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<PlannerMeta> = {
|
||||
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) : []),
|
||||
};
|
||||
|
||||
@@ -42,5 +42,4 @@ export const reviewerRole: RoleDefinition<ReviewerMeta> = {
|
||||
description: "Runs git diff checks and sets approved when the change is ready.",
|
||||
systemPrompt: REVIEWER_SYSTEM,
|
||||
schema: reviewerMetaSchema,
|
||||
extractRefs: null,
|
||||
};
|
||||
|
||||
@@ -24,5 +24,4 @@ export const testerRole: RoleDefinition<TesterMeta> = {
|
||||
description: "Runs test, build, and lint commands and reports pass or fail with details.",
|
||||
systemPrompt: TESTER_SYSTEM,
|
||||
schema: testerMetaSchema,
|
||||
extractRefs: null,
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,5 +21,4 @@ export const developerRole: RoleDefinition<DeveloperMeta> = {
|
||||
"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: () => [],
|
||||
};
|
||||
|
||||
@@ -45,5 +45,4 @@ export const preparerRole: RoleDefinition<PreparerMeta> = {
|
||||
"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,
|
||||
};
|
||||
|
||||
@@ -35,5 +35,4 @@ export const submitterRole: RoleDefinition<SubmitterMeta> = {
|
||||
description: "Pushes the developer's branch to the remote and opens a pull request.",
|
||||
systemPrompt: SUBMITTER_SYSTEM,
|
||||
schema: submitterMetaSchema,
|
||||
extractRefs: null,
|
||||
};
|
||||
|
||||
@@ -31,7 +31,6 @@ const roles: WorkflowDefinition<GreetMeta>["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,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user