Skip to content

fix(openrouter): normalize reasoning controls - #2837

Merged
IsmaelMartinez merged 1 commit into
The-PR-Agent:mainfrom
PeterDaveHello:fix/openrouterReasoningControls
Aug 27, 2026
Merged

fix(openrouter): normalize reasoning controls#2837
IsmaelMartinez merged 1 commit into
The-PR-Agent:mainfrom
PeterDaveHello:fix/openrouterReasoningControls

Conversation

@PeterDaveHello

@PeterDaveHello PeterDaveHello commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Summary

  • route registered models global reasoning effort through the OpenRouter unified reasoning object instead of the LiteLLM 1.98.0 model-gated top-level parameter
  • support OpenRouter routing variants while preserving the original model ID
  • validate provider overrides, normalize max to xhigh, preserve explicit disablement, and keep effort and token budgets mutually exclusive
  • document and warn about model-specific reasoning limits

Behavior changes

  • models listed in SUPPORT_REASONING_EFFORT_MODELS inherit config.reasoning_effort, including OpenRouter :nitro and :floor variants, when no provider-specific effort or positive token budget is set
  • explicit openrouter.reasoning_effort = none keeps reasoning disabled even when a token budget is also configured
  • a positive openrouter.reasoning_max_tokens value takes precedence over the global effort and other non-none OpenRouter-specific efforts, with a warning when a configured effort is ignored
  • invalid OpenRouter-specific effort values emit a warning and are treated as unset
  • max is normalized to xhigh to match the pinned LiteLLM OpenRouter adapter behavior
  • mandatory-reasoning models may reject none; active Anthropic reasoning budgets warn when the effective output cap does not exceed the budget

Testing

  • focused OpenRouter and reasoning-effort suites: 62 passed
  • pinned LiteLLM parameter-validation boundary canary: 1 passed
  • Python compilation and git diff whitespace checks passed

References

@qodo-code-review

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

Normalize OpenRouter reasoning controls

🐞 Bug fix 🧪 Tests 📝 Documentation 🕐 20-40 Minutes

Grey Divider

AI Description

• Route OpenRouter reasoning through unified request bodies to satisfy LiteLLM parameter validation.
• Enforce override validation, max normalization, global fallback, and token-budget precedence.
• Document behavior and add regression coverage for precedence and state isolation.
Diagram

graph TD
  A["Global config"] --> B["LiteLLM handler"] --> C{"OpenRouter model?"} -->|Yes| D["Reasoning normalization"] --> E["extra_body.reasoning"] --> F["LiteLLM"] --> G["OpenRouter API"]
  C -->|No| H["Top-level effort"] --> F
Loading
High-Level Assessment

The PR's provider-specific split is the appropriate approach: it retains LiteLLM's native top-level mapping where supported while using OpenRouter's documented unified reasoning object at the incompatible boundary. Direct OpenRouter calls or globally forcing extra_body would duplicate transport logic or risk changing other providers, so neither is preferable.

Files changed (6) +182 / -47

Bug fix (1) +42 / -16
litellm_ai_handler.pyNormalize OpenRouter reasoning controls +42/-16

Normalize OpenRouter reasoning controls

• Defers registered OpenRouter models from LiteLLM's unsupported top-level reasoning parameter into extra_body.reasoning. It validates provider overrides, inherits the global effort when appropriate, gives positive token budgets precedence, and maps max to xhigh.

pr_agent/algo/ai_handlers/litellm_ai_handler.py

Tests (2) +125 / -16
test_litellm_openrouter_controls.pyExpand OpenRouter reasoning regression coverage +122/-11

Expand OpenRouter reasoning regression coverage

• Adds coverage for global inheritance, provider overrides, invalid-value fallback, disablement, max normalization, and token-budget precedence. It also pins LiteLLM's parameter-validation boundary and restores drop_params to isolate global test state.

tests/unittest/test_litellm_openrouter_controls.py

test_litellm_reasoning_effort.pySeparate native Gemini reasoning expectations +3/-5

Separate native Gemini reasoning expectations

• Removes OpenRouter-prefixed Gemini models from top-level reasoning-effort expectations and points those cases to the dedicated OpenRouter suite.

tests/unittest/test_litellm_reasoning_effort.py

Documentation (2) +10 / -11
changing_a_model.mdDocument OpenRouter reasoning precedence and fallback +5/-5

Document OpenRouter reasoning precedence and fallback

• Explains inheritance from the global reasoning effort, supported values, token-budget precedence, invalid-value fallback, and the max alias. It also refreshes links to current OpenRouter guidance.

docs/docs/usage-guide/changing_a_model.md

__init__.pyClarify provider-specific Gemini reasoning routing +5/-6

Clarify provider-specific Gemini reasoning routing

