diff --git a/.dockerignore b/.dockerignore
index 9c8ebe57..fb39a7e5 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,2 +1,3 @@
venv/
-pr_agent/settings/.secrets.toml
\ No newline at end of file
+pr_agent/settings/.secrets.toml
+pics/
\ No newline at end of file
diff --git a/PR_COMPRESSION.md b/PR_COMPRESSION.md
index 82fde0c4..4783b43b 100644
--- a/PR_COMPRESSION.md
+++ b/PR_COMPRESSION.md
@@ -39,4 +39,4 @@ We use [tiktoken](https://github.com/openai/tiktoken) to tokenize the patches af
4. If we haven't reached the max token length, add the `deleted files` to the prompt until the prompt reaches the max token length (hard stop), skip the rest of the patches.
### Example
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 7db322bd..25ddc715 100644
--- a/README.md
+++ b/README.md
@@ -27,25 +27,25 @@ CodiumAI `PR-Agent` is an open-source tool aiming to help developers review PRs
Describe:
-
+
Review:
-
+
Ask:
-
+
Improve:
-
+
@@ -64,7 +64,7 @@ CodiumAI `PR-Agent` is an open-source tool aiming to help developers review PRs
Experience GPT-4 powered PR review on your public GitHub repository with our hosted PR-Agent. To try it, just mention `@CodiumAI-Agent` and add the desired command in any PR comment! The agent will generate a response based on your command.
-
+
To set up your own PR-Agent, see the [Quickstart](#Quickstart) section
@@ -72,20 +72,20 @@ To set up your own PR-Agent, see the [Quickstart](#Quickstart) section
## Overview
`PR-Agent` offers extensive pull request functionalities across various git providers:
| | | GitHub | Gitlab | Bitbucket |
-|-------|---------------------------------------------|--------|--------|-----------|
-| TOOLS | Review | ✓ | ✓ | ✓ |
-| | ⮑ Inline review | ✓ | ✓ | |
-| | Ask | ✓ | ✓ | |
-| | Auto-Description | ✓ | | |
-| | Improve Code | ✓ | ✓ | |
+|-------|---------------------------------------------|:------:|:------:|:---------:|
+| TOOLS | Review | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| | ⮑ Inline review | :white_check_mark: | :white_check_mark: | |
+| | Ask | :white_check_mark: | :white_check_mark: | |
+| | Auto-Description | :white_check_mark: | | |
+| | Improve Code | :white_check_mark: | :white_check_mark: | |
| | | | | |
-| USAGE | CLI | ✓ | ✓ | ✓ |
-| | Tagging bot | ✓ | ✓ | |
-| | Actions | ✓ | | |
+| USAGE | CLI | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| | Tagging bot | :white_check_mark: | :white_check_mark: | |
+| | Actions | :white_check_mark: | | |
| | | | | |
-| CORE | PR compression | ✓ | ✓ | ✓ |
-| | Repo language prioritization | ✓ | ✓ | ✓ |
-| | Adaptive and token-aware
file patch fitting | ✓ | ✓ | ✓ |
+| CORE | PR compression | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| | Repo language prioritization | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| | Adaptive and token-aware
file patch fitting | :white_check_mark: | :white_check_mark: | :white_check_mark: |
Examples for invoking the different tools via the [CLI](#quickstart):
- **Review**: python cli.py --pr-url=
review
@@ -122,14 +122,14 @@ Here are several ways to install and run PR-Agent:
**PR-Agent** provides four types of interactions ("tools"): `"PR Reviewer"`, `"PR Q&A"`, `"PR Description"` and `"PR Code Sueggestions"`.
-- The "PR Reviewer" tool automatically analyzes PRs, and provides different types of feedback.
-- The "PR Ask" tool answers free-text questions about the PR.
+- The "PR Reviewer" tool automatically analyzes PRs, and provides various types of feedback.
+- The "PR Q&A" tool answers free-text questions about the PR.
- The "PR Description" tool automatically sets the PR Title and body.
- The "PR Code Suggestion" tool provide inline code suggestions for the PR that can be applied and committed.
## How it works
-
+
Check out the [PR Compression strategy](./PR_COMPRESSION.md) page for more details on how we convert a code diff to a manageable LLM prompt
diff --git a/pics/ask.gif b/pics/ask.gif
deleted file mode 100644
index b4a3557b..00000000
Binary files a/pics/ask.gif and /dev/null differ
diff --git a/pics/demo.gif b/pics/demo.gif
deleted file mode 100644
index 16948151..00000000
Binary files a/pics/demo.gif and /dev/null differ
diff --git a/pics/describe.gif b/pics/describe.gif
deleted file mode 100644
index 2120b7a7..00000000
Binary files a/pics/describe.gif and /dev/null differ
diff --git a/pics/git_patch_logic.png b/pics/git_patch_logic.png
deleted file mode 100644
index bc378db1..00000000
Binary files a/pics/git_patch_logic.png and /dev/null differ
diff --git a/pics/improve.gif b/pics/improve.gif
deleted file mode 100644
index 97c94f67..00000000
Binary files a/pics/improve.gif and /dev/null differ
diff --git a/pics/main_pic_4_tools.gif b/pics/main_pic_4_tools.gif
deleted file mode 100644
index 8cdbef05..00000000
Binary files a/pics/main_pic_4_tools.gif and /dev/null differ
diff --git a/pics/pr-agent-review-process1.gif b/pics/pr-agent-review-process1.gif
deleted file mode 100644
index dca5e631..00000000
Binary files a/pics/pr-agent-review-process1.gif and /dev/null differ
diff --git a/pics/pr_agent_overview.png b/pics/pr_agent_overview.png
deleted file mode 100644
index 2ee523bd..00000000
Binary files a/pics/pr_agent_overview.png and /dev/null differ
diff --git a/pics/pr_auto_description.png b/pics/pr_auto_description.png
deleted file mode 100644
index 1f3d1859..00000000
Binary files a/pics/pr_auto_description.png and /dev/null differ
diff --git a/pics/pr_code_suggestions.png b/pics/pr_code_suggestions.png
deleted file mode 100644
index b7c86e2e..00000000
Binary files a/pics/pr_code_suggestions.png and /dev/null differ
diff --git a/pics/pr_questions.png b/pics/pr_questions.png
deleted file mode 100644
index 7ba11491..00000000
Binary files a/pics/pr_questions.png and /dev/null differ
diff --git a/pics/pr_reviewer_1.png b/pics/pr_reviewer_1.png
deleted file mode 100644
index 1ae2bad6..00000000
Binary files a/pics/pr_reviewer_1.png and /dev/null differ
diff --git a/pics/pr_reviewer_2.png b/pics/pr_reviewer_2.png
deleted file mode 100644
index 6e2fe1c3..00000000
Binary files a/pics/pr_reviewer_2.png and /dev/null differ
diff --git a/pics/review.gif b/pics/review.gif
deleted file mode 100644
index 2f9e7457..00000000
Binary files a/pics/review.gif and /dev/null differ
diff --git a/pr_agent/cli.py b/pr_agent/cli.py
index daf60d56..d681776a 100644
--- a/pr_agent/cli.py
+++ b/pr_agent/cli.py
@@ -14,10 +14,10 @@ def run():
parser = argparse.ArgumentParser(description='AI based pull request analyzer', usage="""\
Usage: cli.py --pr-url [].
For example:
-- cli.py --pr-url xxx review
-- cli.py --pr-url xxx describe
-- cli.py --pr-url xxx improve
-- cli.py --pr-url xxx ask "write me a poem about this PR"
+- cli.py --pr-url=... review
+- cli.py --pr-url=... describe
+- cli.py --pr-url=... improve
+- cli.py --pr-url=... ask "write me a poem about this PR"
Supported commands:
review / review_pr - Add a review that includes a summary of the PR and specific suggestions for improvement.
diff --git a/pr_agent/git_providers/gitlab_provider.py b/pr_agent/git_providers/gitlab_provider.py
index d6bc3ee4..07a25e2f 100644
--- a/pr_agent/git_providers/gitlab_provider.py
+++ b/pr_agent/git_providers/gitlab_provider.py
@@ -123,26 +123,11 @@ class GitLabProvider(GitProvider):
range = relevant_lines_end - relevant_lines_start + 1
body = body.replace('```suggestion', f'```suggestion:-0+{range}')
- d = self.last_diff
- #
- # pos_obj = {'position_type': 'text',
- # 'new_path': target_file.filename,
- # 'old_path': target_file.old_filename if target_file.old_filename else target_file.filename,
- # 'base_sha': d.base_commit_sha, 'start_sha': d.start_commit_sha, 'head_sha': d.head_commit_sha}
lines = target_file.head_file.splitlines()
relevant_line_in_file = lines[relevant_lines_start - 1]
edit_type, found, source_line_no, target_file, target_line_no = self.find_in_file(target_file, relevant_line_in_file)
self.send_inline_comment(body, edit_type, found, relevant_file, relevant_line_in_file, source_line_no,
target_file, target_line_no)
- # if lines[relevant_lines_start][0] == '-':
- # pos_obj['old_line'] = relevant_lines_start
- # elif lines[relevant_lines_start][0] == '+':
- # pos_obj['new_line'] = relevant_lines_start
- # else:
- # pos_obj['new_line'] = relevant_lines_start
- # pos_obj['old_line'] = relevant_lines_start
- # self.mr.discussions.create({'body': body,
- # 'position': pos_obj})
def search_line(self, relevant_file, relevant_line_in_file):
target_file = None
diff --git a/pr_agent/settings/configuration.toml b/pr_agent/settings/configuration.toml
index 01bf0a86..82e78df5 100644
--- a/pr_agent/settings/configuration.toml
+++ b/pr_agent/settings/configuration.toml
@@ -12,6 +12,9 @@ num_code_suggestions=3
inline_code_comments = true
ask_and_reflect=false
+[pr_description]
+publish_description_as_comment=false
+
[pr_questions]
[pr_code_suggestions]
diff --git a/pr_agent/settings/pr_reviewer_prompts.toml b/pr_agent/settings/pr_reviewer_prompts.toml
index 3a8f0b51..51a873c4 100644
--- a/pr_agent/settings/pr_reviewer_prompts.toml
+++ b/pr_agent/settings/pr_reviewer_prompts.toml
@@ -2,8 +2,11 @@
system="""You are CodiumAI-PR-Reviewer, a language model designed to review git pull requests.
Your task is to provide constructive and concise feedback for the PR, and also provide meaningfull code suggestions to improve the new PR code (the '+' lines).
- Provide up to {{ num_code_suggestions }} code suggestions.
+{%- if num_code_suggestions > 0 %}
- Try to focus on important suggestions like fixing code problems, issues and bugs. As a second priority, provide suggestions for meaningfull code improvements, like performance, vulnerability, modularity, and best practices.
+- Suggestions should focus on improving the new added code lines.
- Make sure not to provide suggestions repeating modifications already implemented in the new PR code (the '+' lines).
+{%- endif %}
You must use the following JSON schema to format your answer:
```json
@@ -41,6 +44,7 @@ You must use the following JSON schema to format your answer:
"type": "string",
"description": "General suggestions and feedback for the contributors and maintainers of this PR. May include important suggestions for the overall structure, primary purpose, best practices, critical bugs, and other aspects of the PR. Explain your suggestions."
},
+{%- if num_code_suggestions > 0 %}
"Code suggestions": {
"type": "array",
"maxItems": {{ num_code_suggestions }},
@@ -60,6 +64,7 @@ You must use the following JSON schema to format your answer:
}
}
},
+{%- endif %}
{%- if require_security %}
"Security concerns": {
"type": "string",
@@ -88,6 +93,7 @@ Example output:
"PR Feedback":
{
"General PR suggestions": "..., `xxx`...",
+{%- if num_code_suggestions > 0 %}
"Code suggestions": [
{
"relevant file": "directory/xxx.py",
@@ -96,6 +102,7 @@ Example output:
},
...
]
+{%- endif %}
{%- if require_security %},
"Security concerns": "No, because ..."
{%- endif %}
diff --git a/pr_agent/tools/pr_code_suggestions.py b/pr_agent/tools/pr_code_suggestions.py
index c008368a..c75b3771 100644
--- a/pr_agent/tools/pr_code_suggestions.py
+++ b/pr_agent/tools/pr_code_suggestions.py
@@ -42,7 +42,7 @@ class PRCodeSuggestions:
assert type(self.git_provider) != BitbucketProvider, "Bitbucket is not supported for now"
logging.info('Generating code suggestions for PR...')
- if settings.config.publish_review:
+ if settings.config.publish_output:
self.git_provider.publish_comment("Preparing review...", is_temporary=True)
logging.info('Getting PR diff...')
@@ -56,7 +56,7 @@ class PRCodeSuggestions:
self.prediction = await self._get_prediction()
logging.info('Preparing PR review...')
data = self._prepare_pr_code_suggestions()
- if settings.config.publish_review:
+ if settings.config.publish_output:
logging.info('Pushing PR review...')
self.git_provider.remove_initial_comment()
logging.info('Pushing inline code comments...')
diff --git a/pr_agent/tools/pr_description.py b/pr_agent/tools/pr_description.py
index fa0423d7..8600b3fa 100644
--- a/pr_agent/tools/pr_description.py
+++ b/pr_agent/tools/pr_description.py
@@ -36,17 +36,20 @@ class PRDescription:
async def describe(self):
logging.info('Generating a PR description...')
- if settings.config.publish_review:
+ if settings.config.publish_output:
self.git_provider.publish_comment("Preparing pr description...", is_temporary=True)
logging.info('Getting PR diff...')
self.patches_diff = get_pr_diff(self.git_provider, self.token_handler)
logging.info('Getting AI prediction...')
self.prediction = await self._get_prediction()
logging.info('Preparing answer...')
- pr_title, pr_body = self._prepare_pr_answer()
- if settings.config.publish_review:
+ pr_title, pr_body, markdown_text = self._prepare_pr_answer()
+ if settings.config.publish_output:
logging.info('Pushing answer...')
- self.git_provider.publish_description(pr_title, pr_body)
+ if settings.pr_description.publish_description_as_comment:
+ self.git_provider.publish_comment(markdown_text)
+ else:
+ self.git_provider.publish_description(pr_title, pr_body)
self.git_provider.remove_initial_comment()
return ""
@@ -66,10 +69,11 @@ class PRDescription:
def _prepare_pr_answer(self):
data = json.loads(self.prediction)
+ markdown_text = ""
+ for key, value in data.items():
+ markdown_text += f"## {key}\n\n"
+ markdown_text += f"{value}\n\n"
pr_body = ""
- # for key, value in data.items():
- # markdown_text += f"## {key}\n\n"
- # markdown_text += f"{value}\n\n"
title = data['PR Title']
del data['PR Title']
for key, value in data.items():
@@ -80,4 +84,4 @@ class PRDescription:
pr_body += f"**{value}**\n\n___\n"
if settings.config.verbosity_level >= 2:
logging.info(f"title:\n{title}\n{pr_body}")
- return title, pr_body
+ return title, pr_body, markdown_text
diff --git a/pr_agent/tools/pr_information_from_user.py b/pr_agent/tools/pr_information_from_user.py
index adfd9733..a4120cd4 100644
--- a/pr_agent/tools/pr_information_from_user.py
+++ b/pr_agent/tools/pr_information_from_user.py
@@ -34,7 +34,7 @@ class PRInformationFromUser:
async def generate_questions(self):
logging.info('Generating question to the user...')
- if settings.config.publish_review:
+ if settings.config.publish_output:
self.git_provider.publish_comment("Preparing answer...", is_temporary=True)
logging.info('Getting PR diff...')
self.patches_diff = get_pr_diff(self.git_provider, self.token_handler)
@@ -42,7 +42,7 @@ class PRInformationFromUser:
self.prediction = await self._get_prediction()
logging.info('Preparing questions...')
pr_comment = self._prepare_pr_answer()
- if settings.config.publish_review:
+ if settings.config.publish_output:
logging.info('Pushing questions...')
self.git_provider.publish_comment(pr_comment)
self.git_provider.remove_initial_comment()
diff --git a/pr_agent/tools/pr_questions.py b/pr_agent/tools/pr_questions.py
index 8941957b..08af3797 100644
--- a/pr_agent/tools/pr_questions.py
+++ b/pr_agent/tools/pr_questions.py
@@ -36,7 +36,7 @@ class PRQuestions:
async def answer(self):
logging.info('Answering a PR question...')
- if settings.config.publish_review:
+ if settings.config.publish_output:
self.git_provider.publish_comment("Preparing answer...", is_temporary=True)
logging.info('Getting PR diff...')
self.patches_diff = get_pr_diff(self.git_provider, self.token_handler)
@@ -44,7 +44,7 @@ class PRQuestions:
self.prediction = await self._get_prediction()
logging.info('Preparing answer...')
pr_comment = self._prepare_pr_answer()
- if settings.config.publish_review:
+ if settings.config.publish_output:
logging.info('Pushing answer...')
self.git_provider.publish_comment(pr_comment)
self.git_provider.remove_initial_comment()
diff --git a/pr_agent/tools/pr_reviewer.py b/pr_agent/tools/pr_reviewer.py
index a05aaac1..12d4df72 100644
--- a/pr_agent/tools/pr_reviewer.py
+++ b/pr_agent/tools/pr_reviewer.py
@@ -48,7 +48,7 @@ class PRReviewer:
async def review(self):
logging.info('Reviewing PR...')
- if settings.config.publish_review:
+ if settings.config.publish_output:
self.git_provider.publish_comment("Preparing review...", is_temporary=True)
logging.info('Getting PR diff...')
self.patches_diff = get_pr_diff(self.git_provider, self.token_handler)
@@ -56,7 +56,7 @@ class PRReviewer:
self.prediction = await self._get_prediction()
logging.info('Preparing PR review...')
pr_comment = self._prepare_pr_review()
- if settings.config.publish_review:
+ if settings.config.publish_output:
logging.info('Pushing PR review...')
self.git_provider.publish_comment(pr_comment)
self.git_provider.remove_initial_comment()
@@ -94,7 +94,9 @@ class PRReviewer:
del data['PR Feedback']['Security concerns']
data['PR Analysis']['Security concerns'] = val
- if settings.config.git_provider == 'github' and settings.pr_reviewer.inline_code_comments:
+ if settings.config.git_provider == 'github' and \
+ settings.pr_reviewer.inline_code_comments and \
+ 'Code suggestions' in data['PR Feedback']:
del data['PR Feedback']['Code suggestions']
markdown_text = convert_to_markdown(data)
@@ -112,6 +114,9 @@ class PRReviewer:
return markdown_text
def _publish_inline_code_comments(self):
+ if settings.pr_reviewer.num_code_suggestions == 0:
+ return
+
review = self.prediction.strip()
try:
data = json.loads(review)