Compare commits

..

78 Commits

Author SHA1 Message Date
685f001298 s 2024-11-06 14:46:57 +02:00
88c2b90860 static analysis 2024-10-02 09:06:30 +03:00
c84d84ace2 static analysis 2024-10-02 08:56:33 +03:00
Tal
af5a50ac6a Merge pull request #1264 from Codium-ai/tr/commitable_alongside_table
dual publishing mode
2024-10-01 08:38:34 +03:00
bccc2844b9 dual publishing mode 2024-10-01 08:32:29 +03:00
Tal
d80103751e Merge pull request #1263 from Codium-ai/tr/commitable_alongside_table
feat: add dual publishing mode for PR code suggestions
2024-10-01 08:25:00 +03:00
8ff8b1d48e default 2024-10-01 08:22:28 +03:00
da0bd84746 dual 2024-10-01 08:20:16 +03:00
b42ded61f8 docs: add guidelines for implementing proposed code suggestions in improve.md 2024-10-01 08:16:51 +03:00
dfa4f22be2 feat: add dual publishing mode for PR code suggestions
- Introduced dual publishing mode to present high-scoring suggestions as both table entries and commitable PR comments.
- Updated documentation to include configuration options for dual publishing mode.
- Enhanced `pr_code_suggestions.py` to handle dual publishing logic and error handling.
- Modified `configuration.toml` to include `duel_publishing_score_threshold` setting.
2024-10-01 08:01:27 +03:00
Tal
7d55fc174b Merge pull request #1262 from Codium-ai/tr/prompt
style: refine field descriptions in KeyIssuesComponentLink model
2024-09-30 13:06:11 +03:00
968fb71577 refactor: update terminology for issue review recommendations in utils.py 2024-09-30 13:03:42 +03:00
454365913f refactor: update terminology for issue review recommendations in utils.py 2024-09-30 13:00:01 +03:00
bbaba2dbda refactor: update terminology for issue review recommendations in utils.py
style: refine field descriptions in KeyIssuesComponentLink model
2024-09-30 08:58:32 +03:00
e4c6792866 Merge remote-tracking branch 'origin/main' 2024-09-30 07:52:54 +03:00
183dd5d2fc diverse 2024-09-30 07:52:43 +03:00
Tal
2e79392a5f Merge pull request #1256 from Codium-ai/mrT23-patch-2
disable chat message for github action
2024-09-30 07:40:04 +03:00
da4148f336 docs: update links and references to Qodo Merge in documentation 2024-09-29 17:38:02 +03:00
070ed21103 update documentation links to qodo-merge-docs.qodo.ai 2024-09-29 17:32:16 +03:00
Tal
640bc1e28a Merge pull request #1261 from Codium-ai/tr/qodo_merge
Qodo Merge rename
2024-09-29 17:26:13 +03:00
6c4aa468a9 formerly 2024-09-29 17:24:37 +03:00
da20efd050 Qodo Merge rename 2024-09-29 17:19:46 +03:00
c25aaad176 Qodo Merge rename 2024-09-29 17:15:49 +03:00
Tal
b4c20d683c Merge pull request #1260 from Codium-ai/mrT23-patch-3
Update CNAME
2024-09-29 12:26:50 +03:00
Tal
7bc20d6f16 Update CNAME 2024-09-29 12:25:48 +03:00
f894e8831b revert unauthorized merge 2024-09-29 08:37:26 +03:00
25b7e1e777 update docs URL 2024-09-29 08:19:26 +03:00
Tal
6ba2fb212d Merge pull request #1259 from Codium-ai/tr/intro_review
Add intro text option for PR reviews in configuration and utils
2024-09-29 07:32:27 +03:00
4a60046f7c update tests 2024-09-29 07:28:02 +03:00
35b1f5e747 key 2024-09-29 07:23:34 +03:00
d77a819d92 Add intro text option for PR reviews in configuration and utils 2024-09-29 07:06:48 +03:00
f3fd439d47 docs 2024-09-27 16:24:07 +03:00
Tal
6188afff48 Merge pull request #1257 from Codium-ai/tr/code_suggestion_message
docs: update PR-Agent documentation with PR Chat search instructions
2024-09-27 16:15:09 +03:00
57cfdcf274 docs: update PR-Agent documentation with PR Chat search instructions 2024-09-27 16:13:54 +03:00
Tal
1333ac47bc Update configuration.toml 2024-09-26 18:24:11 +03:00
Tal
267e01409b Merge pull request #1255 from Codium-ai/tr/code_suggestion_message
Enable intro and chat text for PR code suggestions in configuration
2024-09-26 17:15:10 +03:00
8bdebcb99f Enable intro and chat text for PR code suggestions in configuration 2024-09-26 17:11:00 +03:00
Tal
a13400b9b8 Merge pull request #1254 from Codium-ai/tr/code_suggestion_message
Add intro and chat text options for PR code suggestions in configuration
2024-09-26 16:31:10 +03:00
89f9cf5adc Add intro and chat text options for PR code suggestions in configuration 2024-09-26 09:07:51 +03:00
Tal
6b653dbe48 Merge pull request #1253 from Codium-ai/tr/code_suggestion_message
Add configuration for auto actions in GitHub Action runner
2024-09-26 08:50:56 +03:00
109b965407 Add configuration for auto actions in GitHub Action runner 2024-09-26 08:03:39 +03:00
Tal
511c5a31db Merge pull request #1252 from Codium-ai/tr/prompts_refactor
improve code suggestion prompt
2024-09-25 21:23:00 +03:00
3dd8050004 improve code suggestion prompt 2024-09-25 21:22:41 +03:00
4b7d01972c improve code suggestion prompt 2024-09-25 21:15:14 +03:00
05ec944a8b improve code suggestion prompt 2024-09-25 17:52:54 +03:00
4713ae74b7 improve code suggestion prompt 2024-09-25 17:42:59 +03:00
c828cdde62 improve code suggestion prompt 2024-09-25 17:41:21 +03:00
6f14f9c8e1 improve code suggestion prompt 2024-09-25 16:22:16 +03:00
Tal
9f8cc75bd3 Merge pull request #1250 from chapeupreto/improve-pipeline-gitlab
docs: improve GitLab installation instruction
2024-09-25 07:11:54 +03:00
0668ccbb9e docs: improve GitLab installation instruction
This commit adds a missing `export` instruction that is required mainly
for self-hosted GitLab installations.
2024-09-24 23:34:40 -03:00
Tal
8a287f8ed6 Merge pull request #1248 from Codium-ai/tr/help_fixes
DocHelper
2024-09-22 16:17:30 +03:00
d5625db3c8 DocHelper 2024-09-22 16:16:59 +03:00
d6b779eef8 DocHelper 2024-09-22 16:14:32 +03:00
804cb9ec1d DocHelper 2024-09-22 15:55:18 +03:00
Tal
47d32283ca Merge pull request #1247 from Codium-ai/tr/help_fixes
Tr/help fixes
2024-09-22 10:23:29 +03:00
397963257d DocHelper 2024-09-22 10:21:47 +03:00
a3fd15bb92 Merge remote-tracking branch 'origin/main' into tr/help_fixes 2024-09-22 09:27:10 +03:00
ded7d96649 DocHelper 2024-09-22 09:23:34 +03:00
Tal
bbf06e25ef Merge pull request #1246 from Codium-ai/tr/docs_update
update docs
2024-09-22 09:20:38 +03:00
7e5ddf7e37 Update improve.md with enhanced self-review configuration details 2024-09-22 09:19:39 +03:00
0198c61cf7 update docs 2024-09-22 09:00:56 +03:00
20d8e76a7f logs 2024-09-22 08:31:56 +03:00
be8052251a Update pr_help_prompts.toml and fix snippet indexing in pr_help_message.py 2024-09-22 08:13:23 +03:00
ba08b13446 update PR-Agent usage instructions in pr_description.py 2024-09-21 21:10:51 +03:00
835684b92a Merge remote-tracking branch 'origin/main'
# Conflicts:
#	pr_agent/tools/pr_description.py
2024-09-21 21:10:38 +03:00
90295b6429 update PR-Agent usage instructions in pr_description.py 2024-09-21 21:10:06 +03:00
Tal
08d6bbc94c Merge pull request #1245 from Codium-ai/tr/help_rag
docs pr help
2024-09-21 20:58:06 +03:00
8229d98842 docs pr help 2024-09-21 20:55:05 +03:00
Tal
9e28aca919 Merge pull request #1244 from Codium-ai/tr/help_rag
Refactor S3 file handling and update Dockerfile to include local Chroma DB file
2024-09-21 19:28:04 +03:00
3e780783cc Add docs db 2024-09-21 19:24:23 +03:00
5c7b65810c Refactor S3 file handling and update Dockerfile to include local Chroma DB file 2024-09-21 19:11:46 +03:00
Tal
f2f82e8805 Merge pull request #1243 from Codium-ai/tr/help_rag
get protection
2024-09-21 17:08:23 +03:00
1e51acff22 get protection 2024-09-21 17:07:46 +03:00
Tal
81e847e477 Merge pull request #1242 from Codium-ai/tr/help_rag
prompts
2024-09-21 16:59:23 +03:00
a70fe27d94 prompts 2024-09-21 16:58:37 +03:00
Tal
1a5835a947 Merge pull request #1241 from Codium-ai/tr/help_rag
Add PR help message functionality and update dependencies
2024-09-21 16:28:42 +03:00
4b74506107 Add PR help message functionality and update dependencies
- Implement PRHelpMessage class to provide AI-powered assistance for pull requests.
- Add methods for similarity search using local, S3, and Pinecone databases.
- Update `requirements.txt` to include new dependencies for langchain and chromadb.
- Modify `configuration.toml` to include `force_local_db` setting for PR help.
- Update `aiohttp` and `openai` package versions.
2024-09-21 16:22:51 +03:00
08319f8492 fixed azure remove comment bug 2024-09-19 12:54:26 +03:00
78 changed files with 2910 additions and 596 deletions

View File

