Commit graph

39401 commits

Author SHA1 Message Date
mateo-berri
ba75de7848
fix(realtime): preserve client session.update fields on follow-up Gemini setup
In non-deferred mode the auto-setup pre-populates session_configuration_request,
so a later client session.update carrying tools or instructions used to fall
into the subsequent path and only forward turn_detection. Rebuild a merged
follow-up setup that overlays the new client fields on top of the original
setup so tools/instructions/etc. are no longer silently dropped.
2026-05-22 21:19:13 +00:00
Cursor Agent
9efcc02776
fix(realtime): correct conversation_id, VAD disable, modality state, empty toolCall
- Gemini tool-call response.done now includes conversation_id so clients
  can match it against the preceding response.created.
- Vertex AI setup no longer overrides an explicit guardrail-injected
  create_response: False back to disabled: False; the guardrail's intent
  to disable VAD auto-response is now respected.
- Modality handler is now passed the locally-updated response/item IDs
  rather than the original input snapshot, preventing stale IDs after a
  prior tool-call/response.done in the same JSON message resets them.
- Skip emitting orphaned response.created/response.done events when
  Gemini sends an empty functionCalls array.

Co-authored-by: Yassin Kortam <yassin@berri.ai>
2026-05-22 21:06:06 +00:00
mateo-berri
24b8e17a4b
test(gemini realtime): exercise toolCall → function_call_output name round-trip
Update test_gemini_realtime_function_call_output_transformation to pre-load
the call_id → name mapping by transforming a Gemini toolCall first, then
assert that the resulting Gemini toolResponse functionResponses entry
carries the function name. This pins the production round-trip rather
than the degenerate 'name missing' branch.
2026-05-22 20:48:11 +00:00
Cursor Agent
36f6d84c22
fix(realtime): avoid double-serialization and normalize non-dict turn_detection in guardrail override
- Skip the force-override block when the injection block already ran for
  the same session.update to avoid redundant JSON re-serialization.
- Normalize non-dict client-provided turn_detection values (flat and
  nested audio.input.turn_detection) to a dict before enforcing
  create_response=False, matching the injection block's behavior and
  preventing potential bypass on backends that accept non-dict values.

Co-authored-by: Yassin Kortam <yassin@berri.ai>
2026-05-22 20:44:58 +00:00
Cursor Agent
50ef9c8c21
fix(gemini realtime): preserve original setup config on follow-up session.update
Gemini Live treats a second BidiGenerateContentSetup as a full session
replacement, not a partial merge. The guardrail-driven turn_detection-only
session.update was emitting a setup containing only model + realtimeInputConfig,
which would silently drop tools, generationConfig, inputAudioTranscription, and
systemInstruction from the original setup. Carry forward the cached original
setup and only override realtimeInputConfig.

Co-authored-by: Yassin Kortam <yassin@berri.ai>
2026-05-22 20:31:15 +00:00
mateo-berri
00cde9da7c
fix(lint): silence PLR0915 on client_ack_messages
The function exceeded the 50-statement limit (64 > 50) after recent
realtime guardrail additions. Matches the existing project pattern for
inherently complex event/message-mapping methods (see _process_event,
translate_messages_to_responses_input, transform_realtime_response,
_arealtime, etc.).
2026-05-22 20:20:11 +00:00
mateo-berri
f2d8a2a8fe
fix(realtime): force create_response=False in all client session.update turn_detection when audio guardrails active
Prevents a client from re-enabling Gemini/GA VAD auto-response (and thereby
bypassing the audio transcription guardrail) by sending a later
session.update with turn_detection.create_response: true.
2026-05-22 20:11:59 +00:00
mateo-berri
fb935426eb
fix(vertex_ai/realtime): normalize all GA-remapped session fields before mapping
Previously _build_vertex_ai_setup_config only lifted nested turn_detection
back to the top level. GA clients' output_modalities and
audio.input.transcription were silently dropped because map_openai_params
only recognises the flat OpenAI-beta keys. Use the parent's
_normalize_session_payload_for_mapping so modalities, transcription, and
turn_detection are all surfaced before mapping.
2026-05-22 19:43:11 +00:00
Cursor Agent
2325041913
fix(gemini realtime): normalize GA-remapped session fields before mapping
map_openai_params only recognises the flat OpenAI-beta keys (modalities,
input_audio_transcription, turn_detection). For GA clients the upstream
shim renames these into the nested GA schema (output_modalities,
audio.input.transcription, audio.input.turn_detection), causing them to
be silently dropped in _handle_session_update. Add a normalization helper
that surfaces the GA-remapped values back at the top level so the
existing mapping logic picks them up. Without this, a GA client
explicitly requesting modalities=['text'] would still default to audio
output.

