mirror of
https://github.com/qodo-ai/pr-agent.git
synced 2025-07-04 12:50:38 +08:00
Merge pull request #942 from barnett-yuxiang/main
Update Python code formatting, configuration loading, and local model additions
This commit is contained in:
@ -1,17 +1,17 @@
|
||||
|
||||
After [installation](https://codium-ai.github.io/Docs-PR-Agent/installation/), there are three basic ways to invoke CodiumAI PR-Agent:
|
||||
After [installation](https://pr-agent-docs.codium.ai/installation/), there are three basic ways to invoke CodiumAI PR-Agent:
|
||||
|
||||
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
|
||||
3. Enabling PR-Agent tools to run automatically when a new PR is opened
|
||||
|
||||
|
||||
Specifically, CLI commands can be issued by invoking a pre-built [docker image](https://codium-ai.github.io/Docs-PR-Agent/installation/#run-from-source), or by invoking a [locally cloned repo](https://codium-ai.github.io/Docs-PR-Agent/installation/#locally).
|
||||
For online usage, you will need to setup either a [GitHub App](https://codium-ai.github.io/Docs-PR-Agent/installation/#run-as-a-github-app), or a [GitHub Action](https://codium-ai.github.io/Docs-PR-Agent/installation/#run-as-a-github-action).
|
||||
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).
|
||||
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 App and GitHub Action also enable to run PR-Agent specific tool automatically when a new PR is opened.
|
||||
|
||||
|
||||
**git provider**: The [git_provider](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml#L4) field in the 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 the configuration file determines the GIT provider that will be used by PR-Agent. Currently, the following providers are supported:
|
||||
`
|
||||
"github", "gitlab", "bitbucket", "azure", "codecommit", "local", "gerrit"
|
||||
`
|
||||
|
@ -46,6 +46,7 @@ command2class = {
|
||||
|
||||
commands = list(command2class.keys())
|
||||
|
||||
|
||||
class PRAgent:
|
||||
def __init__(self, ai_handler: partial[BaseAiHandler,] = LiteLLMAIHandler):
|
||||
self.ai_handler = ai_handler # will be initialized in run_action
|
||||
@ -68,7 +69,9 @@ class PRAgent:
|
||||
for forbidden_arg in self.forbidden_cli_args:
|
||||
for arg in args:
|
||||
if forbidden_arg in arg:
|
||||
get_logger().error(f"CLI argument for param '{forbidden_arg}' is forbidden. Use instead a configuration file.")
|
||||
get_logger().error(
|
||||
f"CLI argument for param '{forbidden_arg}' is forbidden. Use instead a configuration file."
|
||||
)
|
||||
return False
|
||||
args = update_settings_from_args(args)
|
||||
|
||||
@ -94,4 +97,3 @@ class PRAgent:
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
@ -36,4 +36,5 @@ MAX_TOKENS = {
|
||||
'bedrock/anthropic.claude-3-haiku-20240307-v1:0': 100000,
|
||||
'groq/llama3-8b-8192': 8192,
|
||||
'groq/llama3-70b-8192': 8192,
|
||||
'ollama/llama3': 4096,
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
|
||||
class BaseAiHandler(ABC):
|
||||
"""
|
||||
This class defines the interface for an AI handler to be used by the PR Agents.
|
||||
@ -25,4 +26,3 @@ class BaseAiHandler(ABC):
|
||||
temperature (float): the temperature to use for the chat completion
|
||||
"""
|
||||
pass
|
||||
|
||||
|
@ -14,6 +14,7 @@ import functools
|
||||
|
||||
OPENAI_RETRIES = 5
|
||||
|
||||
|
||||
class LangChainOpenAIHandler(BaseAiHandler):
|
||||
def __init__(self):
|
||||
# Initialize OpenAIHandler specific attributes here
|
||||
@ -51,6 +52,7 @@ class LangChainOpenAIHandler(BaseAiHandler):
|
||||
Returns the deployment ID for the OpenAI API.
|
||||
"""
|
||||
return get_settings().get("OPENAI.DEPLOYMENT_ID", None)
|
||||
|
||||
@retry(exceptions=(APIError, Timeout, TryAgain, AttributeError, RateLimitError),
|
||||
tries=OPENAI_RETRIES, delay=2, backoff=2, jitter=(1, 3))
|
||||
async def chat_completion(self, model: str, system: str, user: str, temperature: float = 0.2):
|
||||
|
@ -28,6 +28,7 @@ class OpenAIHandler(BaseAiHandler):
|
||||
|
||||
except AttributeError as e:
|
||||
raise ValueError("OpenAI key is required") from e
|
||||
|
||||
@property
|
||||
def deployment_id(self):
|
||||
"""
|
||||
|
@ -3,6 +3,7 @@ import re
|
||||
|
||||
from pr_agent.config_loader import get_settings
|
||||
|
||||
|
||||
def filter_ignored(files):
|
||||
"""
|
||||
Filter out files that match the ignore patterns.
|
||||
|
@ -9,6 +9,7 @@ from pr_agent.log import setup_logger
|
||||
log_level = os.environ.get("LOG_LEVEL", "INFO")
|
||||
setup_logger(log_level)
|
||||
|
||||
|
||||
def set_parser():
|
||||
parser = argparse.ArgumentParser(description='AI based pull request analyzer', usage=
|
||||
"""\
|
||||
@ -50,6 +51,7 @@ def set_parser():
|
||||
parser.add_argument('rest', nargs=argparse.REMAINDER, default=[])
|
||||
return parser
|
||||
|
||||
|
||||
def run_command(pr_url, command):
|
||||
# Preparing the command
|
||||
run_command_str = f"--pr_url={pr_url} {command.lstrip('/')}"
|
||||
@ -58,6 +60,7 @@ def run_command(pr_url, command):
|
||||
# Run the command. Feedback will appear in GitHub PR comments
|
||||
run(args=args)
|
||||
|
||||
|
||||
def run(inargs=None, args=None):
|
||||
parser = set_parser()
|
||||
if not args:
|
||||
|
@ -34,6 +34,15 @@ global_settings = Dynaconf(
|
||||
|
||||
|
||||
def get_settings():
|
||||
"""
|
||||
Retrieves the current settings.
|
||||
|
||||
This function attempts to fetch the settings from the starlette_context's context object. If it fails,
|
||||
it defaults to the global settings defined outside of this function.
|
||||
|
||||
Returns:
|
||||
Dynaconf: The current settings object, either from the context or the global default.
|
||||
"""
|
||||
try:
|
||||
return context["settings"]
|
||||
except Exception:
|
||||
@ -41,7 +50,7 @@ def get_settings():
|
||||
|
||||
|
||||
# Add local configuration from pyproject.toml of the project being reviewed
|
||||
def _find_repository_root() -> Path:
|
||||
def _find_repository_root() -> Optional[Path]:
|
||||
"""
|
||||
Identify project root directory by recursively searching for the .git directory in the parent directories.
|
||||
"""
|
||||
@ -61,7 +70,7 @@ def _find_pyproject() -> Optional[Path]:
|
||||
"""
|
||||
repo_root = _find_repository_root()
|
||||
if repo_root:
|
||||
pyproject = _find_repository_root() / "pyproject.toml"
|
||||
pyproject = repo_root / "pyproject.toml"
|
||||
return pyproject if pyproject.is_file() else None
|
||||
return None
|
||||
|
||||
|
@ -8,7 +8,6 @@ from pr_agent.git_providers.local_git_provider import LocalGitProvider
|
||||
from pr_agent.git_providers.azuredevops_provider import AzureDevopsProvider
|
||||
from pr_agent.git_providers.gerrit_provider import GerritProvider
|
||||
|
||||
|
||||
_GIT_PROVIDERS = {
|
||||
'github': GithubProvider,
|
||||
'gitlab': GitLabProvider,
|
||||
@ -20,6 +19,7 @@ _GIT_PROVIDERS = {
|
||||
'gerrit': GerritProvider,
|
||||
}
|
||||
|
||||
|
||||
def get_git_provider():
|
||||
try:
|
||||
provider_id = get_settings().config.git_provider
|
||||
|
@ -139,8 +139,11 @@ async def run_action():
|
||||
comment_id = event_payload.get("comment", {}).get("id")
|
||||
provider = get_git_provider()(pr_url=url)
|
||||
if is_pr:
|
||||
await PRAgent().handle_request(url, body,
|
||||
notify=lambda: provider.add_eyes_reaction(comment_id, disable_eyes=disable_eyes))
|
||||
await PRAgent().handle_request(
|
||||
url, body, notify=lambda: provider.add_eyes_reaction(
|
||||
comment_id, disable_eyes=disable_eyes
|
||||
)
|
||||
)
|
||||
else:
|
||||
await PRAgent().handle_request(url, body)
|
||||
|
||||
|
@ -43,7 +43,6 @@ class PRDescription:
|
||||
self.ai_handler = ai_handler()
|
||||
self.ai_handler.main_pr_language = self.main_pr_language
|
||||
|
||||
|
||||
# Initialize the variables dictionary
|
||||
self.vars = {
|
||||
"title": self.git_provider.pr.title,
|
||||
@ -221,9 +220,6 @@ class PRDescription:
|
||||
if 'pr_files' in self.data:
|
||||
self.data['pr_files'] = self.data.pop('pr_files')
|
||||
|
||||
|
||||
|
||||
|
||||
def _prepare_labels(self) -> List[str]:
|
||||
pr_types = []
|
||||
|
||||
@ -512,6 +508,7 @@ def insert_br_after_x_chars(text, x=70):
|
||||
is_inside_code = False
|
||||
return ''.join(new_text).strip()
|
||||
|
||||
|
||||
def replace_code_tags(text):
|
||||
"""
|
||||
Replace odd instances of ` with <code> and even instances of ` with </code>
|
||||
|
@ -21,6 +21,7 @@ class PRReviewer:
|
||||
"""
|
||||
The PRReviewer class is responsible for reviewing a pull request and generating feedback using an AI model.
|
||||
"""
|
||||
|
||||
def __init__(self, pr_url: str, is_answer: bool = False, is_auto: bool = False, args: list = None,
|
||||
ai_handler: partial[BaseAiHandler,] = LiteLLMAIHandler):
|
||||
"""
|
||||
@ -222,7 +223,6 @@ class PRReviewer:
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
incremental_review_markdown_text = None
|
||||
# Add incremental review section
|
||||
if self.incremental.is_incremental:
|
||||
|
Reference in New Issue
Block a user