Skip to content

fix(litellm): detect GPT-5 family when model has openai/ or azure/ prefix#2401

Open
sizickp wants to merge 4 commits into
The-PR-Agent:mainfrom
sizickp:fix/gpt-5-prefix-detection
Open

fix(litellm): detect GPT-5 family when model has openai/ or azure/ prefix#2401
sizickp wants to merge 4 commits into
The-PR-Agent:mainfrom
sizickp:fix/gpt-5-prefix-detection

Conversation

@sizickp
Copy link
Copy Markdown

@sizickp sizickp commented May 18, 2026

Summary

GPT-5 codex models only accept temperature=1. The LiteLLM handler swaps temperature for reasoning_effort only when the model string starts with gpt-5, but users frequently put the full provider-qualified name in [config].model (e.g. openai/gpt-5.1-codex-max). That prefix makes model.startswith('gpt-5') return False, so the handler still sends temperature=0.2 and litellm rejects the call:

litellm.UnsupportedParamsError: gpt-5 models (including gpt-5-codex) don't support temperature=0.2.
Only temperature=1 is supported. ...
Failed to generate prediction with openai/gpt-5.1-codex-max

The primary model always errors, and PR-Agent silently falls back to the secondary model on every invocation — degrading answer quality vs. the configured model, doubling per-call latency, and burning input tokens on a request that can never succeed.

Fix

In pr_agent/algo/ai_handlers/litellm_ai_handler.py::chat_completion, normalize the model name by stripping the openai/ / azure/ prefix before the GPT-5 detection, then rebuild the routed name with the original provider prefix (so Azure routing is preserved when self.azure is set).

This is a minimal, surgical change — no behavior changes for unprefixed names, no widening of the heuristic; just the prefix-aware detection.

Repro

configuration.toml:

[config]
model = "openai/gpt-5.1-codex-max"
fallback_models = ["gpt-5.4-mini"]

Before: every call logs the warning above and falls back. After: the GPT-5 branch runs, reasoning_effort is set, temperature is dropped, and the primary model is used.

Test plan

  • Added test_gpt5_with_openai_prefix_triggers_reasoning_effort covering openai/gpt-5, openai/gpt-5.1-codex, openai/gpt-5.1-codex-max, openai/gpt-5.4-mini. Asserts reasoning_effort is set, temperature is not in kwargs, and the model name is not double-prefixed (openai/openai/...).
  • Added test_gpt5_with_openai_prefix_strips_thinking_suffix for openai/gpt-5_thinking — verifies suffix is removed and provider prefix kept exactly once.
  • All existing test_litellm_* suites still pass (68 tests).

GPT-5 codex models only accept `temperature=1`. The handler converted
`temperature` into `reasoning_effort` only when the model string started
with `gpt-5`, but users frequently set the full provider-qualified name
in their config (e.g. `openai/gpt-5.1-codex-max`). That prefix made the
`startswith('gpt-5')` check fail, so `temperature=0.2` was sent and
litellm rejected the request with `UnsupportedParamsError`. The primary
model then always fell back to the secondary one — silently downgrading
quality and doubling per-call latency/cost.

Normalize the model name by stripping the `openai/` / `azure/` prefix
before the GPT-5 check, and rebuild the routed name with the original
provider so Azure routing is preserved.

Adds regression tests for `openai/gpt-5*` (including `codex-max`) and
for the `_thinking` suffix together with a prefix.
@github-actions github-actions Bot added the bug label May 18, 2026
@qodo-free-for-open-source-projects
Copy link
Copy Markdown
Contributor

Review Summary by Qodo

Fix GPT-5 detection with provider-prefixed model names

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Strip provider prefix before GPT-5 detection to handle prefixed model names
• Preserve original provider prefix in routed model name for Azure compatibility
• Add regression tests for openai/gpt-5* variants and _thinking suffix handling
Diagram
flowchart LR
  A["Model name with prefix<br/>openai/gpt-5.1-codex-max"] -->|removeprefix| B["Normalized base<br/>gpt-5.1-codex-max"]
  B -->|startswith check| C["GPT-5 path triggered"]
  C -->|set reasoning_effort| D["Drop temperature"]
  D -->|rebuild with prefix| E["Route to openai/gpt-5.1-codex-max"]
