diff --git a/README.md b/README.md
index 0fc53a1d5..b6a5f9016 100644
--- a/README.md
+++ b/README.md
@@ -179,43 +179,6 @@ ___
-
-
-[//]: # (
diff --git a/docs/docs/tools/review.md b/docs/docs/tools/review.md
index d92f98586..1552bc9bf 100644
--- a/docs/docs/tools/review.md
+++ b/docs/docs/tools/review.md
@@ -46,61 +46,12 @@ extra_instructions = "..."
- The `pr_commands` lists commands that will be executed automatically when a PR is opened.
- The `[pr_reviewer]` section contains the configurations for the `review` tool you want to edit (if any).
-[//]: # ()
-[//]: # (### Incremental Mode)
-
-[//]: # (Incremental review only considers changes since the last Qodo Merge review. This can be useful when working on the PR in an iterative manner, and you want to focus on the changes since the last review instead of reviewing the entire PR again.)
-
-[//]: # (For invoking the incremental mode, the following command can be used:)
-
-[//]: # (```)
-
-[//]: # (/review -i)
-
-[//]: # (```)
-
-[//]: # (Note that the incremental mode is only available for GitHub.)
-
-[//]: # ()
-[//]: # (![incremental review](https://codium.ai/images/pr_agent/incremental_review_2.png){width=512})
-
-[//]: # (### PR Reflection)
-
-[//]: # ()
-[//]: # (By invoking:)
-
-[//]: # (```)
-
-[//]: # (/reflect_and_review)
-
-[//]: # (```)
-
-[//]: # (The tool will first ask the author questions about the PR, and will guide the review based on their answers.)
-
-[//]: # ()
-[//]: # (![reflection questions](https://codium.ai/images/pr_agent/reflection_questions.png){width=512})
-
-[//]: # ()
-[//]: # (![reflection answers](https://codium.ai/images/pr_agent/reflection_answers.png){width=512})
-
-[//]: # ()
-[//]: # (![reflection insights](https://codium.ai/images/pr_agent/reflection_insights.png){width=512})
-
-
## Configuration options
!!! example "General options"
-
- num_code_suggestions |
- Number of code suggestions provided by the 'review' tool. Default is 0, meaning no code suggestions will be provided by the `review` tool. Note that this is a legacy feature, that will be removed in future releases. Use the `improve` tool instead for code suggestions |
-
-
- inline_code_comments |
- If set to true, the tool will publish the code suggestions as comments on the code diff. Default is false. Note that you need to set `num_code_suggestions`>0 to get code suggestions |
-
persistent_comment |
If set to true, the review comment will be persistent, meaning that every new review request will edit the previous one. Default is true. |
@@ -189,9 +140,9 @@ If enabled, the `review` tool can approve a PR when a specific comment, `/review
!!! tip "Automation"
When you first install Qodo Merge app, the [default mode](../usage-guide/automations_and_usage.md#github-app-automatic-tools-when-a-new-pr-is-opened) for the `review` tool is:
```
- pr_commands = ["/review --pr_reviewer.num_code_suggestions=0", ...]
+ pr_commands = ["/review", ...]
```
- Meaning the `review` tool will run automatically on every PR, without providing code suggestions.
+ Meaning the `review` tool will run automatically on every PR, without any additional configurations.
Edit this field to enable/disable the tool, or to change the configurations used.
!!! tip "Possible labels from the review tool"
@@ -249,12 +200,8 @@ If enabled, the `review` tool can approve a PR when a specific comment, `/review
maximal_review_effort = 5
```
-[//]: # (!!! tip "Code suggestions")
-
-[//]: # ()
-[//]: # ( If you set `num_code_suggestions`>0 , the `review` tool will also provide code suggestions.)
+!!! tip "Code suggestions"
-[//]: # ( )
-[//]: # ( Notice If you are interested **only** in the code suggestions, it is recommended to use the [`improve`](./improve.md) feature instead, since it is a dedicated only to code suggestions, and usually gives better results.)
+ The `review` tool previously included a legacy feature for providing code suggestions (controlled by `--pr_reviewer.num_code_suggestion`). This functionality has been deprecated and replaced by the [`improve`](./improve.md) tool, which offers higher quality and more actionable code suggestions.
-[//]: # ( Use the `review` tool if you want to get more comprehensive feedback, which includes code suggestions as well.)
+
diff --git a/docs/docs/usage-guide/automations_and_usage.md b/docs/docs/usage-guide/automations_and_usage.md
index aab7bd87f..947e056b3 100644
--- a/docs/docs/usage-guide/automations_and_usage.md
+++ b/docs/docs/usage-guide/automations_and_usage.md
@@ -285,7 +285,7 @@ To control which commands will run automatically when a new PR is opened, you ca
[azure_devops_server]
pr_commands = [
"/describe",
- "/review --pr_reviewer.num_code_suggestions=0",
+ "/review",
"/improve",
]
```
diff --git a/pr_agent/agent/pr_agent.py b/pr_agent/agent/pr_agent.py
index d16e7a5ca..2ea720775 100644
--- a/pr_agent/agent/pr_agent.py
+++ b/pr_agent/agent/pr_agent.py
@@ -13,7 +13,6 @@
from pr_agent.tools.pr_description import PRDescription
from pr_agent.tools.pr_generate_labels import PRGenerateLabels
from pr_agent.tools.pr_help_message import PRHelpMessage
-from pr_agent.tools.pr_information_from_user import PRInformationFromUser
from pr_agent.tools.pr_line_questions import PR_LineQuestions
from pr_agent.tools.pr_questions import PRQuestions
from pr_agent.tools.pr_reviewer import PRReviewer
@@ -25,8 +24,6 @@
"answer": PRReviewer,
"review": PRReviewer,
"review_pr": PRReviewer,
- "reflect": PRInformationFromUser,
- "reflect_and_review": PRInformationFromUser,
"describe": PRDescription,
"describe_pr": PRDescription,
"improve": PRCodeSuggestions,
@@ -76,12 +73,10 @@ async def handle_request(self, pr_url, request, notify=None) -> bool:
action = action.lstrip("/").lower()
if action not in command2class:
- get_logger().debug(f"Unknown command: {action}")
+ get_logger().error(f"Unknown command: {action}")
return False
with get_logger().contextualize(command=action, pr_url=pr_url):
get_logger().info("PR-Agent request handler started", analytics=True)
- if action == "reflect_and_review":
- get_settings().pr_reviewer.ask_and_reflect = True
if action == "answer":
if notify:
notify()
diff --git a/pr_agent/algo/utils.py b/pr_agent/algo/utils.py
index e94a84299..af829e14d 100644
--- a/pr_agent/algo/utils.py
+++ b/pr_agent/algo/utils.py
@@ -270,22 +270,6 @@ def convert_to_markdown_v2(output_data: dict,
if gfm_supported:
markdown_text += "
\n"
- if 'code_feedback' in output_data:
- if gfm_supported:
- markdown_text += f"\n\n"
- markdown_text += f"
Code feedback:
\n\n"
- markdown_text += "
"
- else:
- markdown_text += f"\n\n### Code feedback:\n\n"
- for i, value in enumerate(output_data['code_feedback']):
- if value is None or value == '' or value == {} or value == []:
- continue
- markdown_text += parse_code_suggestion(value, i, gfm_supported)+"\n\n"
- if markdown_text.endswith('
'):
- markdown_text= markdown_text[:-4]
- if gfm_supported:
- markdown_text += f""
-
return markdown_text
def extract_relevant_lines_str(end_line, files, relevant_file, start_line, dedent=False):
diff --git a/pr_agent/settings/configuration.toml b/pr_agent/settings/configuration.toml
index 16461b7ef..ec9027999 100644
--- a/pr_agent/settings/configuration.toml
+++ b/pr_agent/settings/configuration.toml
@@ -55,9 +55,6 @@ require_can_be_split_review=false
require_security_review=true
require_ticket_analysis_review=true
# general options
-num_code_suggestions=0 # legacy mode. use the `improve` command instead
-inline_code_comments = false
-ask_and_reflect=false
persistent_comment=true
extra_instructions = ""
final_update_message = true
diff --git a/pr_agent/settings/pr_reviewer_prompts.toml b/pr_agent/settings/pr_reviewer_prompts.toml
index 6477ecf6e..9401a0d35 100644
--- a/pr_agent/settings/pr_reviewer_prompts.toml
+++ b/pr_agent/settings/pr_reviewer_prompts.toml
@@ -1,10 +1,6 @@
[pr_review_prompt]
system="""You are PR-Reviewer, a language model designed to review a Git Pull Request (PR).
-{%- if num_code_suggestions > 0 %}
-Your task is to provide constructive and concise feedback for the PR, and also provide meaningful code suggestions.
-{%- else %}
Your task is to provide constructive and concise feedback for the PR.
-{%- endif %}
The review should focus on new code added in the PR code diff (lines starting with '+')
@@ -49,16 +45,6 @@ __new hunk__
{%- endif %}
- When quoting variables or names from the code, use backticks (`) instead of single quote (').
-{%- if num_code_suggestions > 0 %}
-
-
-Code suggestions guidelines:
-- Provide up to {{ num_code_suggestions }} code suggestions. Try to provide diverse and insightful suggestions.
-- Focus on important suggestions like fixing code problems, issues and bugs. As a second priority, provide suggestions for meaningful code improvements, like performance, vulnerability, modularity, and best practices.
-- Avoid making suggestions that have already been implemented in the PR code. For example, if you want to add logs, or change a variable to const, or anything else, make sure it isn't already in the PR code.
-- Don't suggest to add docstring, type hints, or comments.
-- Suggestions should address the new code added in the PR diff (lines starting with '+')
-{%- endif %}
{%- if extra_instructions %}
@@ -118,25 +104,9 @@ class Review(BaseModel):
{%- if require_can_be_split_review %}
can_be_split: List[SubPR] = Field(min_items=0, max_items=3, description="Can this PR, which contains {{ num_pr_files }} changed files in total, be divided into smaller sub-PRs with distinct tasks that can be reviewed and merged independently, regardless of the order ? Make sure that the sub-PRs are indeed independent, with no code dependencies between them, and that each sub-PR represent a meaningful independent task. Output an empty list if the PR code does not need to be split.")
{%- endif %}
-{%- if num_code_suggestions > 0 %}
-
-class CodeSuggestion(BaseModel):
- relevant_file: str = Field(description="The full file path of the relevant file")
- language: str = Field(description="The programming language of the relevant file")
- suggestion: str = Field(description="a concrete suggestion for meaningfully improving the new PR code. Also describe how, specifically, the suggestion can be applied to new PR code. Add tags with importance measure that matches each suggestion ('important' or 'medium'). Do not make suggestions for updating or adding docstrings, renaming PR title and description, or linter like.")
- relevant_line: str = Field(description="a single code line taken from the relevant file, to which the suggestion applies. The code line should start with a '+'. Make sure to output the line exactly as it appears in the relevant file")
-{%- endif %}
-{%- if num_code_suggestions > 0 %}
class PRReview(BaseModel):
review: Review
- code_feedback: List[CodeSuggestion]
-{%- else %}
-
-
-class PRReview(BaseModel):
- review: Review
-{%- endif %}
=====
@@ -185,18 +155,6 @@ review:
title: ...
- ...
{%- endif %}
-
-{%- if num_code_suggestions > 0 %}
-code_feedback:
-- relevant_file: |
- directory/xxx.py
- language: |
- python
- suggestion: |
- xxx [important]
- relevant_line: |
- xxx
-{%- endif %}
```
Answer should be a valid YAML, and nothing else. Each YAML output MUST be after a newline, with proper indent, and block scalar indicator ('|')
diff --git a/pr_agent/tools/pr_information_from_user.py b/pr_agent/tools/pr_information_from_user.py
deleted file mode 100644
index e5bd2f727..000000000
--- a/pr_agent/tools/pr_information_from_user.py
+++ /dev/null
@@ -1,79 +0,0 @@
-import copy
-from functools import partial
-
-from jinja2 import Environment, StrictUndefined
-
-from pr_agent.algo.ai_handlers.base_ai_handler import BaseAiHandler
-from pr_agent.algo.ai_handlers.litellm_ai_handler import LiteLLMAIHandler
-from pr_agent.algo.pr_processing import get_pr_diff, retry_with_fallback_models
-from pr_agent.algo.token_handler import TokenHandler
-from pr_agent.config_loader import get_settings
-from pr_agent.git_providers import get_git_provider
-from pr_agent.git_providers.git_provider import get_main_pr_language
-from pr_agent.log import get_logger
-
-
-class PRInformationFromUser:
- def __init__(self, pr_url: str, args: list = None,
- ai_handler: partial[BaseAiHandler,] = LiteLLMAIHandler):
- self.git_provider = get_git_provider()(pr_url)
- self.main_pr_language = get_main_pr_language(
- self.git_provider.get_languages(), self.git_provider.get_files()
- )
- self.ai_handler = ai_handler()
- self.ai_handler.main_pr_language = self.main_pr_language
-
- self.vars = {
- "title": self.git_provider.pr.title,
- "branch": self.git_provider.get_pr_branch(),
- "description": self.git_provider.get_pr_description(),
- "language": self.main_pr_language,
- "diff": "", # empty diff for initial calculation
- "commit_messages_str": self.git_provider.get_commit_messages(),
- }
- self.token_handler = TokenHandler(self.git_provider.pr,
- self.vars,
- get_settings().pr_information_from_user_prompt.system,
- get_settings().pr_information_from_user_prompt.user)
- self.patches_diff = None
- self.prediction = None
-
- async def run(self):
- get_logger().info('Generating question to the user...')
- if get_settings().config.publish_output:
- self.git_provider.publish_comment("Preparing questions...", is_temporary=True)
- await retry_with_fallback_models(self._prepare_prediction)
- get_logger().info('Preparing questions...')
- pr_comment = self._prepare_pr_answer()
- if get_settings().config.publish_output:
- get_logger().info('Pushing questions...')
- self.git_provider.publish_comment(pr_comment)
- self.git_provider.remove_initial_comment()
- return ""
-
- async def _prepare_prediction(self, model):
- get_logger().info('Getting PR diff...')
- self.patches_diff = get_pr_diff(self.git_provider, self.token_handler, model)
- get_logger().info('Getting AI prediction...')
- self.prediction = await self._get_prediction(model)
-
- async def _get_prediction(self, model: str):
- variables = copy.deepcopy(self.vars)
- variables["diff"] = self.patches_diff # update diff
- environment = Environment(undefined=StrictUndefined)
- system_prompt = environment.from_string(get_settings().pr_information_from_user_prompt.system).render(variables)
- user_prompt = environment.from_string(get_settings().pr_information_from_user_prompt.user).render(variables)
- if get_settings().config.verbosity_level >= 2:
- get_logger().info(f"\nSystem prompt:\n{system_prompt}")
- get_logger().info(f"\nUser prompt:\n{user_prompt}")
- response, finish_reason = await self.ai_handler.chat_completion(
- model=model, temperature=get_settings().config.temperature, system=system_prompt, user=user_prompt)
- return response
-
- def _prepare_pr_answer(self) -> str:
- model_output = self.prediction.strip()
- if get_settings().config.verbosity_level >= 2:
- get_logger().info(f"answer_str:\n{model_output}")
- answer_str = f"{model_output}\n\n Please respond to the questions above in the following format:\n\n" +\
- "\n>/answer\n>1) ...\n>2) ...\n>...\n"
- return answer_str
diff --git a/pr_agent/tools/pr_reviewer.py b/pr_agent/tools/pr_reviewer.py
index 162c1022e..9905ae3dd 100644
--- a/pr_agent/tools/pr_reviewer.py
+++ b/pr_agent/tools/pr_reviewer.py
@@ -86,7 +86,6 @@ def __init__(self, pr_url: str, is_answer: bool = False, is_auto: bool = False,
"require_estimate_effort_to_review": get_settings().pr_reviewer.require_estimate_effort_to_review,
'require_can_be_split_review': get_settings().pr_reviewer.require_can_be_split_review,
'require_security_review': get_settings().pr_reviewer.require_security_review,
- 'num_code_suggestions': get_settings().pr_reviewer.num_code_suggestions,
'question_str': question_str,
'answer_str': answer_str,
"extra_instructions": get_settings().pr_reviewer.extra_instructions,
@@ -168,8 +167,6 @@ async def run(self) -> None:
self.git_provider.publish_comment(pr_review)
self.git_provider.remove_initial_comment()
- if get_settings().pr_reviewer.inline_code_comments:
- self._publish_inline_code_comments()
else:
get_logger().info("Review output is not published")
get_settings().data = {"artifact": pr_review}
@@ -235,33 +232,6 @@ def _prepare_pr_review(self) -> str:
key_issues_to_review = data['review'].pop('key_issues_to_review')
data['review']['key_issues_to_review'] = key_issues_to_review
- if 'code_feedback' in data:
- code_feedback = data['code_feedback']
-
- # Filter out code suggestions that can be submitted as inline comments
- if get_settings().pr_reviewer.inline_code_comments:
- del data['code_feedback']
- else:
- for suggestion in code_feedback:
- if ('relevant_file' in suggestion) and (not suggestion['relevant_file'].startswith('``')):
- suggestion['relevant_file'] = f"``{suggestion['relevant_file']}``"
-
- if 'relevant_line' not in suggestion:
- suggestion['relevant_line'] = ''
-
- relevant_line_str = suggestion['relevant_line'].split('\n')[0]
-
- # removing '+'
- suggestion['relevant_line'] = relevant_line_str.lstrip('+').strip()
-
- # try to add line numbers link to code suggestions
- if hasattr(self.git_provider, 'generate_link_to_relevant_line_number'):
- link = self.git_provider.generate_link_to_relevant_line_number(suggestion)
- if link:
- suggestion['relevant_line'] = f"[{suggestion['relevant_line']}]({link})"
- else:
- pass
-
incremental_review_markdown_text = None
# Add incremental review section
if self.incremental.is_incremental:
@@ -292,38 +262,6 @@ def _prepare_pr_review(self) -> str:
return markdown_text
- def _publish_inline_code_comments(self) -> None:
- """
- Publishes inline comments on a pull request with code suggestions generated by the AI model.
- """
- if get_settings().pr_reviewer.num_code_suggestions == 0:
- return
-
- first_key = 'review'
- last_key = 'security_concerns'
- data = load_yaml(self.prediction.strip(),
- keys_fix_yaml=["ticket_compliance_check", "estimated_effort_to_review_[1-5]:", "security_concerns:", "key_issues_to_review:",
- "relevant_file:", "relevant_line:", "suggestion:"],
- first_key=first_key, last_key=last_key)
- comments: List[str] = []
- for suggestion in data.get('code_feedback', []):
- relevant_file = suggestion.get('relevant_file', '').strip()
- relevant_line_in_file = suggestion.get('relevant_line', '').strip()
- content = suggestion.get('suggestion', '')
- if not relevant_file or not relevant_line_in_file or not content:
- get_logger().info("Skipping inline comment with missing file/line/content")
- continue
-
- if self.git_provider.is_supported("create_inline_comment"):
- comment = self.git_provider.create_inline_comment(content, relevant_file, relevant_line_in_file)
- if comment:
- comments.append(comment)
- else:
- self.git_provider.publish_inline_comment(content, relevant_file, relevant_line_in_file, suggestion)
-
- if comments:
- self.git_provider.publish_inline_comments(comments)
-
def _get_user_answers(self) -> Tuple[str, str]:
"""
Retrieves the question and answer strings from the discussion messages related to a pull request.
diff --git a/tests/unittest/test_convert_to_markdown.py b/tests/unittest/test_convert_to_markdown.py
index 4d1d1aa40..483787aa8 100644
--- a/tests/unittest/test_convert_to_markdown.py
+++ b/tests/unittest/test_convert_to_markdown.py
@@ -47,13 +47,10 @@ class TestConvertToMarkdown:
def test_simple_dictionary_input(self):
input_data = {'review': {
'estimated_effort_to_review_[1-5]': '1, because the changes are minimal and straightforward, focusing on a single functionality addition.\n',
- 'relevant_tests': 'No\n', 'possible_issues': 'No\n', 'security_concerns': 'No\n'}, 'code_feedback': [
- {'relevant_file': '``pr_agent/git_providers/git_provider.py\n``', 'language': 'python\n',
- 'suggestion': "Consider raising an exception or logging a warning when 'pr_url' attribute is not found. This can help in debugging issues related to the absence of 'pr_url' in instances where it's expected. [important]\n",
- 'relevant_line': '[return ""](https://github.com/Codium-ai/pr-agent-pro/pull/102/files#diff-52d45f12b836f77ed1aef86e972e65404634ea4e2a6083fb71a9b0f9bb9e062fR199)'}]}
+ 'relevant_tests': 'No\n', 'possible_issues': 'No\n', 'security_concerns': 'No\n'}}
- expected_output = f'{PRReviewHeader.REGULAR.value} 🔍\n\nHere are some key observations to aid the review process:\n\n
\n⏱️ Estimated effort to review: 1 🔵⚪⚪⚪⚪ |
\n🧪 No relevant tests |
\n Possible issues: No\n |
\n🔒 No security concerns identified |
\n
\n\n\n
Code feedback:
\n\n
relevant file | pr_agent/git_providers/git_provider.py\n |
suggestion | \n\n\n\nConsider raising an exception or logging a warning when \'pr_url\' attribute is not found. This can help in debugging issues related to the absence of \'pr_url\' in instances where it\'s expected. [important]\n\n\n |
relevant line | return "" |
\n\n'
+ expected_output = f'{PRReviewHeader.REGULAR.value} 🔍\n\nHere are some key observations to aid the review process:\n\n
\n⏱️ Estimated effort to review: 1 🔵⚪⚪⚪⚪ |
\n🧪 No relevant tests |
\n Possible issues: No\n |
\n🔒 No security concerns identified |
\n
'
assert convert_to_markdown_v2(input_data).strip() == expected_output.strip()
@@ -67,7 +64,7 @@ def test_empty_dictionary_input(self):
assert convert_to_markdown_v2(input_data).strip() == expected_output.strip()
def test_dictionary_with_empty_dictionaries(self):
- input_data = {'review': {}, 'code_feedback': [{}]}
+ input_data = {'review': {}}
expected_output = ''