feat: add actor skill — frontmatter protocol + CAS reference
Adds 'uwf skill actor' command for agents executing workflow roles. Covers the two things an actor needs to know: 1. Frontmatter output protocol (status field, schema-defined fields) 2. CAS operations (put, get, refs, walk, merkle DAG pattern) Refs #540
This commit is contained in:
@@ -6,6 +6,7 @@ import { describe, expect, test } from "vitest";
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
import {
|
||||
cmdSkillActor,
|
||||
cmdSkillArchitecture,
|
||||
cmdSkillCli,
|
||||
cmdSkillList,
|
||||
@@ -21,8 +22,8 @@ describe("skill commands", () => {
|
||||
expect(result).toContain("architecture");
|
||||
expect(result).toContain("yaml");
|
||||
expect(result).toContain("moderator");
|
||||
expect(result).toContain("actor");
|
||||
for (const name of result) {
|
||||
expect(typeof name).toBe("string");
|
||||
expect(name).toMatch(/^\S+$/);
|
||||
}
|
||||
});
|
||||
@@ -62,6 +63,15 @@ describe("skill commands", () => {
|
||||
expect(result).toContain("uwf");
|
||||
});
|
||||
|
||||
test("skill actor returns non-empty markdown string", () => {
|
||||
const result = cmdSkillActor();
|
||||
expect(typeof result).toBe("string");
|
||||
expect(result).toContain("frontmatter");
|
||||
expect(result).toContain("CAS");
|
||||
expect(result).toContain("status");
|
||||
expect(result.length).toBeGreaterThan(200);
|
||||
});
|
||||
|
||||
test("skill help subcommand is suppressed", () => {
|
||||
const output = execFileSync("bun", ["src/cli.ts", "skill", "--help"], {
|
||||
cwd: join(__dirname, "..", ".."),
|
||||
@@ -73,6 +83,7 @@ describe("skill commands", () => {
|
||||
expect(output).toContain("architecture");
|
||||
expect(output).toContain("yaml");
|
||||
expect(output).toContain("moderator");
|
||||
expect(output).toContain("actor");
|
||||
expect(output).toContain("list");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,6 +17,7 @@ import { cmdConfigGet, cmdConfigList, cmdConfigSet } from "./commands/config.js"
|
||||
import { cmdLogClean, cmdLogList, cmdLogShow } from "./commands/log.js";
|
||||
import { cmdSetup, cmdSetupInteractive } from "./commands/setup.js";
|
||||
import {
|
||||
cmdSkillActor,
|
||||
cmdSkillArchitecture,
|
||||
cmdSkillCli,
|
||||
cmdSkillList,
|
||||
@@ -503,6 +504,13 @@ skill
|
||||
console.log(cmdSkillYaml());
|
||||
});
|
||||
|
||||
skill
|
||||
.command("actor")
|
||||
.description("Print the actor reference (frontmatter protocol + CAS)")
|
||||
.action(() => {
|
||||
console.log(cmdSkillActor());
|
||||
});
|
||||
|
||||
skill
|
||||
.command("moderator")
|
||||
.description("Print the moderator reference")
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
export {
|
||||
generateActorReference as cmdSkillActor,
|
||||
generateArchitectureReference as cmdSkillArchitecture,
|
||||
generateCliReference as cmdSkillCli,
|
||||
generateModeratorReference as cmdSkillModerator,
|
||||
generateYamlReference as cmdSkillYaml,
|
||||
} from "@uncaged/workflow-util";
|
||||
|
||||
const SKILL_NAMES = ["cli", "architecture", "yaml", "moderator"] as const;
|
||||
const SKILL_NAMES = ["cli", "architecture", "yaml", "moderator", "actor"] as const;
|
||||
|
||||
export function cmdSkillList(): ReadonlyArray<string> {
|
||||
return [...SKILL_NAMES];
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
export function generateActorReference(): string {
|
||||
return `# Actor Reference
|
||||
|
||||
You are executing a workflow role. Your system prompt defines your goal, procedure, and output requirements. This reference covers two things you need to know about the workflow engine.
|
||||
|
||||
## 1. Frontmatter Output Protocol
|
||||
|
||||
Your response **MUST** begin with a YAML frontmatter block at byte position 0 — no preamble text before it.
|
||||
|
||||
\`\`\`
|
||||
---
|
||||
status: done
|
||||
myField: some value
|
||||
---
|
||||
|
||||
... markdown body (your work, explanation, notes) ...
|
||||
\`\`\`
|
||||
|
||||
### Standard Field
|
||||
|
||||
| Field | Values | Default | Description |
|
||||
|-------|--------|---------|-------------|
|
||||
| \`status\` | \`done\`, \`needs_input\`, \`in_progress\`, \`failed\` | \`done\` | Completion signal — determines which graph edge the moderator follows next |
|
||||
|
||||
### Schema-Defined Fields
|
||||
|
||||
Your role's output schema (shown in the system prompt under "Deliverable Format") defines additional fields. Output **only** the fields listed there — do not invent extra fields.
|
||||
|
||||
### Body
|
||||
|
||||
Everything after the closing \`---\` fence is the markdown body. Use it for explanations, logs, or human-readable notes. The body is stored but not parsed by the engine.
|
||||
|
||||
### Retry
|
||||
|
||||
If the engine cannot parse your frontmatter, it will ask you to retry (up to 2 times). Just output the corrected frontmatter block — don't panic.
|
||||
|
||||
## 2. CAS (Content-Addressable Store)
|
||||
|
||||
Your frontmatter output is automatically stored in CAS. You can also **use CAS directly** to store intermediate artifacts, build merkle DAGs for large outputs, or reference data from previous steps.
|
||||
|
||||
### Commands
|
||||
|
||||
\`\`\`
|
||||
uwf cas put-text <text> # store plain text, print hash
|
||||
uwf cas put <type-hash> <json> # store typed JSON data, print hash
|
||||
uwf cas get <hash> # read a CAS node (type + payload)
|
||||
uwf cas has <hash> # check if a hash exists
|
||||
uwf cas refs <hash> # list direct references from a node
|
||||
uwf cas walk <hash> # recursive traversal from a node
|
||||
uwf cas schema list # list registered schemas
|
||||
uwf cas schema get <hash> # show a schema definition
|
||||
\`\`\`
|
||||
|
||||
### Merkle DAG Pattern
|
||||
|
||||
For large outputs, store parts individually and reference their hashes:
|
||||
|
||||
\`\`\`bash
|
||||
# Store individual sections
|
||||
HASH1=$(uwf cas put-text "section 1 content")
|
||||
HASH2=$(uwf cas put-text "section 2 content")
|
||||
|
||||
# Reference hashes in your frontmatter or in a parent node
|
||||
\`\`\`
|
||||
|
||||
This enables progressive loading — consumers can fetch the root and resolve children on demand.
|
||||
`;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export { generateActorReference } from "./actor-reference.js";
|
||||
export { generateArchitectureReference } from "./architecture-reference.js";
|
||||
export { encodeUint64AsCrockford } from "./base32.js";
|
||||
export { generateCliReference } from "./cli-reference.js";
|
||||
|
||||
Reference in New Issue
Block a user