Loading

Grey Divider

File Changes

1. pr_agent/algo/ai_handlers/litellm_ai_handler.py 🐞 Bug fix +9/-2

Normalize model name for GPT-5 prefix detection

• Strip openai/ and azure/ prefixes from model name before GPT-5 detection
• Rebuild model name with original provider prefix to preserve Azure routing
• Remove _thinking suffix from normalized base model, not the prefixed version
• Add detailed comments explaining the prefix-aware detection logic

pr_agent/algo/ai_handlers/litellm_ai_handler.py


2. tests/unittest/test_litellm_reasoning_effort.py 🧪 Tests +59/-0

Add regression tests for prefixed GPT-5 models

• Add test_gpt5_with_openai_prefix_triggers_reasoning_effort covering four prefixed GPT-5 variants
• Verify reasoning_effort is set and temperature is not in kwargs for prefixed models
• Assert model name is not double-prefixed when passed to litellm
• Add test_gpt5_with_openai_prefix_strips_thinking_suffix for openai/gpt-5_thinking edge case

tests/unittest/test_litellm_reasoning_effort.py


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link
Copy Markdown
Contributor

qodo-free-for-open-source-projects Bot commented May 18, 2026

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0)

Grey Divider


Action required

1. patch() line exceeds 120 ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
Several newly added with patch(...) lines in the unit tests exceed the repository's 120-character
line limit, which is enforced by the project's Ruff configuration. This can cause lint/CI failures
and reduces readability.
Code

tests/unittest/test_litellm_reasoning_effort.py[707]

+            with patch('pr_agent.algo.ai_handlers.litellm_ai_handler.acompletion', new_callable=AsyncMock) as mock_completion:
Evidence
PR Compliance ID 9 requires respecting the 120-character line length. The newly added `with
patch(...)` statements are written on single lines that exceed this limit.

AGENTS.md
tests/unittest/test_litellm_reasoning_effort.py[707-707]
tests/unittest/test_litellm_reasoning_effort.py[731-731]
tests/unittest/test_litellm_reasoning_effort.py[751-751]
tests/unittest/test_litellm_reasoning_effort.py[782-782]

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

## Issue description
New test code introduces lines longer than 120 characters (notably `with patch('pr_agent.algo.ai_handlers.litellm_ai_handler.acompletion', ...)`), violating the repo's 120-character line-length convention.
## Issue Context
`pyproject.toml` configures Ruff with `line-length = 120`, so these lines are likely to fail linting.
## Fix Focus Areas
- tests/unittest/test_litellm_reasoning_effort.py[707-707]
- tests/unittest/test_litellm_reasoning_effort.py[731-731]
- tests/unittest/test_litellm_reasoning_effort.py[751-751]
- tests/unittest/test_litellm_reasoning_effort.py[782-782]

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


2. Azure+prefix skips GPT-5 ✓ Resolved 🐞 Bug ≡ Correctness
Description
In Azure mode, chat_completion() prepends azure/ before computing model_base, and the new
removeprefix() chain only removes a single leading provider prefix. If the configured model is
already provider-qualified (e.g. openai/gpt-5* or azure/gpt-5*), model_base can still start
with openai/ or azure/, so the GPT-5 branch is skipped and temperature is sent (triggering the
same LiteLLM UnsupportedParamsError this PR aims to fix).
Code

pr_agent/algo/ai_handlers/litellm_ai_handler.py[R438-440]

+                model_base = model.removeprefix('openai/').removeprefix('azure/')
+                if model_base.startswith('gpt-5'):
              # Use configured reasoning_effort or default to MEDIUM
Evidence
chat_completion() prepends azure/ before the new GPT-5 normalization; the new normalization
removes only one leading prefix, so any provider-qualified model string in Azure mode can still have
a provider segment at the start of model_base and fail GPT-5 detection. Models are sourced from
config/fallbacks without restrictions, so provider-qualified strings are feasible inputs.

pr_agent/algo/ai_handlers/litellm_ai_handler.py[409-413]
pr_agent/algo/ai_handlers/litellm_ai_handler.py[433-461]
pr_agent/algo/pr_processing.py[341-354]

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

