Skip to content

Commit

Permalink
Merge pull request Codium-ai#159 from Codium-ai/tr/edit_any_config_se…
Browse files Browse the repository at this point in the history
…tting

The Configurator Strikes Back
  • Loading branch information
mrT23 authored Jul 30, 2023
2 parents 3cce9fa + a0b5b46 commit 2623db3
Show file tree
Hide file tree
Showing 16 changed files with 120 additions and 57 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 2023-07-30

### Enhanced
- Added the ability to modify any configuration parameter from 'configuration.toml' on-the-fly.
- Updated the command line interface and bot commands to accept configuration changes as arguments.
- Improved the PR agent to handle additional arguments for each action.

## 2023-07-28

### Improved
Expand Down
6 changes: 3 additions & 3 deletions pr_agent/agent/pr_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@ def __init__(self):
async def handle_request(self, pr_url, request) -> bool:
action, *args = request.strip().split()
if any(cmd == action for cmd in ["/answer"]):
await PRReviewer(pr_url, is_answer=True).review()
await PRReviewer(pr_url, is_answer=True, args=args).review()
elif any(cmd == action for cmd in ["/review", "/review_pr", "/reflect_and_review"]):
if settings.pr_reviewer.ask_and_reflect or "/reflect_and_review" in request:
await PRInformationFromUser(pr_url).generate_questions()
await PRInformationFromUser(pr_url, args=args).generate_questions()
else:
await PRReviewer(pr_url, args=args).review()
elif any(cmd == action for cmd in ["/describe", "/describe_pr"]):
await PRDescription(pr_url, args=args).describe()
elif any(cmd == action for cmd in ["/improve", "/improve_code"]):
await PRCodeSuggestions(pr_url).suggest()
await PRCodeSuggestions(pr_url, args=args).suggest()
elif any(cmd == action for cmd in ["/ask", "/ask_question"]):
await PRQuestions(pr_url, args=args).answer()
elif any(cmd == action for cmd in ["/update_changelog"]):
Expand Down
44 changes: 44 additions & 0 deletions pr_agent/algo/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from __future__ import annotations
from typing import List