• Updates the Gemini reasoning-model registry commentary to distinguish native LiteLLM mapping from OpenRouter unified reasoning handling.

pr_agent/algo/init.py

Other (1) +5 / -4
configuration.tomlDefine OpenRouter reasoning configuration semantics +5/-4

Define OpenRouter reasoning configuration semantics

• Documents valid effort values, global fallback behavior, invalid-value handling, and token-budget precedence. Reference links are updated to current OpenRouter documentation.

pr_agent/settings/configuration.toml

@qodo-code-review

qodo-code-review Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (6) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Gemini docstring uses narrative 📘 Rule violation ⚙ Maintainability ⭐ New
Description
The modified class docstring narrates behavior with membership test ... matches and `OpenRouter
models use` instead of imperative phrasing. This violates the required comment and docstring style.
Code

tests/unittest/test_litellm_reasoning_effort.py[R863-865]

+    membership test in chat_completion matches bare and provider-prefixed ids such as
+    "vertex_ai/gemini-2.5-pro". OpenRouter models use extra_body.reasoning instead and
+    are covered by test_litellm_openrouter_controls.py.
Relevance

●●● Strong

Recent accepted precedents support imperative rewrites for modified test docstrings, including a
class docstring.

PR-#2807
PR-#2703

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 2694688 requires imperative phrasing in modified docstrings and comments. The changed class
docstring uses descriptive statements at lines 863-865 rather than imperative wording.

Rule 2694688: Docstrings and comments must use imperative phrasing
tests/unittest/test_litellm_reasoning_effort.py[863-865]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Rewrite the modified Gemini reasoning docstring text so its behavioral guidance uses imperative phrasing rather than descriptive statements.

## Issue Context
Compliance rule 2694688 requires modified docstrings and behavior comments to use imperative phrasing.

## Fix Focus Areas
- tests/unittest/test_litellm_reasoning_effort.py[863-865]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Ignored budget triggers warning ✓ Resolved 🐞 Bug ◔ Observability
Description
When openrouter.reasoning_effort="none" is combined with a positive budget, the code correctly
drops reasoning_max_tokens but the new Anthropic check still compares output tokens against that
ignored value. This emits a false “must be greater” warning even though the outgoing reasoning
payload is only {"enabled": false}, obscuring which configuration is actually active.
Code

pr_agent/algo/ai_handlers/litellm_ai_handler.py[R974-976]

+                        model.startswith("openrouter/anthropic/")
+                        and reasoning_max_tokens > 0
+                        and 0 < effective_max_tokens <= reasoning_max_tokens
Relevance

●●● Strong

Clear false-warning bug: recent handler precedents accept scoped validation preventing inactive or
incompatible settings from affecting requests.

PR-#2518
PR-#2610

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The explicit-none branch logs that the budget is ignored and emits only reasoning.enabled = false,
but the later new condition independently tests the original positive reasoning_max_tokens and can
therefore emit the output-headroom warning for a budget absent from the request.

pr_agent/algo/ai_handlers/litellm_ai_handler.py[939-954]
pr_agent/algo/ai_handlers/litellm_ai_handler.py[972-981]
tests/unittest/test_litellm_openrouter_controls.py[167-172]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Anthropic headroom warning uses the configured `reasoning_max_tokens` even when explicit `reasoning_effort = "none"` caused that budget to be ignored, producing contradictory diagnostics.

## Issue Context
The warning should run only when the final OpenRouter reasoning payload actually contains a positive `max_tokens` budget.

## Fix Focus Areas
- pr_agent/algo/ai_handlers/litellm_ai_handler.py[939-980]
- tests/unittest/test_litellm_openrouter_controls.py[167-173]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Settings comments use narrative ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
The new reasoning_effort and precedence comments use passive or descriptive phrasing such as
values are warned about and A positive value takes precedence. These behavior comments do not
follow the required imperative style.
Code

pr_agent/settings/configuration.toml[R415-416]

+# Invalid reasoning_effort values are warned about and treated as unset.
+# Empty uses config.reasoning_effort for registered reasoning models.
Relevance

●●● Strong

Recent PRs #2823 and #2796 show configuration.toml narrative comments accepted for imperative
rewrite.

PR-#2823
PR-#2796

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 2694688 applies to newly modified comments. The settings comments describe behavior passively
(values are warned about) and narratively (Empty uses, A positive value takes precedence)
instead of using imperative instructions.

Rule 2694688: Docstrings and comments must use imperative phrasing
pr_agent/settings/configuration.toml[415-419]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Rewrite the modified OpenRouter setting comments as direct instructions while retaining the documented defaults and precedence.

## Issue Context
PR Compliance ID 2694688 requires modified behavior comments to use imperative phrasing rather than passive or descriptive statements.

