Skip to content

fix(router): duration-only provider budget config no longer removes deployments - #33366

Closed
unfitcoder101 wants to merge 4 commits into
BerriAI:litellm_internal_stagingfrom
unfitcoder101:fix/provider-budget-duration-only-config
Closed

fix(router): duration-only provider budget config no longer removes deployments#33366
unfitcoder101 wants to merge 4 commits into
BerriAI:litellm_internal_stagingfrom
unfitcoder101:fix/provider-budget-duration-only-config

Conversation

@unfitcoder101

Copy link
Copy Markdown

Problem

A provider budget entry with budget_duration but no max_budget
silently removes all deployments for that provider from the healthy set.

Root cause: inside _filter_out_deployments_above_budget, the block:

if config.max_budget is None:
    continue

uses continue which advances the deployment loop, not just skips
the provider check. The deployment never gets appended to the result.

Fix

Wrapped the budget comparison inside if config.max_budget is not None:
so a missing max_budget means no numeric cap — deployment stays eligible.

Test

Added regression test confirming a duration-only provider config
leaves the deployment in the healthy set.

Fixes #33327

… reasoning_effort

gpt-5.6 family models fail on /v1/chat/completions when function tools are
present because OpenAI applies a default reasoning_effort server-side.
Bridge to /v1/responses unconditionally for is_model_gpt_5_4_plus_model with tools.

Fixes: BerriAI#33221
…eployments

When provider_budget_config has budget_duration but no max_budget,
the deployment was silently removed from the healthy set due to a
misplaced continue statement advancing the deployment loop.

Fix: guard the budget check with config.max_budget is not None so a
missing max_budget means no numeric cap and the deployment stays eligible.

Fixes BerriAI#33327
@greptile-apps

greptile-apps Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR bundles two independent fixes: correcting _filter_out_deployments_above_budget in budget_limiter.py so that a provider config with only budget_duration (no max_budget) no longer silently drops deployments, and updating the GPT-5.4+ bridge check in main.py so tools alone trigger the Responses API path without requiring reasoning_effort.

  • budget_limiter.py: The old continue on config.max_budget is None advanced the outer deployment loop, causing the deployment to never be appended. The fix wraps the numeric comparison inside if config.max_budget is not None, leaving a duration-only config as a no-op.
  • main.py: Rearranges the bridge condition so is_model_gpt_5_4_plus_model(model) and tools is an independent OR branch, decoupled from the reasoning_effort requirement that still applies to the reasoning-summary bridging path.
  • tests/test_provider_budget_fix.py: The new regression test passes the same list object for both potential_deployments and healthy_deployments, causing the method to append to the list while iterating over it — an infinite loop. In production, potential_deployments is always an empty list; the test should match that pattern.

Confidence Score: 3/5

The production logic fix in budget_limiter.py is correct, but the regression test added to cover it will hang indefinitely due to aliasing both list arguments to the same object — the test cannot pass as written.

The core budget_limiter.py change is a clean, targeted fix and the main.py bridge logic is well-reasoned and backed by dedicated tests. However, the only test for the budget fix (test_provider_budget_fix.py) contains a list-aliasing bug that causes an infinite loop, meaning the fix ships with a broken test that can never pass on CI.

tests/test_provider_budget_fix.py needs potential_deployments=[] instead of potential_deployments=healthy_deployments to avoid an infinite loop. The production code in budget_limiter.py and main.py can be reviewed as-is.

Important Files Changed

Filename Overview
litellm/router_strategy/budget_limiter.py Core bug fix: wraps the budget comparison in if config.max_budget is not None so a duration-only provider config no longer causes deployments to be silently excluded. Logic is correct; a duplicate comment was introduced in the same hunk.
tests/test_provider_budget_fix.py Regression test for the budget fix, but it passes the same list object for both potential_deployments and healthy_deployments, which causes an infinite loop when the method appends to the list while iterating over it. Should use potential_deployments=[].
litellm/main.py Logic update to responses_api_bridge_check: for gpt-5.4+ models, tools alone now unconditionally bridge to the Responses API (removing the prior requirement that reasoning_effort also be set). Unrelated to the PR title but the change is self-consistent and tested.
tests/test_litellm/test_gpt56_bridge.py New mock tests for the gpt-5.6 bridge change: one positive case (gpt-5.6 + tools without reasoning_effort bridges) and one negative case (older gpt-5 models with tools but no reasoning_effort do not bridge). Both tests are pure unit tests with no network calls. Missing newline at end of file.

Reviews (1): Last reviewed commit: "fix(router): duration-only provider budg..." | Re-trigger Greptile

Comment on lines +27 to +35
result, _ = limiter._filter_out_deployments_above_budget(
potential_deployments=healthy_deployments,
healthy_deployments=healthy_deployments,
provider_configs=provider_configs,
deployment_configs={},
deployment_providers=["openai"],
spend_map={},
request_tags=[],
)

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.

P1 Same list passed to both potential_deployments and healthy_deployments causes an infinite loop

potential_deployments=healthy_deployments passes the same Python list object for both parameters. Inside _filter_out_deployments_above_budget, the method appends each eligible deployment to potential_deployments while iterating over healthy_deployments. Because both refer to the same list, the first eligible deployment is appended mid-iteration, the iterator sees the new element, processes it again, appends again, and so on indefinitely. In production, potential_deployments is always initialized as a separate empty list (potential_deployments: List[Dict] = [] at line 141 of budget_limiter.py). The test should pass potential_deployments=[] to match the production call pattern and avoid this hang.

Comment on lines +217 to 219
# Check provider budget
# Check provider budget
if self.provider_budget_config:

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.

P2 Duplicate # Check provider budget comment was introduced by the diff. One of them should be removed.

Suggested change
# Check provider budget
# Check provider budget
if self.provider_budget_config:
# Check provider budget
if self.provider_budget_config:

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@codecov

codecov Bot commented Jul 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@codspeed-hq

codspeed-hq Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing unfitcoder101:fix/provider-budget-duration-only-config (1ce9972) with litellm_internal_staging (d6f498f)

Open in CodSpeed

@devin-ai-integration

Copy link
Copy Markdown
Contributor

Closing in favor of #34044. The budget_limiter fix for #33327 is correct, but this branch was cut off #33237 so it bundled the gpt-5.6 main.py change (inheriting the gpt-5.4 test failures) and the regression test aliased potential_deployments to healthy_deployments (infinite loop). #34044 is a clean standalone branch off staging with the one-line fix and a test that passes potential_deployments=[].

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: provider budget config without max_budget removes deployments

1 participant