Co-authored-by: Yassin Kortam <yassin@berri.ai>
2026-05-22 19:29:36 +00:00
Cursor Agent
8cf3f4eda1
fix(vertex_ai realtime): keep VAD enabled when guardrails inject create_response: False
map_automatic_turn_detection sets disabled=True whenever create_response is
absent OR False. Transcription guardrails inject create_response: False to
suppress auto-responses while expecting VAD to stay active, but the previous
override in _build_vertex_ai_setup_config only fired when create_response was
absent, leaving disabled=True and silently breaking speech detection and
transcription events. Vertex Live has no 'VAD on, no auto-response' mode, so
always keep VAD active in the setup config.

Co-authored-by: Yassin Kortam <yassin@berri.ai>
2026-05-22 19:06:38 +00:00
Cursor Agent
6f45b5df06
fix(realtime): set guardrail turn_detection flag only after successful send
Previously the _guardrail_turn_detection_update_sent flag was set inline
during message rewriting in client_ack_messages, before the modified
session.update was forwarded to the backend. If _send_to_backend raised
(e.g. backend WebSocket disconnect), the exception was caught and the
loop continued, but the flag remained True — permanently disabling the
guardrail create_response=False injection for the rest of the session.
Neither the client_ack_messages path nor the
_maybe_send_guardrail_turn_detection_update backup path would retry.

Track the injection locally and only set the flag after _send_to_backend
returns a truthy sent result, matching the pattern used by
_maybe_send_guardrail_turn_detection_update.

Co-authored-by: Yassin Kortam <yassin@berri.ai>
2026-05-22 18:49:47 +00:00
mateo-berri
b721714783 fix(gemini realtime): default response.done modalities to AUDIO and correct audio-done test 2026-05-22 18:34:43 +00:00
Cursor Agent
2f0d8080d1
fix(gemini realtime): default responseModalities to AUDIO in delta events
Align return_new_content_delta_events with the AUDIO defaults used in
_handle_session_update and transform_session_created_event so deferred
session config does not produce TEXT-typed delta events for audio data.

Co-authored-by: Yassin Kortam <yassin@berri.ai>
2026-05-22 18:23:05 +00:00
mateo-berri
bcba880c8b
fix(vertex_ai/realtime): drop follow-up session.update to avoid 1007 close
Vertex AI Live treats setup as a first-and-only client message; emitting a
second setup with realtimeInputConfig only closes the websocket with a 1007
policy error. Reverting the follow-up-setup branch restores the pre-existing
no-op behavior for subsequent session.update messages.
2026-05-22 18:11:21 +00:00
Cursor Agent
159982a892
fix(gemini realtime): default synthetic session.created modalities to AUDIO
The synthetic session.created event emitted in deferred setup mode used
TEXT as the default for responseModalities, while _handle_session_update
defaults to AUDIO. Align the default so clients reading modalities from
the initial session.created see the correct value for live sessions.

Co-authored-by: Yassin Kortam <yassin@berri.ai>
2026-05-22 18:09:03 +00:00
mateo-berri
38e822e41b
fix(realtime): tolerate non-dict turn_detection in guardrail injection
When a client sends a session.update whose turn_detection field is None or
a non-dict value (e.g. "auto"), the guardrail injection used setdefault
followed by item assignment on the returned value, raising TypeError. The
inner except only caught JSONDecodeError/AttributeError, so the TypeError
escaped to the outer Exception handler that wraps the entire client_ack
loop, killing the connection. Replace non-dict turn_detection with a
fresh dict carrying create_response=False so the guardrail still applies
without crashing the loop.
2026-05-22 17:49:18 +00:00
Cursor Agent
76225f35b1
fix(realtime): normalize Vertex AI nested turn_detection and unify session.created guardrail ordering
- Vertex AI _build_vertex_ai_setup_config now lifts nested
  audio.input.turn_detection to the top level before calling
  map_openai_params, mirroring the parent GeminiRealtimeConfig
  behavior. Without this, guardrail-injected create_response: False
  was silently dropped for GA-protocol Vertex AI clients.