import difflib
from datetime import datetime
Expand Down Expand Up @@ -211,3 +212,46 @@ def load_large_diff(file, new_file_content_str: str, original_file_content_str:
except Exception:
pass
return patch


def update_settings_from_args(args: List[str]) -> None:
"""
Update the settings of the Dynaconf object based on the arguments passed to the function.
Args:
args: A list of arguments passed to the function.
Example args: ['--pr_code_suggestions.extra_instructions="be funny',
'--pr_code_suggestions.num_code_suggestions=3']
Returns:
None
Raises:
ValueError: If the argument is not in the correct format.
"""
if args:
for arg in args:
try:
arg = arg.strip('-').strip()
vals = arg.split('=')
if len(vals) != 2:
raise ValueError(f'Invalid argument format: {arg}')
key, value = vals
keys = key.split('.')
d = settings
for i, k in enumerate(keys[:-1]):
if k not in d:
raise ValueError(f'Invalid setting: {key}')
d = d[k]
if keys[-1] not in d:
raise ValueError(f'Invalid setting: {key}')
if isinstance(d[keys[-1]], bool):
d[keys[-1]] = value.lower() in ("yes", "true", "t", "1")
else:
d[keys[-1]] = type(d[keys[-1]])(value)
logging.info(f'Updated setting {key} to: "{value}"')
except ValueError as e:
logging.error(str(e))
except Exception as e:
logging.error(f'Failed to parse argument {arg}: {e}')
7 changes: 5 additions & 2 deletions pr_agent/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ def run(args=None):
improve / improve_code - Suggest improvements to the code in the PR as pull request comments ready to commit.
reflect - Ask the PR author questions about the PR.
update_changelog - Update the changelog based on the PR's contents.
To edit any configuration parameter from 'configuration.toml', just add -config_path=<value>.
For example: '- cli.py --pr-url=... review --pr_reviewer.extra_instructions="focus on the file: ..."'
""")
parser.add_argument('--pr_url', type=str, help='The URL of the PR to review', required=True)
parser.add_argument('command', type=str, help='The', choices=['review', 'review_pr',
Expand Down Expand Up @@ -79,7 +82,7 @@ def _handle_describe_command(pr_url: str, rest: list):

def _handle_improve_command(pr_url: str, rest: list):
print(f"PR code suggestions: {pr_url}")
reviewer = PRCodeSuggestions(pr_url)
reviewer = PRCodeSuggestions(pr_url, args=rest)
asyncio.run(reviewer.suggest())


Expand All @@ -97,7 +100,7 @@ def _handle_reflect_command(pr_url: str, rest: list):

def _handle_review_after_reflect_command(pr_url: str, rest: list):
print(f"Processing author's answers and sending review: {pr_url}")
reviewer = PRReviewer(pr_url, cli_mode=True, is_answer=True)
reviewer = PRReviewer(pr_url, cli_mode=True, is_answer=True, args=rest)
asyncio.run(reviewer.review())

def _handle_update_changelog(pr_url: str, rest: list):
Expand Down
2 changes: 1 addition & 1 deletion pr_agent/config_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"settings/pr_description_prompts.toml",
"settings/pr_code_suggestions_prompts.toml",
"settings/pr_information_from_user_prompts.toml",
"settings/pr_update_changelog.toml",
"settings/pr_update_changelog_prompts.toml",
"settings_prod/.secrets.toml"
]]
)
Expand Down
11 changes: 5 additions & 6 deletions pr_agent/servers/help.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
commands_text = "> **/review [-i]**: Request a review of your Pull Request. For an incremental review, which only " \
"considers changes since the last review, include the '-i' option.\n" \
"> **/describe [-c]**: Modify the PR title and description based on the contents of the PR. " \
"To get the description as comment instead of modifying the PR description, " \
"include the '-c' option.\n" \
"> **/improve**: Suggest improvements to the code in the PR. " \
"These will be provided as pull request comments, ready to commit.\n" \
"> **/ask \\<QUESTION\\>**: Pose a question about the PR.\n"
"> **/describe**: Modify the PR title and description based on the contents of the PR.\n" \
"> **/improve**: Suggest improvements to the code in the PR. \n" \
"> **/ask \\<QUESTION\\>**: Pose a question about the PR.\n\n" \
"To edit any configuration parameter from 'configuration.toml', just add -config_path=<value>. " \
"For example: '/review --pr_reviewer.extra_instructions=\"focus on the file: ...\"'" \


def bot_help_text(user: str):
Expand Down
14 changes: 9 additions & 5 deletions pr_agent/settings/configuration.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,29 @@ publish_output_progress=true
verbosity_level=0 # 0,1,2
use_extra_bad_extensions=false

[pr_reviewer]
[pr_reviewer] # /review #
require_focused_review=true
require_score_review=false
require_tests_review=true
require_security_review=true
num_code_suggestions=0
inline_code_comments = true
ask_and_reflect=false
extra_instructions = ""

[pr_description]
[pr_description] # /describe #
publish_description_as_comment=false
extra_instructions = ""

[pr_questions]
[pr_questions] # /ask #

[pr_code_suggestions]
[pr_code_suggestions] # /improve #
num_code_suggestions=4
extra_instructions = ""

[pr_update_changelog]
[pr_update_changelog] # /update_changelog #
push_changelog_changes=false
extra_instructions = ""

[github]
# The type of deployment to create. Valid values are 'app' or 'user'.
Expand Down
6 changes: 6 additions & 0 deletions pr_agent/settings/pr_code_suggestions_prompts.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ Your task is to provide meaningfull non-trivial code suggestions to improve the
- Make sure not to provide suggestions repeating modifications already implemented in the new PR code (the '+' lines).
- Don't output line numbers in the 'improved code' snippets.
{%- if extra_instructions %}
Extra instructions from the user:
{{ extra_instructions }}
{% endif %}
You must use the following JSON schema to format your answer:
```json
{
Expand Down
6 changes: 6 additions & 0 deletions pr_agent/settings/pr_description_prompts.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ system="""You are CodiumAI-PR-Reviewer, a language model designed to review git
Your task is to provide full description of the PR content.
- Make sure not to focus the new PR code (the '+' lines).
{%- if extra_instructions %}
Extra instructions from the user:
{{ extra_instructions }}
{% endif %}
You must use the following JSON schema to format your answer:
```json
{
Expand Down
6 changes: 6 additions & 0 deletions pr_agent/settings/pr_reviewer_prompts.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ Your task is to provide constructive and concise feedback for the PR, and also p
- Make sure not to provide suggestions repeating modifications already implemented in the new PR code (the '+' lines).
{%- endif %}
{%- if extra_instructions %}
Extra instructions from the user:
{{ extra_instructions }}
{% endif %}
You must use the following JSON schema to format your answer:
```json
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ Your task is to update the CHANGELOG.md file of the project, to shortly summariz
- The output should match the existing CHANGELOG.md format, style and conventions, so it will look like a natural part of the file. For example, if previous changes were summarized in a single line, you should do the same.
- Don't repeat previous changes. Generate only new content, that is not already in the CHANGELOG.md file.
- Be general, and avoid specific details, files, etc. The output should be minimal, no more than 3-4 short lines. Ignore non-relevant subsections.
{%- if extra_instructions %}
Extra instructions from the user:
{{ extra_instructions }}
{%- endif %}
"""

user="""PR Info:
Expand Down
10 changes: 7 additions & 3 deletions pr_agent/tools/pr_code_suggestions.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,21 @@
from pr_agent.algo.ai_handler import AiHandler
from pr_agent.algo.pr_processing import get_pr_diff, retry_with_fallback_models
from pr_agent.algo.token_handler import TokenHandler
from pr_agent.algo.utils import try_fix_json
from pr_agent.algo.utils import try_fix_json, update_settings_from_args
from pr_agent.config_loader import settings
from pr_agent.git_providers import BitbucketProvider, get_git_provider
from pr_agent.git_providers.git_provider import get_main_pr_language


class PRCodeSuggestions:
def __init__(self, pr_url: str, cli_mode=False):
def __init__(self, pr_url: str, cli_mode=False, args: list = None):

self.git_provider = get_git_provider()(pr_url)
self.main_language = get_main_pr_language(
self.git_provider.get_languages(), self.git_provider.get_files()
)
update_settings_from_args(args)

self.ai_handler = AiHandler()
self.patches_diff = None
self.prediction = None
Expand All @@ -31,7 +33,8 @@ def __init__(self, pr_url: str, cli_mode=False):
"description": self.git_provider.get_pr_description(),
"language": self.main_language,
"diff": "", # empty diff for initial calculation
'num_code_suggestions': settings.pr_code_suggestions.num_code_suggestions,
"num_code_suggestions": settings.pr_code_suggestions.num_code_suggestions,
"extra_instructions": settings.pr_code_suggestions.extra_instructions,
}
self.token_handler = TokenHandler(self.git_provider.pr,
self.vars,
Expand Down Expand Up @@ -137,3 +140,4 @@ def dedent_code(self, relevant_file, relevant_lines_start, new_code_snippet):
logging.info(f"Could not dedent code snippet for file {relevant_file}, error: {e}")

return new_code_snippet

24 changes: 5 additions & 19 deletions pr_agent/tools/pr_description.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from pr_agent.algo.ai_handler import AiHandler
from pr_agent.algo.pr_processing import get_pr_diff, retry_with_fallback_models
from pr_agent.algo.token_handler import TokenHandler
from pr_agent.algo.utils import update_settings_from_args
from pr_agent.config_loader import settings
from pr_agent.git_providers import get_git_provider
from pr_agent.git_providers.git_provider import get_main_pr_language
Expand All @@ -21,8 +22,8 @@ def __init__(self, pr_url: str, args: list = None):
pr_url (str): The URL of the pull request.
args (list, optional): List of arguments passed to the PRDescription class. Defaults to None.
"""
self.parse_args(args)
update_settings_from_args(args)

# Initialize the git provider and main PR language
self.git_provider = get_git_provider()(pr_url)
self.main_pr_language = get_main_pr_language(
Expand All @@ -39,6 +40,7 @@ def __init__(self, pr_url: str, args: list = None):
"description": self.git_provider.get_pr_description(),
"language": self.main_pr_language,
"diff": "", # empty diff for initial calculation
"extra_instructions": settings.pr_description.extra_instructions,
}

# Initialize the token handler
Expand All @@ -53,22 +55,6 @@ def __init__(self, pr_url: str, args: list = None):
self.patches_diff = None
self.prediction = None

def parse_args(self, args: List[str]) -> None:
"""
Parse the arguments passed to the PRDescription class and set the 'publish_description_as_comment' attribute accordingly.
Args:
args: A list of arguments passed to the PRReviewer class.
Returns:
None
"""
self.publish_description_as_comment = settings.pr_description.publish_description_as_comment
if args and len(args) >= 1:
arg = args[0]
if arg == "-c":
self.publish_description_as_comment = True

async def describe(self):
"""
Generates a PR description using an AI model and publishes it to the PR.
Expand All @@ -84,7 +70,7 @@ async def describe(self):

if settings.config.publish_output:
logging.info('Pushing answer...')
if self.publish_description_as_comment:
if settings.pr_description.publish_description_as_comment:
self.git_provider.publish_comment(markdown_text)
else:
self.git_provider.publish_description(pr_title, pr_body)
Expand Down
2 changes: 1 addition & 1 deletion pr_agent/tools/pr_information_from_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@


class PRInformationFromUser:
def __init__(self, pr_url: str):
def __init__(self, pr_url: str, args: list = None):
self.git_provider = get_git_provider()(pr_url)
self.main_pr_language = get_main_pr_language(
self.git_provider.get_languages(), self.git_provider.get_files()
Expand Down
6 changes: 4 additions & 2 deletions pr_agent/tools/pr_reviewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from pr_agent.algo.ai_handler import AiHandler
from pr_agent.algo.pr_processing import get_pr_diff, retry_with_fallback_models
from pr_agent.algo.token_handler import TokenHandler
from pr_agent.algo.utils import convert_to_markdown, try_fix_json
from pr_agent.algo.utils import convert_to_markdown, try_fix_json, update_settings_from_args
from pr_agent.config_loader import settings
from pr_agent.git_providers import get_git_provider
from pr_agent.git_providers.git_provider import get_main_pr_language, IncrementalPR
Expand All @@ -30,7 +30,8 @@ def __init__(self, pr_url: str, cli_mode: bool = False, is_answer: bool = False,
is_answer (bool, optional): Indicates whether the review is being done in answer mode. Defaults to False.
args (list, optional): List of arguments passed to the PRReviewer class. Defaults to None.
"""
self.parse_args(args)
update_settings_from_args(args)
self.parse_args(args) # -i command

self.git_provider = get_git_provider()(pr_url, incremental=self.incremental)
self.main_language = get_main_pr_language(
Expand Down Expand Up @@ -60,6 +61,7 @@ def __init__(self, pr_url: str, cli_mode: bool = False, is_answer: bool = False,
'num_code_suggestions': settings.pr_reviewer.num_code_suggestions,
'question_str': question_str,
'answer_str': answer_str,
"extra_instructions": settings.pr_reviewer.extra_instructions,
}

self.token_handler = TokenHandler(
Expand Down
Loading

0 comments on commit 2623db3

Please sign in to comment.