import time from datetime import datetime from typing import Iterator from .code_generator import CodeGenerator from .code_executor import CodeExecutor from .error_parser import parse_error from .reflection import ReflectionModule from .task_classifier import TaskClassifier from .multi_language_agent import MultiLanguageAgent class AgentLoopController: def __init__(self, api_key: str, model: str = "llama-3.3-70b-versatile"): self.generator = CodeGenerator(api_key, model) self.executor = CodeExecutor() self.reflector = ReflectionModule(api_key, model) self.classifier = TaskClassifier() self.multi_agent = MultiLanguageAgent(api_key, model) def run( self, task: str, test_cases: str, max_iterations: int = 5, timeout: int = 10, ) -> Iterator[dict]: start_time = time.time() yield self._evt("start", f"Agent started - max {max_iterations} iterations, {timeout}s timeout") yield self._evt("classifying", "Detecting task type and target languages...") classification = self.classifier.classify(task) mode = classification["mode"] languages = classification.get("languages", ["Python"]) yield self._evt( "classified", f"Mode: {mode.upper()} | Languages: {', '.join(languages)}", mode=mode, languages=languages, ) if mode == "analyze": yield from self._run_analyze(task) else: yield from self._run_execute(task, test_cases, max_iterations, timeout, start_time) def _run_analyze(self, task: str) -> Iterator[dict]: yield self._evt("analyzing", "Generating multi-language analysis with LLM") try: result = self.multi_agent.generate(task) langs = [impl["language"] for impl in result.get("implementations", [])] label = ", ".join(langs) if langs else "response ready" yield self._evt("analysis_ready", f"Analysis complete: {label}", analysis=result) yield self._evt( "complete", "Analysis finished.", success=True, mode="analyze", final_code="", total_time=0, iterations_count=0, iterations=[], analysis=result, ) except Exception as exc: yield self._evt("failed", f"Analysis failed: {exc}", error=str(exc)) def _run_execute( self, task: str, test_cases: str, max_iterations: int, timeout: int, start_time: float ) -> Iterator[dict]: all_iterations: list[dict] = [] yield self._evt("generating", "Generating initial code with LLM") try: code, _ = self.generator.generate(task, test_cases) except Exception as exc: yield self._evt("failed", f"LLM call failed: {exc}", error=str(exc)) return yield self._evt("code_ready", f"Initial code ready ({self._line_count(code)} lines)", code=code, iteration=0) for iteration in range(1, max_iterations + 1): yield self._evt( "executing", f"Executing code - iteration {iteration}/{max_iterations}", code=code, iteration=iteration, ) exec_result = self.executor.execute(code, test_cases, timeout) iter_data: dict = { "iteration": iteration, "code": code, "execution": exec_result, "timestamp": self._ts(), } if exec_result["success"]: iter_data["status"] = "success" all_iterations.append(iter_data) yield self._evt( "success", f"Code passed on iteration {iteration}", code=code, iteration=iteration, execution=exec_result, iteration_data=iter_data, ) yield self._evt( "complete", f"Task completed successfully in {iteration} iteration(s).", iterations=all_iterations, final_code=code, success=True, mode="execute", total_time=round(time.time() - start_time, 2), iterations_count=iteration, ) return error_info = parse_error(exec_result) iter_data["status"] = "failed" iter_data["error"] = error_info all_iterations.append(iter_data) yield self._evt( "error", f"Error on iteration {iteration}: {error_info['type']}: {error_info['message'][:120]}", code=code, iteration=iteration, execution=exec_result, error=error_info, iteration_data=iter_data, ) if iteration < max_iterations: yield self._evt("reflecting", "Sending error to LLM for reflection and fix", iteration=iteration) try: new_code, reflection = self.reflector.reflect_and_refine( task, code, exec_result, error_info ) iter_data["reflection"] = reflection code = new_code yield self._evt( "refined", "Code refined based on error feedback", new_code=new_code, reflection=reflection, iteration=iteration, ) except Exception as exc: yield self._evt("error", f"Reflection failed: {exc}", iteration=iteration) yield self._evt( "complete", f"Reached max iterations ({max_iterations}) without full success.", iterations=all_iterations, final_code=code, success=False, mode="execute", total_time=round(time.time() - start_time, 2), iterations_count=max_iterations, ) def _evt(self, event_type: str, message: str, **kwargs) -> dict: return {"type": event_type, "message": message, "timestamp": self._ts(), **kwargs} @staticmethod def _ts() -> str: return datetime.now().strftime("%H:%M:%S") @staticmethod def _line_count(code: str) -> int: return len(code.strip().splitlines())