## Issue description
In `LiteLLMAIHandler.chat_completion()`, GPT-5 detection relies on `model_base` computed via `removeprefix('openai/').removeprefix('azure/')`. When `self.azure` is enabled, the function prepends `azure/` to the model first; if the incoming model already has a provider prefix, the resulting string can contain multiple provider segments (e.g. `azure/openai/gpt-5...` or `azure/azure/gpt-5...`). The current normalization removes at most one leading prefix, so `model_base` may still begin with a provider segment and fail `startswith('gpt-5')`, causing `temperature` to be passed to GPT-5.
### Issue Context
Models come directly from user configuration/fallback lists and can be provider-qualified strings.
### Fix Focus Areas
- pr_agent/algo/ai_handlers/litellm_ai_handler.py[409-413]
- pr_agent/algo/ai_handlers/litellm_ai_handler.py[433-461]
- pr_agent/algo/pr_processing.py[341-354]
### Suggested fix
Refactor provider handling so you do not build composite provider prefixes:
1) Determine/normalize the provider prefix separately from the model name (don’t mutate `model` with `'azure/' + model` before parsing).
2) Strip provider prefixes in a loop (or parse once) until the remaining model name is the real base (`gpt-5...`).
3) Then rebuild the final routed model string once (provider + base model), ensuring exactly one provider prefix.

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


3. Provider prefix overridden ✓ Resolved 🐞 Bug ≡ Correctness
Description
For GPT-5 models, the new reroute code rebuilds model using `provider_prefix = 'azure/' if
self.azure else 'openai/' after stripping any leading openai/ or azure/` from the input. This
can silently change an explicitly provided provider-qualified model like azure/gpt-5... into
openai/gpt-5... when self.azure is false, routing the request to the wrong provider.
Code

pr_agent/algo/ai_handlers/litellm_ai_handler.py[R458-460]

+                    # Preserve azure/ routing if it was applied above; otherwise route via openai/
+                    provider_prefix = 'azure/' if self.azure else 'openai/'
+                    model = provider_prefix + model_base.replace('_thinking', '')  # remove _thinking suffix
Evidence
The GPT-5 reroute path always reconstructs the model using a prefix derived only from self.azure,
after explicitly removing any openai/ or azure/ prefix from the input. Since model values come
from config/fallback lists, an explicitly provider-qualified model string can be rewritten to a
different provider.

pr_agent/algo/ai_handlers/litellm_ai_handler.py[438-460]
pr_agent/algo/pr_processing.py[341-354]

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

## Issue description
When the GPT-5 branch runs, the code strips a leading provider prefix into `model_base` and then forces the rebuilt provider prefix based on `self.azure`. If the user explicitly passed a provider-qualified model (e.g. `azure/gpt-5...`) while `self.azure` is false, the handler rewrites it to `openai/gpt-5...`.
### Issue Context
The system pulls model strings directly from user config + fallback models; these values may include provider prefixes.
### Fix Focus Areas
- pr_agent/algo/ai_handlers/litellm_ai_handler.py[438-460]
- pr_agent/algo/pr_processing.py[341-354]
### Suggested fix
Preserve the explicit provider prefix when present:
- Parse the incoming `model` into `(explicit_provider_prefix, model_name)` if it starts with `openai/` or `azure/`.
- Choose the provider prefix as:
- `azure/` if `self.azure` is true (Azure mode), else
- `explicit_provider_prefix` if present, else
- default `openai/`.
- Rebuild `model` from that chosen prefix + stripped base model (and apply `_thinking` removal on the base model).

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



Remediation recommended

4. Tests don’t control env state ✓ Resolved 📘 Rule violation ☼ Reliability
Description
The newly added unit tests instantiate LiteLLMAIHandler() without explicitly setting/deleting
environment variables that its constructor reads, which can make the tests flaky in environments
where variables like AWS_USE_IMDS or OPENAI_API_KEY are set. This violates the requirement to
explicitly control env/process-global state in tests.
Code

tests/unittest/test_litellm_reasoning_effort.py[R713-718]

