Refactored gemini, openai and claude into one file and removed logic from the base class, also made helper class definable from command line

This commit is contained in:
2025-06-03 13:04:42 -05:00
parent bd0ce3e340
commit f15228fa58
36 changed files with 487 additions and 3847 deletions
+72 -74
View File
@@ -1,6 +1,5 @@
# tools/github_tool.py
from .base_tool import BaseTool
from .metrics import metrics
import requests
import os
import base64
@@ -57,7 +56,8 @@ class GitHubTool(BaseTool):
},
"required": ["path"]
}
}
},
"_tags": ["read"]
},
{
"type": "function",
@@ -71,7 +71,8 @@ class GitHubTool(BaseTool):
},
"required": ["path"]
}
}
},
"_tags": ["read"]
},
{
"type": "function",
@@ -85,7 +86,8 @@ class GitHubTool(BaseTool):
},
"required": ["query"]
}
}
},
"_tags": ["read"]
},
{
"type": "function",
@@ -100,7 +102,8 @@ class GitHubTool(BaseTool):
},
"required": ["branch_name"]
}
}
},
"_tags": ["write"]
},
{
"type": "function",
@@ -116,7 +119,8 @@ class GitHubTool(BaseTool):
},
"required": ["file_path", "commit_message", "content"]
}
}
},
"_tags": ["write"]
},
{
"type": "function",
@@ -132,7 +136,8 @@ class GitHubTool(BaseTool):
},
"required": ["title", "body"]
}
}
},
"_tags": ["write"]
},
{
"type": "function",
@@ -147,7 +152,8 @@ class GitHubTool(BaseTool):
},
"required": ["file_path"]
}
}
},
"_tags": ["read"]
},
{
"type": "function",
@@ -162,7 +168,8 @@ class GitHubTool(BaseTool):
},
"required": ["file_path"]
}
}
},
"_tags": ["read"]
},
{
"type": "function",
@@ -176,7 +183,8 @@ class GitHubTool(BaseTool):
},
"required": ["branch"]
}
}
},
"_tags": ["read"]
},
{
"type": "function",
@@ -184,7 +192,8 @@ class GitHubTool(BaseTool):
"name": "get_current_branch",
"description": "Get the name of the current branch",
"parameters": { "type": "object", "properties": {} }
}
},
"_tags": ["read"]
},
{
"type": "function",
@@ -198,7 +207,8 @@ class GitHubTool(BaseTool):
},
"required": ["branch_name"]
}
}
},
"_tags": ["read", "write"]
},
{
"type": "function",
@@ -213,7 +223,8 @@ class GitHubTool(BaseTool):
},
"required": ["file_path", "commit_sha"]
}
}
},
"_tags": ["read"]
},
{
"type": "function",
@@ -227,7 +238,8 @@ class GitHubTool(BaseTool):
"all_pages": {"type": "boolean", "description": "Whether to fetch all pages of results", "default": True}
}
}
}
},
"_tags": ["read"]
},
{
"type": "function",
@@ -241,7 +253,8 @@ class GitHubTool(BaseTool):
},
"required": ["pull_number"]
}
}
},
"_tags": ["write"]
},
{
"type": "function",
@@ -255,7 +268,8 @@ class GitHubTool(BaseTool):
},
"required": ["pull_number"]
}
}
},
"_tags": ["write"]
},
{
"type": "function",
@@ -277,7 +291,8 @@ class GitHubTool(BaseTool):
},
"required": ["pull_number"]
}
}
},
"_tags": ["write"]
},
{
"type": "function",
@@ -291,7 +306,8 @@ class GitHubTool(BaseTool):
},
"required": ["branch_name"]
}
}
},
"_tags": ["write"]
},
{
"type": "function",
@@ -305,7 +321,8 @@ class GitHubTool(BaseTool):
},
"required": ["issue_number"]
}
}
},
"_tags": ["read"]
},
{
"type": "function",
@@ -325,7 +342,8 @@ class GitHubTool(BaseTool):
},
"required": ["title", "body"]
}
}
},
"_tags": ["communicate"]
},
{
"type": "function",
@@ -340,7 +358,8 @@ class GitHubTool(BaseTool):
"page": {"type": "integer", "default": 1, "description": "Page number of the results to fetch"}
}
}
}
},
"_tags": ["read"]
},
{
"type": "function",
@@ -355,7 +374,8 @@ class GitHubTool(BaseTool):
},
"required": ["issue_number", "comment"]
}
}
},
"_tags": ["communicate"]
},
{
"type": "function",
@@ -369,7 +389,8 @@ class GitHubTool(BaseTool):
},
"required": ["issue_number"]
}
}
},
"_tags": ["read"]
},
{
"type": "function",
@@ -383,7 +404,8 @@ class GitHubTool(BaseTool):
},
"required": ["pull_number"]
}
}
},
"_tags": ["read"]
},
{
"type": "function",
@@ -398,7 +420,8 @@ class GitHubTool(BaseTool):
},
"required": ["name"]
}
}
},
"_tags": ["communicate"]
},
{
"type": "function",
@@ -413,7 +436,8 @@ class GitHubTool(BaseTool):
},
"required": ["project_id", "column_name"]
}
}
},
"_tags": ["communicate"]
},
{
"type": "function",
@@ -428,7 +452,8 @@ class GitHubTool(BaseTool):
},
"required": ["column_id", "note"]
}
}
},
"_tags": ["communicate"]
},
{
"type": "function",
@@ -444,7 +469,8 @@ class GitHubTool(BaseTool):
},
"required": ["card_id", "position", "column_id"]
}
}
},
"_tags": ["communicate"]
},
{
"type": "function",
@@ -460,7 +486,8 @@ class GitHubTool(BaseTool):
},
"required": ["card_id", "content_id", "content_type"]
}
}
},
"_tags": ["communicate"]
},
{
"type": "function",
@@ -468,7 +495,8 @@ class GitHubTool(BaseTool):
"name": "list_project_boards",
"description": "List project boards associated with the repository",
"parameters": { "type": "object", "properties": {} }
}
},
"_tags": ["communicate"]
},
{
"type": "function",
@@ -482,7 +510,8 @@ class GitHubTool(BaseTool):
},
"required": ["project_id"]
}
}
},
"_tags": ["communicate"]
},
{
"type": "function",
@@ -496,7 +525,8 @@ class GitHubTool(BaseTool):
},
"required": ["pull_number"]
}
}
},
"_tags": ["read"]
},
{
"type": "function",
@@ -510,7 +540,8 @@ class GitHubTool(BaseTool):
},
"required": ["pull_number"]
}
}
},
"_tags": ["read"]
},
{
"type": "function",
@@ -524,7 +555,8 @@ class GitHubTool(BaseTool):
},
"required": ["pull_number"]
}
}
},
"_tags": ["read"]
},
{
"type": "function",
@@ -545,7 +577,8 @@ class GitHubTool(BaseTool):
},
"required": ["pull_number", "body", "commit_id", "path", "position"]
}
}
},
"_tags": ["communicate"]
},
{
"type": "function",
@@ -559,7 +592,8 @@ class GitHubTool(BaseTool):
},
"required": ["pull_number"]
}
}
},
"_tags": ["read"]
},
{
"type": "function",
@@ -575,11 +609,11 @@ class GitHubTool(BaseTool):
},
"required": ["pull_number", "event"]
}
}
},
"_tags": ["communicate"]
}
]
@metrics.measure
def execute(self, function_name, **kwargs):
self.logger.info(f"Executing GitHub Tool function: {function_name} with args: {kwargs}")
# Dispatch to the appropriate private method
@@ -598,7 +632,6 @@ class GitHubTool(BaseTool):
# Private methods for each function, using self.session for HTTP requests
@metrics.measure
def _read_file(self, path):
self.logger.info(f"Reading file: {path} from branch: {self.current_branch}")
url = f"{self.base_url}/repos/{self._repo}/contents/{path}"
@@ -613,7 +646,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _create_branch(self, branch_name, base_branch="main"):
self.logger.info(f"Creating branch: {branch_name} from base: {base_branch}")
# Get SHA of base branch
@@ -639,7 +671,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _commit_file(self, file_path, content, commit_message):
self.logger.info(f"Committing file: {file_path} to branch: {self.current_branch} with message: '{commit_message}'")
if self.current_branch == "main":
@@ -679,7 +710,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _create_pull_request(self, title, body, base="main"):
self.logger.info(f"Creating pull request: '{title}' from branch '{self.current_branch}' to '{base}'")
if self.current_branch == base:
@@ -701,7 +731,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _get_branch_sha(self, branch):
self.logger.info(f"Getting SHA for branch: {branch}")
url = f"{self.base_url}/repos/{self._repo}/git/refs/heads/{branch}"
@@ -715,7 +744,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _list_files(self, path):
self.logger.info(f"Listing files in path: '{path}' on branch: '{self.current_branch}'")
url = f"{self.base_url}/repos/{self._repo}/contents/{path.strip('/')}" # Ensure no leading/trailing slashes for consistency
@@ -738,7 +766,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _search_code(self, query):
self.logger.info(f"Searching code with query: '{query}' in repo: '{self._repo}'")
url = f"{self.base_url}/search/code"
@@ -754,7 +781,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _get_commit_history(self, file_path, num_commits=10):
self.logger.info(f"Getting last {num_commits} commit(s) for file: '{file_path}' on branch '{self.current_branch}'")
url = f"{self.base_url}/repos/{self._repo}/commits"
@@ -775,18 +801,15 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _view_commit_details_for_file(self, file_path, num_commits=10):
# This function is essentially the same as get_commit_history based on its description.
self.logger.info(f"Viewing commit details for file '{file_path}' (last {num_commits} commits) - using _get_commit_history.")
return self._get_commit_history(file_path, num_commits)
@metrics.measure
def _get_current_branch(self):
self.logger.info(f"Current branch is: {self.current_branch}")
return self.current_branch
@metrics.measure
def _set_current_branch(self, branch_name):
self.logger.info(f"Attempting to set current branch to: {branch_name}")
# Check if branch exists by trying to get its SHA
@@ -801,7 +824,6 @@ class GitHubTool(BaseTool):
self.logger.info(success_message)
return success_message
@metrics.measure
def _get_file_at_commit(self, file_path, commit_sha):
self.logger.info(f"Getting file '{file_path}' at commit SHA: {commit_sha}")
url = f"{self.base_url}/repos/{self._repo}/contents/{file_path}"
@@ -816,7 +838,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _list_branches(self, per_page=100, all_pages=True):
self.logger.info(f"Listing branches for repo '{self._repo}'. Per_page={per_page}, All_pages={all_pages}")
url = f"{self.base_url}/repos/{self._repo}/branches"
@@ -844,7 +865,6 @@ class GitHubTool(BaseTool):
self.logger.info(f"Successfully listed {len(branches_list)} branches.")
return branches_list
@metrics.measure
def _approve_pull_request(self, pull_number):
self.logger.info(f"Approving pull request #{pull_number}")
url = f"{self.base_url}/repos/{self._repo}/pulls/{pull_number}/reviews"
@@ -859,7 +879,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _close_pull_request(self, pull_number):
self.logger.info(f"Closing pull request #{pull_number}")
url = f"{self.base_url}/repos/{self._repo}/pulls/{pull_number}"
@@ -874,7 +893,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _merge_pull_request(self, pull_number, commit_title="Merge pull request", commit_message="", merge_method="merge"):
self.logger.info(f"Merging pull request #{pull_number} using method '{merge_method}'")
url = f"{self.base_url}/repos/{self._repo}/pulls/{pull_number}/merge"
@@ -897,7 +915,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _delete_branch(self, branch_name):
self.logger.info(f"Deleting branch: {branch_name}")
if branch_name == "main" or (hasattr(self, 'default_branch') and branch_name == self.default_branch) :
@@ -920,7 +937,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _get_issue_details(self, issue_number):
self.logger.info(f"Getting details for issue #{issue_number}")
url = f"{self.base_url}/repos/{self._repo}/issues/{issue_number}"
@@ -933,7 +949,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _create_issue(self, title, body, labels=None):
self.logger.info(f"Creating new issue with title: '{title}'")
url = f"{self.base_url}/repos/{self._repo}/issues"
@@ -953,7 +968,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _list_issues(self, state="open", per_page=30, page=1):
self.logger.info(f"Listing issues with state: {state}, per_page: {per_page}, page: {page}")
url = f"{self.base_url}/repos/{self._repo}/issues"
@@ -969,7 +983,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _add_issue_comment(self, issue_number, comment):
self.logger.info(f"Adding comment to issue #{issue_number}: '{comment[:50]}...'")
url = f"{self.base_url}/repos/{self._repo}/issues/{issue_number}/comments"
@@ -985,7 +998,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _get_issue_comments(self, issue_number):
self.logger.info(f"Getting comments for issue #{issue_number}")
url = f"{self.base_url}/repos/{self._repo}/issues/{issue_number}/comments"
@@ -1000,14 +1012,12 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _get_pull_request_general_comments(self, pull_number):
self.logger.info(f"Getting general comments for pull request #{pull_number}")
# In GitHub API, PR comments (general, not review comments on lines) are issue comments.
# The PR is also an issue, so use the issue comments endpoint.
return self._get_issue_comments(issue_number=pull_number)
@metrics.measure
def _create_project_board(self, name, body=None):
self.logger.info(f"Creating project board: '{name}'")
url = f"{self.base_url}/repos/{self._repo}/projects"
@@ -1026,7 +1036,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _create_project_column(self, project_id, column_name):
self.logger.info(f"Creating column '{column_name}' for project ID: {project_id}")
url = f"{self.base_url}/projects/{project_id}/columns"
@@ -1044,7 +1053,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _create_project_card(self, column_id, note=None, content_id=None, content_type=None):
self.logger.info(f"Creating card in column ID: {column_id}")
url = f"{self.base_url}/projects/columns/{column_id}/cards"
@@ -1075,7 +1083,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _move_project_card(self, card_id, position, column_id=None):
self.logger.info(f"Moving card ID: {card_id} to position: {position}" + (f" in column ID: {column_id}" if column_id else ""))
url = f"{self.base_url}/projects/columns/cards/{card_id}/moves"
@@ -1100,7 +1107,6 @@ class GitHubTool(BaseTool):
# For updating an existing card to link an issue, one would PATCH the card's content_id/content_type.
# Let's assume the function intends to update an existing card if it's a separate function.
# However, the provided API spec for `link_issue_to_project_card` uses PATCH on card_id, so let's implement that.
@metrics.measure
def _link_issue_to_project_card(self, card_id, content_id, content_type):
self.logger.info(f"Linking content_id {content_id} (type: {content_type}) to card_id {card_id}")
url = f"{self.base_url}/projects/cards/{card_id}" # Note: API docs suggest /projects/columns/cards/{card_id} or /projects/cards/{card_id}
@@ -1120,7 +1126,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _list_project_boards(self):
self.logger.info(f"Listing project boards for repo: {self._repo}")
url = f"{self.base_url}/repos/{self._repo}/projects"
@@ -1136,7 +1141,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _view_project_board_items(self, project_id):
self.logger.info(f"Viewing items for project ID: {project_id}")
columns_url = f"{self.base_url}/projects/{project_id}/columns"
@@ -1165,7 +1169,6 @@ class GitHubTool(BaseTool):
self.logger.info(f"Successfully retrieved items for project ID: {project_id}.")
return project_items
@metrics.measure
def _get_pull_request_details(self, pull_number):
self.logger.info(f"Getting details for PR #{pull_number}")
url = f"{self.base_url}/repos/{self._repo}/pulls/{pull_number}"
@@ -1178,7 +1181,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _get_pull_request_diff(self, pull_number):
self.logger.info(f"Getting diff for PR #{pull_number}")
url = f"{self.base_url}/repos/{self._repo}/pulls/{pull_number}"
@@ -1193,7 +1195,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _get_pull_request_files(self, pull_number):
self.logger.info(f"Getting files for PR #{pull_number}")
url = f"{self.base_url}/repos/{self._repo}/pulls/{pull_number}/files"
@@ -1206,7 +1207,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _create_pull_request_review_comment(self, pull_number, body, commit_id, path, position, side="RIGHT", start_line=None, start_side=None):
self.logger.info(f"Creating review comment on PR #{pull_number}, file '{path}', position {position}")
url = f"{self.base_url}/repos/{self._repo}/pulls/{pull_number}/comments"
@@ -1225,7 +1225,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _list_pull_request_review_comments(self, pull_number):
self.logger.info(f"Listing review comments for PR #{pull_number}")
url = f"{self.base_url}/repos/{self._repo}/pulls/{pull_number}/comments"
@@ -1238,7 +1237,6 @@ class GitHubTool(BaseTool):
self.logger.error(error_message)
return error_message
@metrics.measure
def _submit_pull_request_review(self, pull_number, event, body=None):
self.logger.info(f"Submitting '{event}' review for PR #{pull_number}")
url = f"{self.base_url}/repos/{self._repo}/pulls/{pull_number}/reviews"