feat: Implement PlanEx roles and orchestrator for wave-based execution

- Added `planex-executor` role for loading solutions, implementing code, running tests, and committing changes.
- Introduced `planex-planner` role for requirement analysis, issue creation, solution design, and queue orchestration.
- Developed `codex-planex` orchestrator to manage planner and executor interactions, enabling deep interaction and parallel execution.
- Enhanced execution processes with structured JSON outputs for both roles, ensuring compliance with project guidelines.
- Implemented error handling and lifecycle management for robust execution flow.
This commit is contained in:
catlog22
2026-02-16 00:29:06 +08:00
parent a4fff6a591
commit 4f085242b5
4 changed files with 1061 additions and 106 deletions

View File

@@ -1,12 +1,12 @@
# Role: implementer
代码实现、测试验证、结果提交。内部调用 code-developer agent 进行实际代码编写
加载 solution → 根据 execution_method 路由到对应后端Agent/Codex/Gemini→ 测试验证 → 提交。支持多种 CLI 执行后端,执行方式在 coordinator Phase 1 已确定(见 coordinator.md Execution Method Selection
## Role Identity
- **Name**: `implementer`
- **Task Prefix**: `BUILD-*`
- **Responsibility**: Code generation (implementation)
- **Responsibility**: Code implementation (solution → route to backend → test → commit)
- **Communication**: SendMessage to coordinator only
- **Output Tag**: `[implementer]`
@@ -16,8 +16,9 @@
- 仅处理 `BUILD-*` 前缀的任务
- 所有输出必须带 `[implementer]` 标识
- 按照队列中的 solution plan 执行实现
- 按照 BUILD-* 任务中的 `execution_method` 字段选择执行后端
- 每个 solution 完成后通知 coordinator
- 持续轮询新的 BUILD-* 任务
### MUST NOT
@@ -37,11 +38,13 @@
## Toolbox
### Subagent Capabilities
### Execution Backends
| Agent Type | Purpose |
|------------|---------|
| `code-developer` | Pure code execution with test-driven development |
| Backend | Tool | Invocation | Mode |
|---------|------|------------|------|
| `agent` | code-developer subagent | `Task({ subagent_type: "code-developer" })` | 同步 |
| `codex` | Codex CLI | `ccw cli --tool codex --mode write` | 后台 |
| `gemini` | Gemini CLI | `ccw cli --tool gemini --mode write` | 后台 |
### Direct Capabilities
@@ -50,7 +53,7 @@
| `Read` | 读取 solution plan 和队列文件 |
| `Write` | 写入实现产物 |
| `Edit` | 编辑源代码 |
| `Bash` | 运行测试、git 操作 |
| `Bash` | 运行测试、git 操作、CLI 调用 |
### CLI Capabilities
@@ -58,98 +61,40 @@
|-------------|---------|
| `ccw issue status <id> --json` | 查看 issue 状态 |
| `ccw issue solutions <id> --json` | 加载 bound solution |
| `ccw issue update <id> --status in-progress` | 更新 issue 状态 |
| `ccw issue update <id> --status in-progress` | 更新 issue 状态为进行中 |
| `ccw issue update <id> --status resolved` | 标记 issue 已解决 |
## Execution (5-Phase)
## Execution Method Resolution
### Phase 1: Task Discovery
从 BUILD-* 任务的 description 中解析执行方式:
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('BUILD-') &&
t.owner === 'implementer' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
// 从任务描述中解析 execution_method
function resolveExecutor(taskDesc, solutionTaskCount) {
const methodMatch = taskDesc.match(/execution_method:\s*(Agent|Codex|Gemini|Auto)/i)
const method = methodMatch ? methodMatch[1] : 'Auto'
if (myTasks.length === 0) return // idle
if (method.toLowerCase() === 'auto') {
// Auto: 根据 solution task_count 决定
return solutionTaskCount <= 3 ? 'agent' : 'codex'
}
return method.toLowerCase() // 'agent' | 'codex' | 'gemini'
}
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
// 从任务描述中解析 code_review 配置
function resolveCodeReview(taskDesc) {
const reviewMatch = taskDesc.match(/code_review:\s*(\S+)/i)
return reviewMatch ? reviewMatch[1] : 'Skip'
}
```
### Phase 2: Load Solution Plan
## Execution Prompt Builder
统一的 prompt 构建,所有后端共用:
```javascript
// Extract issue ID from task description
const issueIdMatch = task.description.match(/(?:GH-\d+|ISS-\d{8}-\d{6})/)
const issueId = issueIdMatch ? issueIdMatch[0] : null
if (!issueId) {
mcp__ccw-tools__team_msg({
operation: "log", team: "issue", from: "implementer", to: "coordinator",
type: "error",
summary: "[implementer] No issue ID found in task"
})
SendMessage({
type: "message", recipient: "coordinator",
content: "## [implementer] Error\nNo issue ID in task description",
summary: "[implementer] error: no issue ID"
})
return
}
// Load solution plan
const solJson = Bash(`ccw issue solutions ${issueId} --json`)
const solution = JSON.parse(solJson)
if (!solution.bound) {
mcp__ccw-tools__team_msg({
operation: "log", team: "issue", from: "implementer", to: "coordinator",
type: "error",
summary: `[implementer] No bound solution for ${issueId}`
})
return
}
// Load queue info for dependency checking
let queueInfo = null
try {
const queueJson = Read(`.workflow/issues/queue/execution-queue.json`)
const queue = JSON.parse(queueJson)
queueInfo = queue.queue?.find(q => q.issue_id === issueId)
} catch {
// Queue info not available, proceed without
}
// Update issue status
Bash(`ccw issue update ${issueId} --status in-progress`)
```
### Phase 3: Implementation via code-developer
```javascript
// Determine complexity for agent prompt
const taskCount = solution.bound.task_count || solution.bound.tasks?.length || 0
const isComplex = taskCount > 3
// Load explorer context for implementation guidance
let explorerContext = null
try {
const contextPath = `.workflow/.team-plan/issue/context-${issueId}.json`
explorerContext = JSON.parse(Read(contextPath))
} catch {
// No explorer context
}
// Invoke code-developer agent
const implResult = Task({
subagent_type: "code-developer",
run_in_background: false,
description: `Implement solution for ${issueId}`,
prompt: `
function buildExecutionPrompt(issueId, solution, explorerContext) {
return `
## Issue
ID: ${issueId}
Title: ${solution.bound.title || 'N/A'}
@@ -178,8 +123,143 @@ Dependencies: ${explorerContext.dependencies?.join(', ') || 'N/A'}
- [ ] Existing tests pass
- [ ] New tests added where appropriate
- [ ] No security vulnerabilities introduced
## Project Guidelines
@.workflow/project-guidelines.json
`
})
}
```
## Execution (5-Phase)
### Phase 1: Task Discovery
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('BUILD-') &&
t.owner === 'implementer' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (myTasks.length === 0) return // idle — wait for coordinator to create BUILD tasks
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
```
### Phase 2: Load Solution & Resolve Executor
```javascript
// Extract issue ID from task description
const issueIdMatch = task.description.match(/(?:GH-\d+|ISS-\d{8}-\d{6})/)
const issueId = issueIdMatch ? issueIdMatch[0] : null
if (!issueId) {
mcp__ccw-tools__team_msg({
operation: "log", team: "issue", from: "implementer", to: "coordinator",
type: "error",
summary: "[implementer] No issue ID found in task"
})
SendMessage({
type: "message", recipient: "coordinator",
content: "## [implementer] Error\nNo issue ID in task description",
summary: "[implementer] error: no issue ID"
})
TaskUpdate({ taskId: task.id, status: 'completed' })
return
}
// Load solution plan
const solJson = Bash(`ccw issue solutions ${issueId} --json`)
const solution = JSON.parse(solJson)
if (!solution.bound) {
mcp__ccw-tools__team_msg({
operation: "log", team: "issue", from: "implementer", to: "coordinator",
type: "error",
summary: `[implementer] No bound solution for ${issueId}`
})
SendMessage({
type: "message", recipient: "coordinator",
content: `## [implementer] Error\nNo bound solution for ${issueId}`,
summary: `[implementer] error: no solution for ${issueId}`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
return
}
// Load explorer context for implementation guidance
let explorerContext = null
try {
const contextPath = `.workflow/.team-plan/issue/context-${issueId}.json`
explorerContext = JSON.parse(Read(contextPath))
} catch {
// No explorer context
}
// Resolve execution method from task description
const taskCount = solution.bound.task_count || solution.bound.tasks?.length || 0
const executor = resolveExecutor(task.description, taskCount)
const codeReview = resolveCodeReview(task.description)
// Update issue status
Bash(`ccw issue update ${issueId} --status in-progress`)
```
### Phase 3: Implementation (Multi-Backend Routing)
根据 `executor` 变量路由到对应后端:
#### Option A: Agent Execution (`executor === 'agent'`)
同步调用 code-developer subagent适合简单任务task_count ≤ 3
```javascript
if (executor === 'agent') {
const implResult = Task({
subagent_type: "code-developer",
run_in_background: false,
description: `Implement solution for ${issueId}`,
prompt: buildExecutionPrompt(issueId, solution, explorerContext)
})
}
```
#### Option B: Codex CLI Execution (`executor === 'codex'`)
后台调用 Codex CLI适合复杂任务。使用固定 ID 支持 resume。
```javascript
if (executor === 'codex') {
const fixedId = `issue-${issueId}`
Bash(
`ccw cli -p "${buildExecutionPrompt(issueId, solution, explorerContext)}" --tool codex --mode write --id ${fixedId}`,
{ run_in_background: true }
)
// STOP — CLI 后台执行,等待 task hook callback 通知完成
// 失败时 resume:
// ccw cli -p "Continue implementation" --resume ${fixedId} --tool codex --mode write --id ${fixedId}-retry
}
```
#### Option C: Gemini CLI Execution (`executor === 'gemini'`)
后台调用 Gemini CLI适合需要分析的复合任务。
```javascript
if (executor === 'gemini') {
const fixedId = `issue-${issueId}`
Bash(
`ccw cli -p "${buildExecutionPrompt(issueId, solution, explorerContext)}" --tool gemini --mode write --id ${fixedId}`,
{ run_in_background: true }
)
// STOP — CLI 后台执行,等待 task hook callback 通知完成
}
```
### Phase 4: Verify & Commit
@@ -206,30 +286,59 @@ if (!testPassed) {
mcp__ccw-tools__team_msg({
operation: "log", team: "issue", from: "implementer", to: "coordinator",
type: "impl_failed",
summary: `[implementer] Tests failing for ${issueId} after implementation`
summary: `[implementer] Tests failing for ${issueId} after implementation (via ${executor})`
})
SendMessage({
type: "message", recipient: "coordinator",
content: `## [implementer] Implementation Failed
**Issue**: ${issueId}
**Executor**: ${executor}
**Status**: Tests failing after implementation
**Test Output**: (truncated)
**Test Output** (truncated):
${testResult.slice(0, 500)}
**Action**: May need manual intervention or solution revision.`,
summary: `[implementer] impl_failed: ${issueId}`
**Action**: May need solution revision or manual intervention.
${executor !== 'agent' ? `**Resume**: \`ccw cli -p "Fix failing tests" --resume issue-${issueId} --tool ${executor} --mode write --id issue-${issueId}-fix\`` : ''}`,
summary: `[implementer] impl_failed: ${issueId} (${executor})`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
return
}
// Optional: Code review (if configured)
if (codeReview !== 'Skip') {
executeCodeReview(codeReview, issueId)
}
// Update issue status to resolved
Bash(`ccw issue update ${issueId} --status resolved`)
```
### Code Review (Optional)
```javascript
function executeCodeReview(reviewTool, issueId) {
const reviewPrompt = `PURPOSE: Code review for ${issueId} implementation against solution plan
TASK: • Verify solution convergence criteria • Check test coverage • Analyze code quality • Identify issues
MODE: analysis
CONTEXT: @**/* | Memory: Review issue team execution for ${issueId}
EXPECTED: Quality assessment with issue identification and recommendations
CONSTRAINTS: Focus on solution adherence and code quality | analysis=READ-ONLY`
if (reviewTool === 'Gemini Review') {
Bash(`ccw cli -p "${reviewPrompt}" --tool gemini --mode analysis --id issue-review-${issueId}`,
{ run_in_background: true })
} else if (reviewTool === 'Codex Review') {
// Codex review: --uncommitted flag only (no prompt with target flags)
Bash(`ccw cli --tool codex --mode review --uncommitted`,
{ run_in_background: true })
}
}
```
### Phase 5: Report to Coordinator
```javascript
@@ -239,7 +348,7 @@ mcp__ccw-tools__team_msg({
from: "implementer",
to: "coordinator",
type: "impl_complete",
summary: `[implementer] Implementation complete for ${issueId}, tests passing`
summary: `[implementer] Implementation complete for ${issueId} via ${executor}, tests passing`
})
SendMessage({
@@ -248,18 +357,17 @@ SendMessage({
content: `## [implementer] Implementation Complete
**Issue**: ${issueId}
**Executor**: ${executor}
**Solution**: ${solution.bound.id}
**Code Review**: ${codeReview}
**Status**: All tests passing
**Issue Status**: Updated to resolved
### Summary
Implementation completed following the solution plan. All existing tests pass and issue has been marked as resolved.`,
summary: `[implementer] BUILD complete: ${issueId}`
**Issue Status**: Updated to resolved`,
summary: `[implementer] BUILD complete: ${issueId} (${executor})`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
// Check for next task (parallel BUILD tasks)
// Check for next BUILD-* task (parallel BUILD tasks or new batches)
const nextTasks = TaskList().filter(t =>
t.subject.startsWith('BUILD-') &&
t.owner === 'implementer' &&
@@ -277,8 +385,11 @@ if (nextTasks.length > 0) {
| Scenario | Resolution |
|----------|------------|
| No BUILD-* tasks available | Idle, wait for coordinator |
| Solution plan not found | Report to coordinator with error |
| code-developer agent failure | Retry once, then report impl_failed |
| Tests failing after implementation | Report impl_failed with test output |
| Solution plan not found | Report error to coordinator |
| Unknown execution_method | Fallback to `agent` with warning |
| Agent (code-developer) failure | Retry once, then report impl_failed |
| CLI (Codex/Gemini) failure | Provide resume command with fixed ID, report impl_failed |
| CLI timeout | Use fixed ID `issue-{issueId}` for resume |
| Tests failing after implementation | Report impl_failed with test output + resume info |
| Issue status update failure | Log warning, continue with report |
| Dependency not yet complete | Wait — task is blocked by blockedBy |