+                handler = LiteLLMAIHandler()
+                await handler.chat_completion(
+                    model=model,
+                    system="test system",
+                    user="test user"
+                )
Evidence
PR Compliance ID 17 requires tests to explicitly set/delete environment variables and global state
they depend on. The added tests instantiate LiteLLMAIHandler() (new lines) while the handler
constructor branches on environment variables, so the tests should proactively set/delenv relevant
variables (or assert preconditions) to avoid hidden coupling to the runner environment.

tests/unittest/test_litellm_reasoning_effort.py[713-718]
pr_agent/algo/ai_handlers/litellm_ai_handler.py[51-59]
Best Practice: Learned patterns

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

## Issue description
New tests create `LiteLLMAIHandler()` but do not explicitly control environment variables/process-global state that the handler reads during `__init__`, which can cause flaky behavior depending on the runner environment.
## Issue Context
`LiteLLMAIHandler.__init__()` reads env vars (e.g., `OPENAI_API_KEY`, `AWS_USE_IMDS`) and may execute different initialization paths based on them.
## Fix Focus Areas
- tests/unittest/test_litellm_reasoning_effort.py[688-812]

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


5. Azure cases untested ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
The added unit tests cover only openai/gpt-5* inputs with self.azure false and do not exercise
azure/gpt-5* inputs or Azure-mode behaviors that interact with the new prefix stripping/rerouting.
This leaves the provider-routing and Azure-prefix edge cases unprotected and likely to regress.
Code

tests/unittest/test_litellm_reasoning_effort.py[R699-704]

+        prefixed_models = [
+            "openai/gpt-5",
+            "openai/gpt-5.1-codex",
+            "openai/gpt-5.1-codex-max",
+            "openai/gpt-5.4-mini",
+        ]
Evidence
Group 8 introduces provider-prefix handling tests but only lists openai/... models; there are no
corresponding azure/... tests despite code explicitly handling/removing an azure/ prefix.

tests/unittest/test_litellm_reasoning_effort.py[686-744]
pr_agent/algo/ai_handlers/litellm_ai_handler.py[438-460]

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

## Issue description
Current tests validate `openai/gpt-5*` prefixed inputs but do not cover `azure/gpt-5*` or Azure-mode (`self.azure==True`) interactions with the new prefix normalization and reroute logic.
### Issue Context
Prefix handling logic now strips/rebuilds provider prefixes for GPT-5; without tests for `azure/` and Azure mode, bugs in provider routing/detection can slip through.
### Fix Focus Areas
- tests/unittest/test_litellm_reasoning_effort.py[686-744]
### Suggested fix
Add tests for:
- `model="azure/gpt-5"` with `self.azure` false: assert the provider prefix is preserved (or assert the intended behavior explicitly).
- Azure mode (`OPENAI.API_TYPE=azure` or `AZURE_AD.*` set) with provider-qualified model strings: assert GPT-5 detection still triggers and `temperature` is removed.
- Ensure no double-prefixing occurs in the final `call_kwargs['model']`.

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


Grey Divider

Previous review results

Review updated until commit 79513ba

Results up to commit N/A


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)


Action required
1. patch() line exceeds 120 ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
Several newly added with patch(...) lines in the unit tests exceed the repository's 120-character
line limit, which is enforced by the project's Ruff configuration. This can cause lint/CI failures
and reduces readability.
Code

tests/unittest/test_litellm_reasoning_effort.py[707]

+            with patch('pr_agent.algo.ai_handlers.litellm_ai_handler.acompletion', new_callable=AsyncMock) as mock_completion:
Evidence
PR Compliance ID 9 requires respecting the 120-character line length. The newly added `with
patch(...)` statements are written on single lines that exceed this limit.

AGENTS.md
tests/unittest/test_litellm_reasoning_effort.py[707-707]
tests/unittest/test_litellm_reasoning_effort.py[731-731]
tests/unittest/test_litellm_reasoning_effort.py[751-751]
tests/unittest/test_litellm_reasoning_effort.py[782-782]

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

## Issue description
New test code introduces lines longer than 120 characters (notably `with patch('pr_agent.algo.ai_handlers.litellm_ai_handler.acompletion', ...)`), violating the repo's 120-character line-length convention.
## Issue Context
`pyproject.toml` configures Ruff with `line-length = 120`, so these lines are likely to fail linting.
## Fix Focus Areas
- tests/unittest/test_litellm_reasoning_effort.py[707-707]
- tests/unittest/test_litellm_reasoning_effort.py[731-731]
- tests/unittest/test_litellm_reasoning_effort.py[751-751]
- tests/unittest/test_litellm_reasoning_effort.py[782-782]

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


