From 2f5e8472b90461d00135a450f6210f3db1debaf3 Mon Sep 17 00:00:00 2001 From: mrT23 Date: Wed, 30 Oct 2024 08:48:08 +0200 Subject: [PATCH 01/28] Add PRDescriptionHeader enum for consistent "Changes walkthrough" usage across modules --- pr_agent/algo/utils.py | 2 +- pr_agent/git_providers/azuredevops_provider.py | 2 +- pr_agent/tools/pr_description.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pr_agent/algo/utils.py b/pr_agent/algo/utils.py index 6a23d609..e7d9d5f4 100644 --- a/pr_agent/algo/utils.py +++ b/pr_agent/algo/utils.py @@ -1028,7 +1028,7 @@ def process_description(description_full: str) -> Tuple[str, List]: if not description_full: return "", [] - description_split = description_full.split(PRDescriptionHeader.CHANGES_WALKTHROUGH) + description_split = description_full.split(PRDescriptionHeader.CHANGES_WALKTHROUGH.value) base_description_str = description_split[0] changes_walkthrough_str = "" files = [] diff --git a/pr_agent/git_providers/azuredevops_provider.py b/pr_agent/git_providers/azuredevops_provider.py index de782998..501b1440 100644 --- a/pr_agent/git_providers/azuredevops_provider.py +++ b/pr_agent/git_providers/azuredevops_provider.py @@ -404,7 +404,7 @@ class AzureDevopsProvider(GitProvider): pr_body = pr_body[:ind] if len(pr_body) > MAX_PR_DESCRIPTION_AZURE_LENGTH: - changes_walkthrough_text = PRDescriptionHeader.CHANGES_WALKTHROUGH + changes_walkthrough_text = PRDescriptionHeader.CHANGES_WALKTHROUGH.value ind = pr_body.find(changes_walkthrough_text) if ind != -1: pr_body = pr_body[:ind] diff --git a/pr_agent/tools/pr_description.py b/pr_agent/tools/pr_description.py index 1d397a54..64355b60 100644 --- a/pr_agent/tools/pr_description.py +++ b/pr_agent/tools/pr_description.py @@ -501,7 +501,7 @@ extra_file_yaml = pr_body += "\n" elif 'pr_files' in key.lower() and get_settings().pr_description.enable_semantic_files_types: changes_walkthrough, pr_file_changes = self.process_pr_files_prediction(changes_walkthrough, value) - changes_walkthrough = f"{PRDescriptionHeader.CHANGES_WALKTHROUGH}\n{changes_walkthrough}" + changes_walkthrough = f"{PRDescriptionHeader.CHANGES_WALKTHROUGH.value}\n{changes_walkthrough}" else: # if the value is a list, join its items by comma if isinstance(value, list): From 6b649243556c37868c759d9ee2f5c9a2155919d1 Mon Sep 17 00:00:00 2001 From: "Hussam.lawen" Date: Wed, 30 Oct 2024 17:09:44 +0200 Subject: [PATCH 02/28] switch the order of when to disable the existing code, to make sure reflection see's the full suggestion (before and after) --- pr_agent/tools/pr_code_suggestions.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/pr_agent/tools/pr_code_suggestions.py b/pr_agent/tools/pr_code_suggestions.py index 1426ff1a..37a89a56 100644 --- a/pr_agent/tools/pr_code_suggestions.py +++ b/pr_agent/tools/pr_code_suggestions.py @@ -367,6 +367,18 @@ class PRCodeSuggestions: "code_suggestions_feedback": code_suggestions_feedback[i]}) suggestion["score"] = 7 suggestion["score_why"] = "" + + # if the before and after code is the same, clear one of them + try: + if suggestion['existing_code'] == suggestion['improved_code']: + get_logger().debug( + f"edited improved suggestion {i + 1}, because equal to existing code: {suggestion['existing_code']}") + if get_settings().pr_code_suggestions.commitable_code_suggestions: + suggestion['improved_code'] = "" # we need 'existing_code' to locate the code in the PR + else: + suggestion['existing_code'] = "" + except Exception as e: + get_logger().error(f"Error processing suggestion {i + 1}, error: {e}") else: # get_logger().error(f"Could not self-reflect on suggestions. using default score 7") for i, suggestion in enumerate(data["code_suggestions"]): @@ -422,13 +434,6 @@ class PRCodeSuggestions: continue if ('existing_code' in suggestion) and ('improved_code' in suggestion): - if suggestion['existing_code'] == suggestion['improved_code']: - get_logger().debug( - f"edited improved suggestion {i + 1}, because equal to existing code: {suggestion['existing_code']}") - if get_settings().pr_code_suggestions.commitable_code_suggestions: - suggestion['improved_code'] = "" # we need 'existing_code' to locate the code in the PR - else: - suggestion['existing_code'] = "" suggestion = self._truncate_if_needed(suggestion) one_sentence_summary_list.append(suggestion['one_sentence_summary']) suggestion_list.append(suggestion) From 7419a6d51ac754989c2b6f8b407529ac97813c0a Mon Sep 17 00:00:00 2001 From: nomi3 Date: Thu, 31 Oct 2024 17:40:31 +0900 Subject: [PATCH 03/28] chore: update bitbucket-pipelines.yml filename in installation documentation --- docs/docs/installation/bitbucket.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/installation/bitbucket.md b/docs/docs/installation/bitbucket.md index 8648803f..346c86f8 100644 --- a/docs/docs/installation/bitbucket.md +++ b/docs/docs/installation/bitbucket.md @@ -3,7 +3,7 @@ You can use the Bitbucket Pipeline system to run Qodo Merge on every pull request open or update. -1. Add the following file in your repository bitbucket_pipelines.yml +1. Add the following file in your repository bitbucket-pipelines.yml ```yaml pipelines: From 84c1c1b1cad585442ab229af0540cd800b04f640 Mon Sep 17 00:00:00 2001 From: mrT23 Date: Thu, 31 Oct 2024 11:12:35 +0200 Subject: [PATCH 04/28] Add certifi==2024.8.30 to requirements.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 0adf66ca..ec88a4ca 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,6 +4,7 @@ atlassian-python-api==3.41.4 azure-devops==7.1.0b3 azure-identity==1.15.0 boto3==1.33.6 +certifi==2024.8.30 dynaconf==3.2.4 fastapi==0.111.0 GitPython==3.1.41 From 443d06df06c1458a724dc976eaa8beaead41fee5 Mon Sep 17 00:00:00 2001 From: Pratul Sanwal Date: Fri, 1 Nov 2024 14:47:47 -0400 Subject: [PATCH 05/28] Add configuration option to control publish of no code suggestions message --- pr_agent/settings/configuration.toml | 1 + pr_agent/tools/pr_code_suggestions.py | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/pr_agent/settings/configuration.toml b/pr_agent/settings/configuration.toml index 6d1f0cee..038010e2 100644 --- a/pr_agent/settings/configuration.toml +++ b/pr_agent/settings/configuration.toml @@ -7,6 +7,7 @@ fallback_models=["gpt-4o-2024-05-13"] git_provider="github" publish_output=true publish_output_progress=true +publish_output_no_suggestions=true verbosity_level=0 # 0,1,2 use_extra_bad_extensions=false # Configurations diff --git a/pr_agent/tools/pr_code_suggestions.py b/pr_agent/tools/pr_code_suggestions.py index 37a89a56..e4218ba8 100644 --- a/pr_agent/tools/pr_code_suggestions.py +++ b/pr_agent/tools/pr_code_suggestions.py @@ -113,12 +113,15 @@ class PRCodeSuggestions: if (data is None or 'code_suggestions' not in data or not data['code_suggestions'] and get_settings().config.publish_output): get_logger().warning('No code suggestions found for the PR.') - pr_body = "## PR Code Suggestions ✨\n\nNo code suggestions found for the PR." - get_logger().debug(f"PR output", artifact=pr_body) - if self.progress_response: - self.git_provider.edit_comment(self.progress_response, body=pr_body) - else: - self.git_provider.publish_comment(pr_body) + + if (get_settings().config.publish_output_no_suggestions): + pr_body = "## PR Code Suggestions ✨\n\nNo code suggestions found for the PR." + get_logger().debug(f"PR output", artifact=pr_body) + if self.progress_response: + self.git_provider.edit_comment(self.progress_response, body=pr_body) + else: + self.git_provider.publish_comment(pr_body) + return if (not self.is_extended and get_settings().pr_code_suggestions.rank_suggestions) or \ From dacb45dd8abb398993ed06ab1c0fc9089e5c9590 Mon Sep 17 00:00:00 2001 From: zhouleilei Date: Sat, 2 Nov 2024 09:47:14 +0800 Subject: [PATCH 06/28] Merge branch 'main' of https://github.com/ryanzll/pr-agent update openai api --- .../algo/ai_handlers/openai_ai_handler.py | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/pr_agent/algo/ai_handlers/openai_ai_handler.py b/pr_agent/algo/ai_handlers/openai_ai_handler.py index 999f3d3f..8e755b46 100644 --- a/pr_agent/algo/ai_handlers/openai_ai_handler.py +++ b/pr_agent/algo/ai_handlers/openai_ai_handler.py @@ -1,6 +1,7 @@ +from os import environ from pr_agent.algo.ai_handlers.base_ai_handler import BaseAiHandler import openai -from openai.error import APIError, RateLimitError, Timeout, TryAgain +from openai import APIError, AsyncOpenAI, RateLimitError, Timeout from retry import retry from pr_agent.config_loader import get_settings @@ -14,7 +15,7 @@ class OpenAIHandler(BaseAiHandler): # Initialize OpenAIHandler specific attributes here try: super().__init__() - openai.api_key = get_settings().openai.key + environ["OPENAI_API_KEY"] = get_settings().openai.key if get_settings().get("OPENAI.ORG", None): openai.organization = get_settings().openai.org if get_settings().get("OPENAI.API_TYPE", None): @@ -24,7 +25,7 @@ class OpenAIHandler(BaseAiHandler): if get_settings().get("OPENAI.API_VERSION", None): openai.api_version = get_settings().openai.api_version if get_settings().get("OPENAI.API_BASE", None): - openai.api_base = get_settings().openai.api_base + environ["OPENAI_BASE_URL"] = get_settings().openai.api_base except AttributeError as e: raise ValueError("OpenAI key is required") from e @@ -36,7 +37,7 @@ class OpenAIHandler(BaseAiHandler): """ return get_settings().get("OPENAI.DEPLOYMENT_ID", None) - @retry(exceptions=(APIError, Timeout, TryAgain, AttributeError, RateLimitError), + @retry(exceptions=(APIError, Timeout, AttributeError, RateLimitError), tries=OPENAI_RETRIES, delay=2, backoff=2, jitter=(1, 3)) async def chat_completion(self, model: str, system: str, user: str, temperature: float = 0.2): try: @@ -44,20 +45,19 @@ class OpenAIHandler(BaseAiHandler): get_logger().info("System: ", system) get_logger().info("User: ", user) messages = [{"role": "system", "content": system}, {"role": "user", "content": user}] - - chat_completion = await openai.ChatCompletion.acreate( + client = AsyncOpenAI() + chat_completion = await client.chat.completions.create( model=model, - deployment_id=deployment_id, messages=messages, temperature=temperature, ) - resp = chat_completion["choices"][0]['message']['content'] - finish_reason = chat_completion["choices"][0]["finish_reason"] - usage = chat_completion.get("usage") + resp = chat_completion.choices[0].message.content + finish_reason = chat_completion.choices[0].finish_reason + usage = chat_completion.usage get_logger().info("AI response", response=resp, messages=messages, finish_reason=finish_reason, model=model, usage=usage) return resp, finish_reason - except (APIError, Timeout, TryAgain) as e: + except (APIError, Timeout) as e: get_logger().error("Error during OpenAI inference: ", e) raise except (RateLimitError) as e: @@ -65,4 +65,4 @@ class OpenAIHandler(BaseAiHandler): raise except (Exception) as e: get_logger().error("Unknown error during OpenAI inference: ", e) - raise TryAgain from e + raise \ No newline at end of file From 02949b2b96c5c92f46d09ba25bc25d0920355d1f Mon Sep 17 00:00:00 2001 From: Tal Date: Sun, 3 Nov 2024 14:14:14 +0200 Subject: [PATCH 07/28] Update additional_configurations.md --- docs/docs/usage-guide/additional_configurations.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/docs/usage-guide/additional_configurations.md b/docs/docs/usage-guide/additional_configurations.md index 89573d3f..72aa99b8 100644 --- a/docs/docs/usage-guide/additional_configurations.md +++ b/docs/docs/usage-guide/additional_configurations.md @@ -160,3 +160,13 @@ ignore_pr_target_branches = ["qa"] Where the `ignore_pr_source_branches` and `ignore_pr_target_branches` are lists of regex patterns to match the source and target branches you want to ignore. They are not mutually exclusive, you can use them together or separately. + + +To allow only specific folders (often needed in large monorepos), set: + +``` +[config] +allow_only_specific_folders=['folder1','folder2'] +``` + +For the configuration above, automatic feedback will only be triggered when the PR changes include files from 'folder1' or 'folder2' From ef3241285d973f95b352de25efefcc3cef2d0fbc Mon Sep 17 00:00:00 2001 From: mrT23 Date: Sun, 3 Nov 2024 17:34:30 +0200 Subject: [PATCH 08/28] Add support for processing diffs without line numbers in code suggestions tool --- docs/docs/core-abilities/self_reflection.md | 1 - docs/docs/tools/improve.md | 4 - pr_agent/settings/configuration.toml | 1 - .../settings/pr_code_suggestions_prompts.toml | 21 +- .../pr_code_suggestions_reflect_prompts.toml | 8 +- pr_agent/tools/pr_code_suggestions.py | 206 +++++++++++------- 6 files changed, 140 insertions(+), 101 deletions(-) diff --git a/docs/docs/core-abilities/self_reflection.md b/docs/docs/core-abilities/self_reflection.md index b8acc395..a03e7808 100644 --- a/docs/docs/core-abilities/self_reflection.md +++ b/docs/docs/core-abilities/self_reflection.md @@ -46,6 +46,5 @@ This results in a more refined and valuable set of suggestions for the user, sav ## Appendix - Relevant Configuration Options ``` [pr_code_suggestions] -self_reflect_on_suggestions = true # Enable self-reflection on code suggestions suggestions_score_threshold = 0 # Filter out suggestions with a score below this threshold (0-10) ``` \ No newline at end of file diff --git a/docs/docs/tools/improve.md b/docs/docs/tools/improve.md index 0b1ff8e5..fed8101c 100644 --- a/docs/docs/tools/improve.md +++ b/docs/docs/tools/improve.md @@ -279,10 +279,6 @@ Using a combination of both can help the AI model to provide relevant and tailor persistent_comment If set to true, the improve comment will be persistent, meaning that every new improve request will edit the previous one. Default is false. - - self_reflect_on_suggestions - If set to true, the improve tool will calculate an importance score for each suggestion [1-10], and sort the suggestion labels group based on this score. Default is true. - suggestions_score_threshold Any suggestion with importance score less than this threshold will be removed. Default is 0. Highly recommend not to set this value above 7-8, since above it may clip relevant suggestions that can be useful. diff --git a/pr_agent/settings/configuration.toml b/pr_agent/settings/configuration.toml index 6d1f0cee..5b1dee81 100644 --- a/pr_agent/settings/configuration.toml +++ b/pr_agent/settings/configuration.toml @@ -121,7 +121,6 @@ max_history_len=4 # enable to apply suggestion 💎 apply_suggestions_checkbox=true # suggestions scoring -self_reflect_on_suggestions=true suggestions_score_threshold=0 # [0-10]| recommend not to set this value above 8, since above it may clip highly relevant suggestions # params for '/improve --extended' mode auto_extended_mode=true diff --git a/pr_agent/settings/pr_code_suggestions_prompts.toml b/pr_agent/settings/pr_code_suggestions_prompts.toml index 5bf15f59..b08a3a2a 100644 --- a/pr_agent/settings/pr_code_suggestions_prompts.toml +++ b/pr_agent/settings/pr_code_suggestions_prompts.toml @@ -14,10 +14,10 @@ The PR code diff will be in the following structured format: @@ ... @@ def func1(): __new hunk__ -11 unchanged code line0 in the PR -12 unchanged code line1 in the PR -13 +new code line2 added in the PR -14 unchanged code line3 in the PR + unchanged code line0 in the PR + unchanged code line1 in the PR ++new code line2 added in the PR + unchanged code line3 in the PR __old hunk__ unchanged code line0 unchanged code line1 @@ -35,7 +35,6 @@ __new hunk__ ====== - In the format above, the diff is organized into separate '__new hunk__' and '__old hunk__' sections for each code chunk. '__new hunk__' contains the updated code, while '__old hunk__' shows the removed code. If no code was removed in a specific chunk, the __old hunk__ section will be omitted. -- Line numbers were added for the '__new hunk__' sections to help referencing specific lines in the code suggestions. These numbers are for reference only and are not part of the actual code. - Code lines are prefixed with symbols: '+' for new code added in the PR, '-' for code removed, and ' ' for unchanged code. {%- if is_ai_metadata %} - When available, an AI-generated summary will precede each file's diff, with a high-level overview of the changes. Note that this summary may not be fully accurate or complete. @@ -44,7 +43,7 @@ __new hunk__ Specific guidelines for generating code suggestions: - Provide up to {{ num_code_suggestions }} distinct and insightful code suggestions. -- Focus solely on enhancing new code introduced in the PR, identified by '+' prefixes in '__new hunk__' sections (after the line numbers). +- Focus solely on enhancing new code introduced in the PR, identified by '+' prefixes in '__new hunk__' sections. - Prioritize suggestions that address potential issues, critical problems, and bugs in the PR code. Avoid repeating changes already implemented in the PR. If no pertinent suggestions are applicable, return an empty list. - Don't suggest to add docstring, type hints, or comments, to remove unused imports, or to use more specific exception types. - When referencing variables or names from the code, enclose them in backticks (`). Example: "ensure that `variable_name` is..." @@ -67,12 +66,10 @@ class CodeSuggestion(BaseModel): relevant_file: str = Field(description="Full path of the relevant file") language: str = Field(description="Programming language used by the relevant file") suggestion_content: str = Field(description="An actionable suggestion to enhance, improve or fix the new code introduced in the PR. Don't present here actual code snippets, just the suggestion. Be short and concise") - existing_code: str = Field(description="A short code snippet from a '__new hunk__' section that the suggestion aims to enhance or fix. Include only complete code lines, without line numbers. Use ellipsis (...) for brevity if needed. This snippet should represent the specific PR code targeted for improvement.") + existing_code: str = Field(description="A short code snippet from a '__new hunk__' section that the suggestion aims to enhance or fix. Include only complete code lines. Use ellipsis (...) for brevity if needed. This snippet should represent the specific PR code targeted for improvement.") improved_code: str = Field(description="A refined code snippet that replaces the 'existing_code' snippet after implementing the suggestion.") one_sentence_summary: str = Field(description="A concise, single-sentence overview of the suggested improvement. Focus on the 'what'. Be general, and avoid method or variable names.") - relevant_lines_start: int = Field(description="The relevant line number, from a '__new hunk__' section, where the suggestion starts (inclusive). Should be derived from the hunk line numbers, and correspond to the beginning of the 'existing code' snippet above") - relevant_lines_end: int = Field(description="The relevant line number, from a '__new hunk__' section, where the suggestion ends (inclusive). Should be derived from the hunk line numbers, and correspond to the end of the 'existing code' snippet above") - label: str = Field(description="A single, descriptive label that best characterizes the suggestion type. Possible labels include 'security', 'possible bug', 'possible issue', 'performance', 'enhancement', 'best practice', 'maintainability'. Other relevant labels are also acceptable.") + label: str = Field(description="A single, descriptive label that best characterizes the suggestion type. Possible labels include 'security', 'possible bug', 'possible issue', 'performance', 'enhancement', 'best practice', 'maintainability', 'typo'. Other relevant labels are also acceptable.") class PRCodeSuggestions(BaseModel): @@ -95,8 +92,6 @@ code_suggestions: ... one_sentence_summary: | ... - relevant_lines_start: 12 - relevant_lines_end: 13 label: | ... ``` @@ -112,7 +107,7 @@ Title: '{{title}}' The PR Diff: ====== -{{ diff|trim }} +{{ diff_no_line_numbers|trim }} ====== diff --git a/pr_agent/settings/pr_code_suggestions_reflect_prompts.toml b/pr_agent/settings/pr_code_suggestions_reflect_prompts.toml index 512ec592..34b1eec4 100644 --- a/pr_agent/settings/pr_code_suggestions_reflect_prompts.toml +++ b/pr_agent/settings/pr_code_suggestions_reflect_prompts.toml @@ -15,8 +15,8 @@ Be particularly vigilant for suggestions that: - Contradict or ignore parts of the PR's modifications In such cases, assign the suggestion a score of 0. -For valid suggestions, your role is to provide an impartial and precise score assessment that accurately reflects each suggestion's potential impact on the PR's correctness, quality and functionality. - +Evaluate each valid suggestion by scoring its potential impact on the PR's correctness, quality and functionality. +In addition, you should also detect the line numbers in the '__new hunk__' section that correspond to the 'existing_code' snippet. Key guidelines for evaluation: - Thoroughly examine both the suggestion content and the corresponding PR code diff. Be vigilant for potential errors in each suggestion, ensuring they are logically sound, accurate, and directly derived from the PR code diff. @@ -82,6 +82,8 @@ The output must be a YAML object equivalent to type $PRCodeSuggestionsFeedback, class CodeSuggestionFeedback(BaseModel): suggestion_summary: str = Field(description="Repeated from the input") relevant_file: str = Field(description="Repeated from the input") + relevant_lines_start: int = Field(description="The relevant line number, from a '__new hunk__' section, where the suggestion starts (inclusive). Should be derived from the hunk line numbers, and correspond to the beginning of the relevant 'existing code' snippet") + relevant_lines_end: int = Field(description="The relevant line number, from a '__new hunk__' section, where the suggestion ends (inclusive). Should be derived from the hunk line numbers, and correspond to the end of the relevant 'existing code' snippet") suggestion_score: int = Field(description="Evaluate the suggestion and assign a score from 0 to 10. Give 0 if the suggestion is wrong. For valid suggestions, score from 1 (lowest impact/importance) to 10 (highest impact/importance).") why: str = Field(description="Briefly explain the score given in 1-2 sentences, focusing on the suggestion's impact, relevance, and accuracy.") @@ -96,6 +98,8 @@ code_suggestions: - suggestion_summary: | Use a more descriptive variable name here relevant_file: "src/file1.py" + relevant_lines_start: 13 + relevant_lines_end: 14 suggestion_score: 6 why: | The variable name 't' is not descriptive enough diff --git a/pr_agent/tools/pr_code_suggestions.py b/pr_agent/tools/pr_code_suggestions.py index 37a89a56..8ea02dc4 100644 --- a/pr_agent/tools/pr_code_suggestions.py +++ b/pr_agent/tools/pr_code_suggestions.py @@ -1,6 +1,7 @@ import asyncio import copy import textwrap +import traceback from functools import partial from typing import Dict, List from jinja2 import Environment, StrictUndefined @@ -44,7 +45,7 @@ class PRCodeSuggestions: self.is_extended = self._get_is_extended(args or []) except: self.is_extended = False - num_code_suggestions = get_settings().pr_code_suggestions.num_code_suggestions_per_chunk + num_code_suggestions = int(get_settings().pr_code_suggestions.num_code_suggestions_per_chunk) self.ai_handler = ai_handler() @@ -69,6 +70,7 @@ class PRCodeSuggestions: "description": self.pr_description, "language": self.main_language, "diff": "", # empty diff for initial calculation + "diff_no_line_numbers": "", # empty diff for initial calculation "num_code_suggestions": num_code_suggestions, "extra_instructions": get_settings().pr_code_suggestions.extra_instructions, "commit_messages_str": self.git_provider.get_commit_messages(), @@ -110,15 +112,17 @@ class PRCodeSuggestions: if not data: data = {"code_suggestions": []} - if (data is None or 'code_suggestions' not in data or not data['code_suggestions'] - and get_settings().config.publish_output): - get_logger().warning('No code suggestions found for the PR.') + if (data is None or 'code_suggestions' not in data or not data['code_suggestions']): pr_body = "## PR Code Suggestions ✨\n\nNo code suggestions found for the PR." - get_logger().debug(f"PR output", artifact=pr_body) - if self.progress_response: - self.git_provider.edit_comment(self.progress_response, body=pr_body) + if get_settings().config.publish_output: + get_logger().warning('No code suggestions found for the PR.') + get_logger().debug(f"PR output", artifact=pr_body) + if self.progress_response: + self.git_provider.edit_comment(self.progress_response, body=pr_body) + else: + self.git_provider.publish_comment(pr_body) else: - self.git_provider.publish_comment(pr_body) + get_settings().data = {"artifact": ""} return if (not self.is_extended and get_settings().pr_code_suggestions.rank_suggestions) or \ @@ -195,8 +199,11 @@ class PRCodeSuggestions: self.git_provider.remove_comment(self.progress_response) else: get_logger().info('Code suggestions generated for PR, but not published since publish_output is False.') + get_settings().data = {"artifact": data} + return except Exception as e: - get_logger().error(f"Failed to generate code suggestions for PR, error: {e}") + get_logger().error(f"Failed to generate code suggestions for PR, error: {e}", + artifact={"traceback": traceback.format_exc()}) if get_settings().config.publish_output: if self.progress_response: self.progress_response.delete() @@ -328,7 +335,7 @@ class PRCodeSuggestions: if self.patches_diff: get_logger().debug(f"PR diff", artifact=self.patches_diff) - self.prediction = await self._get_prediction(model, self.patches_diff) + self.prediction = await self._get_prediction(model, self.patches_diff, self.patches_diff_no_line_number) else: get_logger().warning(f"Empty PR diff") self.prediction = None @@ -336,54 +343,76 @@ class PRCodeSuggestions: data = self.prediction return data - async def _get_prediction(self, model: str, patches_diff: str) -> dict: + async def _get_prediction(self, model: str, patches_diff: str, patches_diff_no_line_number: str) -> dict: variables = copy.deepcopy(self.vars) variables["diff"] = patches_diff # update diff + variables["diff_no_line_numbers"] = patches_diff_no_line_number # update diff environment = Environment(undefined=StrictUndefined) system_prompt = environment.from_string(self.pr_code_suggestions_prompt_system).render(variables) user_prompt = environment.from_string(get_settings().pr_code_suggestions_prompt.user).render(variables) response, finish_reason = await self.ai_handler.chat_completion( model=model, temperature=get_settings().config.temperature, system=system_prompt, user=user_prompt) + if not get_settings().config.publish_output: + get_settings().system_prompt = system_prompt + get_settings().user_prompt = user_prompt # load suggestions from the AI response data = self._prepare_pr_code_suggestions(response) - # self-reflect on suggestions - if get_settings().pr_code_suggestions.self_reflect_on_suggestions: - model_turbo = get_settings().config.model_turbo # use turbo model for self-reflection, since it is an easier task - response_reflect = await self.self_reflect_on_suggestions(data["code_suggestions"], - patches_diff, model=model_turbo) - if response_reflect: - response_reflect_yaml = load_yaml(response_reflect) - code_suggestions_feedback = response_reflect_yaml["code_suggestions"] - if len(code_suggestions_feedback) == len(data["code_suggestions"]): - for i, suggestion in enumerate(data["code_suggestions"]): - try: - suggestion["score"] = code_suggestions_feedback[i]["suggestion_score"] - suggestion["score_why"] = code_suggestions_feedback[i]["why"] - except Exception as e: # - get_logger().error(f"Error processing suggestion score {i}", - artifact={"suggestion": suggestion, - "code_suggestions_feedback": code_suggestions_feedback[i]}) - suggestion["score"] = 7 - suggestion["score_why"] = "" - - # if the before and after code is the same, clear one of them - try: - if suggestion['existing_code'] == suggestion['improved_code']: - get_logger().debug( - f"edited improved suggestion {i + 1}, because equal to existing code: {suggestion['existing_code']}") - if get_settings().pr_code_suggestions.commitable_code_suggestions: - suggestion['improved_code'] = "" # we need 'existing_code' to locate the code in the PR - else: - suggestion['existing_code'] = "" - except Exception as e: - get_logger().error(f"Error processing suggestion {i + 1}, error: {e}") - else: - # get_logger().error(f"Could not self-reflect on suggestions. using default score 7") + # self-reflect on suggestions (mandatory, since line numbers are generated now here) + model_reflection = get_settings().config.model + response_reflect = await self.self_reflect_on_suggestions(data["code_suggestions"], + patches_diff, model=model_reflection) + if response_reflect: + response_reflect_yaml = load_yaml(response_reflect) + code_suggestions_feedback = response_reflect_yaml["code_suggestions"] + if len(code_suggestions_feedback) == len(data["code_suggestions"]): for i, suggestion in enumerate(data["code_suggestions"]): - suggestion["score"] = 7 - suggestion["score_why"] = "" + try: + suggestion["score"] = code_suggestions_feedback[i]["suggestion_score"] + suggestion["score_why"] = code_suggestions_feedback[i]["why"] + + if 'relevant_lines_start' not in suggestion: + relevant_lines_start = code_suggestions_feedback[i].get('relevant_lines_start', -1) + relevant_lines_end = code_suggestions_feedback[i].get('relevant_lines_end', -1) + suggestion['relevant_lines_start'] = relevant_lines_start + suggestion['relevant_lines_end'] = relevant_lines_end + if relevant_lines_start < 0 or relevant_lines_end < 0: + suggestion["score"] = 0 + + try: + if get_settings().config.publish_output: + suggestion_statistics_dict = {'score': int(suggestion["score"]), + 'label': suggestion["label"].lower().strip()} + get_logger().info(f"PR-Agent suggestions statistics", + statistics=suggestion_statistics_dict, analytics=True) + except Exception as e: + get_logger().error(f"Failed to log suggestion statistics, error: {e}") + pass + + except Exception as e: # + get_logger().error(f"Error processing suggestion score {i}", + artifact={"suggestion": suggestion, + "code_suggestions_feedback": code_suggestions_feedback[i]}) + suggestion["score"] = 7 + suggestion["score_why"] = "" + + # if the before and after code is the same, clear one of them + try: + if suggestion['existing_code'] == suggestion['improved_code']: + get_logger().debug( + f"edited improved suggestion {i + 1}, because equal to existing code: {suggestion['existing_code']}") + if get_settings().pr_code_suggestions.commitable_code_suggestions: + suggestion['improved_code'] = "" # we need 'existing_code' to locate the code in the PR + else: + suggestion['existing_code'] = "" + except Exception as e: + get_logger().error(f"Error processing suggestion {i + 1}, error: {e}") + else: + # get_logger().error(f"Could not self-reflect on suggestions. using default score 7") + for i, suggestion in enumerate(data["code_suggestions"]): + suggestion["score"] = 7 + suggestion["score_why"] = "" return data @@ -393,10 +422,10 @@ class PRCodeSuggestions: suggestion_truncation_message = get_settings().get("PR_CODE_SUGGESTIONS.SUGGESTION_TRUNCATION_MESSAGE", "") if max_code_suggestion_length > 0: if len(suggestion['improved_code']) > max_code_suggestion_length: - suggestion['improved_code'] = suggestion['improved_code'][:max_code_suggestion_length] - suggestion['improved_code'] += f"\n{suggestion_truncation_message}" get_logger().info(f"Truncated suggestion from {len(suggestion['improved_code'])} " f"characters to {max_code_suggestion_length} characters") + suggestion['improved_code'] = suggestion['improved_code'][:max_code_suggestion_length] + suggestion['improved_code'] += f"\n{suggestion_truncation_message}" return suggestion def _prepare_pr_code_suggestions(self, predictions: str) -> Dict: @@ -411,8 +440,7 @@ class PRCodeSuggestions: one_sentence_summary_list = [] for i, suggestion in enumerate(data['code_suggestions']): try: - needed_keys = ['one_sentence_summary', 'label', 'relevant_file', 'relevant_lines_start', - 'relevant_lines_end'] + needed_keys = ['one_sentence_summary', 'label', 'relevant_file'] is_valid_keys = True for key in needed_keys: if key not in suggestion: @@ -536,9 +564,33 @@ class PRCodeSuggestions: return True return False + def remove_line_numbers(self, patches_diff_list: List[str]) -> List[str]: + # create a copy of the patches_diff_list, without line numbers for '__new hunk__' sections + try: + self.patches_diff_list_no_line_numbers = [] + for patches_diff in self.patches_diff_list: + patches_diff_lines = patches_diff.splitlines() + for i, line in enumerate(patches_diff_lines): + if line.strip(): + if line[0].isdigit(): + # find the first letter in the line that starts with a valid letter + for j, char in enumerate(line): + if not char.isdigit(): + patches_diff_lines[i] = line[j + 1:] + break + self.patches_diff_list_no_line_numbers.append('\n'.join(patches_diff_lines)) + return self.patches_diff_list_no_line_numbers + except Exception as e: + get_logger().error(f"Error removing line numbers from patches_diff_list, error: {e}") + return patches_diff_list + async def _prepare_prediction_extended(self, model: str) -> dict: self.patches_diff_list = get_pr_multi_diffs(self.git_provider, self.token_handler, model, max_calls=get_settings().pr_code_suggestions.max_number_of_calls) + + # create a copy of the patches_diff_list, without line numbers for '__new hunk__' sections + self.patches_diff_list_no_line_numbers = self.remove_line_numbers(self.patches_diff_list) + if self.patches_diff_list: get_logger().info(f"Number of PR chunk calls: {len(self.patches_diff_list)}") get_logger().debug(f"PR diff:", artifact=self.patches_diff_list) @@ -546,12 +598,14 @@ class PRCodeSuggestions: # parallelize calls to AI: if get_settings().pr_code_suggestions.parallel_calls: prediction_list = await asyncio.gather( - *[self._get_prediction(model, patches_diff) for patches_diff in self.patches_diff_list]) + *[self._get_prediction(model, patches_diff, patches_diff_no_line_numbers) for + patches_diff, patches_diff_no_line_numbers in + zip(self.patches_diff_list, self.patches_diff_list_no_line_numbers)]) self.prediction_list = prediction_list else: prediction_list = [] - for i, patches_diff in enumerate(self.patches_diff_list): - prediction = await self._get_prediction(model, patches_diff) + for patches_diff, patches_diff_no_line_numbers in zip(self.patches_diff_list, self.patches_diff_list_no_line_numbers): + prediction = await self._get_prediction(model, patches_diff, patches_diff_no_line_numbers) prediction_list.append(prediction) data = {"code_suggestions": []} @@ -560,18 +614,16 @@ class PRCodeSuggestions: score_threshold = max(1, int(get_settings().pr_code_suggestions.suggestions_score_threshold)) for i, prediction in enumerate(predictions["code_suggestions"]): try: - if get_settings().pr_code_suggestions.self_reflect_on_suggestions: - score = int(prediction.get("score", 1)) - if score >= score_threshold: - data["code_suggestions"].append(prediction) - else: - get_logger().info( - f"Removing suggestions {i} from call {j}, because score is {score}, and score_threshold is {score_threshold}", - artifact=prediction) - else: + score = int(prediction.get("score", 1)) + if score >= score_threshold: data["code_suggestions"].append(prediction) + else: + get_logger().info( + f"Removing suggestions {i} from call {j}, because score is {score}, and score_threshold is {score_threshold}", + artifact=prediction) except Exception as e: - get_logger().error(f"Error getting PR diff for suggestion {i} in call {j}, error: {e}") + get_logger().error(f"Error getting PR diff for suggestion {i} in call {j}, error: {e}", + artifact={"prediction": prediction}) self.data = data else: get_logger().warning(f"Empty PR diff list") @@ -622,7 +674,7 @@ class PRCodeSuggestions: if get_settings().pr_code_suggestions.final_clip_factor != 1: max_len = max( len(data_sorted), - get_settings().pr_code_suggestions.num_code_suggestions_per_chunk, + int(get_settings().pr_code_suggestions.num_code_suggestions_per_chunk), ) new_len = int(0.5 + max_len * get_settings().pr_code_suggestions.final_clip_factor) if new_len < len(data_sorted): @@ -655,10 +707,7 @@ class PRCodeSuggestions: header = f"Suggestion" delta = 66 header += "  " * delta - if get_settings().pr_code_suggestions.self_reflect_on_suggestions: - pr_body += f"""Category{header}Score""" - else: - pr_body += f"""Category{header}""" + pr_body += f"""Category{header}Score""" pr_body += """""" suggestions_labels = dict() # add all suggestions related to each label @@ -669,12 +718,11 @@ class PRCodeSuggestions: suggestions_labels[label].append(suggestion) # sort suggestions_labels by the suggestion with the highest score - if get_settings().pr_code_suggestions.self_reflect_on_suggestions: - suggestions_labels = dict( - sorted(suggestions_labels.items(), key=lambda x: max([s['score'] for s in x[1]]), reverse=True)) - # sort the suggestions inside each label group by score - for label, suggestions in suggestions_labels.items(): - suggestions_labels[label] = sorted(suggestions, key=lambda x: x['score'], reverse=True) + suggestions_labels = dict( + sorted(suggestions_labels.items(), key=lambda x: max([s['score'] for s in x[1]]), reverse=True)) + # sort the suggestions inside each label group by score + for label, suggestions in suggestions_labels.items(): + suggestions_labels[label] = sorted(suggestions, key=lambda x: x['score'], reverse=True) counter_suggestions = 0 for label, suggestions in suggestions_labels.items(): @@ -733,16 +781,14 @@ class PRCodeSuggestions: {example_code.rstrip()} """ - if get_settings().pr_code_suggestions.self_reflect_on_suggestions: - pr_body += f"
Suggestion importance[1-10]: {suggestion['score']}\n\n" - pr_body += f"Why: {suggestion['score_why']}\n\n" - pr_body += f"
" + pr_body += f"
Suggestion importance[1-10]: {suggestion['score']}\n\n" + pr_body += f"Why: {suggestion['score_why']}\n\n" + pr_body += f"
" pr_body += f"" # # add another column for 'score' - if get_settings().pr_code_suggestions.self_reflect_on_suggestions: - pr_body += f"{suggestion['score']}\n\n" + pr_body += f"{suggestion['score']}\n\n" pr_body += f"" counter_suggestions += 1 From 16029e66ad2a526ccc22f98c84291c964d1e797c Mon Sep 17 00:00:00 2001 From: Tal Date: Sun, 3 Nov 2024 18:15:09 +0200 Subject: [PATCH 09/28] Update README.md --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index ef535434..9bebb2a6 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,13 @@ Qode Merge PR-Agent aims to help efficiently review and handle pull requests, by ## News and Updates +### November 3, 2024 + +Meaningful improvement to the quality of code suggestions by separating the code suggestion generation from [line number detection](https://github.com/Codium-ai/pr-agent/pull/1338) + +![image](https://github.com/user-attachments/assets/093c185c-31ca-47a1-a4fe-be7d9335ea66) + + ### October 27, 2024 Qodo Merge PR Agent will now automatically document accepted code suggestions in a dedicated wiki page (`.pr_agent_accepted_suggestions`), enabling users to track historical changes, assess the tool's effectiveness, and learn from previously implemented recommendations in the repository. From 022e407d841a6d5cb4ac4fc01bef823728b31521 Mon Sep 17 00:00:00 2001 From: "Hussam.lawen" Date: Mon, 4 Nov 2024 15:52:39 +0200 Subject: [PATCH 10/28] add documentation for ticket integrations --- .../core-abilities/fetching_ticket_context.md | 115 ++++++++++++++++++ docs/docs/core-abilities/index.md | 2 +- docs/mkdocs.yml | 1 + 3 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 docs/docs/core-abilities/fetching_ticket_context.md diff --git a/docs/docs/core-abilities/fetching_ticket_context.md b/docs/docs/core-abilities/fetching_ticket_context.md new file mode 100644 index 00000000..851895bf --- /dev/null +++ b/docs/docs/core-abilities/fetching_ticket_context.md @@ -0,0 +1,115 @@ +# Fetching Ticket Context for PRs +## Overview +Qodo Merge PR Agent streamlines code review workflows by seamlessly connecting with multiple ticket management systems. +This integration enriches the review process by automatically surfacing relevant ticket information and context alongside code changes. + + +## Affected Tools + +Ticket Recognition Requirements: + +1. The PR description should contain a link to the ticket. +2. For Jira tickets, you should follow the instructions in #jira-integration in order to authenticate with Jira. + + +### Describe tool +Qodo Merge PR Agent will recognize the ticket and use the ticket content (title, description, labels) to provide additional context for the code changes. +By understanding the reasoning and intent behind modifications, the LLM can offer more insightful and relevant code analysis. + +### Review tool +Similarly to the `describe` tool, the `review` tool will use the ticket content to provide additional context for the code changes. + +In addition, This feature will evaluate how well a Pull Request (PR) adheres to its original purpose/intent as defined by the associated ticket or issue mentioned in the PR description. +Each ticket will be assigned a label (Compliance/Alignment level), Indicates the degree to which the PR fulfills its original purpose, Options: Fully compliant, Partially compliant or Not compliant. + + +![Ticket Compliance](https://www.qodo.ai/images/pr_agent/ticket_compliance_review.png){width=768} + +By default, the tool will automatically validate if the PR complies with the referenced ticket. +If you want to disable this feedback, add the following line to your configuration file: + +```toml +[pr_reviewer] +require_ticket_analysis_review=false +``` + +## Providers + +### Github Issues Integration + +Qodo Merge PR Agent will automatically recognize Github issues mentioned in the PR description and fetch the issue content. +Examples of valid GitHub issue references: + +- `https://github.com///issues/` +- `#` +- `/#` + +Since Qodo Merge PR Agent is integrated with GitHub, it doesn't require any additional configuration to fetch GitHub issues. + +### Jira Integration 💎 + +We support both Jira Cloud and Jira Server/Data Center. +To integrate with Jira, The PR Description should contain a link to the Jira ticket. + +For Jira integration, include a ticket reference in your PR description using either the complete URL format `https://.atlassian.net/browse/ISSUE-123` or the shortened ticket ID `ISSUE-123`. + +!!! note "Jira Base URL" + If using the shortened format, ensure your configuration file contains the Jira base URL under the [jira] section like this: + + ```toml + [jira] + jira_base_url = "https://.atlassian.net" + ``` + +#### Jira Cloud 💎 +There are two ways to authenticate with Jira Cloud: + +**1) Jira App Authentication** + +The recommended way to authenticate with Jira Cloud is to install the Qodo Merge app in your Jira Cloud instance. This will allow Qodo Merge to access Jira data on your behalf. + +Installation steps: + +1. Click [here](https://auth.atlassian.com/authorize?audience=api.atlassian.com&client_id=8krKmA4gMD8mM8z24aRCgPCSepZNP1xf&scope=read%3Ajira-work%20offline_access&redirect_uri=https%3A%2F%2Fregister.jira.pr-agent.codium.ai&state=qodomerge&response_type=code&prompt=consent) to install the Qodo Merge app in your Jira Cloud instance, click the `accept` button.
+![Jira Cloud App Installation](https://www.qodo.ai/images/pr_agent/jira_app_installation1.png){width=384} + +2. After installing the app, you will be redirected to the Qodo Merge registration page. and you will see a success message.
+![Jira Cloud App success message](https://www.qodo.ai/images/pr_agent/jira_app_success.png){width=384} + +3. Now you can use the Jira integration in Qodo Merge PR Agent. + +**2) Email/Token Authentication** + +You can create an API token from your Atlassian account: + +1. Log in to https://id.atlassian.com/manage-profile/security/api-tokens. + +2. Click Create API token. + +3. From the dialog that appears, enter a name for your new token and click Create. + +4. Click Copy to clipboard. + +![Jira Cloud API Token](https://images.ctfassets.net/zsv3d0ugroxu/1RYvh9lqgeZjjNe5S3Hbfb/155e846a1cb38f30bf17512b6dfd2229/screenshot_NewAPIToken){width=384} + +5. In your [configuration file](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/) add the following lines: + +```toml +[jira] +jira_api_token = "YOUR_API_TOKEN" +jira_api_email = "YOUR_EMAIL" +``` + + +#### Jira Server/Data Center 💎 + +Currently we only Personal Access Token (PAT) Authentication method. + +1. Create a [Personal Access Token (PAT)](https://confluence.atlassian.com/enterprise/using-personal-access-tokens-1026032365.html) in your Jira account +2. In your [configuration file](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/) add the following lines: + +```toml +[jira] +jira_base_url = "YOUR_JIRA_BASE_URL" # e.g. https://jira.example.com +jira_api_token = "YOUR_API_TOKEN" +``` \ No newline at end of file diff --git a/docs/docs/core-abilities/index.md b/docs/docs/core-abilities/index.md index c9f288bc..51f01b69 100644 --- a/docs/docs/core-abilities/index.md +++ b/docs/docs/core-abilities/index.md @@ -1,6 +1,6 @@ # Core Abilities Qodo Merge utilizes a variety of core abilities to provide a comprehensive and efficient code review experience. These abilities include: - +- [Fetching ticket context](https://qodo-merge-docs.qodo.ai/core-abilities/fetching_ticket_context/) - [Local and global metadata](https://qodo-merge-docs.qodo.ai/core-abilities/metadata/) - [Dynamic context](https://qodo-merge-docs.qodo.ai/core-abilities/dynamic_context/) - [Self-reflection](https://qodo-merge-docs.qodo.ai/core-abilities/self_reflection/) diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index f6957536..b168f621 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -43,6 +43,7 @@ nav: - 💎 Similar Code: 'tools/similar_code.md' - Core Abilities: - 'core-abilities/index.md' + - Fetching ticket context: 'core-abilities/fetching_ticket_context.md' - Local and global metadata: 'core-abilities/metadata.md' - Dynamic context: 'core-abilities/dynamic_context.md' - Self-reflection: 'core-abilities/self_reflection.md' From c1f4964a5539bae2c2e67aee43265e4371d3be13 Mon Sep 17 00:00:00 2001 From: "Hussam.lawen" Date: Mon, 4 Nov 2024 16:19:17 +0200 Subject: [PATCH 11/28] update review --- docs/docs/tools/review.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/tools/review.md b/docs/docs/tools/review.md index 2fd774f6..5c740023 100644 --- a/docs/docs/tools/review.md +++ b/docs/docs/tools/review.md @@ -140,7 +140,7 @@ num_code_suggestions = ... require_ticket_analysis_review - If set to true, and the PR contains a GitHub ticket number, the tool will add a section that checks if the PR in fact fulfilled the ticket requirements. Default is true. + If set to true, and the PR contains a GitHub or Jira ticket link, the tool will add a section that checks if the PR in fact fulfilled the ticket requirements. Default is true. From 5939d3b17b8eb0e5bc826422c452e3b345de93b5 Mon Sep 17 00:00:00 2001 From: "Hussam.lawen" Date: Mon, 4 Nov 2024 16:32:53 +0200 Subject: [PATCH 12/28] readme --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 9bebb2a6..e96d31b5 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,11 @@ Qode Merge PR-Agent aims to help efficiently review and handle pull requests, by ## News and Updates +### November 4, 2024 + +Qodo Merge PR Agent will now leverage context from Jira or GitHub tickets to enhance the PR Feedback. Read more about this feature +[here](https://qodo-merge-docs.qodo.ai/core-abilities/fetching_ticket_context/) + ### November 3, 2024 Meaningful improvement to the quality of code suggestions by separating the code suggestion generation from [line number detection](https://github.com/Codium-ai/pr-agent/pull/1338) From b2181e4c79cec55592c2ccc5af6a5feecb062135 Mon Sep 17 00:00:00 2001 From: "Hussam.lawen" Date: Mon, 4 Nov 2024 16:35:21 +0200 Subject: [PATCH 13/28] typos --- docs/docs/core-abilities/fetching_ticket_context.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/core-abilities/fetching_ticket_context.md b/docs/docs/core-abilities/fetching_ticket_context.md index 851895bf..7b6bd5e7 100644 --- a/docs/docs/core-abilities/fetching_ticket_context.md +++ b/docs/docs/core-abilities/fetching_ticket_context.md @@ -19,7 +19,7 @@ By understanding the reasoning and intent behind modifications, the LLM can offe ### Review tool Similarly to the `describe` tool, the `review` tool will use the ticket content to provide additional context for the code changes. -In addition, This feature will evaluate how well a Pull Request (PR) adheres to its original purpose/intent as defined by the associated ticket or issue mentioned in the PR description. +In addition, this feature will evaluate how well a Pull Request (PR) adheres to its original purpose/intent as defined by the associated ticket or issue mentioned in the PR description. Each ticket will be assigned a label (Compliance/Alignment level), Indicates the degree to which the PR fulfills its original purpose, Options: Fully compliant, Partially compliant or Not compliant. @@ -103,7 +103,7 @@ jira_api_email = "YOUR_EMAIL" #### Jira Server/Data Center 💎 -Currently we only Personal Access Token (PAT) Authentication method. +Currently, we only support the Personal Access Token (PAT) Authentication method. 1. Create a [Personal Access Token (PAT)](https://confluence.atlassian.com/enterprise/using-personal-access-tokens-1026032365.html) in your Jira account 2. In your [configuration file](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/) add the following lines: From eb44ecb1be93da9808ca3d01e9285a0d3a3eb9b5 Mon Sep 17 00:00:00 2001 From: "Hussam.lawen" Date: Mon, 4 Nov 2024 17:18:18 +0200 Subject: [PATCH 14/28] update docs --- docs/docs/core-abilities/fetching_ticket_context.md | 4 ++-- docs/docs/core-abilities/index.md | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/docs/core-abilities/fetching_ticket_context.md b/docs/docs/core-abilities/fetching_ticket_context.md index 7b6bd5e7..cf8aa8d9 100644 --- a/docs/docs/core-abilities/fetching_ticket_context.md +++ b/docs/docs/core-abilities/fetching_ticket_context.md @@ -9,7 +9,7 @@ This integration enriches the review process by automatically surfacing relevant Ticket Recognition Requirements: 1. The PR description should contain a link to the ticket. -2. For Jira tickets, you should follow the instructions in #jira-integration in order to authenticate with Jira. +2. For Jira tickets, you should follow the instructions in [Jira Integration](https://qodo-merge-docs.qodo.ai/core-abilities/fetching_ticket_context/#jira-integration) in order to authenticate with Jira. ### Describe tool @@ -106,7 +106,7 @@ jira_api_email = "YOUR_EMAIL" Currently, we only support the Personal Access Token (PAT) Authentication method. 1. Create a [Personal Access Token (PAT)](https://confluence.atlassian.com/enterprise/using-personal-access-tokens-1026032365.html) in your Jira account -2. In your [configuration file](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/) add the following lines: +2. In your Configuration file/Environment variables/Secrets file, add the following lines: ```toml [jira] diff --git a/docs/docs/core-abilities/index.md b/docs/docs/core-abilities/index.md index 51f01b69..7059b83e 100644 --- a/docs/docs/core-abilities/index.md +++ b/docs/docs/core-abilities/index.md @@ -1,5 +1,6 @@ # Core Abilities Qodo Merge utilizes a variety of core abilities to provide a comprehensive and efficient code review experience. These abilities include: + - [Fetching ticket context](https://qodo-merge-docs.qodo.ai/core-abilities/fetching_ticket_context/) - [Local and global metadata](https://qodo-merge-docs.qodo.ai/core-abilities/metadata/) - [Dynamic context](https://qodo-merge-docs.qodo.ai/core-abilities/dynamic_context/) From 6e3544f52393e0398a84d5bf8e36b3209ad69040 Mon Sep 17 00:00:00 2001 From: Tal Date: Tue, 5 Nov 2024 11:27:38 +0200 Subject: [PATCH 15/28] Update automations_and_usage.md --- .../docs/usage-guide/automations_and_usage.md | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/docs/docs/usage-guide/automations_and_usage.md b/docs/docs/usage-guide/automations_and_usage.md index 57e1adeb..11354503 100644 --- a/docs/docs/usage-guide/automations_and_usage.md +++ b/docs/docs/usage-guide/automations_and_usage.md @@ -72,13 +72,13 @@ The configuration parameter `pr_commands` defines the list of tools that will be ``` [github_app] pr_commands = [ - "/describe --pr_description.final_update_message=false", - "/review --pr_reviewer.num_code_suggestions=0", - "/improve", + "/describe", + "/review", + "/improve --pr_code_suggestions.suggestions_score_threshold=5", ] ``` This means that when a new PR is opened/reopened or marked as ready for review, Qodo Merge will run the `describe`, `review` and `improve` tools. -For the `review` tool, for example, the `num_code_suggestions` parameter will be set to 0. +For the `improve` tool, for example, the `suggestions_score_threshold` parameter will be set to 5 (suggestions below a score of 5 won't be presented) You can override the default tool parameters by using one the three options for a [configuration file](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/): **wiki**, **local**, or **global**. For example, if your local `.pr_agent.toml` file contains: @@ -105,7 +105,7 @@ The configuration parameter `push_commands` defines the list of tools that will handle_push_trigger = true push_commands = [ "/describe", - "/review --pr_reviewer.num_code_suggestions=0 --pr_reviewer.final_update_message=false", + "/review", ] ``` This means that when new code is pushed to the PR, the Qodo Merge will run the `describe` and `review` tools, with the specified parameters. @@ -148,12 +148,12 @@ After setting up a GitLab webhook, to control which commands will run automatica [gitlab] pr_commands = [ "/describe", - "/review --pr_reviewer.num_code_suggestions=0", + "/review", "/improve", ] ``` -the GitLab webhook can also respond to new code that is pushed to an open MR. +The GitLab webhook can also respond to new code that is pushed to an open MR. The configuration toggle `handle_push_trigger` can be used to enable this feature. The configuration parameter `push_commands` defines the list of tools that will be **run automatically** when new code is pushed to the MR. ``` @@ -161,7 +161,7 @@ The configuration parameter `push_commands` defines the list of tools that will handle_push_trigger = true push_commands = [ "/describe", - "/review --pr_reviewer.num_code_suggestions=0 --pr_reviewer.final_update_message=false", + "/review", ] ``` @@ -182,7 +182,7 @@ Each time you invoke a `/review` tool, it will use the extra instructions you se Note that among other limitations, BitBucket provides relatively low rate-limits for applications (up to 1000 requests per hour), and does not provide an API to track the actual rate-limit usage. -If you experience lack of responses from Qodo Merge, you might want to set: `bitbucket_app.avoid_full_files=true` in your configuration file. +If you experience a lack of responses from Qodo Merge, you might want to set: `bitbucket_app.avoid_full_files=true` in your configuration file. This will prevent Qodo Merge from acquiring the full file content, and will only use the diff content. This will reduce the number of requests made to BitBucket, at the cost of small decrease in accuracy, as dynamic context will not be applicable. @@ -194,13 +194,23 @@ Specifically, set the following values: ``` [bitbucket_app] pr_commands = [ - "/review --pr_reviewer.num_code_suggestions=0", + "/review", "/improve --pr_code_suggestions.commitable_code_suggestions=true --pr_code_suggestions.suggestions_score_threshold=7", ] ``` Note that we set specifically for bitbucket, we recommend using: `--pr_code_suggestions.suggestions_score_threshold=7` and that is the default value we set for bitbucket. Since this platform only supports inline code suggestions, we want to limit the number of suggestions, and only present a limited number. +To enable BitBucket app to respond to each **push** to the PR, set (for example): +``` +[bitbucket_app] +handle_push_trigger = true +push_commands = [ + "/describe", + "/review", +] +``` + ## Azure DevOps provider To use Azure DevOps provider use the following settings in configuration.toml: @@ -210,7 +220,7 @@ git_provider="azure" ``` Azure DevOps provider supports [PAT token](https://learn.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows) or [DefaultAzureCredential](https://learn.microsoft.com/en-us/azure/developer/python/sdk/authentication-overview#authentication-in-server-environments) authentication. -PAT is faster to create, but has build in expiration date, and will use the user identity for API calls. +PAT is faster to create, but has a build in expiration date, and will use the user identity for API calls. Using DefaultAzureCredential you can use managed identity or Service principle, which are more secure and will create separate ADO user identity (via AAD) to the agent. If PAT was chosen, you can assign the value in .secrets.toml. From 157251493acdc6d0a273700e2bf9a3a3a22432e6 Mon Sep 17 00:00:00 2001 From: KennyDizi Date: Wed, 6 Nov 2024 07:52:58 +0700 Subject: [PATCH 16/28] Add support claude-3-5-haiku-20241022 model --- pr_agent/algo/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pr_agent/algo/__init__.py b/pr_agent/algo/__init__.py index 83d001a1..f45cfd02 100644 --- a/pr_agent/algo/__init__.py +++ b/pr_agent/algo/__init__.py @@ -31,6 +31,7 @@ MAX_TOKENS = { 'vertex_ai/codechat-bison': 6144, 'vertex_ai/codechat-bison-32k': 32000, 'vertex_ai/claude-3-haiku@20240307': 100000, + 'vertex_ai/claude-3-5-haiku@20241022': 100000, 'vertex_ai/claude-3-sonnet@20240229': 100000, 'vertex_ai/claude-3-opus@20240229': 100000, 'vertex_ai/claude-3-5-sonnet@20240620': 100000, @@ -48,6 +49,7 @@ MAX_TOKENS = { 'anthropic/claude-3-opus-20240229': 100000, 'anthropic/claude-3-5-sonnet-20240620': 100000, 'anthropic/claude-3-5-sonnet-20241022': 100000, + 'anthropic/claude-3-5-haiku-20241022': 100000, 'bedrock/anthropic.claude-instant-v1': 100000, 'bedrock/anthropic.claude-v2': 100000, 'bedrock/anthropic.claude-v2:1': 100000, From c394fc27672f6eb328a2d9e36dd2799807e5a9a0 Mon Sep 17 00:00:00 2001 From: KennyDizi Date: Wed, 6 Nov 2024 07:55:19 +0700 Subject: [PATCH 17/28] Upgrade anthropic version to 0.39.0 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index ec88a4ca..21d2d162 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ aiohttp==3.9.5 -anthropic[vertex]==0.37.1 +anthropic[vertex]==0.39.0 atlassian-python-api==3.41.4 azure-devops==7.1.0b3 azure-identity==1.15.0 From c5ed2f040a086c16bf34fc6997dbe24592819ccb Mon Sep 17 00:00:00 2001 From: KennyDizi Date: Wed, 6 Nov 2024 07:56:30 +0700 Subject: [PATCH 18/28] Update litellm to v1..52.0 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 21d2d162..b57fd494 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ google-cloud-aiplatform==1.38.0 google-generativeai==0.8.3 google-cloud-storage==2.10.0 Jinja2==3.1.2 -litellm==1.50.2 +litellm==1.52.0 loguru==0.7.2 msrest==0.7.1 openai==1.52.1 From 0eacb3e35ee2169bf12d33c0d8d2485a75171ce3 Mon Sep 17 00:00:00 2001 From: KennyDizi Date: Wed, 6 Nov 2024 08:07:19 +0700 Subject: [PATCH 19/28] Update openai to v1.54.1 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b57fd494..75a52b72 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,7 +15,7 @@ Jinja2==3.1.2 litellm==1.52.0 loguru==0.7.2 msrest==0.7.1 -openai==1.52.1 +openai==1.54.1 pytest==7.4.0 PyGithub==1.59.* PyYAML==6.0.1 From 04496f9b0eb2a246ef86ebcb43c228a2525c7524 Mon Sep 17 00:00:00 2001 From: KennyDizi Date: Wed, 6 Nov 2024 08:07:44 +0700 Subject: [PATCH 20/28] Update tiktoken to v0.8.0 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 75a52b72..afb6af68 100644 --- a/requirements.txt +++ b/requirements.txt @@ -22,7 +22,7 @@ PyYAML==6.0.1 python-gitlab==3.15.0 retry==0.9.2 starlette-context==0.3.6 -tiktoken==0.7.0 +tiktoken==0.8.0 ujson==5.8.0 uvicorn==0.22.0 tenacity==8.2.3 From daeca42ae8310fd22d9989d00cdd99921406ef64 Mon Sep 17 00:00:00 2001 From: mrT23 Date: Wed, 6 Nov 2024 12:20:31 +0200 Subject: [PATCH 21/28] Update ticket analysis review setting key in compliance check function --- pr_agent/tools/ticket_pr_compliance_check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pr_agent/tools/ticket_pr_compliance_check.py b/pr_agent/tools/ticket_pr_compliance_check.py index dc760ed1..05cd64fe 100644 --- a/pr_agent/tools/ticket_pr_compliance_check.py +++ b/pr_agent/tools/ticket_pr_compliance_check.py @@ -108,7 +108,7 @@ async def extract_tickets(git_provider): async def extract_and_cache_pr_tickets(git_provider, vars): - if get_settings().get('config.require_ticket_analysis_review', False): + if not get_settings().get('pr_reviewer.require_ticket_analysis_review', False): return related_tickets = get_settings().get('related_tickets', []) if not related_tickets: From d2663f959ae040667abe27e2f937741193957f09 Mon Sep 17 00:00:00 2001 From: mrT23 Date: Wed, 6 Nov 2024 21:22:58 +0200 Subject: [PATCH 22/28] Add focus_only_on_problems setting for targeted code suggestions --- pr_agent/settings/configuration.toml | 3 ++- .../settings/pr_code_suggestions_prompts.toml | 19 +++++++++++++++++-- pr_agent/tools/pr_code_suggestions.py | 6 ++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/pr_agent/settings/configuration.toml b/pr_agent/settings/configuration.toml index 80e2ad84..97d8d363 100644 --- a/pr_agent/settings/configuration.toml +++ b/pr_agent/settings/configuration.toml @@ -107,10 +107,11 @@ enable_help_text=false [pr_code_suggestions] # /improve # -max_context_tokens=14000 +max_context_tokens=16000 # commitable_code_suggestions = false dual_publishing_score_threshold=-1 # -1 to disable, [0-10] to set the threshold (>=) for publishing a code suggestion both in a table and as commitable +focus_only_on_problems=false # extra_instructions = "" rank_suggestions = false diff --git a/pr_agent/settings/pr_code_suggestions_prompts.toml b/pr_agent/settings/pr_code_suggestions_prompts.toml index b08a3a2a..c25e4bb2 100644 --- a/pr_agent/settings/pr_code_suggestions_prompts.toml +++ b/pr_agent/settings/pr_code_suggestions_prompts.toml @@ -1,7 +1,10 @@ [pr_code_suggestions_prompt] system="""You are PR-Reviewer, an AI specializing in Pull Request (PR) code analysis and suggestions. -Your task is to examine the provided code diff, focusing on new code (lines prefixed with '+'), and offer concise, actionable suggestions to fix possible bugs and problems, and enhance code quality, readability, and performance. - +{%- if not focus_only_on_problems %} +Your task is to examine the provided code diff, focusing on new code (lines prefixed with '+'), and offer concise, actionable suggestions to fix possible bugs and problems, and enhance code quality and performance. +{%- else %} +Your task is to examine the provided code diff, focusing on new code (lines prefixed with '+'), and offer concise, actionable suggestions to fix critical bugs and problems. +{%- endif %} The PR code diff will be in the following structured format: ====== @@ -42,9 +45,17 @@ __new hunk__ Specific guidelines for generating code suggestions: +{%- if not focus_only_on_problems %} - Provide up to {{ num_code_suggestions }} distinct and insightful code suggestions. +{%- else %} +- Provide up to {{ num_code_suggestions }} distinct and insightful code suggestions. Return less suggestions if no pertinent ones are applicable. +{%- endif %} - Focus solely on enhancing new code introduced in the PR, identified by '+' prefixes in '__new hunk__' sections. +{%- if not focus_only_on_problems %} - Prioritize suggestions that address potential issues, critical problems, and bugs in the PR code. Avoid repeating changes already implemented in the PR. If no pertinent suggestions are applicable, return an empty list. +{%- else %} +- Only give suggestions that address critical problems and bugs in the PR code. If no relevant suggestions are applicable, return an empty list. +{%- endif %} - Don't suggest to add docstring, type hints, or comments, to remove unused imports, or to use more specific exception types. - When referencing variables or names from the code, enclose them in backticks (`). Example: "ensure that `variable_name` is..." - Be mindful you are viewing a partial PR code diff, not the full codebase. Avoid suggestions that might conflict with unseen code or alerting variables not declared in the visible scope, as the context is incomplete. @@ -69,7 +80,11 @@ class CodeSuggestion(BaseModel): existing_code: str = Field(description="A short code snippet from a '__new hunk__' section that the suggestion aims to enhance or fix. Include only complete code lines. Use ellipsis (...) for brevity if needed. This snippet should represent the specific PR code targeted for improvement.") improved_code: str = Field(description="A refined code snippet that replaces the 'existing_code' snippet after implementing the suggestion.") one_sentence_summary: str = Field(description="A concise, single-sentence overview of the suggested improvement. Focus on the 'what'. Be general, and avoid method or variable names.") +{%- if not focus_only_on_problems %} label: str = Field(description="A single, descriptive label that best characterizes the suggestion type. Possible labels include 'security', 'possible bug', 'possible issue', 'performance', 'enhancement', 'best practice', 'maintainability', 'typo'. Other relevant labels are also acceptable.") +{%- else %} + label: str = Field(description="A single, descriptive label that best characterizes the suggestion type. Possible labels include 'security', 'critical bug', 'general'. The 'general' section should be used for suggestions that address a major issue, but are necessarily on a critical level.") +{%- endif %} class PRCodeSuggestions(BaseModel): diff --git a/pr_agent/tools/pr_code_suggestions.py b/pr_agent/tools/pr_code_suggestions.py index e510bcb0..98fbb629 100644 --- a/pr_agent/tools/pr_code_suggestions.py +++ b/pr_agent/tools/pr_code_suggestions.py @@ -76,6 +76,7 @@ class PRCodeSuggestions: "commit_messages_str": self.git_provider.get_commit_messages(), "relevant_best_practices": "", "is_ai_metadata": get_settings().get("config.enable_ai_metadata", False), + "focus_only_on_problems": get_settings().get("pr_code_suggestions.focus_only_on_problems", False), } self.pr_code_suggestions_prompt_system = get_settings().pr_code_suggestions_prompt.system @@ -451,6 +452,11 @@ class PRCodeSuggestions: if not is_valid_keys: continue + if get_settings().get("pr_code_suggestions.focus_only_on_problems", False): + CRITICAL_LABEL = 'critical' + if CRITICAL_LABEL in suggestion['label'].lower(): # we want the published labels to be less declarative + suggestion['label'] = 'possible issue' + if suggestion['one_sentence_summary'] in one_sentence_summary_list: get_logger().debug(f"Skipping suggestion {i + 1}, because it is a duplicate: {suggestion}") continue From af653a048f219fe916a16f260c22780e7db4abeb Mon Sep 17 00:00:00 2001 From: KennyDizi Date: Thu, 7 Nov 2024 09:12:52 +0700 Subject: [PATCH 23/28] Add support model bedrock/anthropic.claude-3-5-haiku-20241022-v1:0 --- pr_agent/algo/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pr_agent/algo/__init__.py b/pr_agent/algo/__init__.py index f45cfd02..2a9b1f34 100644 --- a/pr_agent/algo/__init__.py +++ b/pr_agent/algo/__init__.py @@ -55,6 +55,7 @@ MAX_TOKENS = { 'bedrock/anthropic.claude-v2:1': 100000, 'bedrock/anthropic.claude-3-sonnet-20240229-v1:0': 100000, 'bedrock/anthropic.claude-3-haiku-20240307-v1:0': 100000, + 'bedrock/anthropic.claude-3-5-haiku-20241022-v1:0': 100000, 'bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0': 100000, 'bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0': 100000, 'claude-3-5-sonnet': 100000, From a8c97bfa7398bcfe938aa7de5005f3f9981a21a5 Mon Sep 17 00:00:00 2001 From: mrT23 Date: Thu, 7 Nov 2024 08:30:18 +0200 Subject: [PATCH 24/28] Add documentation for focus_only_on_problems setting in improve.md and README.md --- README.md | 8 ++++++++ docs/docs/tools/improve.md | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/README.md b/README.md index e96d31b5..9f04c539 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,14 @@ Qode Merge PR-Agent aims to help efficiently review and handle pull requests, by ## News and Updates +### November 7, 2024 + +Added new option: `--pr_code_suggestions.focus_only_on_problems=true` + +When enabled, this option reduces the number of code suggestions and categorizes them into just two groups: "Possible Issues" and "General". The suggestions will focus primarily on identifying and fixing code problems, rather than style considerations like best practices, maintainability, or readability. + +This mode is ideal for developers who want to concentrate specifically on finding and fixing potential bugs in their pull request code. + ### November 4, 2024 Qodo Merge PR Agent will now leverage context from Jira or GitHub tickets to enhance the PR Feedback. Read more about this feature diff --git a/docs/docs/tools/improve.md b/docs/docs/tools/improve.md index fed8101c..524f49b8 100644 --- a/docs/docs/tools/improve.md +++ b/docs/docs/tools/improve.md @@ -275,6 +275,10 @@ Using a combination of both can help the AI model to provide relevant and tailor dual_publishing_score_threshold Minimum score threshold for suggestions to be presented as commitable PR comments in addition to the table. Default is -1 (disabled). + + focus_only_on_problems + If set to true, suggestions will focus primarily on identifying and fixing code problems, and less on style considerations like best practices, maintainability, or readability. Default is false. + persistent_comment If set to true, the improve comment will be persistent, meaning that every new improve request will edit the previous one. Default is false. From 7a5e9102fd33690bc03d36a2464deff2338bf1db Mon Sep 17 00:00:00 2001 From: mrT23 Date: Thu, 7 Nov 2024 08:59:10 +0200 Subject: [PATCH 25/28] Add documentation for focus_only_on_problems setting in improve.md and README.md --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 9f04c539..8eaae23d 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,16 @@ When enabled, this option reduces the number of code suggestions and categorizes This mode is ideal for developers who want to concentrate specifically on finding and fixing potential bugs in their pull request code. +Example result: + +Original mode + +![image](https://qodo.ai/images/pr_agent/code_suggestions_original_mode.png) + +Focused mode + +![image](https://qodo.ai/images/pr_agent/code_suggestions_focused_mode.png) + ### November 4, 2024 Qodo Merge PR Agent will now leverage context from Jira or GitHub tickets to enhance the PR Feedback. Read more about this feature From ee26bf35c17c46999cd036bfbeedee796708512b Mon Sep 17 00:00:00 2001 From: mrT23 Date: Thu, 7 Nov 2024 09:06:30 +0200 Subject: [PATCH 26/28] Add documentation for focus_only_on_problems setting in improve.md and README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8eaae23d..0d94c49b 100644 --- a/README.md +++ b/README.md @@ -55,11 +55,12 @@ Example result: Original mode -![image](https://qodo.ai/images/pr_agent/code_suggestions_original_mode.png) + Focused mode -![image](https://qodo.ai/images/pr_agent/code_suggestions_focused_mode.png) + + ### November 4, 2024 From 84d0f80c81f4d1d8ceeabb4ac6de2a9387f0099c Mon Sep 17 00:00:00 2001 From: mrT23 Date: Thu, 7 Nov 2024 09:07:16 +0200 Subject: [PATCH 27/28] Add documentation for focus_only_on_problems setting in improve.md and README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0d94c49b..bfc7ded4 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,8 @@ When enabled, this option reduces the number of code suggestions and categorizes This mode is ideal for developers who want to concentrate specifically on finding and fixing potential bugs in their pull request code. -Example result: + +**Example results:** Original mode From 6339845eb4ba3eb3f9f54b416777cede7e8bcc99 Mon Sep 17 00:00:00 2001 From: NxPKG Date: Thu, 7 Nov 2024 14:24:35 +0600 Subject: [PATCH 28/28] Remove unused deployment_id variable. The deployment_id variable is assigned but never used in the function. --- pr_agent/algo/ai_handlers/openai_ai_handler.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pr_agent/algo/ai_handlers/openai_ai_handler.py b/pr_agent/algo/ai_handlers/openai_ai_handler.py index 8e755b46..00419c7d 100644 --- a/pr_agent/algo/ai_handlers/openai_ai_handler.py +++ b/pr_agent/algo/ai_handlers/openai_ai_handler.py @@ -41,7 +41,6 @@ class OpenAIHandler(BaseAiHandler): tries=OPENAI_RETRIES, delay=2, backoff=2, jitter=(1, 3)) async def chat_completion(self, model: str, system: str, user: str, temperature: float = 0.2): try: - deployment_id = self.deployment_id get_logger().info("System: ", system) get_logger().info("User: ", user) messages = [{"role": "system", "content": system}, {"role": "user", "content": user}] @@ -65,4 +64,4 @@ class OpenAIHandler(BaseAiHandler): raise except (Exception) as e: get_logger().error("Unknown error during OpenAI inference: ", e) - raise \ No newline at end of file + raise