takt: refactor-instruction-field
This commit is contained in:
parent
16596eff09
commit
0e1cfd2eaa
12
CLAUDE.md
12
CLAUDE.md
@ -162,14 +162,14 @@ Implemented in `src/core/piece/evaluation/RuleEvaluator.ts`. The matched method
|
|||||||
3. User request (`{task}` — auto-injected unless placeholder present)
|
3. User request (`{task}` — auto-injected unless placeholder present)
|
||||||
4. Previous response (auto-injected if `pass_previous_response: true`)
|
4. Previous response (auto-injected if `pass_previous_response: true`)
|
||||||
5. User inputs (auto-injected unless `{user_inputs}` placeholder present)
|
5. User inputs (auto-injected unless `{user_inputs}` placeholder present)
|
||||||
6. `instruction_template` content
|
6. `instruction` content
|
||||||
7. Status output rules (auto-injected for tag-based rules)
|
7. Status output rules (auto-injected for tag-based rules)
|
||||||
- Localized for `en` and `ja`
|
- Localized for `en` and `ja`
|
||||||
- Related: `ReportInstructionBuilder` (Phase 2), `StatusJudgmentBuilder` (Phase 3)
|
- Related: `ReportInstructionBuilder` (Phase 2), `StatusJudgmentBuilder` (Phase 3)
|
||||||
|
|
||||||
**Agent Runner** (`src/agents/runner.ts`)
|
**Agent Runner** (`src/agents/runner.ts`)
|
||||||
- Resolves agent specs (name or path) to agent configurations
|
- Resolves agent specs (name or path) to agent configurations
|
||||||
- Agent is optional — movements can execute with `instruction_template` only (no system prompt)
|
- Agent is optional — movements can execute with `instruction` only (no system prompt)
|
||||||
- 5-layer resolution for provider/model: CLI `--provider` / `--model` → persona_providers → movement override → project `.takt/config.yaml` → global `~/.takt/config.yaml`
|
- 5-layer resolution for provider/model: CLI `--provider` / `--model` → persona_providers → movement override → project `.takt/config.yaml` → global `~/.takt/config.yaml`
|
||||||
- Custom personas via `~/.takt/personas/<name>.md` or prompt files (.md)
|
- Custom personas via `~/.takt/personas/<name>.md` or prompt files (.md)
|
||||||
- Inline system prompts: If agent file doesn't exist, the agent string is used as inline system prompt
|
- Inline system prompts: If agent file doesn't exist, the agent string is used as inline system prompt
|
||||||
@ -299,7 +299,7 @@ loop_monitors:
|
|||||||
threshold: 3 # Cycles before triggering judge
|
threshold: 3 # Cycles before triggering judge
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: "Evaluate if the fix loop is making progress..."
|
instruction: "Evaluate if the fix loop is making progress..."
|
||||||
rules:
|
rules:
|
||||||
- condition: "Progress is being made"
|
- condition: "Progress is being made"
|
||||||
next: fix
|
next: fix
|
||||||
@ -342,7 +342,7 @@ movements:
|
|||||||
my-server:
|
my-server:
|
||||||
command: npx
|
command: npx
|
||||||
args: [-y, my-mcp-server]
|
args: [-y, my-mcp-server]
|
||||||
instruction_template: |
|
instruction: |
|
||||||
Custom instructions for this movement.
|
Custom instructions for this movement.
|
||||||
{task}, {previous_response} are auto-injected if not present as placeholders.
|
{task}, {previous_response} are auto-injected if not present as placeholders.
|
||||||
pass_previous_response: true # Default: true
|
pass_previous_response: true # Default: true
|
||||||
@ -413,7 +413,7 @@ movements:
|
|||||||
part_edit: true # Edit permission for parts
|
part_edit: true # Edit permission for parts
|
||||||
part_permission_mode: edit # Permission mode for parts
|
part_permission_mode: edit # Permission mode for parts
|
||||||
part_allowed_tools: [Read, Glob, Grep, Edit, Write, Bash]
|
part_allowed_tools: [Read, Glob, Grep, Edit, Write, Bash]
|
||||||
instruction_template: |
|
instruction: |
|
||||||
Decompose this task into independent subtasks.
|
Decompose this task into independent subtasks.
|
||||||
rules:
|
rules:
|
||||||
- condition: "All parts completed"
|
- condition: "All parts completed"
|
||||||
@ -549,7 +549,7 @@ Key rules:
|
|||||||
- Policy REJECT lists are what reviewers enforce. If a criterion is not in the policy REJECT list, reviewers will not catch it — even if knowledge explains the reasoning
|
- Policy REJECT lists are what reviewers enforce. If a criterion is not in the policy REJECT list, reviewers will not catch it — even if knowledge explains the reasoning
|
||||||
- Knowledge provides the WHY behind policy criteria. Knowledge alone does not trigger enforcement
|
- Knowledge provides the WHY behind policy criteria. Knowledge alone does not trigger enforcement
|
||||||
- Instructions are bound to a single piece movement. They reference procedures, not principles
|
- Instructions are bound to a single piece movement. They reference procedures, not principles
|
||||||
- Piece YAML `instruction_template` is for movement-specific details (which reports to read, movement routing, output templates)
|
- Piece YAML `instruction` is for movement-specific details (which reports to read, movement routing, output templates)
|
||||||
|
|
||||||
**Separation of concerns in piece engine:**
|
**Separation of concerns in piece engine:**
|
||||||
- `PieceEngine` - Orchestration, state management, event emission
|
- `PieceEngine` - Orchestration, state management, event emission
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: converging (findings decreasing, fixes applied)
|
- condition: converging (findings decreasing, fixes applied)
|
||||||
next: fix_both
|
next: fix_both
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: Healthy (progress being made)
|
- condition: Healthy (progress being made)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: converging (findings decreasing, fixes applied)
|
- condition: converging (findings decreasing, fixes applied)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: converging (findings decreasing, fixes applied)
|
- condition: converging (findings decreasing, fixes applied)
|
||||||
next: fix_both
|
next: fix_both
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: Healthy (progress being made)
|
- condition: Healthy (progress being made)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: converging (findings decreasing, fixes applied)
|
- condition: converging (findings decreasing, fixes applied)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -108,7 +108,7 @@ movements:
|
|||||||
rules:
|
rules:
|
||||||
- condition: synthesis complete
|
- condition: synthesis complete
|
||||||
next: COMPLETE
|
next: COMPLETE
|
||||||
instruction_template: |
|
instruction: |
|
||||||
Two models (Claude / Codex) independently answered the same instruction.
|
Two models (Claude / Codex) independently answered the same instruction.
|
||||||
Synthesize their responses.
|
Synthesize their responses.
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: |
|
instruction: |
|
||||||
The ai_review ↔ ai_fix loop has repeated {cycle_count} times.
|
The ai_review ↔ ai_fix loop has repeated {cycle_count} times.
|
||||||
|
|
||||||
Review the reports from each cycle and determine whether this loop
|
Review the reports from each cycle and determine whether this loop
|
||||||
@ -39,7 +39,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: converging (findings decreasing, fixes applied)
|
- condition: converging (findings decreasing, fixes applied)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: converging (findings decreasing, fixes applied)
|
- condition: converging (findings decreasing, fixes applied)
|
||||||
next: fix_both
|
next: fix_both
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: Healthy (progress being made)
|
- condition: Healthy (progress being made)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-ai-fix
|
instruction: loop-monitor-ai-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: Healthy (making progress)
|
- condition: Healthy (making progress)
|
||||||
next: ai_review
|
next: ai_review
|
||||||
@ -27,7 +27,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: Healthy (findings decreasing, fixes applied)
|
- condition: Healthy (findings decreasing, fixes applied)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: converging (findings decreasing, fixes applied)
|
- condition: converging (findings decreasing, fixes applied)
|
||||||
next: fix_both
|
next: fix_both
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: Healthy (progress being made)
|
- condition: Healthy (progress being made)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-ai-fix
|
instruction: loop-monitor-ai-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: Healthy (making progress)
|
- condition: Healthy (making progress)
|
||||||
next: ai_review
|
next: ai_review
|
||||||
@ -27,7 +27,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: converging (findings decreasing, fixes applied)
|
- condition: converging (findings decreasing, fixes applied)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: |
|
instruction: |
|
||||||
The ai_review ↔ ai_fix loop has repeated {cycle_count} times.
|
The ai_review ↔ ai_fix loop has repeated {cycle_count} times.
|
||||||
|
|
||||||
Review the reports from each cycle and determine whether this loop
|
Review the reports from each cycle and determine whether this loop
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: converging (findings decreasing, fixes applied)
|
- condition: converging (findings decreasing, fixes applied)
|
||||||
next: fix_both
|
next: fix_both
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: Healthy (progress being made)
|
- condition: Healthy (progress being made)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: converging (findings decreasing, fixes applied)
|
- condition: converging (findings decreasing, fixes applied)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -18,7 +18,7 @@ initial_movement: melchior
|
|||||||
movements:
|
movements:
|
||||||
- name: melchior
|
- name: melchior
|
||||||
persona: melchior
|
persona: melchior
|
||||||
instruction_template: |
|
instruction: |
|
||||||
# MAGI System Initiated
|
# MAGI System Initiated
|
||||||
|
|
||||||
## Matter for Deliberation
|
## Matter for Deliberation
|
||||||
@ -48,7 +48,7 @@ movements:
|
|||||||
next: balthasar
|
next: balthasar
|
||||||
- name: balthasar
|
- name: balthasar
|
||||||
persona: balthasar
|
persona: balthasar
|
||||||
instruction_template: |
|
instruction: |
|
||||||
# MAGI System Continuing
|
# MAGI System Continuing
|
||||||
|
|
||||||
## Matter for Deliberation
|
## Matter for Deliberation
|
||||||
@ -82,7 +82,7 @@ movements:
|
|||||||
next: casper
|
next: casper
|
||||||
- name: casper
|
- name: casper
|
||||||
persona: casper
|
persona: casper
|
||||||
instruction_template: |
|
instruction: |
|
||||||
# MAGI System Final Deliberation
|
# MAGI System Final Deliberation
|
||||||
|
|
||||||
## Matter for Deliberation
|
## Matter for Deliberation
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: Healthy (progress being made)
|
- condition: Healthy (progress being made)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -177,7 +177,7 @@ movements:
|
|||||||
rules:
|
rules:
|
||||||
- condition: Review synthesis complete
|
- condition: Review synthesis complete
|
||||||
next: COMPLETE
|
next: COMPLETE
|
||||||
instruction_template: |
|
instruction: |
|
||||||
## Review Results
|
## Review Results
|
||||||
{previous_response}
|
{previous_response}
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: Healthy (progress being made)
|
- condition: Healthy (progress being made)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-ai-fix
|
instruction: loop-monitor-ai-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: Healthy (making progress)
|
- condition: Healthy (making progress)
|
||||||
next: ai_review
|
next: ai_review
|
||||||
@ -27,7 +27,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: Healthy (findings decreasing, fixes applied)
|
- condition: Healthy (findings decreasing, fixes applied)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: |
|
instruction: |
|
||||||
The ai_review ↔ ai_fix loop has repeated {cycle_count} times.
|
The ai_review ↔ ai_fix loop has repeated {cycle_count} times.
|
||||||
|
|
||||||
Review the reports from each cycle and determine whether this loop
|
Review the reports from each cycle and determine whether this loop
|
||||||
@ -39,7 +39,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: Healthy (findings decreasing, fixes applied)
|
- condition: Healthy (findings decreasing, fixes applied)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -265,7 +265,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: |
|
instruction: |
|
||||||
The review → fix cycle has repeated {cycle_count} times.
|
The review → fix cycle has repeated {cycle_count} times.
|
||||||
Check the review report history in the Report Directory and assess convergence.
|
Check the review report history in the Report Directory and assess convergence.
|
||||||
|
|
||||||
@ -282,7 +282,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: |
|
instruction: |
|
||||||
The AI fix → review cycle has repeated {cycle_count} times.
|
The AI fix → review cycle has repeated {cycle_count} times.
|
||||||
Check the review report history in the Report Directory and assess convergence.
|
Check the review report history in the Report Directory and assess convergence.
|
||||||
|
|
||||||
@ -299,7 +299,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: |
|
instruction: |
|
||||||
The supervisor fix → review cycle has repeated {cycle_count} times.
|
The supervisor fix → review cycle has repeated {cycle_count} times.
|
||||||
Check the review report history in the Report Directory and assess convergence.
|
Check the review report history in the Report Directory and assess convergence.
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: |
|
instruction: |
|
||||||
The ai_review ↔ ai_fix loop has repeated {cycle_count} times.
|
The ai_review ↔ ai_fix loop has repeated {cycle_count} times.
|
||||||
|
|
||||||
Review the reports from each cycle and determine whether this loop
|
Review the reports from each cycle and determine whether this loop
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: 健全(指摘数が減少、修正が反映されている)
|
- condition: 健全(指摘数が減少、修正が反映されている)
|
||||||
next: fix_both
|
next: fix_both
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: 健全(進捗あり)
|
- condition: 健全(進捗あり)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: 健全(指摘数が減少、修正が反映されている)
|
- condition: 健全(指摘数が減少、修正が反映されている)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: 健全(指摘数が減少、修正が反映されている)
|
- condition: 健全(指摘数が減少、修正が反映されている)
|
||||||
next: fix_both
|
next: fix_both
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: 健全(進捗あり)
|
- condition: 健全(進捗あり)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: 健全(指摘数が減少、修正が反映されている)
|
- condition: 健全(指摘数が減少、修正が反映されている)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -106,7 +106,7 @@ movements:
|
|||||||
rules:
|
rules:
|
||||||
- condition: 統合完了
|
- condition: 統合完了
|
||||||
next: COMPLETE
|
next: COMPLETE
|
||||||
instruction_template: |
|
instruction: |
|
||||||
2つのモデル(Claude / Codex)が同じ指示に対して独立に回答しました。
|
2つのモデル(Claude / Codex)が同じ指示に対して独立に回答しました。
|
||||||
両者の回答を統合してください。
|
両者の回答を統合してください。
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: |
|
instruction: |
|
||||||
ai_review と ai_fix のループが {cycle_count} 回繰り返されました。
|
ai_review と ai_fix のループが {cycle_count} 回繰り返されました。
|
||||||
|
|
||||||
各サイクルのレポートを確認し、このループが健全(進捗がある)か、
|
各サイクルのレポートを確認し、このループが健全(進捗がある)か、
|
||||||
@ -39,7 +39,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: 健全(指摘数が減少、修正が反映されている)
|
- condition: 健全(指摘数が減少、修正が反映されている)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: 健全(指摘数が減少、修正が反映されている)
|
- condition: 健全(指摘数が減少、修正が反映されている)
|
||||||
next: fix_both
|
next: fix_both
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: 健全(進捗あり)
|
- condition: 健全(進捗あり)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-ai-fix
|
instruction: loop-monitor-ai-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: 健全(進捗あり)
|
- condition: 健全(進捗あり)
|
||||||
next: ai_review
|
next: ai_review
|
||||||
@ -27,7 +27,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: 健全(指摘数が減少、修正が反映されている)
|
- condition: 健全(指摘数が減少、修正が反映されている)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: 健全(指摘数が減少、修正が反映されている)
|
- condition: 健全(指摘数が減少、修正が反映されている)
|
||||||
next: fix_both
|
next: fix_both
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: 健全(進捗あり)
|
- condition: 健全(進捗あり)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-ai-fix
|
instruction: loop-monitor-ai-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: 健全(進捗あり)
|
- condition: 健全(進捗あり)
|
||||||
next: ai_review
|
next: ai_review
|
||||||
@ -27,7 +27,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: 健全(指摘数が減少、修正が反映されている)
|
- condition: 健全(指摘数が減少、修正が反映されている)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: |
|
instruction: |
|
||||||
ai_review と ai_fix のループが {cycle_count} 回繰り返されました。
|
ai_review と ai_fix のループが {cycle_count} 回繰り返されました。
|
||||||
|
|
||||||
各サイクルのレポートを確認し、このループが健全(進捗がある)か、
|
各サイクルのレポートを確認し、このループが健全(進捗がある)か、
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: 健全(指摘数が減少、修正が反映されている)
|
- condition: 健全(指摘数が減少、修正が反映されている)
|
||||||
next: fix_both
|
next: fix_both
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: 健全(進捗あり)
|
- condition: 健全(進捗あり)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: 健全(指摘数が減少、修正が反映されている)
|
- condition: 健全(指摘数が減少、修正が反映されている)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -18,7 +18,7 @@ initial_movement: melchior
|
|||||||
movements:
|
movements:
|
||||||
- name: melchior
|
- name: melchior
|
||||||
persona: melchior
|
persona: melchior
|
||||||
instruction_template: |
|
instruction: |
|
||||||
# MAGI System 起動
|
# MAGI System 起動
|
||||||
|
|
||||||
## 審議事項
|
## 審議事項
|
||||||
@ -48,7 +48,7 @@ movements:
|
|||||||
next: balthasar
|
next: balthasar
|
||||||
- name: balthasar
|
- name: balthasar
|
||||||
persona: balthasar
|
persona: balthasar
|
||||||
instruction_template: |
|
instruction: |
|
||||||
# MAGI System 継続
|
# MAGI System 継続
|
||||||
|
|
||||||
## 審議事項
|
## 審議事項
|
||||||
@ -82,7 +82,7 @@ movements:
|
|||||||
next: casper
|
next: casper
|
||||||
- name: casper
|
- name: casper
|
||||||
persona: casper
|
persona: casper
|
||||||
instruction_template: |
|
instruction: |
|
||||||
# MAGI System 最終審議
|
# MAGI System 最終審議
|
||||||
|
|
||||||
## 審議事項
|
## 審議事項
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: 健全(進捗あり)
|
- condition: 健全(進捗あり)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -177,7 +177,7 @@ movements:
|
|||||||
rules:
|
rules:
|
||||||
- condition: レビュー統合完了
|
- condition: レビュー統合完了
|
||||||
next: COMPLETE
|
next: COMPLETE
|
||||||
instruction_template: |
|
instruction: |
|
||||||
## レビュー結果
|
## レビュー結果
|
||||||
{previous_response}
|
{previous_response}
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: 健全(進捗あり)
|
- condition: 健全(進捗あり)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-ai-fix
|
instruction: loop-monitor-ai-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: 健全(進捗あり)
|
- condition: 健全(進捗あり)
|
||||||
next: ai_review
|
next: ai_review
|
||||||
@ -27,7 +27,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: 健全(指摘数が減少、修正が反映されている)
|
- condition: 健全(指摘数が減少、修正が反映されている)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: |
|
instruction: |
|
||||||
ai_review と ai_fix のループが {cycle_count} 回繰り返されました。
|
ai_review と ai_fix のループが {cycle_count} 回繰り返されました。
|
||||||
|
|
||||||
各サイクルのレポートを確認し、このループが健全(進捗がある)か、
|
各サイクルのレポートを確認し、このループが健全(進捗がある)か、
|
||||||
@ -39,7 +39,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: loop-monitor-reviewers-fix
|
instruction: loop-monitor-reviewers-fix
|
||||||
rules:
|
rules:
|
||||||
- condition: 健全(指摘数が減少、修正が反映されている)
|
- condition: 健全(指摘数が減少、修正が反映されている)
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -265,7 +265,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: |
|
instruction: |
|
||||||
レビュー → 修正のサイクルが {cycle_count} 回繰り返されました。
|
レビュー → 修正のサイクルが {cycle_count} 回繰り返されました。
|
||||||
Report Directory 内のレビューレポート履歴を確認し、収束状況を判断してください。
|
Report Directory 内のレビューレポート履歴を確認し、収束状況を判断してください。
|
||||||
|
|
||||||
@ -282,7 +282,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: |
|
instruction: |
|
||||||
AI修正 → レビューのサイクルが {cycle_count} 回繰り返されました。
|
AI修正 → レビューのサイクルが {cycle_count} 回繰り返されました。
|
||||||
Report Directory 内のレビューレポート履歴を確認し、収束状況を判断してください。
|
Report Directory 内のレビューレポート履歴を確認し、収束状況を判断してください。
|
||||||
|
|
||||||
@ -299,7 +299,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: |
|
instruction: |
|
||||||
監督修正 → レビューのサイクルが {cycle_count} 回繰り返されました。
|
監督修正 → レビューのサイクルが {cycle_count} 回繰り返されました。
|
||||||
Report Directory 内のレビューレポート履歴を確認し、収束状況を判断してください。
|
Report Directory 内のレビューレポート履歴を確認し、収束状況を判断してください。
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@ loop_monitors:
|
|||||||
threshold: 3
|
threshold: 3
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor
|
persona: supervisor
|
||||||
instruction_template: |
|
instruction: |
|
||||||
ai_review と ai_fix のループが {cycle_count} 回繰り返されました。
|
ai_review と ai_fix のループが {cycle_count} 回繰り返されました。
|
||||||
|
|
||||||
各サイクルのレポートを確認し、このループが健全(進捗がある)か、
|
各サイクルのレポートを確認し、このループが健全(進捗がある)か、
|
||||||
|
|||||||
@ -47,22 +47,41 @@ movement 内では**キー名**で参照する(パスを直接書かない)
|
|||||||
- name: movement-name # movement 名(必須、一意)
|
- name: movement-name # movement 名(必須、一意)
|
||||||
persona: coder # ペルソナキー(personas マップを参照、任意)
|
persona: coder # ペルソナキー(personas マップを参照、任意)
|
||||||
policy: coding # ポリシーキー(policies マップを参照、任意)
|
policy: coding # ポリシーキー(policies マップを参照、任意)
|
||||||
policy: [coding, testing] # 複数指定も可(配列)
|
instruction: implement # 指示(instructions マップのキー参照、またはインライン、任意)
|
||||||
instruction: implement # 指示テンプレートキー(instructions マップを参照、任意)
|
|
||||||
knowledge: architecture # ナレッジキー(knowledge マップを参照、任意)
|
knowledge: architecture # ナレッジキー(knowledge マップを参照、任意)
|
||||||
edit: true # ファイル編集可否(必須)
|
edit: true # ファイル編集可否(必須)
|
||||||
required_permission_mode: edit # 必要最小権限: edit / readonly / full(任意)
|
required_permission_mode: edit # 必要最小権限: edit / readonly / full(任意)
|
||||||
session: refresh # セッション管理(任意)
|
session: refresh # セッション管理(任意)
|
||||||
pass_previous_response: true # 前の出力を渡すか(デフォルト: true)
|
pass_previous_response: true # 前の出力を渡すか(デフォルト: true)
|
||||||
allowed_tools: [...] # 許可ツール一覧(任意、参考情報)
|
allowed_tools: [...] # 許可ツール一覧(任意、参考情報)
|
||||||
instruction_template: | # 指示テンプレート(参照解決またはインライン、任意)
|
|
||||||
指示内容...
|
|
||||||
output_contracts: [...] # 出力契約設定(任意)
|
output_contracts: [...] # 出力契約設定(任意)
|
||||||
quality_gates: [...] # 品質ゲート(AIへの指示、任意)
|
quality_gates: [...] # 品質ゲート(AIへの指示、任意)
|
||||||
rules: [...] # 遷移ルール(必須)
|
rules: [...] # 遷移ルール(必須)
|
||||||
```
|
```
|
||||||
|
|
||||||
**`instruction` vs `instruction_template`**: どちらも同じ参照解決ルート(セクションマップ → パス → 3-layer facet → インライン)を使う。`instruction_template` はインライン文字列もそのまま使える。通常はどちらか一方を使用する。
|
複数ポリシー指定(配列):
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: movement-name
|
||||||
|
policy: [coding, testing]
|
||||||
|
```
|
||||||
|
|
||||||
|
参照形式:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: movement-name
|
||||||
|
instruction: implement
|
||||||
|
```
|
||||||
|
|
||||||
|
インライン形式:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: movement-name
|
||||||
|
instruction: |
|
||||||
|
指示内容...
|
||||||
|
```
|
||||||
|
|
||||||
|
**`instruction`(正式) / `instruction_template`(deprecated)**: どちらも同じ参照解決ルート(セクションマップ → パス → 3-layer facet → インライン)を使う。`instruction_template` も互換のため受理されるが、新規定義では `instruction` を使う。
|
||||||
|
|
||||||
### Parallel Movement
|
### Parallel Movement
|
||||||
|
|
||||||
@ -185,7 +204,7 @@ quality_gates:
|
|||||||
|
|
||||||
## テンプレート変数
|
## テンプレート変数
|
||||||
|
|
||||||
`instruction_template`(またはインストラクションファイル)内で使用可能な変数:
|
`instruction`(またはインストラクションファイル)内で使用可能な変数:
|
||||||
|
|
||||||
| 変数 | 説明 |
|
| 変数 | 説明 |
|
||||||
|-----|------|
|
|-----|------|
|
||||||
@ -207,7 +226,7 @@ loop_monitors:
|
|||||||
threshold: 3 # 発動閾値(サイクル回数)
|
threshold: 3 # 発動閾値(サイクル回数)
|
||||||
judge:
|
judge:
|
||||||
persona: supervisor # ペルソナキー参照
|
persona: supervisor # ペルソナキー参照
|
||||||
instruction_template: | # 判定用指示
|
instruction: | # 判定用指示
|
||||||
サイクルが {cycle_count} 回繰り返されました。
|
サイクルが {cycle_count} 回繰り返されました。
|
||||||
健全性を判断してください。
|
健全性を判断してください。
|
||||||
rules:
|
rules:
|
||||||
|
|||||||
@ -35,7 +35,7 @@ function makeSubMovement(name: string, conditions: string[]): PieceMovement {
|
|||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
personaDisplayName: name,
|
personaDisplayName: name,
|
||||||
instructionTemplate: '',
|
instruction: '',
|
||||||
passPreviousResponse: false,
|
passPreviousResponse: false,
|
||||||
rules: conditions.map((c) => ({ condition: c })),
|
rules: conditions.map((c) => ({ condition: c })),
|
||||||
};
|
};
|
||||||
@ -48,7 +48,7 @@ function makeParentMovement(
|
|||||||
return {
|
return {
|
||||||
name: 'parent',
|
name: 'parent',
|
||||||
personaDisplayName: 'parent',
|
personaDisplayName: 'parent',
|
||||||
instructionTemplate: '',
|
instruction: '',
|
||||||
passPreviousResponse: false,
|
passPreviousResponse: false,
|
||||||
parallel,
|
parallel,
|
||||||
rules,
|
rules,
|
||||||
@ -264,7 +264,7 @@ describe('AggregateEvaluator', () => {
|
|||||||
const step: PieceMovement = {
|
const step: PieceMovement = {
|
||||||
name: 'test-movement',
|
name: 'test-movement',
|
||||||
personaDisplayName: 'tester',
|
personaDisplayName: 'tester',
|
||||||
instructionTemplate: '',
|
instruction: '',
|
||||||
passPreviousResponse: false,
|
passPreviousResponse: false,
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -77,7 +77,7 @@ describe('getBuiltinPiece', () => {
|
|||||||
|
|
||||||
const planMovement = piece!.movements.find((movement) => movement.name === 'plan');
|
const planMovement = piece!.movements.find((movement) => movement.name === 'plan');
|
||||||
expect(planMovement).toBeDefined();
|
expect(planMovement).toBeDefined();
|
||||||
expect(planMovement!.instructionTemplate).not.toBe('plan');
|
expect(planMovement!.instruction).not.toBe('plan');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return null for non-existent piece names', () => {
|
it('should return null for non-existent piece names', () => {
|
||||||
|
|||||||
@ -50,7 +50,7 @@ function createMovement(overrides: Partial<PieceMovement> = {}): PieceMovement {
|
|||||||
name: 'test-movement',
|
name: 'test-movement',
|
||||||
persona: 'coder',
|
persona: 'coder',
|
||||||
personaDisplayName: 'Coder',
|
personaDisplayName: 'Coder',
|
||||||
instructionTemplate: '',
|
instruction: '',
|
||||||
passPreviousResponse: false,
|
passPreviousResponse: false,
|
||||||
...overrides,
|
...overrides,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -32,7 +32,7 @@ function buildTeamLeaderConfig(): PieceConfig {
|
|||||||
maxMovements: 5,
|
maxMovements: 5,
|
||||||
movements: [
|
movements: [
|
||||||
makeMovement('implement', {
|
makeMovement('implement', {
|
||||||
instructionTemplate: 'Task: {task}',
|
instruction: 'Task: {task}',
|
||||||
teamLeader: {
|
teamLeader: {
|
||||||
persona: '../personas/team-leader.md',
|
persona: '../personas/team-leader.md',
|
||||||
maxParts: 3,
|
maxParts: 3,
|
||||||
|
|||||||
@ -41,7 +41,7 @@ export function makeMovement(name: string, overrides: Partial<PieceMovement> = {
|
|||||||
name,
|
name,
|
||||||
persona: `../personas/${name}.md`,
|
persona: `../personas/${name}.md`,
|
||||||
personaDisplayName: name,
|
personaDisplayName: name,
|
||||||
instructionTemplate: `Run ${name}`,
|
instruction: `Run ${name}`,
|
||||||
passPreviousResponse: true,
|
passPreviousResponse: true,
|
||||||
...overrides,
|
...overrides,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -137,7 +137,7 @@ describe('PieceEngine: worktree reportDir resolution', () => {
|
|||||||
initialMovement: 'review',
|
initialMovement: 'review',
|
||||||
movements: [
|
movements: [
|
||||||
makeMovement('review', {
|
makeMovement('review', {
|
||||||
instructionTemplate: 'Write report to {report_dir}',
|
instruction: 'Write report to {report_dir}',
|
||||||
outputContracts: [{ name: '00-review.md', format: '00-review', useJudge: true }],
|
outputContracts: [{ name: '00-review.md', format: '00-review', useJudge: true }],
|
||||||
rules: [
|
rules: [
|
||||||
makeRule('approved', 'COMPLETE'),
|
makeRule('approved', 'COMPLETE'),
|
||||||
|
|||||||
@ -520,7 +520,6 @@ describe('normalizePieceConfig with layer resolution', () => {
|
|||||||
name: 'step1',
|
name: 'step1',
|
||||||
persona: 'coder',
|
persona: 'coder',
|
||||||
instruction_template: 'implement',
|
instruction_template: 'implement',
|
||||||
instruction: '{task}',
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
@ -528,7 +527,7 @@ describe('normalizePieceConfig with layer resolution', () => {
|
|||||||
const context: FacetResolutionContext = { projectDir, lang: 'ja' };
|
const context: FacetResolutionContext = { projectDir, lang: 'ja' };
|
||||||
const config = normalizePieceConfig(raw, pieceDir, context);
|
const config = normalizePieceConfig(raw, pieceDir, context);
|
||||||
|
|
||||||
expect(config.movements[0]!.instructionTemplate).toBe('Mapped instruction template');
|
expect(config.movements[0]!.instruction).toBe('Mapped instruction template');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should resolve instruction_template by name via layer resolution', () => {
|
it('should resolve instruction_template by name via layer resolution', () => {
|
||||||
@ -543,7 +542,6 @@ describe('normalizePieceConfig with layer resolution', () => {
|
|||||||
name: 'step1',
|
name: 'step1',
|
||||||
persona: 'coder',
|
persona: 'coder',
|
||||||
instruction_template: 'implement',
|
instruction_template: 'implement',
|
||||||
instruction: '{task}',
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
@ -551,7 +549,7 @@ describe('normalizePieceConfig with layer resolution', () => {
|
|||||||
const context: FacetResolutionContext = { projectDir, lang: 'ja' };
|
const context: FacetResolutionContext = { projectDir, lang: 'ja' };
|
||||||
const config = normalizePieceConfig(raw, pieceDir, context);
|
const config = normalizePieceConfig(raw, pieceDir, context);
|
||||||
|
|
||||||
expect(config.movements[0]!.instructionTemplate).toBe('Project implement template');
|
expect(config.movements[0]!.instruction).toBe('Project implement template');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should keep inline instruction_template when no facet is found', () => {
|
it('should keep inline instruction_template when no facet is found', () => {
|
||||||
@ -564,7 +562,6 @@ Second line remains inline.`;
|
|||||||
name: 'step1',
|
name: 'step1',
|
||||||
persona: 'coder',
|
persona: 'coder',
|
||||||
instruction_template: inlineTemplate,
|
instruction_template: inlineTemplate,
|
||||||
instruction: '{task}',
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
@ -572,7 +569,7 @@ Second line remains inline.`;
|
|||||||
const context: FacetResolutionContext = { projectDir, lang: 'ja' };
|
const context: FacetResolutionContext = { projectDir, lang: 'ja' };
|
||||||
const config = normalizePieceConfig(raw, pieceDir, context);
|
const config = normalizePieceConfig(raw, pieceDir, context);
|
||||||
|
|
||||||
expect(config.movements[0]!.instructionTemplate).toBe(inlineTemplate);
|
expect(config.movements[0]!.instruction).toBe(inlineTemplate);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should resolve loop monitor judge instruction_template via layer resolution', () => {
|
it('should resolve loop monitor judge instruction_template via layer resolution', () => {
|
||||||
@ -612,6 +609,6 @@ Second line remains inline.`;
|
|||||||
const context: FacetResolutionContext = { projectDir, lang: 'ja' };
|
const context: FacetResolutionContext = { projectDir, lang: 'ja' };
|
||||||
const config = normalizePieceConfig(raw, pieceDir, context);
|
const config = normalizePieceConfig(raw, pieceDir, context);
|
||||||
|
|
||||||
expect(config.loopMonitors?.[0]?.judge.instructionTemplate).toBe('Project judge template');
|
expect(config.loopMonitors?.[0]?.judge.instruction).toBe('Project judge template');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -32,7 +32,7 @@ function createMinimalStep(template: string): PieceMovement {
|
|||||||
name: 'test-step',
|
name: 'test-step',
|
||||||
persona: 'test-agent',
|
persona: 'test-agent',
|
||||||
personaDisplayName: 'Test Agent',
|
personaDisplayName: 'Test Agent',
|
||||||
instructionTemplate: template,
|
instruction: template,
|
||||||
passPreviousResponse: false,
|
passPreviousResponse: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -63,7 +63,7 @@ function makeMovement(name: string, agentPath: string, rules: PieceRule[]): Piec
|
|||||||
persona: `./personas/${name}.md`,
|
persona: `./personas/${name}.md`,
|
||||||
personaDisplayName: name,
|
personaDisplayName: name,
|
||||||
personaPath: agentPath,
|
personaPath: agentPath,
|
||||||
instructionTemplate: '{task}',
|
instruction: '{task}',
|
||||||
passPreviousResponse: true,
|
passPreviousResponse: true,
|
||||||
rules,
|
rules,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -40,7 +40,7 @@ function makeMovement(overrides: Partial<PieceMovement> = {}): PieceMovement {
|
|||||||
name: 'test-step',
|
name: 'test-step',
|
||||||
persona: 'test-agent',
|
persona: 'test-agent',
|
||||||
personaDisplayName: 'test-step',
|
personaDisplayName: 'test-step',
|
||||||
instructionTemplate: 'Do the work.',
|
instruction: 'Do the work.',
|
||||||
passPreviousResponse: false,
|
passPreviousResponse: false,
|
||||||
rules: [
|
rules: [
|
||||||
makeRule('Done', 'COMPLETE'),
|
makeRule('Done', 'COMPLETE'),
|
||||||
@ -66,7 +66,7 @@ function makeContext(overrides: Partial<InstructionContext> = {}): InstructionCo
|
|||||||
|
|
||||||
describe('Instruction Builder IT: task auto-injection', () => {
|
describe('Instruction Builder IT: task auto-injection', () => {
|
||||||
it('should auto-inject task as "User Request" section when template has no {task}', () => {
|
it('should auto-inject task as "User Request" section when template has no {task}', () => {
|
||||||
const step = makeMovement({ instructionTemplate: 'Do the work.' });
|
const step = makeMovement({ instruction: 'Do the work.' });
|
||||||
const ctx = makeContext({ task: 'Build the login page' });
|
const ctx = makeContext({ task: 'Build the login page' });
|
||||||
|
|
||||||
const result = buildInstruction(step, ctx);
|
const result = buildInstruction(step, ctx);
|
||||||
@ -76,7 +76,7 @@ describe('Instruction Builder IT: task auto-injection', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT auto-inject task section when template contains {task}', () => {
|
it('should NOT auto-inject task section when template contains {task}', () => {
|
||||||
const step = makeMovement({ instructionTemplate: 'Here is the task: {task}' });
|
const step = makeMovement({ instruction: 'Here is the task: {task}' });
|
||||||
const ctx = makeContext({ task: 'Build the login page' });
|
const ctx = makeContext({ task: 'Build the login page' });
|
||||||
|
|
||||||
const result = buildInstruction(step, ctx);
|
const result = buildInstruction(step, ctx);
|
||||||
@ -93,7 +93,7 @@ describe('Instruction Builder IT: previous_response auto-injection', () => {
|
|||||||
it('should auto-inject previous response when passPreviousResponse is true', () => {
|
it('should auto-inject previous response when passPreviousResponse is true', () => {
|
||||||
const step = makeMovement({
|
const step = makeMovement({
|
||||||
passPreviousResponse: true,
|
passPreviousResponse: true,
|
||||||
instructionTemplate: 'Continue the work.',
|
instruction: 'Continue the work.',
|
||||||
});
|
});
|
||||||
const previousOutput: AgentResponse = {
|
const previousOutput: AgentResponse = {
|
||||||
persona: 'previous-agent',
|
persona: 'previous-agent',
|
||||||
@ -112,7 +112,7 @@ describe('Instruction Builder IT: previous_response auto-injection', () => {
|
|||||||
it('should NOT inject previous response when passPreviousResponse is false', () => {
|
it('should NOT inject previous response when passPreviousResponse is false', () => {
|
||||||
const step = makeMovement({
|
const step = makeMovement({
|
||||||
passPreviousResponse: false,
|
passPreviousResponse: false,
|
||||||
instructionTemplate: 'Do fresh work.',
|
instruction: 'Do fresh work.',
|
||||||
});
|
});
|
||||||
const previousOutput: AgentResponse = {
|
const previousOutput: AgentResponse = {
|
||||||
persona: 'previous-agent',
|
persona: 'previous-agent',
|
||||||
@ -131,7 +131,7 @@ describe('Instruction Builder IT: previous_response auto-injection', () => {
|
|||||||
it('should NOT auto-inject when template contains {previous_response}', () => {
|
it('should NOT auto-inject when template contains {previous_response}', () => {
|
||||||
const step = makeMovement({
|
const step = makeMovement({
|
||||||
passPreviousResponse: true,
|
passPreviousResponse: true,
|
||||||
instructionTemplate: '## Context\n{previous_response}\n\nDo work.',
|
instruction: '## Context\n{previous_response}\n\nDo work.',
|
||||||
});
|
});
|
||||||
const previousOutput: AgentResponse = {
|
const previousOutput: AgentResponse = {
|
||||||
persona: 'prev', status: 'done', content: 'Prior work done.', timestamp: new Date(),
|
persona: 'prev', status: 'done', content: 'Prior work done.', timestamp: new Date(),
|
||||||
@ -161,7 +161,7 @@ describe('Instruction Builder IT: user_inputs auto-injection', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT auto-inject when template contains {user_inputs}', () => {
|
it('should NOT auto-inject when template contains {user_inputs}', () => {
|
||||||
const step = makeMovement({ instructionTemplate: 'Inputs: {user_inputs}' });
|
const step = makeMovement({ instruction: 'Inputs: {user_inputs}' });
|
||||||
const ctx = makeContext({ userInputs: ['Input A'] });
|
const ctx = makeContext({ userInputs: ['Input A'] });
|
||||||
|
|
||||||
const result = buildInstruction(step, ctx);
|
const result = buildInstruction(step, ctx);
|
||||||
@ -175,7 +175,7 @@ describe('Instruction Builder IT: user_inputs auto-injection', () => {
|
|||||||
describe('Instruction Builder IT: iteration variables', () => {
|
describe('Instruction Builder IT: iteration variables', () => {
|
||||||
it('should replace {iteration}, {max_movements}, {movement_iteration} in template', () => {
|
it('should replace {iteration}, {max_movements}, {movement_iteration} in template', () => {
|
||||||
const step = makeMovement({
|
const step = makeMovement({
|
||||||
instructionTemplate: 'Iter: {iteration}/{max_movements}, movement iter: {movement_iteration}',
|
instruction: 'Iter: {iteration}/{max_movements}, movement iter: {movement_iteration}',
|
||||||
});
|
});
|
||||||
const ctx = makeContext({ iteration: 5, maxMovements: 30, movementIteration: 2 });
|
const ctx = makeContext({ iteration: 5, maxMovements: 30, movementIteration: 2 });
|
||||||
|
|
||||||
@ -198,7 +198,7 @@ describe('Instruction Builder IT: iteration variables', () => {
|
|||||||
describe('Instruction Builder IT: report_dir expansion', () => {
|
describe('Instruction Builder IT: report_dir expansion', () => {
|
||||||
it('should replace {report_dir} in template', () => {
|
it('should replace {report_dir} in template', () => {
|
||||||
const step = makeMovement({
|
const step = makeMovement({
|
||||||
instructionTemplate: 'Read the plan from {report_dir}/00-plan.md',
|
instruction: 'Read the plan from {report_dir}/00-plan.md',
|
||||||
});
|
});
|
||||||
const ctx = makeContext({ reportDir: '/tmp/test-project/.takt/runs/20250126-task/reports' });
|
const ctx = makeContext({ reportDir: '/tmp/test-project/.takt/runs/20250126-task/reports' });
|
||||||
|
|
||||||
@ -209,7 +209,7 @@ describe('Instruction Builder IT: report_dir expansion', () => {
|
|||||||
|
|
||||||
it('should replace {report:filename} with full path', () => {
|
it('should replace {report:filename} with full path', () => {
|
||||||
const step = makeMovement({
|
const step = makeMovement({
|
||||||
instructionTemplate: 'Read {report:00-plan.md} for the plan.',
|
instruction: 'Read {report:00-plan.md} for the plan.',
|
||||||
});
|
});
|
||||||
const ctx = makeContext({ reportDir: '/tmp/reports' });
|
const ctx = makeContext({ reportDir: '/tmp/reports' });
|
||||||
|
|
||||||
@ -388,7 +388,7 @@ describe('Instruction Builder IT: template injection prevention', () => {
|
|||||||
it('should escape curly braces in previous response content', () => {
|
it('should escape curly braces in previous response content', () => {
|
||||||
const step = makeMovement({
|
const step = makeMovement({
|
||||||
passPreviousResponse: true,
|
passPreviousResponse: true,
|
||||||
instructionTemplate: 'Continue.',
|
instruction: 'Continue.',
|
||||||
});
|
});
|
||||||
const ctx = makeContext({
|
const ctx = makeContext({
|
||||||
previousOutput: {
|
previousOutput: {
|
||||||
|
|||||||
@ -224,7 +224,7 @@ function makeConfig(): PieceConfig {
|
|||||||
name: 'step1',
|
name: 'step1',
|
||||||
persona: '../agents/coder.md',
|
persona: '../agents/coder.md',
|
||||||
personaDisplayName: 'coder',
|
personaDisplayName: 'coder',
|
||||||
instructionTemplate: 'Do something',
|
instruction: 'Do something',
|
||||||
passPreviousResponse: true,
|
passPreviousResponse: true,
|
||||||
rules: [
|
rules: [
|
||||||
{ condition: 'done', next: 'COMPLETE' },
|
{ condition: 'done', next: 'COMPLETE' },
|
||||||
|
|||||||
@ -66,7 +66,7 @@ function makeMovement(name: string, agentPath: string, rules: PieceRule[]): Piec
|
|||||||
persona: `./personas/${name}.md`,
|
persona: `./personas/${name}.md`,
|
||||||
personaDisplayName: name,
|
personaDisplayName: name,
|
||||||
personaPath: agentPath,
|
personaPath: agentPath,
|
||||||
instructionTemplate: '{task}',
|
instruction: '{task}',
|
||||||
passPreviousResponse: true,
|
passPreviousResponse: true,
|
||||||
rules,
|
rules,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -92,8 +92,8 @@ describe('Piece Loader IT: builtin piece loading', () => {
|
|||||||
|
|
||||||
expect(planMovement).toBeDefined();
|
expect(planMovement).toBeDefined();
|
||||||
expect(implementMovement).toBeDefined();
|
expect(implementMovement).toBeDefined();
|
||||||
expect(planMovement!.instructionTemplate).toContain('missing E2E tests');
|
expect(planMovement!.instruction).toContain('missing E2E tests');
|
||||||
expect(implementMovement!.instructionTemplate).toContain('npm run test:e2e:mock');
|
expect(implementMovement!.instruction).toContain('npm run test:e2e:mock');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load e2e-test as a builtin piece in ja locale', () => {
|
it('should load e2e-test as a builtin piece in ja locale', () => {
|
||||||
@ -110,8 +110,8 @@ describe('Piece Loader IT: builtin piece loading', () => {
|
|||||||
|
|
||||||
expect(planMovement).toBeDefined();
|
expect(planMovement).toBeDefined();
|
||||||
expect(implementMovement).toBeDefined();
|
expect(implementMovement).toBeDefined();
|
||||||
expect(planMovement!.instructionTemplate).toContain('E2Eテスト');
|
expect(planMovement!.instruction).toContain('E2Eテスト');
|
||||||
expect(implementMovement!.instructionTemplate).toContain('npm run test:e2e:mock');
|
expect(implementMovement!.instruction).toContain('npm run test:e2e:mock');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -156,6 +156,49 @@ movements:
|
|||||||
expect(config!.movements.length).toBe(1);
|
expect(config!.movements.length).toBe(1);
|
||||||
expect(config!.movements[0]!.name).toBe('start');
|
expect(config!.movements[0]!.name).toBe('start');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should propagate canonical instruction field through loader for movement and loop monitor judge', () => {
|
||||||
|
// Given: project-local piece that uses instruction on both movement and loop monitor judge
|
||||||
|
const piecesDir = join(testDir, '.takt', 'pieces');
|
||||||
|
mkdirSync(piecesDir, { recursive: true });
|
||||||
|
|
||||||
|
writeFileSync(join(piecesDir, 'instruction-canonical.yaml'), `
|
||||||
|
name: instruction-canonical
|
||||||
|
max_movements: 8
|
||||||
|
initial_movement: step1
|
||||||
|
|
||||||
|
movements:
|
||||||
|
- name: step1
|
||||||
|
instruction: "Step 1 instruction"
|
||||||
|
rules:
|
||||||
|
- condition: next
|
||||||
|
next: step2
|
||||||
|
- name: step2
|
||||||
|
instruction: "Step 2 instruction"
|
||||||
|
rules:
|
||||||
|
- condition: done
|
||||||
|
next: COMPLETE
|
||||||
|
|
||||||
|
loop_monitors:
|
||||||
|
- cycle: [step1, step2]
|
||||||
|
threshold: 2
|
||||||
|
judge:
|
||||||
|
instruction: "Judge instruction"
|
||||||
|
rules:
|
||||||
|
- condition: continue
|
||||||
|
next: step2
|
||||||
|
`);
|
||||||
|
|
||||||
|
// When: loading the piece through the integration entry point
|
||||||
|
const config = loadPiece('instruction-canonical', testDir);
|
||||||
|
|
||||||
|
// Then: canonical instruction is available on normalized movement/judge models
|
||||||
|
expect(config).not.toBeNull();
|
||||||
|
const step1 = config!.movements[0] as unknown as Record<string, unknown>;
|
||||||
|
const judge = config!.loopMonitors?.[0]?.judge as unknown as Record<string, unknown>;
|
||||||
|
expect(step1.instruction).toBe('Step 1 instruction');
|
||||||
|
expect(judge.instruction).toBe('Judge instruction');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Piece Loader IT: agent path resolution', () => {
|
describe('Piece Loader IT: agent path resolution', () => {
|
||||||
|
|||||||
@ -50,7 +50,7 @@ function makeMovement(
|
|||||||
name,
|
name,
|
||||||
persona: 'test-agent',
|
persona: 'test-agent',
|
||||||
personaDisplayName: name,
|
personaDisplayName: name,
|
||||||
instructionTemplate: '{task}',
|
instruction: '{task}',
|
||||||
passPreviousResponse: true,
|
passPreviousResponse: true,
|
||||||
rules,
|
rules,
|
||||||
parallel,
|
parallel,
|
||||||
@ -401,7 +401,7 @@ describe('Rule Evaluation IT: movements without rules', () => {
|
|||||||
name: 'step',
|
name: 'step',
|
||||||
persona: 'agent',
|
persona: 'agent',
|
||||||
personaDisplayName: 'step',
|
personaDisplayName: 'step',
|
||||||
instructionTemplate: '{task}',
|
instruction: '{task}',
|
||||||
passPreviousResponse: true,
|
passPreviousResponse: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -224,7 +224,7 @@ describe('executePiece: SIGINT handler integration', () => {
|
|||||||
name: 'step1',
|
name: 'step1',
|
||||||
persona: '../agents/coder.md',
|
persona: '../agents/coder.md',
|
||||||
personaDisplayName: 'coder',
|
personaDisplayName: 'coder',
|
||||||
instructionTemplate: 'Do something',
|
instruction: 'Do something',
|
||||||
passPreviousResponse: true,
|
passPreviousResponse: true,
|
||||||
rules: [
|
rules: [
|
||||||
{ condition: 'done', next: 'COMPLETE' },
|
{ condition: 'done', next: 'COMPLETE' },
|
||||||
|
|||||||
@ -93,7 +93,7 @@ function makeMovement(
|
|||||||
persona: './agents/agent.md',
|
persona: './agents/agent.md',
|
||||||
personaDisplayName: name,
|
personaDisplayName: name,
|
||||||
personaPath: agentPath,
|
personaPath: agentPath,
|
||||||
instructionTemplate: '{task}',
|
instruction: '{task}',
|
||||||
passPreviousResponse: true,
|
passPreviousResponse: true,
|
||||||
rules,
|
rules,
|
||||||
outputContracts: options.outputContracts,
|
outputContracts: options.outputContracts,
|
||||||
|
|||||||
@ -317,11 +317,11 @@ describe('normalizePieceConfig knowledge resolution', () => {
|
|||||||
|
|
||||||
// --- Test helpers for InstructionBuilder ---
|
// --- Test helpers for InstructionBuilder ---
|
||||||
|
|
||||||
function createMinimalStep(instructionTemplate: string): PieceMovement {
|
function createMinimalStep(instruction: string): PieceMovement {
|
||||||
return {
|
return {
|
||||||
name: 'test-step',
|
name: 'test-step',
|
||||||
personaDisplayName: 'coder',
|
personaDisplayName: 'coder',
|
||||||
instructionTemplate,
|
instruction,
|
||||||
passPreviousResponse: false,
|
passPreviousResponse: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ function createMovement(overrides: Partial<PieceMovement> = {}): PieceMovement {
|
|||||||
return {
|
return {
|
||||||
name: 'reviewers',
|
name: 'reviewers',
|
||||||
personaDisplayName: 'Reviewers',
|
personaDisplayName: 'Reviewers',
|
||||||
instructionTemplate: 'review',
|
instruction: 'review',
|
||||||
passPreviousResponse: false,
|
passPreviousResponse: false,
|
||||||
...overrides,
|
...overrides,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -8,7 +8,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { describe, it, expect } from 'vitest';
|
import { describe, it, expect } from 'vitest';
|
||||||
import { PieceConfigRawSchema, ParallelSubMovementRawSchema, PieceMovementRawSchema } from '../core/models/index.js';
|
import {
|
||||||
|
PieceConfigRawSchema,
|
||||||
|
ParallelSubMovementRawSchema,
|
||||||
|
PieceMovementRawSchema,
|
||||||
|
LoopMonitorJudgeSchema,
|
||||||
|
} from '../core/models/index.js';
|
||||||
|
|
||||||
describe('ParallelSubMovementRawSchema', () => {
|
describe('ParallelSubMovementRawSchema', () => {
|
||||||
it('should validate a valid parallel sub-movement', () => {
|
it('should validate a valid parallel sub-movement', () => {
|
||||||
@ -32,6 +37,39 @@ describe('ParallelSubMovementRawSchema', () => {
|
|||||||
expect(result.success).toBe(true);
|
expect(result.success).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should accept a sub-movement with instruction field', () => {
|
||||||
|
// Given: a parallel sub-movement that uses the new canonical field
|
||||||
|
const raw = {
|
||||||
|
name: 'no-agent-step',
|
||||||
|
instruction: 'Do something',
|
||||||
|
};
|
||||||
|
|
||||||
|
// When: validating the sub-movement schema
|
||||||
|
const result = ParallelSubMovementRawSchema.safeParse(raw);
|
||||||
|
|
||||||
|
// Then: it is accepted
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should accept a sub-movement when instruction and instruction_template are both provided', () => {
|
||||||
|
// Given: both canonical and deprecated fields are present during migration
|
||||||
|
const raw = {
|
||||||
|
name: 'dual-field-sub-step',
|
||||||
|
instruction: 'Canonical instruction',
|
||||||
|
instruction_template: 'Legacy instruction',
|
||||||
|
};
|
||||||
|
|
||||||
|
// When: validating the sub-movement schema
|
||||||
|
const result = ParallelSubMovementRawSchema.safeParse(raw);
|
||||||
|
|
||||||
|
// Then: schema keeps backward compatibility and accepts both fields
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
if (result.success) {
|
||||||
|
expect((result.data as unknown as Record<string, unknown>).instruction).toBe('Canonical instruction');
|
||||||
|
expect((result.data as unknown as Record<string, unknown>).instruction_template).toBe('Legacy instruction');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('should accept optional fields', () => {
|
it('should accept optional fields', () => {
|
||||||
const raw = {
|
const raw = {
|
||||||
name: 'full-sub-step',
|
name: 'full-sub-step',
|
||||||
@ -144,6 +182,39 @@ describe('PieceMovementRawSchema with parallel', () => {
|
|||||||
expect(result.success).toBe(true);
|
expect(result.success).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should accept a movement with instruction only', () => {
|
||||||
|
// Given: a movement that only uses instruction
|
||||||
|
const raw = {
|
||||||
|
name: 'orphan-step',
|
||||||
|
instruction: 'Do something',
|
||||||
|
};
|
||||||
|
|
||||||
|
// When: validating the movement schema
|
||||||
|
const result = PieceMovementRawSchema.safeParse(raw);
|
||||||
|
|
||||||
|
// Then: it is accepted
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should accept a movement when instruction and instruction_template are both provided', () => {
|
||||||
|
// Given: movement includes both canonical and deprecated instruction fields
|
||||||
|
const raw = {
|
||||||
|
name: 'orphan-step',
|
||||||
|
instruction: 'Canonical movement instruction',
|
||||||
|
instruction_template: 'Legacy movement instruction',
|
||||||
|
};
|
||||||
|
|
||||||
|
// When: validating the movement schema
|
||||||
|
const result = PieceMovementRawSchema.safeParse(raw);
|
||||||
|
|
||||||
|
// Then: schema accepts both fields for deprecation window
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
if (result.success) {
|
||||||
|
expect((result.data as unknown as Record<string, unknown>).instruction).toBe('Canonical movement instruction');
|
||||||
|
expect((result.data as unknown as Record<string, unknown>).instruction_template).toBe('Legacy movement instruction');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('should accept a movement with persona (no parallel)', () => {
|
it('should accept a movement with persona (no parallel)', () => {
|
||||||
const raw = {
|
const raw = {
|
||||||
name: 'normal-step',
|
name: 'normal-step',
|
||||||
@ -182,6 +253,46 @@ describe('PieceMovementRawSchema with parallel', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('LoopMonitorJudgeSchema', () => {
|
||||||
|
it('should accept judge configuration with instruction field', () => {
|
||||||
|
// Given: a loop monitor judge with canonical instruction
|
||||||
|
const raw = {
|
||||||
|
persona: 'reviewer',
|
||||||
|
instruction: 'Judge loop health',
|
||||||
|
rules: [{ condition: 'continue', next: 'ai_fix' }],
|
||||||
|
};
|
||||||
|
|
||||||
|
// When: validating judge schema
|
||||||
|
const result = LoopMonitorJudgeSchema.safeParse(raw);
|
||||||
|
|
||||||
|
// Then: it is accepted
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
if (result.success) {
|
||||||
|
expect((result.data as unknown as Record<string, unknown>).instruction).toBe('Judge loop health');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should accept judge configuration during deprecation window when both fields exist', () => {
|
||||||
|
// Given: judge config with both new and deprecated fields
|
||||||
|
const raw = {
|
||||||
|
persona: 'reviewer',
|
||||||
|
instruction: 'Judge loop health',
|
||||||
|
instruction_template: 'legacy judge instruction',
|
||||||
|
rules: [{ condition: 'continue', next: 'ai_fix' }],
|
||||||
|
};
|
||||||
|
|
||||||
|
// When: validating judge schema
|
||||||
|
const result = LoopMonitorJudgeSchema.safeParse(raw);
|
||||||
|
|
||||||
|
// Then: it is accepted for backward compatibility
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
if (result.success) {
|
||||||
|
expect((result.data as unknown as Record<string, unknown>).instruction).toBe('Judge loop health');
|
||||||
|
expect((result.data as unknown as Record<string, unknown>).instruction_template).toBe('legacy judge instruction');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('PieceConfigRawSchema with parallel movements', () => {
|
describe('PieceConfigRawSchema with parallel movements', () => {
|
||||||
it('should validate a piece with parallel movement', () => {
|
it('should validate a piece with parallel movement', () => {
|
||||||
const raw = {
|
const raw = {
|
||||||
|
|||||||
@ -17,7 +17,7 @@ function createStep(fileName: string): PieceMovement {
|
|||||||
return {
|
return {
|
||||||
name: 'reviewers',
|
name: 'reviewers',
|
||||||
personaDisplayName: 'Reviewers',
|
personaDisplayName: 'Reviewers',
|
||||||
instructionTemplate: 'review',
|
instruction: 'review',
|
||||||
passPreviousResponse: false,
|
passPreviousResponse: false,
|
||||||
outputContracts: [{ name: fileName }],
|
outputContracts: [{ name: fileName }],
|
||||||
};
|
};
|
||||||
|
|||||||
@ -49,7 +49,7 @@ const { MockPieceEngine } = vi.hoisted(() => {
|
|||||||
return { status: 'aborted', iteration: 1 };
|
return { status: 'aborted', iteration: 1 };
|
||||||
}
|
}
|
||||||
if (firstStep) {
|
if (firstStep) {
|
||||||
this.emit('movement:start', firstStep, 1, firstStep.instructionTemplate, { provider: undefined, model: undefined });
|
this.emit('movement:start', firstStep, 1, firstStep.instruction, { provider: undefined, model: undefined });
|
||||||
}
|
}
|
||||||
this.emit('piece:complete', { status: 'completed', iteration: 1 });
|
this.emit('piece:complete', { status: 'completed', iteration: 1 });
|
||||||
return { status: 'completed', iteration: 1 };
|
return { status: 'completed', iteration: 1 };
|
||||||
@ -171,7 +171,7 @@ function makeConfig(): PieceConfig {
|
|||||||
name: 'implement',
|
name: 'implement',
|
||||||
persona: '../agents/coder.md',
|
persona: '../agents/coder.md',
|
||||||
personaDisplayName: 'coder',
|
personaDisplayName: 'coder',
|
||||||
instructionTemplate: 'Implement task',
|
instruction: 'Implement task',
|
||||||
passPreviousResponse: true,
|
passPreviousResponse: true,
|
||||||
rules: [{ condition: 'done', next: 'COMPLETE' }],
|
rules: [{ condition: 'done', next: 'COMPLETE' }],
|
||||||
},
|
},
|
||||||
|
|||||||
@ -236,7 +236,7 @@ describe('executePiece debug prompts logging', () => {
|
|||||||
name: 'implement',
|
name: 'implement',
|
||||||
persona: '../agents/coder.md',
|
persona: '../agents/coder.md',
|
||||||
personaDisplayName: 'coder',
|
personaDisplayName: 'coder',
|
||||||
instructionTemplate: 'Implement task',
|
instruction: 'Implement task',
|
||||||
passPreviousResponse: true,
|
passPreviousResponse: true,
|
||||||
rules: [{ condition: 'done', next: 'COMPLETE' }],
|
rules: [{ condition: 'done', next: 'COMPLETE' }],
|
||||||
},
|
},
|
||||||
|
|||||||
@ -77,7 +77,7 @@ const {
|
|||||||
const firstStep = this.config.movements[0];
|
const firstStep = this.config.movements[0];
|
||||||
if (firstStep) {
|
if (firstStep) {
|
||||||
const providerInfo = resolveProviderInfo(firstStep, this.receivedOptions);
|
const providerInfo = resolveProviderInfo(firstStep, this.receivedOptions);
|
||||||
this.emit('movement:start', firstStep, 1, firstStep.instructionTemplate, providerInfo);
|
this.emit('movement:start', firstStep, 1, firstStep.instruction, providerInfo);
|
||||||
this.emit('movement:complete', firstStep, {
|
this.emit('movement:complete', firstStep, {
|
||||||
persona: firstStep.personaDisplayName,
|
persona: firstStep.personaDisplayName,
|
||||||
status: 'done',
|
status: 'done',
|
||||||
@ -85,7 +85,7 @@ const {
|
|||||||
timestamp: new Date('2026-03-04T00:00:00.000Z'),
|
timestamp: new Date('2026-03-04T00:00:00.000Z'),
|
||||||
sessionId: 'movement-session',
|
sessionId: 'movement-session',
|
||||||
providerUsage: mockMovementResponse.providerUsage,
|
providerUsage: mockMovementResponse.providerUsage,
|
||||||
}, firstStep.instructionTemplate);
|
}, firstStep.instruction);
|
||||||
}
|
}
|
||||||
this.emit('piece:complete', { status: 'completed', iteration: 1 });
|
this.emit('piece:complete', { status: 'completed', iteration: 1 });
|
||||||
return { status: 'completed', iteration: 1 };
|
return { status: 'completed', iteration: 1 };
|
||||||
@ -230,7 +230,7 @@ function makeConfig(): PieceConfig {
|
|||||||
name: 'implement',
|
name: 'implement',
|
||||||
persona: '../agents/coder.md',
|
persona: '../agents/coder.md',
|
||||||
personaDisplayName: 'coder',
|
personaDisplayName: 'coder',
|
||||||
instructionTemplate: 'Implement task',
|
instruction: 'Implement task',
|
||||||
passPreviousResponse: true,
|
passPreviousResponse: true,
|
||||||
rules: [{ condition: 'done', next: 'COMPLETE' }],
|
rules: [{ condition: 'done', next: 'COMPLETE' }],
|
||||||
},
|
},
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
* - File-based policy content loading via resolveContentPath
|
* - File-based policy content loading via resolveContentPath
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
||||||
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
|
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
|
||||||
import { join } from 'node:path';
|
import { join } from 'node:path';
|
||||||
import { tmpdir } from 'node:os';
|
import { tmpdir } from 'node:os';
|
||||||
@ -371,7 +371,7 @@ describe('InstructionBuilder policy injection', () => {
|
|||||||
const step = {
|
const step = {
|
||||||
name: 'test-step',
|
name: 'test-step',
|
||||||
personaDisplayName: 'coder',
|
personaDisplayName: 'coder',
|
||||||
instructionTemplate: 'Do the thing.',
|
instruction: 'Do the thing.',
|
||||||
passPreviousResponse: false,
|
passPreviousResponse: false,
|
||||||
policyContents: ['# Coding Policy\n\nWrite clean code.'],
|
policyContents: ['# Coding Policy\n\nWrite clean code.'],
|
||||||
};
|
};
|
||||||
@ -390,7 +390,7 @@ describe('InstructionBuilder policy injection', () => {
|
|||||||
const step = {
|
const step = {
|
||||||
name: 'test-step',
|
name: 'test-step',
|
||||||
personaDisplayName: 'coder',
|
personaDisplayName: 'coder',
|
||||||
instructionTemplate: 'Do the thing.',
|
instruction: 'Do the thing.',
|
||||||
passPreviousResponse: false,
|
passPreviousResponse: false,
|
||||||
policyContents: ['# Coding Policy\n\nWrite clean code.'],
|
policyContents: ['# Coding Policy\n\nWrite clean code.'],
|
||||||
};
|
};
|
||||||
@ -408,7 +408,7 @@ describe('InstructionBuilder policy injection', () => {
|
|||||||
const step = {
|
const step = {
|
||||||
name: 'test-step',
|
name: 'test-step',
|
||||||
personaDisplayName: 'coder',
|
personaDisplayName: 'coder',
|
||||||
instructionTemplate: 'Do the thing.',
|
instruction: 'Do the thing.',
|
||||||
passPreviousResponse: false,
|
passPreviousResponse: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -423,7 +423,7 @@ describe('InstructionBuilder policy injection', () => {
|
|||||||
const step = {
|
const step = {
|
||||||
name: 'test-step',
|
name: 'test-step',
|
||||||
personaDisplayName: 'coder',
|
personaDisplayName: 'coder',
|
||||||
instructionTemplate: 'Do the thing.',
|
instruction: 'Do the thing.',
|
||||||
passPreviousResponse: false,
|
passPreviousResponse: false,
|
||||||
policyContents: ['Policy A content.', 'Policy B content.'],
|
policyContents: ['Policy A content.', 'Policy B content.'],
|
||||||
};
|
};
|
||||||
@ -441,7 +441,7 @@ describe('InstructionBuilder policy injection', () => {
|
|||||||
const step = {
|
const step = {
|
||||||
name: 'test-step',
|
name: 'test-step',
|
||||||
personaDisplayName: 'coder',
|
personaDisplayName: 'coder',
|
||||||
instructionTemplate: 'Do the thing.',
|
instruction: 'Do the thing.',
|
||||||
passPreviousResponse: false,
|
passPreviousResponse: false,
|
||||||
policyContents: ['Step policy.'],
|
policyContents: ['Step policy.'],
|
||||||
};
|
};
|
||||||
@ -545,7 +545,22 @@ describe('section reference resolution', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const config = normalizePieceConfig(raw, testDir);
|
const config = normalizePieceConfig(raw, testDir);
|
||||||
expect(config.movements[0]!.instructionTemplate).toBe('Implement the feature.');
|
expect(config.movements[0]!.instruction).toBe('Implement the feature.');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should expose normalized movement instruction on instruction field', () => {
|
||||||
|
const raw = {
|
||||||
|
name: 'test-piece',
|
||||||
|
movements: [{
|
||||||
|
name: 'impl',
|
||||||
|
persona: 'coder',
|
||||||
|
instruction: 'Canonical movement instruction',
|
||||||
|
}],
|
||||||
|
};
|
||||||
|
|
||||||
|
const config = normalizePieceConfig(raw, testDir);
|
||||||
|
const movement = config.movements[0] as unknown as Record<string, unknown>;
|
||||||
|
expect(movement.instruction).toBe('Canonical movement instruction');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should resolve output contract from report_formats section by name', () => {
|
it('should resolve output contract from report_formats section by name', () => {
|
||||||
@ -586,7 +601,7 @@ describe('section reference resolution', () => {
|
|||||||
expect(config.movements[0]!.persona).toBe('nonexistent');
|
expect(config.movements[0]!.persona).toBe('nonexistent');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should prefer instruction_template over instruction section reference', () => {
|
it('should prefer instruction over instruction_template when both are provided', () => {
|
||||||
const raw = {
|
const raw = {
|
||||||
name: 'test-piece',
|
name: 'test-piece',
|
||||||
instructions: { implement: './instructions/implement.md' },
|
instructions: { implement: './instructions/implement.md' },
|
||||||
@ -599,7 +614,144 @@ describe('section reference resolution', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const config = normalizePieceConfig(raw, testDir);
|
const config = normalizePieceConfig(raw, testDir);
|
||||||
expect(config.movements[0]!.instructionTemplate).toBe('Inline template takes priority.');
|
expect(config.movements[0]!.instruction).toBe('Implement the feature.');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should emit deprecation warning when movement uses instruction_template', () => {
|
||||||
|
// Given: deprecated instruction_template is used on a movement
|
||||||
|
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
||||||
|
try {
|
||||||
|
const raw = {
|
||||||
|
name: 'test-piece',
|
||||||
|
movements: [{
|
||||||
|
name: 'impl',
|
||||||
|
persona: 'coder',
|
||||||
|
instruction_template: 'Legacy movement instruction',
|
||||||
|
}],
|
||||||
|
};
|
||||||
|
|
||||||
|
// When: normalizing piece config
|
||||||
|
normalizePieceConfig(raw, testDir);
|
||||||
|
|
||||||
|
// Then: deprecation warning is emitted
|
||||||
|
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('instruction_template'));
|
||||||
|
} finally {
|
||||||
|
warnSpy.mockRestore();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should emit deprecation warning when loop monitor judge uses instruction_template', () => {
|
||||||
|
// Given: deprecated instruction_template is used on loop monitor judge
|
||||||
|
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
||||||
|
try {
|
||||||
|
const raw = {
|
||||||
|
name: 'test-piece',
|
||||||
|
movements: [
|
||||||
|
{
|
||||||
|
name: 'step1',
|
||||||
|
persona: 'coder',
|
||||||
|
instruction: '{task}',
|
||||||
|
rules: [{ condition: 'next', next: 'step2' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'step2',
|
||||||
|
persona: 'coder',
|
||||||
|
instruction: '{task}',
|
||||||
|
rules: [{ condition: 'done', next: 'COMPLETE' }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
loop_monitors: [
|
||||||
|
{
|
||||||
|
cycle: ['step1', 'step2'],
|
||||||
|
threshold: 2,
|
||||||
|
judge: {
|
||||||
|
persona: 'coder',
|
||||||
|
instruction_template: 'Legacy judge instruction',
|
||||||
|
rules: [{ condition: 'continue', next: 'step2' }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
// When: normalizing piece config
|
||||||
|
normalizePieceConfig(raw, testDir);
|
||||||
|
|
||||||
|
// Then: deprecation warning is emitted
|
||||||
|
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('instruction_template'));
|
||||||
|
} finally {
|
||||||
|
warnSpy.mockRestore();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should prefer loop monitor judge instruction over instruction_template when both are provided', () => {
|
||||||
|
const raw = {
|
||||||
|
name: 'test-piece',
|
||||||
|
instructions: { judge_template: './instructions/implement.md' },
|
||||||
|
movements: [
|
||||||
|
{
|
||||||
|
name: 'step1',
|
||||||
|
persona: 'coder',
|
||||||
|
instruction: '{task}',
|
||||||
|
rules: [{ condition: 'next', next: 'step2' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'step2',
|
||||||
|
persona: 'coder',
|
||||||
|
instruction: '{task}',
|
||||||
|
rules: [{ condition: 'done', next: 'COMPLETE' }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
loop_monitors: [
|
||||||
|
{
|
||||||
|
cycle: ['step1', 'step2'],
|
||||||
|
threshold: 2,
|
||||||
|
judge: {
|
||||||
|
persona: 'coder',
|
||||||
|
instruction: 'judge_template',
|
||||||
|
instruction_template: 'Legacy judge template',
|
||||||
|
rules: [{ condition: 'continue', next: 'step2' }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const config = normalizePieceConfig(raw, testDir);
|
||||||
|
expect(config.loopMonitors?.[0]?.judge.instruction).toBe('Implement the feature.');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should expose normalized loop monitor judge instruction on instruction field', () => {
|
||||||
|
const raw = {
|
||||||
|
name: 'test-piece',
|
||||||
|
movements: [
|
||||||
|
{
|
||||||
|
name: 'step1',
|
||||||
|
persona: 'coder',
|
||||||
|
instruction: '{task}',
|
||||||
|
rules: [{ condition: 'next', next: 'step2' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'step2',
|
||||||
|
persona: 'coder',
|
||||||
|
instruction: '{task}',
|
||||||
|
rules: [{ condition: 'done', next: 'COMPLETE' }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
loop_monitors: [
|
||||||
|
{
|
||||||
|
cycle: ['step1', 'step2'],
|
||||||
|
threshold: 2,
|
||||||
|
judge: {
|
||||||
|
persona: 'coder',
|
||||||
|
instruction: 'Canonical judge instruction',
|
||||||
|
rules: [{ condition: 'continue', next: 'step2' }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const config = normalizePieceConfig(raw, testDir);
|
||||||
|
const judge = config.loopMonitors?.[0]?.judge as unknown as Record<string, unknown>;
|
||||||
|
expect(judge.instruction).toBe('Canonical judge instruction');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should store resolved sections on PieceConfig', () => {
|
it('should store resolved sections on PieceConfig', () => {
|
||||||
@ -653,7 +805,7 @@ describe('section reference resolution', () => {
|
|||||||
const parallel = config.movements[0]!.parallel!;
|
const parallel = config.movements[0]!.parallel!;
|
||||||
expect(parallel[0]!.persona).toBe('./personas/coder.md');
|
expect(parallel[0]!.persona).toBe('./personas/coder.md');
|
||||||
expect(parallel[0]!.policyContents).toEqual(['# Coding Policy\nWrite clean code.']);
|
expect(parallel[0]!.policyContents).toEqual(['# Coding Policy\nWrite clean code.']);
|
||||||
expect(parallel[0]!.instructionTemplate).toBe('Implement the feature.');
|
expect(parallel[0]!.instruction).toBe('Implement the feature.');
|
||||||
expect(parallel[1]!.policyContents).toEqual([
|
expect(parallel[1]!.policyContents).toEqual([
|
||||||
'# Coding Policy\nWrite clean code.',
|
'# Coding Policy\nWrite clean code.',
|
||||||
'# Testing Policy\nTest everything.',
|
'# Testing Policy\nTest everything.',
|
||||||
|
|||||||
@ -17,7 +17,7 @@ function createStep(fileName: string): PieceMovement {
|
|||||||
name: 'implement',
|
name: 'implement',
|
||||||
persona: 'coder',
|
persona: 'coder',
|
||||||
personaDisplayName: 'Coder',
|
personaDisplayName: 'Coder',
|
||||||
instructionTemplate: 'Implement task',
|
instruction: 'Implement task',
|
||||||
passPreviousResponse: false,
|
passPreviousResponse: false,
|
||||||
outputContracts: [{ name: fileName }],
|
outputContracts: [{ name: fileName }],
|
||||||
};
|
};
|
||||||
|
|||||||
@ -11,7 +11,7 @@ function createMovement(overrides: Partial<PieceMovement> = {}): PieceMovement {
|
|||||||
name: 'test-movement',
|
name: 'test-movement',
|
||||||
personaDisplayName: 'test',
|
personaDisplayName: 'test',
|
||||||
edit: false,
|
edit: false,
|
||||||
instructionTemplate: '',
|
instruction: '',
|
||||||
passPreviousResponse: true,
|
passPreviousResponse: true,
|
||||||
...overrides,
|
...overrides,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -43,7 +43,7 @@ describe('runStatusJudgmentPhase', () => {
|
|||||||
name: 'review',
|
name: 'review',
|
||||||
persona: 'reviewer',
|
persona: 'reviewer',
|
||||||
personaDisplayName: 'reviewer',
|
personaDisplayName: 'reviewer',
|
||||||
instructionTemplate: 'Review',
|
instruction: 'Review',
|
||||||
passPreviousResponse: true,
|
passPreviousResponse: true,
|
||||||
rules: [
|
rules: [
|
||||||
{ condition: 'needs_fix', next: 'fix' },
|
{ condition: 'needs_fix', next: 'fix' },
|
||||||
@ -103,7 +103,7 @@ describe('runStatusJudgmentPhase', () => {
|
|||||||
name: 'review',
|
name: 'review',
|
||||||
persona: 'reviewer',
|
persona: 'reviewer',
|
||||||
personaDisplayName: 'reviewer',
|
personaDisplayName: 'reviewer',
|
||||||
instructionTemplate: 'Review',
|
instruction: 'Review',
|
||||||
passPreviousResponse: true,
|
passPreviousResponse: true,
|
||||||
rules: [
|
rules: [
|
||||||
{ condition: 'needs_fix', next: 'fix' },
|
{ condition: 'needs_fix', next: 'fix' },
|
||||||
|
|||||||
@ -9,7 +9,7 @@ describe('createPartMovement', () => {
|
|||||||
name: 'implement',
|
name: 'implement',
|
||||||
persona: 'coder',
|
persona: 'coder',
|
||||||
personaDisplayName: 'Coder',
|
personaDisplayName: 'Coder',
|
||||||
instructionTemplate: 'do work',
|
instruction: 'do work',
|
||||||
passPreviousResponse: false,
|
passPreviousResponse: false,
|
||||||
providerOptions: {
|
providerOptions: {
|
||||||
claude: {
|
claude: {
|
||||||
|
|||||||
@ -16,7 +16,7 @@ export function makeMovement(overrides: Partial<PieceMovement> = {}): PieceMovem
|
|||||||
return {
|
return {
|
||||||
name: 'test-movement',
|
name: 'test-movement',
|
||||||
personaDisplayName: 'tester',
|
personaDisplayName: 'tester',
|
||||||
instructionTemplate: '',
|
instruction: '',
|
||||||
passPreviousResponse: false,
|
passPreviousResponse: false,
|
||||||
...overrides,
|
...overrides,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -12,7 +12,7 @@ function createMovementWithRules(rules: { condition: string; next: string }[]):
|
|||||||
name: 'test-step',
|
name: 'test-step',
|
||||||
persona: 'test-agent',
|
persona: 'test-agent',
|
||||||
personaDisplayName: 'Test Agent',
|
personaDisplayName: 'Test Agent',
|
||||||
instructionTemplate: '{task}',
|
instruction: '{task}',
|
||||||
passPreviousResponse: false,
|
passPreviousResponse: false,
|
||||||
rules: rules.map((r) => ({
|
rules: rules.map((r) => ({
|
||||||
condition: r.condition,
|
condition: r.condition,
|
||||||
@ -47,7 +47,7 @@ describe('determineNextMovementByRules', () => {
|
|||||||
name: 'test-step',
|
name: 'test-step',
|
||||||
persona: 'test-agent',
|
persona: 'test-agent',
|
||||||
personaDisplayName: 'Test Agent',
|
personaDisplayName: 'Test Agent',
|
||||||
instructionTemplate: '{task}',
|
instruction: '{task}',
|
||||||
passPreviousResponse: false,
|
passPreviousResponse: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ describe('determineNextMovementByRules', () => {
|
|||||||
name: 'sub-step',
|
name: 'sub-step',
|
||||||
persona: 'test-agent',
|
persona: 'test-agent',
|
||||||
personaDisplayName: 'Test Agent',
|
personaDisplayName: 'Test Agent',
|
||||||
instructionTemplate: '{task}',
|
instruction: '{task}',
|
||||||
passPreviousResponse: false,
|
passPreviousResponse: false,
|
||||||
rules: [
|
rules: [
|
||||||
{ condition: 'approved' },
|
{ condition: 'approved' },
|
||||||
|
|||||||
@ -126,7 +126,7 @@ function buildTestPieceConfig(): PieceConfig {
|
|||||||
name: 'plan',
|
name: 'plan',
|
||||||
persona: '../personas/plan.md',
|
persona: '../personas/plan.md',
|
||||||
personaDisplayName: 'plan',
|
personaDisplayName: 'plan',
|
||||||
instructionTemplate: 'Run plan',
|
instruction: 'Run plan',
|
||||||
passPreviousResponse: true,
|
passPreviousResponse: true,
|
||||||
rules: [],
|
rules: [],
|
||||||
},
|
},
|
||||||
|
|||||||
47
src/__tests__/yaml-schema-reference.test.ts
Normal file
47
src/__tests__/yaml-schema-reference.test.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
import { readFileSync } from 'node:fs';
|
||||||
|
import { join } from 'node:path';
|
||||||
|
|
||||||
|
describe('yaml-schema reference', () => {
|
||||||
|
it('normal movement examples should not duplicate instruction keys in one movement block', () => {
|
||||||
|
const schemaPath = join(process.cwd(), 'builtins', 'skill', 'references', 'yaml-schema.md');
|
||||||
|
const schemaText = readFileSync(schemaPath, 'utf-8');
|
||||||
|
const normalSectionMatch = schemaText.match(/### 通常 Movement([\s\S]*?)### Parallel Movement/);
|
||||||
|
|
||||||
|
expect(normalSectionMatch).not.toBeNull();
|
||||||
|
const normalSection = normalSectionMatch![1];
|
||||||
|
const yamlBlocks = [...normalSection.matchAll(/```yaml\n([\s\S]*?)```/g)].map((m) => m[1]);
|
||||||
|
|
||||||
|
expect(yamlBlocks.length).toBeGreaterThan(0);
|
||||||
|
|
||||||
|
const hasDuplicatedInstruction = yamlBlocks.some((block) => {
|
||||||
|
const instructionKeys = block
|
||||||
|
.split('\n')
|
||||||
|
.filter((line) => /^ {2}instruction:\s/.test(line));
|
||||||
|
return instructionKeys.length > 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(hasDuplicatedInstruction).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('normal movement examples should not duplicate policy keys in one movement block', () => {
|
||||||
|
const schemaPath = join(process.cwd(), 'builtins', 'skill', 'references', 'yaml-schema.md');
|
||||||
|
const schemaText = readFileSync(schemaPath, 'utf-8');
|
||||||
|
const normalSectionMatch = schemaText.match(/### 通常 Movement([\s\S]*?)### Parallel Movement/);
|
||||||
|
|
||||||
|
expect(normalSectionMatch).not.toBeNull();
|
||||||
|
const normalSection = normalSectionMatch![1];
|
||||||
|
const yamlBlocks = [...normalSection.matchAll(/```yaml\n([\s\S]*?)```/g)].map((m) => m[1]);
|
||||||
|
|
||||||
|
expect(yamlBlocks.length).toBeGreaterThan(0);
|
||||||
|
|
||||||
|
const hasDuplicatedPolicy = yamlBlocks.some((block) => {
|
||||||
|
const policyKeys = block
|
||||||
|
.split('\n')
|
||||||
|
.filter((line) => /^ {2}policy:\s/.test(line));
|
||||||
|
return policyKeys.length > 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(hasDuplicatedPolicy).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -42,7 +42,7 @@ export interface OutputContractItem {
|
|||||||
format: string;
|
format: string;
|
||||||
/** Whether this report is used as input for status judgment phase (default: true) */
|
/** Whether this report is used as input for status judgment phase (default: true) */
|
||||||
useJudge?: boolean;
|
useJudge?: boolean;
|
||||||
/** Instruction prepended before instruction_template (e.g., output destination) */
|
/** Instruction prepended before movement instruction (e.g., output destination) */
|
||||||
order?: string;
|
order?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,7 +143,7 @@ export interface PieceMovement {
|
|||||||
providerOptions?: MovementProviderOptions;
|
providerOptions?: MovementProviderOptions;
|
||||||
/** Whether this movement is allowed to edit project files (true=allowed, false=prohibited, undefined=no prompt) */
|
/** Whether this movement is allowed to edit project files (true=allowed, false=prohibited, undefined=no prompt) */
|
||||||
edit?: boolean;
|
edit?: boolean;
|
||||||
instructionTemplate: string;
|
instruction: string;
|
||||||
/** Rules for movement routing */
|
/** Rules for movement routing */
|
||||||
rules?: PieceRule[];
|
rules?: PieceRule[];
|
||||||
/** Output contracts for this movement (report definitions) */
|
/** Output contracts for this movement (report definitions) */
|
||||||
@ -219,8 +219,8 @@ export interface LoopMonitorJudge {
|
|||||||
persona?: string;
|
persona?: string;
|
||||||
/** Resolved absolute path to persona prompt file (set by loader) */
|
/** Resolved absolute path to persona prompt file (set by loader) */
|
||||||
personaPath?: string;
|
personaPath?: string;
|
||||||
/** Custom instruction template for the judge (uses default if omitted) */
|
/** Custom instruction for the judge (uses default if omitted) */
|
||||||
instructionTemplate?: string;
|
instruction?: string;
|
||||||
/** Rules for the judge's decision */
|
/** Rules for the judge's decision */
|
||||||
rules: LoopMonitorRule[];
|
rules: LoopMonitorRule[];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -162,11 +162,11 @@ export const PieceProviderOptionsSchema = z.object({
|
|||||||
export const OutputContractItemSchema = z.object({
|
export const OutputContractItemSchema = z.object({
|
||||||
/** Report file name */
|
/** Report file name */
|
||||||
name: z.string().min(1),
|
name: z.string().min(1),
|
||||||
/** Instruction appended after instruction_template (e.g., output format) */
|
/** Instruction appended after movement instruction (e.g., output format) */
|
||||||
format: z.string().min(1),
|
format: z.string().min(1),
|
||||||
/** Whether this report is used as input for status judgment phase */
|
/** Whether this report is used as input for status judgment phase */
|
||||||
use_judge: z.boolean().optional().default(true),
|
use_judge: z.boolean().optional().default(true),
|
||||||
/** Instruction prepended before instruction_template (e.g., output destination) */
|
/** Instruction prepended before movement instruction (e.g., output destination) */
|
||||||
order: z.string().optional(),
|
order: z.string().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -376,7 +376,9 @@ export const LoopMonitorRuleSchema = z.object({
|
|||||||
export const LoopMonitorJudgeSchema = z.object({
|
export const LoopMonitorJudgeSchema = z.object({
|
||||||
/** Persona reference — key name from piece-level personas map, or file path */
|
/** Persona reference — key name from piece-level personas map, or file path */
|
||||||
persona: z.string().optional(),
|
persona: z.string().optional(),
|
||||||
/** Custom instruction template for the judge */
|
/** Custom judge instruction */
|
||||||
|
instruction: z.string().optional(),
|
||||||
|
/** Deprecated alias */
|
||||||
instruction_template: z.string().optional(),
|
instruction_template: z.string().optional(),
|
||||||
/** Rules for the judge's decision */
|
/** Rules for the judge's decision */
|
||||||
rules: z.array(LoopMonitorRuleSchema).min(1),
|
rules: z.array(LoopMonitorRuleSchema).min(1),
|
||||||
|
|||||||
@ -462,10 +462,10 @@ export class PieceEngine extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build the default instruction template for a loop monitor judge.
|
* Build the default instruction for a loop monitor judge.
|
||||||
* Used when the monitor config does not specify a custom instruction_template.
|
* Used when the monitor config does not specify a custom instruction.
|
||||||
*/
|
*/
|
||||||
private buildDefaultJudgeInstructionTemplate(
|
private buildDefaultJudgeInstruction(
|
||||||
monitor: LoopMonitorConfig,
|
monitor: LoopMonitorConfig,
|
||||||
cycleCount: number,
|
cycleCount: number,
|
||||||
language: string,
|
language: string,
|
||||||
@ -513,11 +513,11 @@ export class PieceEngine extends EventEmitter {
|
|||||||
cycleCount: number,
|
cycleCount: number,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const language = this.options.language ?? 'en';
|
const language = this.options.language ?? 'en';
|
||||||
const instructionTemplate = monitor.judge.instructionTemplate
|
const instruction = monitor.judge.instruction
|
||||||
?? this.buildDefaultJudgeInstructionTemplate(monitor, cycleCount, language);
|
?? this.buildDefaultJudgeInstruction(monitor, cycleCount, language);
|
||||||
|
|
||||||
// Replace {cycle_count} in custom templates
|
// Replace {cycle_count} in custom instructions
|
||||||
const processedTemplate = instructionTemplate.replace(/\{cycle_count\}/g, String(cycleCount));
|
const processedInstruction = instruction.replace(/\{cycle_count\}/g, String(cycleCount));
|
||||||
|
|
||||||
// Build a synthetic PieceMovement for the judge
|
// Build a synthetic PieceMovement for the judge
|
||||||
const judgeMovement: PieceMovement = {
|
const judgeMovement: PieceMovement = {
|
||||||
@ -531,7 +531,7 @@ export class PieceEngine extends EventEmitter {
|
|||||||
allowedTools: ['Read', 'Glob', 'Grep'],
|
allowedTools: ['Read', 'Glob', 'Grep'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
instructionTemplate: processedTemplate,
|
instruction: processedInstruction,
|
||||||
rules: monitor.judge.rules.map((r) => ({
|
rules: monitor.judge.rules.map((r) => ({
|
||||||
condition: r.condition,
|
condition: r.condition,
|
||||||
next: r.next,
|
next: r.next,
|
||||||
@ -553,7 +553,7 @@ export class PieceEngine extends EventEmitter {
|
|||||||
|
|
||||||
this.emit('movement:start', judgeMovement, this.state.iteration, prebuiltInstruction, this.optionsBuilder.resolveStepProviderModel(judgeMovement));
|
this.emit('movement:start', judgeMovement, this.state.iteration, prebuiltInstruction, this.optionsBuilder.resolveStepProviderModel(judgeMovement));
|
||||||
|
|
||||||
const { response, instruction } = await this.movementExecutor.runNormalMovement(
|
const { response, instruction: executedInstruction } = await this.movementExecutor.runNormalMovement(
|
||||||
judgeMovement,
|
judgeMovement,
|
||||||
this.state,
|
this.state,
|
||||||
this.task,
|
this.task,
|
||||||
@ -562,7 +562,7 @@ export class PieceEngine extends EventEmitter {
|
|||||||
prebuiltInstruction,
|
prebuiltInstruction,
|
||||||
);
|
);
|
||||||
this.emitCollectedReports();
|
this.emitCollectedReports();
|
||||||
this.emit('movement:complete', judgeMovement, response, instruction);
|
this.emit('movement:complete', judgeMovement, response, executedInstruction);
|
||||||
|
|
||||||
// Resolve next movement from the judge's rules
|
// Resolve next movement from the judge's rules
|
||||||
const nextMovement = this.resolveNextMovementFromDone(judgeMovement, response);
|
const nextMovement = this.resolveNextMovementFromDone(judgeMovement, response);
|
||||||
|
|||||||
@ -45,7 +45,7 @@ export function createPartMovement(step: PieceMovement, part: PartDefinition): P
|
|||||||
model: step.model,
|
model: step.model,
|
||||||
requiredPermissionMode: step.teamLeader.partPermissionMode ?? step.requiredPermissionMode,
|
requiredPermissionMode: step.teamLeader.partPermissionMode ?? step.requiredPermissionMode,
|
||||||
edit: step.teamLeader.partEdit ?? step.edit,
|
edit: step.teamLeader.partEdit ?? step.edit,
|
||||||
instructionTemplate: part.instruction,
|
instruction: part.instruction,
|
||||||
passPreviousResponse: false,
|
passPreviousResponse: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -89,7 +89,7 @@ export class InstructionBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Skip auto-injection for sections whose placeholders exist in the template
|
// Skip auto-injection for sections whose placeholders exist in the template
|
||||||
const tmpl = this.step.instructionTemplate;
|
const tmpl = this.step.instruction;
|
||||||
const hasTaskPlaceholder = tmpl.includes('{task}');
|
const hasTaskPlaceholder = tmpl.includes('{task}');
|
||||||
const hasPreviousResponsePlaceholder = tmpl.includes('{previous_response}');
|
const hasPreviousResponsePlaceholder = tmpl.includes('{previous_response}');
|
||||||
const hasUserInputsPlaceholder = tmpl.includes('{user_inputs}');
|
const hasUserInputsPlaceholder = tmpl.includes('{user_inputs}');
|
||||||
@ -120,9 +120,9 @@ export class InstructionBuilder {
|
|||||||
? escapeTemplateChars(this.context.userInputs.join('\n'))
|
? escapeTemplateChars(this.context.userInputs.join('\n'))
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
// Instructions (instruction_template processed)
|
// Instructions (movement instruction with placeholder processing)
|
||||||
const instructions = replaceTemplatePlaceholders(
|
const instructions = replaceTemplatePlaceholders(
|
||||||
this.step.instructionTemplate,
|
tmpl,
|
||||||
this.step,
|
this.step,
|
||||||
{
|
{
|
||||||
...this.context,
|
...this.context,
|
||||||
|
|||||||
@ -272,6 +272,12 @@ function normalizeStepFromRaw(
|
|||||||
const expandedInstruction = step.instruction
|
const expandedInstruction = step.instruction
|
||||||
? resolveRefToContent(step.instruction, sections.resolvedInstructions, pieceDir, 'instructions', context)
|
? resolveRefToContent(step.instruction, sections.resolvedInstructions, pieceDir, 'instructions', context)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
if (step.instruction_template !== undefined) {
|
||||||
|
console.warn(`Movement "${step.name}" uses deprecated field "instruction_template". Use "instruction" instead.`);
|
||||||
|
}
|
||||||
|
const expandedLegacyInstruction = step.instruction_template
|
||||||
|
? resolveRefToContent(step.instruction_template, sections.resolvedInstructions, pieceDir, 'instructions', context)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
const result: PieceMovement = {
|
const result: PieceMovement = {
|
||||||
name: step.name,
|
name: step.name,
|
||||||
@ -286,9 +292,7 @@ function normalizeStepFromRaw(
|
|||||||
requiredPermissionMode: step.required_permission_mode,
|
requiredPermissionMode: step.required_permission_mode,
|
||||||
providerOptions: mergeProviderOptions(inheritedProviderOptions, normalizedProvider.providerOptions),
|
providerOptions: mergeProviderOptions(inheritedProviderOptions, normalizedProvider.providerOptions),
|
||||||
edit: step.edit,
|
edit: step.edit,
|
||||||
instructionTemplate: (step.instruction_template
|
instruction: expandedInstruction || expandedLegacyInstruction || '{task}',
|
||||||
? resolveRefToContent(step.instruction_template, sections.resolvedInstructions, pieceDir, 'instructions', context)
|
|
||||||
: undefined) || expandedInstruction || '{task}',
|
|
||||||
rules,
|
rules,
|
||||||
outputContracts: normalizeOutputContracts(step.output_contracts, pieceDir, sections.resolvedReportFormats, context),
|
outputContracts: normalizeOutputContracts(step.output_contracts, pieceDir, sections.resolvedReportFormats, context),
|
||||||
qualityGates: applyQualityGateOverrides(
|
qualityGates: applyQualityGateOverrides(
|
||||||
@ -335,19 +339,25 @@ function normalizeStepFromRaw(
|
|||||||
|
|
||||||
/** Normalize a raw loop monitor judge from YAML into internal format. */
|
/** Normalize a raw loop monitor judge from YAML into internal format. */
|
||||||
function normalizeLoopMonitorJudge(
|
function normalizeLoopMonitorJudge(
|
||||||
raw: { persona?: string; instruction_template?: string; rules: Array<{ condition: string; next: string }> },
|
raw: { persona?: string; instruction?: string; instruction_template?: string; rules: Array<{ condition: string; next: string }> },
|
||||||
pieceDir: string,
|
pieceDir: string,
|
||||||
sections: PieceSections,
|
sections: PieceSections,
|
||||||
context?: FacetResolutionContext,
|
context?: FacetResolutionContext,
|
||||||
): LoopMonitorJudge {
|
): LoopMonitorJudge {
|
||||||
const { personaSpec, personaPath } = resolvePersona(raw.persona, sections, pieceDir, context);
|
const { personaSpec, personaPath } = resolvePersona(raw.persona, sections, pieceDir, context);
|
||||||
|
if (raw.instruction_template !== undefined) {
|
||||||
|
console.warn('loop_monitors judge uses deprecated field "instruction_template". Use "instruction" instead.');
|
||||||
|
}
|
||||||
|
const resolvedInstruction = raw.instruction
|
||||||
|
? resolveRefToContent(raw.instruction, sections.resolvedInstructions, pieceDir, 'instructions', context)
|
||||||
|
: raw.instruction_template
|
||||||
|
? resolveRefToContent(raw.instruction_template, sections.resolvedInstructions, pieceDir, 'instructions', context)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
persona: personaSpec,
|
persona: personaSpec,
|
||||||
personaPath,
|
personaPath,
|
||||||
instructionTemplate: raw.instruction_template
|
instruction: resolvedInstruction,
|
||||||
? resolveRefToContent(raw.instruction_template, sections.resolvedInstructions, pieceDir, 'instructions', context)
|
|
||||||
: undefined,
|
|
||||||
rules: raw.rules.map((r) => ({ condition: r.condition, next: r.next })),
|
rules: raw.rules.map((r) => ({ condition: r.condition, next: r.next })),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -356,7 +366,7 @@ function normalizeLoopMonitorJudge(
|
|||||||
* Normalize raw loop monitors from YAML into internal format.
|
* Normalize raw loop monitors from YAML into internal format.
|
||||||
*/
|
*/
|
||||||
function normalizeLoopMonitors(
|
function normalizeLoopMonitors(
|
||||||
raw: Array<{ cycle: string[]; threshold: number; judge: { persona?: string; instruction_template?: string; rules: Array<{ condition: string; next: string }> } }> | undefined,
|
raw: Array<{ cycle: string[]; threshold: number; judge: { persona?: string; instruction?: string; instruction_template?: string; rules: Array<{ condition: string; next: string }> } }> | undefined,
|
||||||
pieceDir: string,
|
pieceDir: string,
|
||||||
sections: PieceSections,
|
sections: PieceSections,
|
||||||
context?: FacetResolutionContext,
|
context?: FacetResolutionContext,
|
||||||
|
|||||||
@ -229,7 +229,7 @@ function buildMovementPreviews(piece: PieceConfig, maxCount: number): MovementPr
|
|||||||
name: movement.name,
|
name: movement.name,
|
||||||
personaDisplayName: movement.personaDisplayName,
|
personaDisplayName: movement.personaDisplayName,
|
||||||
personaContent: readMovementPersona(movement),
|
personaContent: readMovementPersona(movement),
|
||||||
instructionContent: movement.instructionTemplate,
|
instructionContent: movement.instruction,
|
||||||
allowedTools: movement.providerOptions?.claude?.allowedTools ?? [],
|
allowedTools: movement.providerOptions?.claude?.allowedTools ?? [],
|
||||||
canEdit: movement.edit === true,
|
canEdit: movement.edit === true,
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user