diff --git a/docs/docs/usage-guide/changing_a_model.md b/docs/docs/usage-guide/changing_a_model.md index c86af096..6ee03759 100644 --- a/docs/docs/usage-guide/changing_a_model.md +++ b/docs/docs/usage-guide/changing_a_model.md @@ -30,50 +30,36 @@ model="" # the OpenAI model you've deployed on Azure (e.g. gpt-4o) fallback_models=["..."] ``` -### Hugging Face +### Ollama -**Local** -You can run Hugging Face models locally through either [VLLM](https://docs.litellm.ai/docs/providers/vllm) or [Ollama](https://docs.litellm.ai/docs/providers/ollama) +You can run models locally through either [VLLM](https://docs.litellm.ai/docs/providers/vllm) or [Ollama](https://docs.litellm.ai/docs/providers/ollama) -E.g. to use a new Hugging Face model locally via Ollama, set: +E.g. to use a new model locally via Ollama, set in `.secrets.toml` or in a configuration file: ``` -[__init__.py] -MAX_TOKENS = { - "model-name-on-ollama": -} -e.g. -MAX_TOKENS={ - ..., - "ollama/llama2": 4096 -} +[config] +model = "ollama/qwen2.5-coder:32b" +fallback_models=["ollama/qwen2.5-coder:32b"] +custom_model_max_tokens=128000 # set the maximal input tokens for the model +duplicate_examples=true # will duplicate the examples in the prompt, to help the model to output structured output - -[config] # in configuration.toml -model = "ollama/llama2" -fallback_models=["ollama/llama2"] - -[ollama] # in .secrets.toml -api_base = ... # the base url for your Hugging Face inference endpoint -# e.g. if running Ollama locally, you may use: -api_base = "http://localhost:11434/" +[ollama] +api_base = "http://localhost:11434" # or whatever port you're running Ollama on ``` -### Inference Endpoints +!!! note "Local models vs commercial models" + Qodo Merge is compatible with almost any AI model, but analyzing complex code repositories and pull requests requires a model specifically optimized for code analysis. + Commercial models such as GPT-4, Claude Sonnet, and Gemini have demonstrated robust capabilities in generating structured output for code analysis tasks with large input. In contrast, most open-source models currently available (as of January 2025) face challenges with these complex tasks. + Based on our testing, local open-source models are suitable for experimentation and learning purposes, but they are not suitable for production-level code analysis tasks. + Hence, for production workflows and real-world usage, we recommend using commercial models. + +### Hugging Face Inference Endpoints To use a new model with Hugging Face Inference Endpoints, for example, set: ``` -[__init__.py] -MAX_TOKENS = { - "model-name-on-huggingface": -} -e.g. -MAX_TOKENS={ - ..., - "meta-llama/Llama-2-7b-chat-hf": 4096 -} [config] # in configuration.toml model = "huggingface/meta-llama/Llama-2-7b-chat-hf" fallback_models=["huggingface/meta-llama/Llama-2-7b-chat-hf"] +custom_model_max_tokens=... # set the maximal input tokens for the model [huggingface] # in .secrets.toml key = ... # your Hugging Face api key diff --git a/pr_agent/config_loader.py b/pr_agent/config_loader.py index b13a3ce7..9ae430ca 100644 --- a/pr_agent/config_loader.py +++ b/pr_agent/config_loader.py @@ -12,7 +12,6 @@ global_settings = Dynaconf( envvar_prefix=False, merge_enabled=True, settings_files=[join(current_dir, f) for f in [ - "settings/.secrets.toml", "settings/configuration.toml", "settings/ignore.toml", "settings/language_extensions.toml", @@ -29,6 +28,7 @@ global_settings = Dynaconf( "settings/pr_add_docs.toml", "settings/custom_labels.toml", "settings/pr_help_prompts.toml", + "settings/.secrets.toml", "settings_prod/.secrets.toml", ]] ) diff --git a/pr_agent/settings/configuration.toml b/pr_agent/settings/configuration.toml index 3bc91099..29cd90e7 100644 --- a/pr_agent/settings/configuration.toml +++ b/pr_agent/settings/configuration.toml @@ -34,6 +34,7 @@ ai_disclaimer_title="" # Pro feature, title for a collapsible disclaimer to AI ai_disclaimer="" # Pro feature, full text for the AI disclaimer output_relevant_configurations=false large_patch_policy = "clip" # "clip", "skip" +duplicate_prompt_examples = false # seed seed=-1 # set positive value to fix the seed (and ensure temperature=0) temperature=0.2 diff --git a/pr_agent/settings/pr_code_suggestions_prompts.toml b/pr_agent/settings/pr_code_suggestions_prompts.toml index 012ae0fc..7a449fb2 100644 --- a/pr_agent/settings/pr_code_suggestions_prompts.toml +++ b/pr_agent/settings/pr_code_suggestions_prompts.toml @@ -125,6 +125,30 @@ The PR Diff: {{ diff_no_line_numbers|trim }} ====== +{%- if duplicate_prompt_examples %} + + +Example output: +```yaml +code_suggestions: +- relevant_file: | + src/file1.py + language: | + python + suggestion_content: | + ... + existing_code: | + ... + improved_code: | + ... + one_sentence_summary: | + ... + label: | + ... +``` +(replace '...' with actual content) +{%- endif %} + Response (should be a valid YAML, and nothing else): ```yaml diff --git a/pr_agent/settings/pr_code_suggestions_reflect_prompts.toml b/pr_agent/settings/pr_code_suggestions_reflect_prompts.toml index 34b1eec4..16ffb435 100644 --- a/pr_agent/settings/pr_code_suggestions_reflect_prompts.toml +++ b/pr_agent/settings/pr_code_suggestions_reflect_prompts.toml @@ -122,6 +122,25 @@ Below are {{ num_code_suggestions }} AI-generated code suggestions for enhancing ====== +{%- if duplicate_prompt_examples %} + + +Example output: +```yaml +code_suggestions: +- suggestion_summary: | + ... + relevant_file: "..." + relevant_lines_start: ... + relevant_lines_end: ... + suggestion_score: ... + why: | + ... +- ... +``` +(replace '...' with actual content) +{%- endif %} + Response (should be a valid YAML, and nothing else): ```yaml """ diff --git a/pr_agent/settings/pr_description_prompts.toml b/pr_agent/settings/pr_description_prompts.toml index 0a15eee3..73ec8459 100644 --- a/pr_agent/settings/pr_description_prompts.toml +++ b/pr_agent/settings/pr_description_prompts.toml @@ -130,6 +130,37 @@ The PR Git Diff: Note that lines in the diff body are prefixed with a symbol that represents the type of change: '-' for deletions, '+' for additions, and ' ' (a space) for unchanged lines. +{%- if duplicate_prompt_examples %} + + +Example output: +```yaml +type: +- Bug fix +- Refactoring +- ... +description: | + ... +title: | + ... +{%- if enable_semantic_files_types %} +pr_files: +- filename: | + ... +{%- if include_file_summary_changes %} + changes_summary: | + ... +{%- endif %} + changes_title: | + ... + label: | + label_key_1 +... +{%- endif %} +``` +(replace '...' with the actual values) +{%- endif %} + Response (should be a valid YAML, and nothing else): ```yaml diff --git a/pr_agent/settings/pr_reviewer_prompts.toml b/pr_agent/settings/pr_reviewer_prompts.toml index 9401a0d3..fb5a134e 100644 --- a/pr_agent/settings/pr_reviewer_prompts.toml +++ b/pr_agent/settings/pr_reviewer_prompts.toml @@ -221,6 +221,59 @@ The PR code diff: ====== +{%- if duplicate_prompt_examples %} + + +Example output: +```yaml +review: +{%- if related_tickets %} + ticket_compliance_check: + - ticket_url: | + ... + ticket_requirements: | + ... + fully_compliant_requirements: | + ... + not_compliant_requirements: | + ... + overall_compliance_level: | + ... +{%- endif %} +{%- if require_estimate_effort_to_review %} + estimated_effort_to_review_[1-5]: | + 3 +{%- endif %} +{%- if require_score %} + score: 89 +{%- endif %} + relevant_tests: | + No + key_issues_to_review: + - relevant_file: | + ... + issue_header: | + ... + issue_content: | + ... + start_line: ... + end_line: ... + - ... + security_concerns: | + No +{%- if require_can_be_split_review %} + can_be_split: + - relevant_files: + - ... + - ... + title: ... + - ... +{%- endif %} +``` +(replace '...' with the actual values) +{%- endif %} + + Response (should be a valid YAML, and nothing else): ```yaml """ diff --git a/pr_agent/tools/pr_code_suggestions.py b/pr_agent/tools/pr_code_suggestions.py index f3d7cda4..aebe5dec 100644 --- a/pr_agent/tools/pr_code_suggestions.py +++ b/pr_agent/tools/pr_code_suggestions.py @@ -81,6 +81,7 @@ class PRCodeSuggestions: "relevant_best_practices": "", "is_ai_metadata": get_settings().get("config.enable_ai_metadata", False), "focus_only_on_problems": get_settings().get("pr_code_suggestions.focus_only_on_problems", False), + 'duplicate_prompt_examples': get_settings().config.get('duplicate_prompt_examples', False), } self.pr_code_suggestions_prompt_system = get_settings().pr_code_suggestions_prompt.system @@ -830,7 +831,8 @@ class PRCodeSuggestions: "diff": patches_diff, 'num_code_suggestions': len(suggestion_list), 'prev_suggestions_str': prev_suggestions_str, - "is_ai_metadata": get_settings().get("config.enable_ai_metadata", False)} + "is_ai_metadata": get_settings().get("config.enable_ai_metadata", False), + 'duplicate_prompt_examples': get_settings().config.get('duplicate_prompt_examples', False)} environment = Environment(undefined=StrictUndefined) if dedicated_prompt: diff --git a/pr_agent/tools/pr_description.py b/pr_agent/tools/pr_description.py index 18df4f10..7744b699 100644 --- a/pr_agent/tools/pr_description.py +++ b/pr_agent/tools/pr_description.py @@ -71,7 +71,8 @@ class PRDescription: "custom_labels_class": "", # will be filled if necessary in 'set_custom_labels' function "enable_semantic_files_types": get_settings().pr_description.enable_semantic_files_types, "related_tickets": "", - "include_file_summary_changes": len(self.git_provider.get_diff_files()) <= self.COLLAPSIBLE_FILE_LIST_THRESHOLD + "include_file_summary_changes": len(self.git_provider.get_diff_files()) <= self.COLLAPSIBLE_FILE_LIST_THRESHOLD, + 'duplicate_prompt_examples': get_settings().config.get('duplicate_prompt_examples', False), } self.user_description = self.git_provider.get_user_description() diff --git a/pr_agent/tools/pr_reviewer.py b/pr_agent/tools/pr_reviewer.py index 9905ae3d..ee3bb963 100644 --- a/pr_agent/tools/pr_reviewer.py +++ b/pr_agent/tools/pr_reviewer.py @@ -94,6 +94,7 @@ class PRReviewer: "enable_custom_labels": get_settings().config.enable_custom_labels, "is_ai_metadata": get_settings().get("config.enable_ai_metadata", False), "related_tickets": get_settings().get('related_tickets', []), + 'duplicate_prompt_examples': get_settings().config.get('duplicate_prompt_examples', False), } self.token_handler = TokenHandler(