- realtime_streaming session.created handling now sends the
  (possibly re-typed) event first and then triggers the guardrail
  turn-detection update for both first and duplicate cases, removing
  the inconsistent guardrail-then-event ordering for duplicates.

Co-authored-by: Yassin Kortam <yassin@berri.ai>
2026-05-22 17:16:34 +00:00
Cursor Agent
8e6fe6c8ad
fix(gemini-realtime): preserve nested turn_detection through map_openai_params
After the GA remap moves session.turn_detection into session.audio.input.turn_detection,
Gemini's map_openai_params only looks at top-level keys and silently drops it. Normalize
the extracted turn_detection back to the top level on first session.update so the guardrail
create_response:False (and any client-provided VAD settings) reach the Gemini setup.

Co-authored-by: Yassin Kortam <yassin@berri.ai>
2026-05-22 17:02:12 +00:00
Cursor Agent
24af92663d
fix(realtime): correct deferred-setup session.created modalities and reset IDs after response.done
- Convert provider's real session.created to session.updated when a synthetic
  one was already forwarded so clients receive the authoritative modalities
  derived from their session.update instead of the synthetic placeholder.
- Reset current_response_id / current_output_item_id after Gemini RESPONSE_DONE
  so a toolCall arriving in a later frame starts a fresh response instead of
  reusing the completed response's ID and emitting a duplicate response.done.

