mirror of
https://github.com/leonvanzyl/autocoder.git
synced 2026-02-01 23:13:36 +00:00
feat: add multi-feature batching for coding agents
Enable the orchestrator to assign 1-3 features per coding agent subprocess, selected via dependency chain extension + same-category fill. This reduces cold-start overhead and leverages shared context across related features. Orchestrator (parallel_orchestrator.py): - Add batch tracking: _batch_features and _feature_to_primary data structures - Add build_feature_batches() with dependency chain + category fill algorithm - Add start_feature_batch() and _spawn_coding_agent_batch() methods - Update _on_agent_complete() for batch cleanup across all features - Update stop_feature() with _feature_to_primary lookup - Update get_ready_features() to exclude all batch feature IDs - Update main loop to build batches then spawn per available slot CLI and agent layer: - Add --feature-ids (comma-separated) and --batch-size CLI args - Add feature_ids parameter to run_autonomous_agent() with batch prompt selection - Add get_batch_feature_prompt() with sequential workflow instructions WebSocket layer (server/websocket.py): - Add BATCH_CODING_AGENT_START_PATTERN and BATCH_FEATURES_COMPLETE_PATTERN - Add _handle_batch_agent_start() and _handle_batch_agent_complete() methods - Add featureIds field to all agent_update messages - Track current_feature_id updates as agent moves through batch Frontend (React UI): - Add featureIds to ActiveAgent and WSAgentUpdateMessage types - Update KanbanColumn and DependencyGraph agent-feature maps for batch - Update AgentCard to show "Batch: #X, #Y, #Z" with active feature highlight - Add "Features per Agent" segmented control (1-3) in SettingsModal Settings integration (full stack): - Add batch_size to schemas, settings router, agent router, process manager - Default batch_size=3, user-configurable 1-3 via settings UI - batch_size=1 is functionally identical to pre-batching behavior Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
30
agent.py
30
agent.py
@@ -31,6 +31,7 @@ from progress import (
|
||||
)
|
||||
from prompts import (
|
||||
copy_spec_to_project,
|
||||
get_batch_feature_prompt,
|
||||
get_coding_prompt,
|
||||
get_initializer_prompt,
|
||||
get_single_feature_prompt,
|
||||
@@ -139,6 +140,7 @@ async def run_autonomous_agent(
|
||||
max_iterations: Optional[int] = None,
|
||||
yolo_mode: bool = False,
|
||||
feature_id: Optional[int] = None,
|
||||
feature_ids: Optional[list[int]] = None,
|
||||
agent_type: Optional[str] = None,
|
||||
testing_feature_id: Optional[int] = None,
|
||||
testing_feature_ids: Optional[list[int]] = None,
|
||||
@@ -152,6 +154,7 @@ async def run_autonomous_agent(
|
||||
max_iterations: Maximum number of iterations (None for unlimited)
|
||||
yolo_mode: If True, skip browser testing in coding agent prompts
|
||||
feature_id: If set, work only on this specific feature (used by orchestrator for coding agents)
|
||||
feature_ids: If set, work on these features in batch (used by orchestrator for batch mode)
|
||||
agent_type: Type of agent: "initializer", "coding", "testing", or None (auto-detect)
|
||||
testing_feature_id: For testing agents, the pre-claimed feature ID to test (legacy single mode)
|
||||
testing_feature_ids: For testing agents, list of feature IDs to batch test
|
||||
@@ -165,7 +168,9 @@ async def run_autonomous_agent(
|
||||
print(f"Agent type: {agent_type}")
|
||||
if yolo_mode:
|
||||
print("Mode: YOLO (testing agents disabled)")
|
||||
if feature_id:
|
||||
if feature_ids and len(feature_ids) > 1:
|
||||
print(f"Feature batch: {', '.join(f'#{fid}' for fid in feature_ids)}")
|
||||
elif feature_id:
|
||||
print(f"Feature assignment: #{feature_id}")
|
||||
if max_iterations:
|
||||
print(f"Max iterations: {max_iterations}")
|
||||
@@ -239,6 +244,8 @@ async def run_autonomous_agent(
|
||||
import os
|
||||
if agent_type == "testing":
|
||||
agent_id = f"testing-{os.getpid()}" # Unique ID for testing agents
|
||||
elif feature_ids and len(feature_ids) > 1:
|
||||
agent_id = f"batch-{feature_ids[0]}"
|
||||
elif feature_id:
|
||||
agent_id = f"feature-{feature_id}"
|
||||
else:
|
||||
@@ -250,9 +257,13 @@ async def run_autonomous_agent(
|
||||
prompt = get_initializer_prompt(project_dir)
|
||||
elif agent_type == "testing":
|
||||
prompt = get_testing_prompt(project_dir, testing_feature_id, testing_feature_ids)
|
||||
elif feature_id:
|
||||
elif feature_ids and len(feature_ids) > 1:
|
||||
# Batch mode (used by orchestrator for multi-feature coding agents)
|
||||
prompt = get_batch_feature_prompt(feature_ids, project_dir, yolo_mode)
|
||||
elif feature_id or (feature_ids is not None and len(feature_ids) == 1):
|
||||
# Single-feature mode (used by orchestrator for coding agents)
|
||||
prompt = get_single_feature_prompt(feature_id, project_dir, yolo_mode)
|
||||
fid = feature_id if feature_id is not None else feature_ids[0] # type: ignore[index]
|
||||
prompt = get_single_feature_prompt(fid, project_dir, yolo_mode)
|
||||
else:
|
||||
# General coding prompt (legacy path)
|
||||
prompt = get_coding_prompt(project_dir, yolo_mode=yolo_mode)
|
||||
@@ -356,12 +367,19 @@ async def run_autonomous_agent(
|
||||
print("The autonomous agent has finished its work.")
|
||||
break
|
||||
|
||||
# Single-feature mode OR testing agent: exit after one session
|
||||
if feature_id is not None or agent_type == "testing":
|
||||
# Single-feature mode, batch mode, or testing agent: exit after one session
|
||||
if feature_ids and len(feature_ids) > 1:
|
||||
print(f"\nBatch mode: Features {', '.join(f'#{fid}' for fid in feature_ids)} session complete.")
|
||||
break
|
||||
elif feature_id is not None or (feature_ids is not None and len(feature_ids) == 1):
|
||||
fid = feature_id if feature_id is not None else feature_ids[0] # type: ignore[index]
|
||||
if agent_type == "testing":
|
||||
print("\nTesting agent complete. Terminating session.")
|
||||
else:
|
||||
print(f"\nSingle-feature mode: Feature #{feature_id} session complete.")
|
||||
print(f"\nSingle-feature mode: Feature #{fid} session complete.")
|
||||
break
|
||||
elif agent_type == "testing":
|
||||
print("\nTesting agent complete. Terminating session.")
|
||||
break
|
||||
|
||||
# Reset rate limit retries only if no rate limit signal was detected
|
||||
|
||||
Reference in New Issue
Block a user