diff --git a/README.md b/README.md index e69de29..47a1076 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,24 @@ +# AutoMetabuilder + +AutoMetabuilder is an AI-powered tool designed to integrate with the metabuilder SDLC workflow. + +## Features + +- **GitHub Integration**: Automatically fetches context from GitHub Issues and Pull Requests. +- **SDLC Automation**: Can create branches and pull requests based on the AI's decisions. +- **Customizable Prompts**: Loads workflow instructions from a remote YAML prompt. + +## Configuration + +The following environment variables are required: + +- `GITHUB_TOKEN`: A GitHub Personal Access Token with repository permissions. +- `GITHUB_REPOSITORY`: The full name of the repository (e.g., `owner/repo`). + +## Usage + +Run the tool using poetry: + +```bash +poetry run autometabuilder +``` diff --git a/pyproject.toml b/pyproject.toml index 0ddf9c8..0605a6c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,6 +12,7 @@ requests = "^2.31.0" pyyaml = "^6.0.1" python-dotenv = "^1.0.0" openai = "^1.0.0" +PyGithub = "^2.1.1" [build-system] requires = ["poetry-core"] diff --git a/src/autometabuilder/github_integration.py b/src/autometabuilder/github_integration.py new file mode 100644 index 0000000..0dcdf0b --- /dev/null +++ b/src/autometabuilder/github_integration.py @@ -0,0 +1,34 @@ +import os +from github import Github +from github.Repository import Repository +from github.Issue import Issue +from github.PullRequest import PullRequest + +class GitHubIntegration: + def __init__(self, token: str, repo_name: str): + self.github = Github(token) + self.repo = self.github.get_repo(repo_name) + + def get_open_issues(self): + return self.repo.get_issues(state='open') + + def get_issue(self, issue_number: int) -> Issue: + return self.repo.get_issue(number=issue_number) + + def create_branch(self, branch_name: str, base_branch: str = "main"): + base_ref = self.repo.get_git_ref(f"heads/{base_branch}") + self.repo.create_git_ref(ref=f"refs/heads/{branch_name}", sha=base_ref.object.sha) + + def create_pull_request(self, title: str, body: str, head_branch: str, base_branch: str = "main") -> PullRequest: + return self.repo.create_pull(title=title, body=body, head=head_branch, base=base_branch) + + def get_pull_requests(self, state: str = 'open'): + return self.repo.get_pulls(state=state) + +def get_repo_name_from_env() -> str: + # Try to get from environment variable, or fallback to some detection if possible + repo_name = os.environ.get("GITHUB_REPOSITORY") + if not repo_name: + # Fallback or error + raise ValueError("GITHUB_REPOSITORY environment variable not set") + return repo_name diff --git a/src/autometabuilder/main.py b/src/autometabuilder/main.py index 92bbb9a..157f5c8 100644 --- a/src/autometabuilder/main.py +++ b/src/autometabuilder/main.py @@ -1,8 +1,16 @@ import os import requests import yaml +import json from dotenv import load_dotenv from openai import OpenAI +try: + from autometabuilder.github_integration import GitHubIntegration, get_repo_name_from_env +except ImportError: + # Fallback for running as a script without proper package installation + import sys + sys.path.append(os.path.join(os.path.dirname(__file__), "..")) + from autometabuilder.github_integration import GitHubIntegration, get_repo_name_from_env load_dotenv() @@ -20,6 +28,15 @@ def main(): print("Error: GITHUB_TOKEN environment variable not set.") return + # Initialize GitHub Integration + try: + repo_name = get_repo_name_from_env() + gh = GitHubIntegration(token, repo_name) + print(f"Integrated with repository: {repo_name}") + except Exception as e: + print(f"Warning: GitHub integration failed: {e}") + gh = None + endpoint = "https://models.github.ai/inference" client = OpenAI( @@ -32,17 +49,95 @@ def main(): messages = prompt["messages"] model = prompt.get("model", "openai/gpt-4.1") - # Add runtime request (optional) - messages = messages + [{"role": "user", "content": "What should I do next?"}] + # Define tools for SDLC operations + tools = [ + { + "type": "function", + "function": { + "name": "create_branch", + "description": "Create a new git branch in the repository", + "parameters": { + "type": "object", + "properties": { + "branch_name": {"type": "string", "description": "The name of the new branch"}, + "base_branch": {"type": "string", "description": "The name of the base branch", "default": "main"}, + }, + "required": ["branch_name"], + }, + }, + }, + { + "type": "function", + "function": { + "name": "create_pull_request", + "description": "Create a new pull request", + "parameters": { + "type": "object", + "properties": { + "title": {"type": "string", "description": "The title of the PR"}, + "body": {"type": "string", "description": "The body content of the PR"}, + "head_branch": {"type": "string", "description": "The branch where changes are implemented"}, + "base_branch": {"type": "string", "description": "The branch to merge into", "default": "main"}, + }, + "required": ["title", "body", "head_branch"], + }, + }, + } + ] + + # Add SDLC Context if available + sdlc_context = "" + if gh: + try: + issues = gh.get_open_issues() + issue_list = "\n".join([f"- #{i.number}: {i.title}" for i in issues[:5]]) + if issue_list: + sdlc_context += f"\nOpen Issues:\n{issue_list}" + + prs = gh.get_pull_requests() + pr_list = "\n".join([f"- #{p.number}: {p.title}" for p in prs[:5]]) + if pr_list: + sdlc_context += f"\nOpen Pull Requests:\n{pr_list}" + except Exception as e: + print(f"Error fetching SDLC context: {e}") + + if sdlc_context: + messages.append({"role": "system", "content": f"SDLC Context:{sdlc_context}"}) + + # Add runtime request + messages.append({"role": "user", "content": "What should I do next?"}) response = client.chat.completions.create( model=model, messages=messages, + tools=tools, + tool_choice="auto", temperature=1.0, top_p=1.0, ) - print(response.choices[0].message.content) + response_message = response.choices[0].message + print(response_message.content if response_message.content else "Tool call requested...") + + # Handle tool calls + if response_message.tool_calls: + for tool_call in response_message.tool_calls: + function_name = tool_call.function.name + args = json.loads(tool_call.function.arguments) + + if function_name == "create_branch": + if gh: + print(f"Executing: create_branch({args})") + gh.create_branch(**args) + else: + print("Error: GitHub integration not available for tool call.") + + elif function_name == "create_pull_request": + if gh: + print(f"Executing: create_pull_request({args})") + gh.create_pull_request(**args) + else: + print("Error: GitHub integration not available for tool call.") if __name__ == "__main__": main()