mirror of
https://github.com/leonvanzyl/autocoder.git
synced 2026-01-30 06:12:06 +00:00
feat: decouple regression testing agents from coding agents
Major refactoring of the parallel orchestrator to run regression testing agents independently from coding agents. This improves system reliability and provides better control over testing behavior. Key changes: Database & MCP Layer: - Add testing_in_progress and last_tested_at columns to Feature model - Add feature_claim_for_testing() for atomic test claim with retry - Add feature_release_testing() to release claims after testing - Refactor claim functions to iterative loops (no recursion) - Add OperationalError retry handling for transient DB errors - Reduce MAX_CLAIM_RETRIES from 10 to 5 Orchestrator: - Decouple testing agent lifecycle from coding agents - Add _maintain_testing_agents() for continuous testing maintenance - Fix TOCTOU race in _spawn_testing_agent() - hold lock during spawn - Add _cleanup_stale_testing_locks() with 30-min timeout - Fix log ordering - start_session() before stale flag cleanup - Add stale testing_in_progress cleanup on startup Dead Code Removal: - Remove count_testing_in_concurrency from entire stack (12+ files) - Remove ineffective with_for_update() from features router API & UI: - Pass testing_agent_ratio via CLI to orchestrator - Update testing prompt template to use new claim/release tools - Rename UI label to "Regression Agents" with clearer description - Add process_utils.py for cross-platform process tree management Testing agents now: - Run continuously as long as passing features exist - Can re-test features multiple times to catch regressions - Are controlled by fixed count (0-3) via testing_agent_ratio setting - Have atomic claiming to prevent concurrent testing of same feature Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -26,11 +26,11 @@ def _get_project_path(project_name: str) -> Path:
|
||||
return get_project_path(project_name)
|
||||
|
||||
|
||||
def _get_settings_defaults() -> tuple[bool, str, int, bool]:
|
||||
def _get_settings_defaults() -> tuple[bool, str, int]:
|
||||
"""Get defaults from global settings.
|
||||
|
||||
Returns:
|
||||
Tuple of (yolo_mode, model, testing_agent_ratio, count_testing_in_concurrency)
|
||||
Tuple of (yolo_mode, model, testing_agent_ratio)
|
||||
"""
|
||||
import sys
|
||||
root = Path(__file__).parent.parent.parent
|
||||
@@ -49,9 +49,7 @@ def _get_settings_defaults() -> tuple[bool, str, int, bool]:
|
||||
except (ValueError, TypeError):
|
||||
testing_agent_ratio = 1
|
||||
|
||||
count_testing = (settings.get("count_testing_in_concurrency") or "false").lower() == "true"
|
||||
|
||||
return yolo_mode, model, testing_agent_ratio, count_testing
|
||||
return yolo_mode, model, testing_agent_ratio
|
||||
|
||||
|
||||
router = APIRouter(prefix="/api/projects/{project_name}/agent", tags=["agent"])
|
||||
@@ -101,7 +99,6 @@ async def get_agent_status(project_name: str):
|
||||
parallel_mode=manager.parallel_mode,
|
||||
max_concurrency=manager.max_concurrency,
|
||||
testing_agent_ratio=manager.testing_agent_ratio,
|
||||
count_testing_in_concurrency=manager.count_testing_in_concurrency,
|
||||
)
|
||||
|
||||
|
||||
@@ -114,20 +111,18 @@ async def start_agent(
|
||||
manager = get_project_manager(project_name)
|
||||
|
||||
# Get defaults from global settings if not provided in request
|
||||
default_yolo, default_model, default_testing_ratio, default_count_testing = _get_settings_defaults()
|
||||
default_yolo, default_model, default_testing_ratio = _get_settings_defaults()
|
||||
|
||||
yolo_mode = request.yolo_mode if request.yolo_mode is not None else default_yolo
|
||||
model = request.model if request.model else default_model
|
||||
max_concurrency = request.max_concurrency or 1
|
||||
testing_agent_ratio = request.testing_agent_ratio if request.testing_agent_ratio is not None else default_testing_ratio
|
||||
count_testing = request.count_testing_in_concurrency if request.count_testing_in_concurrency is not None else default_count_testing
|
||||
|
||||
success, message = await manager.start(
|
||||
yolo_mode=yolo_mode,
|
||||
model=model,
|
||||
max_concurrency=max_concurrency,
|
||||
testing_agent_ratio=testing_agent_ratio,
|
||||
count_testing_in_concurrency=count_testing,
|
||||
)
|
||||
|
||||
# Notify scheduler of manual start (to prevent auto-stop during scheduled window)
|
||||
|
||||
Reference in New Issue
Block a user