mirror of
https://github.com/qodo-ai/pr-agent.git
synced 2025-07-19 03:50:40 +08:00
Merge branch 'main' of https://github.com/Codium-ai/pr-agent into fix_bitbucket_improve_issue
This commit is contained in:
@ -87,8 +87,6 @@ class AiHandler:
|
||||
f"Generating completion with {model}"
|
||||
f"{(' from deployment ' + deployment_id) if deployment_id else ''}"
|
||||
)
|
||||
if self.azure:
|
||||
model = self.azure + "/" + model
|
||||
response = await acompletion(
|
||||
model=model,
|
||||
deployment_id=deployment_id,
|
||||
@ -97,6 +95,7 @@ class AiHandler:
|
||||
{"role": "user", "content": user}
|
||||
],
|
||||
temperature=temperature,
|
||||
azure=self.azure,
|
||||
force_timeout=get_settings().config.ai_timeout
|
||||
)
|
||||
except (APIError, Timeout, TryAgain) as e:
|
||||
|
@ -276,7 +276,7 @@ def _fix_key_value(key: str, value: str):
|
||||
def load_yaml(review_text: str) -> dict:
|
||||
review_text = review_text.removeprefix('```yaml').rstrip('`')
|
||||
try:
|
||||
data = yaml.load(review_text, Loader=yaml.SafeLoader)
|
||||
data = yaml.safe_load(review_text)
|
||||
except Exception as e:
|
||||
logging.error(f"Failed to parse AI prediction: {e}")
|
||||
data = try_fix_yaml(review_text)
|
||||
|
@ -4,11 +4,13 @@ from pr_agent.git_providers.codecommit_provider import CodeCommitProvider
|
||||
from pr_agent.git_providers.github_provider import GithubProvider
|
||||
from pr_agent.git_providers.gitlab_provider import GitLabProvider
|
||||
from pr_agent.git_providers.local_git_provider import LocalGitProvider
|
||||
from pr_agent.git_providers.azuredevops_provider import AzureDevopsProvider
|
||||
|
||||
_GIT_PROVIDERS = {
|
||||
'github': GithubProvider,
|
||||
'gitlab': GitLabProvider,
|
||||
'bitbucket': BitbucketProvider,
|
||||
'azure': AzureDevopsProvider,
|
||||
'codecommit': CodeCommitProvider,
|
||||
'local' : LocalGitProvider
|
||||
}
|
||||
|
269
pr_agent/git_providers/azuredevops_provider.py
Normal file
269
pr_agent/git_providers/azuredevops_provider.py
Normal file
@ -0,0 +1,269 @@
|
||||
import json
|
||||
import logging
|
||||
from typing import Optional, Tuple
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import os
|
||||
|
||||
AZURE_DEVOPS_AVAILABLE = True
|
||||
try:
|
||||
from msrest.authentication import BasicAuthentication
|
||||
from azure.devops.connection import Connection
|
||||
from azure.devops.v7_1.git.models import Comment, CommentThread, GitVersionDescriptor, GitPullRequest
|
||||
except ImportError:
|
||||
AZURE_DEVOPS_AVAILABLE = False
|
||||
|
||||
from ..algo.pr_processing import clip_tokens
|
||||
from ..config_loader import get_settings
|
||||
from ..algo.utils import load_large_diff
|
||||
from ..algo.language_handler import is_valid_file
|
||||
from .git_provider import EDIT_TYPE, FilePatchInfo
|
||||
|
||||
|
||||
class AzureDevopsProvider:
|
||||
def __init__(self, pr_url: Optional[str] = None, incremental: Optional[bool] = False):
|
||||
if not AZURE_DEVOPS_AVAILABLE:
|
||||
raise ImportError("Azure DevOps provider is not available. Please install the required dependencies.")
|
||||
|
||||
self.azure_devops_client = self._get_azure_devops_client()
|
||||
|
||||
self.workspace_slug = None
|
||||
self.repo_slug = None
|
||||
self.repo = None
|
||||
self.pr_num = None
|
||||
self.pr = None
|
||||
self.temp_comments = []
|
||||
self.incremental = incremental
|
||||
if pr_url:
|
||||
self.set_pr(pr_url)
|
||||
|
||||
def is_supported(self, capability: str) -> bool:
|
||||
if capability in ['get_issue_comments', 'create_inline_comment', 'publish_inline_comments', 'get_labels', 'remove_initial_comment']:
|
||||
return False
|
||||
return True
|
||||
|
||||
def set_pr(self, pr_url: str):
|
||||
self.workspace_slug, self.repo_slug, self.pr_num = self._parse_pr_url(pr_url)
|
||||
self.pr = self._get_pr()
|
||||
|
||||
def get_repo_settings(self):
|
||||
try:
|
||||
contents = self.azure_devops_client.get_item_content(repository_id=self.repo_slug,
|
||||
project=self.workspace_slug, download=False,
|
||||
include_content_metadata=False, include_content=True,
|
||||
path=".pr_agent.toml")
|
||||
return contents
|
||||
except Exception as e:
|
||||
logging.exception("get repo settings error")
|
||||
return ""
|
||||
|
||||
def get_files(self):
|
||||
files = []
|
||||
for i in self.azure_devops_client.get_pull_request_commits(project=self.workspace_slug,
|
||||
repository_id=self.repo_slug,
|
||||
pull_request_id=self.pr_num):
|
||||
|
||||
changes_obj = self.azure_devops_client.get_changes(project=self.workspace_slug,
|
||||
repository_id=self.repo_slug, commit_id=i.commit_id)
|
||||
|
||||
for c in changes_obj.changes:
|
||||
files.append(c['item']['path'])
|
||||
return list(set(files))
|
||||
|
||||
def get_diff_files(self) -> list[FilePatchInfo]:
|
||||
try:
|
||||
base_sha = self.pr.last_merge_target_commit
|
||||
head_sha = self.pr.last_merge_source_commit
|
||||
|
||||
commits = self.azure_devops_client.get_pull_request_commits(project=self.workspace_slug,
|
||||
repository_id=self.repo_slug,
|
||||
pull_request_id=self.pr_num)
|
||||
|
||||
diff_files = []
|
||||
diffs = []
|
||||
diff_types = {}
|
||||
|
||||
for c in commits:
|
||||
changes_obj = self.azure_devops_client.get_changes(project=self.workspace_slug,
|
||||
repository_id=self.repo_slug, commit_id=c.commit_id)
|
||||
for i in changes_obj.changes:
|
||||
diffs.append(i['item']['path'])
|
||||
diff_types[i['item']['path']] = i['changeType']
|
||||
|
||||
diffs = list(set(diffs))
|
||||
|
||||
for file in diffs:
|
||||
if not is_valid_file(file):
|
||||
continue
|
||||
|
||||
version = GitVersionDescriptor(version=head_sha.commit_id, version_type='commit')
|
||||
new_file_content_str = self.azure_devops_client.get_item(repository_id=self.repo_slug,
|
||||
path=file,
|
||||
project=self.workspace_slug,
|
||||
version_descriptor=version,
|
||||
download=False,
|
||||
include_content=True)
|
||||
|
||||
new_file_content_str = new_file_content_str.content
|
||||
|
||||
edit_type = EDIT_TYPE.MODIFIED
|
||||
if diff_types[file] == 'add':
|
||||
edit_type = EDIT_TYPE.ADDED
|
||||
elif diff_types[file] == 'delete':
|
||||
edit_type = EDIT_TYPE.DELETED
|
||||
elif diff_types[file] == 'rename':
|
||||
edit_type = EDIT_TYPE.RENAMED
|
||||
|
||||
version = GitVersionDescriptor(version=base_sha.commit_id, version_type='commit')
|
||||
original_file_content_str = self.azure_devops_client.get_item(repository_id=self.repo_slug,
|
||||
path=file,
|
||||
project=self.workspace_slug,
|
||||
version_descriptor=version,
|
||||
download=False,
|
||||
include_content=True)
|
||||
original_file_content_str = original_file_content_str.content
|
||||
|
||||
patch = load_large_diff(file, new_file_content_str, original_file_content_str)
|
||||
|
||||
diff_files.append(FilePatchInfo(original_file_content_str, new_file_content_str,
|
||||
patch=patch,
|
||||
filename=file,
|
||||
edit_type=edit_type))
|
||||
|
||||
self.diff_files = diff_files
|
||||
return diff_files
|
||||
except Exception as e:
|
||||
print(f"Error: {str(e)}")
|
||||
return []
|
||||
|
||||
def publish_comment(self, pr_comment: str, is_temporary: bool = False):
|
||||
comment = Comment(content=pr_comment)
|
||||
thread = CommentThread(comments=[comment])
|
||||
thread_response = self.azure_devops_client.create_thread(comment_thread=thread, project=self.workspace_slug,
|
||||
repository_id=self.repo_slug,
|
||||
pull_request_id=self.pr_num)
|
||||
if is_temporary:
|
||||
self.temp_comments.append({'thread_id': thread_response.id, 'comment_id': comment.id})
|
||||
|
||||
def publish_description(self, pr_title: str, pr_body: str):
|
||||
try:
|
||||
updated_pr = GitPullRequest()
|
||||
updated_pr.title = pr_title
|
||||
updated_pr.description = pr_body
|
||||
self.azure_devops_client.update_pull_request(project=self.workspace_slug,
|
||||
repository_id=self.repo_slug,
|
||||
pull_request_id=self.pr_num,
|
||||
git_pull_request_to_update=updated_pr)
|
||||
except Exception as e:
|
||||
logging.exception(f"Could not update pull request {self.pr_num} description: {e}")
|
||||
|
||||
def remove_initial_comment(self):
|
||||
return "" # not implemented yet
|
||||
|
||||
def publish_inline_comment(self, body: str, relevant_file: str, relevant_line_in_file: str):
|
||||
raise NotImplementedError("Azure DevOps provider does not support publishing inline comment yet")
|
||||
|
||||
def create_inline_comment(self, body: str, relevant_file: str, relevant_line_in_file: str):
|
||||
raise NotImplementedError("Azure DevOps provider does not support creating inline comments yet")
|
||||
|
||||
def publish_inline_comments(self, comments: list[dict]):
|
||||
raise NotImplementedError("Azure DevOps provider does not support publishing inline comments yet")
|
||||
|
||||
def get_title(self):
|
||||
return self.pr.title
|
||||
|
||||
def get_languages(self):
|
||||
languages = []
|
||||
files = self.azure_devops_client.get_items(project=self.workspace_slug, repository_id=self.repo_slug,
|
||||
recursion_level="Full", include_content_metadata=True,
|
||||
include_links=False, download=False)
|
||||
for f in files:
|
||||
if f.git_object_type == 'blob':
|
||||
file_name, file_extension = os.path.splitext(f.path)
|
||||
languages.append(file_extension[1:])
|
||||
|
||||
extension_counts = {}
|
||||
for ext in languages:
|
||||
if ext != '':
|
||||
extension_counts[ext] = extension_counts.get(ext, 0) + 1
|
||||
|
||||
total_extensions = sum(extension_counts.values())
|
||||
|
||||
extension_percentages = {ext: (count / total_extensions) * 100 for ext, count in extension_counts.items()}
|
||||
|
||||
return extension_percentages
|
||||
|
||||
def get_pr_branch(self):
|
||||
pr_info = self.azure_devops_client.get_pull_request_by_id(project=self.workspace_slug,
|
||||
pull_request_id=self.pr_num)
|
||||
source_branch = pr_info.source_ref_name.split('/')[-1]
|
||||
return source_branch
|
||||
|
||||
def get_pr_description(self):
|
||||
max_tokens = get_settings().get("CONFIG.MAX_DESCRIPTION_TOKENS", None)
|
||||
if max_tokens:
|
||||
return clip_tokens(self.pr.description, max_tokens)
|
||||
return self.pr.description
|
||||
|
||||
def get_user_id(self):
|
||||
return 0
|
||||
|
||||
def get_issue_comments(self):
|
||||
raise NotImplementedError("Azure DevOps provider does not support issue comments yet")
|
||||
|
||||
def add_eyes_reaction(self, issue_comment_id: int) -> Optional[int]:
|
||||
return True
|
||||
|
||||
def remove_reaction(self, issue_comment_id: int, reaction_id: int) -> bool:
|
||||
return True
|
||||
|
||||
def get_issue_comments(self):
|
||||
raise NotImplementedError("Azure DevOps provider does not support issue comments yet")
|
||||
|
||||
@staticmethod
|
||||
def _parse_pr_url(pr_url: str) -> Tuple[str, int]:
|
||||
parsed_url = urlparse(pr_url)
|
||||
|
||||
if 'azure.com' not in parsed_url.netloc:
|
||||
raise ValueError("The provided URL is not a valid Azure DevOps URL")
|
||||
|
||||
path_parts = parsed_url.path.strip('/').split('/')
|
||||
|
||||
if len(path_parts) < 6 or path_parts[4] != 'pullrequest':
|
||||
raise ValueError("The provided URL does not appear to be a Azure DevOps PR URL")
|
||||
|
||||
workspace_slug = path_parts[1]
|
||||
repo_slug = path_parts[3]
|
||||
try:
|
||||
pr_number = int(path_parts[5])
|
||||
except ValueError as e:
|
||||
raise ValueError("Unable to convert PR number to integer") from e
|
||||
|
||||
return workspace_slug, repo_slug, pr_number
|
||||
|
||||
def _get_azure_devops_client(self):
|
||||
try:
|
||||
pat = get_settings().azure_devops.pat
|
||||
org = get_settings().azure_devops.org
|
||||
except AttributeError as e:
|
||||
raise ValueError(
|
||||
"Azure DevOps PAT token is required ") from e
|
||||
|
||||
credentials = BasicAuthentication('', pat)
|
||||
azure_devops_connection = Connection(base_url=org, creds=credentials)
|
||||
azure_devops_client = azure_devops_connection.clients.get_git_client()
|
||||
|
||||
return azure_devops_client
|
||||
|
||||
def _get_repo(self):
|
||||
if self.repo is None:
|
||||
self.repo = self.azure_devops_client.get_repository(project=self.workspace_slug,
|
||||
repository_id=self.repo_slug)
|
||||
return self.repo
|
||||
|
||||
def _get_pr(self):
|
||||
self.pr = self.azure_devops_client.get_pull_request_by_id(pull_request_id=self.pr_num, project=self.workspace_slug)
|
||||
return self.pr
|
||||
|
||||
def get_commit_messages(self):
|
||||
return "" # not implemented yet
|
@ -1,3 +1,4 @@
|
||||
import logging
|
||||
from abc import ABC, abstractmethod
|
||||
from dataclasses import dataclass
|
||||
|
||||
@ -137,6 +138,8 @@ def get_main_pr_language(languages, files) -> str:
|
||||
# validate that the specific commit uses the main language
|
||||
extension_list = []
|
||||
for file in files:
|
||||
if isinstance(file, str):
|
||||
file = FilePatchInfo(base_file=None, head_file=None, patch=None, filename=file)
|
||||
extension_list.append(file.filename.rsplit('.')[-1])
|
||||
|
||||
# get the most common extension
|
||||
@ -158,10 +161,12 @@ def get_main_pr_language(languages, files) -> str:
|
||||
most_common_extension == 'scala' and top_language == 'scala' or \
|
||||
most_common_extension == 'kt' and top_language == 'kotlin' or \
|
||||
most_common_extension == 'pl' and top_language == 'perl' or \
|
||||
most_common_extension == 'swift' and top_language == 'swift':
|
||||
most_common_extension == 'swift' and top_language == 'swift' or \
|
||||
most_common_extension == top_language:
|
||||
main_language_str = top_language
|
||||
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
logging.exception(e)
|
||||
pass
|
||||
|
||||
return main_language_str
|
||||
|
@ -1,8 +1,8 @@
|
||||
[pr_code_suggestions_prompt]
|
||||
system="""You are a language model called PR-Code-Reviewer.
|
||||
Your task is to provide meaningful actionable code suggestions, to improve the new code presented in a PR.
|
||||
system="""You are a language model called PR-Code-Reviewer, that specializes in suggesting code improvements for Pull Request (PR).
|
||||
Your task is to provide meaningful and actionable code suggestions, to improve the new code presented in a PR.
|
||||
|
||||
Example PR Diff input:
|
||||
Example for a PR Diff input:
|
||||
'
|
||||
## src/file1.py
|
||||
|
||||
@ -10,8 +10,8 @@ Example PR Diff input:
|
||||
__new hunk__
|
||||
12 code line that already existed in the file...
|
||||
13 code line that already existed in the file....
|
||||
14 +new code line added in the PR
|
||||
15 code line that already existed in the file...
|
||||
14 +new code line1 added in the PR
|
||||
15 +new code line2 added in the PR
|
||||
16 code line that already existed in the file...
|
||||
__old hunk__
|
||||
code line that already existed in the file...
|
||||
@ -31,13 +31,17 @@ __old hunk__
|
||||
'
|
||||
|
||||
Specific instructions:
|
||||
- Focus on important suggestions like fixing code problems, issues and bugs. As a second priority, provide suggestions for meaningful code improvements, like performance, vulnerability, modularity, and best practices.
|
||||
- Suggestions should refer only to code from the '__new hunk__' sections, and focus on new lines of code (lines starting with '+').
|
||||
- Provide the exact line number range (inclusive) for each issue.
|
||||
- Assume there is additional relevant code, that is not included in the diff.
|
||||
- Provide up to {{ num_code_suggestions }} code suggestions.
|
||||
- Avoid making suggestions that have already been implemented in the PR code. For example, if you want to add logs, or change a variable to const, or anything else, make sure it isn't already in the '__new hunk__' code.
|
||||
- Don't suggest to add docstring or type hints.
|
||||
- Prioritize suggestions that address major problems, issues and bugs in the code.
|
||||
As a second priority, suggestions should focus on best practices, code readability, maintainability, enhancments, performance, and other aspects.
|
||||
Don't suggest to add docstring or type hints.
|
||||
Try to provide diverse and insightful suggestions.
|
||||
- Suggestions should refer only to code from the '__new hunk__' sections, and focus on new lines of code (lines starting with '+').
|
||||
Avoid making suggestions that have already been implemented in the PR code. For example, if you want to add logs, or change a variable to const, or anything else, make sure it isn't already in the '__new hunk__' code.
|
||||
For each suggestion, make sure to take into consideration also the context, meaning the lines before and after the relevant code.
|
||||
- Provide the exact line numbers range (inclusive) for each issue.
|
||||
- Assume there is additional relevant code, that is not included in the diff.
|
||||
|
||||
|
||||
{%- if extra_instructions %}
|
||||
|
||||
@ -45,63 +49,76 @@ Extra instructions from the user:
|
||||
{{ extra_instructions }}
|
||||
{%- endif %}
|
||||
|
||||
You must use the following JSON schema to format your answer:
|
||||
```json
|
||||
{
|
||||
"Code suggestions": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"maxItems": {{ num_code_suggestions }},
|
||||
"uniqueItems": "true",
|
||||
"items": {
|
||||
"relevant file": {
|
||||
"type": "string",
|
||||
"description": "the relevant file full path"
|
||||
},
|
||||
"suggestion content": {
|
||||
"type": "string",
|
||||
"description": "a concrete suggestion for meaningfully improving the new PR code (lines from the '__new hunk__' sections, starting with '+')."
|
||||
},
|
||||
"existing code": {
|
||||
"type": "string",
|
||||
"description": "a code snippet showing the relevant code lines from a '__new hunk__' section. It must be continuous, correctly formatted and indented, and without line numbers."
|
||||
},
|
||||
"relevant lines": {
|
||||
"type": "string",
|
||||
"description": "the relevant lines from a '__new hunk__' section, in the format of 'start_line-end_line'. For example: '10-15'. They should be derived from the hunk line numbers, and correspond to the 'existing code' snippet above."
|
||||
},
|
||||
"improved code": {
|
||||
"type": "string",
|
||||
"description": "a new code snippet that can be used to replace the relevant lines in '__new hunk__' code. Replacement suggestions should be complete, correctly formatted and indented, and without line numbers."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
You must use the following YAML schema to format your answer:
|
||||
```yaml
|
||||
Code suggestions:
|
||||
type: array
|
||||
minItems: 1
|
||||
maxItems: {{ num_code_suggestions }}
|
||||
uniqueItems: true
|
||||
items:
|
||||
relevant file:
|
||||
type: string
|
||||
description: the relevant file full path
|
||||
suggestion content:
|
||||
type: string
|
||||
description: |-
|
||||
a concrete suggestion for meaningfully improving the new PR code.
|
||||
existing code:
|
||||
type: string
|
||||
description: |-
|
||||
a code snippet showing the relevant code lines from a '__new hunk__' section.
|
||||
It must be continuous, correctly formatted and indented, and without line numbers.
|
||||
relevant lines:
|
||||
type: string
|
||||
description: |-
|
||||
the relevant lines from a '__new hunk__' section, in the format of 'start_line-end_line'.
|
||||
For example: '10-15'. They should be derived from the hunk line numbers, and correspond to the 'existing code' snippet above.
|
||||
improved code:
|
||||
type: string
|
||||
description: |-
|
||||
a new code snippet that can be used to replace the relevant lines in '__new hunk__' code.
|
||||
Replacement suggestions should be complete, correctly formatted and indented, and without line numbers.
|
||||
```
|
||||
|
||||
Don't output line numbers in the 'improved code' snippets.
|
||||
Example output:
|
||||
```yaml
|
||||
Code suggestions:
|
||||
- relevant file: |-
|
||||
src/file1.py
|
||||
suggestion content: |-
|
||||
Add a docstring to func1()
|
||||
existing code: |-
|
||||
def func1():
|
||||
relevant lines: '12-12'
|
||||
improved code: |-
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
Each YAML output MUST be after a newline, indented, with block scalar indicator ('|-').
|
||||
Don't repeat the prompt in the answer, and avoid outputting the 'type' and 'description' fields.
|
||||
"""
|
||||
|
||||
user="""PR Info:
|
||||
Title: '{{title}}'
|
||||
Branch: '{{branch}}'
|
||||
Description: '{{description}}'
|
||||
{%- if language %}
|
||||
Main language: {{language}}
|
||||
{%- endif %}
|
||||
{%- if commit_messages_str %}
|
||||
|
||||
Commit messages:
|
||||
{{commit_messages_str}}
|
||||
Title: '{{title}}'
|
||||
|
||||
Branch: '{{branch}}'
|
||||
|
||||
Description: '{{description}}'
|
||||
|
||||
{%- if language %}
|
||||
|
||||
Main language: {{language}}
|
||||
{%- endif %}
|
||||
|
||||
|
||||
The PR Diff:
|
||||
```
|
||||
{{diff}}
|
||||
{{- diff|trim }}
|
||||
```
|
||||
|
||||
Response (should be a valid JSON, and nothing else):
|
||||
```json
|
||||
Response (should be a valid YAML, and nothing else):
|
||||
```yaml
|
||||
"""
|
||||
|
@ -1,16 +1,13 @@
|
||||
import copy
|
||||
import json
|
||||
import logging
|
||||
import textwrap
|
||||
from typing import List
|
||||
|
||||
import yaml
|
||||
from typing import List, Dict
|
||||
from jinja2 import Environment, StrictUndefined
|
||||
|
||||
from pr_agent.algo.ai_handler import AiHandler
|
||||
from pr_agent.algo.pr_processing import get_pr_diff, retry_with_fallback_models, get_pr_multi_diffs
|
||||
from pr_agent.algo.token_handler import TokenHandler
|
||||
from pr_agent.algo.utils import try_fix_json
|
||||
from pr_agent.algo.utils import load_yaml
|
||||
from pr_agent.config_loader import get_settings
|
||||
from pr_agent.git_providers import BitbucketProvider, get_git_provider
|
||||
from pr_agent.git_providers.git_provider import get_main_pr_language
|
||||
@ -98,14 +95,11 @@ class PRCodeSuggestions:
|
||||
|
||||
return response
|
||||
|
||||
def _prepare_pr_code_suggestions(self) -> str:
|
||||
def _prepare_pr_code_suggestions(self) -> Dict:
|
||||
review = self.prediction.strip()
|
||||
try:
|
||||
data = json.loads(review)
|
||||
except json.decoder.JSONDecodeError:
|
||||
if get_settings().config.verbosity_level >= 2:
|
||||
logging.info(f"Could not parse json response: {review}")
|
||||
data = try_fix_json(review, code_suggestions=True)
|
||||
data = load_yaml(review)
|
||||
if isinstance(data, list):
|
||||
data = {'Code suggestions': data}
|
||||
return data
|
||||
|
||||
def push_inline_code_suggestions(self, data):
|
||||
@ -227,7 +221,7 @@ class PRCodeSuggestions:
|
||||
response, finish_reason = await self.ai_handler.chat_completion(model=model, system=system_prompt,
|
||||
user=user_prompt)
|
||||
|
||||
sort_order = yaml.safe_load(response)
|
||||
sort_order = load_yaml(response)
|
||||
for s in sort_order['Sort Order']:
|
||||
suggestion_number = s['suggestion number']
|
||||
importance_order = s['importance order']
|
||||
|
Reference in New Issue
Block a user