2. Azure+prefix skips GPT-5 ✓ Resolved 🐞 Bug ≡ Correctness
Description
In Azure mode, chat_completion() prepends azure/ before computing model_base, and the new
removeprefix() chain only removes a single leading provider prefix. If the configured model is
already provider-qualified (e.g. openai/gpt-5* or azure/gpt-5*), model_base can still start
with openai/ or azure/, so the GPT-5 branch is skipped and temperature is sent (triggering the
same LiteLLM UnsupportedParamsError this PR aims to fix).
Code

pr_agent/algo/ai_handlers/litellm_ai_handler.py[R438-440]

+                model_base = model.removeprefix('openai/').removeprefix('azure/')
+                if model_base.startswith('gpt-5'):
               # Use configured reasoning_effort or default to MEDIUM
Evidence
chat_completion() prepends azure/ before the new GPT-5 normalization; the new normalization
removes only one leading prefix, so any provider-qualified model string in Azure mode can still have
a provider segment at the start of model_base and fail GPT-5 detection. Models are sourced from
config/fallbacks without restrictions, so provider-qualified strings are feasible inputs.

pr_agent/algo/ai_handlers/litellm_ai_handler.py[409-413]
pr_agent/algo/ai_handlers/litellm_ai_handler.py[433-461]
pr_agent/algo/pr_processing.py[341-354]

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

## Issue description
In `LiteLLMAIHandler.chat_completion()`, GPT-5 detection relies on `model_base` computed via `removeprefix('openai/').removeprefix('azure/')`. When `self.azure` is enabled, the function prepends `azure/` to the model first; if the incoming model already has a provider prefix, the resulting string can contain multiple provider segments (e.g. `azure/openai/gpt-5...` or `azure/azure/gpt-5...`). The current normalization removes at most one leading prefix, so `model_base` may still begin with a provider segment and fail `startswith('gpt-5')`, causing `temperature` to be passed to GPT-5.
### Issue Context
Models come directly from user configuration/fallback lists and can be provider-qualified strings.
### Fix Focus Areas
- pr_agent/algo/ai_handlers/litellm_ai_handler.py[409-413]
- pr_agent/algo/ai_handlers/litellm_ai_handler.py[433-461]
- pr_agent/algo/pr_processing.py[341-354]
### Suggested fix
Refactor provider handling so you do not build composite provider prefixes:
1) Determine/normalize the provider prefix separately from the model name (don’t mutate `model` with `'azure/' + model` before parsing).
2) Strip provider prefixes in a loop (or parse once) until the remaining model name is the real base (`gpt-5...`).
3) Then rebuild the final routed model string once (provider + base model), ensuring exactly one provider prefix.

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


3. Provider prefix overridden ✓ Resolved 🐞 Bug ≡ Correctness
Description
For GPT-5 models, the new reroute code rebuilds model using `provider_prefix = 'azure/' if
self.azure else 'openai/' after stripping any leading openai/ or azure/` from the input. This
can silently change an explicitly provided provider-qualified model like azure/gpt-5... into
openai/gpt-5... when self.azure is false, routing the request to the wrong provider.
Code

pr_agent/algo/ai_handlers/litellm_ai_handler.py[R458-460]

+                    # Preserve azure/ routing if it was applied above; otherwise route via openai/
+                    provider_prefix = 'azure/' if self.azure else 'openai/'
+                    model = provider_prefix + model_base.replace('_thinking', '')  # remove _thinking suffix
Evidence
The GPT-5 reroute path always reconstructs the model using a prefix derived only from self.azure,
after explicitly removing any openai/ or azure/ prefix from the input. Since model values come
from config/fallback lists, an explicitly provider-qualified model string can be rewritten to a
different provider.

pr_agent/algo/ai_handlers/litellm_ai_handler.py[438-460]
pr_agent/algo/pr_processing.py[341-354]

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

