Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@smallfish06
Copy link
Contributor

@smallfish06 smallfish06 commented Jun 13, 2025

User description

Background (Why)

Although we had configured the feature to merge language-specific instructions from user settings into the extra instructions, that logic was not being executed in our GitHub Action.

Changes (What)

  • Added logic to merge language-specific instructions specified in user settings into the extra_instructions array

PR Type

Enhancement


Description

• Add language-specific instructions to extra instructions for non-English locales
• Merge response language settings into PR tools configuration
• Enhance internationalization support for PR agent tools


Changes diagram

flowchart LR
  A["User Settings"] --> B["Check Response Language"]
  B --> C{"Language != en-us?"}
  C -->|Yes| D["Create Language Instruction"]
  D --> E["Append to Extra Instructions"]
  E --> F["Update PR Tools Config"]
  C -->|No| G["Skip Language Instructions"]
Loading

Changes walkthrough 📝

Relevant files
Enhancement
utils.py
Add language-specific instruction merging logic                   

pr_agent/git_providers/utils.py

• Import DynaBox from dynaconf utilities
• Add logic to check
response_language setting
• Append language-specific instructions to
PR tools when non-English locale is set
• Update extra_instructions
for PR description, code suggestions, and reviewer tools

+23/-0   

Need help?
  • Type /help how to ... in the comments thread for any questions about Qodo Merge usage.
  • Check out the documentation for more information.
  • @qodo-merge-for-open-source
    Copy link
    Contributor

    PR Reviewer Guide 🔍

    Here are some key observations to aid the review process:

    ⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
    🧪 No relevant tests
    🔒 No security concerns identified
    ⚡ Recommended focus areas for review

    Performance Issue

    The code iterates through all settings using get_settings() in a loop, which could be inefficient. Consider directly accessing the specific settings needed instead of iterating through all configuration keys.

    for key in get_settings():
        setting = get_settings().get(key)
        if isinstance(setting, DynaBox):
            if key.lower() in ['pr_description', 'pr_code_suggestions', 'pr_reviewer']:
                if hasattr(setting, 'extra_instructions'):
                    extra_instructions = setting.extra_instructions
    
                    if lang_instruction_text not in str(extra_instructions):
                        updated_instructions = (
                            str(extra_instructions) + separator_text + lang_instruction_text
                            if extra_instructions else lang_instruction_text
                        )
                        setting.extra_instructions = updated_instructions
    Logic Bug

    The string containment check lang_instruction_text not in str(extra_instructions) may produce false positives if the language instruction text appears as a substring in existing instructions, potentially leading to duplicate additions.

    if lang_instruction_text not in str(extra_instructions):
        updated_instructions = (
    Code Quality

    The hardcoded list of tool names in the condition check makes the code brittle and harder to maintain. Consider using a configuration-driven approach or constants to define which tools should receive language instructions.

    if key.lower() in ['pr_description', 'pr_code_suggestions', 'pr_reviewer']:
        if hasattr(setting, 'extra_instructions'):

    @qodo-merge-for-open-source
    Copy link
    Contributor

    qodo-merge-for-open-source bot commented Jun 13, 2025

    PR Code Suggestions ✨

    Latest suggestions up to d4e8f61

    CategorySuggestion                                                                                                                                    Impact
    Possible issue
    Restrict iteration to known keys

    Iterating over the entire settings object may not yield the specific review
    components. Target the known instruction keys directly using getattr on
    get_settings(), ensuring you only update pr_description, pr_code_suggestions,
    and pr_reviewer. This change avoids missing or unintended keys during the
    update.

    pr_agent/servers/github_action_runner.py [94-96]

    -for key in get_settings():
    -    setting = get_settings().get(key)
    +settings = get_settings()
    +for key in ['pr_description', 'pr_code_suggestions', 'pr_reviewer']:
    +    setting = getattr(settings, key, None)
         if isinstance(setting, DynaBox):
    • Apply / Chat
    Suggestion importance[1-10]: 5

    __

    Why: Narrowing the loop to only pr_description, pr_code_suggestions, and pr_reviewer makes the intent clearer and avoids iterating unrelated settings, improving maintainability with minimal impact.

    Low
    Guard against non-string locale values

    Ensure response_language is a string before calling .lower() to prevent
    attribute errors if the setting is non-string. Converting it with str() guards
    against unexpected types.

    pr_agent/servers/github_action_runner.py [87-88]

     response_language = get_settings().config.get('response_language', 'en-us')
    -if response_language.lower() != 'en-us':
    +response_language_str = str(response_language)
    +if response_language_str.lower() != 'en-us':
    • Apply / Chat
    Suggestion importance[1-10]: 3

    __

    Why: Casting response_language to str prevents potential attribute errors for unexpected types, but it's a defensive change with low overall impact.

    Low
    General
    Cache settings before loop

    Cache the result of get_settings() in a local variable before the loop to avoid
    repeated calls and improve performance. This also prevents any side effects if
    get_settings() has internal state.

    pr_agent/servers/github_action_runner.py [94-95]

    -for key in get_settings():
    -    setting = get_settings().get(key)
    +settings = get_settings()
    +for key in settings:
    +    setting = settings.get(key)
    • Apply / Chat
    Suggestion importance[1-10]: 4

    __

    Why: Storing get_settings() in a local variable avoids repeated calls and potential side effects, but the performance gain is minimal in this context.

    Low
    • More
    • Author self-review: I have reviewed the PR code suggestions, and addressed the relevant ones.

    Previous suggestions

    Suggestions up to commit d4e8f61
    CategorySuggestion                                                                                                                                    Impact
    Possible issue
    Make instruction updates idempotent and efficient

    The current logic may append multiple conflicting language instructions if the
    language setting is changed, as it only checks for the new instruction text.
    Additionally, the loop iterates over all settings inefficiently. The suggested
    change makes the update idempotent by removing any pre-existing language
    instruction before adding the new one, and it improves performance by iterating
    only over relevant keys.

    pr_agent/servers/github_action_runner.py [94-106]

    -for key in get_settings():
    -    setting = get_settings().get(key)
    -    if isinstance(setting, DynaBox):
    -        if key.lower() in ['pr_description', 'pr_code_suggestions', 'pr_reviewer']:
    -            if hasattr(setting, 'extra_instructions'):
    -                extra_instructions = setting.extra_instructions
    +settings = get_settings()
    +tool_keys = ['pr_description', 'pr_code_suggestions', 'pr_reviewer']
    +base_instruction = "Your response MUST be written in the language corresponding to locale code:"
     
    -                if lang_instruction_text not in str(extra_instructions):
    -                    updated_instructions = (
    -                        str(extra_instructions) + separator_text + lang_instruction_text
    -                        if extra_instructions else lang_instruction_text
    -                    )
    -                    setting.extra_instructions = updated_instructions
    +for key in tool_keys:
    +    setting = settings.get(key)
    +    if isinstance(setting, DynaBox) and hasattr(setting, 'extra_instructions'):
    +        instructions_str = str(setting.extra_instructions or "")
     
    +        # Remove previous language instruction to ensure idempotency
    +        instruction_pos = instructions_str.find(base_instruction)
    +        if instruction_pos != -1:
    +            separator_pos = instructions_str.rfind(separator_text, 0, instruction_pos)
    +            if separator_pos != -1:
    +                instructions_str = instructions_str[:separator_pos]
    +            else:
    +                instructions_str = ""
    +
    +        # Add the new language instruction
    +        if instructions_str:
    +            updated_instructions = f"{instructions_str}{separator_text}{lang_instruction_text}"
    +        else:
    +            updated_instructions = lang_instruction_text
    +        setting.extra_instructions = updated_instructions
    +
    Suggestion importance[1-10]: 8

    __

    Why: The suggestion correctly identifies a potential bug where changing the response language could lead to multiple, conflicting language instructions being appended. It also rightly points out that iterating over a predefined list of keys is more efficient than iterating over all settings. The proposed fix is robust and improves the correctness of the new feature.

    Medium
    Suggestions up to commit d4e8f61
    CategorySuggestion                                                                                                                                    Impact
    General
    Iterate directly over relevant keys

    The current loop iterates over all settings, which is inefficient. It's better
    to iterate directly over the specific tool configurations you intend to modify.
    This change makes the code more direct, readable, and performant by avoiding
    unnecessary iterations and checks.

    pr_agent/servers/github_action_runner.py [94-106]

    -for key in get_settings():
    -    setting = get_settings().get(key)
    -    if isinstance(setting, DynaBox):
    -        if key.lower() in ['pr_description', 'pr_code_suggestions', 'pr_reviewer']:
    -            if hasattr(setting, 'extra_instructions'):
    -                extra_instructions = setting.extra_instructions
    +relevant_tools = ['pr_description', 'pr_code_suggestions', 'pr_reviewer']
    +for tool_key in relevant_tools:
    +    setting = get_settings().get(tool_key)
    +    if isinstance(setting, DynaBox) and hasattr(setting, 'extra_instructions'):
    +        extra_instructions = setting.extra_instructions
     
    -                if lang_instruction_text not in str(extra_instructions):
    -                    updated_instructions = (
    -                        str(extra_instructions) + separator_text + lang_instruction_text
    -                        if extra_instructions else lang_instruction_text
    -                    )
    -                    setting.extra_instructions = updated_instructions
    +        if lang_instruction_text not in str(extra_instructions):
    +            updated_instructions = (
    +                str(extra_instructions) + separator_text + lang_instruction_text
    +                if extra_instructions else lang_instruction_text
    +            )
    +            setting.extra_instructions = updated_instructions
    Suggestion importance[1-10]: 6
    Low
    Suggestions up to commit 9b19935
    CategorySuggestion                                                                                                                                    Impact
    General
    Cache settings object for efficiency

    Calling get_settings() multiple times in a loop is inefficient and could lead to
    inconsistent state. Store the settings object once and reuse it throughout the
    loop.

    pr_agent/git_providers/utils.py [74-77]

    -for key in get_settings():
    -    setting = get_settings().get(key)
    +settings = get_settings()
    +for key in settings:
    +    setting = settings.get(key)
         if isinstance(setting, DynaBox):
             if key.lower() in ['pr_description', 'pr_code_suggestions', 'pr_reviewer']:
    Suggestion importance[1-10]: 6

    __

    Why: The suggestion correctly identifies that get_settings() is called multiple times within a loop, which is inefficient. Caching the settings object in a variable before the loop is a good practice that improves both performance and code readability.

    Low
    Add explicit None check

    The string conversion and substring check could fail if extra_instructions is
    None or has unexpected type. Add explicit None check before string operations to
    prevent potential runtime errors.

    pr_agent/git_providers/utils.py [81-86]

    -if lang_instruction_text not in str(extra_instructions):
    +if extra_instructions is None or lang_instruction_text not in str(extra_instructions):
         updated_instructions = (
             str(extra_instructions) + separator_text + lang_instruction_text
             if extra_instructions else lang_instruction_text
         )
         setting.extra_instructions = updated_instructions
    Suggestion importance[1-10]: 5

    __

    Why: The suggestion improves code clarity and robustness by adding an explicit extra_instructions is None check. While the original code handles the None case correctly due to the ternary operator, the suggested change makes the intent clearer and avoids the potentially confusing str(None) conversion in the condition.

    Low
    Fix case-insensitive string comparison

    The comparison should be case-insensitive for both the retrieved value and the
    default. The current code only lowercases the retrieved value but not the
    default comparison value.

    pr_agent/git_providers/utils.py [67-68]

     response_language = get_settings().config.get('response_language', 'en-us')
    -if response_language.lower() != 'en-us':
    +if response_language.lower() != 'en-us'.lower():
    Suggestion importance[1-10]: 1

    __

    Why: The suggestion to use .lower() on the hardcoded string 'en-us' is redundant because the string is already in lowercase. This change has no functional impact on the code's behavior.

    Low

    @mrT23
    Copy link
    Collaborator

    mrT23 commented Jun 13, 2025

    This is not the correct place to add it. it will cause duplication and unwanted repititions

    Add it here instead

    pr_agent/servers/github_action_runner.py

    @smallfish06
    Copy link
    Contributor Author

    @mrT23 Thanks. Moved those codes to pr_agent/servers/github_action_runner.py

    Co-authored-by: qodo-merge-for-open-source[bot] <189517486+qodo-merge-for-open-source[bot]@users.noreply.github.com>
    @mrT23 mrT23 merged commit 1c5f203 into qodo-ai:main Jun 17, 2025
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Projects

    None yet

    Development

    Successfully merging this pull request may close these issues.

    3 participants