diff --git a/src/maca/agents/base.py b/src/maca/agents/base.py index 57e1b74..2f406cf 100644 --- a/src/maca/agents/base.py +++ b/src/maca/agents/base.py @@ -1,5 +1,5 @@ import os -import subprocess +import re class BaseAgent: def __init__(self, name, model_client): @@ -54,3 +54,12 @@ def clean_code_content(self, content): if not cleaned: break return content + + def parse_files(self, response_text): + pattern = r"\[FILE:\s*([^\s\]]+)\]\s*(?:\r?\n)*```\w*\s*\n(.*?)\n```" + matches = re.findall(pattern, response_text, re.DOTALL) + + files = {} + for filepath, content in matches: + files[filepath.strip()] = self.clean_code_content(content) + return files diff --git a/src/maca/agents/coder.py b/src/maca/agents/coder.py index 2d99f33..3466338 100644 --- a/src/maca/agents/coder.py +++ b/src/maca/agents/coder.py @@ -6,17 +6,12 @@ def __init__(self, name, model_client): super().__init__(name, model_client) def run(self, task_description, plan, repo_files_content=None, history=None): - files_context = "" - if repo_files_content: - files_context = "\n\nExisting File Contents:\n" - for filepath, content in repo_files_content.items(): - files_context += f"--- FILE: {filepath} ---\n{content}\n\n" + system_instruction = self._build_system_instruction() + prompt = self._build_prompt(task_description, plan, repo_files_content, history) + return self.model_client.generate(prompt, system_instruction) - history_str = "" - if history: - history_str = "\n\nPrevious Conversation History:\n" + "\n".join(history) - - system_instruction = ( + def _build_system_instruction(self): + return ( "You are a Software Coder Agent. Your job is to implement the changes outlined in the plan.\n\n" "CRITICAL: You MUST write the file identifier line in the EXACT format: [FILE: path/to/file.ext]\n" "Do NOT use markdown headers (like '## FILE: ...' or '# FILE: ...'), bullet points, or bold text. " @@ -29,21 +24,27 @@ def run(self, task_description, plan, repo_files_content=None, history=None): "Make sure to provide the entire, complete contents of the file. Do not use placeholders or ellipsis." ) - prompt = ( - f"User Task: {task_description}{history_str}\n\n" + def _build_prompt(self, task_description, plan, repo_files_content, history): + history_context = self._format_history(history) + files_context = self._format_files_context(repo_files_content) + + return ( + f"User Task: {task_description}{history_context}\n\n" f"Implementation Plan:\n{plan}\n" f"{files_context}\n" "Please implement the changes and output the files using the requested [FILE: path] format." ) - response = self.model_client.generate(prompt, system_instruction) - return response + def _format_history(self, history): + if not history: + return "" + return "\n\nPrevious Conversation History:\n" + "\n".join(history) - def parse_files(self, response_text): - pattern = r"\[FILE:\s*([^\s\]]+)\]\s*(?:\r?\n)*```\w*\s*\n(.*?)\n```" - matches = re.findall(pattern, response_text, re.DOTALL) + def _format_files_context(self, repo_files_content): + if not repo_files_content: + return "" - files = {} - for filepath, content in matches: - files[filepath.strip()] = self.clean_code_content(content) - return files + formatted_files = "\n\nExisting File Contents:\n" + for filepath, content in repo_files_content.items(): + formatted_files += f"--- FILE: {filepath} ---\n{content}\n\n" + return formatted_files diff --git a/src/maca/agents/reviewer.py b/src/maca/agents/reviewer.py index 9ecfddf..d560be5 100644 --- a/src/maca/agents/reviewer.py +++ b/src/maca/agents/reviewer.py @@ -6,15 +6,12 @@ def __init__(self, model_client): super().__init__("Reviewer", model_client) def run(self, task_description, generated_files, history=None): - files_str = "" - for filepath, content in generated_files.items(): - files_str += f"--- FILE: {filepath} ---\n{content}\n\n" + system_instruction = self._build_system_instruction() + prompt = self._build_prompt(task_description, generated_files, history) + return self.model_client.generate(prompt, system_instruction) - history_str = "" - if history: - history_str = "\n\nPrevious Conversation History:\n" + "\n".join(history) - - system_instruction = ( + def _build_system_instruction(self): + return ( "You are a Senior Reviewer Agent. Your job is to review the code generated for the task. " "Look for syntax errors, logical bugs, missing imports, or edge cases. " "If changes are needed, explain why and output the corrected files.\n\n" @@ -29,20 +26,26 @@ def run(self, task_description, generated_files, history=None): "If the code is perfect, output a summary and conclude with the word: APPROVED." ) - prompt = ( - f"User Task: {task_description}{history_str}\n\n" - f"Generated Files to Review:\n{files_str}" + def _build_prompt(self, task_description, generated_files, history): + history_context = self._format_history(history) + files_context = self._format_files_context(generated_files) + + return ( + f"User Task: {task_description}{history_context}\n\n" + f"Generated Files to Review:\n{files_context}" "Please review the code, suggest improvements, and output corrected files if needed." ) - response = self.model_client.generate(prompt, system_instruction) - return response + def _format_history(self, history): + if not history: + return "" + return "\n\nPrevious Conversation History:\n" + "\n".join(history) - def parse_files(self, response_text): - pattern = r"\[FILE:\s*([^\s\]]+)\]\s*(?:\r?\n)*```\w*\s*\n(.*?)\n```" - matches = re.findall(pattern, response_text, re.DOTALL) + def _format_files_context(self, files): + if not files: + return "" - files = {} - for filepath, content in matches: - files[filepath.strip()] = self.clean_code_content(content) - return files + formatted_files = "" + for filepath, content in files.items(): + formatted_files += f"--- FILE: {filepath} ---\n{content}\n\n" + return formatted_files