## Issue description
When the GPT-5 branch runs, the code strips a leading provider prefix into `model_base` and then forces the rebuilt provider prefix based on `self.azure`. If the user explicitly passed a provider-qualified model (e.g. `azure/gpt-5...`) while `self.azure` is false, the handler rewrites it to `openai/gpt-5...`.
### Issue Context
The system pulls model strings directly from user config + fallback models; these values may include provider prefixes.
### Fix Focus Areas
- pr_agent/algo/ai_handlers/litellm_ai_handler.py[438-460]
- pr_agent/algo/pr_processing.py[341-354]
### Suggested fix
Preserve the explicit provider prefix when present:
- Parse the incoming `model` into `(explicit_provider_prefix, model_name)` if it starts with `openai/` or `azure/`.
- Choose the provider prefix as:
- `azure/` if `self.azure` is true (Azure mode), else
- `explicit_provider_prefix` if present, else
- default `openai/`.
- Rebuild `model` from that chosen prefix + stripped base model (and apply `_thinking` removal on the base model).

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



Remediation recommended
4. Tests don’t control env state ✓ Resolved 📘 Rule violation ☼ Reliability
Description
The newly added unit tests instantiate LiteLLMAIHandler() without explicitly setting/deleting
environment variables that its constructor reads, which can make the tests flaky in environments
where variables like AWS_USE_IMDS or OPENAI_API_KEY are set. This violates the requirement to
explicitly control env/process-global state in tests.
Code

tests/unittest/test_litellm_reasoning_effort.py[R713-718]

+                handler = LiteLLMAIHandler()
+                await handler.chat_completion(
+                    model=model,
+                    system="test system",
+                    user="test user"
+                )
Evidence
PR Compliance ID 17 requires tests to explicitly set/delete environment variables and global state
they depend on. The added tests instantiate LiteLLMAIHandler() (new lines) while the handler
constructor branches on environment variables, so the tests should proactively set/delenv relevant
variables (or assert preconditions) to avoid hidden coupling to the runner environment.

tests/unittest/test_litellm_reasoning_effort.py[713-718]
pr_agent/algo/ai_handlers/litellm_ai_handler.py[51-59]
Best Practice: Learned patterns

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

## Issue description
New tests create `LiteLLMAIHandler()` but do not explicitly control environment variables/process-global state that the handler reads during `__init__`, which can cause flaky behavior depending on the runner environment.
## Issue Context
`LiteLLMAIHandler.__init__()` reads env vars (e.g., `OPENAI_API_KEY`, `AWS_USE_IMDS`) and may execute different initialization paths based on them.
## Fix Focus Areas
- tests/unittest/test_litellm_reasoning_effort.py[688-812]

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


5. Azure cases untested ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
The added unit tests cover only openai/gpt-5* inputs with self.azure false and do not exercise
azure/gpt-5* inputs or Azure-mode behaviors that interact with the new prefix stripping/rerouting.
This leaves the provider-routing and Azure-prefix edge cases unprotected and likely to regress.
Code

tests/unittest/test_litellm_reasoning_effort.py[R699-704]

+        prefixed_models = [
+            "openai/gpt-5",
+            "openai/gpt-5.1-codex",
+            "openai/gpt-5.1-codex-max",
+            "openai/gpt-5.4-mini",
+        ]
Evidence
Group 8 introduces provider-prefix handling tests but only lists openai/... models; there are no
corresponding azure/... tests despite code explicitly handling/removing an azure/ prefix.

tests/unittest/test_litellm_reasoning_effort.py[686-744]
pr_agent/algo/ai_handlers/litellm_ai_handler.py[438-460]

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

## Issue description
Current tests validate `openai/gpt-5*` prefixed inputs but do not cover `azure/gpt-5*` or Azure-mode (`self.azure==True`) interactions with the new prefix normalization and reroute logic.
### Issue Context
Prefix handling logic now strips/rebuilds provider prefixes for GPT-5; without tests for `azure/` and Azure mode, bugs in provider routing/detection can slip through.
### Fix Focus Areas
- tests/unittest/test_litellm_reasoning_effort.py[686-744]
### Suggested fix
Add tests for:
- `model="azure/gpt-5"` with `self.azure` false: assert the provider prefix is preserved (or assert the intended behavior explicitly).
- Azure mode (`OPENAI.API_TYPE=azure` or `AZURE_AD.*` set) with provider-qualified model strings: assert GPT-5 detection still triggers and `temperature` is removed.
- Ensure no double-prefixing occurs in the final `call_kwargs['model']`.

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


