diff --git a/ROADMAP.md b/ROADMAP.md index 37c90b2..c7be20f 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -7,10 +7,10 @@ - [x] Multi-language support for messages ## Phase 2: Enhanced Context & Reasoning -- [ ] **Roadmap Awareness**: Bot should explicitly read and update `ROADMAP.md`. -- [ ] **Repository Indexing**: Implement a way to index the codebase for better context. -- [ ] **Declarative Task Processing**: Move more logic into JSON/YAML specifications. -- [ ] **Feedback Loop**: Support for the AI to read comments on PRs it created. +- [x] **Roadmap Awareness**: Bot should explicitly read and update `ROADMAP.md`. +- [x] **Repository Indexing**: Implement a way to index the codebase for better context. +- [x] **Declarative Task Processing**: Move more logic into JSON/YAML specifications. +- [x] **Feedback Loop**: Support for the AI to read comments on PRs it created. ## Phase 3: Advanced Automation - [ ] **Automated Testing**: Integration with test runners to verify changes before PR. diff --git a/src/autometabuilder/github_integration.py b/src/autometabuilder/github_integration.py index 419ff55..61c417d 100644 --- a/src/autometabuilder/github_integration.py +++ b/src/autometabuilder/github_integration.py @@ -47,6 +47,11 @@ class GitHubIntegration: """Get pull requests from the repository.""" return self.repo.get_pulls(state=state) + def get_pull_request_comments(self, pr_number: int): + """Get comments from a specific pull request.""" + pr = self.repo.get_pull(pr_number) + return pr.get_issue_comments() + def get_repo_name_from_env() -> str: """Retrieve repository name from environment variable.""" diff --git a/src/autometabuilder/main.py b/src/autometabuilder/main.py index 009625d..57f2867 100644 --- a/src/autometabuilder/main.py +++ b/src/autometabuilder/main.py @@ -55,28 +55,62 @@ def get_sdlc_context(gh: GitHubIntegration, msgs: dict) -> str: return sdlc_context +def update_roadmap(content: str): + """Update ROADMAP.md with new content.""" + with open("ROADMAP.md", "w", encoding="utf-8") as f: + f.write(content) + print("ROADMAP.md updated successfully.") + + +def list_files(directory: str = "."): + """List files in the repository for indexing.""" + files_list = [] + for root, _, files in os.walk(directory): + if ".git" in root or "__pycache__" in root or ".venv" in root: + continue + for file in files: + files_list.append(os.path.join(root, file)) + + result = "\n".join(files_list) + print(f"Indexing repository files in {directory}...") + return result + + def handle_tool_calls(resp_msg, gh: GitHubIntegration, msgs: dict): - """Process tool calls from the AI response.""" - if resp_msg.tool_calls: - for tool_call in resp_msg.tool_calls: - function_name = tool_call.function.name - args = json.loads(tool_call.function.arguments) + """Process tool calls from the AI response using a declarative mapping.""" + if not resp_msg.tool_calls: + return - if function_name == "create_branch": - if gh: - print( - msgs["info_executing_create_branch"].format(args=args) - ) - gh.create_branch(**args) - else: - print(msgs["error_github_not_available"]) + # Declarative mapping of tool names to functions + tool_map = { + "create_branch": gh.create_branch if gh else None, + "create_pull_request": gh.create_pull_request if gh else None, + "get_pull_request_comments": gh.get_pull_request_comments if gh else None, + "update_roadmap": update_roadmap, + "list_files": list_files, + } - elif function_name == "create_pull_request": - if gh: - print(msgs["info_executing_create_pr"].format(args=args)) - gh.create_pull_request(**args) - else: - print(msgs["error_github_not_available"]) + for tool_call in resp_msg.tool_calls: + function_name = tool_call.function.name + args = json.loads(tool_call.function.arguments) + + handler = tool_map.get(function_name) + if handler: + print(msgs.get("info_executing_tool", "Executing tool: {name}").format(name=function_name)) + try: + result = handler(**args) + if result: + # In a real scenario, we might want to feed this back to the AI + if hasattr(result, "__iter__") and not isinstance(result, str): + # Handle iterables (like PyGithub PaginatedList) + for item in list(result)[:5]: + print(f"- {item}") + else: + print(result) + except Exception as e: + print(f"Error executing {function_name}: {e}") + else: + print(msgs.get("error_tool_not_found", "Tool {name} not found or unavailable.").format(name=function_name)) def main(): diff --git a/src/autometabuilder/messages_en.json b/src/autometabuilder/messages_en.json index 85ca11e..dff29d2 100644 --- a/src/autometabuilder/messages_en.json +++ b/src/autometabuilder/messages_en.json @@ -7,6 +7,8 @@ "info_tool_call_requested": "Tool call requested...", "info_executing_create_branch": "Executing: create_branch({args})", "info_executing_create_pr": "Executing: create_pull_request({args})", + "info_executing_tool": "Executing tool: {name}", + "error_tool_not_found": "Tool {name} not found or unavailable.", "error_github_not_available": "Error: GitHub integration not available for tool call.", "error_github_repo_missing": "GITHUB_REPOSITORY environment variable not set", "sdlc_context_label": "SDLC Context:", diff --git a/src/autometabuilder/tools.json b/src/autometabuilder/tools.json index a112270..a07514e 100644 --- a/src/autometabuilder/tools.json +++ b/src/autometabuilder/tools.json @@ -56,5 +56,60 @@ ] } } + }, + { + "type": "function", + "function": { + "name": "get_pull_request_comments", + "description": "Get comments from a specific pull request to read feedback", + "parameters": { + "type": "object", + "properties": { + "pr_number": { + "type": "integer", + "description": "The number of the pull request" + } + }, + "required": [ + "pr_number" + ] + } + } + }, + { + "type": "function", + "function": { + "name": "update_roadmap", + "description": "Update the ROADMAP.md file with new progress", + "parameters": { + "type": "object", + "properties": { + "content": { + "type": "string", + "description": "The full new content for ROADMAP.md" + } + }, + "required": [ + "content" + ] + } + } + }, + { + "type": "function", + "function": { + "name": "list_files", + "description": "List all files in the repository for indexing and context", + "parameters": { + "type": "object", + "properties": { + "directory": { + "type": "string", + "description": "The directory to list (default is root)", + "default": "." + } + } + } + } } ]