Co-authored-by: Yassin Kortam <yassin@berri.ai>
2026-05-22 16:45:13 +00:00
Sameer Kankute
86ace3ef1a
Merge branch 'litellm_internal_staging' into litellm_live_api_tool_calling_support 2026-05-22 21:56:28 +05:30
Sameer Kankute
ef36e89638
feat(mcp): Add tool call and tool list support via UI for Oauth mcps (#28454)
* feat(mcp): cache OAuth token client-side so Tools tab loads without re-auth

After a user creates an OAuth MCP server and completes the authorization
flow, the resulting access token is now stored in sessionStorage keyed by
server_id.  The MCP Tools tab reads this cached token and includes it as
an MCP auth header when listing and invoking tools, so the user never sees
an empty tool list.  When the session ends (tab close / new browser) an
Authorize button re-triggers the flow without leaving the Tools screen.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>

* fix(ui/mcp): surface listMCPTools 401 errors so auth gate reappears

listMCPTools previously swallowed all errors (including HTTP 401) by
returning a synthetic { tools: [], error: 'network_error', ... } payload.
That made the useQuery retry-on-401 guard and mcpToolsError dead code,
so expired OAuth tokens never re-triggered the auth gate.

- Throw an enhanced Error with .status attached on non-2xx responses
  (still preserves the legacy shape for true network failures so the
  caller can render a generic message without crashing).
- Clear the cached OAuth session token when the tools query fails with
  401, mirroring callMCPTool's onError handler so the Authorize button
  is shown again.
- Surface mcpToolsError in the existing error banner.

Co-authored-by: Yassin Kortam <yassin@berri.ai>

* fix(mcp-tools): stable onSuccess + reuse parsed flow state

- Pass stable setOauthToken setter directly as onSuccess to avoid
  recreating useToolsOAuthFlow's resumeOAuthFlow on every render.
- Reuse the already-parsed FLOW_STATE_KEY value (peeked) instead of
  re-reading and re-parsing sessionStorage in resumeOAuthFlow.

Co-authored-by: Yassin Kortam <yassin@berri.ai>

* fix(ui/mcp): restore listMCPTools never-throws contract

The previous fix made listMCPTools throw on HTTP errors while still
returning a synthetic object on network errors. This inconsistent
contract broke existing callers (MCPToolPermissions, MCPAppsPanel,
MCPConnectPicker) which inspect result.error / result.message and
expect the function to never throw.

- Return a normalized { tools: [], error, message, status, ... }
  object on HTTP errors (instead of throwing) so all callers see a
  consistent shape and the user-visible error text from
  result.message is preserved.
- Convert the returned error object into a thrown Error inside the
  one caller that needs it — the useQuery in mcp_tools.tsx — so the
  401 retry/onError handlers still trigger and clear the cached
  OAuth token.

Co-authored-by: Yassin Kortam <yassin@berri.ai>

* fix greptile

* fix(mcp): align OAuth header alias lookup with dashboard sanitization

Backend auth header resolution now matches x-mcp-{alias} keys produced by
the dashboard sanitizer, and the Tools tab re-syncs OAuth tokens when
serverId changes.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(mcp): widen auth header lookup types for list_tools

Accept legacy str | dict server auth maps and annotate list_tools
server_auth_header as Union[str, dict] for mypy.

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor(ui): extract shared buildCallbackUrl/clearStorage for MCP OAuth hooks

Hoist the duplicate buildCallbackUrl and clearStorage helpers out of
useToolsOAuthFlow and useUserMcpOAuthFlow into a new shared module
src/hooks/mcpOAuthUtils.ts so the two hooks cannot drift if the URL
construction or storage cleanup logic needs to change.

Co-authored-by: Yassin Kortam <yassin@berri.ai>

* fix(ui): don't gate M2M OAuth MCP servers behind interactive authorize

M2M (client_credentials) OAuth servers share auth_type="oauth2" with
interactive PKCE servers, but the backend fetches their token internally
and they typically lack a user authorization endpoint. Gating tool
listing on them rendered an Authorize button that would fail or redirect
incorrectly. Detect M2M via the presence of token_url (matching the
existing heuristic in mcp_server_edit.tsx) and skip the auth gate.

Co-authored-by: Yassin Kortam <yassin@berri.ai>

* fix(ui/mcp): return error shape when listMCPTools JSON parse fails

Restore the never-throws contract when response.json() fails on a 2xx
body so callers do not receive null and crash on result.tools.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Yassin Kortam <yassin@berri.ai>
2026-05-22 09:04:04 -07:00
Sameer Kankute
7a93cceb9f
Add error_description and hint for oauth flows (#28471)
* Add error_description and hint for oauth flows

* Fix tests

* fix(mcp-oauth): improve redirect_uri errors without leaking internal config

Use NoReturn on _oauth_invalid_request, structured errors for BYOK loopback
validation, and refactor validate_trusted_redirect_uri to satisfy PLR0915.
Keep PROXY_BASE_URL and raw proxy_base_url in server logs only, not in the
HTTP 400 body returned to unauthenticated callers.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(mcp-oauth): stop leaking internal proxy origin in redirect_uri 400 body

The trusted-redirect-uri rejection helper included the proxy's
resolved scheme/host/port (e.g. http://litellm-internal:4000) in both
the error_description and as a top-level proxy_origin field. Since
the OAuth /authorize endpoint is unauthenticated, any caller could
probe with a crafted redirect_uri and enumerate the internal network
topology behind a reverse proxy.

Keep full diagnostic detail in the server-side warning log
(including the computed proxy base) but omit proxy-side values from
the HTTP 400 body. Also drop the duplicated origin computation in
_raise_trusted_redirect_uri_rejected now that those values are no
longer needed by the response.

Co-authored-by: Yassin Kortam <yassin@berri.ai>

* fix(mcp-oauth): remove dead userinfo check in redirect_uri validation

The first check combined missing netloc with userinfo presence, making
the second userinfo-only check unreachable. Split into two distinct
checks so each error message reflects the actual failure mode.

Co-authored-by: Yassin Kortam <yassin@berri.ai>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Yassin Kortam <yassin@berri.ai>
2026-05-22 09:00:39 -07:00
Sameer Kankute
d96e26064f
Fix conflicts and UI (#28477) 2026-05-22 08:55:28 -07:00
Cursor Agent
c1647f6f59
fix(gemini realtime): pop tool_call_id mapping after use to bound memory
Co-authored-by: Yassin Kortam <yassin@berri.ai>
2026-05-22 14:19:59 +00:00
Cursor Agent
abb7080496
fix(realtime): consolidate send-and-cache, guard session.update lookup, preserve client turn_detection in GA remap
- Replace duplicated transform/send/cache logic in client_ack_messages with a call to _send_to_backend so future changes stay in one place.
- VertexAIRealtimeConfig.transform_realtime_request now uses .get('session') or {} for the first session.update so a malformed client payload no longer crashes the connection.
- Move the audio-transcription guardrail turn_detection injection to run BEFORE the beta->GA session remap. This lets the injected create_response ride along with any client-provided turn_detection fields (e.g. silence_duration_ms) into the nested audio.input.turn_detection path produced by the remap instead of being stranded as a separate root-level dict.
- Update the deferred-mode injection test to assert the GA-shaped location.

Co-authored-by: Yassin Kortam <yassin@berri.ai>
2026-05-22 14:06:02 +00:00
Cursor Agent
cb49dd974e
fix(realtime): forward turn_detection updates for Vertex; respect partial VAD config; cache setup after send
Co-authored-by: Yassin Kortam <yassin@berri.ai>
2026-05-22 13:50:15 +00:00
Sameer Kankute
8df4d5386b
fix(gemini/realtime): resolve mypy TypedDict errors in transformation
Align realtime event payloads and setup types with OpenAI/Gemini TypedDicts so mypy passes and tool-call events type-check correctly.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 18:55:47 +05:30
Cursor Agent
df7c3da1f7
fix(realtime): log injected message and forward guardrail VAD-disable on Gemini
- Move store_input() after the guardrail turn_detection injection in
  client_ack_messages so audit logs reflect what is actually forwarded
  to the backend (previously the unmodified pre-injection message was
  logged).
- In Gemini's _handle_session_update, allow a session.update that only
  carries a turn_detection change to be forwarded as a follow-up Gemini
  setup with realtimeInputConfig.automaticActivityDetection set, even
  after the initial setup. This restores the guardrail layer's ability
  to disable VAD auto-response in non-deferred mode (the default Gemini
  flow), which was a regression after _handle_session_update started
  silently dropping subsequent session.update messages. Both flat
  beta-style and nested GA-style turn_detection payloads are accepted.

Co-authored-by: Yassin Kortam <yassin@berri.ai>
2026-05-22 13:17:59 +00:00
Sameer Kankute
b12f52ae26
fix lint 2026-05-22 18:44:28 +05:30
Sameer Kankute
f5ecff22ed
fix(gemini/realtime): reset response IDs after tool-call response.done
After closing a tool-call response, clear current_output_item_id and
current_response_id so post-tool model turns emit a fresh response.created
preamble. Add regression tests and align guardrail turn_detection test with
GA session shape; apply Black formatting.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 18:23:02 +05:30
Cursor Agent
165fedd83a
fix(realtime): correct guardrail flag and event-mapping fallback
- realtime_streaming: only mark _guardrail_turn_detection_update_sent
  when the message was actually delivered to the backend. The provider
  transformation (e.g. Gemini after initial setup) may silently drop
  session.update; previously we set the flag anyway, falsely claiming
  the disable was sent and preventing any retry on subsequent
  session.created events. _send_to_backend now returns whether at
  least one transformed message was sent.

- gemini realtime transformation: avoid shadowing the outer
  openai_event variable in map_openai_event's fallback loop. With
  the new toolCall entry now last in MAP_GEMINI_FIELD_TO_OPENAI_EVENT,
  an unmatched key would otherwise leak FUNCTION_CALL_ARGUMENTS_DONE
  and skip the ValueError raise. Use a distinct loop variable so the
  is-None check correctly raises for unknown Gemini messages.

Co-authored-by: Yassin Kortam <yassin@berri.ai>
2026-05-22 12:43:45 +00:00
Cursor Agent
25a5ebe68d
fix(vertex_ai/realtime): call super().__init__() to initialize tool call state
Co-authored-by: Yassin Kortam <yassin@berri.ai>
2026-05-22 12:25:36 +00:00
Sameer Kankute
f942c8c66e
fix: resolve merge conflict markers in UI build chunk
Take litellm_internal_staging version of e1a670efcb966aaa.js after
incomplete merge left conflict markers in the committed artifact.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 17:47:05 +05:30
Sameer Kankute
54f352c6a5
Merge litellm_internal_staging into litellm_live_api_tool_calling_support
Resolve conflicts: keep both gemini_live_defer_setup and
use_legacy_interactions_schema flags; combine realtime streaming
session caching with beta/GA disable-auto-response message builder.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 17:46:06 +05:30
Sameer Kankute
6fb312fb1d
fix(realtime): include function name in toolResponse (P1)
- Store call_id → name mapping when receiving toolCall from Gemini
- Look up and include name in functionResponses when sending tool results
- Required by Gemini Live API spec for proper tool call routing
- Add test to verify name field is included in round-trip

Made-with: Cursor
2026-05-22 17:44:04 +05:30
Sameer Kankute
4af845d43a
fix(realtime): emit response.done after tool-call sequence (P0 CRITICAL)
- Add response.done event after tool-call loop to signal response completion
- Required by OpenAI SDK clients to submit tool results
- Without this, clients stall indefinitely waiting for response completion
- Update test to verify complete 6-event sequence including response.done

Made-with: Cursor
2026-05-22 17:44:04 +05:30
Sameer Kankute
4fb0833670
fix(realtime): add response.output_item.done to complete tool-call sequence
- Emit response.output_item.done between function_call_arguments.done and conversation.item.created
- Required by OpenAI Realtime spec to finalize function-call items
- Update test to verify complete event sequence

Made-with: Cursor
2026-05-22 17:44:04 +05:30
Sameer Kankute
77571e811d
fix(realtime): emit response.created preamble before tool-call events
- Emit response.created, output_item.added, and conversation.item.created for function calls
- Ensures OpenAI Realtime API spec compliance
- Add test for preamble emission

Made-with: Cursor
2026-05-22 17:44:04 +05:30
Sameer Kankute
6274bc0d7b
fix(realtime): inject turn_detection into first session.update for deferred mode
- Instead of sending turn_detection as separate message (which gets dropped), inject it into the first client session.update
- This ensures guardrails work correctly in deferred mode
- Add test for turn_detection injection in deferred mode

Made-with: Cursor
2026-05-22 17:44:04 +05:30
Sameer Kankute
86f5c21025
fix(realtime): address P1 issues - guardrail timing and inputAudioTranscription default
- Remove early guardrail turn-detection update that consumed first setup slot
- Add inputAudioTranscription default in Gemini deferred-mode setup
- Add tests for both fixes

Made-with: Cursor
2026-05-22 17:44:04 +05:30
harish-berri
d04373f4ce
Add granian as a ASGI compliant web server. Provider better throughput stability, (#26027)
Some checks are pending
Unit Tests: Proxy DB Operations / endpoints-and-responses (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Waiting to run
Unit Tests: Proxy DB Operations / auth-checks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / budgets (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / custom-logging (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / db-and-spend (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / key-generation (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / logging-misc (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-runtime (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-server-core (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / schema-migration (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-utils (push) Blocked by required conditions
Unit Tests: Security / security (push) Waiting to run
* Add granian as a ASGI compliant web server. Provides better stability, 10-20 RPS improvement under standard LT conditions.

TODO: Verify poetry lock details and add locust numbers to PR

* Update granian version in license_cache.json and pyproject.toml to 2.5.7

* Enhance proxy CLI tests by adding SSL initialization checks for Granian server. Remove Python version skip conditions and implement tests to ensure SSL certificate and key are required for server initialization.

* update uv lock to fix granian import error
2026-05-21 19:08:37 -07:00
ryan-crabbe-berri
07bcd2c19e
test(e2e): forward LITELLM_LICENSE to UI e2e proxy (#28398)
* test(e2e): forward LITELLM_LICENSE to UI e2e proxy

The UI e2e job ran without LITELLM_LICENSE, so premium_user was always
false in the issued login JWT and premium-gated UI surfaces (Team-BYOK
Model switch, etc.) couldn't be driven through the UI. Forward the env
var from run_e2e.sh and the CircleCI e2e_ui_testing job, and add a
sanity test that decodes the admin storage state token and asserts
premium_user=true so the wiring fails loudly if it ever regresses.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Update ui/litellm-dashboard/e2e_tests/tests/proxy-admin/license.spec.ts

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-05-21 18:17:03 -07:00
yuneng-jiang
9fcd424318
chore(deps): bump deps (#28528)
* build(deps): bump next from 16.2.4 to 16.2.6 in /ui/litellm-dashboard (#27665)

Bumps [next](https://github.com/vercel/next.js) from 16.2.4 to 16.2.6.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v16.2.4...v16.2.6)

---
updated-dependencies:
- dependency-name: next
  dependency-version: 16.2.6
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump protobufjs in /tests/pass_through_tests (#28296)

Bumps [protobufjs](https://github.com/protobufjs/protobuf.js) from 7.5.6 to 7.6.0.
- [Release notes](https://github.com/protobufjs/protobuf.js/releases)
- [Changelog](https://github.com/protobufjs/protobuf.js/blob/protobufjs-v7.6.0/CHANGELOG.md)
- [Commits](https://github.com/protobufjs/protobuf.js/compare/protobufjs-v7.5.6...protobufjs-v7.6.0)

---
updated-dependencies:
- dependency-name: protobufjs
  dependency-version: 7.6.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump ws from 8.20.0 to 8.20.1 in /tests/pass_through_tests (#28303)

Bumps [ws](https://github.com/websockets/ws) from 8.20.0 to 8.20.1.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.20.0...8.20.1)

---
updated-dependencies:
- dependency-name: ws
  dependency-version: 8.20.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-22 00:42:21 +00:00
yuneng-jiang
2a5dfcd5bc
build(deps-dev): bump black to 26.3.1 and apply formatting (#28525)
* build(deps-dev): bump black 24.10.0 -> 26.3.1

* style: apply black 26.3.1 formatting

* chore: authorize black 26.3.1 license in liccheck.ini
2026-05-21 17:24:18 -07:00
yuneng-jiang
0715ed3359
build(deps): bump next from 16.2.4 to 16.2.6 in /ui/litellm-dashboard (#27665) (#28524)
Bumps [next](https://github.com/vercel/next.js) from 16.2.4 to 16.2.6.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v16.2.4...v16.2.6)

---
updated-dependencies:
- dependency-name: next
  dependency-version: 16.2.6
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-22 00:13:56 +00:00
yuneng-jiang
f1abe03ed6
fix(docker): restore npm to non_root builder image (#28519)
The non_root builder stage installs `nodejs` but not `npm`. Without `npm`
on PATH, prisma-python falls back to downloading a Node runtime via
nodeenv from nodejs.org, and that downloaded binary fails to load
`libatomic.so.1` — breaking `prisma generate` and the image build.

`npm` was dropped from this apk list in ca52e346b0. Restoring it lets
prisma-python use the system Node + npm, matching docker/Dockerfile
which already installs `npm` for the same reason.
2026-05-21 17:02:42 -07:00
yuneng-jiang
3f953dfa96
test(vertex_ai): tolerate transient 500 in google maps grounding test (#28503)
test_gemini_google_maps_tool_simple makes live calls to Vertex AI's
Google Maps grounding backend, which intermittently returns
500 INTERNAL ("Please retry") — a transient Google-side failure, not a
LiteLLM bug. The request LiteLLM emits matches Google's published
googleMaps grounding spec field-for-field, and the maps-platform 500
only occurs after Vertex accepts the request.

The test already passes on RateLimitError; treat InternalServerError
the same way so transient Vertex-side failures don't fail CI.
2026-05-21 17:01:49 -07:00
yuneng-jiang
67e6e5e1df
test(proxy): behavior-pinning matrix for team management endpoints (#28441)
* test(proxy): behavior-pinning matrix for team management endpoints

PR2 (Team Tier-1) of the management-endpoint behavior-pinning effort.
Extends the tests/proxy_behavior/management/ harness PR1 built and adds
the actor x target-resource authz matrix for the 7 team endpoints:
/team/new, /team/info, /team/list, /team/update, /team/member_add,
/team/member_delete, /team/member_update.

Tests-only, no production code changes.

Harness extensions:
- actors.py: ORG_B_ADMIN actor (org admin of ORG_B) and TEAM_GAMMA (an
  ORG_A team with no actor members), so team-targeting endpoints get a
  clean own / same-org-other / cross-org target axis.
- conftest.py: create_scratch_team() raw-seeds target teams without
  /team/new side effects; the scratch teardown now also strips dangling
  scratch-team refs from LiteLLM_UserTable.teams.

156 new scenarios; status codes pinned to observed handler behavior.

* test(proxy): record mutmut run blockers in PR2 triage doc

Attempted a scoped local mutmut run for G5; it did not complete. Record
the three concrete blockers in mutmut_triage/pr2-team-tier1.md so the next
attempt has a head start:

1. mutmut's mutants/ sandbox is import-shadowed by the worktree source.
2. the legacy mock suite and the real-DB behavior suite cannot share a
   pytest session (mock suite globally patches prisma_client).
3. the CI mutation-test.yml workflow starts no Postgres, so its stats
   phase now aborts on the behavior-suite tests PR1 added to tests_dir.

mutmut stays a deferred follow-up (as in PR1); the binding pre-merge
signal remains the behavior matrix (G1) and the G4 regression-replay.

* test(proxy): drop suite README + triage doc, trim test comments

Remove the two prose docs from the behavior suite (README.md and
mutmut_triage/pr2-team-tier1.md) and tighten the comment blocks on the
team test files + harness down to the load-bearing parts (the gate each
matrix pins, plus genuinely surprising results). No behavior change —
all 286 scenarios still pass.

* test(proxy): remove mutmut tests_dir comment
2026-05-21 16:57:25 -07:00
Yassin Kortam
10bd7406e0
feat: add guardrail violation span attributes and fix missing spans on pre-call blocks (#28364)
- Fix missing guardrail child spans when a pre-call guardrail blocks the request before reaching the LLM provider; `async_post_call_failure_hook` now calls `_emit_guardrail_spans_from_request_data` to emit spans from `request_data["metadata"]` regardless of whether `_handle_failure` already fired
- Add `guardrail_status`, `guardrail_action`, and `guardrail_violation_categories` as queryable top-level OTEL span attributes so trace backends can filter/group by violation type without parsing the redacted `guardrail_response` blob
- Introduce `_emit_guardrail_spans_from_request_data` helper that constructs minimal kwargs from `request_data["metadata"]` and routes through `_create_guardrail_span`, sharing the same dedupe state to prevent double-emitting when both failure hooks fire
- Extend `BedrockGuardrail` with `_build_tracing_detail` and `_extract_violation_category_names` which flatten BLOCKED assessments into human-readable category labels (topic names, content-filter types, PII entity types, named regex names) before redaction, and surface Bedrock's raw `action` field via `tracing_detail`
- Security: violation category extraction deliberately omits `customWords.match` and unnamed regex `match` values because those fields carry the user-submitted content that triggered the rule; only operator-defined `name`/`type` labels are emitted
- Add `violation_categories` and `guardrail_action` fields to `StandardLoggingGuardrailInformation` and `GuardrailTracingDetail` TypedDicts to carry the pre-redaction metadata through the logging pipeline
- Add comprehensive test suite covering: guardrail span creation on failure, dedupe between `_handle_failure` and `async_post_call_failure_hook`, per-span status attributes for multi-guardrail sequences, Bedrock category extraction for all policy types, security leak prevention, and end-to-end `CustomGuardrail` violation path

Co-authored-by: Yassin Kortam <yassinkortam@g.ucla.edu>
2026-05-21 15:49:42 -07:00
milan-berri
b55749248d
fix(logging): recalculate cost after router retry failures (#28476)
* fix(logging): recalculate cost after router retry failures

Do not preserve response_cost=0 from failure_handler when processing a
successful response; only keep pre-calculated costs > 0 (pass-through).

Co-authored-by: Cursor <cursoragent@cursor.com>

* test(logging): guard pass-through zero cost; use != 0 preserve check

Use != 0 for pre-calculated cost preservation (Greptile feedback). Add tests
for zero cost in _hidden_params and for hidden_params overriding failure 0.

Co-authored-by: Cursor <cursoragent@cursor.com>

* test(vertex): skip google maps tool test on transient upstream 500

The test test_gemini_google_maps_tool_simple calls real Vertex AI with the
googleMaps tool, which depends on Google Maps Platform. CI has been
failing on local_testing_part1 across many unrelated PRs (including this
one and the litellm_internal_staging base) with an InternalServerError
500 from Maps Platform ('Internal server error. Please retry. ...maps-
platform-support'), which is an external upstream flake unrelated to
the change under test.

Catch litellm.InternalServerError and skip (mirroring the existing
RateLimitError handler) so transient upstream outages don't block CI.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: mateo-berri <277851410+mateo-berri@users.noreply.github.com>
2026-05-21 14:07:05 -07:00