2025-11-20 21:28:55 +00:00
|
|
|
"""
|
|
|
|
|
Configuration module for AI Agent system.
|
|
|
|
|
"""
|
|
|
|
|
import os
|
|
|
|
|
from dataclasses import dataclass
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
from typing import Optional
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
class AgentConfig:
|
|
|
|
|
"""Configuration for AI agent execution."""
|
|
|
|
|
|
|
|
|
|
# Project paths
|
|
|
|
|
project_root: Path
|
|
|
|
|
component: str # 'web_v2', 'backend', 'common'
|
|
|
|
|
|
|
|
|
|
# Agent limits
|
|
|
|
|
max_iterations: int = 10
|
2025-11-20 23:05:04 +00:00
|
|
|
max_retries: int = 5
|
2025-11-20 21:28:55 +00:00
|
|
|
timeout_hours: int = 6
|
|
|
|
|
|
|
|
|
|
# Cursor CLI settings
|
|
|
|
|
cursor_api_key: Optional[str] = None
|
|
|
|
|
cursor_model: str = "claude-3-5-sonnet-20241022"
|
|
|
|
|
|
|
|
|
|
# State file paths
|
|
|
|
|
@property
|
|
|
|
|
def agent_dir(self) -> Path:
|
|
|
|
|
return self.project_root / "ai_docs" / "agent" / self.component
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def task_list_path(self) -> Path:
|
|
|
|
|
return self.agent_dir / "task_list.json"
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def agent_state_path(self) -> Path:
|
|
|
|
|
return self.agent_dir / "agent_state.json"
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def global_lock_path(self) -> Path:
|
|
|
|
|
return self.project_root / "ai_docs" / "agent" / "global_lock.json"
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def prompts_dir(self) -> Path:
|
|
|
|
|
return self.project_root / "ai_docs" / "agent" / "prompts"
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def component_root(self) -> Path:
|
|
|
|
|
"""Root directory of the component being worked on."""
|
|
|
|
|
if self.component == "web_v2":
|
|
|
|
|
return self.project_root / "mnemo_cards_web_v2"
|
|
|
|
|
elif self.component == "backend":
|
|
|
|
|
return self.project_root / "mnemo_cards_backend"
|
|
|
|
|
elif self.component == "common":
|
|
|
|
|
return self.project_root / "mnemo_cards_common"
|
|
|
|
|
else:
|
|
|
|
|
raise ValueError(f"Unknown component: {self.component}")
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def from_env(cls, component: str) -> "AgentConfig":
|
|
|
|
|
"""Create configuration from environment variables."""
|
|
|
|
|
project_root = Path(os.getenv("PROJECT_ROOT", os.getcwd()))
|
|
|
|
|
|
|
|
|
|
return cls(
|
|
|
|
|
project_root=project_root,
|
|
|
|
|
component=component,
|
|
|
|
|
max_iterations=int(os.getenv("MAX_ITERATIONS", "10")),
|
|
|
|
|
max_retries=int(os.getenv("MAX_RETRIES", "3")),
|
|
|
|
|
timeout_hours=int(os.getenv("TIMEOUT_HOURS", "6")),
|
|
|
|
|
cursor_api_key=os.getenv("CURSOR_API_KEY"),
|
|
|
|
|
cursor_model=os.getenv("CURSOR_MODEL", "claude-3-5-sonnet-20241022"),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def validate(self) -> None:
|
|
|
|
|
"""Validate configuration."""
|
|
|
|
|
if not self.project_root.exists():
|
|
|
|
|
raise ValueError(f"Project root does not exist: {self.project_root}")
|
|
|
|
|
|
|
|
|
|
if not self.cursor_api_key:
|
|
|
|
|
raise ValueError("CURSOR_API_KEY environment variable is required")
|
|
|
|
|
|
|
|
|
|
if self.component not in ["web_v2", "backend", "common"]:
|
|
|
|
|
raise ValueError(f"Invalid component: {self.component}")
|
|
|
|
|
|
|
|
|
|
if not self.component_root.exists():
|
|
|
|
|
raise ValueError(f"Component root does not exist: {self.component_root}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Component-specific configurations
|
|
|
|
|
COMPONENT_CONFIGS = {
|
|
|
|
|
"web_v2": {
|
|
|
|
|
"test_command": "cd mnemo_cards_web_v2 && flutter test",
|
|
|
|
|
"lint_command": "cd mnemo_cards_web_v2 && flutter analyze",
|
|
|
|
|
"build_command": "cd mnemo_cards_web_v2 && flutter build web",
|
|
|
|
|
},
|
|
|
|
|
"backend": {
|
|
|
|
|
"test_command": "cd mnemo_cards_backend && dart test",
|
|
|
|
|
"lint_command": "cd mnemo_cards_backend && dart analyze",
|
|
|
|
|
"build_command": "cd mnemo_cards_backend && dart compile exe bin/server.dart",
|
|
|
|
|
},
|
|
|
|
|
"common": {
|
|
|
|
|
"test_command": "cd mnemo_cards_common && dart test",
|
|
|
|
|
"lint_command": "cd mnemo_cards_common && dart analyze",
|
|
|
|
|
"build_command": None, # No build for common package
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_test_command(component: str) -> str:
|
|
|
|
|
"""Get test command for component."""
|
|
|
|
|
return COMPONENT_CONFIGS[component]["test_command"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_lint_command(component: str) -> str:
|
|
|
|
|
"""Get lint command for component."""
|
|
|
|
|
return COMPONENT_CONFIGS[component]["lint_command"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_build_command(component: str) -> Optional[str]:
|
|
|
|
|
"""Get build command for component."""
|
|
|
|
|
return COMPONENT_CONFIGS[component]["build_command"]
|
|
|
|
|
|