## Fix Focus Areas
- pr_agent/settings/configuration.toml[415-419]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View medium (6)
4. Gemini comment uses narrative 📘 Rule violation ⚙ Maintainability
Description
The revised Gemini block comment describes behavior with narrative phrasing such as `Gemini 2.5
exposes` instead of an imperative instruction. This violates the required phrasing convention for
modified comments.
Code

pr_agent/algo/init.py[R397-400]

+    # Gemini 2.5 exposes a thinking budget controlled by reasoning_effort. Without
+    # these entries a configured effort is silently dropped, so a runaway thinking
+    # trace can consume the whole output budget and return an empty completion.
+    # LiteLLM maps native provider paths to thinkingConfig.thinkingBudget, while
Relevance

●●● Strong

Team consistently rewrites narrative comments to imperative phrasing per rule 2694688 (PR #2817,
#2797).

PR-#2817
PR-#2797

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 2694688 requires imperative phrasing in modified comments. The cited block begins with
descriptive statements such as Gemini 2.5 exposes and LiteLLM maps rather than imperative
wording.

Rule 2694688: Docstrings and comments must use imperative phrasing
pr_agent/algo/init.py[397-401]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Rewrite the modified Gemini reasoning comment so behavior-oriented sentences use imperative phrasing.

## Issue Context
PR Compliance ID 2694688 requires newly modified comments to use commands or instructions rather than descriptive narrative.

## Fix Focus Areas
- pr_agent/algo/__init__.py[397-401]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. OpenRouter comments use narrative 📘 Rule violation ⚙ Maintainability
Description
Several newly added OpenRouter comments narrate behavior with phrases such as `Some OpenRouter
models reject, Registered reasoning models inherit, and OpenRouter treats`. They should use
imperative instructions under the comment phrasing rule.
Code

pr_agent/algo/ai_handlers/litellm_ai_handler.py[R772-773]

+                        # Some OpenRouter models reject LiteLLM's top-level parameter;
+                        # defer to OpenRouter's unified reasoning object below.
Relevance

●●● Strong

Strong precedent: reviewers repeatedly require imperative comment rewrites in litellm_ai_handler.py
(PR #2817, #2797).

PR-#2817
PR-#2797

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 2694688 requires modified behavior comments to be imperative. The cited comments use
descriptive constructions including Some OpenRouter models reject, `Registered reasoning models
inherit, OpenRouter treats, and OpenRouter uses`.

Rule 2694688: Docstrings and comments must use imperative phrasing
pr_agent/algo/ai_handlers/litellm_ai_handler.py[772-773]
pr_agent/algo/ai_handlers/litellm_ai_handler.py[872-873]
pr_agent/algo/ai_handlers/litellm_ai_handler.py[927-928]
pr_agent/algo/ai_handlers/litellm_ai_handler.py[939-940]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Rewrite the newly modified OpenRouter behavior comments in imperative mood while preserving their technical meaning.

## Issue Context
PR Compliance ID 2694688 disallows narrative behavior descriptions in newly added or modified comments. Use instruction-style wording such as `Route`, `Prefer`, or `Normalize`.

## Fix Focus Areas
- pr_agent/algo/ai_handlers/litellm_ai_handler.py[772-773]
- pr_agent/algo/ai_handlers/litellm_ai_handler.py[872-873]
- pr_agent/algo/ai_handlers/litellm_ai_handler.py[927-928]
- pr_agent/algo/ai_handlers/litellm_ai_handler.py[939-940]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Effort setting exceeds line limit ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
The modified reasoning_effort setting and its expanded inline documentation exceed 120 characters.
Keeping the explanation on the same line violates the maximum line-length rule.
Code

pr_agent/settings/configuration.toml[416]

+reasoning_effort = "" # override config.reasoning_effort; "" uses the configured value for registered reasoning models; valid: "none", "minimal", "low", "medium", "high", "xhigh", "max"
Relevance

●●● Strong

Recent configuration reviews accepted wrapping overlong comments and enforcing the 120-character
limit.

PR-#2796
PR-#2622

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 2694690 applies a 120-character maximum to modified source files; line 416 combines the setting
with a long list of valid values and exceeds that maximum.

Rule 2694690: Enforce maximum line length of 120 characters
pr_agent/settings/configuration.toml[416-416]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The `reasoning_effort` configuration line exceeds 120 characters because of its expanded inline comment.

## Issue Context
Move or wrap the explanatory text into preceding TOML comment lines while leaving the key and default unchanged.

## Fix Focus Areas
- pr_agent/settings/configuration.toml[416-416]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. Budget setting exceeds line limit ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
The modified reasoning_max_tokens setting and precedence explanation exceed 120 characters on one
line. The explanatory comment should be wrapped or moved above the key.
Code

pr_agent/settings/configuration.toml[417]

+reasoning_max_tokens = 0 # explicit token budget; a positive value takes precedence over reasoning_effort, including "none"; 0 = unset
Relevance

●●● Strong

Recent configuration reviews accepted wrapping overlong inline comments to satisfy the line-length
rule.

PR-#2796
PR-#2622

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 2694690 requires modified non-generated source lines to stay within 120 characters, while
changed line 417 includes a lengthy precedence comment beyond that limit.

Rule 2694690: Enforce maximum line length of 120 characters
pr_agent/settings/configuration.toml[417-417]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The `reasoning_max_tokens` configuration line exceeds the repository's 120-character maximum.

## Issue Context
Preserve the default and precedence semantics, but place the longer explanation on preceding TOML comment lines.

## Fix Focus Areas
- pr_agent/settings/configuration.toml[417-417]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. Test docstring uses description ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
The new test docstring starts with descriptive third-person phrasing, A token budget suppresses,
rather than an imperative verb. This violates the required docstring phrasing convention.
Code

tests/unittest/test_litellm_openrouter_controls.py[139]

+        """A token budget suppresses the mutually exclusive effort control."""
Relevance

●● Moderate

Imperative docstring findings have mixed outcomes; recent test-docstring examples were accepted, but
similar descriptive wording was rejected.

PR-#2807
PR-#2703
PR-#2661

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 2694688 requires newly added function or method docstrings to begin in imperative mood; line
139 instead begins with the descriptive subject-and-verb phrase A token budget suppresses.

Rule 2694688: Docstrings and comments must use imperative phrasing
tests/unittest/test_litellm_openrouter_controls.py[139-139]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new `test_reasoning_max_tokens` docstring uses descriptive rather than imperative phrasing.

## Issue Context
Start the sentence with an imperative verb while retaining the explanation of mutually exclusive controls, for example `Verify that a token budget suppresses the mutually exclusive effort control.`

## Fix Focus Areas
- tests/unittest/test_litellm_openrouter_controls.py[139-139]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


9. Model guidance exceeds 120 characters 📘 Rule violation ⚙ Maintainability
Description
The updated OpenRouter behavior paragraph is kept on one physical line exceeding the 120-character
maximum. This reduces readability and violates the repository-wide line-length requirement.
Code

docs/docs/usage-guide/changing_a_model.md[522]

+For `openrouter/...` models you can optionally restrict which upstream providers Openrouter uses, control reasoning, and cap the completion length. All keys live in the `[openrouter]` section of `configuration.toml`. Registered reasoning models inherit `config.reasoning_effort` unless an Openrouter-specific effort or token budget is set.
Evidence
Rule 2694690 limits non-generated source lines to 120 characters, while the changed Markdown
paragraph at line 522 is visibly far longer than that limit.

Rule 2694690: Enforce maximum line length of 120 characters
docs/docs/usage-guide/changing_a_model.md[522-522]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The updated OpenRouter behavior paragraph exceeds the 120-character line limit.

## Issue Context
Preserve the Markdown rendering and wording while splitting the source across shorter physical lines.

## Fix Focus Areas
- docs/docs/usage-guide/changing_a_model.md[522-522]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

10. Precedence paragraph exceeds line limit 📘 Rule violation ⚙ Maintainability
Description
The expanded precedence and fallback documentation is placed on one line far beyond 120 characters.
It must be source-wrapped to satisfy the configured maximum.
Code

docs/docs/usage-guide/changing_a_model.md[535]

+`provider_only` and `reasoning_effort = "none"` are useful to pin a specific provider and to bound the cost of reasoning models. Because Openrouter treats effort and token budgets as mutually exclusive, a positive `reasoning_max_tokens` value takes precedence over every effort value, including `"none"`. Invalid Openrouter-specific effort values are warned about and treated as unset, so registered reasoning models fall back to `config.reasoning_effort`. See the Openrouter [provider routing](https://openrouter.ai/docs/guides/routing/provider-selection) and [reasoning tokens](https://openrouter.ai/docs/guides/best-practices/reasoning-tokens) docs.
Relevance

● Weak

Recent reviews rejected source-wrapping long documentation paragraphs on the same repository rule.

PR-#2817
PR-#2774
PR-#2796

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The repository-wide rule 2694690 sets a 120-character maximum, and changed line 535 contains the
entire multi-sentence explanation and two links on one physical line.

Rule 2694690: Enforce maximum line length of 120 characters
docs/docs/usage-guide/changing_a_model.md[535-535]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The updated OpenRouter precedence paragraph greatly exceeds the 120-character line limit.

## Issue Context
Split the Markdown source across physical lines while preserving the rendered paragraph, links, and semantics.

## Fix Focus Areas
- docs/docs/usage-guide/changing_a_model.md[535-535]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


11. Effort example exceeds 120 characters 📘 Rule violation ⚙ Maintainability
Description
The changed reasoning_effort example comment exceeds the 120-character maximum on a single line.
The example should be wrapped without changing its documented values.
Code

docs/docs/usage-guide/changing_a_model.md[530]

+# reasoning_effort = "low"             # override global effort: "none", "minimal", "low", "medium", "high", "xhigh" or "max"
Relevance

● Weak

Recent team precedent rejects wrapping long Markdown lines despite the 120-character rule.

PR-#2817
PR-#2774

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 2694690 requires lines to remain within 120 characters; the newly modified example at line 530
is approximately 126 characters.

Rule 2694690: Enforce maximum line length of 120 characters
docs/docs/usage-guide/changing_a_model.md[530-530]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The OpenRouter `reasoning_effort` example comment exceeds 120 characters.

## Issue Context
Keep the same allowed-value documentation while wrapping it into shorter Markdown/TOML example lines.

## Fix Focus Areas
- docs/docs/usage-guide/changing_a_model.md[530-530]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


  • Author self-review: I have reviewed the code review findings, and addressed the relevant ones.

Grey Divider

Context sources
✅ Compliance rules (platform): 34 rules
Review mode: ⚖️ Balanced: The push changes runtime reasoning-control behavior across several interacting precedence, validation, routing-variant, and provider-specific paths, creating real correctness risk, but it remains a coherent localized concern suitable for one careful review pass.

Grey Divider

Tip of the day
💡 Did you know, you can ask Qodo to dismiss a finding you disagree with, with your reason on record

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Previous reviews

Review updated until commit d6c7f1b

Results up to commit 44b6fc5 ⚖️ Balanced


🐞 Bugs (0) 📘 Rule violations (3) 📎 Requirement gaps (0) 🎨 UX issues (0) 📜 Skill insights (0)


Remediation recommended
1. Effort setting exceeds line limit ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
The modified reasoning_effort setting and its expanded inline documentation exceed 120 characters.
Keeping the explanation on the same line violates the maximum line-length rule.
Code

pr_agent/settings/configuration.toml[416]

+reasoning_effort = "" # override config.reasoning_effort; "" uses the configured value for registered reasoning models; valid: "none", "minimal", "low", "medium", "high", "xhigh", "max"
Relevance

●●● Strong

Recent configuration reviews accepted wrapping overlong comments and enforcing the 120-character
limit.

PR-#2796
PR-#2622

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 2694690 applies a 120-character maximum to modified source files; line 416 combines the setting
with a long list of valid values and exceeds that maximum.

Rule 2694690: Enforce maximum line length of 120 characters
pr_agent/settings/configuration.toml[416-416]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The `reasoning_effort` configuration line exceeds 120 characters because of its expanded inline comment.

## Issue Context
Move or wrap the explanatory text into preceding TOML comment lines while leaving the key and default unchanged.

## Fix Focus Areas
- pr_agent/settings/configuration.toml[416-416]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Budget setting exceeds line limit ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
The modified reasoning_max_tokens setting and precedence explanation exceed 120 characters on one
line. The explanatory comment should be wrapped or moved above the key.
Code

pr_agent/settings/configuration.toml[417]

+reasoning_max_tokens = 0 # explicit token budget; a positive value takes precedence over reasoning_effort, including "none"; 0 = unset
Relevance

●●● Strong

Recent configuration reviews accepted wrapping overlong inline comments to satisfy the line-length
rule.

PR-#2796
PR-#2622

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 2694690 requires modified non-generated source lines to stay within 120 characters, while
changed line 417 includes a lengthy precedence comment beyond that limit.

Rule 2694690: Enforce maximum line length of 120 characters
pr_agent/settings/configuration.toml[417-417]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The `reasoning_max_tokens` configuration line exceeds the repository's 120-character maximum.

## Issue Context
Preserve the default and precedence semantics, but place the longer explanation on preceding TOML comment lines.

## Fix Focus Areas
- pr_agent/settings/configuration.toml[417-417]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Model guidance exceeds 120 characters 📘 Rule violation ⚙ Maintainability
Description
The updated OpenRouter behavior paragraph is kept on one physical line exceeding the 120-character
maximum. This reduces readability and violates the repository-wide line-length requirement.
Code

docs/docs/usage-guide/changing_a_model.md[522]

+For `openrouter/...` models you can optionally restrict which upstream providers Openrouter uses, control reasoning, and cap the completion length. All keys live in the `[openrouter]` section of `configuration.toml`. Registered reasoning models inherit `config.reasoning_effort` unless an Openrouter-specific effort or token budget is set.
Evidence
Rule 2694690 limits non-generated source lines to 120 characters, while the changed Markdown
paragraph at line 522 is visibly far longer than that limit.

Rule 2694690: Enforce maximum line length of 120 characters
docs/docs/usage-guide/changing_a_model.md[522-522]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The updated OpenRouter behavior paragraph exceeds the 120-character line limit.

## Issue Context
Preserve the Markdown rendering and wording while splitting the source across shorter physical lines.

## Fix Focus Areas
- docs/docs/usage-guide/changing_a_model.md[522-522]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View medium (1)
4. Test docstring uses description ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
The new test docstring starts with descriptive third-person phrasing, A token budget suppresses,
rather than an imperative verb. This violates the required docstring phrasing convention.
Code

tests/unittest/test_litellm_openrouter_controls.py[139]

+        """A token budget suppresses the mutually exclusive effort control."""
Relevance

●● Moderate

Imperative docstring findings have mixed outcomes; recent test-docstring examples were accepted, but
similar descriptive wording was rejected.

PR-#2807
PR-#2703
PR-#2661

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 2694688 requires newly added function or method docstrings to begin in imperative mood; line
139 instead begins with the descriptive subject-and-verb phrase A token budget suppresses.

Rule 2694688: Docstrings and comments must use imperative phrasing
tests/unittest/test_litellm_openrouter_controls.py[139-139]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new `test_reasoning_max_tokens` docstring uses descriptive rather than imperative phrasing.

## Issue Context
Start the sentence with an imperative verb while retaining the explanation of mutually exclusive controls, for example `Verify that a token budget suppresses the mutually exclusive effort control.`

## Fix Focus Areas
- tests/unittest/test_litellm_openrouter_controls.py[139-139]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational
5. Precedence paragraph exceeds line limit 📘 Rule violation ⚙ Maintainability
Description
The expanded precedence and fallback documentation is placed on one line far beyond 120 characters.
It must be source-wrapped to satisfy the configured maximum.
Code

docs/docs/usage-guide/changing_a_model.md[535]

+`provider_only` and `reasoning_effort = "none"` are useful to pin a specific provider and to bound the cost of reasoning models. Because Openrouter treats effort and token budgets as mutually exclusive, a positive `reasoning_max_tokens` value takes precedence over every effort value, including `"none"`. Invalid Openrouter-specific effort values are warned about and treated as unset, so registered reasoning models fall back to `config.reasoning_effort`. See the Openrouter [provider routing](https://openrouter.ai/docs/guides/routing/provider-selection) and [reasoning tokens](https://openrouter.ai/docs/guides/best-practices/reasoning-tokens) docs.
Relevance

● Weak

Recent reviews rejected source-wrapping long documentation paragraphs on the same repository rule.

PR-#2817
PR-#2774
PR-#2796

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The repository-wide rule 2694690 sets a 120-character maximum, and changed line 535 contains the
entire multi-sentence explanation and two links on one physical line.

Rule 2694690: Enforce maximum line length of 120 characters
docs/docs/usage-guide/changing_a_model.md[535-535]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The updated OpenRouter precedence paragraph greatly exceeds the 120-character line limit.

## Issue Context
Split the Markdown source across physical lines while preserving the rendered paragraph, links, and semantics.

## Fix Focus Areas
- docs/docs/usage-guide/changing_a_model.md[535-535]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Effort example exceeds 120 characters 📘 Rule violation ⚙ Maintainability
Description
The changed reasoning_effort example comment exceeds the 120-character maximum on a single line.
The example should be wrapped without changing its documented values.
Code

docs/docs/usage-guide/changing_a_model.md[530]

+# reasoning_effort = "low"             # override global effort: "none", "minimal", "low", "medium", "high", "xhigh" or "max"
Relevance

● Weak

Recent team precedent rejects wrapping long Markdown lines despite the 120-character rule.

PR-#2817
PR-#2774

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 2694690 requires lines to remain within 120 characters; the newly modified example at line 530
is approximately 126 characters.

Rule 2694690: Enforce maximum line length of 120 characters
docs/docs/usage-guide/changing_a_model.md[530-530]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The OpenRouter `reasoning_effort` example comment exceeds 120 characters.

## Issue Context
Keep the same allowed-value documentation while wrapping it into shorter Markdown/TOML example lines.

## Fix Focus Areas
- docs/docs/usage-guide/changing_a_model.md[530-530]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Results up to commit 54cdcdb ⚖️ Balanced


🐞 Bugs (0) 📘 Rule violations (2) 📎 Requirement gaps (0) 🎨 UX issues (0) 📜 Skill insights (0)


Remediation recommended
1. Gemini comment uses narrative 📘 Rule violation ⚙ Maintainability
Description
The revised Gemini block comment describes behavior with narrative phrasing such as `Gemini 2.5
exposes` instead of an imperative instruction. This violates the required phrasing convention for
modified comments.
Code

pr_agent/algo/init.py[R397-400]

+    # Gemini 2.5 exposes a thinking budget controlled by reasoning_effort. Without
+    # these entries a configured effort is silently dropped, so a runaway thinking
+    # trace can consume the whole output budget and return an empty completion.
+    # LiteLLM maps native provider paths to thinkingConfig.thinkingBudget, while
Relevance

●●● Strong

Team consistently rewrites narrative comments to imperative phrasing per rule 2694688 (PR #2817,
#2797).

PR-#2817
PR-#2797

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 2694688 requires imperative phrasing in modified comments. The cited block begins with
descriptive statements such as Gemini 2.5 exposes and LiteLLM maps rather than imperative
wording.

Rule 2694688: Docstrings and comments must use imperative phrasing
pr_agent/algo/init.py[397-401]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Rewrite the modified Gemini reasoning comment so behavior-oriented sentences use imperative phrasing.

## Issue Context
PR Compliance ID 2694688 requires newly modified comments to use commands or instructions rather than descriptive narrative.

## Fix Focus Areas
- pr_agent/algo/__init__.py[397-401]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. OpenRouter comments use narrative 📘 Rule violation ⚙ Maintainability
Description
Several newly added OpenRouter comments narrate behavior with phrases such as `Some OpenRouter
models reject, Registered reasoning models inherit, and OpenRouter treats`. They should use
imperative instructions under the comment phrasing rule.
Code

pr_agent/algo/ai_handlers/litellm_ai_handler.py[R772-773]

+                        # Some OpenRouter models reject LiteLLM's top-level parameter;
+                        # defer to OpenRouter's unified reasoning object below.
Relevance

●●● Strong

Strong precedent: reviewers repeatedly require imperative comment rewrites in litellm_ai_handler.py
(PR #2817, #2797).

PR-#2817
PR-#2797

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 2694688 requires modified behavior comments to be imperative. The cited comments use
descriptive constructions including Some OpenRouter models reject, `Registered reasoning models
inherit, OpenRouter treats, and OpenRouter uses`.

Rule 2694688: Docstrings and comments must use imperative phrasing
pr_agent/algo/ai_handlers/litellm_ai_handler.py[772-773]
pr_agent/algo/ai_handlers/litellm_ai_handler.py[872-873]
pr_agent/algo/ai_handlers/litellm_ai_handler.py[927-928]
pr_agent/algo/ai_handlers/litellm_ai_handler.py[939-940]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Rewrite the newly modified OpenRouter behavior comments in imperative mood while preserving their technical meaning.

## Issue Context
PR Compliance ID 2694688 disallows narrative behavior descriptions in newly added or modified comments. Use instruction-style wording such as `Route`, `Prefer`, or `Normalize`.

## Fix Focus Areas
- pr_agent/algo/ai_handlers/litellm_ai_handler.py[772-773]
- pr_agent/algo/ai_handlers/litellm_ai_handler.py[872-873]
- pr_agent/algo/ai_handlers/litellm_ai_handler.py[927-928]
- pr_agent/algo/ai_handlers/litellm_ai_handler.py[939-940]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Settings comments use narrative ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
The new reasoning_effort and precedence comments use passive or descriptive phrasing such as
values are warned about and A positive value takes precedence. These behavior comments do not
follow the required imperative style.
Code

pr_agent/settings/configuration.toml[R415-416]

+# Invalid reasoning_effort values are warned about and treated as unset.
+# Empty uses config.reasoning_effort for registered reasoning models.
Relevance

●●● Strong

Recent PRs #2823 and #2796 show configuration.toml narrative comments accepted for imperative
rewrite.

PR-#2823
PR-#2796

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 2694688 applies to newly modified comments. The settings comments describe behavior passively
(values are warned about) and narratively (Empty uses, A positive value takes precedence)
instead of using imperative instructions.

Rule 2694688: Docstrings and comments must use imperative phrasing
pr_agent/settings/configuration.toml[415-419]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Rewrite the modified OpenRouter setting comments as direct instructions while retaining the documented defaults and precedence.

## Issue Context
PR Compliance ID 2694688 requires modified behavior comments to use imperative phrasing rather than passive or descriptive statements.

## Fix Focus Areas
- pr_agent/settings/configuration.toml[415-419]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Results up to commit 2c9e974 ⚖️ Balanced


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 📜 Skill insights (0)


Remediation recommended
1. Ignored budget triggers warning ✓ Resolved 🐞 Bug ◔ Observability
Description
When openrouter.reasoning_effort="none" is combined with a positive budget, the code correctly
drops reasoning_max_tokens but the new Anthropic check still compares output tokens against that
ignored value. This emits a false “must be greater” warning even though the outgoing reasoning
payload is only {"enabled": false}, obscuring which configuration is actually active.
Code

pr_agent/algo/ai_handlers/litellm_ai_handler.py[R974-976]

+                        model.startswith("openrouter/anthropic/")
+                        and reasoning_max_tokens > 0
+                        and 0 < effective_max_tokens <= reasoning_max_tokens
Relevance

●●● Strong

Clear false-warning bug: recent handler precedents accept scoped validation preventing inactive or
incompatible settings from affecting requests.

PR-#2518
PR-#2610

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The explicit-none branch logs that the budget is ignored and emits only reasoning.enabled = false,
but the later new condition independently tests the original positive reasoning_max_tokens and can
therefore emit the output-headroom warning for a budget absent from the request.

pr_agent/algo/ai_handlers/litellm_ai_handler.py[939-954]
pr_agent/algo/ai_handlers/litellm_ai_handler.py[972-981]
tests/unittest/test_litellm_openrouter_controls.py[167-172]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Anthropic headroom warning uses the configured `reasoning_max_tokens` even when explicit `reasoning_effort = "none"` caused that budget to be ignored, producing contradictory diagnostics.

## Issue Context
The warning should run only when the final OpenRouter reasoning payload actually contains a positive `max_tokens` budget.

## Fix Focus Areas
- pr_agent/algo/ai_handlers/litellm_ai_handler.py[939-980]
- tests/unittest/test_litellm_openrouter_controls.py[167-173]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@PeterDaveHello
PeterDaveHello force-pushed the fix/openrouterReasoningControls branch from 44b6fc5 to 54cdcdb Compare August 27, 2026 18:33
@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 54cdcdb

@PeterDaveHello
PeterDaveHello force-pushed the fix/openrouterReasoningControls branch from 54cdcdb to 2c9e974 Compare August 27, 2026 18:56
@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 2c9e974

Route registered models' global reasoning effort through OpenRouter's
unified reasoning object instead of LiteLLM 1.98.0's model-gated
top-level parameter.

Validate provider-specific overrides, preserve explicit disablement,
fall back to the global value when they are invalid, normalize max to
xhigh, and keep effort and token budgets mutually exclusive.

Update the configuration guide and add regression coverage for LiteLLM
validation, OpenRouter variants, precedence, model-specific limits, and
global-state isolation.

References:
- https://openrouter.ai/docs/guides/best-practices/reasoning-tokens
@PeterDaveHello
PeterDaveHello force-pushed the fix/openrouterReasoningControls branch from 2c9e974 to d6c7f1b Compare August 27, 2026 19:03
@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit d6c7f1b

@IsmaelMartinez IsmaelMartinez left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, tested and works.

Worth saying this is a real breakage rather than a nicety: on stock config openrouter/google/gemini-2.5-pro fails outright with UnsupportedParamsError. Nothing outside openrouter/ changes.

One fix inline: setting only reasoning_max_tokens warns on every request. Qodo's six open findings are comment-phrasing and line-length rules I would not hold you to, though changing_a_model.md:535 is worth a glance since it went from 304 characters to 1098.

Comment on lines +930 to +937
if not effective_reasoning_effort:
if reasoning_max_tokens > 0 and openrouter_reasoning_effort:
get_logger().warning(
f"Ignoring config.reasoning_effort='{openrouter_reasoning_effort}' because "
"openrouter.reasoning_max_tokens takes precedence."
)
elif reasoning_max_tokens <= 0:
effective_reasoning_effort = openrouter_reasoning_effort or ""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

openrouter_reasoning_effort carries config.reasoning_effort, which ships as medium, so anyone setting only openrouter.reasoning_max_tokens gets this warning on every request without having configured anything contradictory.

none is the genuine contradiction, and the only case with a test asserting a warning. Demoting the rest keeps the signal; your 62 tests still pass.

Suggested change
if not effective_reasoning_effort:
if reasoning_max_tokens > 0 and openrouter_reasoning_effort:
get_logger().warning(
f"Ignoring config.reasoning_effort='{openrouter_reasoning_effort}' because "
"openrouter.reasoning_max_tokens takes precedence."
)
elif reasoning_max_tokens <= 0:
effective_reasoning_effort = openrouter_reasoning_effort or ""
if not effective_reasoning_effort:
if reasoning_max_tokens > 0 and openrouter_reasoning_effort:
message = (
f"Ignoring config.reasoning_effort='{openrouter_reasoning_effort}' because "
"openrouter.reasoning_max_tokens takes precedence."
)
if openrouter_reasoning_effort == "none":
get_logger().warning(message)
else:
get_logger().info(message)
elif reasoning_max_tokens <= 0:
effective_reasoning_effort = openrouter_reasoning_effort or ""

@IsmaelMartinez
IsmaelMartinez merged commit c27c0ef into The-PR-Agent:main Aug 27, 2026
5 checks passed
@PeterDaveHello
PeterDaveHello deleted the fix/openrouterReasoningControls branch September 1, 2026 15:14
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.

2 participants