From fd41041e12ec654d2a75a53c07c16d0ccc31a00d Mon Sep 17 00:00:00 2001 From: "Abuzar Mahmood (aider)" Date: Sat, 22 Feb 2025 17:49:38 -0500 Subject: [PATCH 1/9] feat: Add GitHub Actions log parsing and error feedback functionality --- src/agents.py | 35 +++++++++++++++------- src/git_utils.py | 63 ++++++++++++++++++++++++++++++++++++++ src/response_agent.py | 70 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 157 insertions(+), 11 deletions(-) diff --git a/src/agents.py b/src/agents.py index 4934e47..ead45d8 100644 --- a/src/agents.py +++ b/src/agents.py @@ -43,16 +43,31 @@ "summary_assistant": """You are a helpful GitHub bot that reviews issues and generates appropriate responses. Analyze the issue details carefully and summarize the suggestions and changes made by other agents. """, - "feedback_assistant": """You are a helpful GitHub bot that processes user feedback on previous bot responses. - Analyze the user's feedback carefully and suggest improvements to the original response. - Focus on addressing specific concerns raised by the user. - Maintain a professional and helpful tone. - DO NOT MAKE ANY CHANGES TO THE FILES OR CREATE NEW FILES. Only provide information or suggestions. - If no changes are needed, respond accordingly. - NEVER ask for user input and NEVER expect it. - If possible, suggest concrete code changes or additions that can be made. Be specific about what files and what lines. - Provide code blocks where you can. - Include any relevant code snippets or technical details from the original response that should be preserved. + "feedback_assistant": """You are a helpful GitHub bot that processes user feedback and error messages. + You can handle two types of input: + 1. User feedback on previous bot responses + 2. Error messages from GitHub Actions workflow runs + + For user feedback: + - Analyze feedback carefully and suggest improvements + - Focus on addressing specific concerns + - Maintain a professional tone + - Suggest concrete code changes where possible + - Include relevant code snippets + + For workflow errors: + - Analyze the error messages carefully + - Identify the root cause of the failure + - Suggest specific fixes for the errors + - Provide code examples where helpful + - Include any relevant documentation links + + General guidelines: + - DO NOT MAKE ANY CHANGES TO FILES. Only provide suggestions. + - Be specific about files and lines that need changes + - NEVER ask for user input + - Use code blocks for all code examples + - Keep responses clear and actionable """, "generate_edit_command_assistant": """You are a helpful GitHub bot that synthesizes all discussion in an issue thread to generate a command for a bot to make edits. Analyze the issue details and comments carefully to generate a detailed and well-organized command. diff --git a/src/git_utils.py b/src/git_utils.py index 3903752..1fe508d 100644 --- a/src/git_utils.py +++ b/src/git_utils.py @@ -5,6 +5,8 @@ import os import subprocess import git +import requests +import re from branch_handler import ( get_issue_related_branches, get_current_branch, @@ -345,6 +347,67 @@ def push_changes_with_authentication( return success_bool, error_msg +def get_workflow_run_logs(repo: Repository, run_id: int) -> List[str]: + """ + Fetch and parse logs from a GitHub Actions workflow run + + Args: + repo: The GitHub repository + run_id: ID of the workflow run + + Returns: + List of extracted log lines + + Raises: + RuntimeError: If logs cannot be fetched + """ + try: + # Get workflow run logs + logs_url = f"https://api.github.com/repos/{repo.full_name}/actions/runs/{run_id}/logs" + headers = { + "Accept": "application/vnd.github+json", + "Authorization": f"Bearer {os.getenv('GITHUB_TOKEN')}", + "X-GitHub-Api-Version": "2022-11-28" + } + response = requests.get(logs_url, headers=headers) + response.raise_for_status() + return response.text.splitlines() + except Exception as e: + raise RuntimeError(f"Failed to fetch workflow logs: {str(e)}") + +def extract_errors_from_logs(log_lines: List[str]) -> List[str]: + """ + Extract error messages from workflow log lines + + Args: + log_lines: List of log lines to parse + + Returns: + List of extracted error messages + """ + error_lines = [] + capture = False + for line in log_lines: + # Start capturing on error indicators + if any(indicator in line for indicator in [ + "Traceback (most recent call last):", + "error:", + "Error:", + "ERROR:", + "FAILED" + ]): + capture = True + error_lines.append(line) + continue + + # Keep capturing until we hit a likely end + if capture: + error_lines.append(line) + if line.strip() == "" or "Process completed" in line: + capture = False + + return error_lines + def has_linked_pr(issue: Issue) -> bool: """ Check if an issue has a linked pull request diff --git a/src/response_agent.py b/src/response_agent.py index 2c6f1b2..5a2582d 100644 --- a/src/response_agent.py +++ b/src/response_agent.py @@ -1,10 +1,11 @@ """ Agent for generating responses to GitHub issues using pyautogen """ -from typing import Optional, Tuple +from typing import Optional, Tuple, List from dotenv import load_dotenv import string +import requests import triggers from agents import ( create_user_agent, @@ -564,6 +565,73 @@ def run_aider(message: str, repo_path: str) -> str: raise RuntimeError(f"Failed to run aider: {e.stderr}") +def process_workflow_errors( + issue: Issue, + repo: Repository, + run_id: int, + pr: PullRequest +) -> None: + """ + Process errors from a GitHub Actions workflow run and post feedback + + Args: + issue: Related GitHub issue + repo: GitHub repository + run_id: Workflow run ID + pr: Related pull request + """ + try: + # Get and parse workflow logs + log_lines = get_workflow_run_logs(repo, run_id) + errors = extract_errors_from_logs(log_lines) + + if errors: + # Create feedback agent + feedback_assistant = create_agent("feedback_assistant", llm_config) + + # Generate prompt with error context + error_text = "\n".join(errors) + feedback_prompt = generate_prompt( + "feedback_assistant", + repo_name=repo.full_name, + repo_path=bot_tools.get_local_repo_path(repo.full_name), + details=get_issue_details(issue), + issue=issue, + original_response="", + feedback_text=f"GitHub Actions workflow failed with errors:\n{error_text}" + ) + + # Get feedback on errors + feedback_results = user.initiate_chats( + [ + { + "recipient": feedback_assistant, + "message": feedback_prompt, + "max_turns": 10, + "summary_method": "reflection_with_llm", + } + ] + ) + + # Extract solution from feedback + for chat in feedback_results[0].chat_history[::-1]: + if check_not_empty(chat['content']): + solution = chat['content'] + break + + # Post feedback as PR comment + response = f"Analysis of workflow failure:\n\n" + response += f"Errors found:\n```\n{error_text}\n```\n\n" + response += f"Suggested solutions:\n{solution}" + + write_str = clean_response(response) + signature = "\n\n---\n*This response was automatically generated by blech_bot*" + pr.create_issue_comment(write_str + signature) + + except Exception as e: + error_msg = f"Failed to process workflow errors: {str(e)}" + pr.create_issue_comment(error_msg) + def process_repository( repo_name: str, ) -> None: From 3d9c290f1e65023a79ab97be119a430618d6e878 Mon Sep 17 00:00:00 2001 From: "Abuzar Mahmood (aider)" Date: Sat, 22 Feb 2025 17:49:48 -0500 Subject: [PATCH 2/9] fix: Import missing types and functions for workflow error processing --- src/response_agent.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/response_agent.py b/src/response_agent.py index 5a2582d..d1dd470 100644 --- a/src/response_agent.py +++ b/src/response_agent.py @@ -6,6 +6,8 @@ from dotenv import load_dotenv import string import requests +from github.PullRequest import PullRequest +from git_utils import get_workflow_run_logs, extract_errors_from_logs, clean_response import triggers from agents import ( create_user_agent, @@ -602,7 +604,8 @@ def process_workflow_errors( ) # Get feedback on errors - feedback_results = user.initiate_chats( + user_agent = create_user_agent() + feedback_results = user_agent.initiate_chats( [ { "recipient": feedback_assistant, From 825ae068ce5fe1c01bdbb921e817e3d8695c9811 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 22 Feb 2025 22:49:56 +0000 Subject: [PATCH 3/9] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/agents.py | 6 +++--- src/git_utils.py | 10 ++++++---- src/response_agent.py | 17 +++++++++-------- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/agents.py b/src/agents.py index ead45d8..da4d58a 100644 --- a/src/agents.py +++ b/src/agents.py @@ -47,21 +47,21 @@ You can handle two types of input: 1. User feedback on previous bot responses 2. Error messages from GitHub Actions workflow runs - + For user feedback: - Analyze feedback carefully and suggest improvements - Focus on addressing specific concerns - Maintain a professional tone - Suggest concrete code changes where possible - Include relevant code snippets - + For workflow errors: - Analyze the error messages carefully - Identify the root cause of the failure - Suggest specific fixes for the errors - Provide code examples where helpful - Include any relevant documentation links - + General guidelines: - DO NOT MAKE ANY CHANGES TO FILES. Only provide suggestions. - Be specific about files and lines that need changes diff --git a/src/git_utils.py b/src/git_utils.py index 1fe508d..0d97ae0 100644 --- a/src/git_utils.py +++ b/src/git_utils.py @@ -375,13 +375,14 @@ def get_workflow_run_logs(repo: Repository, run_id: int) -> List[str]: except Exception as e: raise RuntimeError(f"Failed to fetch workflow logs: {str(e)}") + def extract_errors_from_logs(log_lines: List[str]) -> List[str]: """ Extract error messages from workflow log lines - + Args: log_lines: List of log lines to parse - + Returns: List of extracted error messages """ @@ -399,15 +400,16 @@ def extract_errors_from_logs(log_lines: List[str]) -> List[str]: capture = True error_lines.append(line) continue - + # Keep capturing until we hit a likely end if capture: error_lines.append(line) if line.strip() == "" or "Process completed" in line: capture = False - + return error_lines + def has_linked_pr(issue: Issue) -> bool: """ Check if an issue has a linked pull request diff --git a/src/response_agent.py b/src/response_agent.py index d1dd470..e42111b 100644 --- a/src/response_agent.py +++ b/src/response_agent.py @@ -575,7 +575,7 @@ def process_workflow_errors( ) -> None: """ Process errors from a GitHub Actions workflow run and post feedback - + Args: issue: Related GitHub issue repo: GitHub repository @@ -586,11 +586,11 @@ def process_workflow_errors( # Get and parse workflow logs log_lines = get_workflow_run_logs(repo, run_id) errors = extract_errors_from_logs(log_lines) - + if errors: # Create feedback agent feedback_assistant = create_agent("feedback_assistant", llm_config) - + # Generate prompt with error context error_text = "\n".join(errors) feedback_prompt = generate_prompt( @@ -602,7 +602,7 @@ def process_workflow_errors( original_response="", feedback_text=f"GitHub Actions workflow failed with errors:\n{error_text}" ) - + # Get feedback on errors user_agent = create_user_agent() feedback_results = user_agent.initiate_chats( @@ -615,26 +615,27 @@ def process_workflow_errors( } ] ) - + # Extract solution from feedback for chat in feedback_results[0].chat_history[::-1]: if check_not_empty(chat['content']): solution = chat['content'] break - + # Post feedback as PR comment response = f"Analysis of workflow failure:\n\n" response += f"Errors found:\n```\n{error_text}\n```\n\n" response += f"Suggested solutions:\n{solution}" - + write_str = clean_response(response) signature = "\n\n---\n*This response was automatically generated by blech_bot*" pr.create_issue_comment(write_str + signature) - + except Exception as e: error_msg = f"Failed to process workflow errors: {str(e)}" pr.create_issue_comment(error_msg) + def process_repository( repo_name: str, ) -> None: From 7a5835a5da47933bcf6b6a9f94e6426bf8ee94dc Mon Sep 17 00:00:00 2001 From: "abuzarmahmood (aider)" Date: Mon, 24 Feb 2025 15:32:27 +0000 Subject: [PATCH 4/9] refactor: Improve GitHub workflow log retrieval error handling --- src/git_utils.py | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/git_utils.py b/src/git_utils.py index 0d97ae0..52918bb 100644 --- a/src/git_utils.py +++ b/src/git_utils.py @@ -360,19 +360,46 @@ def get_workflow_run_logs(repo: Repository, run_id: int) -> List[str]: Raises: RuntimeError: If logs cannot be fetched + ValueError: If GitHub token is missing + PermissionError: If user lacks required permissions """ + token = os.getenv('GITHUB_TOKEN') + if not token: + raise ValueError("GitHub token not found in environment variables") + try: # Get workflow run logs logs_url = f"https://api.github.com/repos/{repo.full_name}/actions/runs/{run_id}/logs" headers = { "Accept": "application/vnd.github+json", - "Authorization": f"Bearer {os.getenv('GITHUB_TOKEN')}", + "Authorization": f"Bearer {token}", "X-GitHub-Api-Version": "2022-11-28" } response = requests.get(logs_url, headers=headers) + + if response.status_code == 403: + raise PermissionError( + "Insufficient permissions to access workflow logs. " + "Admin rights to the repository are required." + ) + elif response.status_code == 404: + raise RuntimeError( + f"Workflow run with ID {run_id} not found in repository {repo.full_name}" + ) + response.raise_for_status() + + # Check if response is HTML (error page) instead of logs + content_type = response.headers.get('content-type', '') + if 'text/html' in content_type: + raise RuntimeError( + "Received HTML response instead of logs. " + "This likely indicates an authentication or permission issue." + ) + return response.text.splitlines() - except Exception as e: + + except requests.exceptions.RequestException as e: raise RuntimeError(f"Failed to fetch workflow logs: {str(e)}") From 031e5af98697eac10c2093f37cbd60d1d7206940 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 24 Feb 2025 15:34:53 +0000 Subject: [PATCH 5/9] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/git_utils.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/git_utils.py b/src/git_utils.py index 52918bb..4d9faa4 100644 --- a/src/git_utils.py +++ b/src/git_utils.py @@ -376,7 +376,7 @@ def get_workflow_run_logs(repo: Repository, run_id: int) -> List[str]: "X-GitHub-Api-Version": "2022-11-28" } response = requests.get(logs_url, headers=headers) - + if response.status_code == 403: raise PermissionError( "Insufficient permissions to access workflow logs. " @@ -386,9 +386,9 @@ def get_workflow_run_logs(repo: Repository, run_id: int) -> List[str]: raise RuntimeError( f"Workflow run with ID {run_id} not found in repository {repo.full_name}" ) - + response.raise_for_status() - + # Check if response is HTML (error page) instead of logs content_type = response.headers.get('content-type', '') if 'text/html' in content_type: @@ -396,9 +396,9 @@ def get_workflow_run_logs(repo: Repository, run_id: int) -> List[str]: "Received HTML response instead of logs. " "This likely indicates an authentication or permission issue." ) - + return response.text.splitlines() - + except requests.exceptions.RequestException as e: raise RuntimeError(f"Failed to fetch workflow logs: {str(e)}") From 4d968e09a903dfc8fe7500736cf782d6db6b7c95 Mon Sep 17 00:00:00 2001 From: "abuzarmahmood (aider)" Date: Mon, 24 Mar 2025 21:35:18 +0000 Subject: [PATCH 6/9] feat: Add max consecutive attempts limit for auto-fix workflow errors --- src/git_utils.py | 24 ++++++++++++++++++++++++ src/response_agent.py | 23 +++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/src/git_utils.py b/src/git_utils.py index 4d9faa4..b3618b8 100644 --- a/src/git_utils.py +++ b/src/git_utils.py @@ -437,6 +437,30 @@ def extract_errors_from_logs(log_lines: List[str]) -> List[str]: return error_lines +def get_auto_fix_attempt_count(pr: PullRequest) -> int: + """ + Get the number of auto-fix attempts from PR comments + + Args: + pr: The GitHub pull request + + Returns: + Number of auto-fix attempts made so far + """ + comments = list(pr.get_issue_comments()) + attempt_count = 0 + + for comment in comments: + if "generated by blech_bot" in comment.body and "Attempt " in comment.body: + # Extract attempt number using regex + match = re.search(r"Attempt (\d+)/", comment.body) + if match: + current_attempt = int(match.group(1)) + attempt_count = max(attempt_count, current_attempt) + + return attempt_count + + def has_linked_pr(issue: Issue) -> bool: """ Check if an issue has a linked pull request diff --git a/src/response_agent.py b/src/response_agent.py index e42111b..6e21da1 100644 --- a/src/response_agent.py +++ b/src/response_agent.py @@ -3,6 +3,9 @@ """ from typing import Optional, Tuple, List +# Maximum number of consecutive attempts to auto-fix +MAX_CONSECUTIVE_ATTEMPTS = 5 + from dotenv import load_dotenv import string import requests @@ -30,6 +33,7 @@ get_development_branch, has_linked_pr, push_changes_with_authentication, + get_auto_fix_attempt_count, ) from github.Repository import Repository from github.Issue import Issue @@ -588,11 +592,16 @@ def process_workflow_errors( errors = extract_errors_from_logs(log_lines) if errors: + # Track number of attempts to auto-fix + attempts = 0 + # Create feedback agent feedback_assistant = create_agent("feedback_assistant", llm_config) # Generate prompt with error context error_text = "\n".join(errors) + + # Initial feedback prompt feedback_prompt = generate_prompt( "feedback_assistant", repo_name=repo.full_name, @@ -622,10 +631,24 @@ def process_workflow_errors( solution = chat['content'] break + # Get current attempt count + current_attempt = get_auto_fix_attempt_count(pr) + 1 + + # Check if we've reached the maximum attempts + if current_attempt > MAX_CONSECUTIVE_ATTEMPTS: + response = f"Maximum number of auto-fix attempts ({MAX_CONSECUTIVE_ATTEMPTS}) reached.\n\n" + response += f"Please review the errors manually:\n```\n{error_text}\n```" + + write_str = clean_response(response) + signature = "\n\n---\n*This response was automatically generated by blech_bot*" + pr.create_issue_comment(write_str + signature) + return + # Post feedback as PR comment response = f"Analysis of workflow failure:\n\n" response += f"Errors found:\n```\n{error_text}\n```\n\n" response += f"Suggested solutions:\n{solution}" + response += f"\n\nAttempt {current_attempt}/{MAX_CONSECUTIVE_ATTEMPTS}" write_str = clean_response(response) signature = "\n\n---\n*This response was automatically generated by blech_bot*" From fe5fc0c091a210ba4e9bd95201874e42ad3e429d Mon Sep 17 00:00:00 2001 From: "abuzarmahmood (aider)" Date: Mon, 24 Mar 2025 21:48:43 +0000 Subject: [PATCH 7/9] feat: Add GitHub Actions workflow error parsing and auto-fix functionality --- src/git_utils.py | 127 ++++++++++++++++++++++++++++++++++++++++++ src/response_agent.py | 91 ++++++++++++++++++++++++++++++ 2 files changed, 218 insertions(+) diff --git a/src/git_utils.py b/src/git_utils.py index b3618b8..2d6c474 100644 --- a/src/git_utils.py +++ b/src/git_utils.py @@ -7,6 +7,19 @@ import git import requests import re +from github.PullRequest import PullRequest + + +def clean_response(response: str) -> str: + """Remove any existing signatures or TERMINATE flags from response text""" + # Remove TERMINATE flags + response = re.sub(r'\bTERMINATE\b', '', response, flags=re.IGNORECASE) + + # Remove existing signatures + response = re.sub( + r'\n\n---\n\*This response was automatically generated by blech_bot\*\s*$', '', response) + + return response.strip() from branch_handler import ( get_issue_related_branches, get_current_branch, @@ -484,6 +497,120 @@ def has_linked_pr(issue: Issue) -> bool: return False +def get_workflow_run_logs(repo: Repository, run_id: int) -> List[str]: + """ + Fetch and parse logs from a GitHub Actions workflow run + + Args: + repo: The GitHub repository + run_id: ID of the workflow run + + Returns: + List of extracted log lines + + Raises: + RuntimeError: If logs cannot be fetched + ValueError: If GitHub token is missing + PermissionError: If user lacks required permissions + """ + token = os.getenv('GITHUB_TOKEN') + if not token: + raise ValueError("GitHub token not found in environment variables") + + try: + # Get workflow run logs + logs_url = f"https://api.github.com/repos/{repo.full_name}/actions/runs/{run_id}/logs" + headers = { + "Accept": "application/vnd.github+json", + "Authorization": f"Bearer {token}", + "X-GitHub-Api-Version": "2022-11-28" + } + response = requests.get(logs_url, headers=headers) + + if response.status_code == 403: + raise PermissionError( + "Insufficient permissions to access workflow logs. " + "Admin rights to the repository are required." + ) + elif response.status_code == 404: + raise RuntimeError( + f"Workflow run with ID {run_id} not found in repository {repo.full_name}" + ) + + response.raise_for_status() + + # Check if response is HTML (error page) instead of logs + content_type = response.headers.get('content-type', '') + if 'text/html' in content_type: + raise RuntimeError( + "Received HTML response instead of logs. " + "This likely indicates an authentication or permission issue." + ) + + return response.text.splitlines() + + except requests.exceptions.RequestException as e: + raise RuntimeError(f"Failed to fetch workflow logs: {str(e)}") + + +def extract_errors_from_logs(log_lines: List[str]) -> List[str]: + """ + Extract error messages from workflow log lines + + Args: + log_lines: List of log lines to parse + + Returns: + List of extracted error messages + """ + error_lines = [] + capture = False + for line in log_lines: + # Start capturing on error indicators + if any(indicator in line for indicator in [ + "Traceback (most recent call last):", + "error:", + "Error:", + "ERROR:", + "FAILED" + ]): + capture = True + error_lines.append(line) + continue + + # Keep capturing until we hit a likely end + if capture: + error_lines.append(line) + if line.strip() == "" or "Process completed" in line: + capture = False + + return error_lines + + +def get_auto_fix_attempt_count(pr: PullRequest) -> int: + """ + Get the number of auto-fix attempts from PR comments + + Args: + pr: The GitHub pull request + + Returns: + Number of auto-fix attempts made so far + """ + comments = list(pr.get_issue_comments()) + attempt_count = 0 + + for comment in comments: + if "generated by blech_bot" in comment.body and "Attempt " in comment.body: + # Extract attempt number using regex + match = re.search(r"Attempt (\d+)/", comment.body) + if match: + current_attempt = int(match.group(1)) + attempt_count = max(attempt_count, current_attempt) + + return attempt_count + + if __name__ == '__main__': client = get_github_client() repo = get_repository(client, 'katzlabbrandeis/blech_clust') diff --git a/src/response_agent.py b/src/response_agent.py index 6e21da1..62edac6 100644 --- a/src/response_agent.py +++ b/src/response_agent.py @@ -6,6 +6,9 @@ # Maximum number of consecutive attempts to auto-fix MAX_CONSECUTIVE_ATTEMPTS = 5 +# Maximum number of consecutive attempts to auto-fix +MAX_CONSECUTIVE_ATTEMPTS = 5 + from dotenv import load_dotenv import string import requests @@ -659,6 +662,94 @@ def process_workflow_errors( pr.create_issue_comment(error_msg) +def process_workflow_errors( + issue: Issue, + repo: Repository, + run_id: int, + pr: PullRequest +) -> None: + """ + Process errors from a GitHub Actions workflow run and post feedback + + Args: + issue: Related GitHub issue + repo: GitHub repository + run_id: Workflow run ID + pr: Related pull request + """ + try: + # Get and parse workflow logs + log_lines = get_workflow_run_logs(repo, run_id) + errors = extract_errors_from_logs(log_lines) + + if errors: + # Track number of attempts to auto-fix + attempts = 0 + + # Create feedback agent + feedback_assistant = create_agent("feedback_assistant", llm_config) + + # Generate prompt with error context + error_text = "\n".join(errors) + + # Initial feedback prompt + feedback_prompt = generate_prompt( + "feedback_assistant", + repo_name=repo.full_name, + repo_path=bot_tools.get_local_repo_path(repo.full_name), + details=get_issue_details(issue), + issue=issue, + original_response="", + feedback_text=f"GitHub Actions workflow failed with errors:\n{error_text}" + ) + + # Get feedback on errors + user_agent = create_user_agent() + feedback_results = user_agent.initiate_chats( + [ + { + "recipient": feedback_assistant, + "message": feedback_prompt, + "max_turns": 10, + "summary_method": "reflection_with_llm", + } + ] + ) + + # Extract solution from feedback + for chat in feedback_results[0].chat_history[::-1]: + if check_not_empty(chat['content']): + solution = chat['content'] + break + + # Get current attempt count + current_attempt = get_auto_fix_attempt_count(pr) + 1 + + # Check if we've reached the maximum attempts + if current_attempt > MAX_CONSECUTIVE_ATTEMPTS: + response = f"Maximum number of auto-fix attempts ({MAX_CONSECUTIVE_ATTEMPTS}) reached.\n\n" + response += f"Please review the errors manually:\n```\n{error_text}\n```" + + write_str = clean_response(response) + signature = "\n\n---\n*This response was automatically generated by blech_bot*" + pr.create_issue_comment(write_str + signature) + return + + # Post feedback as PR comment + response = f"Analysis of workflow failure:\n\n" + response += f"Errors found:\n```\n{error_text}\n```\n\n" + response += f"Suggested solutions:\n{solution}" + response += f"\n\nAttempt {current_attempt}/{MAX_CONSECUTIVE_ATTEMPTS}" + + write_str = clean_response(response) + signature = "\n\n---\n*This response was automatically generated by blech_bot*" + pr.create_issue_comment(write_str + signature) + + except Exception as e: + error_msg = f"Failed to process workflow errors: {str(e)}" + pr.create_issue_comment(error_msg) + + def process_repository( repo_name: str, ) -> None: From c0b114977c6ce484ad1940c5ae23eb5fd6214fe9 Mon Sep 17 00:00:00 2001 From: "abuzarmahmood (aider)" Date: Mon, 24 Mar 2025 21:48:53 +0000 Subject: [PATCH 8/9] refactor: Update git_utils imports in response_agent.py --- src/response_agent.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/response_agent.py b/src/response_agent.py index 62edac6..d1798a3 100644 --- a/src/response_agent.py +++ b/src/response_agent.py @@ -13,7 +13,6 @@ import string import requests from github.PullRequest import PullRequest -from git_utils import get_workflow_run_logs, extract_errors_from_logs, clean_response import triggers from agents import ( create_user_agent, @@ -37,6 +36,9 @@ has_linked_pr, push_changes_with_authentication, get_auto_fix_attempt_count, + get_workflow_run_logs, + extract_errors_from_logs, + clean_response, ) from github.Repository import Repository from github.Issue import Issue From 2c58e72f3d9b640dbfb7ebd58b63ec28743e2cab Mon Sep 17 00:00:00 2001 From: abuzarmahmood Date: Tue, 22 Jul 2025 19:22:53 +0000 Subject: [PATCH 9/9] feat: implement GitHub Action log fetching and error extraction functions Co-authored-by: aider (gpt-4o) --- src/git_utils.py | 15 +++++++++++++++ src/response_agent.py | 10 ++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/git_utils.py b/src/git_utils.py index 2d6c474..453b89b 100644 --- a/src/git_utils.py +++ b/src/git_utils.py @@ -9,6 +9,21 @@ import re from github.PullRequest import PullRequest +def get_workflow_logs(repo_full_name, run_id, token): + """Fetch logs for a specific GitHub Actions workflow run""" + url = f"https://api.github.com/repos/{repo_full_name}/actions/runs/{run_id}/logs" + headers = {"Authorization": f"token {token}"} + response = requests.get(url, headers=headers) + if response.status_code == 200: + return response.content + else: + raise Exception(f"Failed to fetch logs: {response.status_code}") + +def create_branch_for_fixes(repo, base_branch, new_branch_name): + """Create a new branch based on the existing branch""" + repo.git.checkout(base_branch) + repo.git.checkout('-b', new_branch_name) + def clean_response(response: str) -> str: """Remove any existing signatures or TERMINATE flags from response text""" diff --git a/src/response_agent.py b/src/response_agent.py index d1798a3..92ef3a4 100644 --- a/src/response_agent.py +++ b/src/response_agent.py @@ -24,6 +24,8 @@ import bot_tools from git_utils import ( + get_workflow_logs, + create_branch_for_fixes, get_github_client, get_repository, write_issue_response, @@ -86,6 +88,14 @@ def check_not_empty(data: str) -> bool: return False +def extract_errors_from_logs(log_content): + """Parse the fetched logs and extract error messages""" + errors = [] + for line in log_content.splitlines(): + if "error" in line.lower(): + errors.append(line) + return errors + def generate_feedback_response( issue: Issue, repo_name: str,