Qodo Logo

Comment on lines 438 to 440
model_base = model.removeprefix('openai/').removeprefix('azure/')
if model_base.startswith('gpt-5'):
# Use configured reasoning_effort or default to MEDIUM
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Action required

1. Azure+prefix skips gpt-5 🐞 Bug ≡ Correctness

In Azure mode, chat_completion() prepends azure/ before computing model_base, and the new
removeprefix() chain only removes a single leading provider prefix. If the configured model is
already provider-qualified (e.g. openai/gpt-5* or azure/gpt-5*), model_base can still start
with openai/ or azure/, so the GPT-5 branch is skipped and temperature is sent (triggering the
same LiteLLM UnsupportedParamsError this PR aims to fix).
Agent Prompt
### Issue description
In `LiteLLMAIHandler.chat_completion()`, GPT-5 detection relies on `model_base` computed via `removeprefix('openai/').removeprefix('azure/')`. When `self.azure` is enabled, the function prepends `azure/` to the model first; if the incoming model already has a provider prefix, the resulting string can contain multiple provider segments (e.g. `azure/openai/gpt-5...` or `azure/azure/gpt-5...`). The current normalization removes at most one leading prefix, so `model_base` may still begin with a provider segment and fail `startswith('gpt-5')`, causing `temperature` to be passed to GPT-5.

### Issue Context
Models come directly from user configuration/fallback lists and can be provider-qualified strings.

### Fix Focus Areas
- pr_agent/algo/ai_handlers/litellm_ai_handler.py[409-413]
- pr_agent/algo/ai_handlers/litellm_ai_handler.py[433-461]
- pr_agent/algo/pr_processing.py[341-354]

### Suggested fix
Refactor provider handling so you do not build composite provider prefixes:
1) Determine/normalize the provider prefix separately from the model name (don’t mutate `model` with `'azure/' + model` before parsing).
2) Strip provider prefixes in a loop (or parse once) until the remaining model name is the real base (`gpt-5...`).
3) Then rebuild the final routed model string once (provider + base model), ensuring exactly one provider prefix.

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

Comment thread pr_agent/algo/ai_handlers/litellm_ai_handler.py Outdated
@sizickp sizickp force-pushed the fix/gpt-5-prefix-detection branch from b7fe4eb to 0d9006b Compare May 18, 2026 10:38
@qodo-free-for-open-source-projects
Copy link
Copy Markdown
Contributor

qodo-free-for-open-source-projects Bot commented May 18, 2026

Persistent review updated to latest commit 0d9006b

Comment thread tests/unittest/test_litellm_reasoning_effort.py Outdated
@sizickp sizickp force-pushed the fix/gpt-5-prefix-detection branch from 0d9006b to 8c4377f Compare May 18, 2026 10:54
@qodo-free-for-open-source-projects
Copy link
Copy Markdown
Contributor

qodo-free-for-open-source-projects Bot commented May 18, 2026

Persistent review updated to latest commit 8c4377f

Sergey Petrov added 2 commits May 18, 2026 14:44
…efixes

Address two routing issues raised by the Qodo review on the initial fix:

1. Stacked prefixes (Azure mode + provider-qualified config). With
   self.azure prepending "azure/" to a model that already had an
   "openai/" or "azure/" prefix in config, the single removeprefix()
   call left a residual provider segment, GPT-5 detection failed, and
   temperature was still sent (the original bug this PR fixes).
2. Explicit "azure/" rewritten to "openai/" when self.azure was false.
   The previous rebuild used "azure/ if self.azure else openai/",
   which ignored an explicit "azure/" the user had written in config
   and silently rerouted the request to OpenAI.

Strip provider prefixes in a loop so any number of stacked segments is
removed, and choose the rebuilt prefix by priority: Azure mode >
explicit prefix in user config > "openai/" default. Capture the user's
original model string before the azure auto-prepend so the explicit
prefix is still visible at rebuild time.

