Commit graph

35261 commits

Author SHA1 Message Date
Hendrik Jaks
35bd69e146 fix(ui): guard storeLoginToken against empty/whitespace-only tokens
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 12:06:43 +02:00
Hendrik Jaks
06260df412 style: remove stray double blank line in user_dashboard.tsx
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 12:01:09 +02:00
Hendrik Jaks
20ad73fda4
Apply suggestion from @greptile-apps[bot]
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-03-13 11:40:01 +02:00
Hendrik Jaks
a607754b35
Update ui/litellm-dashboard/src/utils/cookieUtils.ts
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-03-13 11:33:53 +02:00
Hendrik Jaks
acdc6145b3 fix(ui): scope deleteCookie sessionStorage cleanup to token key only
Also document the sessionStorage cross-tab trade-off: per-tab scope
means users behind an HttpOnly proxy must log in once per tab, but
this is intentional to avoid localStorage XSS exposure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 11:12:35 +02:00
Hendrik Jaks
523d1c388f fix(ui): use shared getCookie in page.tsx and user_dashboard.tsx
Replace local getCookie functions in page.tsx and user_dashboard.tsx
with the shared one from cookieUtils that has the sessionStorage
fallback. Without this, the HttpOnly cookie fix was incomplete —
page.tsx (the dashboard entry point) could not read the token,
causing the redirect loop to persist.

Also scope the sessionStorage fallback to the "token" key only,
and clear sessionStorage in page.tsx deleteCookie.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 11:06:43 +02:00
Hendrik Jaks
461cf00408 fix(ui): use sessionStorage instead of cookie for login token storage
Replace setTokenCookie (which is a no-op when reverse proxy adds HttpOnly)
with storeLoginToken using sessionStorage. Add sessionStorage fallback to
getCookie so the token is found even when the cookie is HttpOnly. Also handle
'=' in cookie values with .slice(1).join("=") and clear sessionStorage on
logout.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 10:58:06 +02:00
Hendrik Jaks
22409da932
Update ui/litellm-dashboard/src/utils/cookieUtils.ts
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-03-13 10:22:32 +02:00
Hendrik Jaks
04f835ecfa
Update ui/litellm-dashboard/src/utils/cookieUtils.ts
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-03-13 10:15:21 +02:00
Hendrik Jaks
2c5caac531 fix: address second round of Greptile review feedback
- Add loginCall integration tests verifying setTokenCookie is called with
  token and skipped when absent (backward-compatibility path)
- Use encodeURIComponent/decodeURIComponent in setTokenCookie/getCookie
  for defense-in-depth against non-standard token formats

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 10:09:52 +02:00
Hendrik Jaks
a8864ea12b fix: address Greptile review feedback
- Add window guard to setTokenCookie for SSR consistency with clearTokenCookies
- Add SSR test for window undefined case
- Add code comment explaining why JWT is included in response body

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 10:02:10 +02:00
Hendrik Jaks
6eb78e46c9 fix(ui): resolve login redirect loop when reverse proxy adds HttpOnly to cookies
When LiteLLM is behind nginx-ingress or similar with security-hardened
configs, the reverse proxy adds HttpOnly to all Set-Cookie headers. This
makes the JWT token unreadable by JavaScript, causing an infinite login
redirect loop. Fix by returning the JWT token in the /v2/login response
body so the frontend can set a JS-accessible cookie directly.

