refactor!: rename RoleDefinition.meta → frontmatter
BREAKING CHANGE: All workflow YAML files must use 'frontmatter' instead of 'meta'. - workflow-protocol: RoleDefinition.meta → frontmatter, schema updated - cli-workflow: validate.ts, workflow.ts — resolveMetaRef → resolveFrontmatterRef - workflow-agent-kit: run.ts — metaSchema → frontmatterSchema - All YAML files updated (examples/, .workflows/) Fixes #374
This commit is contained in:
@@ -23,7 +23,7 @@ roles:
|
|||||||
1. Store it via `uwf cas put "<markdown content>"` and capture the returned hash
|
1. Store it via `uwf cas put "<markdown content>"` and capture the returned hash
|
||||||
2. Put the hash in meta.plan (required when status=ready)
|
2. Put the hash in meta.plan (required when status=ready)
|
||||||
output: "Output a brief summary of the test spec. Frontmatter must include: status (ready or insufficient_info) and plan (CAS hash of the test spec, required when status=ready)."
|
output: "Output a brief summary of the test spec. Frontmatter must include: status (ready or insufficient_info) and plan (CAS hash of the test spec, required when status=ready)."
|
||||||
meta:
|
frontmatter:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
status:
|
status:
|
||||||
@@ -45,7 +45,7 @@ roles:
|
|||||||
5. Ensure `bun run build` passes with no errors
|
5. Ensure `bun run build` passes with no errors
|
||||||
6. Run `bun test` to verify all tests pass
|
6. Run `bun test` to verify all tests pass
|
||||||
output: "List all files changed and provide a summary. Frontmatter must include: status (done or failed)."
|
output: "List all files changed and provide a summary. Frontmatter must include: status (done or failed)."
|
||||||
meta:
|
frontmatter:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
status:
|
status:
|
||||||
@@ -75,7 +75,7 @@ roles:
|
|||||||
Only review standards compliance. Do NOT test functionality.
|
Only review standards compliance. Do NOT test functionality.
|
||||||
If rejecting, you MUST explain the specific reason in your output.
|
If rejecting, you MUST explain the specific reason in your output.
|
||||||
output: "Explain your decision with specific file/line references. Frontmatter must include: approved (true or false)."
|
output: "Explain your decision with specific file/line references. Frontmatter must include: approved (true or false)."
|
||||||
meta:
|
frontmatter:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
approved:
|
approved:
|
||||||
@@ -95,7 +95,7 @@ roles:
|
|||||||
- fix_code: tests fail or implementation doesn't match spec → send back to developer
|
- fix_code: tests fail or implementation doesn't match spec → send back to developer
|
||||||
- fix_spec: the spec itself is wrong or incomplete → send back to planner
|
- fix_spec: the spec itself is wrong or incomplete → send back to planner
|
||||||
output: "Report test results per scenario. Frontmatter must include: status (passed, fix_code, or fix_spec)."
|
output: "Report test results per scenario. Frontmatter must include: status (passed, fix_code, or fix_spec)."
|
||||||
meta:
|
frontmatter:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
status:
|
status:
|
||||||
@@ -115,7 +115,7 @@ roles:
|
|||||||
4. On push success: create a PR via `tea pr create --title "..." --description "..."`
|
4. On push success: create a PR via `tea pr create --title "..." --description "..."`
|
||||||
- PR description must follow the project template: What / Why / Changes / Ref sections, with `Fixes #N` in Ref
|
- PR description must follow the project template: What / Why / Changes / Ref sections, with `Fixes #N` in Ref
|
||||||
output: "Include PR URL on success or error log on failure. Frontmatter must include: success (true or false)."
|
output: "Include PR URL on success or error log on failure. Frontmatter must include: success (true or false)."
|
||||||
meta:
|
frontmatter:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
success:
|
success:
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ roles:
|
|||||||
output: |
|
output: |
|
||||||
Provide your analysis as markdown under the frontmatter.
|
Provide your analysis as markdown under the frontmatter.
|
||||||
The frontmatter must include your structured findings.
|
The frontmatter must include your structured findings.
|
||||||
meta:
|
frontmatter:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
thesis:
|
thesis:
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ roles:
|
|||||||
- planning
|
- planning
|
||||||
procedure: "Analyze the issue and create a detailed, actionable implementation plan."
|
procedure: "Analyze the issue and create a detailed, actionable implementation plan."
|
||||||
output: "Output the plan summary and list of concrete steps."
|
output: "Output the plan summary and list of concrete steps."
|
||||||
meta:
|
frontmatter:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
plan:
|
plan:
|
||||||
@@ -28,7 +28,7 @@ roles:
|
|||||||
- testing
|
- testing
|
||||||
procedure: "Implement the plan. Write code, tests, and ensure existing tests pass."
|
procedure: "Implement the plan. Write code, tests, and ensure existing tests pass."
|
||||||
output: "List all files changed and provide a summary of the implementation."
|
output: "List all files changed and provide a summary of the implementation."
|
||||||
meta:
|
frontmatter:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
filesChanged:
|
filesChanged:
|
||||||
@@ -46,7 +46,7 @@ roles:
|
|||||||
- static-analysis
|
- static-analysis
|
||||||
procedure: "Review the implementation against the plan. Check for bugs, edge cases, and style."
|
procedure: "Review the implementation against the plan. Check for bugs, edge cases, and style."
|
||||||
output: "Approve or reject with detailed comments explaining your decision."
|
output: "Approve or reject with detailed comments explaining your decision."
|
||||||
meta:
|
frontmatter:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
approved:
|
approved:
|
||||||
|
|||||||
@@ -46,11 +46,16 @@ function isJsonSchema(value: unknown): value is JSONSchema {
|
|||||||
return typeof value === "object" && value !== null && !Array.isArray(value);
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function resolveMetaRef(uwf: UwfStore, roleName: string, meta: unknown): Promise<CasRef> {
|
async function resolveFrontmatterRef(
|
||||||
if (!isJsonSchema(meta)) {
|
uwf: UwfStore,
|
||||||
fail(`role "${roleName}": meta must be a JSON Schema object`);
|
roleName: string,
|
||||||
|
frontmatter: unknown,
|
||||||
|
): Promise<CasRef> {
|
||||||
|
if (!isJsonSchema(frontmatter)) {
|
||||||
|
fail(`role "${roleName}": frontmatter must be a JSON Schema object`);
|
||||||
}
|
}
|
||||||
const schema: JSONSchema = meta.title === undefined ? { ...meta, title: roleName } : meta;
|
const schema: JSONSchema =
|
||||||
|
frontmatter.title === undefined ? { ...frontmatter, title: roleName } : frontmatter;
|
||||||
return putSchema(uwf.store, schema);
|
return putSchema(uwf.store, schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,14 +65,18 @@ export async function materializeWorkflowPayload(
|
|||||||
): Promise<WorkflowPayload> {
|
): Promise<WorkflowPayload> {
|
||||||
const roles: Record<string, RoleDefinition> = {};
|
const roles: Record<string, RoleDefinition> = {};
|
||||||
for (const [roleName, role] of Object.entries(raw.roles)) {
|
for (const [roleName, role] of Object.entries(raw.roles)) {
|
||||||
const meta = await resolveMetaRef(uwf, `${raw.name}.${roleName}`, role.meta);
|
const frontmatter = await resolveFrontmatterRef(
|
||||||
|
uwf,
|
||||||
|
`${raw.name}.${roleName}`,
|
||||||
|
role.frontmatter,
|
||||||
|
);
|
||||||
roles[roleName] = {
|
roles[roleName] = {
|
||||||
description: role.description,
|
description: role.description,
|
||||||
goal: role.goal,
|
goal: role.goal,
|
||||||
capabilities: role.capabilities,
|
capabilities: role.capabilities,
|
||||||
procedure: role.procedure,
|
procedure: role.procedure,
|
||||||
output: role.output,
|
output: role.output,
|
||||||
meta,
|
frontmatter,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ function isRoleDefinition(value: unknown): boolean {
|
|||||||
if (!isRecord(value)) {
|
if (!isRecord(value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const meta = value.meta;
|
const frontmatter = value.frontmatter;
|
||||||
const metaOk = isRecord(meta) && typeof meta.type === "string";
|
const frontmatterOk = isRecord(frontmatter) && typeof frontmatter.type === "string";
|
||||||
const capabilities = value.capabilities;
|
const capabilities = value.capabilities;
|
||||||
const capabilitiesOk =
|
const capabilitiesOk =
|
||||||
Array.isArray(capabilities) && capabilities.every((c) => typeof c === "string");
|
Array.isArray(capabilities) && capabilities.every((c) => typeof c === "string");
|
||||||
@@ -26,7 +26,7 @@ function isRoleDefinition(value: unknown): boolean {
|
|||||||
capabilitiesOk &&
|
capabilitiesOk &&
|
||||||
typeof value.procedure === "string" &&
|
typeof value.procedure === "string" &&
|
||||||
typeof value.output === "string" &&
|
typeof value.output === "string" &&
|
||||||
metaOk
|
frontmatterOk
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -130,13 +130,18 @@ export function createAgent(options: AgentOptions): () => Promise<void> {
|
|||||||
fail(`unknown role: ${role}`);
|
fail(`unknown role: ${role}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const metaSchema = getSchema(ctx.meta.store, roleDef.meta);
|
const frontmatterSchema = getSchema(ctx.meta.store, roleDef.frontmatter);
|
||||||
if (metaSchema !== null) {
|
if (frontmatterSchema !== null) {
|
||||||
ctx.outputFormatInstruction = buildOutputFormatInstruction(metaSchema);
|
ctx.outputFormatInstruction = buildOutputFormatInstruction(frontmatterSchema);
|
||||||
}
|
}
|
||||||
|
|
||||||
const agentResult = await runAgent(options, ctx);
|
const agentResult = await runAgent(options, ctx);
|
||||||
const outputHash = await extractOutput(agentResult.output, roleDef.meta, storageRoot, ctx);
|
const outputHash = await extractOutput(
|
||||||
|
agentResult.output,
|
||||||
|
roleDef.frontmatter,
|
||||||
|
storageRoot,
|
||||||
|
ctx,
|
||||||
|
);
|
||||||
const stepHash = await persistStep({
|
const stepHash = await persistStep({
|
||||||
ctx,
|
ctx,
|
||||||
outputHash,
|
outputHash,
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ import type { JSONSchema } from "@uncaged/json-cas";
|
|||||||
|
|
||||||
const ROLE_DEFINITION: JSONSchema = {
|
const ROLE_DEFINITION: JSONSchema = {
|
||||||
type: "object",
|
type: "object",
|
||||||
required: ["description", "goal", "capabilities", "procedure", "output", "meta"],
|
required: ["description", "goal", "capabilities", "procedure", "output", "frontmatter"],
|
||||||
properties: {
|
properties: {
|
||||||
description: { type: "string" },
|
description: { type: "string" },
|
||||||
goal: { type: "string" },
|
goal: { type: "string" },
|
||||||
capabilities: { type: "array", items: { type: "string" } },
|
capabilities: { type: "array", items: { type: "string" } },
|
||||||
procedure: { type: "string" },
|
procedure: { type: "string" },
|
||||||
output: { type: "string" },
|
output: { type: "string" },
|
||||||
meta: { type: "string", format: "cas_ref" },
|
frontmatter: { type: "string", format: "cas_ref" },
|
||||||
},
|
},
|
||||||
additionalProperties: false,
|
additionalProperties: false,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export type RoleDefinition = {
|
|||||||
capabilities: string[];
|
capabilities: string[];
|
||||||
procedure: string;
|
procedure: string;
|
||||||
output: string;
|
output: string;
|
||||||
meta: CasRef;
|
frontmatter: CasRef;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Transition = {
|
export type Transition = {
|
||||||
|
|||||||
Reference in New Issue
Block a user