Tests added for:
- explicit "azure/" preserved when self.azure is false
- Azure mode with bare / openai/- / azure/- prefixed configs all
  producing exactly one "azure/" prefix
Four `with patch(...)` statements in the GPT-5 provider-prefix tests
exceeded the repo's 120-character line limit (ruff line-length=120 in
pyproject.toml). Wrap them onto multiple lines so the test file does
not regress lint compliance for the newly added cases.
@sizickp sizickp force-pushed the fix/gpt-5-prefix-detection branch from 8c4377f to 66026ff Compare May 18, 2026 11:44
@qodo-free-for-open-source-projects
Copy link
Copy Markdown
Contributor

qodo-free-for-open-source-projects Bot commented May 18, 2026

Persistent review updated to latest commit 66026ff

Address Qodo review feedback: the added Group 8 tests instantiate
LiteLLMAIHandler() directly, and its __init__ branches on environment
variables such as AWS_USE_IMDS, OPENAI_API_KEY, and the AWS_* set. With
those vars potentially leaking from the runner environment, the tests
could behave differently across machines or CI runners (e.g. attempt
boto3 import when AWS_USE_IMDS is set).

Explicitly delete the relevant env vars via monkeypatch.delenv() at the
start of each new test, so the constructor takes a deterministic path
regardless of where the suite runs.
@qodo-free-for-open-source-projects
Copy link
Copy Markdown
Contributor

qodo-free-for-open-source-projects Bot commented May 18, 2026

Persistent review updated to latest commit 79513ba

@CzechExplorer
Copy link
Copy Markdown

Error running review: usage: ensemble_review.py [-h] [--post] pr
ensemble_review.py: error: unrecognized arguments: --quiet

@CzechExplorer
Copy link
Copy Markdown

📡 Fetching PR #2401...
Title: fix(litellm): detect GPT-5 family when model has openai/ or azure/ prefix

🚀 Starting ensemble review with 3 models...
🤖 DeepSeek-V4-Flash-EL...
🤖 Gemini-3-Flash...
🤖 GPT-5-Mini...
✅ GPT-5-Mini done
✅ Gemini-3-Flash done
✅ DeepSeek-V4-Flash-EL done

============================================================

📋 Ensemble PR Review (Critical Issues Only)

PR: fix(litellm): detect GPT-5 family when model has openai/ or azure/ prefix
URL: #2401
Author: @sizickp


🔷 GPT-5 Mini

No critical issues found

Rating: 10/10 — The change is a small, well-contained normalization and reconstruction of the model string to detect GPT-5 regardless of provider prefixes, with tests covering the important cases (openai/ and azure/ prefixes, _thinking suffix, Azure mode). I did not see any of the listed critical problems: no new secrets, no SQL/injection, no race conditions, no unhandled exceptions that would obviously crash (string ops are safe), and behavior is backward-compatible.

Confidence: High


🟠 Gemini 3.1 Flash

1. Critical Issues

No critical issues found.

The PR correctly addresses a bug where GPT-5 models (which require reasoning_effort instead of temperature) were not being correctly identified when prefixed with provider strings like openai/ or azure/. The fix uses a robust normalization approach and includes comprehensive unit tests to verify that prefixes are handled correctly without being duplicated or lost.

2. Rating

Rating: 10/10
The change is surgical, addresses a specific failure mode that causes unnecessary fallbacks and latency, and includes high-quality regression tests covering various prefix combinations.

3. Confidence

Confidence: High


🔵 DeepSeek V4 Flash

Analysis

Critical Issues

No critical issues found.

Rating

10/10 — The change is minimal, targeted, and well-tested. It correctly handles provider prefixes for GPT-5 model detection without introducing any security vulnerabilities, crashes, data loss, breaking changes, race conditions, injection flaws, hardcoded secrets, or unhandled exceptions. The logic for stripping and rebuilding prefixes is sound and matches the described intent. All edge cases (stacked prefixes, Azure mode, explicit prefixes, _thinking suffix) are covered by unit tests.

Confidence

High — The diff is small, the logic is straightforward, and the test suite comprehensively validates the new behavior. No hidden risks are evident.


🤖 Review generated via ensemble of 3 models (DeepSeek V4 Flash, Gemini 3 Flash, GPT-5 Mini)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants