docs: update wf-stateless-design.md for new/resume $START semantics #103
@@ -15,7 +15,7 @@ export {
|
||||
validateFrontmatter,
|
||||
} from "./frontmatter-markdown/index.js";
|
||||
export { createLogger } from "./logger.js";
|
||||
export { generateModeratorReference } from "./moderator-reference.js";
|
||||
|
||||
export type {
|
||||
CreateProcessLoggerOptions,
|
||||
ProcessLogFn,
|
||||
@@ -35,4 +35,3 @@ export { extractUlidTimestamp, generateUlid } from "./ulid.js";
|
||||
export { generateUsageReference } from "./usage-reference.js";
|
||||
export { VERSION } from "./version.js";
|
||||
export { generateWorkflowAuthoringReference } from "./workflow-authoring-reference.js";
|
||||
export { generateYamlReference } from "./yaml-reference.js";
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
export function generateModeratorReference(): string {
|
||||
return `# Moderator Reference
|
||||
|
||||
## Overview
|
||||
|
||||
The moderator is the workflow engine's routing component. It evaluates the directed graph defined in the workflow YAML to determine the next role (or \`$END\`) after each step — with zero LLM cost.
|
||||
|
||||
## Status-Based Routing
|
||||
|
||||
The moderator uses **status-based routing**: it inspects the previous step's extracted output (specifically the \`$status\` field) and looks up the corresponding edge in the graph.
|
||||
|
||||
### Graph Structure
|
||||
|
||||
The graph is a nested map: \`Record<Role | "$START", Record<Status, Target>>\`. Each role maps its possible \`$status\` values to a target with a \`role\` and \`prompt\`:
|
||||
|
||||
\`\`\`yaml
|
||||
graph:
|
||||
$START:
|
||||
new: { role: planner, prompt: "Analyze the issue." }
|
||||
resume: { role: planner, prompt: "Review the previous run output and continue." }
|
||||
planner:
|
||||
ready: { role: developer, prompt: "Implement the plan (CAS hash: {{{plan}}})." }
|
||||
insufficient_info: { role: $END, prompt: "Not enough info." }
|
||||
developer:
|
||||
done: { role: reviewer, prompt: "Review branch {{{branch}}} at {{{worktree}}}." }
|
||||
failed: { role: $END, prompt: "Developer failed: {{{reason}}}." }
|
||||
reviewer:
|
||||
approved: { role: tester, prompt: "Run tests on {{{branch}}} at {{{worktree}}}." }
|
||||
rejected: { role: developer, prompt: "Fix issues: {{{comments}}}." }
|
||||
\`\`\`
|
||||
|
||||
### Routing Algorithm
|
||||
|
||||
1. Look up \`graph[lastRole]\` to get the status map for the current role
|
||||
2. Look up \`statusMap[lastOutput.$status]\` to get the target
|
||||
3. If target role is \`$END\`, mark thread as completed
|
||||
4. Otherwise, render the edge prompt (Mustache templates with \`{{{field}}}\` from output) and spawn the next agent
|
||||
|
||||
### Edge Prompts and Mustache Templates
|
||||
|
||||
Edge prompts use triple-brace Mustache syntax (\`{{{field}}}\`) to interpolate values from the previous step's output into the next agent's task prompt. This passes structured data (branch names, file paths, CAS hashes) between roles without manual wiring.
|
||||
|
||||
## Special Nodes
|
||||
|
||||
- \`$START\` — entry point; uses status keys \`new\` (first start) and \`resume\` (resuming a completed thread)
|
||||
- \`$END\` — terminal node; thread completes when reached and is moved to history
|
||||
|
||||
## Integration with Steps
|
||||
|
||||
Each \`uwf thread exec\` cycle:
|
||||
1. Moderator reads the thread's head step output
|
||||
2. Looks up \`graph[lastRole][output.$status]\` to pick the next role
|
||||
3. If next is \`$END\`, marks thread as completed
|
||||
4. Otherwise, renders the edge prompt and spawns the agent for the selected role
|
||||
5. Extract pipeline parses agent output → new step node → append to CAS chain
|
||||
`;
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
export function generateYamlReference(): string {
|
||||
return `# Workflow YAML Schema Reference
|
||||
|
||||
## Top-Level Structure
|
||||
|
||||
A workflow YAML file defines the complete workflow specification:
|
||||
|
||||
\`\`\`yaml
|
||||
name: solve-issue # verb-first kebab-case identifier
|
||||
description: "..." # human-readable description
|
||||
|
||||
roles: # named actors in the workflow
|
||||
planner:
|
||||
description: "Analyzes issue and outputs a plan"
|
||||
goal: "You are a planning agent."
|
||||
capabilities:
|
||||
- issue-analysis
|
||||
- planning
|
||||
procedure: |
|
||||
1. Read the issue
|
||||
2. Produce a test spec
|
||||
output: "Output the plan summary. Set $status to ready or insufficient_info."
|
||||
frontmatter: # JSON Schema for structured output (drives routing)
|
||||
oneOf:
|
||||
- properties:
|
||||
$status: { const: ready }
|
||||
plan: { type: string }
|
||||
required: [$status, plan]
|
||||
- properties:
|
||||
$status: { const: insufficient_info }
|
||||
required: [$status]
|
||||
|
||||
graph: # status-based routing (nested map)
|
||||
$START:
|
||||
new: { role: planner, prompt: "Analyze the issue." }
|
||||
resume: { role: planner, prompt: "Review the previous run output and continue." }
|
||||
planner:
|
||||
ready: { role: developer, prompt: "Implement plan {{{plan}}}." }
|
||||
insufficient_info: { role: $END, prompt: "Not enough info." }
|
||||
\`\`\`
|
||||
|
||||
## roles
|
||||
|
||||
Each role defines an actor in the workflow:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| \`description\` | string | Short description of the role's purpose |
|
||||
| \`goal\` | string | System-level goal statement for the agent |
|
||||
| \`capabilities\` | string[] | Tags describing what the role can do |
|
||||
| \`procedure\` | string | Step-by-step instructions for the agent |
|
||||
| \`output\` | string | Description of expected output format |
|
||||
| \`frontmatter\` | JSON Schema | Defines the structured output the agent must produce |
|
||||
|
||||
### frontmatter
|
||||
|
||||
The \`frontmatter\` field is a standard JSON Schema object. The extract pipeline validates agent output against it. Key conventions:
|
||||
- \`$status\` field drives routing decisions in the graph
|
||||
- Use \`const\` or \`enum\` to constrain status values
|
||||
- Use \`oneOf\` to define multiple valid output shapes (one per status)
|
||||
- All \`required\` fields must appear in the agent's frontmatter output
|
||||
|
||||
## graph
|
||||
|
||||
The graph is a nested map defining status-based routing:
|
||||
|
||||
\`\`\`
|
||||
Record<Role | "$START", Record<Status, { role: string, prompt: string }>>
|
||||
\`\`\`
|
||||
|
||||
| Level | Key | Value |
|
||||
|-------|-----|-------|
|
||||
| Outer | Role name or \`$START\` | Status map for that role |
|
||||
| Inner | \`$status\` value | Target: \`{ role, prompt }\` |
|
||||
|
||||
### Special Nodes
|
||||
- \`$START\` — entry point; uses status keys \`new\` (first start) and \`resume\` (resuming a completed thread)
|
||||
- \`$END\` — terminal node; thread completes when reached
|
||||
|
||||
### Edge Prompts
|
||||
Prompts use triple-brace Mustache templates (\`{{{field}}}\`) to interpolate values from the previous step's output. Example: \`"Implement plan {{{plan}}} in repo {{{repoPath}}}."\`
|
||||
`;
|
||||
}
|
||||
Reference in New Issue
Block a user