"""Coder Agent — writes code, creates files, debugs. Handles steps that involve writing code, creating files, or fixing bugs. Can use the write_file and shell_exec tools. """ from __future__ import annotations import logging import re from typing import Any from .agent_base import BaseAgent from ..memory.goal_memory import Goal logger = logging.getLogger(__name__) class CoderAgent(BaseAgent): """Writes code and creates files for goal steps.""" def __init__(self, goal_memory, persistent_memory=None, generate_fn=None): super().__init__( name="coder", role="Code Writer", description="Writes code, creates files, and debugs issues", goal_memory=goal_memory, persistent_memory=persistent_memory, generate_fn=generate_fn, poll_interval_s=2.0, ) def _can_handle(self, goal: Goal) -> bool: """Coder handles goals related to code.""" keywords = ["code", "function", "file", "implement", "write", "create", "build", "debug", "fix", "bug", "program", "script", "module", "class"] text = (goal.title + " " + goal.description).lower() return any(kw in text for kw in keywords) def process_goal(self, goal: Goal) -> dict[str, Any]: """Execute a coding step.""" if goal.current_step >= len(goal.steps): return {"success": True, "output": "No more steps"} step = goal.steps[goal.current_step] prompt = ( f"You are a code writer agent. Execute this step:\n" f"Goal: {goal.title}\n" f"Step: {step['title']}\n" f"Description: {step['description']}\n" f"Write the code or create the file needed. Be concise.\n" ) response = self._generate(prompt) # Extract file content from response files_created = self._extract_and_save_files(response) if files_created: return {"success": True, "output": f"Created files: {', '.join(files_created)}"} return {"success": True, "output": response[:200]} def _extract_and_save_files(self, text: str) -> list[str]: """Extract file blocks from LLM output and save them.""" files = [] # Pattern: ```file: path\n content ``` pattern = r"```file:\s*(.+?)\n(.*?)```" matches = re.findall(pattern, text, re.DOTALL) for path, content in matches: path = path.strip() try: import os os.makedirs(os.path.dirname(path) or ".", exist_ok=True) with open(path, "w", encoding="utf-8") as f: f.write(content.strip()) files.append(path) logger.info("Coder created file: %s", path) except Exception as e: logger.error("Failed to create file %s: %s", path, e) return files