2023-08-01 14:43:26 +03:00
import shlex
2023-12-17 16:52:03 +02:00
from functools import partial
2023-12-13 08:16:02 +08:00
from pr_agent . algo . ai_handlers . base_ai_handler import BaseAiHandler
2023-12-14 08:53:22 +02:00
from pr_agent . algo . ai_handlers . litellm_ai_handler import LiteLLMAIHandler
2025-02-20 17:51:16 +02:00
from pr_agent . algo . cli_args import CliArgs
2023-08-01 14:43:26 +03:00
from pr_agent . algo . utils import update_settings_from_args
from pr_agent . config_loader import get_settings
2023-10-14 01:39:05 +03:00
from pr_agent . git_providers . utils import apply_repo_settings
2023-12-13 08:16:45 +08:00
from pr_agent . log import get_logger
2023-09-27 16:48:17 +03:00
from pr_agent . tools . pr_add_docs import PRAddDocs
2023-07-16 15:42:50 +03:00
from pr_agent . tools . pr_code_suggestions import PRCodeSuggestions
2023-10-16 14:56:00 +03:00
from pr_agent . tools . pr_config import PRConfig
2023-07-16 15:42:50 +03:00
from pr_agent . tools . pr_description import PRDescription
2023-10-26 23:28:33 +03:00
from pr_agent . tools . pr_generate_labels import PRGenerateLabels
2024-02-18 12:01:16 +02:00
from pr_agent . tools . pr_help_message import PRHelpMessage
2024-02-15 14:25:22 +02:00
from pr_agent . tools . pr_line_questions import PR_LineQuestions
2023-07-06 00:21:08 +03:00
from pr_agent . tools . pr_questions import PRQuestions
from pr_agent . tools . pr_reviewer import PRReviewer
2023-10-16 14:56:00 +03:00
from pr_agent . tools . pr_similar_issue import PRSimilarIssue
2023-07-26 20:05:18 +03:00
from pr_agent . tools . pr_update_changelog import PRUpdateChangelog
2023-07-06 00:21:08 +03:00
2023-08-01 14:43:26 +03:00
command2class = {
2023-08-16 16:17:00 -04:00
" auto_review " : PRReviewer ,
2023-08-01 14:43:26 +03:00
" answer " : PRReviewer ,
" review " : PRReviewer ,
" review_pr " : PRReviewer ,
" describe " : PRDescription ,
" describe_pr " : PRDescription ,
" improve " : PRCodeSuggestions ,
" improve_code " : PRCodeSuggestions ,
" ask " : PRQuestions ,
" ask_question " : PRQuestions ,
2024-02-15 14:25:22 +02:00
" ask_line " : PR_LineQuestions ,
2023-08-01 14:43:26 +03:00
" update_changelog " : PRUpdateChangelog ,
2023-08-02 16:42:54 +03:00
" config " : PRConfig ,
" settings " : PRConfig ,
2024-02-18 12:01:16 +02:00
" help " : PRHelpMessage ,
2023-08-20 15:01:06 +03:00
" similar_issue " : PRSimilarIssue ,
2023-09-27 16:48:17 +03:00
" add_docs " : PRAddDocs ,
2023-10-26 23:28:33 +03:00
" generate_labels " : PRGenerateLabels ,
2023-08-01 14:43:26 +03:00
}
commands = list ( command2class . keys ( ) )
2023-07-06 00:21:08 +03:00
2024-06-03 23:58:31 +08:00
2025-02-26 14:37:15 +02:00
2023-07-06 00:21:08 +03:00
class PRAgent :
2023-12-17 16:52:03 +02:00
def __init__ ( self , ai_handler : partial [ BaseAiHandler , ] = LiteLLMAIHandler ) :
2024-06-03 23:58:31 +08:00
self . ai_handler = ai_handler # will be initialized in run_action
2023-07-06 00:21:08 +03:00
2023-08-07 18:09:39 +03:00
async def handle_request ( self , pr_url , request , notify = None ) - > bool :
2023-08-01 17:44:08 +03:00
# First, apply repo specific settings if exists
2023-10-14 01:39:05 +03:00
apply_repo_settings ( pr_url )
2023-08-01 17:44:08 +03:00
# Then, apply user specific settings if exists
2023-11-12 16:11:34 +02:00
if isinstance ( request , str ) :
request = request . replace ( " ' " , " \\ ' " )
lexer = shlex . shlex ( request , posix = True )
lexer . whitespace_split = True
action , * args = list ( lexer )
else :
action , * args = request
2024-02-06 08:31:36 +02:00
2025-02-20 17:51:16 +02:00
# validate args
is_valid , arg = CliArgs . validate_user_args ( args )
if not is_valid :
get_logger ( ) . error (
f " CLI argument for param ' { arg } ' is forbidden. Use instead a configuration file. "
)
return False
# Update settings from args
2023-08-01 14:43:26 +03:00
args = update_settings_from_args ( args )
2023-08-01 17:44:08 +03:00
2025-02-26 14:37:15 +02:00
# Append the response language in the extra instructions
2025-02-27 10:50:28 +02:00
response_language = get_settings ( ) . config . get ( ' response_language ' , ' en-us ' )
if response_language . lower ( ) != ' en-us ' :
get_logger ( ) . info ( f ' User has set the response language to: { response_language } ' )
2025-02-26 14:37:15 +02:00
for key in get_settings ( ) :
setting = get_settings ( ) . get ( key )
if str ( type ( setting ) ) == " <class ' dynaconf.utils.boxing.DynaBox ' > " :
if hasattr ( setting , ' extra_instructions ' ) :
2025-02-27 10:50:28 +02:00
current_extra_instructions = setting . extra_instructions
if current_extra_instructions :
2025-02-27 11:06:31 +02:00
setting . extra_instructions = current_extra_instructions + f " \n ====== \n \n In addition, Your response MUST be written in the language corresponding to local code: { response_language } . This is crucial. "
2025-02-27 10:50:28 +02:00
else :
2025-02-27 11:06:31 +02:00
setting . extra_instructions = f " Your response MUST be written in the language corresponding to locale code: ' { response_language } ' . This is crucial. "
2025-02-26 14:37:15 +02:00
2023-08-01 14:43:26 +03:00
action = action . lstrip ( " / " ) . lower ( )
2024-04-12 20:32:47 +03:00
if action not in command2class :
2024-12-25 08:22:53 +02:00
get_logger ( ) . error ( f " Unknown command: { action } " )
2024-04-12 20:32:47 +03:00
return False
2024-08-17 09:15:05 +03:00
with get_logger ( ) . contextualize ( command = action , pr_url = pr_url ) :
2024-02-26 16:15:23 +02:00
get_logger ( ) . info ( " PR-Agent request handler started " , analytics = True )
2024-02-15 12:13:56 +02:00
if action == " answer " :
if notify :
notify ( )
await PRReviewer ( pr_url , is_answer = True , args = args , ai_handler = self . ai_handler ) . run ( )
elif action == " auto_review " :
await PRReviewer ( pr_url , is_auto = True , args = args , ai_handler = self . ai_handler ) . run ( )
elif action in command2class :
if notify :
notify ( )
await command2class [ action ] ( pr_url , ai_handler = self . ai_handler , args = args ) . run ( )
else :
return False
return True