Fixes #19663

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 09:49:55 +02:00
github-actions[bot]
9cd7ad2634
chore: regenerate poetry.lock to match pyproject.toml (#23514)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-13 05:29:52 +00:00
yuneng-jiang
ef78fa7025
Merge pull request #23496 from BerriAI/bump_ver_1822
bump: version 1.82.1 → 1.82.2
2026-03-12 22:29:06 -07:00
Emerson Gomes
92d39c308c
fix(gemini): preserve toolConfig on native generate_content (#23493) 2026-03-12 17:48:09 -07:00
yuneng-jiang
976f1a0115
Merge pull request #23497 from BerriAI/litellm_/modest-dijkstra
[Fix] BaseModelResponseIterator crashes on non-string stream chunks
2026-03-12 16:20:28 -07:00
yuneng-jiang
d16c8c5590 [Fix] BaseModelResponseIterator crashes on non-string stream chunks
The empty-line filter in __next__/__anext__ called .strip() without
checking the type first. When the Responses API yields Pydantic
BaseModel events (e.g. ResponseCreatedEvent), this raises
AttributeError. Add an isinstance(str_line, str) guard so non-string
objects pass through to _handle_string_chunk as intended.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 16:16:32 -07:00
yuneng-jiang
820d63f3a6 bump: version 1.82.1 → 1.82.2 2026-03-12 16:07:38 -07:00
Shivam Rawat
f5ffc59309
fix(proxy): Windows compatibility for Prisma engine watchdog (#23494)
Guard os.waitpid and os.WNOHANG usage with sys.platform check.
These APIs are Unix-only; on Windows they cause AttributeError
and prevent proxy startup.

- _try_waitpid_watch: return False on Windows, fall back to
  os.kill polling
- _reap_all_zombies: return empty set on Windows (no zombies)

Add unit tests for Windows path.

Made-with: Cursor
2026-03-12 16:02:37 -07:00
yuneng-jiang
62c8494423
Merge pull request #23490 from BerriAI/litellm_add_pkce_env_key_docs
[Docs] Add PKCE_STRICT_CACHE_MISS to env variables reference
2026-03-12 15:35:06 -07:00
yuneng-jiang
372cc45164 [Docs] Add PKCE_STRICT_CACHE_MISS to environment variables reference
Document the PKCE_STRICT_CACHE_MISS environment variable in config_settings.md
to fix the CI env key documentation check.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 15:32:35 -07:00
yuneng-jiang
229d2008a3
Merge pull request #23488 from BerriAI/litellm_/peaceful-poincare
[Fix] Flaky and outdated router integration tests
2026-03-12 15:24:51 -07:00
yuneng-jiang
e351521243 [Fix] Fix flaky and outdated router integration tests
- test_router_cooldown_handlers: add mock_response to avoid real API call requiring OPENAI_API_KEY
- test_router_timeout: update deprecated claude-3-5-haiku-20241022 to claude-haiku-4-5
- test_router_fallbacks: relax assertion from == 4 to >= 3 to handle cooldown timing variance

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 15:20:55 -07:00
yuneng-jiang
8b256d7488
Merge pull request #23487 from BerriAI/litellm_fix_ruff_sso_statement_count
[Fix] Ruff PLR0915 too-many-statements in ui_sso.py
2026-03-12 15:15:04 -07:00
yuneng-jiang
c06bdaa68d [Fix] Ruff PLR0915 too-many-statements in ui_sso.py
Extract helpers to bring `get_generic_sso_response` (63 → ≤50) and
`prepare_token_exchange_parameters` (54 → ≤50) under the statement limit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 15:08:40 -07:00
yuneng-jiang
f1a7e42577
Merge pull request #23485 from BerriAI/litellm_/sleepy-swirles
[Fix] Realtime websocket tests for websockets v15+ API
2026-03-12 15:02:18 -07:00
yuneng-jiang
79ffcf297d
Merge pull request #23486 from BerriAI/litellm_/beautiful-kilby
[Fix] Add litellm-proxy-extras to CI requirements
2026-03-12 15:01:56 -07:00
yuneng-jiang
53d704a1f1 [Fix] Add litellm-proxy-extras to CI requirements for prisma migrations
PR #23257 made proxy startup fail if prisma migrate fails, which
exposed that litellm-proxy-extras was never installed in CI. The import
error was previously silently ignored. Unpinned so it always pulls the
latest version from PyPI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 14:58:22 -07:00
Joe Reyna
03a0c37608
Merge pull request #23467 from joereyna/fix/mcp-oauth2-token-cache-tests
fix: add oauth2_flow="client_credentials" to MCPServer test helper
2026-03-12 14:55:42 -07:00
yuneng-jiang
3f0c7b5552 [Fix] Update realtime websocket tests for websockets v15+ API
Use explicit imports from websockets.exceptions (ConnectionClosedOK,
ConnectionClosedError) instead of the removed websockets.exceptions
attribute, and add openai/ model prefix so get_llm_provider resolves
the provider correctly in CI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 14:40:48 -07:00
yuneng-jiang
89d8401d72
Merge pull request #23483 from BerriAI/litellm_update_deprecated_test_models
[Fix] Update Deprecated Model Names in CI Tests
2026-03-12 14:16:52 -07:00
yuneng-jiang
41b6cb02de
Merge pull request #23482 from BerriAI/litellm_fix_ruff_mcp_rest_endpoints
[Fix] Ruff lint errors in MCP server files
2026-03-12 14:16:33 -07:00
yuneng-jiang
cc81e3c226 Replace deprecated model names in tests that were removed from remote model cost map
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 14:12:07 -07:00
yuneng-jiang
515fbcae99 [Fix] Ruff lint errors in MCP server files
Remove unused `timezone` imports (F401) and extract single-server tool
listing logic into `_list_tools_for_single_server` helper to fix PLR0915
(too many statements) in `list_tool_rest_api`.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 14:11:05 -07:00
yuneng-jiang
f3e870a3a9
Merge pull request #23478 from BerriAI/litellm_fix_o1_preview_outdated_test
[Fix] Remove Deprecated o1-preview from Azure O-series Test
2026-03-12 13:26:46 -07:00
yuneng-jiang
fe8660da01
Merge pull request #23477 from BerriAI/litellm_/unruffled-shaw
[Fix] Remove recursion in BFL _read_image_bytes
2026-03-12 13:26:24 -07:00
yuneng-jiang
a93c069dd5 [Fix] Add max_depth guard to BFL _read_image_bytes recursive function
Use the standard depth/max_depth pattern with DEFAULT_MAX_RECURSE_DEPTH
to guard the recursive list-unwrapping in _read_image_bytes, matching
the existing pattern used by _read_all_bytes in vertex_imagen.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 13:22:56 -07:00
yuneng-jiang
fb65384a76 [Fix] Remove deprecated o1-preview from O-series test and deduplicate is_o_series check
o1-preview is deprecated and not in the model registry with supports_reasoning=True,
causing the Azure O-series config test to fail. Also removed a duplicate is_o_series
assignment in utils.py.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 13:22:00 -07:00
yuneng-jiang
553cfc6d72 [Fix] Remove recursion in BFL _read_image_bytes to pass CI recursive detector
Replace recursive list-unwrapping with an iterative loop (max 10 levels)
to avoid being flagged by the recursive function detector CI check.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 13:19:42 -07:00
yuneng-jiang
25e7d3372b
Merge pull request #23474 from BerriAI/litellm_litellm-ci-stability-c0eb
Litellm ci stability
2026-03-12 13:15:16 -07:00
Cursor Agent
ba8fed7fc8
refactor: extract _list_tools_for_single_server helper to fix PLR0915
Extract the single-server branch of list_tool_rest_api into a dedicated
helper function _list_tools_for_single_server. This reduces the statement
count in list_tool_rest_api from 57 to under 50, resolving the PLR0915
ruff lint error without needing a per-file-ignore.

The behavior is unchanged — all validation, IP-filtering, error handling,
and tool-fetching logic is preserved identically in the extracted helper.

Co-authored-by: yuneng-jiang <yuneng-jiang@users.noreply.github.com>
2026-03-12 20:06:10 +00:00
Cursor Agent
e242356570
fix(ci): fix ruff lint errors and 9 failing unit tests on main
Lint fixes (check_code_and_doc_quality job):
- Remove unused variable reasoning_effort in gpt_5_transformation.py (F841)
- Remove unused timezone imports in mcp_server rest_endpoints.py and server.py (F401)
- Remove unused ProxyBaseLLMRequestProcessing import in realtime endpoints.py (F401)
- Add BaseRealtimeHTTPConfig to TYPE_CHECKING block in utils.py (F821)
- Add PLR0915 per-file-ignore for mcp_server/rest_endpoints.py in ruff.toml

Test fixes (litellm_mapped_tests_llms job):
- Gemini video cost tests: pass explicit model_info to video_generation_cost()
  instead of relying on gemini/veo-3.0-generate-preview being in model_prices JSON
- Anthropic max_tokens tests: mock get_max_tokens() to return expected values
  instead of depending on claude-3-5-sonnet-20241022 being in model_prices JSON
- Vertex AI pydantic obj test: update from removed gemini-1.5-pro to gemini-2.5-flash,
  update expected request body to use response_json_schema format
- Vertex AI/Bedrock file_content integration tests: update mocks to target
  base_llm_http_handler.retrieve_file_content (the new code path via
  ProviderConfigManager) instead of the old vertex_ai_files_instance/
  bedrock_files_instance paths

Co-authored-by: yuneng-jiang <yuneng-jiang@users.noreply.github.com>
2026-03-12 19:58:43 +00:00
yuneng-jiang
7f0ec1e3d8
Merge pull request #23469 from BerriAI/litellm_extras_mar12
[Infra] Proxy Extras
2026-03-12 12:50:17 -07:00
yuneng-jiang
5ffa6b955e build 2026-03-12 12:49:36 -07:00
yuneng-jiang
3a3fd64fcb bump: version 0.4.55 → 0.4.56 2026-03-12 12:46:47 -07:00
yuneng-jiang
cffb2676a5 bump: version 0.4.54 → 0.4.55 2026-03-12 12:46:46 -07:00
Ishaan Jaff
7697b1c397
fix(sso): direct PKCE token exchange + Redis wiring for multi-instance SSO (#22923)
* fix(sso): add direct PKCE token exchange and Redis cache wiring for multi-instance SSO

When PKCE is enabled, bypass fastapi-sso and perform direct token exchange so
code_verifier is correctly included. Store PKCE verifiers as dict in cache
for proper JSON serialization in Redis. Wire user_api_key_cache to Redis when
available so PKCE verifiers are shared across ECS tasks/pods.

Also adds clearer error messages when PKCE is required but not configured.

* refactor(sso): extract PKCE token exchange into SSOAuthenticationHandler methods

- Move import httpx/jwt to module level (top of file, not inside function)
- Extract inline PKCE token exchange + userinfo logic into two static methods:
  _pkce_token_exchange() and _get_pkce_userinfo()
- get_generic_sso_response PKCE path is now a single method call
- Fix double-logging in except block for non-PKCE errors
- Use %-style log formatting (no f-strings in log calls)

* fix: address greptile review feedback

- Fix access_token missing in PKCE path: read from combined_response directly
  instead of generic_sso.access_token (which is only set by verify_and_process)
- Fix PKCE error hint firing when PKCE is already enabled: only show
  'set GENERIC_CLIENT_USE_PKCE=true' advice when code_verifier was absent
- Fix unguarded KeyError on access_token: check for error field in HTTP 200
  responses before accessing token_response['access_token']
- Fix silent empty userinfo: raise ProxyException when both userinfo endpoint
  and id_token fallback produce no user data
- Fix backward-incompatible Redis wiring: only attach Redis to user_api_key_cache
  when GENERIC_CLIENT_USE_PKCE=true, preserving existing in-memory behaviour

* fix: address second round of greptile review feedback

- Fix PKCE error hint: check env var directly (not code_verifier presence) to
  distinguish 'PKCE not configured' from 'PKCE enabled but cache miss'
- Fix misleading Redis TTL comment in proxy_server.py

* fix: address third round of greptile review feedback

- Fix CRITICAL log firing on every non-PKCE callback: only log when PKCE is enabled
- Remove unused pkce_env_value intermediate variable
- Prefer reusing redis_usage_cache over creating separate RedisCache instance
  (avoids losing advanced connection options like SSL, timeouts, db)

* fix: address fourth round of greptile review feedback

- Strip OAuth token credentials from response_convertor input to prevent
  access_token/id_token appearing in restricted-group error messages
- Reuse single httpx.AsyncClient for both token exchange and userinfo requests
  to avoid a second TCP/TLS handshake per SSO callback
- Revert Redis wiring to user_api_key_cache: PKCE code already uses
  redis_usage_cache directly; wiring would route all API-key lookups through
  Redis unnecessarily. Add startup warning instead when PKCE+Redis mismatch.
- Move _OAUTH_TOKEN_FIELDS to module level

* fix remaining PKCE test assertion for dict-format verifier storage

* sanitize PKCE cache log to not expose verifier content

* address greptile review feedback (greploop iteration 3)

* address greptile review feedback (greploop iteration 4)

* address greptile review feedback (greploop iteration 5)

* simplify _get_pkce_userinfo: remove shared-client complexity, use async with directly

* address greptile review feedback (greploop iteration 6)

* address greptile review feedback (greploop iteration 7)

* address greptile review feedback (greploop iteration 8)

* address greptile review feedback (greploop iteration 9)

* address greptile review feedback (greploop iteration 10)

* address greptile review feedback (greploop iteration 11)

* address greptile review feedback (greploop iteration 12)

* fix misleading comment on user_api_key_cache TTL line

* address greptile review feedback (greploop iteration 13)

* address greptile review feedback (greploop iteration 14)

* address greptile review feedback (greploop iteration 15)

* address greptile review feedback (greploop iteration 16)

* address greptile review feedback (greploop iteration 17)

* address greptile review feedback (greploop iteration 18)

* address greptile review feedback (greploop iteration 19)

* address greptile review feedback (greploop iteration 20)

* address greptile review feedback (greploop iteration 21)

* address greptile review feedback (greploop iteration 22)

* address greptile review feedback (greploop iteration 23)

* address greptile review feedback (greploop iteration 24)

* address greptile review feedback (greploop iteration 25)

* address greptile review feedback (greploop iteration 26)

* address greptile review feedback (greploop iteration 27)

* address greptile review feedback (greploop iteration 28)

* address greptile review feedback (greploop iteration 29)

* address greptile review feedback (greploop iteration 30)

* address greptile review feedback (greploop iteration 31)

* address greptile review feedback (greploop iteration 32)

* address greptile review feedback (greploop iteration 33)

* address greptile review feedback (greploop iteration 34)

* address greptile review feedback (greploop iteration 35)

* address greptile review feedback (greploop iteration 37)

- read GENERIC_CLIENT_USE_PKCE env var once in prepare_token_exchange_parameters
- include actual decode error in jwt.decode failure exception message
- add GENERIC_CLIENT_USE_PKCE=true to no-state regression test

* defer PKCE verifier deletion until after all downstream processing

Move _delete_pkce_verifier to after response_convertor and
process_sso_jwt_access_token complete. If JWT processing raises,
the verifier stays in cache so the user can retry without restarting
the full OAuth flow.

* address greptile review feedback (greploop iteration 38)

- fix strict-mode cache miss error message to differentiate
  cross-instance routing failures (Redis configured) from single-instance
  issues (TTL expiry, pod restart) when only in-memory cache is available
- add comment above _get_pkce_userinfo call explaining that bearer
  credentials are always sourced from token_response in the merge step

* fix null JSON response body in _pkce_token_exchange

- Guard against HTTP 200 with body null: response.json() returns None
  for JSON null, and calling .get() on None raises AttributeError.
  Now raises a clean ProxyException with a clear error message.
- Fix misleading userinfo warning: was always saying "empty dict" but
  also fires for JSON null responses; updated to say "empty or null".
- Add HTTP status code assertion to cache miss test.

* address greptile review feedback (greploop iteration 39)

- fix credential leakage: directly assign received_response from
  combined_response instead of relying on nonlocal mutation; Pyright
  was flagging the old guard as unreachable, meaning credential stripping
  might not execute — now it always runs unconditionally
- add test for legacy plain-string cache format backward compat branch
- add test for HTTP 200 with no error field and no access_token (else branch)
- add test for HTTP 200 with JSON null body (new AttributeError guard)

* fix _OAUTH_TOKEN_FIELDS merge loop to preserve userinfo values on absent fields

When the token endpoint omits a bearer-credential field entirely (field
absent from token_response), the previous code deleted it from merged even
if userinfo provided a valid value. Now:
- non-null in token_response → restore authoritative token endpoint value
- explicit null in token_response → remove key from merged (clean absence)
- field absent from token_response → leave userinfo value unchanged

* use HTTP 401 for PKCE missing config errors

GENERIC_CLIENT_ID and GENERIC_TOKEN_ENDPOINT missing when PKCE is
enabled are auth-flow failures, not server errors. Use 401 instead
of 500 to avoid triggering false-positive server error alerts in
monitoring systems.

* address greptile review feedback (greploop iteration 40)

- fix duplicate error logging: demote first format-error log to DEBUG
  so the detailed ERROR in strict-mode branch is not duplicated
- add HTTP status code assertions to all PKCE ProxyException tests
  for better regression protection against accidental code changes

* add credential absence assertions to test_pkce_token_exchange_basic_auth

Verify that client_id and client_secret are NOT double-sent in the POST
body when Basic Auth is used (include_client_id=False with client_secret).
Catches regressions where credentials leak into both Auth header and body.

* address greptile review feedback (greploop iteration 41)

- add Bearer token header assertion to test_pkce_token_exchange_credentials_in_body
- add cache query assertions to both non-strict mode tests to confirm
  the cache was accessed before the warning path triggers

* address greptile review feedback (greploop iteration 42)

- assert null id_token is absent from merged result in basic auth test
- add test for HTTP 200 empty/null userinfo body with no id_token fallback

* use caplog to verify warning logs in non-strict cache miss tests

The two non-strict mode tests now use pytest's caplog fixture to assert
that a warning is actually emitted, not just that the code continues
without raising. This catches regressions where the warning silently
disappears.

* remove dead-code response=None guard in _pkce_token_exchange

* clean up stale pkce verifier cache entries in non-strict mode

* fix test: configure async_delete_cache as AsyncMock and assert cleanup called

* add sentinel guard so pkce-no-redis warning only fires once across hot-reloads

* fix misleading comments: code_verifier init and bearer-credential merge docs

* add best-effort cleanup in strict-mode for corrupt/empty cache entries

* add redirect_uri assertion, userinfo body in non-200 log, sentinel comment
2026-03-12 12:41:39 -07:00
Cesar Garcia
7ec78232b2
Merge pull request #23440 from BerriAI/litellm_oss_staging_03_11_2026
Litellm oss staging 03 11 2026
2026-03-12 16:24:14 -03:00
Chesars
690ad4c45b fix(openai): drop all reasoning_effort for gpt-5.4 + tools, including 'none'
OpenAI rejects any reasoning_effort (even 'none') with tools in
/v1/chat/completions for gpt-5.4. Update the guard to drop reasoning_effort
regardless of value. Add docs explaining the auto-drop behavior.
2026-03-12 16:22:40 -03:00
Chesars
17dbc61f39 fix(openai): align gpt-5.4 reasoning_effort drop with main
Remove dead routing condition (is_model_gpt_5_4_plus_model) that
prevented reasoning_effort from being dropped when tools are present.
The Responses API routing was never merged, so the guard was a no-op
that broke the drop logic introduced by 14b52b1318 on main.
2026-03-12 16:22:40 -03:00