@ -25,11 +25,11 @@ CodiumAI PR-Agent aims to help efficiently review and handle pull requests, by p
</div> </div>
### [Documentation](https://pr-agent-docs.codium.ai/) ### [Documentation](https://pr-agent-docs.codium.ai/)
- See the [Installation Guide](https://pr-agent-docs.codium.ai/installation/) for instructions on installing PR-Agent on different platforms. - See the [Installation Guide](https://qodo-merge-docs.qodo.ai/installation/) for instructions on installing PR-Agent on different platforms.
- See the [Usage Guide](https://pr-agent-docs.codium.ai/usage-guide/) for instructions on running PR-Agent tools via different interfaces, such as CLI, PR Comments, or by automatically triggering them when a new PR is opened. - See the [Usage Guide](https://qodo-merge-docs.qodo.ai/usage-guide/) for instructions on running PR-Agent tools via different interfaces, such as CLI, PR Comments, or by automatically triggering them when a new PR is opened.
- See the [Tools Guide](https://pr-agent-docs.codium.ai/tools/) for a detailed description of the different tools, and the available configurations for each tool. - See the [Tools Guide](https://qodo-merge-docs.qodo.ai/tools/) for a detailed description of the different tools, and the available configurations for each tool.
## Table of Contents ## Table of Contents
@ -43,6 +43,12 @@ CodiumAI PR-Agent aims to help efficiently review and handle pull requests, by p
## News and Updates ## News and Updates
### September 21, 2024
Need help with PR-Agent? New feature - simply comment `/help "your question"` in a pull request, and PR-Agent will provide you with the [relevant documentation](https://github.com/Codium-ai/pr-agent/pull/1241#issuecomment-2365259334).
<kbd><img src="https://www.codium.ai/images/pr_agent/pr_help_chat.png" width="768"></kbd>
### September 12, 2024 ### September 12, 2024
[Dynamic context](https://pr-agent-docs.codium.ai/core-abilities/dynamic_context/) is now the default option for context extension. [Dynamic context](https://pr-agent-docs.codium.ai/core-abilities/dynamic_context/) is now the default option for context extension.
This feature enables PR-Agent to dynamically adjusting the relevant context for each code hunk, while avoiding overflowing the model with too much information. This feature enables PR-Agent to dynamically adjusting the relevant context for each code hunk, while avoiding overflowing the model with too much information.
@ -256,7 +262,7 @@ Note that when you set your own PR-Agent or use CodiumAI hosted PR-Agent, there
2. **Improved privacy** - No data will be stored or used to train models. PR-Agent Pro will employ zero data retention, and will use an OpenAI account with zero data retention. 2. **Improved privacy** - No data will be stored or used to train models. PR-Agent Pro will employ zero data retention, and will use an OpenAI account with zero data retention.
3. **Improved support** - PR-Agent Pro users will receive priority support, and will be able to request new features and capabilities. 3. **Improved support** - PR-Agent Pro users will receive priority support, and will be able to request new features and capabilities.
4. **Extra features** -In addition to the benefits listed above, PR-Agent Pro will emphasize more customization, and the usage of static code analysis, in addition to LLM logic, to improve results. 4. **Extra features** -In addition to the benefits listed above, PR-Agent Pro will emphasize more customization, and the usage of static code analysis, in addition to LLM logic, to improve results.
See [here](https://pr-agent-docs.codium.ai/#pr-agent-pro) for a list of features available in PR-Agent Pro. See [here](https://qodo-merge-docs.qodo.ai/overview/pr_agent_pro/) for a list of features available in PR-Agent Pro.

View File

@ -1,6 +1,7 @@
FROM python:3.12.3 AS base FROM python:3.12.3 AS base
WORKDIR /app WORKDIR /app
ADD docs/chroma_db.zip /app/docs/chroma_db.zip
ADD pyproject.toml . ADD pyproject.toml .
ADD requirements.txt . ADD requirements.txt .
RUN pip install . && rm pyproject.toml requirements.txt RUN pip install . && rm pyproject.toml requirements.txt

View File

@ -1 +1 @@
# [Visit Our Docs Portal](https://pr-agent-docs.codium.ai/) # [Visit Our Docs Portal](https://qodo-merge-docs.qodo.ai/)

BIN
docs/chroma_db.zip Normal file

Binary file not shown.

View File

@ -1 +1 @@
pr-agent-docs.codium.ai qodo-merge-docs.qodo.ai

View File

@ -1,5 +1,5 @@
We take your code's security and privacy seriously: We take your code's security and privacy seriously:
- The Chrome extension will not send your code to any external servers. - The Chrome extension will not send your code to any external servers.
- For private repositories, we will first validate the user's identity and permissions. After authentication, we generate responses using the existing PR-Agent Pro integration. - For private repositories, we will first validate the user's identity and permissions. After authentication, we generate responses using the existing Qodo Merge Pro integration.

View File

@ -4,22 +4,22 @@
The PR-Chat feature allows to freely chat with your PR code, within your GitHub environment. The PR-Chat feature allows to freely chat with your PR code, within your GitHub environment.
It will seamlessly use the PR as context to your chat session, and provide AI-powered feedback. It will seamlessly use the PR as context to your chat session, and provide AI-powered feedback.
To enable private chat, simply install the PR-Agent Chrome extension. After installation, each PR's file-changed tab will include a chat box, where you may ask questions about your code. To enable private chat, simply install the Qodo Merge Chrome extension. After installation, each PR's file-changed tab will include a chat box, where you may ask questions about your code.
This chat session is **private**, and won't be visible to other users. This chat session is **private**, and won't be visible to other users.
All open-source repositories are supported. All open-source repositories are supported.
For private repositories, you will also need to install PR-Agent Pro, After installation, make sure to open at least one new PR to fully register your organization. Once done, you can chat with both new and existing PRs across all installed repositories. For private repositories, you will also need to install Qodo Merge Pro, After installation, make sure to open at least one new PR to fully register your organization. Once done, you can chat with both new and existing PRs across all installed repositories.
#### Context-aware PR chat #### Context-aware PR chat
PR-Agent constructs a comprehensive context for each pull request, incorporating the PR description, commit messages, and code changes with extended dynamic context. This contextual information, along with additional PR-related data, forms the foundation for an AI-powered chat session. The agent then leverages this rich context to provide intelligent, tailored responses to user inquiries about the pull request. Qodo Merge constructs a comprehensive context for each pull request, incorporating the PR description, commit messages, and code changes with extended dynamic context. This contextual information, along with additional PR-related data, forms the foundation for an AI-powered chat session. The agent then leverages this rich context to provide intelligent, tailored responses to user inquiries about the pull request.
<img src="https://codium.ai/images/pr_agent/pr_chat_1.png" width="768"> <img src="https://codium.ai/images/pr_agent/pr_chat_1.png" width="768">
<img src="https://codium.ai/images/pr_agent/pr_chat_2.png" width="768"> <img src="https://codium.ai/images/pr_agent/pr_chat_2.png" width="768">
### Toolbar extension ### Toolbar extension
With PR-Agent Chrome extension, it's [easier than ever](https://www.youtube.com/watch?v=gT5tli7X4H4) to interactively configure and experiment with the different tools and configuration options. With Qodo Merge Chrome extension, it's [easier than ever](https://www.youtube.com/watch?v=gT5tli7X4H4) to interactively configure and experiment with the different tools and configuration options.
For private repositories, after you found the setup that works for you, you can also easily export it as a persistent configuration file, and use it for automatic commands. For private repositories, after you found the setup that works for you, you can also easily export it as a persistent configuration file, and use it for automatic commands.
@ -27,11 +27,11 @@ For private repositories, after you found the setup that works for you, you can
<img src="https://codium.ai/images/pr_agent/toolbar2.png" width="512"> <img src="https://codium.ai/images/pr_agent/toolbar2.png" width="512">
### PR-Agent filters ### Qodo Merge filters
PR-Agent filters is a sidepanel option. that allows you to filter different message in the conversation tab. Qodo Merge filters is a sidepanel option. that allows you to filter different message in the conversation tab.
For example, you can choose to present only message from PR-Agent, or filter those messages, focusing only on user's comments. For example, you can choose to present only message from Qodo Merge, or filter those messages, focusing only on user's comments.
<img src="https://codium.ai/images/pr_agent/pr_agent_filters1.png" width="256"> <img src="https://codium.ai/images/pr_agent/pr_agent_filters1.png" width="256">
@ -40,7 +40,7 @@ For example, you can choose to present only message from PR-Agent, or filter tho
### Enhanced code suggestions ### Enhanced code suggestions
PR-Agent Chrome extension adds the following capabilities to code suggestions tool's comments: Qodo Merge Chrome extension adds the following capabilities to code suggestions tool's comments:
- Auto-expand the table when you are viewing a code block, to avoid clipping. - Auto-expand the table when you are viewing a code block, to avoid clipping.
- Adding a "quote-and-reply" button, that enables to address and comment on a specific suggestion (for example, asking the author to fix the issue) - Adding a "quote-and-reply" button, that enables to address and comment on a specific suggestion (for example, asking the author to fix the issue)

View File

@ -1,11 +1,11 @@
[PR-Agent Chrome extension](https://chromewebstore.google.com/detail/pr-agent-chrome-extension/ephlnjeghhogofkifjloamocljapahnl) is a collection of tools that integrates seamlessly with your GitHub environment, aiming to enhance your Git usage experience, and providing AI-powered capabilities to your PRs. [Qodo Merge Chrome extension](https://chromewebstore.google.com/detail/pr-agent-chrome-extension/ephlnjeghhogofkifjloamocljapahnl) is a collection of tools that integrates seamlessly with your GitHub environment, aiming to enhance your Git usage experience, and providing AI-powered capabilities to your PRs.
With a single-click installation you will gain access to a context-aware chat on your pull requests code, a toolbar extension with multiple AI feedbacks, PR-Agent filters, and additional abilities. With a single-click installation you will gain access to a context-aware chat on your pull requests code, a toolbar extension with multiple AI feedbacks, Qodo Merge filters, and additional abilities.
The extension is powered by top code models like Claude 3.5 Sonnet and GPT4. All the extension's features are free to use on public repositories. The extension is powered by top code models like Claude 3.5 Sonnet and GPT4. All the extension's features are free to use on public repositories.
For private repositories, you will need to install [PR-Agent Pro](https://github.com/apps/codiumai-pr-agent-pro) in addition to the extension (Quick GitHub app setup with a 14-day free trial. No credit card needed). For private repositories, you will need to install [Qodo Merge Pro](https://github.com/apps/codiumai-pr-agent-pro) in addition to the extension (Quick GitHub app setup with a 14-day free trial. No credit card needed).
For a demonstration of how to install PR-Agent Pro and use it with the Chrome extension, please refer to the tutorial video at the provided [link](https://codium.ai/images/pr_agent/private_repos.mp4). For a demonstration of how to install Qodo Merge Pro and use it with the Chrome extension, please refer to the tutorial video at the provided [link](https://codium.ai/images/pr_agent/private_repos.mp4).
<img src="https://codium.ai/images/pr_agent/PR-AgentChat.gif" width="768"> <img src="https://codium.ai/images/pr_agent/PR-AgentChat.gif" width="768">

View File

@ -1,6 +1,6 @@
## TL;DR ## TL;DR
PR-Agent uses an **asymmetric and dynamic context strategy** to improve AI analysis of code changes in pull requests. Qodo Merge uses an **asymmetric and dynamic context strategy** to improve AI analysis of code changes in pull requests.
It provides more context before changes than after, and dynamically adjusts the context based on code structure (e.g., enclosing functions or classes). It provides more context before changes than after, and dynamically adjusts the context based on code structure (e.g., enclosing functions or classes).
This approach balances providing sufficient context for accurate analysis, while avoiding needle-in-the-haystack information overload that could degrade AI performance or exceed token limits. This approach balances providing sufficient context for accurate analysis, while avoiding needle-in-the-haystack information overload that could degrade AI performance or exceed token limits.
@ -43,14 +43,14 @@ Pull requests often encompass multiple changes across many files, potentially sp
- Increased context expands the token count, increasing processing time and cost, and may prevent the model from processing the entire pull request in a single pass. - Increased context expands the token count, increasing processing time and cost, and may prevent the model from processing the entire pull request in a single pass.
## Asymmetric and dynamic context ## Asymmetric and dynamic context
To address these challenges, PR-Agent employs an **asymmetric** and **dynamic** context strategy, providing the model with more focused and relevant context information for each code change. To address these challenges, Qodo Merge employs an **asymmetric** and **dynamic** context strategy, providing the model with more focused and relevant context information for each code change.
**Asymmetric:** **Asymmetric:**
We start by recognizing that the context preceding a code change is typically more crucial for understanding the modification than the context following it. We start by recognizing that the context preceding a code change is typically more crucial for understanding the modification than the context following it.
Consequently, PR-Agent implements an asymmetric context policy, decoupling the context window into two distinct segments: one for the code before the change and another for the code after. Consequently, Qodo Merge implements an asymmetric context policy, decoupling the context window into two distinct segments: one for the code before the change and another for the code after.
By independently adjusting each context window, PR-Agent can supply the model with a more tailored and pertinent context for individual code changes. By independently adjusting each context window, Qodo Merge can supply the model with a more tailored and pertinent context for individual code changes.
**Dynamic:** **Dynamic:**

View File

@ -1,43 +1,43 @@
# Overview - Impact Evaluation 💎 # Overview - Impact Evaluation 💎
Demonstrating the return on investment (ROI) of AI-powered initiatives is crucial for modern organizations. Demonstrating the return on investment (ROI) of AI-powered initiatives is crucial for modern organizations.
To address this need, PR-Agent has developed an AI impact measurement tools and metrics, providing advanced analytics to help businesses quantify the tangible benefits of AI adoption in their PR review process. To address this need, Qodo Merge has developed an AI impact measurement tools and metrics, providing advanced analytics to help businesses quantify the tangible benefits of AI adoption in their PR review process.
## Auto Impact Validator - Real-Time Tracking of Implemented PR-Agent Suggestions ## Auto Impact Validator - Real-Time Tracking of Implemented Qodo Merge Suggestions
### How It Works ### How It Works
When a user pushes a new commit to the pull request, PR-Agent automatically compares the updated code against the previous suggestions, marking them as implemented if the changes address these recommendations, whether directly or indirectly: When a user pushes a new commit to the pull request, Qodo Merge automatically compares the updated code against the previous suggestions, marking them as implemented if the changes address these recommendations, whether directly or indirectly:
1. **Direct Implementation:** The user directly addresses the suggestion as-is in the PR, either by clicking on the "apply code suggestion" checkbox or by making the changes manually. 1. **Direct Implementation:** The user directly addresses the suggestion as-is in the PR, either by clicking on the "apply code suggestion" checkbox or by making the changes manually.
2. **Indirect Implementation:** PR-Agent recognizes when a suggestion's intent is fulfilled, even if the exact code changes differ from the original recommendation. It marks these suggestions as implemented, acknowledging that users may achieve the same goal through alternative solutions. 2. **Indirect Implementation:** Qodo Merge recognizes when a suggestion's intent is fulfilled, even if the exact code changes differ from the original recommendation. It marks these suggestions as implemented, acknowledging that users may achieve the same goal through alternative solutions.
### Real-Time Visual Feedback ### Real-Time Visual Feedback
Upon confirming that a suggestion was implemented, PR-Agent automatically adds a ✅ (check mark) to the relevant suggestion, enabling transparent tracking of PR-Agent's impact analysis. Upon confirming that a suggestion was implemented, Qodo Merge automatically adds a ✅ (check mark) to the relevant suggestion, enabling transparent tracking of Qodo Merge's impact analysis.
PR-Agent will also add, inside the relevant suggestions, an explanation of how the new code was impacted by each suggestion. Qodo Merge will also add, inside the relevant suggestions, an explanation of how the new code was impacted by each suggestion.
![Suggestion_checkmark](https://codium.ai/images/pr_agent/auto_suggestion_checkmark.png){width=512} ![Suggestion_checkmark](https://codium.ai/images/pr_agent/auto_suggestion_checkmark.png){width=512}
### Dashboard Metrics ### Dashboard Metrics
The dashboard provides macro-level insights into the overall impact of PR-Agent on the pull-request process with key productivity metrics. The dashboard provides macro-level insights into the overall impact of Qodo Merge on the pull-request process with key productivity metrics.
By offering clear, data-driven evidence of PR-Agent's impact, it empowers leadership teams to make informed decisions about the tool's effectiveness and ROI. By offering clear, data-driven evidence of Qodo Merge's impact, it empowers leadership teams to make informed decisions about the tool's effectiveness and ROI.
Here are key metrics that the dashboard tracks: Here are key metrics that the dashboard tracks:
#### PR-Agent Impacts per 1K Lines #### Qodo Merge Impacts per 1K Lines
![Dashboard](https://codium.ai/images/pr_agent/impacts_per_1k_llines.png){width=512} ![Dashboard](https://codium.ai/images/pr_agent/impacts_per_1k_llines.png){width=512}
> Explanation: for every 1K lines of code (additions/edits), PR-Agent had on average ~X suggestions implemented. > Explanation: for every 1K lines of code (additions/edits), Qodo Merge had on average ~X suggestions implemented.
**Why This Metric Matters:** **Why This Metric Matters:**
1. **Standardized and Comparable Measurement:** By measuring impacts per 1K lines of code additions, you create a standardized metric that can be compared across different projects, teams, customers, and time periods. This standardization is crucial for meaningful analysis, benchmarking, and identifying where PR-Agent is most effective. 1. **Standardized and Comparable Measurement:** By measuring impacts per 1K lines of code additions, you create a standardized metric that can be compared across different projects, teams, customers, and time periods. This standardization is crucial for meaningful analysis, benchmarking, and identifying where Qodo Merge is most effective.
2. **Accounts for PR Variability and Incentivizes Quality:** This metric addresses the fact that "Not all PRs are created equal." By normalizing against lines of code rather than PR count, you account for the variability in PR sizes and focus on the quality and impact of suggestions rather than just the number of PRs affected. 2. **Accounts for PR Variability and Incentivizes Quality:** This metric addresses the fact that "Not all PRs are created equal." By normalizing against lines of code rather than PR count, you account for the variability in PR sizes and focus on the quality and impact of suggestions rather than just the number of PRs affected.
3. **Quantifies Value and ROI:** The metric directly correlates with the value PR-Agent is providing, showing how frequently it offers improvements relative to the amount of new code being written. This provides a clear, quantifiable way to demonstrate PR-Agent's return on investment to stakeholders. 3. **Quantifies Value and ROI:** The metric directly correlates with the value Qodo Merge is providing, showing how frequently it offers improvements relative to the amount of new code being written. This provides a clear, quantifiable way to demonstrate Qodo Merge's return on investment to stakeholders.
#### Suggestion Effectiveness Across Categories #### Suggestion Effectiveness Across Categories
![Impacted_Suggestion_Score](https://codium.ai/images/pr_agent/impact_by_category.png){width=512} ![Impacted_Suggestion_Score](https://codium.ai/images/pr_agent/impact_by_category.png){width=512}
> Explanation: This chart illustrates the distribution of implemented suggestions across different categories, enabling teams to better understand PR-Agent's impact on various aspects of code quality and development practices. > Explanation: This chart illustrates the distribution of implemented suggestions across different categories, enabling teams to better understand Qodo Merge's impact on various aspects of code quality and development practices.
#### Suggestion Score Distribution #### Suggestion Score Distribution
![Impacted_Suggestion_Score](https://codium.ai/images/pr_agent/impacted_score_dist.png){width=512} ![Impacted_Suggestion_Score](https://codium.ai/images/pr_agent/impacted_score_dist.png){width=512}

View File

@ -1,12 +1,12 @@
# Core Abilities # Core Abilities
PR-Agent utilizes a variety of core abilities to provide a comprehensive and efficient code review experience. These abilities include: Qodo Merge utilizes a variety of core abilities to provide a comprehensive and efficient code review experience. These abilities include:
- [Local and global metadata](https://pr-agent-docs.codium.ai/core-abilities/metadata/) - [Local and global metadata](https://qodo-merge-docs.qodo.ai/core-abilities/metadata/)
- [Dynamic context](https://pr-agent-docs.codium.ai/core-abilities/dynamic_context/) - [Dynamic context](https://qodo-merge-docs.qodo.ai/core-abilities/dynamic_context/)
- [Self-reflection](https://pr-agent-docs.codium.ai/core-abilities/self_reflection/) - [Self-reflection](https://qodo-merge-docs.qodo.ai/core-abilities/self_reflection/)
- [Impact evaluation](https://pr-agent-docs.codium.ai/core-abilities/impact_evaluation/) - [Impact evaluation](https://qodo-merge-docs.qodo.ai/core-abilities/impact_evaluation/)
- [Interactivity](https://pr-agent-docs.codium.ai/core-abilities/interactivity/) - [Interactivity](https://qodo-merge-docs.qodo.ai/core-abilities/interactivity/)
- [Compression strategy](https://pr-agent-docs.codium.ai/core-abilities/compression_strategy/) - [Compression strategy](https://qodo-merge-docs.qodo.ai/core-abilities/compression_strategy/)
- [Code-oriented YAML](https://pr-agent-docs.codium.ai/core-abilities/code_oriented_yaml/) - [Code-oriented YAML](https://qodo-merge-docs.qodo.ai/core-abilities/code_oriented_yaml/)
- [Static code analysis](https://pr-agent-docs.codium.ai/core-abilities/static_code_analysis/) - [Static code analysis](https://qodo-merge-docs.qodo.ai/core-abilities/static_code_analysis/)
- [Code fine-tuning benchmark](https://pr-agent-docs.codium.ai/finetuning_benchmark/) - [Code fine-tuning benchmark](https://qodo-merge-docs.qodo.ai/finetuning_benchmark/)

View File

@ -1,6 +1,6 @@
## Local and global metadata injection with multi-stage analysis ## Local and global metadata injection with multi-stage analysis
(1) (1)
PR-Agent initially retrieves for each PR the following data: Qodo Merge initially retrieves for each PR the following data:
- PR title and branch name - PR title and branch name
- PR original description - PR original description
@ -9,10 +9,10 @@ PR-Agent initially retrieves for each PR the following data:
- The entire content of the files that were modified in the PR - The entire content of the files that were modified in the PR
!!! tip "Tip: Organization-level metadata" !!! tip "Tip: Organization-level metadata"
In addition to the inputs above, PR-Agent can incorporate supplementary preferences provided by the user, like [`extra_instructions` and `organization best practices`](https://pr-agent-docs.codium.ai/tools/improve/#extra-instructions-and-best-practices). This information can be used to enhance the PR analysis. In addition to the inputs above, Qodo Merge can incorporate supplementary preferences provided by the user, like [`extra_instructions` and `organization best practices`](https://qodo-merge-docs.qodo.ai/tools/improve/#extra-instructions-and-best-practices). This information can be used to enhance the PR analysis.
(2) (2)
By default, the first command that PR-Agent executes is [`describe`](https://pr-agent-docs.codium.ai/tools/describe/), which generates three types of outputs: By default, the first command that Qodo Merge executes is [`describe`](https://qodo-merge-docs.qodo.ai/tools/describe/), which generates three types of outputs:
- PR Type (e.g. bug fix, feature, refactor, etc) - PR Type (e.g. bug fix, feature, refactor, etc)
- PR Description - a bullet point summary of the PR - PR Description - a bullet point summary of the PR
@ -21,7 +21,7 @@ By default, the first command that PR-Agent executes is [`describe`](https://pr-
These AI-generated outputs are now considered as part of the PR metadata, and can be used in subsequent commands like `review` and `improve`. These AI-generated outputs are now considered as part of the PR metadata, and can be used in subsequent commands like `review` and `improve`.
This effectively enables multi-stage chain-of-thought analysis, without doing any additional API calls which will cost time and money. This effectively enables multi-stage chain-of-thought analysis, without doing any additional API calls which will cost time and money.
For example, when generating code suggestions for different files, PR-Agent can inject the AI-generated ["Changes walkthrough"](https://github.com/Codium-ai/pr-agent/pull/1202#issue-2511546839) file summary in the prompt: For example, when generating code suggestions for different files, Qodo Merge can inject the AI-generated ["Changes walkthrough"](https://github.com/Codium-ai/pr-agent/pull/1202#issue-2511546839) file summary in the prompt:
``` ```
## File: 'src/file1.py' ## File: 'src/file1.py'
@ -49,8 +49,8 @@ __old hunk__
... ...
``` ```
(3) The entire PR files that were retrieved are also used to expand and enhance the PR context (see [Dynamic Context](https://pr-agent-docs.codium.ai/core-abilities/dynamic-context/)). (3) The entire PR files that were retrieved are also used to expand and enhance the PR context (see [Dynamic Context](https://qodo-merge-docs.qodo.ai/core-abilities/dynamic-context/)).
(4) All the metadata described above represents several level of cumulative analysis - ranging from hunk level, to file level, to PR level, to organization level. (4) All the metadata described above represents several level of cumulative analysis - ranging from hunk level, to file level, to PR level, to organization level.
This comprehensive approach enables PR-Agent AI models to generate more precise and contextually relevant suggestions and feedback. This comprehensive approach enables Qodo Merge AI models to generate more precise and contextually relevant suggestions and feedback.

View File

@ -1,6 +1,6 @@
## TL;DR ## TL;DR
PR-Agent implements a **self-reflection** process where the AI model reflects, scores, and re-ranks its own suggestions, eliminating irrelevant or incorrect ones. Qodo Merge implements a **self-reflection** process where the AI model reflects, scores, and re-ranks its own suggestions, eliminating irrelevant or incorrect ones.
This approach improves the quality and relevance of suggestions, saving users time and enhancing their experience. This approach improves the quality and relevance of suggestions, saving users time and enhancing their experience.
Configuration options allow users to set a score threshold for further filtering out suggestions. Configuration options allow users to set a score threshold for further filtering out suggestions.
@ -9,7 +9,7 @@ Configuration options allow users to set a score threshold for further filtering
Given that not all generated code suggestions will be relevant, it is crucial to enable users to review them in a fast and efficient way, allowing quick identification and filtering of non-applicable ones. Given that not all generated code suggestions will be relevant, it is crucial to enable users to review them in a fast and efficient way, allowing quick identification and filtering of non-applicable ones.
To achieve this goal, PR-Agent offers a dedicated hierarchical structure when presenting suggestions to users: To achieve this goal, Qodo Merge offers a dedicated hierarchical structure when presenting suggestions to users:
- A "category" section groups suggestions by their category, allowing users to quickly dismiss irrelevant suggestions. - A "category" section groups suggestions by their category, allowing users to quickly dismiss irrelevant suggestions.
- Each suggestion is first described by a one-line summary, which can be expanded to a full description by clicking on a collapsible. - Each suggestion is first described by a one-line summary, which can be expanded to a full description by clicking on a collapsible.
@ -34,7 +34,7 @@ This process consists of the following steps:
Note that presenting all generated suggestions simultaneously provides the model with a comprehensive context, enabling it to make more informed decisions compared to evaluating each suggestion individually. Note that presenting all generated suggestions simultaneously provides the model with a comprehensive context, enabling it to make more informed decisions compared to evaluating each suggestion individually.
To conclude, the self-reflection process enables PR-Agent to prioritize suggestions based on their importance, eliminate inaccurate or irrelevant proposals, and optionally exclude suggestions that fall below a specified threshold of significance. To conclude, the self-reflection process enables Qodo Merge to prioritize suggestions based on their importance, eliminate inaccurate or irrelevant proposals, and optionally exclude suggestions that fall below a specified threshold of significance.
This results in a more refined and valuable set of suggestions for the user, saving time and improving the overall experience. This results in a more refined and valuable set of suggestions for the user, saving time and improving the overall experience.
## Example Results ## Example Results

View File

@ -1,6 +1,6 @@
## Overview - Static Code Analysis 💎 ## Overview - Static Code Analysis 💎
By combining static code analysis with LLM capabilities, PR-Agent can provide a comprehensive analysis of the PR code changes on a component level. By combining static code analysis with LLM capabilities, Qodo Merge can provide a comprehensive analysis of the PR code changes on a component level.
It scans the PR code changes, finds all the code components (methods, functions, classes) that changed, and enables to interactively generate tests, docs, code suggestions and similar code search for each component. It scans the PR code changes, finds all the code components (methods, functions, classes) that changed, and enables to interactively generate tests, docs, code suggestions and similar code search for each component.
@ -13,7 +13,7 @@ It scans the PR code changes, finds all the code components (methods, functions,
### Analyze PR ### Analyze PR
The [`analyze`](https://pr-agent-docs.codium.ai/tools/analyze/) tool enables to interactively generate tests, docs, code suggestions and similar code search for each component that changed in the PR. The [`analyze`](https://qodo-merge-docs.qodo.ai/tools/analyze/) tool enables to interactively generate tests, docs, code suggestions and similar code search for each component that changed in the PR.
It can be invoked manually by commenting on any PR: It can be invoked manually by commenting on any PR:
``` ```
/analyze /analyze
@ -27,7 +27,7 @@ Clicking on each checkbox will trigger the relevant tool for the selected compon
### Generate Tests ### Generate Tests
The [`test`](https://pr-agent-docs.codium.ai/tools/test/) tool generate tests for a selected component, based on the PR code changes. The [`test`](https://qodo-merge-docs.qodo.ai/tools/test/) tool generate tests for a selected component, based on the PR code changes.
It can be invoked manually by commenting on any PR: It can be invoked manually by commenting on any PR:
``` ```
/test component_name /test component_name
@ -38,7 +38,7 @@ where 'component_name' is the name of a specific component in the PR, Or be tri
### Generate Docs for a Component ### Generate Docs for a Component
The [`add_docs`](https://pr-agent-docs.codium.ai/tools/documentation/) tool scans the PR code changes, and automatically generate docstrings for any code components that changed in the PR. The [`add_docs`](https://qodo-merge-docs.qodo.ai/tools/documentation/) tool scans the PR code changes, and automatically generate docstrings for any code components that changed in the PR.
It can be invoked manually by commenting on any PR: It can be invoked manually by commenting on any PR:
``` ```
/add_docs component_name /add_docs component_name
@ -49,7 +49,7 @@ Or be triggered interactively by using the `analyze` tool.
![Docs single component](https://codium.ai/images/pr_agent/docs_single_component.png){width=768} ![Docs single component](https://codium.ai/images/pr_agent/docs_single_component.png){width=768}
### Generate Code Suggestions for a Component ### Generate Code Suggestions for a Component
The [`improve_component`](https://pr-agent-docs.codium.ai/tools/improve_component/) tool generates code suggestions for a specific code component that changed in the PR. The [`improve_component`](https://qodo-merge-docs.qodo.ai/tools/improve_component/) tool generates code suggestions for a specific code component that changed in the PR.
It can be invoked manually by commenting on any PR: It can be invoked manually by commenting on any PR:
``` ```
/improve_component component_name /improve_component component_name
@ -61,7 +61,7 @@ Or be triggered interactively by using the `analyze` tool.
### Find Similar Code ### Find Similar Code
The [`similar code`](https://pr-agent-docs.codium.ai/tools/similar_code/) tool retrieves the most similar code components from inside the organization's codebase, or from open-source code. The [`similar code`](https://qodo-merge-docs.qodo.ai/tools/similar_code/) tool retrieves the most similar code components from inside the organization's codebase, or from open-source code.
For example: For example:

View File

@ -1,14 +1,14 @@
# FAQ # FAQ
??? note "Question: Can PR-Agent serve as a substitute for a human reviewer?" ??? note "Question: Can Qodo Merge serve as a substitute for a human reviewer?"
#### Answer:<span style="display:none;">1</span> #### Answer:<span style="display:none;">1</span>
PR-Agent is designed to assist, not replace, human reviewers. Qodo Merge is designed to assist, not replace, human reviewers.
Reviewing PRs is a tedious and time-consuming task often seen as a "chore". In addition, the longer the PR the shorter the relative feedback, since long PRs can overwhelm reviewers, both in terms of technical difficulty, and the actual review time. Reviewing PRs is a tedious and time-consuming task often seen as a "chore". In addition, the longer the PR the shorter the relative feedback, since long PRs can overwhelm reviewers, both in terms of technical difficulty, and the actual review time.
PR-Agent aims to address these pain points, and to assist and empower both the PR author and reviewer. Qodo Merge aims to address these pain points, and to assist and empower both the PR author and reviewer.
However, PR-Agent has built-in safeguards to ensure the developer remains in the driver's seat. For example: However, Qodo Merge has built-in safeguards to ensure the developer remains in the driver's seat. For example:
1. Preserves user's original PR header 1. Preserves user's original PR header
2. Places user's description above the AI-generated PR description 2. Places user's description above the AI-generated PR description
@ -35,33 +35,33 @@ ___
- Only if the `Category` header is relevant, the user should move to the summarized suggestion description. - Only if the `Category` header is relevant, the user should move to the summarized suggestion description.
- Only if the summarized suggestion description is relevant, the user should click on the collapsible, to read the full suggestion description with a code preview example. - Only if the summarized suggestion description is relevant, the user should click on the collapsible, to read the full suggestion description with a code preview example.
- In addition, we recommend to use the [`extra_instructions`](https://pr-agent-docs.codium.ai/tools/improve/#extra-instructions-and-best-practices) field to guide the model to suggestions that are more relevant to the specific needs of the project. - In addition, we recommend to use the [`extra_instructions`](https://qodo-merge-docs.qodo.ai/tools/improve/#extra-instructions-and-best-practices) field to guide the model to suggestions that are more relevant to the specific needs of the project.
- The interactive [PR chat](https://pr-agent-docs.codium.ai/chrome-extension/) also provides an easy way to get more tailored suggestions and feedback from the AI model. - The interactive [PR chat](https://qodo-merge-docs.qodo.ai/chrome-extension/) also provides an easy way to get more tailored suggestions and feedback from the AI model.
___ ___
??? note "Question: How can I get more tailored suggestions?" ??? note "Question: How can I get more tailored suggestions?"
#### Answer:<span style="display:none;">3</span> #### Answer:<span style="display:none;">3</span>
See [here](https://pr-agent-docs.codium.ai/tools/improve/#extra-instructions-and-best-practices) for more information on how to use the `extra_instructions` and `best_practices` configuration options, to guide the model to more tailored suggestions. See [here](https://qodo-merge-docs.qodo.ai/tools/improve/#extra-instructions-and-best-practices) for more information on how to use the `extra_instructions` and `best_practices` configuration options, to guide the model to more tailored suggestions.
___ ___
??? note "Question: Will you store my code ? Are you using my code to train models?" ??? note "Question: Will you store my code ? Are you using my code to train models?"
#### Answer:<span style="display:none;">4</span> #### Answer:<span style="display:none;">4</span>
No. PR-Agent strict privacy policy ensures that your code is not stored or used for training purposes. No. Qodo Merge strict privacy policy ensures that your code is not stored or used for training purposes.
For a detailed overview of our data privacy policy, please refer to [this link](https://pr-agent-docs.codium.ai/overview/data_privacy/) For a detailed overview of our data privacy policy, please refer to [this link](https://qodo-merge-docs.qodo.ai/overview/data_privacy/)
___ ___
??? note "Question: Can I use my own LLM keys with PR-Agent?" ??? note "Question: Can I use my own LLM keys with Qodo Merge?"
#### Answer:<span style="display:none;">5</span> #### Answer:<span style="display:none;">5</span>
When you self-host, you use your own keys. When you self-host, you use your own keys.
PR-Agent Pro with SaaS deployment is a hosted version of PR-Agent, where Codium AI manages the infrastructure and the keys. Qodo Merge Pro with SaaS deployment is a hosted version of Qodo Merge, where Qodo manages the infrastructure and the keys.
For enterprise customers, on-prem deployment is also available. [Contact us](https://www.codium.ai/contact/#pricing) for more information. For enterprise customers, on-prem deployment is also available. [Contact us](https://www.codium.ai/contact/#pricing) for more information.
___ ___

View File

@ -1,10 +1,10 @@
# PR-Agent Code Fine-tuning Benchmark # Qodo Merge Code Fine-tuning Benchmark
On coding tasks, the gap between open-source models and top closed-source models such as GPT4 is significant. On coding tasks, the gap between open-source models and top closed-source models such as GPT4 is significant.
<br> <br>
In practice, open-source models are unsuitable for most real-world code tasks, and require further fine-tuning to produce acceptable results. In practice, open-source models are unsuitable for most real-world code tasks, and require further fine-tuning to produce acceptable results.
_PR-Agent fine-tuning benchmark_ aims to benchmark open-source models on their ability to be fine-tuned for a coding task. _Qodo Merge fine-tuning benchmark_ aims to benchmark open-source models on their ability to be fine-tuned for a coding task.
Specifically, we chose to fine-tune open-source models on the task of analyzing a pull request, and providing useful feedback and code suggestions. Specifically, we chose to fine-tune open-source models on the task of analyzing a pull request, and providing useful feedback and code suggestions.
Here are the results: Here are the results:
@ -53,8 +53,8 @@ Here are the results:
### Training dataset ### Training dataset
Our training dataset comprises 25,000 pull requests, aggregated from permissive license repos. For each pull request, we generated responses for the three main tools of PR-Agent: Our training dataset comprises 25,000 pull requests, aggregated from permissive license repos. For each pull request, we generated responses for the three main tools of Qodo Merge:
[Describe](https://pr-agent-docs.codium.ai/tools/describe/), [Review](https://pr-agent-docs.codium.ai/tools/improve/) and [Improve](https://pr-agent-docs.codium.ai/tools/improve/). [Describe](https://qodo-merge-docs.qodo.ai/tools/describe/), [Review](https://qodo-merge-docs.qodo.ai/tools/improve/) and [Improve](https://qodo-merge-docs.qodo.ai/tools/improve/).
On the raw data collected, we employed various automatic and manual cleaning techniques to ensure the outputs were of the highest quality, and suitable for instruct-tuning. On the raw data collected, we employed various automatic and manual cleaning techniques to ensure the outputs were of the highest quality, and suitable for instruct-tuning.

View File

@ -1,25 +1,38 @@
# Overview # Overview
CodiumAI PR-Agent is an open-source tool to help efficiently review and handle pull requests. Qodo Merge is an open-source tool to help efficiently review and handle pull requests.
- See the [Installation Guide](./installation/index.md) for instructions on installing and running the tool on different git platforms. - See the [Installation Guide](./installation/index.md) for instructions on installing and running the tool on different git platforms.
- See the [Usage Guide](./usage-guide/index.md) for instructions on running the PR-Agent commands via different interfaces, including _CLI_, _online usage_, or by _automatically triggering_ them when a new PR is opened. - See the [Usage Guide](./usage-guide/index.md) for instructions on running the Qodo Merge commands via different interfaces, including _CLI_, _online usage_, or by _automatically triggering_ them when a new PR is opened.
- See the [Tools Guide](./tools/index.md) for a detailed description of the different tools. - See the [Tools Guide](./tools/index.md) for a detailed description of the different tools.
## PR-Agent Features ## Qodo Merge Docs Smart Search
PR-Agent offers extensive pull request functionalities across various git providers.
To search the documentation site using natural language:
1) Comment `/help "your question"` in either:
- A pull request where Qodo Merge is installed
- A [PR Chat](https://qodo-merge-docs.qodo.ai/chrome-extension/features/#pr-chat)
2) Qodo Merge will respond with an [answer](https://github.com/Codium-ai/pr-agent/pull/1241#issuecomment-2365259334) that includes relevant documentation links.
## Qodo Merge Features
Qodo Merge offers extensive pull request functionalities across various git providers.
| | | GitHub | Gitlab | Bitbucket | Azure DevOps | | | | GitHub | Gitlab | Bitbucket | Azure DevOps |
|-------|-----------------------------------------------------------------------------------------------------------------------|:------:|:------:|:---------:|:------------:| |-------|-----------------------------------------------------------------------------------------------------------------------|:------:|:------:|:---------:|:------------:|
| TOOLS | Review | ✅ | ✅ | ✅ | ✅ | | TOOLS | Review | ✅ | ✅ | ✅ | ✅ |
| | ⮑ Incremental | ✅ | | | | | | ⮑ Incremental | ✅ | | | |
| | ⮑ [SOC2 Compliance](https://pr-agent-docs.codium.ai/tools/review/#soc2-ticket-compliance){:target="_blank"} 💎 | ✅ | ✅ | ✅ | | | | ⮑ [SOC2 Compliance](https://qodo-merge-docs.qodo.ai/tools/review/#soc2-ticket-compliance){:target="_blank"} 💎 | ✅ | ✅ | ✅ | |
| | Ask | ✅ | ✅ | ✅ | ✅ | | | Ask | ✅ | ✅ | ✅ | ✅ |
| | Describe | ✅ | ✅ | ✅ | ✅ | | | Describe | ✅ | ✅ | ✅ | ✅ |
| | ⮑ [Inline file summary](https://pr-agent-docs.codium.ai/tools/describe/#inline-file-summary){:target="_blank"} 💎 | ✅ | ✅ | | | | | ⮑ [Inline file summary](https://qodo-merge-docs.qodo.ai/tools/describe/#inline-file-summary){:target="_blank"} 💎 | ✅ | ✅ | | |
| | Improve | ✅ | ✅ | ✅ | ✅ | | | Improve | ✅ | ✅ | ✅ | ✅ |
| | ⮑ Extended | ✅ | ✅ | ✅ | ✅ | | | ⮑ Extended | ✅ | ✅ | ✅ | ✅ |
| | [Custom Prompt](./tools/custom_prompt.md){:target="_blank"} 💎 | ✅ | ✅ | ✅ | | | | [Custom Prompt](./tools/custom_prompt.md){:target="_blank"} 💎 | ✅ | ✅ | ✅ | |
@ -42,7 +55,7 @@ PR-Agent offers extensive pull request functionalities across various git provid
| | [Static code analysis](./tools/analyze.md/){:target="_blank"} 💎 | ✅ | ✅ | ✅ | | | | [Static code analysis](./tools/analyze.md/){:target="_blank"} 💎 | ✅ | ✅ | ✅ | |
| | [Multiple configuration options](./usage-guide/configuration_options.md){:target="_blank"} 💎 | ✅ | ✅ | ✅ | | | | [Multiple configuration options](./usage-guide/configuration_options.md){:target="_blank"} 💎 | ✅ | ✅ | ✅ | |
💎 marks a feature available only in [PR-Agent Pro](https://www.codium.ai/pricing/){:target="_blank"} 💎 marks a feature available only in [Qodo Merge Pro](https://www.codium.ai/pricing/){:target="_blank"}
## Example Results ## Example Results
@ -74,8 +87,8 @@ PR-Agent offers extensive pull request functionalities across various git provid
## How it Works ## How it Works
The following diagram illustrates PR-Agent tools and their flow: The following diagram illustrates Qodo Merge tools and their flow:
![PR-Agent Tools](https://codium.ai/images/pr_agent/diagram-v0.9.png) ![Qodo Merge Tools](https://codium.ai/images/pr_agent/diagram-v0.9.png)
Check out the [core abilities](core-abilities/index.md) page for a comprehensive overview of the variety of core abilities used by PR-Agent. Check out the [core abilities](core-abilities/index.md) page for a comprehensive overview of the variety of core abilities used by Qodo Merge.

View File

@ -1,5 +1,5 @@
## Azure DevOps Pipeline ## Azure DevOps Pipeline
You can use a pre-built Action Docker image to run PR-Agent as an Azure devops pipeline. You can use a pre-built Action Docker image to run Qodo Merge as an Azure devops pipeline.
add the following file to your repository under `azure-pipelines.yml`: add the following file to your repository under `azure-pipelines.yml`:
```yaml ```yaml
# Opt out of CI triggers # Opt out of CI triggers
@ -47,11 +47,11 @@ stages:
env: env:
azure_devops__pat: $(azure_devops_pat) azure_devops__pat: $(azure_devops_pat)
openai__key: $(OPENAI_KEY) openai__key: $(OPENAI_KEY)
displayName: 'Run PR Agent' displayName: 'Run Qodo Merge'
``` ```
This script will run PR-Agent on every new merge request, with the `improve`, `review`, and `describe` commands. This script will run Qodo Merge on every new merge request, with the `improve`, `review`, and `describe` commands.
Note that you need to export the `azure_devops__pat` and `OPENAI_KEY` variables in the Azure DevOps pipeline settings (Pipelines -> Library -> + Variable group): Note that you need to export the `azure_devops__pat` and `OPENAI_KEY` variables in the Azure DevOps pipeline settings (Pipelines -> Library -> + Variable group):
![PR Agent Pro](https://codium.ai/images/pr_agent/azure_devops_pipeline_secrets.png){width=468} ![Qodo Merge Pro](https://codium.ai/images/pr_agent/azure_devops_pipeline_secrets.png){width=468}
Make sure to give pipeline permissions to the `pr_agent` variable group. Make sure to give pipeline permissions to the `pr_agent` variable group.

View File

@ -1,7 +1,7 @@
## Run as a Bitbucket Pipeline ## Run as a Bitbucket Pipeline
You can use the Bitbucket Pipeline system to run PR-Agent on every pull request open or update. 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
@ -29,7 +29,7 @@ Note that comments on a PR are not supported in Bitbucket Pipeline.
## Run using CodiumAI-hosted Bitbucket app 💎 ## Run using CodiumAI-hosted Bitbucket app 💎
Please contact visit [PR-Agent pro](https://www.codium.ai/pricing/) if you're interested in a hosted BitBucket app solution that provides full functionality including PR reviews and comment handling. It's based on the [bitbucket_app.py](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/git_providers/bitbucket_provider.py) implementation. Please contact visit [Qodo Merge Pro](https://www.codium.ai/pricing/) if you're interested in a hosted BitBucket app solution that provides full functionality including PR reviews and comment handling. It's based on the [bitbucket_app.py](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/git_providers/bitbucket_provider.py) implementation.
## Bitbucket Server and Data Center ## Bitbucket Server and Data Center
@ -58,7 +58,7 @@ python cli.py --pr_url https://git.onpreminstanceofbitbucket.com/projects/PROJEC
### Run it as service ### Run it as service
To run pr-agent as webhook, build the docker image: To run Qodo Merge as webhook, build the docker image:
``` ```
docker build . -t codiumai/pr-agent:bitbucket_server_webhook --target bitbucket_server_webhook -f docker/Dockerfile docker build . -t codiumai/pr-agent:bitbucket_server_webhook --target bitbucket_server_webhook -f docker/Dockerfile
docker push codiumai/pr-agent:bitbucket_server_webhook # Push to your Docker repository docker push codiumai/pr-agent:bitbucket_server_webhook # Push to your Docker repository

View File

@ -1,6 +1,6 @@
## Run as a GitHub Action ## Run as a GitHub Action
You can use our pre-built Github Action Docker image to run PR-Agent as a Github Action. You can use our pre-built Github Action Docker image to run Qodo Merge as a Github Action.
1) Add the following file to your repository under `.github/workflows/pr_agent.yml`: 1) Add the following file to your repository under `.github/workflows/pr_agent.yml`:
@ -60,7 +60,7 @@ The GITHUB_TOKEN secret is automatically created by GitHub.
3) Merge this change to your main branch. 3) Merge this change to your main branch.
When you open your next PR, you should see a comment from `github-actions` bot with a review of your PR, and instructions on how to use the rest of the tools. When you open your next PR, you should see a comment from `github-actions` bot with a review of your PR, and instructions on how to use the rest of the tools.
4) You may configure PR-Agent by adding environment variables under the env section corresponding to any configurable property in the [configuration](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml) file. Some examples: 4) You may configure Qodo Merge by adding environment variables under the env section corresponding to any configurable property in the [configuration](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml) file. Some examples:
```yaml ```yaml
env: env:
# ... previous environment values # ... previous environment values
@ -68,7 +68,7 @@ When you open your next PR, you should see a comment from `github-actions` bot w
PR_REVIEWER.REQUIRE_TESTS_REVIEW: "false" # Disable tests review PR_REVIEWER.REQUIRE_TESTS_REVIEW: "false" # Disable tests review
PR_CODE_SUGGESTIONS.NUM_CODE_SUGGESTIONS: 6 # Increase number of code suggestions PR_CODE_SUGGESTIONS.NUM_CODE_SUGGESTIONS: 6 # Increase number of code suggestions
``` ```
See detailed usage instructions in the [USAGE GUIDE](https://pr-agent-docs.codium.ai/usage-guide/automations_and_usage/#github-action) See detailed usage instructions in the [USAGE GUIDE](https://qodo-merge-docs.qodo.ai/usage-guide/automations_and_usage/#github-action)
--- ---
@ -155,7 +155,7 @@ cp pr_agent/settings/.secrets_template.toml pr_agent/settings/.secrets.toml
9. Install the app by navigating to the "Install App" tab and selecting your desired repositories. 9. Install the app by navigating to the "Install App" tab and selecting your desired repositories.
> **Note:** When running PR-Agent from GitHub App, the default configuration file (configuration.toml) will be loaded. > **Note:** When running Qodo Merge from GitHub app, the default configuration file (configuration.toml) will be loaded.
> However, you can override the default tool parameters by uploading a local configuration file `.pr_agent.toml` > However, you can override the default tool parameters by uploading a local configuration file `.pr_agent.toml`
> For more information please check out the [USAGE GUIDE](../usage-guide/automations_and_usage.md#github-app) > For more information please check out the [USAGE GUIDE](../usage-guide/automations_and_usage.md#github-app)
--- ---
@ -185,7 +185,7 @@ For example: `GITHUB.WEBHOOK_SECRET` --> `GITHUB__WEBHOOK_SECRET`
## AWS CodeCommit Setup ## AWS CodeCommit Setup
Not all features have been added to CodeCommit yet. As of right now, CodeCommit has been implemented to run the pr-agent CLI on the command line, using AWS credentials stored in environment variables. (More features will be added in the future.) The following is a set of instructions to have pr-agent do a review of your CodeCommit pull request from the command line: Not all features have been added to CodeCommit yet. As of right now, CodeCommit has been implemented to run the Qodo Merge CLI on the command line, using AWS credentials stored in environment variables. (More features will be added in the future.) The following is a set of instructions to have Qodo Merge do a review of your CodeCommit pull request from the command line:
1. Create an IAM user that you will use to read CodeCommit pull requests and post comments 1. Create an IAM user that you will use to read CodeCommit pull requests and post comments
* Note: That user should have CLI access only, not Console access * Note: That user should have CLI access only, not Console access

View File

@ -1,5 +1,5 @@
## Run as a GitLab Pipeline ## Run as a GitLab Pipeline
You can use a pre-built Action Docker image to run PR-Agent as a GitLab pipeline. This is a simple way to get started with PR-Agent without setting up your own server. You can use a pre-built Action Docker image to run Qodo Merge as a GitLab pipeline. This is a simple way to get started with Qodo Merge without setting up your own server.
(1) Add the following file to your repository under `.gitlab-ci.yml`: (1) Add the following file to your repository under `.gitlab-ci.yml`:
```yaml ```yaml
@ -16,6 +16,7 @@ pr_agent_job:
- echo "Running PR Agent action step" - echo "Running PR Agent action step"
- export MR_URL="$CI_MERGE_REQUEST_PROJECT_URL/merge_requests/$CI_MERGE_REQUEST_IID" - export MR_URL="$CI_MERGE_REQUEST_PROJECT_URL/merge_requests/$CI_MERGE_REQUEST_IID"
- echo "MR_URL=$MR_URL" - echo "MR_URL=$MR_URL"
- export gitlab__url=$CI_SERVER_PROTOCOL://$CI_SERVER_FQDN
- export gitlab__PERSONAL_ACCESS_TOKEN=$GITLAB_PERSONAL_ACCESS_TOKEN - export gitlab__PERSONAL_ACCESS_TOKEN=$GITLAB_PERSONAL_ACCESS_TOKEN
- export config__git_provider="gitlab" - export config__git_provider="gitlab"
- export openai__key=$OPENAI_KEY - export openai__key=$OPENAI_KEY
@ -25,8 +26,8 @@ pr_agent_job:
rules: rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"' - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
``` ```
This script will run PR-Agent on every new merge request. You can modify the `rules` section to run PR-Agent on different events. This script will run Qodo Merge on every new merge request. You can modify the `rules` section to run Qodo Merge on different events.
You can also modify the `script` section to run different PR-Agent commands, or with different parameters by exporting different environment variables. You can also modify the `script` section to run different Qodo Merge commands, or with different parameters by exporting different environment variables.
(2) Add the following masked variables to your GitLab repository (CI/CD -> Variables): (2) Add the following masked variables to your GitLab repository (CI/CD -> Variables):
@ -48,7 +49,7 @@ Note that if your base branches are not protected, don't set the variables as `p
``` ```
WEBHOOK_SECRET=$(python -c "import secrets; print(secrets.token_hex(10))") WEBHOOK_SECRET=$(python -c "import secrets; print(secrets.token_hex(10))")
``` ```
3. Follow the instructions to build the Docker image, setup a secrets file and deploy on your own server from [here](https://pr-agent-docs.codium.ai/installation/github/#run-as-a-github-app) steps 4-7. 3. Follow the instructions to build the Docker image, setup a secrets file and deploy on your own server from [here](https://qodo-merge-docs.qodo.ai/installation/github/#run-as-a-github-app) steps 4-7.
4. In the secrets file, fill in the following: 4. In the secrets file, fill in the following:
- Your OpenAI key. - Your OpenAI key.

View File

@ -1,12 +1,12 @@
# Installation # Installation
## Self-hosted PR-Agent ## Self-hosted Qodo Merge
If you choose to host you own PR-Agent, you first need to acquire two tokens: If you choose to host you own Qodo Merge, you first need to acquire two tokens:
1. An OpenAI key from [here](https://platform.openai.com/api-keys), with access to GPT-4 (or a key for other [language models](https://pr-agent-docs.codium.ai/usage-guide/changing_a_model/), if you prefer). 1. An OpenAI key from [here](https://platform.openai.com/api-keys), with access to GPT-4 (or a key for other [language models](https://qodo-merge-docs.qodo.ai/usage-guide/changing_a_model/), if you prefer).
2. A GitHub\GitLab\BitBucket personal access token (classic), with the repo scope. [GitHub from [here](https://github.com/settings/tokens)] 2. A GitHub\GitLab\BitBucket personal access token (classic), with the repo scope. [GitHub from [here](https://github.com/settings/tokens)]
There are several ways to use self-hosted PR-Agent: There are several ways to use self-hosted Qodo Merge:
- [Locally](./locally.md) - [Locally](./locally.md)
- [GitHub](./github.md) - [GitHub](./github.md)
@ -14,8 +14,8 @@ There are several ways to use self-hosted PR-Agent:
- [BitBucket](./bitbucket.md) - [BitBucket](./bitbucket.md)
- [Azure DevOps](./azure.md) - [Azure DevOps](./azure.md)
## PR-Agent Pro 💎 ## Qodo Merge Pro 💎
PR-Agent Pro, an app hosted by CodiumAI for GitHub\GitLab\BitBucket, is also available. Qodo Merge Pro, an app hosted by CodiumAI for GitHub\GitLab\BitBucket, is also available.
<br> <br>
With PR-Agent Pro, installation is as simple as signing up and adding the PR-Agent app to your relevant repo. With Qodo Merge Pro, installation is as simple as signing up and adding the Qodo Merge app to your relevant repo.
See [here](https://pr-agent-docs.codium.ai/installation/pr_agent_pro/) for more details. See [here](https://qodo-merge-docs.qodo.ai/installation/pr_agent_pro/) for more details.

View File

@ -1,33 +1,33 @@
## Getting Started with PR-Agent Pro ## Getting Started with Qodo Merge Pro
PR-Agent Pro is a versatile application compatible with GitHub, GitLab, and BitBucket, hosted by CodiumAI. Qodo Merge Pro is a versatile application compatible with GitHub, GitLab, and BitBucket, hosted by CodiumAI.
See [here](https://pr-agent-docs.codium.ai/#pr-agent-pro) for more details about the benefits of using PR-Agent Pro. See [here](https://qodo-merge-docs.qodo.ai/overview/pr_agent_pro/) for more details about the benefits of using Qodo Merge Pro.
Interested parties can subscribe to PR-Agent Pro through the following [link](https://www.codium.ai/pricing/). Interested parties can subscribe to Qodo Merge Pro through the following [link](https://www.codium.ai/pricing/).
After subscribing, you are granted the ability to easily install the application across any of your repositories. After subscribing, you are granted the ability to easily install the application across any of your repositories.
![PR Agent Pro](https://codium.ai/images/pr_agent/pr_agent_pro_install.png){width=468} ![Qodo Merge Pro](https://codium.ai/images/pr_agent/pr_agent_pro_install.png){width=468}
Each user who wants to use PR-Agent pro needs to buy a seat. Each user who wants to use Qodo Merge pro needs to buy a seat.
Initially, CodiumAI offers a two-week trial period at no cost, after which continued access requires each user to secure a personal seat. Initially, CodiumAI offers a two-week trial period at no cost, after which continued access requires each user to secure a personal seat.
Once a user acquires a seat, they gain the flexibility to use PR-Agent Pro across any repository where it was enabled. Once a user acquires a seat, they gain the flexibility to use Qodo Merge Pro across any repository where it was enabled.
Users without a purchased seat who interact with a repository featuring PR-Agent Pro are entitled to receive up to five complimentary feedbacks. Users without a purchased seat who interact with a repository featuring Qodo Merge Pro are entitled to receive up to five complimentary feedbacks.
Beyond this limit, PR-Agent Pro will cease to respond to their inquiries unless a seat is purchased. Beyond this limit, Qodo Merge Pro will cease to respond to their inquiries unless a seat is purchased.
## Install PR-Agent Pro for GitHub Enterprise Server ## Install Qodo Merge Pro for GitHub Enterprise Server
You can install PR-Agent Pro application on your GitHub Enterprise Server, and enjoy two weeks of free trial. You can install Qodo Merge Pro application on your GitHub Enterprise Server, and enjoy two weeks of free trial.
After the trial period, to continue using PR-Agent Pro, you will need to contact us for an [Enterprise license](https://www.codium.ai/pricing/). After the trial period, to continue using Qodo Merge Pro, you will need to contact us for an [Enterprise license](https://www.codium.ai/pricing/).
## Install PR-Agent Pro for GitLab (Teams & Enterprise) ## Install Qodo Merge Pro for GitLab (Teams & Enterprise)
Since GitLab platform does not support apps, installing PR-Agent Pro for GitLab is a bit more involved, and requires the following steps: Since GitLab platform does not support apps, installing Qodo Merge Pro for GitLab is a bit more involved, and requires the following steps:
### Step 1 ### Step 1
Acquire a personal, project or group level access token. Enable the “api” scope in order to allow PR-Agent to read pull requests, comment and respond to requests. Acquire a personal, project or group level access token. Enable the “api” scope in order to allow Qodo Merge to read pull requests, comment and respond to requests.
<figure markdown="1"> <figure markdown="1">
![Step 1](https://www.codium.ai/images/pr_agent/gitlab_pro_pat.png){width=750} ![Step 1](https://www.codium.ai/images/pr_agent/gitlab_pro_pat.png){width=750}
@ -65,4 +65,4 @@ Enable SSL verification: Check the box.
Youre all set! Youre all set!
Open a new merge request or add a MR comment with one of PR-Agents commands such as /review, /describe or /improve. Open a new merge request or add a MR comment with one of Qodo Merges commands such as /review, /describe or /improve.

View File

@ -1,16 +1,16 @@
## Self-hosted PR-Agent ## Self-hosted Qodo Merge
- If you self-host PR-Agent with your OpenAI (or other LLM provider) API key, it is between you and the provider. We don't send your code data to PR-Agent servers. - If you self-host Qodo Merge with your OpenAI (or other LLM provider) API key, it is between you and the provider. We don't send your code data to Qodo Merge servers.
## PR-Agent Pro 💎 ## Qodo Merge Pro 💎
- When using PR-Agent Pro 💎, hosted by CodiumAI, we will not store any of your data, nor will we use it for training. You will also benefit from an OpenAI account with zero data retention. - When using Qodo Merge Pro 💎, hosted by CodiumAI, we will not store any of your data, nor will we use it for training. You will also benefit from an OpenAI account with zero data retention.
- For certain clients, CodiumAI-hosted PR-Agent Pro will use CodiumAIs proprietary models. If this is the case, you will be notified. - For certain clients, CodiumAI-hosted Qodo Merge Pro will use CodiumAIs proprietary models. If this is the case, you will be notified.
- No passive collection of Code and Pull Requests data — PR-Agent will be active only when you invoke it, and it will then extract and analyze only data relevant to the executed command and queried pull request. - No passive collection of Code and Pull Requests data — Qodo Merge will be active only when you invoke it, and it will then extract and analyze only data relevant to the executed command and queried pull request.
## PR-Agent Chrome extension ## Qodo Merge Chrome extension
- The [PR-Agent Chrome extension](https://chromewebstore.google.com/detail/pr-agent-chrome-extension/ephlnjeghhogofkifjloamocljapahnl) will not send your code to any external servers. - The [Qodo Merge Chrome extension](https://chromewebstore.google.com/detail/pr-agent-chrome-extension/ephlnjeghhogofkifjloamocljapahnl) will not send your code to any external servers.

View File

@ -1,25 +1,38 @@
# Overview # Overview
CodiumAI PR-Agent is an open-source tool to help efficiently review and handle pull requests. Qodo Merge is an open-source tool to help efficiently review and handle pull requests.
- See the [Installation Guide](./installation/index.md) for instructions on installing and running the tool on different git platforms. - See the [Installation Guide](./installation/index.md) for instructions on installing and running the tool on different git platforms.
- See the [Usage Guide](./usage-guide/index.md) for instructions on running the PR-Agent commands via different interfaces, including _CLI_, _online usage_, or by _automatically triggering_ them when a new PR is opened. - See the [Usage Guide](./usage-guide/index.md) for instructions on running the Qodo Merge commands via different interfaces, including _CLI_, _online usage_, or by _automatically triggering_ them when a new PR is opened.
- See the [Tools Guide](./tools/index.md) for a detailed description of the different tools. - See the [Tools Guide](./tools/index.md) for a detailed description of the different tools.
## PR-Agent Features ## Qodo Merge Docs Smart Search
PR-Agent offers extensive pull request functionalities across various git providers.
To search the documentation site using natural language:
1) Comment `/help "your question"` in either:
- A pull request where Qodo Merge is installed
- A [PR Chat](https://qodo-merge-docs.qodo.ai/chrome-extension/features/#pr-chat)
2) Qodo Merge will respond with an [answer](https://github.com/Codium-ai/pr-agent/pull/1241#issuecomment-2365259334) that includes relevant documentation links.
## Qodo Merge Features
Qodo Merge offers extensive pull request functionalities across various git providers.
| | | GitHub | Gitlab | Bitbucket | Azure DevOps | | | | GitHub | Gitlab | Bitbucket | Azure DevOps |
|-------|-----------------------------------------------------------------------------------------------------------------------|:------:|:------:|:---------:|:------------:| |-------|-----------------------------------------------------------------------------------------------------------------------|:------:|:------:|:---------:|:------------:|
| TOOLS | Review | ✅ | ✅ | ✅ | ✅ | | TOOLS | Review | ✅ | ✅ | ✅ | ✅ |
| | ⮑ Incremental | ✅ | | | | | | ⮑ Incremental | ✅ | | | |
| | ⮑ [SOC2 Compliance](https://pr-agent-docs.codium.ai/tools/review/#soc2-ticket-compliance){:target="_blank"} 💎 | ✅ | ✅ | ✅ | ✅ | | | ⮑ [SOC2 Compliance](https://qodo-merge-docs.qodo.ai/tools/review/#soc2-ticket-compliance){:target="_blank"} 💎 | ✅ | ✅ | ✅ | ✅ |
| | Ask | ✅ | ✅ | ✅ | ✅ | | | Ask | ✅ | ✅ | ✅ | ✅ |
| | Describe | ✅ | ✅ | ✅ | ✅ | | | Describe | ✅ | ✅ | ✅ | ✅ |
| | ⮑ [Inline file summary](https://pr-agent-docs.codium.ai/tools/describe/#inline-file-summary){:target="_blank"} 💎 | ✅ | ✅ | | ✅ | | | ⮑ [Inline file summary](https://qodo-merge-docs.qodo.ai/tools/describe/#inline-file-summary){:target="_blank"} 💎 | ✅ | ✅ | | ✅ |
| | Improve | ✅ | ✅ | ✅ | ✅ | | | Improve | ✅ | ✅ | ✅ | ✅ |
| | ⮑ Extended | ✅ | ✅ | ✅ | ✅ | | | ⮑ Extended | ✅ | ✅ | ✅ | ✅ |
| | [Custom Prompt](./tools/custom_prompt.md){:target="_blank"} 💎 | ✅ | ✅ | ✅ | ✅ | | | [Custom Prompt](./tools/custom_prompt.md){:target="_blank"} 💎 | ✅ | ✅ | ✅ | ✅ |
@ -42,7 +55,7 @@ PR-Agent offers extensive pull request functionalities across various git provid
| | [Static code analysis](./tools/analyze.md/){:target="_blank"} 💎 | ✅ | ✅ | ✅ | ✅ | | | [Static code analysis](./tools/analyze.md/){:target="_blank"} 💎 | ✅ | ✅ | ✅ | ✅ |
| | [Multiple configuration options](./usage-guide/configuration_options.md){:target="_blank"} 💎 | ✅ | ✅ | ✅ | ✅ | | | [Multiple configuration options](./usage-guide/configuration_options.md){:target="_blank"} 💎 | ✅ | ✅ | ✅ | ✅ |
💎 marks a feature available only in [PR-Agent Pro](https://www.codium.ai/pricing/){:target="_blank"} 💎 marks a feature available only in [Qodo Merge Pro](https://www.codium.ai/pricing/){:target="_blank"}
## Example Results ## Example Results
@ -74,8 +87,8 @@ PR-Agent offers extensive pull request functionalities across various git provid
## How it Works ## How it Works
The following diagram illustrates PR-Agent tools and their flow: The following diagram illustrates Qodo Merge tools and their flow:
![PR-Agent Tools](https://codium.ai/images/pr_agent/diagram-v0.9.png) ![Qodo Merge Tools](https://codium.ai/images/pr_agent/diagram-v0.9.png)
Check out the [PR Compression strategy](core-abilities/index.md) page for more details on how we convert a code diff to a manageable LLM prompt Check out the [PR Compression strategy](core-abilities/index.md) page for more details on how we convert a code diff to a manageable LLM prompt

View File

@ -1,52 +1,52 @@
### Overview ### Overview
[PR-Agent Pro](https://www.codium.ai/pricing/) is a hosted version of PR-Agent, provided by CodiumAI. A complimentary two-week trial is offered, followed by a monthly subscription fee. [Qodo Merge Pro](https://www.codium.ai/pricing/) is a hosted version of Qodo Merge, provided by Qodo. A complimentary two-week trial is offered, followed by a monthly subscription fee.
PR-Agent Pro is designed for companies and teams that require additional features and capabilities. It provides the following benefits: Qodo Merge Pro is designed for companies and teams that require additional features and capabilities. It provides the following benefits:
1. **Fully managed** - We take care of everything for you - hosting, models, regular updates, and more. Installation is as simple as signing up and adding the PR-Agent app to your GitHub\GitLab\BitBucket repo. 1. **Fully managed** - We take care of everything for you - hosting, models, regular updates, and more. Installation is as simple as signing up and adding the Qodo Merge app to your GitHub\GitLab\BitBucket repo.
2. **Improved privacy** - No data will be stored or used to train models. PR-Agent Pro will employ zero data retention, and will use an OpenAI and Claude accounts with zero data retention. 2. **Improved privacy** - No data will be stored or used to train models. Qodo Merge Pro will employ zero data retention, and will use an OpenAI and Claude accounts with zero data retention.
3. **Improved support** - PR-Agent Pro users will receive priority support, and will be able to request new features and capabilities. 3. **Improved support** - Qodo Merge Pro users will receive priority support, and will be able to request new features and capabilities.
4. **Supporting self-hosted git servers** - PR-Agent Pro can be installed on GitHub Enterprise Server, GitLab, and BitBucket. For more information, see the [installation guide](https://pr-agent-docs.codium.ai/installation/pr_agent_pro/). 4. **Supporting self-hosted git servers** - Qodo Merge Pro can be installed on GitHub Enterprise Server, GitLab, and BitBucket. For more information, see the [installation guide](https://qodo-merge-docs.qodo.ai/installation/pr_agent_pro/).
5. **PR Chat** - PR-Agent Pro allows you to engage in [private chat](https://pr-agent-docs.codium.ai/chrome-extension/features/#pr-chat) about your pull requests on private repositories. 5. **PR Chat** - Qodo Merge Pro allows you to engage in [private chat](https://qodo-merge-docs.qodo.ai/chrome-extension/features/#pr-chat) about your pull requests on private repositories.
### Additional features ### Additional features
Here are some of the additional features and capabilities that PR-Agent Pro offers: Here are some of the additional features and capabilities that Qodo Merge Pro offers:
| Feature | Description | | Feature | Description |
|----------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------| |----------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [**Model selection**](https://pr-agent-docs.codium.ai/usage-guide/PR_agent_pro_models/#pr-agent-pro-models) | Choose the model that best fits your needs, among top models like `GPT4` and `Claude-Sonnet-3.5` | [**Model selection**](https://qodo-merge-docs.qodo.ai/usage-guide/PR_agent_pro_models/) | Choose the model that best fits your needs, among top models like `GPT4` and `Claude-Sonnet-3.5`
| [**Global and wiki configuration**](https://pr-agent-docs.codium.ai/usage-guide/configuration_options/) | Control configurations for many repositories from a single location; <br>Edit configuration of a single repo without commiting code | | [**Global and wiki configuration**](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/) | Control configurations for many repositories from a single location; <br>Edit configuration of a single repo without commiting code |
| [**Apply suggestions**](https://pr-agent-docs.codium.ai/tools/improve/#overview) | Generate commitable code from the relevant suggestions interactively by clicking on a checkbox | | [**Apply suggestions**](https://qodo-merge-docs.qodo.ai/tools/improve/#overview) | Generate commitable code from the relevant suggestions interactively by clicking on a checkbox |
| [**Suggestions impact**](https://pr-agent-docs.codium.ai/tools/improve/#assessing-impact) | Automatically mark suggestions that were implemented by the user (either directly in GitHub, or indirectly in the IDE) to enable tracking of the impact of the suggestions | | [**Suggestions impact**](https://qodo-merge-docs.qodo.ai/tools/improve/#assessing-impact) | Automatically mark suggestions that were implemented by the user (either directly in GitHub, or indirectly in the IDE) to enable tracking of the impact of the suggestions |
| [**CI feedback**](https://pr-agent-docs.codium.ai/tools/ci_feedback/) | Automatically analyze failed CI checks on GitHub and provide actionable feedback in the PR conversation, helping to resolve issues quickly | | [**CI feedback**](https://qodo-merge-docs.qodo.ai/tools/ci_feedback/) | Automatically analyze failed CI checks on GitHub and provide actionable feedback in the PR conversation, helping to resolve issues quickly |
| [**Advanced usage statistics**](https://www.codium.ai/contact/#/) | PR-Agent Pro offers detailed statistics at user, repository, and company levels, including metrics about PR-Agent usage, and also general statistics and insights | | [**Advanced usage statistics**](https://www.codium.ai/contact/#/) | Qodo Merge Pro offers detailed statistics at user, repository, and company levels, including metrics about Qodo Merge usage, and also general statistics and insights |
| [**Incorporating companies' best practices**](https://pr-agent-docs.codium.ai/tools/improve/#best-practices) | Use the companies' best practices as reference to increase the effectiveness and the relevance of the code suggestions | | [**Incorporating companies' best practices**](https://qodo-merge-docs.qodo.ai/tools/improve/#best-practices) | Use the companies' best practices as reference to increase the effectiveness and the relevance of the code suggestions |
| [**Interactive triggering**](https://pr-agent-docs.codium.ai/tools/analyze/#example-usage) | Interactively apply different tools via the `analyze` command | | [**Interactive triggering**](https://qodo-merge-docs.qodo.ai/tools/analyze/#example-usage) | Interactively apply different tools via the `analyze` command |
| [**SOC2 compliance check**](https://pr-agent-docs.codium.ai/tools/review/#configuration-options) | Ensures the PR contains a ticket to a project management system (e.g., Jira, Asana, Trello, etc.) | [**SOC2 compliance check**](https://qodo-merge-docs.qodo.ai/tools/review/#configuration-options) | Ensures the PR contains a ticket to a project management system (e.g., Jira, Asana, Trello, etc.)
| [**Custom labels**](https://pr-agent-docs.codium.ai/tools/describe/#handle-custom-labels-from-the-repos-labels-page) | Define custom labels for PR-Agent to assign to the PR | | [**Custom labels**](https://qodo-merge-docs.qodo.ai/tools/describe/#handle-custom-labels-from-the-repos-labels-page) | Define custom labels for Qodo Merge to assign to the PR |
### Additional tools ### Additional tools
Here are additional tools that are available only for PR-Agent Pro users: Here are additional tools that are available only for Qodo Merge Pro users:
| Feature | Description | | Feature | Description |
|---------|-------------| |---------|-------------|
| [**Custom Prompt Suggestions**](https://pr-agent-docs.codium.ai/tools/custom_prompt/) | Generate code suggestions based on custom prompts from the user | | [**Custom Prompt Suggestions**](https://qodo-merge-docs.qodo.ai/tools/custom_prompt/) | Generate code suggestions based on custom prompts from the user |
| [**Analyze PR components**](https://pr-agent-docs.codium.ai/tools/analyze/) | Identify the components that changed in the PR, and enable to interactively apply different tools to them | | [**Analyze PR components**](https://qodo-merge-docs.qodo.ai/tools/analyze/) | Identify the components that changed in the PR, and enable to interactively apply different tools to them |
| [**Tests**](https://pr-agent-docs.codium.ai/tools/test/) | Generate tests for code components that changed in the PR | | [**Tests**](https://qodo-merge-docs.qodo.ai/tools/test/) | Generate tests for code components that changed in the PR |
| [**PR documentation**](https://pr-agent-docs.codium.ai/tools/documentation/) | Generate docstring for code components that changed in the PR | | [**PR documentation**](https://qodo-merge-docs.qodo.ai/tools/documentation/) | Generate docstring for code components that changed in the PR |
| [**Improve Component**](https://pr-agent-docs.codium.ai/tools/improve_component/) | Generate code suggestions for code components that changed in the PR | | [**Improve Component**](https://qodo-merge-docs.qodo.ai/tools/improve_component/) | Generate code suggestions for code components that changed in the PR |
| [**Similar code search**](https://pr-agent-docs.codium.ai/tools/similar_code/) | Search for similar code in the repository, organization, or entire GitHub | | [**Similar code search**](https://qodo-merge-docs.qodo.ai/tools/similar_code/) | Search for similar code in the repository, organization, or entire GitHub |
### Supported languages ### Supported languages
PR-Agent Pro leverages the world's leading code models - Claude 3.5 Sonnet and GPT-4. Qodo Merge Pro leverages the world's leading code models - Claude 3.5 Sonnet and GPT-4.
As a result, its primary tools such as `describe`, `review`, and `improve`, as well as the PR-chat feature, support virtually all programming languages. As a result, its primary tools such as `describe`, `review`, and `improve`, as well as the PR-chat feature, support virtually all programming languages.
For specialized commands that require static code analysis, PR-Agent Pro offers support for specific languages. For more details about features that require static code analysis, please refer to the [documentation](https://pr-agent-docs.codium.ai/tools/analyze/#overview). For specialized commands that require static code analysis, Qodo Merge Pro offers support for specific languages. For more details about features that require static code analysis, please refer to the [documentation](https://qodo-merge-docs.qodo.ai/tools/analyze/#overview).

View File

@ -28,7 +28,7 @@ When working from CLI, you need to apply the [configuration changes](#configurat
To enable custom labels, you need to apply the [configuration changes](#configuration-options) to the local `.pr_agent.toml` file in you repository. To enable custom labels, you need to apply the [configuration changes](#configuration-options) to the local `.pr_agent.toml` file in you repository.
#### 3. Handle custom labels from the Repo's labels page 💎 #### 3. Handle custom labels from the Repo's labels page 💎
> This feature is available only in PR-Agent Pro > This feature is available only in Qodo Merge Pro
* GitHub : `https://github.com/{owner}/{repo}/labels`, or click on the "Labels" tab in the issues or PRs page. * GitHub : `https://github.com/{owner}/{repo}/labels`, or click on the "Labels" tab in the issues or PRs page.
* GitLab : `https://gitlab.com/{owner}/{repo}/-/labels`, or click on "Manage" -> "Labels" on the left menu. * GitLab : `https://gitlab.com/{owner}/{repo}/-/labels`, or click on "Manage" -> "Labels" on the left menu.

View File

@ -25,7 +25,7 @@ If you want to edit [configurations](#configuration-options), add the relevant o
### Automatic triggering ### Automatic triggering
To run the `describe` automatically when a PR is opened, define in a [configuration file](https://pr-agent-docs.codium.ai/usage-guide/configuration_options/#wiki-configuration-file): To run the `describe` automatically when a PR is opened, define in a [configuration file](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/#wiki-configuration-file):
``` ```
[github_app] [github_app]
pr_commands = [ pr_commands = [
@ -157,7 +157,7 @@ The marker `pr_agent:type` will be replaced with the PR type, `pr_agent:summary`
The default labels of the describe tool are quite generic, since they are meant to be used in any repo: [`Bug fix`, `Tests`, `Enhancement`, `Documentation`, `Other`]. The default labels of the describe tool are quite generic, since they are meant to be used in any repo: [`Bug fix`, `Tests`, `Enhancement`, `Documentation`, `Other`].
You can define custom labels that are relevant for your repo and use cases. You can define custom labels that are relevant for your repo and use cases.
Custom labels can be defined in a [configuration file](https://pr-agent-docs.codium.ai/tools/custom_labels/#configuration-options), or directly in the repo's [labels page](#handle-custom-labels-from-the-repos-labels-page). Custom labels can be defined in a [configuration file](https://qodo-merge-docs.qodo.ai/tools/custom_labels/#configuration-options), or directly in the repo's [labels page](#handle-custom-labels-from-the-repos-labels-page).
Make sure to provide proper title, and a detailed and well-phrased description for each label, so the tool will know when to suggest it. Make sure to provide proper title, and a detailed and well-phrased description for each label, so the tool will know when to suggest it.
Each label description should be a **conditional statement**, that indicates if to add the label to the PR or not, according to the PR content. Each label description should be a **conditional statement**, that indicates if to add the label to the PR or not, according to the PR content.
@ -205,7 +205,7 @@ The description should be comprehensive and detailed, indicating when to add the
## Usage Tips ## Usage Tips
!!! tip "Automation" !!! tip "Automation"
- When you first install PR-Agent app, the [default mode](../usage-guide/automations_and_usage.md#github-app) for the describe tool is: - When you first install Qodo Merge app, the [default mode](../usage-guide/automations_and_usage.md#github-app) for the describe tool is:
``` ```
pr_commands = ["/describe", ...] pr_commands = ["/describe", ...]
``` ```

View File

@ -1,6 +1,6 @@
## Overview ## Overview
The `help` tool provides a list of all the available tools and their descriptions. The `help` tool provides a list of all the available tools and their descriptions.
For PR-Agent Pro users, it also enables to trigger each tool by checking the relevant box. For Qodo Merge Pro users, it also enables to trigger each tool by checking the relevant box.
It can be invoked manually by commenting on any PR: It can be invoked manually by commenting on any PR:
``` ```

View File

@ -1,7 +1,7 @@
## Overview ## Overview
The `improve` tool scans the PR code changes, and automatically generates [meaningful](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/pr_code_suggestions_prompts.toml#L41) suggestions for improving the PR code. The `improve` tool scans the PR code changes, and automatically generates [meaningful](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/pr_code_suggestions_prompts.toml#L41) suggestions for improving the PR code.
The tool can be triggered automatically every time a new PR is [opened](../usage-guide/automations_and_usage.md#github-app-automatic-tools-when-a-new-pr-is-opened), or it can be invoked manually by commenting on any PR: The tool can be triggered automatically every time a new PR is [opened](../usage-guide/automations_and_usage.md#github-app-automatic-tools-when-a-new-pr-is-opened), or it can be invoked manually by commenting on any PR:
``` ```toml
/improve /improve
``` ```
@ -9,7 +9,7 @@ The tool can be triggered automatically every time a new PR is [opened](../usage
![code_suggestions_as_comment_open.png](https://codium.ai/images/pr_agent/code_suggestions_as_comment_open.png){width=512} ![code_suggestions_as_comment_open.png](https://codium.ai/images/pr_agent/code_suggestions_as_comment_open.png){width=512}
Note that the `Apply this suggestion` checkbox, which interactively converts a suggestion into a commitable code comment, is available only for PR-Agent Pro 💎 users. Note that the `Apply this suggestion` checkbox, which interactively converts a suggestion into a commitable code comment, is available only for Qodo Merge Pro 💎 users.
## Example usage ## Example usage
@ -19,12 +19,12 @@ Note that the `Apply this suggestion` checkbox, which interactively converts a s
Invoke the tool manually by commenting `/improve` on any PR. The code suggestions by default are presented as a single comment: Invoke the tool manually by commenting `/improve` on any PR. The code suggestions by default are presented as a single comment:
To edit [configurations](#configuration-options) related to the improve tool, use the following template: To edit [configurations](#configuration-options) related to the improve tool, use the following template:
``` ```toml
/improve --pr_code_suggestions.some_config1=... --pr_code_suggestions.some_config2=... /improve --pr_code_suggestions.some_config1=... --pr_code_suggestions.some_config2=...
``` ```
For example, you can choose to present all the suggestions as commitable code comments, by running the following command: For example, you can choose to present all the suggestions as commitable code comments, by running the following command:
``` ```toml
/improve --pr_code_suggestions.commitable_code_suggestions=true /improve --pr_code_suggestions.commitable_code_suggestions=true
``` ```
@ -36,8 +36,8 @@ Also note that collapsible are not supported in _Bitbucket_. Hence, the suggesti
### Automatic triggering ### Automatic triggering
To run the `improve` automatically when a PR is opened, define in a [configuration file](https://pr-agent-docs.codium.ai/usage-guide/configuration_options/#wiki-configuration-file): To run the `improve` automatically when a PR is opened, define in a [configuration file](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/#wiki-configuration-file):
``` ```toml
[github_app] [github_app]
pr_commands = [ pr_commands = [
"/improve", "/improve",
@ -54,14 +54,14 @@ num_code_suggestions_per_chunk = ...
### Assessing Impact 💎 ### Assessing Impact 💎
Note that PR-Agent pro tracks two types of implementations: Note that Qodo Merge pro tracks two types of implementations:
- Direct implementation - when the user directly applies the suggestion by clicking the `Apply` checkbox. - Direct implementation - when the user directly applies the suggestion by clicking the `Apply` checkbox.
- Indirect implementation - when the user implements the suggestion in their IDE environment. In this case, PR-Agent will utilize, after each commit, a dedicated logic to identify if a suggestion was implemented, and will mark it as implemented. - Indirect implementation - when the user implements the suggestion in their IDE environment. In this case, Qodo Merge will utilize, after each commit, a dedicated logic to identify if a suggestion was implemented, and will mark it as implemented.
![code_suggestions_asses_impact](https://codium.ai/images/pr_agent/code_suggestions_asses_impact.png){width=512} ![code_suggestions_asses_impact](https://codium.ai/images/pr_agent/code_suggestions_asses_impact.png){width=512}
In post-process, PR-Agent counts the number of suggestions that were implemented, and provides general statistics and insights about the suggestions' impact on the PR process. In post-process, Qodo Merge counts the number of suggestions that were implemented, and provides general statistics and insights about the suggestions' impact on the PR process.
![code_suggestions_asses_impact_stats_1](https://codium.ai/images/pr_agent/code_suggestions_asses_impact_stats_1.png){width=512} ![code_suggestions_asses_impact_stats_1](https://codium.ai/images/pr_agent/code_suggestions_asses_impact_stats_1.png){width=512}
@ -70,15 +70,43 @@ In post-process, PR-Agent counts the number of suggestions that were implemented
## Usage Tips ## Usage Tips
### Implementing the proposed code suggestions
Each generated suggestion consists of three key elements:
1. A single-line summary of the proposed change
2. An expandable section containing a comprehensive description of the suggestion
3. A diff snippet showing the recommended code modification (before and after)
We advise users to apply critical analysis and judgment when implementing the proposed suggestions.
In addition to mistakes (which may happen, but are rare), sometimes the presented code modification may serve more as an _illustrative example_ than a direct applicable solution.
In such cases, we recommend prioritizing the suggestion's detailed description, using the diff snippet primarily as a supporting reference.
### Dual publishing mode
Our recommended approach for presenting code suggestions is through a [table](https://qodo-merge-docs.qodo.ai/tools/improve/#overview) (`--pr_code_suggestions.commitable_code_suggestions=false`).
This method significantly reduces the PR footprint and allows for quick and easy digestion of multiple suggestions.
We also offer a complementary **dual publishing mode**. When enabled, suggestions exceeding a certain score threshold are not only displayed in the table, but also presented as commitable PR comments.
This mode helps highlight suggestions deemed more critical.
To activate dual publishing mode, use the following setting:
```toml
[pr_code_suggestions]
dual_publishing_score_threshold = x
```
Where x represents the minimum score threshold (>=) for suggestions to be presented as commitable PR comments in addition to the table. Default is -1 (disabled).
### Self-review ### Self-review
If you set in a configuration file: If you set in a configuration file:
``` ```toml
[pr_code_suggestions] [pr_code_suggestions]
demand_code_suggestions_self_review = true demand_code_suggestions_self_review = true
``` ```
The `improve` tool will add a checkbox below the suggestions, prompting user to acknowledge that they have reviewed the suggestions. The `improve` tool will add a checkbox below the suggestions, prompting user to acknowledge that they have reviewed the suggestions.
You can set the content of the checkbox text via: You can set the content of the checkbox text via:
``` ```toml
[pr_code_suggestions] [pr_code_suggestions]
code_suggestions_self_review_text = "... (your text here) ..." code_suggestions_self_review_text = "... (your text here) ..."
``` ```
@ -86,18 +114,49 @@ code_suggestions_self_review_text = "... (your text here) ..."
![self_review_1](https://codium.ai/images/pr_agent/self_review_1.png){width=512} ![self_review_1](https://codium.ai/images/pr_agent/self_review_1.png){width=512}
💎 In addition, by setting:
```
[pr_code_suggestions]
approve_pr_on_self_review = true
```
the tool can automatically approve the PR when the user checks the self-review checkbox.
!!! tip "Tip - demanding self-review from the PR author"
If you set the number of required reviewers for a PR to 2, this effectively means that the PR author must click the self-review checkbox before the PR can be merged (in addition to a human reviewer). !!! tip "Tip - demanding self-review from the PR author 💎"
By setting:
```toml
[pr_code_suggestions]
approve_pr_on_self_review = true
```
the tool can automatically add an approval when the PR author clicks the self-review checkbox.
- If you set the number of required reviewers for a PR to 2, this effectively means that the PR author must click the self-review checkbox before the PR can be merged (in addition to a human reviewer).
![self_review_2](https://codium.ai/images/pr_agent/self_review_2.png){width=512} ![self_review_2](https://codium.ai/images/pr_agent/self_review_2.png){width=512}
- If you keep the number of required reviewers for a PR to 1 and enable this configuration, this effectively means that the PR author can approve the PR by actively clicking the self-review checkbox.
To prevent unauthorized approvals, this configuration defaults to false, and cannot be altered through online comments; enabling requires a direct update to the configuration file and a commit to the repository. This ensures that utilizing the feature demands a deliberate documented decision by the repository owner.
### How many code suggestions are generated?
Qodo Merge uses a dynamic strategy to generate code suggestions based on the size of the pull request (PR). Here's how it works:
1) Chunking large PRs:
- Qodo Merge divides large PRs into 'chunks'.
- Each chunk contains up to `pr_code_suggestions.max_context_tokens` tokens (default: 14,000).
2) Generating suggestions:
- For each chunk, Qodo Merge generates up to `pr_code_suggestions.num_code_suggestions_per_chunk` suggestions (default: 4).
This approach has two main benefits:
- Scalability: The number of suggestions scales with the PR size, rather than being fixed.
- Quality: By processing smaller chunks, the AI can maintain higher quality suggestions, as larger contexts tend to decrease AI performance.
Note: Chunking is primarily relevant for large PRs. For most PRs (up to 500 lines of code), Qodo Merge will be able to process the entire code in a single call.
### 'Extra instructions' and 'best practices' ### 'Extra instructions' and 'best practices'
#### Extra instructions #### Extra instructions
@ -108,7 +167,7 @@ You can use the `extra_instructions` configuration option to give the AI model a
Be specific, clear, and concise in the instructions. With extra instructions, you are the prompter. Specify relevant aspects that you want the model to focus on. Be specific, clear, and concise in the instructions. With extra instructions, you are the prompter. Specify relevant aspects that you want the model to focus on.
Examples for possible instructions: Examples for possible instructions:
``` ```toml
[pr_code_suggestions] [pr_code_suggestions]
extra_instructions="""\ extra_instructions="""\
(1) Answer in japanese (1) Answer in japanese
@ -141,16 +200,16 @@ This file is only an example. Since it is used as a prompt for an AI model, we w
2) A lengthy file probably represent a more "**generic**" set of guidelines, which the AI model is already familiar with. The objective is to focus on a more targeted set of guidelines tailored to the specific needs of this project. 2) A lengthy file probably represent a more "**generic**" set of guidelines, which the AI model is already familiar with. The objective is to focus on a more targeted set of guidelines tailored to the specific needs of this project.
##### Local and global best practices ##### Local and global best practices
By default, PR-Agent will look for a local `best_practices.md` wiki file in the root of the relevant local repo. By default, Qodo Merge will look for a local `best_practices.md` wiki file in the root of the relevant local repo.
If you want to enable also a global `best_practices.md` wiki file, set first in the global configuration file: If you want to enable also a global `best_practices.md` wiki file, set first in the global configuration file:
``` ```toml
[best_practices] [best_practices]
enable_global_best_practices = true enable_global_best_practices = true
``` ```
Then, create a `best_practices.md` wiki file in the root of [global](https://pr-agent-docs.codium.ai/usage-guide/configuration_options/#global-configuration-file) configuration repository, `pr-agent-settings`. Then, create a `best_practices.md` wiki file in the root of [global](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/#global-configuration-file) configuration repository, `pr-agent-settings`.
##### Example results ##### Example results
@ -170,22 +229,18 @@ Using a combination of both can help the AI model to provide relevant and tailor
??? example "General options" ??? example "General options"
<table> <table>
<tr>
<td><b>num_code_suggestions</b></td>
<td>Number of code suggestions provided by the 'improve' tool. Default is 4 for CLI, 0 for auto tools.</td>
</tr>
<tr> <tr>
<td><b>extra_instructions</b></td> <td><b>extra_instructions</b></td>
<td>Optional extra instructions to the tool. For example: "focus on the changes in the file X. Ignore change in ...".</td> <td>Optional extra instructions to the tool. For example: "focus on the changes in the file X. Ignore change in ...".</td>
</tr> </tr>
<tr>
<td><b>rank_suggestions</b></td>
<td>If set to true, the tool will rank the suggestions, based on importance. Default is false.</td>
</tr>
<tr> <tr>
<td><b>commitable_code_suggestions</b></td> <td><b>commitable_code_suggestions</b></td>
<td>If set to true, the tool will display the suggestions as commitable code comments. Default is false.</td> <td>If set to true, the tool will display the suggestions as commitable code comments. Default is false.</td>
</tr> </tr>
<tr>
<td><b>dual_publishing_score_threshold</b></td>
<td>Minimum score threshold for suggestions to be presented as commitable PR comments in addition to the table. Default is -1 (disabled).</td>
</tr>
<tr> <tr>
<td><b>persistent_comment</b></td> <td><b>persistent_comment</b></td>
<td>If set to true, the improve comment will be persistent, meaning that every new improve request will edit the previous one. Default is false.</td> <td>If set to true, the improve comment will be persistent, meaning that every new improve request will edit the previous one. Default is false.</td>
@ -212,39 +267,35 @@ Using a combination of both can help the AI model to provide relevant and tailor
</tr> </tr>
</table> </table>
??? example "params for 'extended' mode" ??? example "Params for number of suggestions and AI calls"
<table> <table>
<tr> <tr>
<td><b>auto_extended_mode</b></td> <td><b>auto_extended_mode</b></td>
<td>Enable extended mode automatically (no need for the --extended option). Default is true.</td> <td>Enable chunking the PR code and running the tool on each chunk. Default is true.</td>
</tr> </tr>
<tr> <tr>
<td><b>num_code_suggestions_per_chunk</b></td> <td><b>num_code_suggestions_per_chunk</b></td>
<td>Number of code suggestions provided by the 'improve' tool, per chunk. Default is 5.</td> <td>Number of code suggestions provided by the 'improve' tool, per chunk. Default is 4.</td>
</tr>
<tr>
<td><b>max_number_of_calls</b></td>
<td>Maximum number of chunks. Default is 3.</td>
</tr> </tr>
<tr> <tr>
<td><b>rank_extended_suggestions</b></td> <td><b>rank_extended_suggestions</b></td>
<td>If set to true, the tool will rank the suggestions, based on importance. Default is true.</td> <td>If set to true, the tool will rank the suggestions, based on importance. Default is true.</td>
</tr> </tr>
<tr>
<td><b>max_number_of_calls</b></td>
<td>Maximum number of chunks. Default is 5.</td>
</tr>
<tr>
<td><b>final_clip_factor</b></td>
<td>Factor to remove suggestions with low confidence. Default is 0.9.</td>
</tr>
</table> </table>
## A note on code suggestions quality ## A note on code suggestions quality
- AI models for code are getting better and better (Sonnet-3.5 and GPT-4), but they are not flawless. Not all the suggestions will be perfect, and a user should not accept all of them automatically. Critical reading and judgment are required. - AI models for code are getting better and better (Sonnet-3.5 and GPT-4), but they are not flawless. Not all the suggestions will be perfect, and a user should not accept all of them automatically. Critical reading and judgment are required.
- While mistakes of the AI are rare but can happen, a real benefit from the suggestions of the `improve` (and [`review`](https://pr-agent-docs.codium.ai/tools/review/)) tool is to catch, with high probability, **mistakes or bugs done by the PR author**, when they happen. So, it's a good practice to spend the needed ~30-60 seconds to review the suggestions, even if not all of them are always relevant. - While mistakes of the AI are rare but can happen, a real benefit from the suggestions of the `improve` (and [`review`](https://qodo-merge-docs.qodo.ai/tools/review/)) tool is to catch, with high probability, **mistakes or bugs done by the PR author**, when they happen. So, it's a good practice to spend the needed ~30-60 seconds to review the suggestions, even if not all of them are always relevant.
- The hierarchical structure of the suggestions is designed to help the user to _quickly_ understand them, and to decide which ones are relevant and which are not: - The hierarchical structure of the suggestions is designed to help the user to _quickly_ understand them, and to decide which ones are relevant and which are not:
- Only if the `Category` header is relevant, the user should move to the summarized suggestion description - Only if the `Category` header is relevant, the user should move to the summarized suggestion description
- Only if the summarized suggestion description is relevant, the user should click on the collapsible, to read the full suggestion description with a code preview example. - Only if the summarized suggestion description is relevant, the user should click on the collapsible, to read the full suggestion description with a code preview example.
- In addition, we recommend to use the [`extra_instructions`](https://pr-agent-docs.codium.ai/tools/improve/#extra-instructions-and-best-practices) field to guide the model to suggestions that are more relevant to the specific needs of the project. - In addition, we recommend to use the [`extra_instructions`](https://qodo-merge-docs.qodo.ai/tools/improve/#extra-instructions-and-best-practices) field to guide the model to suggestions that are more relevant to the specific needs of the project.
- The interactive [PR chat](https://pr-agent-docs.codium.ai/chrome-extension/) also provides an easy way to get more tailored suggestions and feedback from the AI model. - The interactive [PR chat](https://qodo-merge-docs.qodo.ai/chrome-extension/) also provides an easy way to get more tailored suggestions and feedback from the AI model.

View File

@ -1,6 +1,6 @@
# Tools # Tools
Here is a list of PR-Agent tools, each with a dedicated page that explains how to use it: Here is a list of Qodo Merge tools, each with a dedicated page that explains how to use it:
| Tool | Description | | Tool | Description |
|------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------| |------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------|
@ -19,4 +19,4 @@ Here is a list of PR-Agent tools, each with a dedicated page that explains how t
| **💎 [Improve Component (`/improve_component component_name`](./improve_component.md))** | Generates code suggestions for a specific code component that changed in the PR | | **💎 [Improve Component (`/improve_component component_name`](./improve_component.md))** | Generates code suggestions for a specific code component that changed in the PR |
| **💎 [CI Feedback (`/checks ci_job`](./ci_feedback.md))** | Automatically generates feedback and analysis for a failed CI job | | **💎 [CI Feedback (`/checks ci_job`](./ci_feedback.md))** | Automatically generates feedback and analysis for a failed CI job |
Note that the tools marked with 💎 are available only for PR-Agent Pro users. Note that the tools marked with 💎 are available only for Qodo Merge Pro users.

View File

@ -8,7 +8,7 @@ The tool can be triggered automatically every time a new PR is [opened](../usage
Note that the main purpose of the `review` tool is to provide the **PR reviewer** with useful feedbacks and insights. The PR author, in contrast, may prefer to save time and focus on the output of the [improve](./improve.md) tool, which provides actionable code suggestions. Note that the main purpose of the `review` tool is to provide the **PR reviewer** with useful feedbacks and insights. The PR author, in contrast, may prefer to save time and focus on the output of the [improve](./improve.md) tool, which provides actionable code suggestions.
(Read more about the different personas in the PR process and how PR-Agent aims to assist them in our [blog](https://www.codium.ai/blog/understanding-the-challenges-and-pain-points-of-the-pull-request-cycle/)) (Read more about the different personas in the PR process and how Qodo Merge aims to assist them in our [blog](https://www.codium.ai/blog/understanding-the-challenges-and-pain-points-of-the-pull-request-cycle/))
## Example usage ## Example usage
@ -30,7 +30,7 @@ If you want to edit [configurations](#configuration-options), add the relevant o
### Automatic triggering ### Automatic triggering
To run the `review` automatically when a PR is opened, define in a [configuration file](https://pr-agent-docs.codium.ai/usage-guide/configuration_options/#wiki-configuration-file): To run the `review` automatically when a PR is opened, define in a [configuration file](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/#wiki-configuration-file):
``` ```
[github_app] [github_app]
pr_commands = [ pr_commands = [
@ -49,7 +49,7 @@ num_code_suggestions = ...
[//]: # () [//]: # ()
[//]: # (### Incremental Mode) [//]: # (### Incremental Mode)
[//]: # (Incremental review only considers changes since the last PR-Agent 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.) [//]: # (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:) [//]: # (For invoking the incremental mode, the following command can be used:)
@ -198,7 +198,7 @@ If enabled, the `review` tool can approve a PR when a specific comment, `/review
On the other hand, if you find one of the enabled features to be irrelevant for your use case, disable it. No default configuration can fit all use cases. On the other hand, if you find one of the enabled features to be irrelevant for your use case, disable it. No default configuration can fit all use cases.
!!! tip "Automation" !!! tip "Automation"
When you first install PR-Agent 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: 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 --pr_reviewer.num_code_suggestions=0", ...]
``` ```
@ -237,7 +237,7 @@ If enabled, the `review` tool can approve a PR when a specific comment, `/review
!!! tip "Auto-approval" !!! tip "Auto-approval"
PR-Agent can approve a PR when a specific comment is invoked. Qodo Merge can approve a PR when a specific comment is invoked.
To ensure safety, the auto-approval feature is disabled by default. To enable auto-approval, you need to actively set in a pre-defined configuration file the following: To ensure safety, the auto-approval feature is disabled by default. To enable auto-approval, you need to actively set in a pre-defined configuration file the following:
``` ```
@ -251,7 +251,7 @@ If enabled, the `review` tool can approve a PR when a specific comment, `/review
``` ```
/review auto_approve /review auto_approve
``` ```
PR-Agent will automatically approve the PR, and add a comment with the approval. Qodo Merge will automatically approve the PR, and add a comment with the approval.
You can also enable auto-approval only if the PR meets certain requirements, such as that the `estimated_review_effort` label is equal or below a certain threshold, by adjusting the flag: You can also enable auto-approval only if the PR meets certain requirements, such as that the `estimated_review_effort` label is equal or below a certain threshold, by adjusting the flag:

View File

@ -8,9 +8,9 @@ For example:
![similar code global](https://codium.ai/images/pr_agent/similar_code_global2.png){width=768} ![similar code global](https://codium.ai/images/pr_agent/similar_code_global2.png){width=768}
PR-Agent will examine the code component and will extract the most relevant keywords to search for similar code: Qodo Merge will examine the code component and will extract the most relevant keywords to search for similar code:
- `extracted keywords`: the keywords that were extracted from the code by PR-Agent. the link will open a search page with the extracted keywords, to allow the user to modify the search if needed. - `extracted keywords`: the keywords that were extracted from the code by Qodo Merge. the link will open a search page with the extracted keywords, to allow the user to modify the search if needed.
- `search context`: the context in which the search will be performed, organization's codebase or open-source code (Global). - `search context`: the context in which the search will be performed, organization's codebase or open-source code (Global).
- `similar code`: the most similar code components found. the link will open the code component in the relevant file. - `similar code`: the most similar code components found. the link will open the code component in the relevant file.
- `relevant repositories`: the open-source repositories in which that are relevant to the searched code component and it's keywords. - `relevant repositories`: the open-source repositories in which that are relevant to the searched code component and it's keywords.

View File

@ -1,30 +1,18 @@
## PR-Agent Pro Models ## Qodo Merge Pro Models
The default models used by PR-Agent Pro are OpenAI's GPT-4 models. We use a combination of GPT-4-Turbo and GPT-4o to strike a balance between speed and quality. The default models used by Qodo Merge Pro are a combination of Claude-3.5-sonnet and OpenAI's GPT-4 models.
However, users can change the model used by PR-Agent Pro to Claude-3.5-sonnet, which also excels at code tasks. Users can configure Qodo Merge Pro to use solely a specific model by editing the [configuration](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/) file.
To do so, add the following to your [configuration](https://pr-agent-docs.codium.ai/usage-guide/configuration_options/) file:
For example, to restrict Qodo Merge Pro to using only `Claude-3.5-sonnet`, add this setting:
``` ```
[config] [config]
model="claude-3-5-sonnet" model="claude-3-5-sonnet"
``` ```
Note that Claude models tend to give lower scores for each suggestion, so if you are using a [threshold](https://pr-agent-docs.codium.ai/tools/improve/#configuration-options): Or to restrict Qodo Merge Pro to using only `GPT-4o`, add this setting:
``` ```
[pr_code_suggestions] [config]
suggestions_score_threshold=... model="gpt-4o"
```
You might need to adjust this value when switching models.
### Dedicated models per tool
You can also use different models for different tools. For example, you can use the Claude-3.5-sonnet model only for the `improve` tool (and keep the default GPT-4 model for the other tools) by adding the following to your configuration file:
```
[github_app]
pr_commands = [
"/describe --pr_description.final_update_message=false",
"/review --pr_reviewer.num_code_suggestions=0",
"/improve --config.model=claude-3-5-sonnet",
]
``` ```

View File

@ -1,6 +1,6 @@
## Show possible configurations ## Show possible configurations
The possible configurations of pr-agent are stored in [here](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml). The possible configurations of Qodo Merge are stored in [here](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml).
In the [tools](https://pr-agent-docs.codium.ai/tools/) page you can find explanations on how to use these configurations for each tool. In the [tools](https://qodo-merge-docs.qodo.ai/tools/) page you can find explanations on how to use these configurations for each tool.
To print all the available configurations as a comment on your PR, you can use the following command: To print all the available configurations as a comment on your PR, you can use the following command:
``` ```
@ -22,7 +22,7 @@ Will output an additional field showing the actual configurations used for the `
## Ignoring files from analysis ## Ignoring files from analysis
In some cases, you may want to exclude specific files or directories from the analysis performed by CodiumAI PR-Agent. This can be useful, for example, when you have files that are generated automatically or files that shouldn't be reviewed, like vendor code. In some cases, you may want to exclude specific files or directories from the analysis performed by Qodo Merge. This can be useful, for example, when you have files that are generated automatically or files that shouldn't be reviewed, like vendor code.
You can ignore files or folders using the following methods: You can ignore files or folders using the following methods:
- `IGNORE.GLOB` - `IGNORE.GLOB`
@ -52,7 +52,7 @@ regex = ['.*\.py$']
## Extra instructions ## Extra instructions
All PR-Agent tools have a parameter called `extra_instructions`, that enables to add free-text extra instructions. Example usage: All Qodo Merge tools have a parameter called `extra_instructions`, that enables to add free-text extra instructions. Example usage:
``` ```
/update_changelog --pr_update_changelog.extra_instructions="Make sure to update also the version ..." /update_changelog --pr_update_changelog.extra_instructions="Make sure to update also the version ..."
``` ```
@ -64,8 +64,8 @@ This mode provides a very good speed-quality-cost tradeoff, and can handle most
When the PR is above the token limit, it employs a [PR Compression strategy](../core-abilities/index.md). When the PR is above the token limit, it employs a [PR Compression strategy](../core-abilities/index.md).
However, for very large PRs, or in case you want to emphasize quality over speed and cost, there are two possible solutions: However, for very large PRs, or in case you want to emphasize quality over speed and cost, there are two possible solutions:
1) [Use a model](https://codium-ai.github.io/Docs-PR-Agent/usage-guide/#changing-a-model) with larger context, like GPT-32K, or claude-100K. This solution will be applicable for all the tools. 1) [Use a model](https://qodo-merge-docs.qodo.ai/usage-guide/changing_a_model/) with larger context, like GPT-32K, or claude-100K. This solution will be applicable for all the tools.
2) For the `/improve` tool, there is an ['extended' mode](https://codium-ai.github.io/Docs-PR-Agent/tools/#improve) (`/improve --extended`), 2) For the `/improve` tool, there is an ['extended' mode](https://qodo-merge-docs.qodo.ai/tools/improve/) (`/improve --extended`),
which divides the PR into chunks, and processes each chunk separately. With this mode, regardless of the model, no compression will be done (but for large PRs, multiple model calls may occur) which divides the PR into chunks, and processes each chunk separately. With this mode, regardless of the model, no compression will be done (but for large PRs, multiple model calls may occur)
@ -85,7 +85,7 @@ By default, around any change in your PR, git patch provides three lines of cont
code line that already existed in the file... code line that already existed in the file...
``` ```
PR-Agent will try to increase the number of lines of context, via the parameter: Qodo Merge will try to increase the number of lines of context, via the parameter:
``` ```
[config] [config]
patch_extra_lines_before=3 patch_extra_lines_before=3
@ -94,12 +94,12 @@ patch_extra_lines_after=1
Increasing this number provides more context to the model, but will also increase the token budget, and may overwhelm the model with too much information, unrelated to the actual PR code changes. Increasing this number provides more context to the model, but will also increase the token budget, and may overwhelm the model with too much information, unrelated to the actual PR code changes.
If the PR is too large (see [PR Compression strategy](https://github.com/Codium-ai/pr-agent/blob/main/PR_COMPRESSION.md)), PR-Agent may automatically set this number to 0, and will use the original git patch. If the PR is too large (see [PR Compression strategy](https://github.com/Codium-ai/pr-agent/blob/main/PR_COMPRESSION.md)), Qodo Merge may automatically set this number to 0, and will use the original git patch.
## Editing the prompts ## Editing the prompts
The prompts for the various PR-Agent tools are defined in the `pr_agent/settings` folder. The prompts for the various Qodo Merge tools are defined in the `pr_agent/settings` folder.
In practice, the prompts are loaded and stored as a standard setting object. In practice, the prompts are loaded and stored as a standard setting object.
Hence, editing them is similar to editing any other configuration value - just place the relevant key in `.pr_agent.toml`file, and override the default value. Hence, editing them is similar to editing any other configuration value - just place the relevant key in `.pr_agent.toml`file, and override the default value.
@ -138,7 +138,7 @@ LANGSMITH_BASE_URL=<url>
## Ignoring automatic commands in PRs ## Ignoring automatic commands in PRs
In some cases, you may want to automatically ignore specific PRs . PR-Agent enables you to ignore PR with a specific title, or from/to specific branches (regex matching). In some cases, you may want to automatically ignore specific PRs . Qodo Merge enables you to ignore PR with a specific title, or from/to specific branches (regex matching).
To ignore PRs with a specific title such as "[Bump]: ...", you can add the following to your `configuration.toml` file: To ignore PRs with a specific title such as "[Bump]: ...", you can add the following to your `configuration.toml` file:

View File

@ -1,5 +1,5 @@
## Local repo (CLI) ## Local repo (CLI)
When running from your locally cloned PR-Agent repo (CLI), your local configuration file will be used. When running from your locally cloned Qodo Merge repo (CLI), your local configuration file will be used.
Examples of invoking the different tools via the CLI: Examples of invoking the different tools via the CLI:
- **Review**: `python -m pr_agent.cli --pr_url=<pr_url> review` - **Review**: `python -m pr_agent.cli --pr_url=<pr_url> review`
@ -28,7 +28,7 @@ This is useful for debugging or experimenting with different tools.
(3) (3)
**git provider**: The [git_provider](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml#L5) field in a configuration file determines the GIT provider that will be used by PR-Agent. Currently, the following providers are supported: **git provider**: The [git_provider](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml#L5) field in a configuration file determines the GIT provider that will be used by Qodo Merge. Currently, the following providers are supported:
` `
"github", "gitlab", "bitbucket", "azure", "codecommit", "local", "gerrit" "github", "gitlab", "bitbucket", "azure", "codecommit", "local", "gerrit"
` `
@ -39,7 +39,7 @@ Default is "github".
### Online usage ### Online usage
Online usage means invoking PR-Agent tools by [comments](https://github.com/Codium-ai/pr-agent/pull/229#issuecomment-1695021901) on a PR. Online usage means invoking Qodo Merge tools by [comments](https://github.com/Codium-ai/pr-agent/pull/229#issuecomment-1695021901) on a PR.
Commands for invoking the different tools via comments: Commands for invoking the different tools via comments:
- **Review**: `/review` - **Review**: `/review`
@ -60,8 +60,8 @@ Any configuration value in [configuration file](https://github.com/Codium-ai/pr-
## GitHub App ## GitHub App
!!! note "Configurations for PR-Agent Pro" !!! note "Configurations for Qodo Merge Pro"
PR-Agent Pro for GitHub is an App, hosted by CodiumAI. So all the instructions below are relevant also for PR-Agent Pro users. Qodo Merge Pro for GitHub is an App, hosted by CodiumAI. So all the instructions below are relevant also for Qodo Merge Pro users.
Same goes for [GitLab webhook](#gitlab-webhook) and [BitBucket App](#bitbucket-app) sections. Same goes for [GitLab webhook](#gitlab-webhook) and [BitBucket App](#bitbucket-app) sections.
### GitHub app automatic tools when a new PR is opened ### GitHub app automatic tools when a new PR is opened
@ -77,10 +77,10 @@ pr_commands = [
"/improve", "/improve",
] ]
``` ```
This means that when a new PR is opened/reopened or marked as ready for review, PR-Agent will run the `describe`, `review` and `improve` tools. 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 `review` tool, for example, the `num_code_suggestions` parameter will be set to 0.
You can override the default tool parameters by using one the three options for a [configuration file](https://codium-ai.github.io/Docs-PR-Agent/usage-guide/#configuration-options): **wiki**, **local**, or **global**. 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: For example, if your local `.pr_agent.toml` file contains:
``` ```
[pr_description] [pr_description]
@ -108,10 +108,10 @@ push_commands = [
"/review --pr_reviewer.num_code_suggestions=0 --pr_reviewer.final_update_message=false", "/review --pr_reviewer.num_code_suggestions=0 --pr_reviewer.final_update_message=false",
] ]
``` ```
This means that when new code is pushed to the PR, the PR-Agent will run the `describe` and `review` tools, with the specified parameters. 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.
## GitHub Action ## GitHub Action
`GitHub Action` is a different way to trigger PR-Agent tools, and uses a different configuration mechanism than `GitHub App`.<br> `GitHub Action` is a different way to trigger Qodo Merge tools, and uses a different configuration mechanism than `GitHub App`.<br>
You can configure settings for `GitHub Action` by adding environment variables under the env section in `.github/workflows/pr_agent.yml` file. You can configure settings for `GitHub Action` by adding environment variables under the env section in `.github/workflows/pr_agent.yml` file.
Specifically, start by setting the following environment variables: Specifically, start by setting the following environment variables:
```yaml ```yaml
@ -133,14 +133,14 @@ If not set, the default configuration is `["opened", "reopened", "ready_for_revi
Review result is output as JSON to `steps.{step-id}.outputs.review` property. Review result is output as JSON to `steps.{step-id}.outputs.review` property.
The JSON structure is equivalent to the yaml data structure defined in [pr_reviewer_prompts.toml](https://github.com/idubnori/pr-agent/blob/main/pr_agent/settings/pr_reviewer_prompts.toml). The JSON structure is equivalent to the yaml data structure defined in [pr_reviewer_prompts.toml](https://github.com/idubnori/pr-agent/blob/main/pr_agent/settings/pr_reviewer_prompts.toml).
Note that you can give additional config parameters by adding environment variables to `.github/workflows/pr_agent.yml`, or by using a `.pr_agent.toml` [configuration file](https://pr-agent-docs.codium.ai/usage-guide/configuration_options/#global-configuration-file) in the root of your repo Note that you can give additional config parameters by adding environment variables to `.github/workflows/pr_agent.yml`, or by using a `.pr_agent.toml` [configuration file](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/#global-configuration-file) in the root of your repo
For example, you can set an environment variable: `pr_description.publish_labels=false`, or add a `.pr_agent.toml` file with the following content: For example, you can set an environment variable: `pr_description.publish_labels=false`, or add a `.pr_agent.toml` file with the following content:
``` ```
[pr_description] [pr_description]
publish_labels = false publish_labels = false
``` ```
to prevent PR-Agent from publishing labels when running the `describe` tool. to prevent Qodo Merge from publishing labels when running the `describe` tool.
## GitLab Webhook ## GitLab Webhook
After setting up a GitLab webhook, to control which commands will run automatically when a new MR is opened, you can set the `pr_commands` parameter in the configuration file, similar to the GitHub App: After setting up a GitLab webhook, to control which commands will run automatically when a new MR is opened, you can set the `pr_commands` parameter in the configuration file, similar to the GitHub App:
@ -168,22 +168,22 @@ push_commands = [
Note that to use the 'handle_push_trigger' feature, you need to give the gitlab webhook also the "Push events" scope. Note that to use the 'handle_push_trigger' feature, you need to give the gitlab webhook also the "Push events" scope.
## BitBucket App ## BitBucket App
Similar to GitHub app, when running PR-Agent from BitBucket App, the default [configuration file](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml) from a pre-built docker will be initially loaded. Similar to GitHub app, when running Qodo Merge from BitBucket App, the default [configuration file](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml) from a pre-built docker will be initially loaded.
By uploading a local `.pr_agent.toml` file to the root of the repo's main branch, you can edit and customize any configuration parameter. Note that you need to upload `.pr_agent.toml` prior to creating a PR, in order for the configuration to take effect. By uploading a local `.pr_agent.toml` file to the root of the repo's main branch, you can edit and customize any configuration parameter. Note that you need to upload `.pr_agent.toml` prior to creating a PR, in order for the configuration to take effect.
For example, if your local `.pr_agent.toml` file contains: For example, if your local `.pr_agent.toml` file contains:
``` ```
[pr_reviewer] [pr_reviewer]
inline_code_comments = true extra_instructions = "Answer in japanese"
``` ```
Each time you invoke a `/review` tool, it will use inline code comments. Each time you invoke a `/review` tool, it will use the extra instructions you set in the local configuration file.
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. 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 PR-Agent, you might want to set: `bitbucket_app.avoid_full_files=true` in your configuration file. If you experience lack of responses from Qodo Merge, you might want to set: `bitbucket_app.avoid_full_files=true` in your configuration file.
This will prevent PR-Agent 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. 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.
### BitBucket Self-Hosted App automatic tools ### BitBucket Self-Hosted App automatic tools

View File

@ -1,7 +1,7 @@
The different tools and sub-tools used by CodiumAI PR-Agent are adjustable via the **[configuration file](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml)**. The different tools and sub-tools used by Qodo Merge are adjustable via the **[configuration file](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml)**.
In addition to general configuration options, each tool has its own configurations. For example, the `review` tool will use parameters from the [pr_reviewer](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml#L16) section in the configuration file. In addition to general configuration options, each tool has its own configurations. For example, the `review` tool will use parameters from the [pr_reviewer](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml#L16) section in the configuration file.
See the [Tools Guide](https://codium-ai.github.io/Docs-PR-Agent/tools/) for a detailed description of the different tools and their configurations. See the [Tools Guide](https://qodo-merge-docs.qodo.ai/tools/) for a detailed description of the different tools and their configurations.
There are three ways to set persistent configurations: There are three ways to set persistent configurations:
@ -20,7 +20,7 @@ In terms of precedence, wiki configurations will override local configurations,
`Platforms supported: GitHub, GitLab` `Platforms supported: GitHub, GitLab`
With PR-Agent-Pro, you can set configurations by creating a page called `.pr_agent.toml` in the [wiki](https://github.com/Codium-ai/pr-agent/wiki/pr_agent.toml) of the repo. With Qodo Merge Pro, you can set configurations by creating a page called `.pr_agent.toml` in the [wiki](https://github.com/Codium-ai/pr-agent/wiki/pr_agent.toml) of the repo.
The advantage of this method is that it allows to set configurations without needing to commit new content to the repo - just edit the wiki page and **save**. The advantage of this method is that it allows to set configurations without needing to commit new content to the repo - just edit the wiki page and **save**.
@ -34,7 +34,7 @@ An example content:
generate_ai_title=true generate_ai_title=true
``` ```
PR-Agent will know to remove the surrounding quotes when reading the configuration content. Qodo Merge will know to remove the surrounding quotes when reading the configuration content.
## Local configuration file ## Local configuration file

View File

@ -1,7 +1,7 @@
# Usage guide # Usage guide
This page provides a detailed guide on how to use PR-Agent. This page provides a detailed guide on how to use Qodo Merge.
It includes information on how to adjust PR-Agent configurations, define which tools will run automatically, and other advanced configurations. It includes information on how to adjust Qodo Merge configurations, define which tools will run automatically, and other advanced configurations.
- [Introduction](./introduction.md) - [Introduction](./introduction.md)
@ -23,4 +23,4 @@ It includes information on how to adjust PR-Agent configurations, define which t
- [Changing a model](./additional_configurations.md#changing-a-model) - [Changing a model](./additional_configurations.md#changing-a-model)
- [Patch Extra Lines](./additional_configurations.md#patch-extra-lines) - [Patch Extra Lines](./additional_configurations.md#patch-extra-lines)
- [Editing the prompts](./additional_configurations.md#editing-the-prompts) - [Editing the prompts](./additional_configurations.md#editing-the-prompts)
- [PR-Agent Pro Models](./PR_agent_pro_models.md) - [Qodo Merge Pro Models](./PR_agent_pro_models.md)

View File

@ -1,13 +1,13 @@
After [installation](https://pr-agent-docs.codium.ai/installation/), there are three basic ways to invoke CodiumAI PR-Agent: After [installation](https://qodo-merge-docs.qodo.ai/installation/), there are three basic ways to invoke Qodo Merge:
1. Locally running a CLI command 1. Locally running a CLI command
2. Online usage - by [commenting](https://github.com/Codium-ai/pr-agent/pull/229#issuecomment-1695021901) on a PR 2. Online usage - by [commenting](https://github.com/Codium-ai/pr-agent/pull/229#issuecomment-1695021901) on a PR
3. Enabling PR-Agent tools to run automatically when a new PR is opened 3. Enabling Qodo Merge tools to run automatically when a new PR is opened
Specifically, CLI commands can be issued by invoking a pre-built [docker image](https://pr-agent-docs.codium.ai/installation/locally/#using-docker-image), or by invoking a [locally cloned repo](https://pr-agent-docs.codium.ai/installation/locally/#run-from-source). Specifically, CLI commands can be issued by invoking a pre-built [docker image](https://qodo-merge-docs.qodo.ai/installation/locally/#using-docker-image), or by invoking a [locally cloned repo](https://qodo-merge-docs.qodo.ai/installation/locally/#run-from-source).
For online usage, you will need to setup either a [GitHub App](https://pr-agent-docs.codium.ai/installation/github/#run-as-a-github-app) or a [GitHub Action](https://pr-agent-docs.codium.ai/installation/github/#run-as-a-github-action) (GitHub), a [GitLab webhook](https://pr-agent-docs.codium.ai/installation/gitlab/#run-a-gitlab-webhook-server) (GitLab), or a [BitBucket App](https://pr-agent-docs.codium.ai/installation/bitbucket/#run-using-codiumai-hosted-bitbucket-app) (BitBucket). For online usage, you will need to setup either a [GitHub App](https://qodo-merge-docs.qodo.ai/installation/github/#run-as-a-github-app) or a [GitHub Action](https://qodo-merge-docs.qodo.ai/installation/github/#run-as-a-github-action) (GitHub), a [GitLab webhook](https://qodo-merge-docs.qodo.ai/installation/gitlab/#run-a-gitlab-webhook-server) (GitLab), or a [BitBucket App](https://qodo-merge-docs.qodo.ai/installation/bitbucket/#run-using-codiumai-hosted-bitbucket-app) (BitBucket).
These platforms also enable to run PR-Agent specific tools automatically when a new PR is opened, or on each push to a branch. These platforms also enable to run Qodo Merge specific tools automatically when a new PR is opened, or on each push to a branch.

View File

@ -1,15 +1,15 @@
Unfortunately, it is not possible in GitHub to disable mail notifications from a specific user. Unfortunately, it is not possible in GitHub to disable mail notifications from a specific user.
If you are subscribed to notifications for a repo with PR-Agent, we recommend turning off notifications for PR comments, to avoid lengthy emails: If you are subscribed to notifications for a repo with Qodo Merge, we recommend turning off notifications for PR comments, to avoid lengthy emails:
![notifications](https://codium.ai/images/pr_agent/notifications.png){width=512} ![notifications](https://codium.ai/images/pr_agent/notifications.png){width=512}
As an alternative, you can filter in your mail provider the notifications specifically from the PR-Agent bot, [see how](https://www.quora.com/How-can-you-filter-emails-for-specific-people-in-Gmail#:~:text=On%20the%20Filters%20and%20Blocked,the%20body%20of%20the%20email). As an alternative, you can filter in your mail provider the notifications specifically from the Qodo Merge bot, [see how](https://www.quora.com/How-can-you-filter-emails-for-specific-people-in-Gmail#:~:text=On%20the%20Filters%20and%20Blocked,the%20body%20of%20the%20email).
![filter_mail_notifications](https://codium.ai/images/pr_agent/filter_mail_notifications.png){width=512} ![filter_mail_notifications](https://codium.ai/images/pr_agent/filter_mail_notifications.png){width=512}
Another option to reduce the mail overload, yet still receive notifications on PR-Agent tools, is to disable the help collapsible section in PR-Agent bot comments. Another option to reduce the mail overload, yet still receive notifications on Qodo Merge tools, is to disable the help collapsible section in Qodo Merge bot comments.
This can done by setting `enable_help_text=false` for the relevant tool in the configuration file. This can done by setting `enable_help_text=false` for the relevant tool in the configuration file.
For example, to disable the help text for the `pr_reviewer` tool, set: For example, to disable the help text for the `pr_reviewer` tool, set:
``` ```

View File

@ -1,11 +1,11 @@
site_name: PR-Agent Documentation site_name: Qodo Merge (formerly known as PR-Agent)
repo_url: https://github.com/Codium-ai/pr-agent repo_url: https://github.com/Codium-ai/pr-agent
repo_name: Codium-ai/pr-agent repo_name: Codium-ai/pr-agent
nav: nav:
- Overview: - Overview:
- 'index.md' - 'index.md'
- 💎 PR-Agent Pro: 'overview/pr_agent_pro.md' - 💎 Qodo Merge Pro: 'overview/pr_agent_pro.md'
- Data Privacy: 'overview/data_privacy.md' - Data Privacy: 'overview/data_privacy.md'
- Installation: - Installation:
- 'installation/index.md' - 'installation/index.md'
@ -14,7 +14,7 @@ nav:
- GitLab: 'installation/gitlab.md' - GitLab: 'installation/gitlab.md'
- BitBucket: 'installation/bitbucket.md' - BitBucket: 'installation/bitbucket.md'
- Azure DevOps: 'installation/azure.md' - Azure DevOps: 'installation/azure.md'
- 💎 PR-Agent Pro: 'installation/pr_agent_pro.md' - 💎 Qodo Merge Pro: 'installation/pr_agent_pro.md'
- Usage Guide: - Usage Guide:
- 'usage-guide/index.md' - 'usage-guide/index.md'
- Introduction: 'usage-guide/introduction.md' - Introduction: 'usage-guide/introduction.md'
@ -23,7 +23,7 @@ nav:
- Managing Mail Notifications: 'usage-guide/mail_notifications.md' - Managing Mail Notifications: 'usage-guide/mail_notifications.md'
- Changing a Model: 'usage-guide/changing_a_model.md' - Changing a Model: 'usage-guide/changing_a_model.md'
- Additional Configurations: 'usage-guide/additional_configurations.md' - Additional Configurations: 'usage-guide/additional_configurations.md'
- 💎 PR-Agent Pro Models: 'usage-guide/PR_agent_pro_models' - 💎 Qodo Merge Pro Models: 'usage-guide/PR_agent_pro_models'
- Tools: - Tools:
- 'tools/index.md' - 'tools/index.md'
- Describe: 'tools/describe.md' - Describe: 'tools/describe.md'
@ -53,7 +53,7 @@ nav:
- Static code analysis: 'core-abilities/static_code_analysis.md' - Static code analysis: 'core-abilities/static_code_analysis.md'
- Code Fine-tuning Benchmark: 'finetuning_benchmark/index.md' - Code Fine-tuning Benchmark: 'finetuning_benchmark/index.md'
- Chrome Extension: - Chrome Extension:
- PR-Agent Chrome Extension: 'chrome-extension/index.md' - Qodo Merge Chrome Extension: 'chrome-extension/index.md'
- Features: 'chrome-extension/features.md' - Features: 'chrome-extension/features.md'
- Data Privacy: 'chrome-extension/data_privacy.md' - Data Privacy: 'chrome-extension/data_privacy.md'
- FAQ: - FAQ:

View File

@ -101,11 +101,11 @@ def process_patch_lines(patch_str, original_file_str, patch_extra_lines_before,
# Update start and size in one line each # Update start and size in one line each
extended_start1, extended_start2 = extended_start1 + i, extended_start2 + i extended_start1, extended_start2 = extended_start1 + i, extended_start2 + i
extended_size1, extended_size2 = extended_size1 - i, extended_size2 - i extended_size1, extended_size2 = extended_size1 - i, extended_size2 - i
get_logger().debug(f"Found section header in line {i} before the hunk") # get_logger().debug(f"Found section header in line {i} before the hunk")
section_header = '' section_header = ''
break break
if not found_header: if not found_header:
get_logger().debug(f"Section header not found in the extra lines before the hunk") # get_logger().debug(f"Section header not found in the extra lines before the hunk")
extended_start1, extended_size1, extended_start2, extended_size2 = \ extended_start1, extended_size1, extended_start2, extended_size2 = \
_calc_context_limits(patch_extra_lines_before) _calc_context_limits(patch_extra_lines_before)
else: else:

View File

@ -100,8 +100,8 @@ def convert_to_markdown_v2(output_data: dict,
emojis = { emojis = {
"Can be split": "🔀", "Can be split": "🔀",
"Possible issues": "",
"Key issues to review": "", "Key issues to review": "",
"Recommended focus areas for review": "",
"Score": "🏅", "Score": "🏅",
"Relevant tests": "🧪", "Relevant tests": "🧪",
"Focused PR": "", "Focused PR": "",
@ -120,6 +120,9 @@ def convert_to_markdown_v2(output_data: dict,
if not output_data or not output_data.get('review', {}): if not output_data or not output_data.get('review', {}):
return "" return ""
if get_settings().get("pr_reviewer.enable_intro_text", False):
markdown_text += f"Here are some key observations to aid the review process:\n\n"
if gfm_supported: if gfm_supported:
markdown_text += "<table>\n" markdown_text += "<table>\n"
@ -189,23 +192,21 @@ def convert_to_markdown_v2(output_data: dict,
if is_value_no(value): if is_value_no(value):
if gfm_supported: if gfm_supported:
markdown_text += f"<tr><td>" markdown_text += f"<tr><td>"
markdown_text += f"{emoji}&nbsp;<strong>No key issues to review</strong>" markdown_text += f"{emoji}&nbsp;<strong>No major issues detected</strong>"
markdown_text += f"</td></tr>\n" markdown_text += f"</td></tr>\n"
else: else:
markdown_text += f"### {emoji} No key issues to review\n\n" markdown_text += f"### {emoji} No major issues detected\n\n"
else: else:
# issues = value.split('\n- ') issues = value
issues =value
# for i, _ in enumerate(issues):
# issues[i] = issues[i].strip().strip('-').strip()
if gfm_supported: if gfm_supported:
markdown_text += f"<tr><td>" markdown_text += f"<tr><td>"
markdown_text += f"{emoji}&nbsp;<strong>{key_nice}</strong><br><br>\n\n" # markdown_text += f"{emoji}&nbsp;<strong>{key_nice}</strong><br><br>\n\n"
markdown_text += f"{emoji}&nbsp;<strong>Recommended focus areas for review</strong><br><br>\n\n"
else: else:
markdown_text += f"### {emoji} Key issues to review\n\n#### \n" markdown_text += f"### {emoji} Recommended focus areas for review\n\n#### \n"
for i, issue in enumerate(issues): for i, issue in enumerate(issues):
try: try:
if not issue: if not issue or not isinstance(issue, dict):
continue continue
relevant_file = issue.get('relevant_file', '').strip() relevant_file = issue.get('relevant_file', '').strip()
issue_header = issue.get('issue_header', '').strip() issue_header = issue.get('issue_header', '').strip()
@ -220,7 +221,7 @@ def convert_to_markdown_v2(output_data: dict,
issue_str = f"[**{issue_header}**]({reference_link})\n\n{issue_content}\n\n" issue_str = f"[**{issue_header}**]({reference_link})\n\n{issue_content}\n\n"
markdown_text += f"{issue_str}\n\n" markdown_text += f"{issue_str}\n\n"
except Exception as e: except Exception as e:
get_logger().exception(f"Failed to process key issues to review: {e}") get_logger().exception(f"Failed to process 'Recommended focus areas for review': {e}")
if gfm_supported: if gfm_supported:
markdown_text += f"</td></tr>\n" markdown_text += f"</td></tr>\n"
else: else:

View File

@ -27,8 +27,9 @@ global_settings = Dynaconf(
"settings/pr_update_changelog_prompts.toml", "settings/pr_update_changelog_prompts.toml",
"settings/pr_custom_labels.toml", "settings/pr_custom_labels.toml",
"settings/pr_add_docs.toml", "settings/pr_add_docs.toml",
"settings/custom_labels.toml",
"settings/pr_help_prompts.toml",
"settings_prod/.secrets.toml", "settings_prod/.secrets.toml",
"settings/custom_labels.toml"
]] ]]
) )

View File

@ -80,7 +80,7 @@ async def run_action():
except Exception as e: except Exception as e:
get_logger().info(f"github action: failed to apply repo settings: {e}") get_logger().info(f"github action: failed to apply repo settings: {e}")
# Handle pull request event # Handle pull request opened event
if GITHUB_EVENT_NAME == "pull_request": if GITHUB_EVENT_NAME == "pull_request":
action = event_payload.get("action") action = event_payload.get("action")
@ -101,9 +101,13 @@ async def run_action():
if auto_improve is None: if auto_improve is None:
auto_improve = get_setting_or_env("GITHUB_ACTION_CONFIG.AUTO_IMPROVE", None) auto_improve = get_setting_or_env("GITHUB_ACTION_CONFIG.AUTO_IMPROVE", None)
# Set the configuration for auto actions
get_settings().config.is_auto_command = True # Set the flag to indicate that the command is auto
get_settings().pr_description.final_update_message = False # No final update message when auto_describe is enabled
get_logger().info(f"Running auto actions: auto_describe={auto_describe}, auto_review={auto_review}, auto_improve={auto_improve}")
# invoke by default all three tools # invoke by default all three tools
if auto_describe is None or is_true(auto_describe): if auto_describe is None or is_true(auto_describe):
get_settings().pr_description.final_update_message = False # No final update message when auto_describe is enabled
await PRDescription(pr_url).run() await PRDescription(pr_url).run()
if auto_review is None or is_true(auto_review): if auto_review is None or is_true(auto_review):
await PRReviewer(pr_url).run() await PRReviewer(pr_url).run()

View File

@ -69,6 +69,7 @@ enable_review_labels_effort=true
require_all_thresholds_for_incremental_review=false require_all_thresholds_for_incremental_review=false
minimal_commits_for_incremental_review=0 minimal_commits_for_incremental_review=0
minimal_minutes_for_incremental_review=0 minimal_minutes_for_incremental_review=0
enable_intro_text=true
enable_help_text=false # Determines whether to include help text in the PR review. Enabled by default. enable_help_text=false # Determines whether to include help text in the PR review. Enabled by default.
# auto approval # auto approval
enable_auto_approval=false enable_auto_approval=false
@ -108,18 +109,22 @@ enable_help_text=false
[pr_code_suggestions] # /improve # [pr_code_suggestions] # /improve #
max_context_tokens=14000 max_context_tokens=14000
num_code_suggestions=4 #
commitable_code_suggestions = false 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
#
extra_instructions = "" extra_instructions = ""
rank_suggestions = false rank_suggestions = false
enable_help_text=false enable_help_text=false
enable_chat_text=false
enable_intro_text=true
persistent_comment=true persistent_comment=true
max_history_len=4 max_history_len=4
# enable to apply suggestion 💎 # enable to apply suggestion 💎
apply_suggestions_checkbox=true apply_suggestions_checkbox=true
# suggestions scoring # suggestions scoring
self_reflect_on_suggestions=true self_reflect_on_suggestions=true
suggestions_score_threshold=0 # [0-10]. highly recommend not to set this value above 8, since above it may clip highly relevant suggestions 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 # params for '/improve --extended' mode
auto_extended_mode=true auto_extended_mode=true
num_code_suggestions_per_chunk=4 num_code_suggestions_per_chunk=4
@ -183,6 +188,8 @@ enable_help_text=true
final_update_message = false final_update_message = false
[pr_help] # /help # [pr_help] # /help #
force_local_db=false
num_retrieved_snippets=5
[pr_config] # /config # [pr_config] # /config #

View File

@ -1,9 +1,9 @@
[pr_code_suggestions_prompt] [pr_code_suggestions_prompt]
system="""You are PR-Reviewer, a language model that specializes in suggesting improvements to a Pull Request (PR) code. system="""You are PR-Reviewer, an AI specializing in Pull Request (PR) code analysis and suggestions.
Your task is to provide meaningful and actionable code suggestions, to improve the new code presented in a PR code diff (lines starting with '+'). 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.
The format we will use to present the PR code diff: The PR code diff will be in the following structured format:
====== ======
## File: 'src/file1.py' ## File: 'src/file1.py'
{%- if is_ai_metadata %} {%- if is_ai_metadata %}
@ -35,28 +35,27 @@ __old hunk__
... ...
====== ======
- In this format, we separate each hunk of diff code to '__new hunk__' and '__old hunk__' sections. The '__new hunk__' section contains the new code of the chunk, and the '__old hunk__' section contains the old code, that was removed. If no new code was added in a specific hunk, '__new hunk__' section will not be presented. If no code was removed, '__old hunk__' section will not be presented. - 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 added or removed in a specific chunk, the corresponding section will be omitted.
- We also added line numbers for the '__new hunk__' code, to help you refer to the code lines in your suggestions. These line numbers are not part of the actual code, and should only used for reference. - 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 ('+', '-', ' '). The '+' symbol indicates new code added in the PR, the '-' symbol indicates code removed in the PR, and the ' ' symbol indicates unchanged 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 %} {%- if is_ai_metadata %}
- If available, an AI-generated summary will appear and provide a high-level overview of the file changes. Note that this summary may not be fully accurate or complete. - 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.
{%- endif %} {%- endif %}
Specific instructions for generating code suggestions:
- Provide up to {{ num_code_suggestions }} code suggestions. Specific guidelines for generating code suggestions:
- The suggestions should be diverse and insightful. They should focus on improving only the new code introduced in the PR, meaning lines from '__new hunk__' sections, starting with '+' (after the line numbers). - Provide up to {{ num_code_suggestions }} distinct and insightful code suggestions.
- Prioritize suggestions that address possible issues, major problems, and bugs in the PR code. Don't repeat changes already present in the PR. If there are no relevant suggestions for the PR, return an empty list. - Focus solely on enhancing new code introduced in the PR, identified by '+' prefixes in '__new hunk__' sections (after the line numbers).
- Don't suggest to add docstring, type hints, or comments, or to remove unused imports. - 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.
- Suggestions should not repeat code already present in the '__new hunk__' sections. - Avoid proposing additions of docstrings, type hints, or comments, or the removal of unused imports.
- Provide the exact line numbers range (inclusive) for each suggestion. Use the line numbers from the '__new hunk__' sections. - When referencing variables or names from the code, enclose them in backticks (`). Example: "ensure that `variable_name` is..."
- Every time you cite variables or names from the code, use backticks ('`'). For 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 on variables not declared in the visible scope, as the context is incomplete.
- Take into account that you are reviewing a PR code diff, and that the entire codebase is not available for you as context. Hence, avoid suggestions that might conflict with unseen parts of the codebase.
{%- if extra_instructions %} {%- if extra_instructions %}
Extra instructions from the user, that should be taken into account with high priority: Extra user-provided instructions (should be addressed with high priority):
====== ======
{{ extra_instructions }} {{ extra_instructions }}
====== ======
@ -66,15 +65,16 @@ Extra instructions from the user, that should be taken into account with high pr
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): class CodeSuggestion(BaseModel):
relevant_file: str = Field(description="The full file path of the relevant file") relevant_file: str = Field(description="Full path of the relevant file")
language: str = Field(description="The programming language of the relevant file") language: str = Field(description="Programming language used by the relevant file")
suggestion_content: str = Field(description="an actionable suggestion for meaningfully improving the new code introduced in the PR") 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, demonstrating the relevant code lines from a '__new hunk__' section. It must be without line numbers. Quote only full code lines, not partial ones. Use abbreviations ("...") of full lines if needed") 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.")
improved_code: str = Field(description="a new code snippet, that can be used to replace the relevant 'existing_code' lines in '__new hunk__' code after applying the suggestion") 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 short summary of the suggestion action, in a single sentence. Focus on the 'what'. Be general, and avoid method or variable names.") 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 'existing code' snippet above") 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 '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 label for the suggestion, to help the user understand the suggestion type. For example: 'security', 'possible bug', 'possible issue', 'performance', 'enhancement', 'best practice', 'maintainability', etc. Other labels are also allowed") 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.")
class PRCodeSuggestions(BaseModel): class PRCodeSuggestions(BaseModel):
code_suggestions: List[CodeSuggestion] code_suggestions: List[CodeSuggestion]
@ -120,112 +120,3 @@ The PR Diff:
Response (should be a valid YAML, and nothing else): Response (should be a valid YAML, and nothing else):
```yaml ```yaml
""" """
[pr_code_suggestions_prompt_claude]
system="""You are PR-Reviewer, a language model that specializes in suggesting improvements to a Pull Request (PR) code.
Your task is to provide meaningful and actionable code suggestions, to improve the new code presented in a PR code diff (lines starting with '+').
The format we will use to present the PR code diff:
======
## File: 'src/file1.py'
{%- if is_ai_metadata %}
### AI-generated changes summary:
* ...
* ...
{%- endif %}
@@ ... @@ 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
__old hunk__
unchanged code line0
unchanged code line1
-old code line2 removed in the PR
unchanged code line3
@@ ... @@ def func2():
__new hunk__
...
__old hunk__
...
## File: 'src/file2.py'
...
======
- In this format, we separate each hunk of diff code to '__new hunk__' and '__old hunk__' sections. The '__new hunk__' section contains the new code of the chunk, and the '__old hunk__' section contains the old code, that was removed. If no new code was added in a specific hunk, '__new hunk__' section will not be presented. If no code was removed, '__old hunk__' section will not be presented.
- We also added line numbers for the '__new hunk__' code, to help you refer to the code lines in your suggestions. These line numbers are not part of the actual code, and should only used for reference.
- Code lines are prefixed with symbols ('+', '-', ' '). The '+' symbol indicates new code added in the PR, the '-' symbol indicates code removed in the PR, and the ' ' symbol indicates unchanged code. \
{%- if is_ai_metadata %}
- If available, an AI-generated summary will appear and provide a high-level overview of the file changes. Note that this summary may not be fully accurate or complete.
{%- endif %}
Specific instructions for generating code suggestions:
- Provide up to {{ num_code_suggestions }} code suggestions.
- The suggestions should be diverse and insightful. They should focus on improving only the new code introduced in the PR, meaning lines from '__new hunk__' sections, starting with '+' (after the line numbers).
- Prioritize suggestions that address possible issues, major problems, and bugs in the PR code. Don't repeat changes already present in the PR. If there are no relevant suggestions for the PR, return an empty list.
- Don't suggest to add docstring, type hints, or comments, or to remove unused imports.
- Provide the exact line numbers range (inclusive) for each suggestion. Use the line numbers from the '__new hunk__' sections.
- Every time you cite variables or names from the code, use backticks ('`'). For example: 'ensure that `variable_name` is ...'
- Take into account that you are recieving as an input only a PR code diff. The entire codebase is not available for you as context. Hence, avoid suggestions that might conflict with unseen parts of the codebase, like imports, global variables, etc.
{%- if extra_instructions %}
Extra instructions from the user, that should be taken into account with high priority:
======
{{ extra_instructions }}
======
{%- endif %}
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 full file path of the relevant file")
language: str = Field(description="the programming language of the relevant file")
suggestion_content: str = Field(description="an actionable suggestion for meaningfully improving 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, demonstrating the relevant code lines from a '__new hunk__' section. It must be without line numbers. Quote only full code lines, not partial ones. Use abbreviations ("...") of full lines if needed")
improved_code: str = Field(description="a new code snippet, that can be used to replace the relevant 'existing_code' lines in '__new hunk__' 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.")
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 '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 'existing code' snippet above")
label: str = Field(description="a single label for the suggestion, to help the user understand the suggestion type. For example: 'security', 'possible bug', 'possible issue', 'performance', 'enhancement', 'best practice', 'maintainability', etc. Other labels are also allowed")
class PRCodeSuggestions(BaseModel):
code_suggestions: List[CodeSuggestion]
=====
Example output:
```yaml
code_suggestions:
- relevant_file: |
src/file1.py
language: |
python
suggestion_content: |
...
existing_code: |
...
improved_code: |
...
one_sentence_summary: |
...
relevant_lines_start: 12
relevant_lines_end: 13
label: |
...
```
Each YAML output MUST be after a newline, indented, with block scalar indicator ('|').
"""

View File

@ -1,32 +1,55 @@
[pr_code_suggestions_reflect_prompt] [pr_code_suggestions_reflect_prompt]
system="""You are a language model that specializes in reviewing and evaluating suggestions for a Pull Request (PR) code. system="""You are an AI language model specialized in reviewing and evaluating code suggestions for a Pull Request (PR).
Your task is to analyze a PR code diff and evaluate a set of AI-generated code suggestions. These suggestions aim to address potential bugs and problems, and enhance the new code introduced in the PR.
Your input is a PR code, and a list of code suggestions that were generated for the PR. Examine each suggestion meticulously, assessing its quality, relevance, and accuracy within the context of PR. Keep in mind that the suggestions may vary in their correctness and accuracy. Your evaluation should be based on a thorough comparison between each suggestion and the actual PR code diff.
Your goal is to inspect, review and score the suggestsions. Consider the following components of each suggestion:
Be aware - the suggestions may not always be correct or accurate, and you should evaluate them in relation to the actual PR code diff presented. Sometimes the suggestion may ignore parts of the actual code diff, and in that case, you should give it a score of 0. 1. 'one_sentence_summary' - A brief summary of the suggestion's purpose
2. 'suggestion_content' - The detailed suggestion content, explaining the proposed modification
3. 'existing_code' - a code snippet from a __new hunk__ section in the PR code diff that the suggestion addresses
4. 'improved_code' - a code snippet demonstrating how the 'existing_code' should be after the suggestion is applied
Specific instructions: Be particularly vigilant for suggestions that:
- Carefully review both the suggestion content, and the related PR code diff. Mistakes in the suggestions can occur. Make sure the suggestions are logical and correct, and properly derived from the PR code diff. - Overlook crucial details in the PR
- In addition to the exact code lines mentioned in each suggestion, review the code around them, to ensure that the suggestions are contextually accurate. - The 'improved_code' section does not accurately reflect the suggested changes, in relation to the 'existing_code'
- Check that the 'existing_code' field is valid. The 'existing_code' content should match, or be derived, from code lines from a 'new hunk' section in the PR code diff. - Contradict or ignore parts of the PR's modifications
- Check that the 'improved_code' section correctly reflects the suggestion content. In such cases, assign the suggestion a score of 0.
- High scores (8 to 10) should be given to correct suggestions that address major bugs and issues, or security concerns. Lower scores (3 to 7) should be for correct suggestions addressing minor issues, code style, code readability, maintainability, etc. Don't give high scores to suggestions that are not crucial, and bring only small improvement or optimization.
- Order the feedback the same way the suggestions are ordered in the input. 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.
The format that is used to present the PR code diff is as follows: 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.
- Extend your review beyond the specifically mentioned code lines to encompass surrounding context, verifying the suggestions' contextual accuracy.
- Validate the 'existing_code' field by confirming it matches or is accurately derived from code lines within a '__new hunk__' section of the PR code diff.
- Ensure the 'improved_code' section accurately reflects the 'existing_code' segment after the suggested modification is applied.
- Apply a nuanced scoring system:
- Reserve high scores (8-10) for suggestions addressing critical issues such as major bugs or security concerns.
- Assign moderate scores (3-7) to suggestions that tackle minor issues, improve code style, enhance readability, or boost maintainability.
- Avoid inflating scores for suggestions that, while correct, offer only marginal improvements or optimizations.
- Maintain the original order of suggestions in your feedback, corresponding to their input sequence.
The PR code diff will be presented in the following structured format:
====== ======
## File: 'src/file1.py' ## File: 'src/file1.py'
{%- if is_ai_metadata %}
### AI-generated changes summary:
* ...
* ...
{%- endif %}
@@ ... @@ def func1(): @@ ... @@ def func1():
__new hunk__ __new hunk__
12 code line1 that remained unchanged in the PR 11 unchanged code line0 in the PR
12 unchanged code line1 in the PR
13 +new code line2 added in the PR 13 +new code line2 added in the PR
14 code line3 that remained unchanged in the PR 14 unchanged code line3 in the PR
__old hunk__ __old hunk__
code line1 that remained unchanged in the PR unchanged code line0
-old code line2 that was removed in the PR unchanged code line1
code line3 that remained unchanged in the PR -old code line2 removed in the PR
unchanged code line3
@@ ... @@ def func2(): @@ ... @@ def func2():
__new hunk__ __new hunk__
@ -38,19 +61,21 @@ __old hunk__
## File: 'src/file2.py' ## File: 'src/file2.py'
... ...
====== ======
- In this format, we separated each hunk of code to '__new hunk__' and '__old hunk__' sections. The '__new hunk__' section contains the new code of the chunk, and the '__old hunk__' section contains the old code that was removed. - 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 added or removed in a specific chunk, the corresponding section will be omitted.
- If no new code was added in a specific hunk, '__new hunk__' section will not be presented. If no code was removed, '__old hunk__' section will not be presented. - Line numbers are included for the '__new hunk__' sections to enable referencing specific lines in the code suggestions. These numbers are for reference only and are not part of the actual code.
- We added line numbers for the '__new hunk__' sections, to help you refer to the code lines in your suggestions. These line numbers are not part of the actual code, and are only used for reference. - Code lines are prefixed with symbols: '+' for new code added in the PR, '-' for code removed, and ' ' for unchanged code.
- Code lines are prefixed symbols ('+', '-', ' '). The '+' symbol indicates new code added in the PR, the '-' symbol indicates code removed in the PR, and the ' ' symbol indicates 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 comprehensive.
{%- endif %}
The output must be a YAML object equivalent to type $PRCodeSuggestionsFeedback, according to the following Pydantic definitions: The output must be a YAML object equivalent to type $PRCodeSuggestionsFeedback, according to the following Pydantic definitions:
===== =====
class CodeSuggestionFeedback(BaseModel): class CodeSuggestionFeedback(BaseModel):
suggestion_summary: str = Field(description="repeated from the input") suggestion_summary: str = Field(description="Repeated from the input")
relevant_file: str = Field(description="repeated from the input") relevant_file: str = Field(description="Repeated from the input")
suggestion_score: int = Field(description="The actual output - the score of the suggestion, from 0 to 10. Give 0 if the suggestion is wrong. Otherwise, give a score from 1 to 10 (inclusive), where 1 is the lowest and 10 is the highest.") 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="Short and concise explanation of why the suggestion received the score (one to two sentences).") why: str = Field(description="Briefly explain the score given in 1-2 sentences, focusing on the suggestion's impact, relevance, and accuracy.")
class PRCodeSuggestionsFeedback(BaseModel): class PRCodeSuggestionsFeedback(BaseModel):
code_suggestions: List[CodeSuggestionFeedback] code_suggestions: List[CodeSuggestionFeedback]
@ -79,7 +104,7 @@ user="""You are given a Pull Request (PR) code diff:
====== ======
And here is a list of corresponding {{ num_code_suggestions }} code suggestions to improve this Pull Request code: Below are {{ num_code_suggestions }} AI-generated code suggestions for enhancing the Pull Request:
====== ======
{{ suggestion_str|trim }} {{ suggestion_str|trim }}
====== ======

View File

@ -0,0 +1,48 @@
[pr_help_prompts]
system="""You are Doc-helper, a language models designed to answer questions about a documentation website for an open-soure project called "PR-Agent".
You will recieve a question, and a list of snippets that were collected for a documentation site using RAG as the retrieval method.
Your goal is to provide the best answer to the question using the snippets provided.
Additional instructions:
- Try to be short and concise in your answers. Give examples if needed.
- It is possible some of the snippets may not be relevant to the question. In that case, you should ignore them and focus on the ones that are relevant.
- The main tools of pr-agent are 'describe', 'review', 'improve'. If there is ambiguity to which tool the user is referring to, prioritize snippets of these tools over others.
The output must be a YAML object equivalent to type $DocHelper, according to the following Pydantic definitions:
=====
class DocHelper(BaseModel):
user_question: str = Field(description="The user's question")
response: str = Field(description="The response to the user's question")
relevant_snippets: List[int] = Field(description="One-based index of the relevant snippets in the list of snippets provided. Order the by relevance, with the most relevant first. If a snippet was not relevant, do not include it in the list.")
=====
Example output:
```yaml
user_question: |
...
response: |
...
relevant_snippets:
- 1
- 2
- 4
"""
user="""\
User's Question:
=====
{{ question|trim }}
=====
Relevant doc snippets retrieved:
=====
{{ snippets|trim }}
=====
Response (should be a valid YAML, and nothing else):
```yaml
"""

View File

@ -81,10 +81,10 @@ class SubPR(BaseModel):
class KeyIssuesComponentLink(BaseModel): class KeyIssuesComponentLink(BaseModel):
relevant_file: str = Field(description="The full file path of the relevant file") relevant_file: str = Field(description="The full file path of the relevant file")
issue_header: str = Field(description="one or two word title for the the issue. For example: 'Possible Bug', 'Performance Issue', 'Code Smell', etc.") issue_header: str = Field(description="One or two word title for the the issue. For example: 'Possible Bug', 'Performance Issue', 'Code Smell', etc.")
issue_content: str = Field(description="a short and concise description of the issue that needs to be reviewed") issue_content: str = Field(description="A short and concise summary of what should be further inspected and validated during the PR review process for this issue. Don't state line numbers here")
start_line: int = Field(description="the start line that corresponds to this issue in the relevant file") start_line: int = Field(description="The start line that corresponds to this issue in the relevant file")
end_line: int = Field(description="the end line that corresponds to this issue in the relevant file") end_line: int = Field(description="The end line that corresponds to this issue in the relevant file")
class Review(BaseModel): class Review(BaseModel):
{%- if require_estimate_effort_to_review %} {%- if require_estimate_effort_to_review %}
@ -99,7 +99,7 @@ class Review(BaseModel):
{%- if question_str %} {%- if question_str %}
insights_from_user_answers: str = Field(description="shortly summarize the insights you gained from the user's answers to the questions") insights_from_user_answers: str = Field(description="shortly summarize the insights you gained from the user's answers to the questions")
{%- endif %} {%- endif %}
key_issues_to_review: List[KeyIssuesComponentLink] = Field("A list of bugs, issue or major performance concerns introduced in this PR, which the PR reviewer should further investigate") key_issues_to_review: List[KeyIssuesComponentLink] = Field("A diverse list of bugs, issue or major performance concerns introduced in this PR, which the PR reviewer should further investigate")
{%- if require_security_review %} {%- if require_security_review %}
security_concerns: str = Field(description="Does this PR code introduce possible vulnerabilities such as exposure of sensitive information (e.g., API keys, secrets, passwords), or security concerns like SQL injection, XSS, CSRF, and others ? Answer 'No' (without explaining why) if there are no possible issues. If there are security concerns or issues, start your answer with a short header, such as: 'Sensitive information exposure: ...', 'SQL injection: ...' etc. Explain your answer. Be specific and give examples if possible") security_concerns: str = Field(description="Does this PR code introduce possible vulnerabilities such as exposure of sensitive information (e.g., API keys, secrets, passwords), or security concerns like SQL injection, XSS, CSRF, and others ? Answer 'No' (without explaining why) if there are no possible issues. If there are security concerns or issues, start your answer with a short header, such as: 'Sensitive information exposure: ...', 'SQL injection: ...' etc. Explain your answer. Be specific and give examples if possible")
{%- endif %} {%- endif %}

View File

@ -0,0 +1,5 @@
# Credits
These queries, and some of the logic, were adopted from the excellent [Aider](https://github.com/paul-gauthier/aider/blob/main/aider/queries/README.md) project.

View File

@ -0,0 +1,9 @@
(struct_specifier name: (type_identifier) @name.definition.class body:(_)) @definition.class
(declaration type: (union_specifier name: (type_identifier) @name.definition.class)) @definition.class
(function_declarator declarator: (identifier) @name.definition.function) @definition.function
(type_definition declarator: (type_identifier) @name.definition.type) @definition.type
(enum_specifier name: (type_identifier) @name.definition.type) @definition.type

View File

@ -0,0 +1,46 @@
(class_declaration
name: (identifier) @name.definition.class
) @definition.class
(class_declaration
bases: (base_list (_) @name.reference.class)
) @reference.class
(interface_declaration
name: (identifier) @name.definition.interface
) @definition.interface
(interface_declaration
bases: (base_list (_) @name.reference.interface)
) @reference.interface
(method_declaration
name: (identifier) @name.definition.method
) @definition.method
(object_creation_expression
type: (identifier) @name.reference.class
) @reference.class
(type_parameter_constraints_clause
target: (identifier) @name.reference.class
) @reference.class
(type_constraint
type: (identifier) @name.reference.class
) @reference.class
(variable_declaration
type: (identifier) @name.reference.class
) @reference.class
(invocation_expression
function:
(member_access_expression
name: (identifier) @name.reference.send
)
) @reference.send
(namespace_declaration
name: (identifier) @name.definition.module
) @definition.module

View File

@ -0,0 +1,15 @@
(struct_specifier name: (type_identifier) @name.definition.class body:(_)) @definition.class
(declaration type: (union_specifier name: (type_identifier) @name.definition.class)) @definition.class
(function_declarator declarator: (identifier) @name.definition.function) @definition.function
(function_declarator declarator: (field_identifier) @name.definition.function) @definition.function
(function_declarator declarator: (qualified_identifier scope: (namespace_identifier) @scope name: (identifier) @name.definition.method)) @definition.method
(type_definition declarator: (type_identifier) @name.definition.type) @definition.type
(enum_specifier name: (type_identifier) @name.definition.type) @definition.type
(class_specifier name: (type_identifier) @name.definition.class) @definition.class

View File

@ -0,0 +1,8 @@
;; defun/defsubst
(function_definition name: (symbol) @name.definition.function) @definition.function
;; Treat macros as function definitions for the sake of TAGS.
(macro_definition name: (symbol) @name.definition.function) @definition.function
;; Match function calls
(list (symbol) @name.reference.function) @reference.function

View File

@ -0,0 +1,54 @@
; Definitions
; * modules and protocols
(call
target: (identifier) @ignore
(arguments (alias) @name.definition.module)
(#match? @ignore "^(defmodule|defprotocol)$")) @definition.module
; * functions/macros
(call
target: (identifier) @ignore
(arguments
[
; zero-arity functions with no parentheses
(identifier) @name.definition.function
; regular function clause
(call target: (identifier) @name.definition.function)
; function clause with a guard clause
(binary_operator
left: (call target: (identifier) @name.definition.function)
operator: "when")
])
(#match? @ignore "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp)$")) @definition.function
; References
; ignore calls to kernel/special-forms keywords
(call
target: (identifier) @ignore
(#match? @ignore "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defmodule|defprotocol|defimpl|defstruct|defexception|defoverridable|alias|case|cond|else|for|if|import|quote|raise|receive|require|reraise|super|throw|try|unless|unquote|unquote_splicing|use|with)$"))
; ignore module attributes
(unary_operator
operator: "@"
operand: (call
target: (identifier) @ignore))
; * function call
(call
target: [
; local
(identifier) @name.reference.call
; remote
(dot
right: (identifier) @name.reference.call)
]) @reference.call
; * pipe into function call
(binary_operator
operator: "|>"
right: (identifier) @name.reference.call) @reference.call
; * modules
(alias) @name.reference.module @reference.module

View File

@ -0,0 +1,19 @@
(value_declaration (function_declaration_left (lower_case_identifier) @name.definition.function)) @definition.function
(function_call_expr (value_expr (value_qid) @name.reference.function)) @reference.function
(exposed_value (lower_case_identifier) @name.reference.function) @reference.function
(type_annotation ((lower_case_identifier) @name.reference.function) (colon)) @reference.function
(type_declaration ((upper_case_identifier) @name.definition.type)) @definition.type
(type_ref (upper_case_qid (upper_case_identifier) @name.reference.type)) @reference.type
(exposed_type (upper_case_identifier) @name.reference.type) @reference.type
(type_declaration (union_variant (upper_case_identifier) @name.definition.union)) @definition.union
(value_expr (upper_case_qid (upper_case_identifier) @name.reference.union)) @reference.union
(module_declaration
(upper_case_qid (upper_case_identifier)) @name.definition.module
) @definition.module

View File

@ -0,0 +1,30 @@
(
(comment)* @doc
.
(function_declaration
name: (identifier) @name.definition.function) @definition.function
(#strip! @doc "^//\\s*")
(#set-adjacent! @doc @definition.function)
)
(
(comment)* @doc
.
(method_declaration
name: (field_identifier) @name.definition.method) @definition.method
(#strip! @doc "^//\\s*")
(#set-adjacent! @doc @definition.method)
)
(call_expression
function: [
(identifier) @name.reference.call
(parenthesized_expression (identifier) @name.reference.call)
(selector_expression field: (field_identifier) @name.reference.call)
(parenthesized_expression (selector_expression field: (field_identifier) @name.reference.call))
]) @reference.call
(type_spec
name: (type_identifier) @name.definition.type) @definition.type
(type_identifier) @name.reference.type @reference.type

View File

@ -0,0 +1,20 @@
(class_declaration
name: (identifier) @name.definition.class) @definition.class
(method_declaration
name: (identifier) @name.definition.method) @definition.method
(method_invocation
name: (identifier) @name.reference.call
arguments: (argument_list) @reference.call)
(interface_declaration
name: (identifier) @name.definition.interface) @definition.interface
(type_list
(type_identifier) @name.reference.implementation) @reference.implementation
(object_creation_expression
type: (type_identifier) @name.reference.class) @reference.class
(superclass (type_identifier) @name.reference.class) @reference.class

View File

@ -0,0 +1,88 @@
(
(comment)* @doc
.
(method_definition
name: (property_identifier) @name.definition.method) @definition.method
(#not-eq? @name.definition.method "constructor")
(#strip! @doc "^[\\s\\*/]+|^[\\s\\*/]$")
(#select-adjacent! @doc @definition.method)
)
(
(comment)* @doc
.
[
(class
name: (_) @name.definition.class)
(class_declaration
name: (_) @name.definition.class)
] @definition.class
(#strip! @doc "^[\\s\\*/]+|^[\\s\\*/]$")
(#select-adjacent! @doc @definition.class)
)
(
(comment)* @doc
.
[
(function
name: (identifier) @name.definition.function)
(function_declaration
name: (identifier) @name.definition.function)
(generator_function
name: (identifier) @name.definition.function)
(generator_function_declaration
name: (identifier) @name.definition.function)
] @definition.function
(#strip! @doc "^[\\s\\*/]+|^[\\s\\*/]$")
(#select-adjacent! @doc @definition.function)
)
(
(comment)* @doc
.
(lexical_declaration
(variable_declarator
name: (identifier) @name.definition.function
value: [(arrow_function) (function)]) @definition.function)
(#strip! @doc "^[\\s\\*/]+|^[\\s\\*/]$")
(#select-adjacent! @doc @definition.function)
)
(
(comment)* @doc
.
(variable_declaration
(variable_declarator
name: (identifier) @name.definition.function
value: [(arrow_function) (function)]) @definition.function)
(#strip! @doc "^[\\s\\*/]+|^[\\s\\*/]$")
(#select-adjacent! @doc @definition.function)
)
(assignment_expression
left: [
(identifier) @name.definition.function
(member_expression
property: (property_identifier) @name.definition.function)
]
right: [(arrow_function) (function)]
) @definition.function
(pair
key: (property_identifier) @name.definition.function
value: [(arrow_function) (function)]) @definition.function
(
(call_expression
function: (identifier) @name.reference.call) @reference.call
(#not-match? @name.reference.call "^(require)$")
)
(call_expression
function: (member_expression
property: (property_identifier) @name.reference.call)
arguments: (_) @reference.call)
(new_expression
constructor: (_) @name.reference.class) @reference.class

View File

@ -0,0 +1,115 @@
; Modules
;--------
(
(comment)? @doc .
(module_definition (module_binding (module_name) @name.definition.module) @definition.module)
(#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$")
)
(module_path (module_name) @name.reference.module) @reference.module
; Module types
;--------------
(
(comment)? @doc .
(module_type_definition (module_type_name) @name.definition.interface) @definition.interface
(#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$")
)
(module_type_path (module_type_name) @name.reference.implementation) @reference.implementation
; Functions
;----------
(
(comment)? @doc .
(value_definition
[
(let_binding
pattern: (value_name) @name.definition.function
(parameter))
(let_binding
pattern: (value_name) @name.definition.function
body: [(fun_expression) (function_expression)])
] @definition.function
)
(#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$")
)
(
(comment)? @doc .
(external (value_name) @name.definition.function) @definition.function
(#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$")
)
(application_expression
function: (value_path (value_name) @name.reference.call)) @reference.call
(infix_expression
left: (value_path (value_name) @name.reference.call)
operator: (concat_operator) @reference.call
(#eq? @reference.call "@@"))
(infix_expression
operator: (rel_operator) @reference.call
right: (value_path (value_name) @name.reference.call)
(#eq? @reference.call "|>"))
; Operator
;---------
(
(comment)? @doc .
(value_definition
(let_binding
pattern: (parenthesized_operator (_) @name.definition.function)) @definition.function)
(#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$")
)
[
(prefix_operator)
(sign_operator)
(pow_operator)
(mult_operator)
(add_operator)
(concat_operator)
(rel_operator)
(and_operator)
(or_operator)
(assign_operator)
(hash_operator)
(indexing_operator)
(let_operator)
(let_and_operator)
(match_operator)
] @name.reference.call @reference.call
; Classes
;--------
(
(comment)? @doc .
[
(class_definition (class_binding (class_name) @name.definition.class) @definition.class)
(class_type_definition (class_type_binding (class_type_name) @name.definition.class) @definition.class)
]
(#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$")
)
[
(class_path (class_name) @name.reference.class)
(class_type_path (class_type_name) @name.reference.class)
] @reference.class
; Methods
;--------
(
(comment)? @doc .
(method_definition (method_name) @name.definition.method) @definition.method
(#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$")
)
(method_invocation (method_name) @name.reference.call) @reference.call

View File

@ -0,0 +1,26 @@
(class_declaration
name: (name) @name.definition.class) @definition.class
(function_definition
name: (name) @name.definition.function) @definition.function
(method_declaration
name: (name) @name.definition.function) @definition.function
(object_creation_expression
[
(qualified_name (name) @name.reference.class)
(variable_name (name) @name.reference.class)
]) @reference.class
(function_call_expression
function: [
(qualified_name (name) @name.reference.call)
(variable_name (name)) @name.reference.call
]) @reference.call
(scoped_call_expression
name: (name) @name.reference.call) @reference.call
(member_call_expression
name: (name) @name.reference.call) @reference.call

View File

@ -0,0 +1,12 @@
(class_definition
name: (identifier) @name.definition.class) @definition.class
(function_definition
name: (identifier) @name.definition.function) @definition.function
(call
function: [
(identifier) @name.reference.call
(attribute
attribute: (identifier) @name.reference.call)
]) @reference.call

View File

@ -0,0 +1,26 @@
(classlessPredicate
name: (predicateName) @name.definition.function) @definition.function
(memberPredicate
name: (predicateName) @name.definition.method) @definition.method
(aritylessPredicateExpr
name: (literalId) @name.reference.call) @reference.call
(module
name: (moduleName) @name.definition.module) @definition.module
(dataclass
name: (className) @name.definition.class) @definition.class
(datatype
name: (className) @name.definition.class) @definition.class
(datatypeBranch
name: (className) @name.definition.class) @definition.class
(qualifiedRhs
name: (predicateName) @name.reference.call) @reference.call
(typeExpr
name: (className) @name.reference.type) @reference.type

View File

@ -0,0 +1,64 @@
; Method definitions
(
(comment)* @doc
.
[
(method
name: (_) @name.definition.method) @definition.method
(singleton_method
name: (_) @name.definition.method) @definition.method
]
(#strip! @doc "^#\\s*")
(#select-adjacent! @doc @definition.method)
)
(alias
name: (_) @name.definition.method) @definition.method
(setter
(identifier) @ignore)
; Class definitions
(
(comment)* @doc
.
[
(class
name: [
(constant) @name.definition.class
(scope_resolution
name: (_) @name.definition.class)
]) @definition.class
(singleton_class
value: [
(constant) @name.definition.class
(scope_resolution
name: (_) @name.definition.class)
]) @definition.class
]
(#strip! @doc "^#\\s*")
(#select-adjacent! @doc @definition.class)
)
; Module definitions
(
(module
name: [
(constant) @name.definition.module
(scope_resolution
name: (_) @name.definition.module)
]) @definition.module
)
; Calls
(call method: (identifier) @name.reference.call) @reference.call
(
[(identifier) (constant)] @name.reference.call @reference.call
(#is-not? local)
(#not-match? @name.reference.call "^(lambda|load|require|require_relative|__FILE__|__LINE__)$")
)

View File

@ -0,0 +1,60 @@
; ADT definitions
(struct_item
name: (type_identifier) @name.definition.class) @definition.class
(enum_item
name: (type_identifier) @name.definition.class) @definition.class
(union_item
name: (type_identifier) @name.definition.class) @definition.class
; type aliases
(type_item
name: (type_identifier) @name.definition.class) @definition.class
; method definitions
(declaration_list
(function_item
name: (identifier) @name.definition.method)) @definition.method
; function definitions
(function_item
name: (identifier) @name.definition.function) @definition.function
; trait definitions
(trait_item
name: (type_identifier) @name.definition.interface) @definition.interface
; module definitions
(mod_item
name: (identifier) @name.definition.module) @definition.module
; macro definitions
(macro_definition
name: (identifier) @name.definition.macro) @definition.macro
; references
(call_expression
function: (identifier) @name.reference.call) @reference.call
(call_expression
function: (field_expression
field: (field_identifier) @name.reference.call)) @reference.call
(macro_invocation
macro: (identifier) @name.reference.call) @reference.call
; implementations
(impl_item
trait: (type_identifier) @name.reference.implementation) @reference.implementation
(impl_item
type: (type_identifier) @name.reference.implementation
!trait) @reference.implementation

View File

@ -0,0 +1,41 @@
(function_signature
name: (identifier) @name.definition.function) @definition.function
(method_signature
name: (property_identifier) @name.definition.method) @definition.method
(abstract_method_signature
name: (property_identifier) @name.definition.method) @definition.method
(abstract_class_declaration
name: (type_identifier) @name.definition.class) @definition.class
(module
name: (identifier) @name.definition.module) @definition.module
(interface_declaration
name: (type_identifier) @name.definition.interface) @definition.interface
(type_annotation
(type_identifier) @name.reference.type) @reference.type
(new_expression
constructor: (identifier) @name.reference.class) @reference.class
(function_declaration
name: (identifier) @name.definition.function) @definition.function
(method_definition
name: (property_identifier) @name.definition.method) @definition.method
(class_declaration
name: (type_identifier) @name.definition.class) @definition.class
(interface_declaration
name: (type_identifier) @name.definition.class) @definition.class
(type_alias_declaration
name: (type_identifier) @name.definition.type) @definition.type
(enum_declaration
name: (identifier) @name.definition.enum) @definition.enum

View File

@ -0,0 +1,150 @@
import os
from pathlib import Path
from grep_ast import TreeContext
from grep_ast.parsers import PARSERS
# from pygments.lexers import guess_lexer_for_filename
# from pygments.token import Token
from tree_sitter_languages import get_language, get_parser
def filename_to_lang(filename):
file_extension = os.path.splitext(filename)[0]
lang = PARSERS.get(file_extension)
return lang
class FileSummary:
"""
This class is used to summarize the content of a file using tree-sitter queries.
Supported languages: C, C++, C#, elisp, elixir, go, java, javascript, ocaml, php, python, ql, ruby, rust, typescript
"""
def __init__(self, fname_full_path: str, project_base_path, parent_context=True, child_context=False, header_max=0):
self.fname_full_path = fname_full_path
self.project_base_path = project_base_path
self.fname_rel = os.path.relpath(fname_full_path, project_base_path)
self.main_queries_path = Path(__file__).parent.parent // 'queries'
if not os.path.exists(fname_full_path):
print(f"File {fname_full_path} does not exist")
with open(fname_full_path, "w") as f:
code = f.read()
self.code = code.rstrip("\n") + "\n"
self.parent_context = parent_context
self.child_context = child_context
self.header_max = header_max
def summarize(self):
query_results = self.get_query_results()
summary_str = self.query_processing(query_results)
return summary_str
def render_file_summary(self, lines_of_interest: list):
code = self.code
fname_rel = self.fname_rel
context = TreeContext(
fname_rel,
code,
color=False,
line_number=True, # number the lines (1-indexed)
parent_context=self.parent_context,
child_context=self.child_context,
last_line=False,
margin=0,
mark_lois=False,
loi_pad=0,
header_max=self.header_max, # max number of lines to show in a function header
show_top_of_file_parent_scope=False,
)
context.lines_of_interest = set()
context.add_lines_of_interest(lines_of_interest)
context.add_context()
res = context.format()
return res
def query_processing(self, query_results: list):
if not query_results:
return ""
output = ""
def_lines = [q['line'] for q in query_results if q['kind'] == "def"]
output += "\n"
output += query_results[0]['fname'] + ":\n"
output += self.render_file_summary(def_lines)
return output
def get_queries_scheme(self, lang) -> str:
try:
# Load the relevant queries
path = os.path.join(self.main_queries_path, f"tree-sitter-{lang}-tags.scm")
with open(path, "r") as f:
return f.read()
except KeyError:
return 0
def get_query_results(self):
fname_rel = self.fname_rel
code = self.code
lang = filename_to_lang(fname_rel)
if not lang:
return
try:
language = get_language(lang)
parser = get_parser(lang)
except Exception as err:
print(f"Skipping file {fname_rel}: {err}")
return
query_scheme_str = self.get_queries_scheme(lang)
tree = parser.parse(bytes(code, "utf-8"))
# Run the queries
query = language.query(query_scheme_str)
captures = list(query.captures(tree.root_node))
# Parse the results into a list of "def" and "ref" tags
visited_set = set()
results = []
for node, tag in captures:
if tag.startswith("name.definition."):
kind = "ref"
elif tag.startswith("name.reference."):
kind = "def"
else:
continue
visited_set.add(kind)
result = dict(
fname=fname_rel,
name=node.text.decode("utf-8"),
kind=kind,
line=node.start_point[0],
)
results.append(result)
if "ref" in visited_set:
return results
if "def" not in visited_set:
return results
## currently we are interested only in defs
# # We saw defs, without any refs
# # Some files only provide defs (cpp, for example)
# # Use pygments to backfill refs
# try:
# lexer = guess_lexer_for_filename(fname, code)
# except Exception:
# return
#
# tokens = list(lexer.get_tokens(code))
# tokens = [token[1] for token in tokens if token[0] in Token.Name]
#
# for t in tokens:
# result = dict(
# fname=fname,
# name=t,
# kind="ref",
# line=-1,
# )
# results.append(result)
return results

View File

@ -0,0 +1,428 @@
// Taken from 'https://github.com/dolphin-emu/dolphin'
// Copyright 2017 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <array>
#include <bit>
#include <memory>
#include <mbedtls/aes.h>
#include "Common/Assert.h"
#include "Common/CPUDetect.h"
#include "Common/Crypto/AES.h"
#ifdef _MSC_VER
#include <intrin.h>
#else
#if defined(_M_X86_64)
#include <x86intrin.h>
#elif defined(_M_ARM_64)
#include <arm_acle.h>
#include <arm_neon.h>
#endif
#endif
#ifdef _MSC_VER
#define ATTRIBUTE_TARGET(x)
#else
#define ATTRIBUTE_TARGET(x) [[gnu::target(x)]]
#endif
namespace Common::AES
{
// For x64 and arm64, it's very unlikely a user's cpu does not support the accelerated version,
// fallback is just in case.
template <Mode AesMode>
class ContextGeneric final : public Context
{
public:
ContextGeneric(const u8* key)
{
mbedtls_aes_init(&ctx);
if constexpr (AesMode == Mode::Encrypt)
ASSERT(!mbedtls_aes_setkey_enc(&ctx, key, 128));
else
ASSERT(!mbedtls_aes_setkey_dec(&ctx, key, 128));
}
virtual bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out,
size_t len) const override
{
std::array<u8, BLOCK_SIZE> iv_tmp{};
if (iv)
std::memcpy(&iv_tmp[0], iv, BLOCK_SIZE);
constexpr int mode = (AesMode == Mode::Encrypt) ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT;
if (mbedtls_aes_crypt_cbc(const_cast<mbedtls_aes_context*>(&ctx), mode, len, &iv_tmp[0], buf_in,
buf_out))
return false;
if (iv_out)
std::memcpy(iv_out, &iv_tmp[0], BLOCK_SIZE);
return true;
}
private:
mbedtls_aes_context ctx{};
};
#if defined(_M_X86_64)
// Note that (for instructions with same data width) the actual instructions emitted vary depending
// on compiler and flags. The naming is somewhat confusing, because VAES cpuid flag was added after
// VAES(VEX.128):
// clang-format off
// instructions | cpuid flag | #define
// AES(128) | AES | -
// VAES(VEX.128) | AES & AVX | __AVX__
// VAES(VEX.256) | VAES | -
// VAES(EVEX.128) | VAES & AVX512VL | __AVX512VL__
// VAES(EVEX.256) | VAES & AVX512VL | __AVX512VL__
// VAES(EVEX.512) | VAES & AVX512F | __AVX512F__
// clang-format on
template <Mode AesMode>
class ContextAESNI final : public Context
{
static inline __m128i Aes128KeygenAssistFinish(__m128i key, __m128i kga)
{
__m128i tmp = _mm_shuffle_epi32(kga, _MM_SHUFFLE(3, 3, 3, 3));
tmp = _mm_xor_si128(tmp, key);
key = _mm_slli_si128(key, 4);
tmp = _mm_xor_si128(tmp, key);
key = _mm_slli_si128(key, 4);
tmp = _mm_xor_si128(tmp, key);
key = _mm_slli_si128(key, 4);
tmp = _mm_xor_si128(tmp, key);
return tmp;
}
template <size_t RoundIdx>
ATTRIBUTE_TARGET("aes")
inline constexpr void StoreRoundKey(__m128i rk)
{
if constexpr (AesMode == Mode::Encrypt)
round_keys[RoundIdx] = rk;
else
{
constexpr size_t idx = NUM_ROUND_KEYS - RoundIdx - 1;
if constexpr (idx == 0 || idx == NUM_ROUND_KEYS - 1)
round_keys[idx] = rk;
else
round_keys[idx] = _mm_aesimc_si128(rk);
}
}
template <size_t RoundIdx, int Rcon>
ATTRIBUTE_TARGET("aes")
inline constexpr __m128i Aes128Keygen(__m128i rk)
{
rk = Aes128KeygenAssistFinish(rk, _mm_aeskeygenassist_si128(rk, Rcon));
StoreRoundKey<RoundIdx>(rk);
return rk;
}
public:
ContextAESNI(const u8* key)
{
__m128i rk = _mm_loadu_si128((const __m128i*)key);
StoreRoundKey<0>(rk);
rk = Aes128Keygen<1, 0x01>(rk);
rk = Aes128Keygen<2, 0x02>(rk);
rk = Aes128Keygen<3, 0x04>(rk);
rk = Aes128Keygen<4, 0x08>(rk);
rk = Aes128Keygen<5, 0x10>(rk);
rk = Aes128Keygen<6, 0x20>(rk);
rk = Aes128Keygen<7, 0x40>(rk);
rk = Aes128Keygen<8, 0x80>(rk);
rk = Aes128Keygen<9, 0x1b>(rk);
Aes128Keygen<10, 0x36>(rk);
}
ATTRIBUTE_TARGET("aes")
inline void CryptBlock(__m128i* iv, const u8* buf_in, u8* buf_out) const
{
__m128i block = _mm_loadu_si128((const __m128i*)buf_in);
if constexpr (AesMode == Mode::Encrypt)
{
block = _mm_xor_si128(_mm_xor_si128(block, *iv), round_keys[0]);
for (size_t i = 1; i < Nr; ++i)
block = _mm_aesenc_si128(block, round_keys[i]);
block = _mm_aesenclast_si128(block, round_keys[Nr]);
*iv = block;
}
else
{
__m128i iv_next = block;
block = _mm_xor_si128(block, round_keys[0]);
for (size_t i = 1; i < Nr; ++i)
block = _mm_aesdec_si128(block, round_keys[i]);
block = _mm_aesdeclast_si128(block, round_keys[Nr]);
block = _mm_xor_si128(block, *iv);
*iv = iv_next;
}
_mm_storeu_si128((__m128i*)buf_out, block);
}
// Takes advantage of instruction pipelining to parallelize.
template <size_t NumBlocks>
ATTRIBUTE_TARGET("aes")
inline void DecryptPipelined(__m128i* iv, const u8* buf_in, u8* buf_out) const
{
constexpr size_t Depth = NumBlocks;
__m128i block[Depth];
for (size_t d = 0; d < Depth; d++)
block[d] = _mm_loadu_si128(&((const __m128i*)buf_in)[d]);
__m128i iv_next[1 + Depth];
iv_next[0] = *iv;
for (size_t d = 0; d < Depth; d++)
iv_next[1 + d] = block[d];
for (size_t d = 0; d < Depth; d++)
block[d] = _mm_xor_si128(block[d], round_keys[0]);
// The main speedup is here
for (size_t i = 1; i < Nr; ++i)
for (size_t d = 0; d < Depth; d++)
block[d] = _mm_aesdec_si128(block[d], round_keys[i]);
for (size_t d = 0; d < Depth; d++)
block[d] = _mm_aesdeclast_si128(block[d], round_keys[Nr]);
for (size_t d = 0; d < Depth; d++)
block[d] = _mm_xor_si128(block[d], iv_next[d]);
*iv = iv_next[1 + Depth - 1];
for (size_t d = 0; d < Depth; d++)
_mm_storeu_si128(&((__m128i*)buf_out)[d], block[d]);
}
virtual bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out,
size_t len) const override
{
if (len % BLOCK_SIZE)
return false;
__m128i iv_block = iv ? _mm_loadu_si128((const __m128i*)iv) : _mm_setzero_si128();
if constexpr (AesMode == Mode::Decrypt)
{
// On amd zen2...(benchmark, not real-world):
// With AES(128) instructions, BLOCK_DEPTH results in following speedup vs. non-pipelined: 4:
// 18%, 8: 22%, 9: 26%, 10-15: 31%. 16: 8% (register exhaustion). With VAES(VEX.128), 10 gives
// 36% speedup vs. its corresponding baseline. VAES(VEX.128) is ~4% faster than AES(128). The
// result is similar on zen3.
// Zen3 in general is 20% faster than zen2 in aes, and VAES(VEX.256) is 35% faster than
// zen3/VAES(VEX.128).
// It seems like VAES(VEX.256) should be faster?
constexpr size_t BLOCK_DEPTH = 10;
constexpr size_t CHUNK_LEN = BLOCK_DEPTH * BLOCK_SIZE;
while (len >= CHUNK_LEN)
{
DecryptPipelined<BLOCK_DEPTH>(&iv_block, buf_in, buf_out);
buf_in += CHUNK_LEN;
buf_out += CHUNK_LEN;
len -= CHUNK_LEN;
}
}
len /= BLOCK_SIZE;
while (len--)
{
CryptBlock(&iv_block, buf_in, buf_out);
buf_in += BLOCK_SIZE;
buf_out += BLOCK_SIZE;
}
if (iv_out)
_mm_storeu_si128((__m128i*)iv_out, iv_block);
return true;
}
private:
std::array<__m128i, NUM_ROUND_KEYS> round_keys;
};
#endif
#if defined(_M_ARM_64)
template <Mode AesMode>
class ContextNeon final : public Context
{
public:
template <size_t RoundIdx>
inline constexpr void StoreRoundKey(const u32* rk)
{
const uint8x16_t rk_block = vreinterpretq_u8_u32(vld1q_u32(rk));
if constexpr (AesMode == Mode::Encrypt)
round_keys[RoundIdx] = rk_block;
else
{
constexpr size_t idx = NUM_ROUND_KEYS - RoundIdx - 1;
if constexpr (idx == 0 || idx == NUM_ROUND_KEYS - 1)
round_keys[idx] = rk_block;
else
round_keys[idx] = vaesimcq_u8(rk_block);
}
}
ContextNeon(const u8* key)
{
constexpr u8 rcon[]{0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36};
std::array<u32, Nb * NUM_ROUND_KEYS> rk{};
// This uses a nice trick I've seen in wolfssl (not sure original author),
// which uses vaeseq_u8 to assist keygen.
// vaeseq_u8: op1 = SubBytes(ShiftRows(AddRoundKey(op1, op2)))
// given RotWord == ShiftRows for row 1 (rol(x,8))
// Probably not super fast (moves to/from vector regs constantly), but it is nice and simple.
std::memcpy(&rk[0], key, KEY_SIZE);
StoreRoundKey<0>(&rk[0]);
for (size_t i = 0; i < rk.size() - Nk; i += Nk)
{
const uint8x16_t enc = vaeseq_u8(vreinterpretq_u8_u32(vmovq_n_u32(rk[i + 3])), vmovq_n_u8(0));
const u32 temp = vgetq_lane_u32(vreinterpretq_u32_u8(enc), 0);
rk[i + 4] = rk[i + 0] ^ std::rotr(temp, 8) ^ rcon[i / Nk];
rk[i + 5] = rk[i + 4] ^ rk[i + 1];
rk[i + 6] = rk[i + 5] ^ rk[i + 2];
rk[i + 7] = rk[i + 6] ^ rk[i + 3];
// clang-format off
// Not great
const size_t rki = 1 + i / Nk;
switch (rki)
{
case 1: StoreRoundKey< 1>(&rk[Nk * rki]); break;
case 2: StoreRoundKey< 2>(&rk[Nk * rki]); break;
case 3: StoreRoundKey< 3>(&rk[Nk * rki]); break;
case 4: StoreRoundKey< 4>(&rk[Nk * rki]); break;
case 5: StoreRoundKey< 5>(&rk[Nk * rki]); break;
case 6: StoreRoundKey< 6>(&rk[Nk * rki]); break;
case 7: StoreRoundKey< 7>(&rk[Nk * rki]); break;
case 8: StoreRoundKey< 8>(&rk[Nk * rki]); break;
case 9: StoreRoundKey< 9>(&rk[Nk * rki]); break;
case 10: StoreRoundKey<10>(&rk[Nk * rki]); break;
}
// clang-format on
}
}
inline void CryptBlock(uint8x16_t* iv, const u8* buf_in, u8* buf_out) const
{
uint8x16_t block = vld1q_u8(buf_in);
if constexpr (AesMode == Mode::Encrypt)
{
block = veorq_u8(block, *iv);
for (size_t i = 0; i < Nr - 1; ++i)
block = vaesmcq_u8(vaeseq_u8(block, round_keys[i]));
block = vaeseq_u8(block, round_keys[Nr - 1]);
block = veorq_u8(block, round_keys[Nr]);
*iv = block;
}
else
{
uint8x16_t iv_next = block;
for (size_t i = 0; i < Nr - 1; ++i)
block = vaesimcq_u8(vaesdq_u8(block, round_keys[i]));
block = vaesdq_u8(block, round_keys[Nr - 1]);
block = veorq_u8(block, round_keys[Nr]);
block = veorq_u8(block, *iv);
*iv = iv_next;
}
vst1q_u8(buf_out, block);
}
virtual bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out,
size_t len) const override
{
if (len % BLOCK_SIZE)
return false;
uint8x16_t iv_block = iv ? vld1q_u8(iv) : vmovq_n_u8(0);
len /= BLOCK_SIZE;
while (len--)
{
CryptBlock(&iv_block, buf_in, buf_out);
buf_in += BLOCK_SIZE;
buf_out += BLOCK_SIZE;
}
if (iv_out)
vst1q_u8(iv_out, iv_block);
return true;
}
private:
std::array<uint8x16_t, NUM_ROUND_KEYS> round_keys;
};
#endif
template <Mode AesMode>
std::unique_ptr<Context> CreateContext(const u8* key)
{
if (cpu_info.bAES)
{
#if defined(_M_X86_64)
#if defined(__AVX__)
// If compiler enables AVX, the intrinsics will generate VAES(VEX.128) instructions.
// In the future we may want to compile the code twice and explicitly override the compiler
// flags. There doesn't seem to be much performance difference between AES(128) and
// VAES(VEX.128) at the moment, though.
if (cpu_info.bAVX)
#endif
return std::make_unique<ContextAESNI<AesMode>>(key);
#elif defined(_M_ARM_64)
return std::make_unique<ContextNeon<AesMode>>(key);
#endif
}
return std::make_unique<ContextGeneric<AesMode>>(key);
}
std::unique_ptr<Context> CreateContextEncrypt(const u8* key)
{
return CreateContext<Mode::Encrypt>(key);
}
std::unique_ptr<Context> CreateContextDecrypt(const u8* key)
{
return CreateContext<Mode::Decrypt>(key);
}
// OFB encryption and decryption are the exact same. We don't encrypt though.
void CryptOFB(const u8* key, const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out, size_t size)
{
mbedtls_aes_context aes_ctx;
size_t iv_offset = 0;
std::array<u8, 16> iv_tmp{};
if (iv)
std::memcpy(&iv_tmp[0], iv, 16);
ASSERT(!mbedtls_aes_setkey_enc(&aes_ctx, key, 128));
mbedtls_aes_crypt_ofb(&aes_ctx, size, &iv_offset, &iv_tmp[0], buf_in, buf_out);
if (iv_out)
std::memcpy(iv_out, &iv_tmp[0], 16);
}
} // namespace Common::AES

View File

@ -0,0 +1,586 @@
package com.houarizegai.calculator.ui;
import com.houarizegai.calculator.theme.properties.Theme;
import com.houarizegai.calculator.theme.ThemeLoader;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.event.ItemEvent;
import java.util.Map;
import java.util.regex.Pattern;
import java.awt.Color;
import javax.swing.*;
import static com.houarizegai.calculator.util.ColorUtil.hex2Color;
public class CalculatorUI {
private static final String FONT_NAME = "Comic Sans MS";
private static final String DOUBLE_OR_NUMBER_REGEX = "([-]?\\d+[.]\\d*)|(\\d+)|(-\\d+)";
private static final String APPLICATION_TITLE = "Calculator";
private static final int WINDOW_WIDTH = 410;
private static final int WINDOW_HEIGHT = 600;
private static final int BUTTON_WIDTH = 80;
private static final int BUTTON_HEIGHT = 70;
private static final int MARGIN_X = 20;
private static final int MARGIN_Y = 60;
private final JFrame window;
private JComboBox<String> comboCalculatorType;
private JComboBox<String> comboTheme;
private JTextField inputScreen;
private JButton btnC;
private JButton btnBack;
private JButton btnMod;
private JButton btnDiv;
private JButton btnMul;
private JButton btnSub;
private JButton btnAdd;
private JButton btn0;
private JButton btn1;
private JButton btn2;
private JButton btn3;
private JButton btn4;
private JButton btn5;
private JButton btn6;
private JButton btn7;
private JButton btn8;
private JButton btn9;
private JButton btnPoint;
private JButton btnEqual;
private JButton btnRoot;
private JButton btnPower;
private JButton btnLog;
private char selectedOperator = ' ';
private boolean go = true; // For calculate with Opt != (=)
private boolean addToDisplay = true; // Connect numbers in display
private double typedValue = 0;
private final Map<String, Theme> themesMap;
public CalculatorUI() {
themesMap = ThemeLoader.loadThemes();
window = new JFrame(APPLICATION_TITLE);
window.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
window.setLocationRelativeTo(null);
int[] columns = {MARGIN_X, MARGIN_X + 90, MARGIN_X + 90 * 2, MARGIN_X + 90 * 3, MARGIN_X + 90 * 4};
int[] rows = {MARGIN_Y, MARGIN_Y + 100, MARGIN_Y + 100 + 80, MARGIN_Y + 100 + 80 * 2, MARGIN_Y + 100 + 80 * 3, MARGIN_Y + 100 + 80 * 4};
initInputScreen(columns, rows);
initButtons(columns, rows);
initCalculatorTypeSelector();
initThemeSelector();
window.setLayout(null);
window.setResizable(false);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
}
public double calculate(double firstNumber, double secondNumber, char operator) {
switch (operator) {
case '+':
return firstNumber + secondNumber;
case '-':
return firstNumber - secondNumber;
case '*':
return firstNumber * secondNumber;
case '/':
return firstNumber / secondNumber;
case '%':
return firstNumber % secondNumber;
case '^':
return Math.pow(firstNumber, secondNumber);
default:
return secondNumber;
}
}
private void initThemeSelector() {
comboTheme = createComboBox(themesMap.keySet().toArray(new String[0]), 230, 30, "Theme");
comboTheme.addItemListener(event -> {
if (event.getStateChange() != ItemEvent.SELECTED)
return;
String selectedTheme = (String) event.getItem();
applyTheme(themesMap.get(selectedTheme));
});
if (themesMap.entrySet().iterator().hasNext()) {
applyTheme(themesMap.entrySet().iterator().next().getValue());
}
}
private void initInputScreen(int[] columns, int[] rows) {
inputScreen = new JTextField("0");
inputScreen.setBounds(columns[0], rows[0], 350, 70);
inputScreen.setEditable(false);
inputScreen.setBackground(Color.WHITE);
inputScreen.setFont(new Font(FONT_NAME, Font.PLAIN, 33));
window.add(inputScreen);
}
private void initCalculatorTypeSelector() {
comboCalculatorType = createComboBox(new String[]{"Standard", "Scientific"}, 20, 30, "Calculator type");
comboCalculatorType.addItemListener(event -> {
if (event.getStateChange() != ItemEvent.SELECTED)
return;
String selectedItem = (String) event.getItem();
switch (selectedItem) {
case "Standard":
window.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
btnRoot.setVisible(false);
btnPower.setVisible(false);
btnLog.setVisible(false);
break;
case "Scientific":
window.setSize(WINDOW_WIDTH + 80, WINDOW_HEIGHT);
btnRoot.setVisible(true);
btnPower.setVisible(true);
btnLog.setVisible(true);
break;
}
});
}
private void initButtons(int[] columns, int[] rows) {
btnC = createButton("C", columns[0], rows[1]);
btnC.addActionListener(event -> {
inputScreen.setText("0");
selectedOperator = ' ';
typedValue = 0;
});
btnBack = createButton("<-", columns[1], rows[1]);
btnBack.addActionListener(event -> {
String str = inputScreen.getText();
StringBuilder str2 = new StringBuilder();
for (int i = 0; i < (str.length() - 1); i++) {
str2.append(str.charAt(i));
}
if (str2.toString().equals("")) {
inputScreen.setText("0");
} else {
inputScreen.setText(str2.toString());
}
});
btnMod = createButton("%", columns[2], rows[1]);
btnMod.addActionListener(event -> {
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()) || !go)
return;
typedValue = calculate(typedValue, Double.parseDouble(inputScreen.getText()), selectedOperator);
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
inputScreen.setText(String.valueOf((int) typedValue));
} else {
inputScreen.setText(String.valueOf(typedValue));
}
selectedOperator = '%';
go = false;
addToDisplay = false;
});
btnDiv = createButton("/", columns[3], rows[1]);
btnDiv.addActionListener(event -> {
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()))
return;
if (go) {
typedValue = calculate(typedValue, Double.parseDouble(inputScreen.getText()), selectedOperator);
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
inputScreen.setText(String.valueOf((int) typedValue));
} else {
inputScreen.setText(String.valueOf(typedValue));
}
selectedOperator = '/';
go = false;
addToDisplay = false;
} else {
selectedOperator = '/';
}
});
btn7 = createButton("7", columns[0], rows[2]);
btn7.addActionListener(event -> {
if (addToDisplay) {
if (Pattern.matches("[0]*", inputScreen.getText())) {
inputScreen.setText("7");
} else {
inputScreen.setText(inputScreen.getText() + "7");
}
} else {
inputScreen.setText("7");
addToDisplay = true;
}
go = true;
});
btn8 = createButton("8", columns[1], rows[2]);
btn8.addActionListener(event -> {
if (addToDisplay) {
if (Pattern.matches("[0]*", inputScreen.getText())) {
inputScreen.setText("8");
} else {
inputScreen.setText(inputScreen.getText() + "8");
}
} else {
inputScreen.setText("8");
addToDisplay = true;
}
go = true;
});
btn9 = createButton("9", columns[2], rows[2]);
btn9.addActionListener(event -> {
if (addToDisplay) {
if (Pattern.matches("[0]*", inputScreen.getText())) {
inputScreen.setText("9");
} else {
inputScreen.setText(inputScreen.getText() + "9");
}
} else {
inputScreen.setText("9");
addToDisplay = true;
}
go = true;
});
btnMul = createButton("*", columns[3], rows[2]);
btnMul.addActionListener(event -> {
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()))
return;
if (go) {
typedValue = calculate(typedValue, Double.parseDouble(inputScreen.getText()), selectedOperator);
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
inputScreen.setText(String.valueOf((int) typedValue));
} else {
inputScreen.setText(String.valueOf(typedValue));
}
selectedOperator = '*';
go = false;
addToDisplay = false;
} else {
selectedOperator = '*';
}
});
btn4 = createButton("4", columns[0], rows[3]);
btn4.addActionListener(event -> {
if (addToDisplay) {
if (Pattern.matches("[0]*", inputScreen.getText())) {
inputScreen.setText("4");
} else {
inputScreen.setText(inputScreen.getText() + "4");
}
} else {
inputScreen.setText("4");
addToDisplay = true;
}
go = true;
});
btn5 = createButton("5", columns[1], rows[3]);
btn5.addActionListener(event -> {
if (addToDisplay) {
if (Pattern.matches("[0]*", inputScreen.getText())) {
inputScreen.setText("5");
} else {
inputScreen.setText(inputScreen.getText() + "5");
}
} else {
inputScreen.setText("5");
addToDisplay = true;
}
go = true;
});
btn6 = createButton("6", columns[2], rows[3]);
btn6.addActionListener(event -> {
if (addToDisplay) {
if (Pattern.matches("[0]*", inputScreen.getText())) {
inputScreen.setText("6");
} else {
inputScreen.setText(inputScreen.getText() + "6");
}
} else {
inputScreen.setText("6");
addToDisplay = true;
}
go = true;
});
btnSub = createButton("-", columns[3], rows[3]);
btnSub.addActionListener(event -> {
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()))
return;
if (go) {
typedValue = calculate(typedValue, Double.parseDouble(inputScreen.getText()), selectedOperator);
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
inputScreen.setText(String.valueOf((int) typedValue));
} else {
inputScreen.setText(String.valueOf(typedValue));
}
selectedOperator = '-';
go = false;
addToDisplay = false;
} else {
selectedOperator = '-';
}
});
btn1 = createButton("1", columns[0], rows[4]);
btn1.addActionListener(event -> {
if (addToDisplay) {
if (Pattern.matches("[0]*", inputScreen.getText())) {
inputScreen.setText("1");
} else {
inputScreen.setText(inputScreen.getText() + "1");
}
} else {
inputScreen.setText("1");
addToDisplay = true;
}
go = true;
});
btn2 = createButton("2", columns[1], rows[4]);
btn2.addActionListener(event -> {
if (addToDisplay) {
if (Pattern.matches("[0]*", inputScreen.getText())) {
inputScreen.setText("2");
} else {
inputScreen.setText(inputScreen.getText() + "2");
}
} else {
inputScreen.setText("2");
addToDisplay = true;
}
go = true;
});
btn3 = createButton("3", columns[2], rows[4]);
btn3.addActionListener(event -> {
if (addToDisplay) {
if (Pattern.matches("[0]*", inputScreen.getText())) {
inputScreen.setText("3");
} else {
inputScreen.setText(inputScreen.getText() + "3");
}
} else {
inputScreen.setText("3");
addToDisplay = true;
}
go = true;
});
btnAdd = createButton("+", columns[3], rows[4]);
btnAdd.addActionListener(event -> {
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()))
return;
if (go) {
typedValue = calculate(typedValue, Double.parseDouble(inputScreen.getText()), selectedOperator);
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
inputScreen.setText(String.valueOf((int) typedValue));
} else {
inputScreen.setText(String.valueOf(typedValue));
}
selectedOperator = '+';
go = false;
addToDisplay = false;
} else {
selectedOperator = '+';
}
});
btnPoint = createButton(".", columns[0], rows[5]);
btnPoint.addActionListener(event -> {
if (addToDisplay) {
if (!inputScreen.getText().contains(".")) {
inputScreen.setText(inputScreen.getText() + ".");
}
} else {
inputScreen.setText("0.");
addToDisplay = true;
}
go = true;
});
btn0 = createButton("0", columns[1], rows[5]);
btn0.addActionListener(event -> {
if (addToDisplay) {
if (Pattern.matches("[0]*", inputScreen.getText())) {
inputScreen.setText("0");
} else {
inputScreen.setText(inputScreen.getText() + "0");
}
} else {
inputScreen.setText("0");
addToDisplay = true;
}
go = true;
});
btnEqual = createButton("=", columns[2], rows[5]);
btnEqual.addActionListener(event -> {
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()))
return;
if (go) {
typedValue = calculate(typedValue, Double.parseDouble(inputScreen.getText()), selectedOperator);
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
inputScreen.setText(String.valueOf((int) typedValue));
} else {
inputScreen.setText(String.valueOf(typedValue));
}
selectedOperator = '=';
addToDisplay = false;
}
});
btnEqual.setSize(2 * BUTTON_WIDTH + 10, BUTTON_HEIGHT);
btnRoot = createButton("", columns[4], rows[1]);
btnRoot.addActionListener(event -> {
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()))
return;
if (go) {
typedValue = Math.sqrt(Double.parseDouble(inputScreen.getText()));
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
inputScreen.setText(String.valueOf((int) typedValue));
} else {
inputScreen.setText(String.valueOf(typedValue));
}
selectedOperator = '√';
addToDisplay = false;
}
});
btnRoot.setVisible(false);
btnPower = createButton("pow", columns[4], rows[2]);
btnPower.addActionListener(event -> {
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()))
return;
if (go) {
typedValue = calculate(typedValue, Double.parseDouble(inputScreen.getText()), selectedOperator);
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
inputScreen.setText(String.valueOf((int) typedValue));
} else {
inputScreen.setText(String.valueOf(typedValue));
}
selectedOperator = '^';
go = false;
addToDisplay = false;
} else {
selectedOperator = '^';
}
});
btnPower.setFont(new Font("Comic Sans MS", Font.PLAIN, 24));
btnPower.setVisible(false);
btnLog = createButton("ln", columns[4], rows[3]);
btnLog.addActionListener(event -> {
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()))
return;
if (go) {
typedValue = Math.log(Double.parseDouble(inputScreen.getText()));
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
inputScreen.setText(String.valueOf((int) typedValue));
} else {
inputScreen.setText(String.valueOf(typedValue));
}
selectedOperator = 'l';
addToDisplay = false;
}
});
btnLog.setVisible(false);
}
private JComboBox<String> createComboBox(String[] items, int x, int y, String toolTip) {
JComboBox<String> combo = new JComboBox<>(items);
combo.setBounds(x, y, 140, 25);
combo.setToolTipText(toolTip);
combo.setCursor(new Cursor(Cursor.HAND_CURSOR));
window.add(combo);
return combo;
}
private JButton createButton(String label, int x, int y) {
JButton btn = new JButton(label);
btn.setBounds(x, y, BUTTON_WIDTH, BUTTON_HEIGHT);
btn.setFont(new Font("Comic Sans MS", Font.PLAIN, 28));
btn.setCursor(new Cursor(Cursor.HAND_CURSOR));
btn.setFocusable(false);
window.add(btn);
return btn;
}
private void applyTheme(Theme theme) {
window.getContentPane().setBackground(hex2Color(theme.getApplicationBackground()));
comboCalculatorType.setForeground(hex2Color(theme.getTextColor()));
comboTheme.setForeground(hex2Color(theme.getTextColor()));
inputScreen.setForeground(hex2Color(theme.getTextColor()));
btn0.setForeground(hex2Color(theme.getTextColor()));
btn1.setForeground(hex2Color(theme.getTextColor()));
btn2.setForeground(hex2Color(theme.getTextColor()));
btn3.setForeground(hex2Color(theme.getTextColor()));
btn4.setForeground(hex2Color(theme.getTextColor()));
btn5.setForeground(hex2Color(theme.getTextColor()));
btn6.setForeground(hex2Color(theme.getTextColor()));
btn7.setForeground(hex2Color(theme.getTextColor()));
btn8.setForeground(hex2Color(theme.getTextColor()));
btn9.setForeground(hex2Color(theme.getTextColor()));
btnPoint.setForeground(hex2Color(theme.getTextColor()));
btnC.setForeground(hex2Color(theme.getTextColor()));
btnBack.setForeground(hex2Color(theme.getTextColor()));
btnMod.setForeground(hex2Color(theme.getTextColor()));
btnDiv.setForeground(hex2Color(theme.getTextColor()));
btnMul.setForeground(hex2Color(theme.getTextColor()));
btnSub.setForeground(hex2Color(theme.getTextColor()));
btnAdd.setForeground(hex2Color(theme.getTextColor()));
btnRoot.setForeground(hex2Color(theme.getTextColor()));
btnLog.setForeground(hex2Color(theme.getTextColor()));
btnPower.setForeground(hex2Color(theme.getTextColor()));
btnEqual.setForeground(hex2Color(theme.getBtnEqualTextColor()));
comboCalculatorType.setBackground(hex2Color(theme.getApplicationBackground()));
comboTheme.setBackground(hex2Color(theme.getApplicationBackground()));
inputScreen.setBackground(hex2Color(theme.getApplicationBackground()));
btn0.setBackground(hex2Color(theme.getNumbersBackground()));
btn1.setBackground(hex2Color(theme.getNumbersBackground()));
btn2.setBackground(hex2Color(theme.getNumbersBackground()));
btn3.setBackground(hex2Color(theme.getNumbersBackground()));
btn4.setBackground(hex2Color(theme.getNumbersBackground()));
btn5.setBackground(hex2Color(theme.getNumbersBackground()));
btn6.setBackground(hex2Color(theme.getNumbersBackground()));
btn7.setBackground(hex2Color(theme.getNumbersBackground()));
btn8.setBackground(hex2Color(theme.getNumbersBackground()));
btn9.setBackground(hex2Color(theme.getNumbersBackground()));
btnPoint.setBackground(hex2Color(theme.getNumbersBackground()));
btnC.setBackground(hex2Color(theme.getOperatorBackground()));
btnBack.setBackground(hex2Color(theme.getOperatorBackground()));
btnMod.setBackground(hex2Color(theme.getOperatorBackground()));
btnDiv.setBackground(hex2Color(theme.getOperatorBackground()));
btnMul.setBackground(hex2Color(theme.getOperatorBackground()));
btnSub.setBackground(hex2Color(theme.getOperatorBackground()));
btnAdd.setBackground(hex2Color(theme.getOperatorBackground()));
btnRoot.setBackground(hex2Color(theme.getOperatorBackground()));
btnLog.setBackground(hex2Color(theme.getOperatorBackground()));
btnPower.setBackground(hex2Color(theme.getOperatorBackground()));
btnEqual.setBackground(hex2Color(theme.getBtnEqualBackground()));
}
}

View File

@ -0,0 +1,138 @@
// @ts-ignore
import { Pattern } from './types/Pattern'; // @ts-ignore
import { Match } from './types/Match'; // @ts-ignore
import * as symbols from './internals/symbols'; // @ts-ignore
import { matchPattern } from './internals/helpers'; // @ts-ignore
type MatchState<output> =
| { matched: true; value: output }
| { matched: false; value: undefined };
const unmatched: MatchState<never> = {
matched: false,
value: undefined,
};
/**
* `match` creates a **pattern matching expression**.
* * Use `.with(pattern, handler)` to pattern match on the input.
* * Use `.exhaustive()` or `.otherwise(() => defaultValue)` to end the expression and get the result.
*
* [Read the documentation for `match` on GitHub](https://github.com/gvergnaud/ts-pattern#match)
*
* @example
* declare let input: "A" | "B";
*
* return match(input)
* .with("A", () => "It's an A!")
* .with("B", () => "It's a B!")
* .exhaustive();
*
*/
export function match<const input, output = symbols.unset>(
value: input
): Match<input, output> {
return new MatchExpression(value, unmatched) as any;
}
/**
* This class represents a match expression. It follows the
* builder pattern, we chain methods to add features to the expression
* until we call `.exhaustive`, `.otherwise` or the unsafe `.run`
* method to execute it.
*
* The types of this class aren't public, the public type definition
* can be found in src/types/Match.ts.
*/
class MatchExpression<input, output> {
constructor(private input: input, private state: MatchState<output>) {}
with(...args: any[]): MatchExpression<input, output> {
if (this.state.matched) return this;
const handler: (selection: unknown, value: input) => output =
args[args.length - 1];
const patterns: Pattern<input>[] = [args[0]];
let predicate: ((value: input) => unknown) | undefined = undefined;
if (args.length === 3 && typeof args[1] === 'function') {
// case with guard as second argument
patterns.push(args[0]);
predicate = args[1];
} else if (args.length > 2) {
// case with several patterns
patterns.push(...args.slice(1, args.length - 1));
}
let hasSelections = false;
let selected: Record<string, unknown> = {};
const select = (key: string, value: unknown) => {
hasSelections = true;
selected[key] = value;
};
const matched =
patterns.some((pattern) => matchPattern(pattern, this.input, select)) &&
(predicate ? Boolean(predicate(this.input)) : true);
const selections = hasSelections
? symbols.anonymousSelectKey in selected
? selected[symbols.anonymousSelectKey]
: selected
: this.input;
const state = matched
? {
matched: true as const,
value: handler(selections, this.input),
}
: unmatched;
return new MatchExpression(this.input, state);
}
when(
predicate: (value: input) => unknown,
handler: (selection: input, value: input) => output
): MatchExpression<input, output> {
if (this.state.matched) return this;
const matched = Boolean(predicate(this.input));
return new MatchExpression<input, output>(
this.input,
matched
? { matched: true, value: handler(this.input, this.input) }
: unmatched
);
}
otherwise(handler: (value: input) => output): output {
if (this.state.matched) return this.state.value;
return handler(this.input);
}
exhaustive(): output {
return this.run();
}
run(): output {
if (this.state.matched) return this.state.value;
let displayedValue;
try {
displayedValue = JSON.stringify(this.input);
} catch (e) {
displayedValue = this.input;
}
throw new Error(
`Pattern matching error: no pattern matches value ${displayedValue}`
);
}
returnType() {
return this;
}
}

View File

@ -0,0 +1,43 @@
import os
from pathlib import Path
from pr_agent.static_analysis.src.file_summary import FileSummary
class TestFileSummary:
def setup_method(self):
self.base_path = Path(__file__).parent
self.project_base_path = Path(__file__).parent.parent.parent.parent
def test_file_summary_cpp(self):
fname = os.path.join(self.base_path, 'example_files/AES.cpp')
if not os.path.exists(fname):
print(f"File {fname} does not exist")
return False
fname_summary = FileSummary(fname, self.project_base_path, parent_context=False, child_context=False,
header_max=0)
output = fname_summary.summarize()
expected_output = '\npr_agent/static_analysis/tests/example_files/AES.cpp:\n...⋮...\n 32│namespace Common::AES\n 33│{\n...⋮...\n 36│template <Mode AesMode>\n 37│class ContextGeneric final : public Context\n 38│{\n 39│public:\n 40│ ContextGeneric(const u8* key)\n...⋮...\n 49│ virtual bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out,\n...⋮...\n 70│#if defined(_M_X86_64)\n 71│\n...⋮...\n 84│template <Mode AesMode>\n 85│class ContextAESNI final : public Context\n 86│{\n 87│ static inline __m128i Aes128KeygenAssistFinish(__m128i key, __m128i kga)\n...⋮...\n103│ inline constexpr void StoreRoundKey(__m128i rk)\n...⋮...\n119│ inline constexpr __m128i Aes128Keygen(__m128i rk)\n...⋮...\n127│ ContextAESNI(const u8* key)\n...⋮...\n144│ inline void CryptBlock(__m128i* iv, const u8* buf_in, u8* buf_out) const\n...⋮...\n178│ inline void DecryptPipelined(__m128i* iv, const u8* buf_in, u8* buf_out) const\n...⋮...\n209│ virtual bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out,\n...⋮...\n259│#if defined(_M_ARM_64)\n260│\n261│template <Mode AesMode>\n262│class ContextNeon final : public Context\n263│{\n264│public:\n265│ template <size_t RoundIdx>\n266│ inline constexpr void StoreRoundKey(const u32* rk)\n...⋮...\n281│ ContextNeon(const u8* key)\n...⋮...\n322│ inline void CryptBlock(uint8x16_t* iv, const u8* buf_in, u8* buf_out) const\n...⋮...\n353│ virtual bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out,\n...⋮...\n381│template <Mode AesMode>\n382│std::unique_ptr<Context> CreateContext(const u8* key)\n...⋮...\n402│std::unique_ptr<Context> CreateContextEncrypt(const u8* key)\n...⋮...\n407│std::unique_ptr<Context> CreateContextDecrypt(const u8* key)\n...⋮...\n413│void CryptOFB(const u8* key, const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out, size_t size)\n...⋮...\n'
assert output == expected_output
def test_file_typescript(self):
fname = os.path.join(self.base_path, 'example_files/match.ts')
if not os.path.exists(fname):
print(f"File {fname} does not exist")
return False
fname_summary = FileSummary(fname, self.project_base_path, parent_context=False, child_context=False,
header_max=0)
output = fname_summary.summarize()
expected_output = '\npr_agent/static_analysis/tests/example_files/match.ts:\n...⋮...\n 6│type MatchState<output> =\n...⋮...\n 31│export function match<const input, output = symbols.unset>(\n...⋮...\n 46│class MatchExpression<input, output> {\n 47│ constructor(private input: input, private state: MatchState<output>) {}\n 48│\n 49│ with(...args: any[]): MatchExpression<input, output> {\n...⋮...\n 94│ when(\n...⋮...\n110│ otherwise(handler: (value: input) => output): output {\n...⋮...\n115│ exhaustive(): output {\n...⋮...\n119│ run(): output {\n...⋮...\n134│ returnType() {\n...⋮...\n'
assert output == expected_output
def test_file_java(self):
fname = os.path.join(self.base_path, 'example_files/calc.java')
if not os.path.exists(fname):
print(f"File {fname} does not exist")
return False
fname_summary = FileSummary(fname, self.project_base_path, parent_context=False, child_context=False,
header_max=0)
output = fname_summary.summarize()
expected_output = '\npr_agent/static_analysis/tests/example_files/calc.java:\n...⋮...\n 16│public class CalculatorUI {\n 17│\n...⋮...\n 84│ public double calculate(double firstNumber, double secondNumber, char operator) {\n...⋮...\n103│ private void initThemeSelector() {\n...⋮...\n118│ private void initInputScreen(int[] columns, int[] rows) {\n...⋮...\n127│ private void initCalculatorTypeSelector() {\n...⋮...\n151│ private void initButtons(int[] columns, int[] rows) {\n...⋮...\n510│ private JComboBox<String> createComboBox(String[] items, int x, int y, String toolTip) {\n...⋮...\n520│ private JButton createButton(String label, int x, int y) {\n...⋮...\n531│ private void applyTheme(Theme theme) {\n...⋮...\n'
assert output == expected_output

View File

@ -44,10 +44,8 @@ class PRCodeSuggestions:
self.is_extended = self._get_is_extended(args or []) self.is_extended = self._get_is_extended(args or [])
except: except:
self.is_extended = False self.is_extended = False
if self.is_extended: num_code_suggestions = get_settings().pr_code_suggestions.num_code_suggestions_per_chunk
num_code_suggestions = get_settings().pr_code_suggestions.num_code_suggestions_per_chunk
else:
num_code_suggestions = get_settings().pr_code_suggestions.num_code_suggestions
self.ai_handler = ai_handler() self.ai_handler = ai_handler()
self.ai_handler.main_pr_language = self.main_language self.ai_handler.main_pr_language = self.main_language
@ -77,11 +75,7 @@ class PRCodeSuggestions:
"relevant_best_practices": "", "relevant_best_practices": "",
"is_ai_metadata": get_settings().get("config.enable_ai_metadata", False), "is_ai_metadata": get_settings().get("config.enable_ai_metadata", False),
} }
if 'claude' in get_settings().config.model: self.pr_code_suggestions_prompt_system = get_settings().pr_code_suggestions_prompt.system
# prompt for Claude, with minor adjustments
self.pr_code_suggestions_prompt_system = get_settings().pr_code_suggestions_prompt_claude.system
else:
self.pr_code_suggestions_prompt_system = get_settings().pr_code_suggestions_prompt.system
self.token_handler = TokenHandler(self.git_provider.pr, self.token_handler = TokenHandler(self.git_provider.pr,
self.vars, self.vars,
@ -149,6 +143,9 @@ class PRCodeSuggestions:
pr_body += ' <!-- approve pr self-review -->' pr_body += ' <!-- approve pr self-review -->'
# add usage guide # add usage guide
if (get_settings().pr_code_suggestions.enable_chat_text and get_settings().config.is_auto_command
and isinstance(self.git_provider, GithubProvider)):
pr_body += "\n\n>💡 Need additional feedback ? start a [PR chat](https://chromewebstore.google.com/detail/ephlnjeghhogofkifjloamocljapahnl) \n\n"
if get_settings().pr_code_suggestions.enable_help_text: if get_settings().pr_code_suggestions.enable_help_text:
pr_body += "<hr>\n\n<details> <summary><strong>💡 Tool usage guide:</strong></summary><hr> \n\n" pr_body += "<hr>\n\n<details> <summary><strong>💡 Tool usage guide:</strong></summary><hr> \n\n"
pr_body += HelpMessage.get_improve_usage_guide() pr_body += HelpMessage.get_improve_usage_guide()
@ -158,6 +155,7 @@ class PRCodeSuggestions:
if get_settings().get('config', {}).get('output_relevant_configurations', False): if get_settings().get('config', {}).get('output_relevant_configurations', False):
pr_body += show_relevant_configurations(relevant_section='pr_code_suggestions') pr_body += show_relevant_configurations(relevant_section='pr_code_suggestions')
# publish the PR comment
if get_settings().pr_code_suggestions.persistent_comment: if get_settings().pr_code_suggestions.persistent_comment:
final_update_message = False final_update_message = False
self.publish_persistent_comment_with_history(pr_body, self.publish_persistent_comment_with_history(pr_body,
@ -173,10 +171,28 @@ class PRCodeSuggestions:
else: else:
self.git_provider.publish_comment(pr_body) self.git_provider.publish_comment(pr_body)
# dual publishing mode
if int(get_settings().pr_code_suggestions.dual_publishing_score_threshold) > 0:
data_above_threshold = {'code_suggestions': []}
try:
for suggestion in data['code_suggestions']:
if int(suggestion.get('score', 0)) >= int(get_settings().pr_code_suggestions.dual_publishing_score_threshold) \
and suggestion.get('improved_code'):
data_above_threshold['code_suggestions'].append(suggestion)
if not data_above_threshold['code_suggestions'][-1]['existing_code']:
get_logger().info(f'Identical existing and improved code for dual publishing found')
data_above_threshold['code_suggestions'][-1]['existing_code'] = suggestion[
'improved_code']
if data_above_threshold['code_suggestions']:
get_logger().info(
f"Publishing {len(data_above_threshold['code_suggestions'])} suggestions in dual publishing mode")
self.push_inline_code_suggestions(data_above_threshold)
except Exception as e:
get_logger().error(f"Failed to publish dual publishing suggestions, error: {e}")
else: else:
self.push_inline_code_suggestions(data) self.push_inline_code_suggestions(data)
if self.progress_response: if self.progress_response:
self.progress_response.delete() self.git_provider.remove_comment(self.progress_response)
else: else:
get_logger().info('Code suggestions generated for PR, but not published since publish_output is False.') get_logger().info('Code suggestions generated for PR, but not published since publish_output is False.')
except Exception as e: except Exception as e:
@ -601,7 +617,6 @@ class PRCodeSuggestions:
if get_settings().pr_code_suggestions.final_clip_factor != 1: if get_settings().pr_code_suggestions.final_clip_factor != 1:
max_len = max( max_len = max(
len(data_sorted), len(data_sorted),
get_settings().pr_code_suggestions.num_code_suggestions,
get_settings().pr_code_suggestions.num_code_suggestions_per_chunk, 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) new_len = int(0.5 + max_len * get_settings().pr_code_suggestions.final_clip_factor)
@ -622,14 +637,15 @@ class PRCodeSuggestions:
pr_body += "No suggestions found to improve this PR." pr_body += "No suggestions found to improve this PR."
return pr_body return pr_body
if get_settings().pr_code_suggestions.enable_intro_text and get_settings().config.is_auto_command:
pr_body += "Explore these optional code suggestions:\n\n"
language_extension_map_org = get_settings().language_extension_map_org language_extension_map_org = get_settings().language_extension_map_org
extension_to_language = {} extension_to_language = {}
for language, extensions in language_extension_map_org.items(): for language, extensions in language_extension_map_org.items():
for ext in extensions: for ext in extensions:
extension_to_language[ext] = language extension_to_language[ext] = language
pr_body = "## PR Code Suggestions ✨\n\n"
pr_body += "<table>" pr_body += "<table>"
header = f"Suggestion" header = f"Suggestion"
delta = 66 delta = 66
@ -690,7 +706,7 @@ class PRCodeSuggestions:
patch = "\n".join(patch_orig.splitlines()[5:]).strip('\n') patch = "\n".join(patch_orig.splitlines()[5:]).strip('\n')
example_code = "" example_code = ""
example_code += f"```diff\n{patch}\n```\n" example_code += f"```diff\n{patch.rstrip()}\n```\n"
if i == 0: if i == 0:
pr_body += f"""<td>\n\n""" pr_body += f"""<td>\n\n"""
else: else:
@ -746,7 +762,8 @@ class PRCodeSuggestions:
variables = {'suggestion_list': suggestion_list, variables = {'suggestion_list': suggestion_list,
'suggestion_str': suggestion_str, 'suggestion_str': suggestion_str,
"diff": patches_diff, "diff": patches_diff,
'num_code_suggestions': len(suggestion_list)} 'num_code_suggestions': len(suggestion_list),
"is_ai_metadata": get_settings().get("config.enable_ai_metadata", False)}
environment = Environment(undefined=StrictUndefined) environment = Environment(undefined=StrictUndefined)
system_prompt_reflect = environment.from_string( system_prompt_reflect = environment.from_string(
get_settings().pr_code_suggestions_reflect_prompt.system).render( get_settings().pr_code_suggestions_reflect_prompt.system).render(

View File

@ -117,9 +117,8 @@ class PRDescription:
pr_body += "<hr>\n\n<details> <summary><strong>✨ Describe tool usage guide:</strong></summary><hr> \n\n" pr_body += "<hr>\n\n<details> <summary><strong>✨ Describe tool usage guide:</strong></summary><hr> \n\n"
pr_body += HelpMessage.get_describe_usage_guide() pr_body += HelpMessage.get_describe_usage_guide()
pr_body += "\n</details>\n" pr_body += "\n</details>\n"
elif self.git_provider.is_supported("gfm_markdown") and get_settings().pr_description.enable_help_comment: elif get_settings().pr_description.enable_help_comment:
pr_body += "\n\n___\n\n> 💡 **PR-Agent usage**:" pr_body += '\n\n___\n\n> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull request to receive relevant information'
pr_body += "\n>Comment `/help` on the PR to get a list of all available PR-Agent tools and their descriptions\n\n"
# Output the relevant configurations if enabled # Output the relevant configurations if enabled
if get_settings().get('config', {}).get('output_relevant_configurations', False): if get_settings().get('config', {}).get('output_relevant_configurations', False):

View File

@ -1,106 +1,360 @@
import os
import traceback
import zipfile
import tempfile
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 retry_with_fallback_models
from pr_agent.algo.token_handler import TokenHandler
from pr_agent.algo.utils import ModelType, load_yaml
from pr_agent.config_loader import get_settings from pr_agent.config_loader import get_settings
from pr_agent.git_providers import get_git_provider, GithubProvider from pr_agent.git_providers import get_git_provider, GithubProvider, BitbucketServerProvider, \
get_git_provider_with_context
from pr_agent.log import get_logger from pr_agent.log import get_logger
def extract_header(snippet):
res = ''
lines = snippet.split('===Snippet content===')[0].split('\n')
highest_header = ''
highest_level = float('inf')
for line in lines[::-1]:
line = line.strip()
if line.startswith('Header '):
highest_header = line.split(': ')[1]
if highest_header:
res = f"#{highest_header.lower().replace(' ', '-')}"
return res
class PRHelpMessage: class PRHelpMessage:
def __init__(self, pr_url: str, args=None, ai_handler=None): def __init__(self, pr_url: str, args=None, ai_handler: partial[BaseAiHandler,] = LiteLLMAIHandler):
self.git_provider = get_git_provider()(pr_url) self.git_provider = get_git_provider_with_context(pr_url)
self.ai_handler = ai_handler()
self.question_str = self.parse_args(args)
self.num_retrieved_snippets = get_settings().get('pr_help.num_retrieved_snippets', 5)
if self.question_str:
self.vars = {
"question": self.question_str,
"snippets": "",
}
self.token_handler = TokenHandler(None,
self.vars,
get_settings().pr_help_prompts.system,
get_settings().pr_help_prompts.user)
async def _prepare_prediction(self, model: str):
try:
variables = copy.deepcopy(self.vars)
environment = Environment(undefined=StrictUndefined)
system_prompt = environment.from_string(get_settings().pr_help_prompts.system).render(variables)
user_prompt = environment.from_string(get_settings().pr_help_prompts.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)
return response
except Exception as e:
get_logger().error(f"Error while preparing prediction: {e}")
return ""
def parse_args(self, args):
if args and len(args) > 0:
question_str = " ".join(args)
else:
question_str = ""
return question_str
def get_sim_results_from_s3_db(self, embeddings):
get_logger().info("Loading the S3 index...")
sim_results = []
try:
from langchain_chroma import Chroma
from urllib import request
with tempfile.TemporaryDirectory() as temp_dir:
# Define the local file path within the temporary directory
local_file_path = os.path.join(temp_dir, 'chroma_db.zip')
bucket = 'pr-agent'
file_name = 'chroma_db.zip'
s3_url = f'https://{bucket}.s3.amazonaws.com/{file_name}'
request.urlretrieve(s3_url, local_file_path)
# # Download the file from S3 to the temporary directory
# s3 = boto3.client('s3')
# s3.download_file(bucket, file_name, local_file_path)
# Extract the contents of the zip file
with zipfile.ZipFile(local_file_path, 'r') as zip_ref:
zip_ref.extractall(temp_dir)
vectorstore = Chroma(persist_directory=temp_dir + "/chroma_db",
embedding_function=embeddings)
sim_results = vectorstore.similarity_search_with_score(self.question_str, k=self.num_retrieved_snippets)
except Exception as e:
get_logger().error(f"Error while getting sim from S3: {e}",
artifact={"traceback": traceback.format_exc()})
return sim_results
def get_sim_results_from_local_db(self, embeddings):
get_logger().info("Loading the local index...")
sim_results = []
try:
from langchain_chroma import Chroma
get_logger().info("Loading the Chroma index...")
db_path = "./docs/chroma_db.zip"
if not os.path.exists(db_path):
db_path= "/app/docs/chroma_db.zip"
if not os.path.exists(db_path):
get_logger().error("Local db not found")
return sim_results
with tempfile.TemporaryDirectory() as temp_dir:
# Extract the ZIP file
with zipfile.ZipFile(db_path, 'r') as zip_ref:
zip_ref.extractall(temp_dir)
vectorstore = Chroma(persist_directory=temp_dir + "/chroma_db",
embedding_function=embeddings)
# Do similarity search
sim_results = vectorstore.similarity_search_with_score(self.question_str, k=self.num_retrieved_snippets)
except Exception as e:
get_logger().error(f"Error while getting sim from local db: {e}",
artifact={"traceback": traceback.format_exc()})
return sim_results
def get_sim_results_from_pinecone_db(self, embeddings):
get_logger().info("Loading the Pinecone index...")
sim_results = []
try:
from langchain_pinecone import PineconeVectorStore
INDEX_NAME = "pr-agent-docs"
vectorstore = PineconeVectorStore(
index_name=INDEX_NAME, embedding=embeddings,
pinecone_api_key=get_settings().pinecone.api_key
)
# Do similarity search
sim_results = vectorstore.similarity_search_with_score(self.question_str, k=self.num_retrieved_snippets)
except Exception as e:
get_logger().error(f"Error while getting sim from Pinecone db: {e}",
artifact={"traceback": traceback.format_exc()})
return sim_results
async def run(self): async def run(self):
try: try:
if not self.git_provider.is_supported("gfm_markdown"): if self.question_str:
self.git_provider.publish_comment( get_logger().info(f'Answering a PR question about the PR {self.git_provider.pr_url} ')
"The `Help` tool requires gfm markdown, which is not supported by your code platform.")
return
get_logger().info('Getting PR Help Message...') if not get_settings().get('openai.key'):
relevant_configs = {'pr_help': dict(get_settings().pr_help), if get_settings().config.publish_output:
'config': dict(get_settings().config)} self.git_provider.publish_comment(
get_logger().debug("Relevant configs", artifacts=relevant_configs) "The `Help` tool chat feature requires an OpenAI API key for calculating embeddings")
pr_comment = "## PR Agent Walkthrough 🤖\n\n" else:
pr_comment += "Welcome to the PR Agent, an AI-powered tool for automated pull request analysis, feedback, suggestions and more.""" get_logger().error("The `Help` tool chat feature requires an OpenAI API key for calculating embeddings")
pr_comment += "\n\nHere is a list of tools you can use to interact with the PR Agent:\n" return
base_path = "https://pr-agent-docs.codium.ai/tools"
tool_names = [] # Initialize embeddings
tool_names.append(f"[DESCRIBE]({base_path}/describe/)") from langchain_openai import OpenAIEmbeddings
tool_names.append(f"[REVIEW]({base_path}/review/)") embeddings = OpenAIEmbeddings(model="text-embedding-3-small",
tool_names.append(f"[IMPROVE]({base_path}/improve/)") api_key=get_settings().openai.key)
tool_names.append(f"[UPDATE CHANGELOG]({base_path}/update_changelog/)")
tool_names.append(f"[ADD DOCS]({base_path}/documentation/) 💎")
tool_names.append(f"[TEST]({base_path}/test/) 💎")
tool_names.append(f"[IMPROVE COMPONENT]({base_path}/improve_component/) 💎")
tool_names.append(f"[ANALYZE]({base_path}/analyze/) 💎")
tool_names.append(f"[ASK]({base_path}/ask/)")
tool_names.append(f"[GENERATE CUSTOM LABELS]({base_path}/custom_labels/) 💎")
tool_names.append(f"[CI FEEDBACK]({base_path}/ci_feedback/) 💎")
tool_names.append(f"[CUSTOM PROMPT]({base_path}/custom_prompt/) 💎")
tool_names.append(f"[SIMILAR ISSUE]({base_path}/similar_issues/)")
descriptions = [] # Get similar snippets via similarity search
descriptions.append("Generates PR description - title, type, summary, code walkthrough and labels") if get_settings().pr_help.force_local_db:
descriptions.append("Adjustable feedback about the PR, possible issues, security concerns, review effort and more") sim_results = self.get_sim_results_from_local_db(embeddings)
descriptions.append("Code suggestions for improving the PR") elif get_settings().get('pinecone.api_key'):
descriptions.append("Automatically updates the changelog") sim_results = self.get_sim_results_from_pinecone_db(embeddings)
descriptions.append("Generates documentation to methods/functions/classes that changed in the PR") else:
descriptions.append("Generates unit tests for a specific component, based on the PR code change") sim_results = self.get_sim_results_from_s3_db(embeddings)
descriptions.append("Code suggestions for a specific component that changed in the PR") if not sim_results:
descriptions.append("Identifies code components that changed in the PR, and enables to interactively generate tests, docs, and code suggestions for each component") get_logger().info("Failed to load the S3 index. Loading the local index...")
descriptions.append("Answering free-text questions about the PR") sim_results = self.get_sim_results_from_local_db(embeddings)
descriptions.append("Generates custom labels for the PR, based on specific guidelines defined by the user") if not sim_results:
descriptions.append("Generates feedback and analysis for a failed CI job") get_logger().error("Failed to retrieve similar snippets. Exiting...")
descriptions.append("Generates custom suggestions for improving the PR code, derived only from a specific guidelines prompt defined by the user") return
descriptions.append("Automatically retrieves and presents similar issues")
commands =[] # Prepare relevant snippets
commands.append("`/describe`") relevant_pages_full, relevant_snippets_full_header, relevant_snippets_str =\
commands.append("`/review`") await self.prepare_relevant_snippets(sim_results)
commands.append("`/improve`") self.vars['snippets'] = relevant_snippets_str.strip()
commands.append("`/update_changelog`")
commands.append("`/add_docs`")
commands.append("`/test`")
commands.append("`/improve_component`")
commands.append("`/analyze`")
commands.append("`/ask`")
commands.append("`/generate_labels`")
commands.append("`/checks`")
commands.append("`/custom_prompt`")
commands.append("`/similar_issue`")
checkbox_list = [] # run the AI model
checkbox_list.append(" - [ ] Run <!-- /describe -->") response = await retry_with_fallback_models(self._prepare_prediction, model_type=ModelType.REGULAR)
checkbox_list.append(" - [ ] Run <!-- /review -->") response_yaml = load_yaml(response)
checkbox_list.append(" - [ ] Run <!-- /improve -->") response_str = response_yaml.get('response')
checkbox_list.append(" - [ ] Run <!-- /update_changelog -->") relevant_snippets_numbers = response_yaml.get('relevant_snippets')
checkbox_list.append(" - [ ] Run <!-- /add_docs -->")
checkbox_list.append(" - [ ] Run <!-- /test -->")
checkbox_list.append(" - [ ] Run <!-- /improve_component -->")
checkbox_list.append(" - [ ] Run <!-- /analyze -->")
checkbox_list.append("[*]")
checkbox_list.append("[*]")
checkbox_list.append("[*]")
checkbox_list.append("[*]")
checkbox_list.append("[*]")
checkbox_list.append("[*]")
checkbox_list.append("[*]")
checkbox_list.append("[*]")
if isinstance(self.git_provider, GithubProvider) and not get_settings().config.get('disable_checkboxes', False): if not relevant_snippets_numbers:
pr_comment += f"<table><tr align='left'><th align='left'>Tool</th><th align='left'>Description</th><th align='left'>Trigger Interactively :gem:</th></tr>" get_logger().info(f"Could not find relevant snippets for the question: {self.question_str}")
for i in range(len(tool_names)): if get_settings().config.publish_output:
pr_comment += f"\n<tr><td align='left'>\n\n<strong>{tool_names[i]}</strong></td>\n<td>{descriptions[i]}</td>\n<td>\n\n{checkbox_list[i]}\n</td></tr>" answer_str = f"### Question: \n{self.question_str}\n\n"
pr_comment += "</table>\n\n" answer_str += f"### Answer:\n\n"
pr_comment += f"""\n\n(1) Note that each tool be [triggered automatically](https://pr-agent-docs.codium.ai/usage-guide/automations_and_usage/#github-app-automatic-tools-when-a-new-pr-is-opened) when a new PR is opened, or called manually by [commenting on a PR](https://pr-agent-docs.codium.ai/usage-guide/automations_and_usage/#online-usage).""" answer_str += f"Could not find relevant information to answer the question. Please provide more details and try again."
pr_comment += f"""\n\n(2) Tools marked with [*] require additional parameters to be passed. For example, to invoke the `/ask` tool, you need to comment on a PR: `/ask "<question content>"`. See the relevant documentation for each tool for more details.""" self.git_provider.publish_comment(answer_str)
return ""
# prepare the answer
answer_str = ""
if response_str:
answer_str += f"### Question: \n{self.question_str}\n\n"
answer_str += f"### Answer:\n{response_str.strip()}\n\n"
answer_str += f"#### Relevant Sources:\n\n"
paged_published = []
for page in relevant_snippets_numbers:
page = int(page - 1)
if page < len(relevant_pages_full) and page >= 0:
if relevant_pages_full[page] in paged_published:
continue
link = f"{relevant_pages_full[page]}{relevant_snippets_full_header[page]}"
# answer_str += f"> - [{relevant_pages_full[page]}]({link})\n"
answer_str += f"> - {link}\n"
paged_published.append(relevant_pages_full[page])
# publish the answer
if get_settings().config.publish_output:
self.git_provider.publish_comment(answer_str)
else:
get_logger().info(f"Answer:\n{answer_str}")
else: else:
pr_comment += f"<table><tr align='left'><th align='left'>Tool</th><th align='left'>Command</th><th align='left'>Description</th></tr>" if not isinstance(self.git_provider, BitbucketServerProvider) and not self.git_provider.is_supported("gfm_markdown"):
for i in range(len(tool_names)): self.git_provider.publish_comment(
pr_comment += f"\n<tr><td align='left'>\n\n<strong>{tool_names[i]}</strong></td><td>{commands[i]}</td><td>{descriptions[i]}</td></tr>" "The `Help` tool requires gfm markdown, which is not supported by your code platform.")
pr_comment += "</table>\n\n" return
pr_comment += f"""\n\nNote that each tool be [invoked automatically](https://pr-agent-docs.codium.ai/usage-guide/automations_and_usage/) when a new PR is opened, or called manually by [commenting on a PR](https://pr-agent-docs.codium.ai/usage-guide/automations_and_usage/#online-usage)."""
if get_settings().config.publish_output: get_logger().info('Getting PR Help Message...')
self.git_provider.publish_comment(pr_comment) relevant_configs = {'pr_help': dict(get_settings().pr_help),
'config': dict(get_settings().config)}
get_logger().debug("Relevant configs", artifacts=relevant_configs)
pr_comment = "## PR Agent Walkthrough 🤖\n\n"
pr_comment += "Welcome to the PR Agent, an AI-powered tool for automated pull request analysis, feedback, suggestions and more."""
pr_comment += "\n\nHere is a list of tools you can use to interact with the PR Agent:\n"
base_path = "https://pr-agent-docs.codium.ai/tools"
tool_names = []
tool_names.append(f"[DESCRIBE]({base_path}/describe/)")
tool_names.append(f"[REVIEW]({base_path}/review/)")
tool_names.append(f"[IMPROVE]({base_path}/improve/)")
tool_names.append(f"[UPDATE CHANGELOG]({base_path}/update_changelog/)")
tool_names.append(f"[ADD DOCS]({base_path}/documentation/) 💎")
tool_names.append(f"[TEST]({base_path}/test/) 💎")
tool_names.append(f"[IMPROVE COMPONENT]({base_path}/improve_component/) 💎")
tool_names.append(f"[ANALYZE]({base_path}/analyze/) 💎")
tool_names.append(f"[ASK]({base_path}/ask/)")
tool_names.append(f"[GENERATE CUSTOM LABELS]({base_path}/custom_labels/) 💎")
tool_names.append(f"[CI FEEDBACK]({base_path}/ci_feedback/) 💎")
tool_names.append(f"[CUSTOM PROMPT]({base_path}/custom_prompt/) 💎")
tool_names.append(f"[SIMILAR ISSUE]({base_path}/similar_issues/)")
descriptions = []
descriptions.append("Generates PR description - title, type, summary, code walkthrough and labels")
descriptions.append("Adjustable feedback about the PR, possible issues, security concerns, review effort and more")
descriptions.append("Code suggestions for improving the PR")
descriptions.append("Automatically updates the changelog")
descriptions.append("Generates documentation to methods/functions/classes that changed in the PR")
descriptions.append("Generates unit tests for a specific component, based on the PR code change")
descriptions.append("Code suggestions for a specific component that changed in the PR")
descriptions.append("Identifies code components that changed in the PR, and enables to interactively generate tests, docs, and code suggestions for each component")
descriptions.append("Answering free-text questions about the PR")
descriptions.append("Generates custom labels for the PR, based on specific guidelines defined by the user")
descriptions.append("Generates feedback and analysis for a failed CI job")
descriptions.append("Generates custom suggestions for improving the PR code, derived only from a specific guidelines prompt defined by the user")
descriptions.append("Automatically retrieves and presents similar issues")
commands =[]
commands.append("`/describe`")
commands.append("`/review`")
commands.append("`/improve`")
commands.append("`/update_changelog`")
commands.append("`/add_docs`")
commands.append("`/test`")
commands.append("`/improve_component`")
commands.append("`/analyze`")
commands.append("`/ask`")
commands.append("`/generate_labels`")
commands.append("`/checks`")
commands.append("`/custom_prompt`")
commands.append("`/similar_issue`")
checkbox_list = []
checkbox_list.append(" - [ ] Run <!-- /describe -->")
checkbox_list.append(" - [ ] Run <!-- /review -->")
checkbox_list.append(" - [ ] Run <!-- /improve -->")
checkbox_list.append(" - [ ] Run <!-- /update_changelog -->")
checkbox_list.append(" - [ ] Run <!-- /add_docs -->")
checkbox_list.append(" - [ ] Run <!-- /test -->")
checkbox_list.append(" - [ ] Run <!-- /improve_component -->")
checkbox_list.append(" - [ ] Run <!-- /analyze -->")
checkbox_list.append("[*]")
checkbox_list.append("[*]")
checkbox_list.append("[*]")
checkbox_list.append("[*]")
checkbox_list.append("[*]")
checkbox_list.append("[*]")
checkbox_list.append("[*]")
checkbox_list.append("[*]")
if isinstance(self.git_provider, GithubProvider) and not get_settings().config.get('disable_checkboxes', False):
pr_comment += f"<table><tr align='left'><th align='left'>Tool</th><th align='left'>Description</th><th align='left'>Trigger Interactively :gem:</th></tr>"
for i in range(len(tool_names)):
pr_comment += f"\n<tr><td align='left'>\n\n<strong>{tool_names[i]}</strong></td>\n<td>{descriptions[i]}</td>\n<td>\n\n{checkbox_list[i]}\n</td></tr>"
pr_comment += "</table>\n\n"
pr_comment += f"""\n\n(1) Note that each tool be [triggered automatically](https://pr-agent-docs.codium.ai/usage-guide/automations_and_usage/#github-app-automatic-tools-when-a-new-pr-is-opened) when a new PR is opened, or called manually by [commenting on a PR](https://pr-agent-docs.codium.ai/usage-guide/automations_and_usage/#online-usage)."""
pr_comment += f"""\n\n(2) Tools marked with [*] require additional parameters to be passed. For example, to invoke the `/ask` tool, you need to comment on a PR: `/ask "<question content>"`. See the relevant documentation for each tool for more details."""
elif isinstance(self.git_provider, BitbucketServerProvider):
# only support basic commands in BBDC
pr_comment = generate_bbdc_table(tool_names[:4], descriptions[:4])
else:
pr_comment += f"<table><tr align='left'><th align='left'>Tool</th><th align='left'>Command</th><th align='left'>Description</th></tr>"
for i in range(len(tool_names)):
pr_comment += f"\n<tr><td align='left'>\n\n<strong>{tool_names[i]}</strong></td><td>{commands[i]}</td><td>{descriptions[i]}</td></tr>"
pr_comment += "</table>\n\n"
pr_comment += f"""\n\nNote that each tool be [invoked automatically](https://pr-agent-docs.codium.ai/usage-guide/automations_and_usage/) when a new PR is opened, or called manually by [commenting on a PR](https://pr-agent-docs.codium.ai/usage-guide/automations_and_usage/#online-usage)."""
if get_settings().config.publish_output:
self.git_provider.publish_comment(pr_comment)
except Exception as e: except Exception as e:
get_logger().error(f"Error while running PRHelpMessage: {e}") get_logger().exception(f"Error while running PRHelpMessage: {e}")
return "" return ""
async def prepare_relevant_snippets(self, sim_results):
# Get relevant snippets
relevant_snippets_full = []
relevant_pages_full = []
relevant_snippets_full_header = []
th = 0.75
for s in sim_results:
page = s[0].metadata['source']
content = s[0].page_content
score = s[1]
relevant_snippets_full.append(content)
relevant_snippets_full_header.append(extract_header(content))
relevant_pages_full.append(page)
# build the snippets string
relevant_snippets_str = ""
for i, s in enumerate(relevant_snippets_full):
relevant_snippets_str += f"Snippet {i+1}:\n\n{s}\n\n"
relevant_snippets_str += "-------------------\n\n"
return relevant_pages_full, relevant_snippets_full_header, relevant_snippets_str
def generate_bbdc_table(column_arr_1, column_arr_2):
# Generating header row
header_row = "| Tool | Description | \n"
# Generating separator row
separator_row = "|--|--|\n"
# Generating data rows
data_rows = ""
max_len = max(len(column_arr_1), len(column_arr_2))
for i in range(max_len):
col1 = column_arr_1[i] if i < len(column_arr_1) else ""
col2 = column_arr_2[i] if i < len(column_arr_2) else ""
data_rows += f"| {col1} | {col2} |\n"
# Combine all parts to form the complete table
markdown_table = header_row + separator_row + data_rows
return markdown_table

View File

@ -1,4 +1,4 @@
aiohttp==3.9.4 aiohttp==3.9.5
anthropic[vertex]==0.21.3 anthropic[vertex]==0.21.3
atlassian-python-api==3.41.4 atlassian-python-api==3.41.4
azure-devops==7.1.0b3 azure-devops==7.1.0b3
@ -13,7 +13,7 @@ Jinja2==3.1.2
litellm==1.43.13 litellm==1.43.13
loguru==0.7.2 loguru==0.7.2
msrest==0.7.1 msrest==0.7.1
openai==1.40.6 openai==1.46.0
pytest==7.4.0 pytest==7.4.0
PyGithub==1.59.* PyGithub==1.59.*
PyYAML==6.0.1 PyYAML==6.0.1
@ -28,6 +28,18 @@ gunicorn==22.0.0
pytest-cov==5.0.0 pytest-cov==5.0.0
pydantic==2.8.2 pydantic==2.8.2
html2text==2024.2.26 html2text==2024.2.26
# help bot
langchain==0.3.0
langchain-openai==0.2.0
langchain-pinecone==0.2.0
langchain-chroma==0.1.4
chromadb==0.5.7
#
tree_sitter==0.21.3
tree_sitter_languages==1.10.2
grep_ast==0.3.3
#Pygments==2.18.0
# Uncomment the following lines to enable the 'similar issue' tool # Uncomment the following lines to enable the 'similar issue' tool
# pinecone-client # pinecone-client
# pinecone-datasets @ git+https://github.com/mrT23/pinecone-datasets.git@main # pinecone-datasets @ git+https://github.com/mrT23/pinecone-datasets.git@main

View File

@ -3,4 +3,3 @@
from setuptools import setup from setuptools import setup
setup() setup()
print("aaa")

View File

@ -53,7 +53,7 @@ class TestConvertToMarkdown:
'relevant_line': '[return ""](https://github.com/Codium-ai/pr-agent-pro/pull/102/files#diff-52d45f12b836f77ed1aef86e972e65404634ea4e2a6083fb71a9b0f9bb9e062fR199)'}]} 'relevant_line': '[return ""](https://github.com/Codium-ai/pr-agent-pro/pull/102/files#diff-52d45f12b836f77ed1aef86e972e65404634ea4e2a6083fb71a9b0f9bb9e062fR199)'}]}
expected_output = f'{PRReviewHeader.REGULAR.value} 🔍\n\n<table>\n<tr><td>⏱️&nbsp;<strong>Estimated effort to review</strong>: 1 🔵⚪⚪⚪⚪</td></tr>\n<tr><td>🧪&nbsp;<strong>No relevant tests</strong></td></tr>\n<tr><td>&nbsp;<strong>Possible issues</strong>: No\n</td></tr>\n<tr><td>🔒&nbsp;<strong>No security concerns identified</strong></td></tr>\n</table>\n\n\n<details><summary> <strong>Code feedback:</strong></summary>\n\n<hr><table><tr><td>relevant file</td><td>pr_agent/git_providers/git_provider.py\n</td></tr><tr><td>suggestion &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td><td>\n\n<strong>\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</strong>\n</td></tr><tr><td>relevant line</td><td><a href=\'https://github.com/Codium-ai/pr-agent-pro/pull/102/files#diff-52d45f12b836f77ed1aef86e972e65404634ea4e2a6083fb71a9b0f9bb9e062fR199\'>return ""</a></td></tr></table><hr>\n\n</details>' expected_output = f'{PRReviewHeader.REGULAR.value} 🔍\n\nHere are some key observations to aid the review process:\n\n<table>\n<tr><td>⏱️&nbsp;<strong>Estimated effort to review</strong>: 1 🔵⚪⚪⚪⚪</td></tr>\n<tr><td>🧪&nbsp;<strong>No relevant tests</strong></td></tr>\n<tr><td>&nbsp;<strong>Possible issues</strong>: No\n</td></tr>\n<tr><td>🔒&nbsp;<strong>No security concerns identified</strong></td></tr>\n</table>\n\n\n<details><summary> <strong>Code feedback:</strong></summary>\n\n<hr><table><tr><td>relevant file</td><td>pr_agent/git_providers/git_provider.py\n</td></tr><tr><td>suggestion &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td><td>\n\n<strong>\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</strong>\n</td></tr><tr><td>relevant line</td><td><a href=\'https://github.com/Codium-ai/pr-agent-pro/pull/102/files#diff-52d45f12b836f77ed1aef86e972e65404634ea4e2a6083fb71a9b0f9bb9e062fR199\'>return ""</a></td></tr></table><hr>\n\n</details>'
assert convert_to_markdown_v2(input_data).strip() == expected_output.strip() assert convert_to_markdown_v2(input_data).strip() == expected_output.strip()