revert: Restore lite-execute and schema to 196b805, keep 50k context protection

- Revert cost-aware batching and multi-agent parallelism in lite-execute
- Remove execution_group and task complexity from schema
- Remove execution_group rules from lite-plan
- Keep 50k context threshold protection in lite-plan

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
catlog22
2025-11-28 15:34:14 +08:00
parent 96dd9bef5f
commit 3e6ed5e4c3
3 changed files with 76 additions and 124 deletions

View File

@@ -149,14 +149,14 @@ Input Parsing:
Execution:
├─ Step 1: Initialize result tracking (previousExecutionResults = [])
├─ Step 2: Task grouping & batch creation (cost-aware)
│ ├─ Build hybrid dependencies (explicit depends_on + file conflicts via modification_points)
│ ├─ Phase 1: Group by execution_group (explicit parallel groups)
│ ├─ Phase 2: Cost-aware batching (MAX_BATCH_COST=8, Low=1/Medium=2/High=4)
├─ Step 2: Task grouping & batch creation
│ ├─ Extract explicit depends_on (no file/keyword inference)
│ ├─ Group: independent tasks → single parallel batch (maximize utilization)
│ ├─ Group: dependent tasks → sequential phases (respect dependencies)
│ └─ Create TodoWrite list for batches
├─ Step 3: Launch execution
│ ├─ Parallel batches: ⚡ concurrent via multiple tool calls
│ └─ Sequential batches: → one by one
│ ├─ Phase 1: All independent tasks (⚡ single batch, concurrent)
│ └─ Phase 2+: Dependent tasks by dependency order
├─ Step 4: Track progress (TodoWrite updates per batch)
└─ Step 5: Code review (if codeReviewTool ≠ "Skip")
@@ -181,96 +181,67 @@ previousExecutionResults = []
**Dependency Analysis & Grouping Algorithm**:
```javascript
const MAX_BATCH_COST = 8 // Workload limit per batch (tunable)
// Task cost based on complexity (Low=1, Medium=2, High=4)
function calculateTaskCost(task) {
const costs = { Low: 1, Medium: 2, High: 4 }
return costs[task.complexity] || 1
}
// Build hybrid dependencies: explicit depends_on + implicit file conflicts
function buildDependencies(tasks) {
// Use explicit depends_on from plan.json (no inference from file/keywords)
function extractDependencies(tasks) {
const taskIdToIndex = {}
tasks.forEach((t, i) => { taskIdToIndex[t.id] = i })
const fileOwner = {} // Track which task last modified each file
return tasks.map((task, i) => {
const deps = new Set()
// 1. Explicit depends_on
;(task.depends_on || []).forEach(depId => {
const idx = taskIdToIndex[depId]
if (idx !== undefined && idx < i) deps.add(idx)
})
// 2. Implicit file conflicts via modification_points
;(task.modification_points || []).forEach(mp => {
if (fileOwner[mp.file] !== undefined && fileOwner[mp.file] !== i) {
deps.add(fileOwner[mp.file])
}
fileOwner[mp.file] = i
})
return { ...task, taskIndex: i, dependencies: [...deps], cost: calculateTaskCost(task) }
// Only use explicit depends_on from plan.json
const deps = (task.depends_on || [])
.map(depId => taskIdToIndex[depId])
.filter(idx => idx !== undefined && idx < i)
return { ...task, taskIndex: i, dependencies: deps }
})
}
// Group into cost-aware batches with execution_group priority
// Group into batches: maximize parallel execution
function createExecutionCalls(tasks, executionMethod) {
const tasksWithDeps = buildDependencies(tasks)
const tasksWithDeps = extractDependencies(tasks)
const processed = new Set()
const calls = []
let parallelIdx = 1, sequentialIdx = 1
// Phase 1: Group by execution_group (explicit parallel groups)
const groups = {}
tasksWithDeps.forEach(t => {
if (t.execution_group) {
groups[t.execution_group] = groups[t.execution_group] || []
groups[t.execution_group].push(t)
}
})
Object.entries(groups).forEach(([groupId, groupTasks]) => {
groupTasks.forEach(t => processed.add(t.taskIndex))
// Phase 1: All independent tasks → single parallel batch (maximize utilization)
const independentTasks = tasksWithDeps.filter(t => t.dependencies.length === 0)
if (independentTasks.length > 0) {
independentTasks.forEach(t => processed.add(t.taskIndex))
calls.push({
method: executionMethod,
executionType: "parallel",
groupId: `P${parallelIdx++}`,
taskSummary: groupTasks.map(t => t.title).join(' | '),
tasks: groupTasks
groupId: "P1",
taskSummary: independentTasks.map(t => t.title).join(' | '),
tasks: independentTasks
})
})
}
// Phase 2: Process remaining by dependency order with cost-aware batching
// Phase 2: Dependent tasks → sequential batches (respect dependencies)
let sequentialIndex = 1
let remaining = tasksWithDeps.filter(t => !processed.has(t.taskIndex))
while (remaining.length > 0) {
const ready = remaining.filter(t => t.dependencies.every(d => processed.has(d)))
if (ready.length === 0) { ready.push(...remaining) } // Break circular deps
// Find tasks whose dependencies are all satisfied
const ready = remaining.filter(t =>
t.dependencies.every(d => processed.has(d))
)
// Cost-aware batch creation
let batch = [], batchCost = 0
const stillReady = [...ready]
while (stillReady.length > 0) {
const idx = stillReady.findIndex(t => batchCost + t.cost <= MAX_BATCH_COST)
if (idx === -1) break
const task = stillReady.splice(idx, 1)[0]
batch.push(task)
batchCost += task.cost
if (ready.length === 0) {
console.warn('Circular dependency detected, forcing remaining tasks')
ready.push(...remaining)
}
if (batch.length === 0) batch = [ready[0]] // At least one task
batch.forEach(t => processed.add(t.taskIndex))
// Group ready tasks (can run in parallel within this phase)
ready.forEach(t => processed.add(t.taskIndex))
calls.push({
method: executionMethod,
executionType: batch.length > 1 ? "parallel" : "sequential",
groupId: batch.length > 1 ? `P${parallelIdx++}` : `S${sequentialIdx++}`,
taskSummary: batch.map(t => t.title).join(batch.length > 1 ? ' | ' : ' → '),
tasks: batch
executionType: ready.length > 1 ? "parallel" : "sequential",
groupId: ready.length > 1 ? `P${calls.length + 1}` : `S${sequentialIndex++}`,
taskSummary: ready.map(t => t.title).join(ready.length > 1 ? ' | ' : ' → '),
tasks: ready
})
remaining = remaining.filter(t => !processed.has(t.taskIndex))
}
return calls
}
@@ -287,30 +258,14 @@ TodoWrite({
### Step 3: Launch Execution
**Execution Flow**: Parallel batches concurrently (multiple agents) → Sequential batches in order
**Unified executeBatch dispatcher**:
```javascript
// Dispatch batch to appropriate executor (Agent or Codex)
function executeBatch(batch) {
if (batch.method === "Agent") {
return executeBatchAgent(batch) // See Option A below
} else {
return executeBatchCodex(batch) // See Option B below
}
}
```
**Execution orchestration**:
**Execution Flow**: Parallel batches concurrently → Sequential batches in order
```javascript
const parallel = executionCalls.filter(c => c.executionType === "parallel")
const sequential = executionCalls.filter(c => c.executionType === "sequential")
// Phase 1: Launch all parallel batches (MULTIPLE CONCURRENT AGENTS)
// Each batch → separate agent instance → true parallelism
// Phase 1: Launch all parallel batches (single message with multiple tool calls)
if (parallel.length > 0) {
TodoWrite({ todos: executionCalls.map(c => ({ status: c.executionType === "parallel" ? "in_progress" : "pending" })) })
// Promise.all dispatches each batch to its own agent concurrently
parallelResults = await Promise.all(parallel.map(c => executeBatch(c)))
previousExecutionResults.push(...parallelResults)
TodoWrite({ todos: executionCalls.map(c => ({ status: parallel.includes(c) ? "completed" : "pending" })) })
@@ -353,12 +308,10 @@ ${task.acceptance.map((criterion, i) => `${i + 1}. ${criterion}`).join('\n')}
`
}
// executeBatch(batch) - called for each parallel/sequential batch
function executeBatchAgent(batch) {
return Task(
subagent_type="code-developer",
description=`Implement batch ${batch.groupId}: ${batch.taskSummary}`,
prompt=`
Task(
subagent_type="code-developer",
description="Implement planned tasks",
prompt=`
${originalUserInput ? `## Original User Request\n${originalUserInput}\n\n` : ''}
## Implementation Plan
@@ -366,8 +319,8 @@ function executeBatchAgent(batch) {
**Summary**: ${planObject.summary}
**Approach**: ${planObject.approach}
## Batch ${batch.groupId}: Task Breakdown (${batch.tasks.length} tasks)
${batch.tasks.map((task, i) => formatTaskForAgent(task, i)).join('\n')}
## Task Breakdown (${planObject.tasks.length} tasks)
${planObject.tasks.map((task, i) => formatTaskForAgent(task, i)).join('\n')}
${previousExecutionResults.length > 0 ? `\n## Previous Execution Results\n${previousExecutionResults.map(result => `
[${result.executionId}] ${result.status}
@@ -408,11 +361,10 @@ ${result.notes ? `Notes: ${result.notes}` : ''}
Read exploration files for comprehensive context from multiple angles.` : ''}
## Requirements
MUST complete ALL ${batch.tasks.length} tasks in batch ${batch.groupId}.
Return only after all tasks in this batch are fully implemented and tested.
MUST complete ALL ${planObject.tasks.length} tasks listed above in this single execution.
Return only after all tasks are fully implemented and tested.
`
)
}
)
```
**Result Collection**: After completion, collect result following `executionResult` structure (see Data Structures section)
@@ -444,11 +396,7 @@ ${task.acceptance.map((criterion, i) => ` - ${criterion}`).join('\n')}
`
}
// executeBatch(batch) - called for each parallel/sequential batch
const timeoutByComplexity = { "Low": 2400000, "Medium": 3600000, "High": 6000000 }
function executeBatchCodex(batch) {
return Bash(`codex --full-auto exec "
codex --full-auto exec "
${originalUserInput ? `## Original User Request\n${originalUserInput}\n\n` : ''}
## Implementation Plan
@@ -456,8 +404,8 @@ ${originalUserInput ? `## Original User Request\n${originalUserInput}\n\n` : ''}
TASK: ${planObject.summary}
APPROACH: ${planObject.approach}
### Batch ${batch.groupId}: Task Breakdown (${batch.tasks.length} tasks)
${batch.tasks.map((task, i) => formatTaskForCodex(task, i)).join('\n')}
### Task Breakdown (${planObject.tasks.length} tasks)
${planObject.tasks.map((task, i) => formatTaskForCodex(task, i)).join('\n')}
${previousExecutionResults.length > 0 ? `\n### Previous Execution Results\n${previousExecutionResults.map(result => `
[${result.executionId}] ${result.status}
@@ -501,15 +449,30 @@ Read exploration files for comprehensive architectural, pattern, and constraint
` : ''}
## Requirements
MUST complete ALL ${batch.tasks.length} tasks in batch ${batch.groupId}.
Return only after all tasks in this batch are fully implemented and tested.
MUST complete ALL ${planObject.tasks.length} tasks listed above in this single execution.
Return only after all tasks are fully implemented and tested.
Complexity: ${planObject.complexity}
" --skip-git-repo-check -s danger-full-access`, { timeout: timeoutByComplexity[planObject.complexity] || 3600000 })
}
" --skip-git-repo-check -s danger-full-access
```
**Note**: Timeout based on complexity (Low=40min, Medium=60min, High=100min) is handled in `executeBatchCodex`.
**Execution with tracking**:
```javascript
// Launch CLI in foreground (NOT background)
// Timeout based on complexity: Low=40min, Medium=60min, High=100min
const timeoutByComplexity = {
"Low": 2400000, // 40 minutes
"Medium": 3600000, // 60 minutes
"High": 6000000 // 100 minutes
}
bash_result = Bash(
command=cli_command,
timeout=timeoutByComplexity[planObject.complexity] || 3600000
)
// Update TodoWrite when execution completes
```
**Result Collection**: After completion, analyze output and collect result following `executionResult` structure
@@ -576,8 +539,8 @@ codex --full-auto exec "[Verify plan acceptance criteria at ${plan.json}]" --ski
## Best Practices
**Input Modes**: In-memory (lite-plan), prompt (standalone), file (JSON/text)
**Task Grouping**: Hybrid dependencies (explicit depends_on + file conflicts) + execution_group priority + cost-aware batching (MAX_BATCH_COST=8)
**Execution**: Parallel batches via single Claude message with multiple tool calls; cost balances workload (Low=1, Medium=2, High=4)
**Task Grouping**: Based on explicit depends_on only; independent tasks run in single parallel batch
**Execution**: All independent tasks launch concurrently via single Claude message with multiple tool calls
## Error Handling

View File

@@ -415,8 +415,6 @@ Generate plan.json with:
3. **Substantial tasks**: Each task should represent 15-60 minutes of work
4. **True dependencies only**: Only use depends_on when Task B cannot start without Task A's output
5. **Prefer parallel**: Most tasks should be independent (no depends_on)
6. **Explicit parallel groups**: Assign same `execution_group` ID (e.g., "group-1") to tasks that can run concurrently; null for others
7. **Task complexity**: Set `complexity` (Low/Medium/High) for workload balancing - executor uses cost units (1/2/4)
## Execution
1. Read ALL exploration files for comprehensive context

View File

@@ -118,15 +118,6 @@
"pattern": "^T[0-9]+$"
},
"description": "Task IDs this task depends on (e.g., ['T1', 'T2'])"
},
"execution_group": {
"type": ["string", "null"],
"description": "Parallel execution group ID. Tasks with same group ID run concurrently. null = use depends_on logic"
},
"complexity": {
"type": "string",
"enum": ["Low", "Medium", "High"],
"description": "Task complexity for workload balancing (Low=1, Medium=2, High=4 cost units)"
}
}
},