diff --git a/pr_agent/algo/utils.py b/pr_agent/algo/utils.py
index 87411430..9a150864 100644
--- a/pr_agent/algo/utils.py
+++ b/pr_agent/algo/utils.py
@@ -474,4 +474,13 @@ def clip_tokens(text: str, max_tokens: int, add_three_dots=True) -> str:
return clipped_text
except Exception as e:
get_logger().warning(f"Failed to clip tokens: {e}")
- return text
\ No newline at end of file
+ return text
+
+def replace_code_tags(text):
+ """
+ Replace odd instances of ` with and even instances of ` with
+ """
+ parts = text.split('`')
+ for i in range(1, len(parts), 2):
+ parts[i] = '' + parts[i] + '
'
+ return ''.join(parts)
\ No newline at end of file
diff --git a/pr_agent/settings/pr_code_suggestions_prompts.toml b/pr_agent/settings/pr_code_suggestions_prompts.toml
index 5aa3cce2..2fb224c7 100644
--- a/pr_agent/settings/pr_code_suggestions_prompts.toml
+++ b/pr_agent/settings/pr_code_suggestions_prompts.toml
@@ -47,14 +47,15 @@ Extra instructions from the user:
======
{%- endif %}
-The output must be a YAML object equivalent to type PRCodeSuggestions, according to the following Pydantic definitions:
+The output must be a YAML object equivalent to type $PRCodeSuggestions, according to the following Pydantic definitions:
=====
class CodeSuggestion(BaseModel):
relevant_file: str = Field(description="the relevant file full path")
suggestion_content: str = Field(description="an actionable suggestion for meaningfully improving the new code introduced in the PR")
{%- if summarize_mode %}
- existing_code: str = Field(description="a short code snippet from a '__new hunk__' section to illustrate the relevant existing code. Don't show the line numbers. Shorten parts of the code ('...') if needed")
- improved_code: str = Field(description="a short code snippet to illustrate the improved code, after applying the suggestion. Shorten parts of the code ('...') if needed")
+ existing_code: str = Field(description="a short code snippet from a '__new hunk__' section to illustrate the relevant existing code. Don't show the line numbers.")
+ improved_code: str = Field(description="a short code snippet to illustrate the improved code, after applying the suggestion.")
+ one_sentence_summary:str = Field(description="a short summary of the suggestion action, in a single sentence. Focus on the 'what'. Be general, and avoid method or variable names.")
{%- else %}
existing_code: str = Field(description="a code snippet, demonstrating the relevant code lines from a '__new hunk__' section. It must be contiguous, correctly formatted and indented, and without line numbers")
improved_code: str = Field(description="a new code snippet, that can be used to replace the relevant lines in '__new hunk__' code. Replacement suggestions should be complete, correctly formatted and indented, and without line numbers")
@@ -75,12 +76,23 @@ code_suggestions:
src/file1.py
suggestion_content: |-
Add a docstring to func1()
+{%- if summarize_mode %}
+ existing_code: |-
+ def func1():
+ improved_code: |-
+ ...
+ one_sentence_summary: |-
+ ...
+ relevant_lines_start: 12
+ relevant_lines_end: 12
+{%- else %}
existing_code: |-
def func1():
relevant_lines_start: 12
relevant_lines_end: 12
improved_code: |-
...
+{%- endif %}
label: |-
...
```
diff --git a/pr_agent/tools/pr_code_suggestions.py b/pr_agent/tools/pr_code_suggestions.py
index b4f7a973..ddc7913e 100644
--- a/pr_agent/tools/pr_code_suggestions.py
+++ b/pr_agent/tools/pr_code_suggestions.py
@@ -8,12 +8,13 @@ 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, get_pr_multi_diffs, retry_with_fallback_models
from pr_agent.algo.token_handler import TokenHandler
-from pr_agent.algo.utils import load_yaml
+from pr_agent.algo.utils import load_yaml, replace_code_tags
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
-
+from pr_agent.tools.pr_description import insert_br_after_x_chars
+import difflib
class PRCodeSuggestions:
def __init__(self, pr_url: str, cli_mode=False, args: list = None,
@@ -299,7 +300,7 @@ class PRCodeSuggestions:
def publish_summarizes_suggestions(self, data: Dict):
try:
- data_markdown = "## PR Code Suggestions\n\n"
+ pr_body = "## PR Code Suggestions\n\n"
language_extension_map_org = get_settings().language_extension_map_org
extension_to_language = {}
@@ -307,30 +308,77 @@ class PRCodeSuggestions:
for ext in extensions:
extension_to_language[ext] = language
- for s in data['code_suggestions']:
- try:
- extension_s = s['relevant_file'].rsplit('.')[-1]
- code_snippet_link = self.git_provider.get_line_link(s['relevant_file'], s['relevant_lines_start'],
- s['relevant_lines_end'])
- label = s['label'].strip()
- data_markdown += f"\n💡 [{label}]\n\n**{s['suggestion_content'].rstrip().rstrip()}**\n\n"
- if code_snippet_link:
- data_markdown += f" File: [{s['relevant_file']} ({s['relevant_lines_start']}-{s['relevant_lines_end']})]({code_snippet_link})\n\n"
+ pr_body += "
"
+ header = f"Suggestions"
+ delta = 77
+ header += " " * delta
+ pr_body += f""" | {header} |
"""
+ pr_body += """"""
+ suggestions_labels = dict()
+ # add all suggestions related to to each label
+ for suggestion in data['code_suggestions']:
+ label = suggestion['label'].strip().strip("'").strip('"')
+ if label not in suggestions_labels:
+ suggestions_labels[label] = []
+ suggestions_labels[label].append(suggestion)
+
+ for label, suggestions in suggestions_labels.items():
+ pr_body += f"""{label} | """
+ pr_body += f""""""
+ # pr_body += f"""{len(suggestions)} suggestions"""
+ pr_body += f""""""
+ for suggestion in suggestions:
+
+ relevant_file = suggestion['relevant_file'].strip()
+ relevant_lines_start = int(suggestion['relevant_lines_start'])
+ relevant_lines_end = int(suggestion['relevant_lines_end'])
+ range_str = ""
+ if relevant_lines_start == relevant_lines_end:
+ range_str = f"[{relevant_lines_start}]"
else:
- data_markdown += f"File: {s['relevant_file']} ({s['relevant_lines_start']}-{s['relevant_lines_end']})\n\n"
- if self.git_provider.is_supported("gfm_markdown"):
- data_markdown += " Example code:\n\n"
- data_markdown += f"___\n\n"
- language_name = "python"
- if extension_s and (extension_s in extension_to_language):
- language_name = extension_to_language[extension_s]
- data_markdown += f"Existing code:\n```{language_name}\n{s['existing_code'].rstrip()}\n```\n"
- data_markdown += f"Improved code:\n```{language_name}\n{s['improved_code'].rstrip()}\n```\n"
- if self.git_provider.is_supported("gfm_markdown"):
- data_markdown += " \n"
- data_markdown += "\n___\n\n"
- except Exception as e:
- get_logger().error(f"Could not parse suggestion: {s}, error: {e}")
- self.git_provider.publish_comment(data_markdown)
+ range_str = f"[{relevant_lines_start}-{relevant_lines_end}]"
+ code_snippet_link = self.git_provider.get_line_link(relevant_file, relevant_lines_start,
+ relevant_lines_end)
+ # add html table for each suggestion
+
+ suggestion_content = suggestion['suggestion_content'].rstrip().rstrip()
+
+ suggestion_content = insert_br_after_x_chars(suggestion_content, 90)
+ # pr_body += f"{suggestion_content}"
+ existing_code = suggestion['existing_code'].rstrip()+"\n"
+ improved_code = suggestion['improved_code'].rstrip()+"\n"
+
+ diff = difflib.unified_diff(existing_code.split('\n'),
+ improved_code.split('\n'), n=999)
+ patch_orig = "\n".join(diff)
+ patch = "\n".join(patch_orig.splitlines()[5:]).strip('\n')
+
+ example_code = ""
+ example_code += f"```diff\n{patch}\n```\n"
+
+ pr_body += f""""""
+ suggestion_summary = suggestion['one_sentence_summary'].strip()
+ if '`' in suggestion_summary:
+ suggestion_summary = replace_code_tags(suggestion_summary)
+ suggestion_summary = suggestion_summary + max((77-len(suggestion_summary)), 0)*" "
+ pr_body += f"""\n\n{suggestion_summary}\n\n___\n\n"""
+
+ pr_body += f"""
+
+
+**{suggestion_content}**
+
+[{relevant_file} {range_str}]({code_snippet_link})
+
+{example_code}
+"""
+ pr_body += f" "
+ pr_body += f" | "
+
+ pr_body += """ | """
+ # pr_body += " "
+ pr_body += """ |
"""
+ pr_body += """
"""
+ self.git_provider.publish_comment(pr_body)
except Exception as e:
get_logger().info(f"Failed to publish summarized code suggestions, error: {e}")
diff --git a/pr_agent/tools/pr_description.py b/pr_agent/tools/pr_description.py
index 71906f0e..51df9ee4 100644
--- a/pr_agent/tools/pr_description.py
+++ b/pr_agent/tools/pr_description.py
@@ -399,7 +399,7 @@ class PRDescription:
filename = filename.strip()
link = self.git_provider.get_line_link(filename, relevant_line_start=-1)
- file_change_description = self._insert_br_after_x_chars(file_change_description, x=(delta - 5))
+ file_change_description = insert_br_after_x_chars(file_change_description, x=(delta - 5))
pr_body += f"""
@@ -427,25 +427,25 @@ class PRDescription:
pass
return pr_body
- def _insert_br_after_x_chars(self, text, x=70):
- """
- Insert into a string after a word that increases its length above x characters.
- """
- if len(text) < x:
- return text
+def insert_br_after_x_chars(text, x=70):
+ """
+ Insert into a string after a word that increases its length above x characters.
+ """
+ if len(text) < x:
+ return text
- words = text.split(' ')
- new_text = ""
- current_length = 0
+ words = text.split(' ')
+ new_text = ""
+ current_length = 0
- for word in words:
- # Check if adding this word exceeds x characters
- if current_length + len(word) > x:
- new_text += " " # Insert line break
- current_length = 0 # Reset counter
+ for word in words:
+ # Check if adding this word exceeds x characters
+ if current_length + len(word) > x:
+ new_text += " " # Insert line break
+ current_length = 0 # Reset counter
- # Add the word to the new text
- new_text += word + " "
- current_length += len(word) + 1 # Add 1 for the space
+ # Add the word to the new text
+ new_text += word + " "
+ current_length += len(word) + 1 # Add 1 for the space
- return new_text.strip() # Remove trailing space
+ return new_text.strip() # Remove trailing space
|