Commit Graph
241 Commits
Author SHA1 Message Date
Krish DholakiaandGitHub 244bdffd1b Merge pull request #23509 from michelligabriele/fix/pass-through-duplicate-failure-logs
fix(proxy): prevent duplicate callback logs for pass-through endpoint failures
2026-03-18 11:57:50 -07:00
Kelvin TranandGitHub c6e9a2a40f Merge branch 'main' into fix/cache-control-params-anthropic-document-file-message-blocks 2026-03-17 15:34:00 -07:00
Kelvin Tran d0c5f494a8 fix: cache_control directive dropped anthropic document/file blocks 2026-03-17 14:30:12 -07:00
Sameer KankuteandGitHub b796ee9f03 Merge pull request #23530 from Sameerlite/litellm_preserve-final-streaming-attributes
fix(streaming): preserve custom attributes on final stream chunk
2026-03-16 19:12:41 +05:30
Krish DholakiaandGitHub ca4329aeb9 Root cause fix - migrate all logging update to use 1 function - for centralized kwarg updates (#23659)
* fix: Fixes https://github.com/BerriAI/litellm/issues/23185

* fix(responses/main.py): ensure litellm metadata custom cost works

* refactor: move all logging updates to a common function, to have just 1 place to update logging kwarg updates
2026-03-15 23:21:01 -07:00
Krish DholakiaandGitHub 8abf2d8e34 fix: Fixes https://github.com/BerriAI/litellm/issues/23185 (#23647) 2026-03-14 12:30:52 -07:00
milan-berriandGitHub d29287c1c3 fix: normalize content_filtered finish_reason (#23564)
Map provider finish_reason "content_filtered" to the OpenAI-compatible "content_filter" and extend core_helpers tests to cover this case.

Made-with: Cursor
2026-03-14 10:50:33 -07:00
Sameer Kankute a01248658e fix(streaming): preserve upstream custom fields on final chunk
Ensure final finish_reason chunks retain non-OpenAI attributes from original provider chunks, including the holding_chunk flush path where delta is non-empty. Add regression tests for both final-chunk branches.

Made-with: Cursor
2026-03-13 13:06:18 +05:30
michelligabriele a4f94b241b fix(proxy): prevent duplicate callback logs for pass-through endpoint failures
Pass-through endpoint failures fired both async_failure_handler and
async_post_call_failure_hook, causing duplicate logs in callback
integrations. Add pass-through guards to the failure path, matching
the existing success path behavior.
2026-03-13 04:32:36 +01:00
Cesar GarciaandGitHub 6bd7cd7573 Merge branch 'main' into litellm_oss_staging_03_11_2026 2026-03-12 10:43:08 -03:00
Chesars 1be6b31e2f merge: resolve conflicts between main and litellm_oss_staging_03_11_2026 2026-03-12 09:38:31 -03:00
yuneng-jiangandGitHub 626d120873 Merge pull request #23425 from BerriAI/cursor/litellm-ci-stability-4513
[Infra] CI/CD Fixes
2026-03-11 21:08:16 -07:00
Sameer KankuteandGitHub 49d653c3aa Revert "chore: cleanup deprecated models from pricing JSON" 2026-03-12 09:27:40 +05:30
Cursor Agentandyuneng-jiang aacc7b18f8 fix(ci): add missing provider docs, fix deprecated model refs in cost tests
- Add black_forest_labs and charity_engine to provider_endpoints_support.json
  (fixes check_code_and_doc_quality job)
- Replace o1-mini with o1 in test_reasoning_tokens_no_price_set (model removed
  from cost map)
- Replace gemini-2.5-pro-exp-03-25 with gemini-2.5-pro in
  test_generic_cost_per_token_above_200k_tokens (model removed from cost map)
- Fix test_get_cost_for_anthropic_web_search to use claude-3-7-sonnet-20250219
  with custom_llm_provider='anthropic' so web search cost is computed correctly

Co-authored-by: yuneng-jiang <yuneng-jiang@users.noreply.github.com>
2026-03-12 03:11:29 +00:00
Chesars d81d751af0 fix(tests): update tests to use models still present in pricing JSON
Replace removed deprecated models (claude-3-5-sonnet-20241022,
claude-3-5-haiku-20241022, claude-3-5-haiku-latest) with current
models in web_search and cost calculation tests.
2026-03-11 14:50:47 -03:00
+2 3f18cd2fdc [Docs] Fix "Page Not Found" link for Anthropic endpoint (#23349)
* fix(anthropic): enforce type:'object' on tool input schemas

Anthropic's API requires all tool input_schema to have type:'object'
at the root level. When OpenAI-format tools have parameters with a
missing or non-'object' type field (common with MCP tool servers),
the schema was passed through unchanged, causing Anthropic to reject
with: 'tools.N.custom.input_schema.type: Input should be object'.

The existing default handles the case where parameters is entirely
missing, but does not normalize schemas that ARE provided with a
wrong or absent type field.

Fix: After extracting _input_schema in _map_tool_helper(), ensure
type is set to 'object' and properties exists. This matches the
normalization already done implicitly by the Bedrock handler.

Added 4 unit tests covering: missing type, wrong type, valid schema
(no-op), and entirely missing parameters.

Related issues: #12020, #64, #1671

* fix(anthropic): deduplicate tool_result messages by tool_call_id

Anthropic requires exactly one tool_result per tool_use. When
conversation history (e.g. from session resume/checkpoint restore)
contains duplicate tool result messages with the same tool_call_id,
the API rejects with: 'each tool_use must have a single result.
Found multiple tool_result blocks with id: <id>'.

This is already handled for Bedrock via _deduplicate_bedrock_tool_content()
but was missing from the Anthropic direct and Vertex AI partner paths,
which share sanitize_messages_for_tool_calling().

Fix: Add Case D to sanitize_messages_for_tool_calling() — after the
existing orphan detection passes, scan for duplicate tool_call_ids
and keep only the last occurrence (most complete result).

Added 3 unit tests: dedup with duplicates, no-op with unique IDs,
and behavior when modify_params=False.

Related issues: #11804, #11029, #6836, #1782, #151

* fix: shallow copy input_schema to avoid caller mutation + add mutation guard test

Addresses Greptile review:
- dict(_input_schema) before mutation prevents cross-provider state leakage
- Test asserts original tool parameters dict is unchanged after call

* feat: add qwen3.5 series for openrouter

* fix: typo on max_output_tokens and max_tokens from qwen3.5 series

* chore: fix

* chore: fix

* [Test] UI - Logs: Add unit tests for 5 untested view_logs components

Add vitest tests for TypeBadges, ErrorViewer, ConfigInfoMessage, TimeCell, and TruncatedValue covering rendering, user interactions, and edge cases.

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

* Rename 'Team-Based Guardrails' to 'Team Bring-Your-Own Guardrails' (#23307)

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

* feat(chat-ui): responses API + MCP tool execution in /chat (#23297)

* feat(ui): add Chat UI v0 — standalone LiteLLM-branded chat window

Adds a full chat UI accessible from the sidebar Chat link (opens in new tab).
- Standalone route at /chat (outside dashboard layout — no Navbar/Sidebar chrome)
- Claude.ai-style layout: model selector top-left, LiteLLM logo center, settings top-right
- Greeting with time-of-day, centered input card, suggestion chips (Write/Learn/Code/Brainstorm)
- Sliding conversation history sidebar with Cmd+K search, rename, delete, date grouping
- localStorage-backed conversation persistence (litellm_chat_history_v1)
- Streaming completions via makeOpenAIChatCompletionRequest with AbortController stop support
- MCP server picker (toggle servers on/off per conversation)
- LiteLLM aesthetic: white/light-gray background, Ant Design blue (#1677ff) primary, system font
- Sidebar2: Chat menu item opens in new tab via window.open

* feat(chat-ui): responses API + MCP tool execution display

- Switch /chat from chat completions to responses API (previous_response_id session chaining)
- Add MCP server picker with search filter in chat input bar
- Show MCP tool call events (list_tools + call_tool) inline in chat via MCPEventsDisplay
- Add tool chip strip showing available tools when MCP servers are selected
- Non-blocking MCP toggle: server added immediately, verification in background (works for no-auth MCPs like deepwiki)
- Add truncateAfterMessage to useChatHistory for edit/retry
- Sync activeConversationId on URL change (fixes stale conversation on new chat)
- Add "Open Chat" shortcut button to sidebar

* fix(chat-ui): switch to responses API, remove dead code, add tests

- Switch handleSend from makeOpenAIChatCompletionRequest to makeOpenAIResponsesRequest with previous_response_id session chaining
- Add responsesSessionId state; reset to null when starting a new conversation
- Remove unused ChatInputBar.tsx and ModelSelector.tsx (dead code)
- Add tests/test_litellm/test_chat_ui_responses_session.py covering previous_response_id forwarding and signature validation

* fix(chat-ui): address greptile review issues

- Reset responsesSessionId when activeConversationId changes (not just on new conversation)
- Wire onMCPEvent callback into makeOpenAIResponsesRequest; render MCPEventsDisplay below messages
- Clear mcpEvents on each new send
- Explicitly filter history to user/assistant roles only (no tool-role casting)
- Remove duplicate "Chat" menu item from sidebar (pinned button serves same purpose)
- Make Sider a flex column so "Open Chat" button actually pins to bottom
- Fix tests to intercept real HTTP requests and assert previous_response_id in body

* fix(chat-ui): address greptile review feedback (greploop iteration 1)

- Fix duplicate context: when responsesSessionId is set, only send the
  new user message as input (prior context is already server-side via
  session chaining). Full history is still sent on the first turn.
- Fix ephemeral MCP events: store events per-message in ChatMessage.mcpEvents
  instead of ephemeral component state. Events now survive across turns
  and render inline below each assistant response via MCPEventsDisplay.
- Remove stale mcpEvents useState and ephemeral panel at bottom of chat.

* fix(chat-ui): address greptile review feedback (greploop iteration 2)

- Fix stale session on edit/retry: derive previousResponseId as null when
  historyOverride is set so edit/retry always starts a fresh Responses API
  session rather than chaining off a now-invalid prior session
- Fix unsafe MCPEvent cast: import MCPEvent directly from MCPEventsDisplay
  into types.ts and type ChatMessage.mcpEvents as MCPEvent[], eliminating
  the bare 'as MCPEvent[]' cast in ChatMessages.tsx

* fix(chat-ui): fix MCPEvent layering, batch localStorage writes, module-level test imports

- Move MCPEvent interface definition into chat/types.ts (single source of truth)
- MCPEventsDisplay.tsx now imports MCPEvent from types.ts instead of defining it locally
- Batch MCP event localStorage writes: accumulate during stream, persist once in finally
- Move test imports to module level per PEP 8 convention

* fix(chat-ui): fix MCPEvent import path and rename truncateFromMessage

- responses_api.tsx now imports MCPEvent directly from chat/types (not via MCPEventsDisplay re-export)
- Remove the now-unnecessary MCPEvent re-export from MCPEventsDisplay.tsx
- Rename truncateAfterMessage → truncateFromMessage: the function removes the target message and all subsequent ones (not just what comes after), so the new name accurately describes the behavior

* fix(responses-api): fix whitespace token filter and MCP server URL construction

- Drop the delta.trim() whitespace filter that was silently swallowing spaces
  and newlines during streaming, causing words to concatenate and paragraphs
  to collapse. Only skip truly empty strings (delta.length > 0).
- Use proxyBaseUrl for MCP server_url construction instead of the hardcoded
  relative path "litellm_proxy/mcp", so non-root deployments route correctly.

* fix(responses-api): use unique server_label per MCP server to prevent tool routing collisions

* fix(chat-ui): move MCPEvent to shared mcp_tools/types, skip partial events on abort

- Move MCPEvent interface to mcp_tools/types.tsx (shared with MCPServer/MCPTool),
  eliminating the playground→chat cross-module dependency. chat/types.ts and
  both playground components now import from mcp_tools/types.
- Only persist accumulated MCP events when the stream completes cleanly; aborted
  or errored turns drop partial events to avoid showing incomplete tool calls.

* fix(responses-api): use server_name for MCP URL routing, fix test path

- Use server_name (not alias) as the URL path segment for MCP server_url;
  alias is a display name that may differ from the registered proxy route.
  URL-encode the path to handle names with spaces/special characters.
- Fix sys.path.insert in tests to use __file__-relative path so tests pass
  regardless of which directory pytest is invoked from.

* fix(chat-ui): fix stale session after failed edit, clean MCP event persistence, unique server_label

- Eagerly call setResponsesSessionId(null) when historyOverride is set so a
  failed/aborted edit does not leave a stale session contaminating the next turn
- Replace abort-signal check with streamCompletedCleanly flag to correctly skip
  MCP event persistence on both abort and non-abort errors (network/API failures)
- Use server_name (unique) as server_label instead of alias to prevent silent
  tool-routing failures when two MCP servers share the same display name

* [Feat] UI - Show logos on MCP Apps page (#23320)

* feat(ui): add MCP server logo support across admin and chat UIs

- New MCPLogoSelector component with grid of well-known logos (GitHub,
  Slack, Notion, Linear, Jira, etc.) and custom URL input
- Create MCP Server form: logo picker with preview, OpenAPI presets
  auto-fill logo from registry icon_url
- Edit MCP Server form: logo picker pre-populated from mcp_info.logo_url
- Admin table: logos rendered next to server name in Name column
- Chat MCPAppsPanel: logos on server cards (list + detail view) with
  graceful fallback to letter avatars
- Chat MCPConnectPicker: logos next to server names in toggle list
- Fix pre-existing bug: setTools -> clearTools in create form cancel
- All 321 vitest files / 3211 tests pass

Co-authored-by: Ishaan Jaff <ishaan-jaff@users.noreply.github.com>

* feat(ui): use local SVG logos for MCP services, fix Chat UI rendering

- Add 15 new MCP service logo SVGs (Slack, Notion, Linear, Jira, Figma,
  Gmail, Stripe, Salesforce, Shopify, HubSpot, Twilio, Sentry, Zapier,
  GitLab, Google Drive) to both source and pre-built directories
- Switch MCPLogoSelector from CDN URLs (cdn.simpleicons.org) to local
  asset paths (/ui/assets/logos/) for reliable rendering
- Logos now served by the proxy itself, working from any page path
  including /ui/chat/ (absolute paths resolve correctly everywhere)

Co-authored-by: Ishaan Jaff <ishaan-jaff@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Ishaan Jaff <ishaan-jaff@users.noreply.github.com>

* fix(codeql): remove ruby from language matrix (#23227)

* Add team-scoped MCP server filtering for key creation and fix UnboundLocalError

When creating a key, the MCP server list now filters by the selected team's
allowed servers. Also fixes UnboundLocalError on `is_restricted_virtual_key`
when `team_id` query param was provided to GET /v1/mcp/server.

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

* Fix cross-team MCP server info disclosure and restricted key bypass

The GET /v1/mcp/server endpoint allowed any authenticated user to pass
an arbitrary team_id and enumerate another team's MCP server config.
Restricted virtual keys could also use the team_id param to bypass
their access limitations. Add team membership check for non-admins
and block restricted keys from using the team_id filter.

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

* Fix mcp_tool_permissions JSON string deserialization in _resolve_team_allowed_mcp_servers

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

* [Feature] UI - MCP Servers: Add per-server health recheck

Allow users to recheck health for individual MCP servers by clicking
the health status badge. On hover the badge text changes to "Recheck"
with a refresh icon, and the check runs only for that server.

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

* Fix Anthropic docs link for beta endpoint

Update the Anthropic /v1/messages beta endpoint docstring to point to
its current pass-through documentation.

This keeps the change scoped to the incorrect URL and avoids changing
unverified wording in the surrounding comment.

---------

Co-authored-by: netbrah <162479981+netbrah@users.noreply.github.com>
Co-authored-by: Yong woo Song <ywsong.dev@kakao.com>
Co-authored-by: yuneng-jiang <yuneng.jiang@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Krish Dholakia <krrishdholakia@gmail.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Ishaan Jaff <ishaanjaffer0324@gmail.com>
Co-authored-by: Sameer Kankute <sameer@berri.ai>
Co-authored-by: Ishaan Jaff <ishaan-jaff@users.noreply.github.com>
Co-authored-by: Joe Reyna <joseph.reyna@gmail.com>
2026-03-11 20:17:41 +05:30
Sameer KankuteandGitHub 43217c8a4b Merge branch 'main' into litellm_oss_staging_03_10_2026 2026-03-11 18:32:17 +05:30
Sameer KankuteandGitHub b9a311743f Merge pull request #23104 from netbrah/fix/anthropic-deduplicate-tool-results
fix(anthropic): deduplicate tool_result messages by tool_call_id
2026-03-11 13:04:59 +05:30
Chesars 2315d4b73c fix: resolve merge conflicts with staging branch
Keep unified _FINISH_REASON_MAP dict approach, discard upstream's
inconsistent _VALID_OPENAI_FINISH_REASONS frozenset that mapped to
values not in the OpenAIChatCompletionFinishReason Literal.
2026-03-10 17:27:57 -03:00
xykongandGitHub 810de556bd fix(streaming): map unknown finish_reason values to finish_reason_unspecified to prevent ValidationError in stream_chunk_builder (#22673)
* fix(streaming): map unknown finish_reason values to finish_reason_unspecified

Some LLM providers return non-standard finish_reason values that are not
in the OpenAIChatCompletionFinishReason Literal (e.g. ZhipuAI/GLM returns
'network_error' when a streaming error occurs mid-response).

Previously map_finish_reason() fell through with return finish_reason,
passing the unknown value directly to Choices.__init__() which calls
Pydantic validation. This caused a ValidationError that was caught by
stream_chunk_builder() and re-raised as the misleading:
  litellm.APIError: Error building chunks for logging/streaming usage calculation

Fix: after all known provider-specific mappings, check if the value is in
the valid set (stop, length, tool_calls, content_filter, function_call,
guardrail_intervened, eos, finish_reason_unspecified, malformed_function_call).
Any value not in this set is mapped to 'finish_reason_unspecified' instead
of being returned as-is.

This is consistent with how other unknown stop reasons (e.g. Vertex AI's
FINISH_REASON_UNSPECIFIED) are already handled.

* refactor: use get_args(OpenAIChatCompletionFinishReason) for valid set

Per code review feedback: replace the hardcoded _valid_finish_reasons set
with a module-level frozenset derived dynamically from the source-of-truth
Literal type via typing.get_args(). This ensures the valid-reason check
stays in sync automatically when new finish reasons are added to the Literal,
and avoids recreating the set on every streaming chunk call.

* test(map_finish_reason): add unit tests and warning log for unknown finish reasons

- Add TestMapFinishReason class in test_core_helpers.py covering:
  - All known OpenAI-native values pass through unchanged (parametrized)
  - Provider-specific mappings: Anthropic, Cohere, Vertex AI
  - Unknown/provider-specific values map to 'finish_reason_unspecified'
  - Regression test for ZhipuAI/GLM-5 'network_error' case
- Add verbose_logger.warning() in map_finish_reason() when an unknown
  finish_reason is encountered, so operators can track which providers
  return non-standard values
2026-03-10 21:25:24 +05:30
Harshit28j 558523fd75 fix: req changes by greptile 2026-03-10 18:33:17 +05:30
Harshit28j 8c3d6db482 fix: claude code req traces on langfuse 2026-03-10 18:21:42 +05:30
netbrahandPalanisamy, Dinesh 5d1106f018 fix(anthropic): deduplicate tool_result messages by tool_call_id
Anthropic requires exactly one tool_result per tool_use. When
conversation history (e.g. from session resume/checkpoint restore)
contains duplicate tool result messages with the same tool_call_id,
the API rejects with: 'each tool_use must have a single result.
Found multiple tool_result blocks with id: <id>'.

This is already handled for Bedrock via _deduplicate_bedrock_tool_content()
but was missing from the Anthropic direct and Vertex AI partner paths,
which share sanitize_messages_for_tool_calling().

Fix: Add Case D to sanitize_messages_for_tool_calling() — after the
existing orphan detection passes, scan for duplicate tool_call_ids
and keep only the last occurrence (most complete result).

Added 3 unit tests: dedup with duplicates, no-op with unique IDs,
and behavior when modify_params=False.

Related issues: #11804, #11029, #6836, #1782, #151
2026-03-08 10:02:45 -04:00
Sameer Kankute d8f139fe4d feat(openai): add 272K tier pricing for GPT-5.4/5.4-pro
Prompts >272K input tokens priced at 2x input, 1.5x output for full session
(standard, batch, flex). Applies to models with 1.05M context window (gpt-5.4,
gpt-5.4-pro).

- Add input/output_cost_per_token_above_272k_tokens to model_prices
- Add above_272k fields to ModelInfoBase and get_model_info extraction
- Add test_generic_cost_per_token_gpt54_above_272k_tokens

Made-with: Cursor
2026-03-06 22:26:14 +05:30
giulio-leone fb8bd60c7d fix(streaming): prevent Vertex AI Claude content truncation when finish_reason races content 2026-03-04 22:44:48 +01:00
Sameer Kankute 851be58775 Add day 0 support of gemini-3.1-flash-lite-preview 2026-03-03 15:07:47 +05:30
Chesars ec16bd3509 merge: resolve conflict with upstream/main in presidio.py
Take upstream's refactored PII handling with _unmask_pii_text and
_process_response_for_pii helpers. Add missing StreamingChoices import.
2026-03-02 17:40:22 -03:00
Chesars 5495003e60 fix: add missing Dict/Optional imports in ChatGPT streaming_utils
Fixes NameError at runtime when ChatGPTToolCallNormalizer is
instantiated. The imports were missed when type hints were changed
from Python 3.10+ syntax (dict[], str | None) to typing module
syntax (Dict[], Optional[str]).
2026-03-02 17:19:40 -03:00
98974771fd fix: add sync streaming fallback + fix 429 for all streaming paths (#22375)
* fix: add sync streaming mid-stream fallback + fix 429 for all streaming paths

Some LiteLLM providers (Vertex AI, Bedrock, Predibase, Codestral) use a
deferred HTTP pattern where the streaming HTTP request is made lazily on
the first iteration, not during completion()/acompletion(). This means
errors surface during __next__/__anext__, outside the Router's
retry/fallback machinery.

Two gaps existed:
1. __anext__ had a blanket 4xx filter (PR #18698) that blocked 429 from
   MidStreamFallbackError — fixed here by exempting 429.
2. __next__ had NO MidStreamFallbackError support at all, and the Router
   had no sync streaming fallback wrapper — both added here.

Changes:
- streaming_handler.py: Extract shared _handle_stream_fallback_error()
  used by both __next__ and __anext__. Maps exceptions, filters
  non-retriable 4xx (excluding 429), wraps everything else in
  MidStreamFallbackError.
- router.py: Add _completion_streaming_iterator() (sync mirror of
  _acompletion_streaming_iterator). Modify _completion() to wrap
  streaming responses. Add is_pre_first_chunk check to both async
  and sync iterators to skip continuation prompt on pre-call errors.

Fixes #22296
Relates to #20870, #8648, #6532

* fix: no-op assertion in sync streaming fallback test

The assertion `... is None or True` always evaluated to True,
meaning it never actually verified anything. Replace with a
proper check that messages match the original (no continuation
prompt on pre-first-chunk errors).

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 15:55:05 -08:00
Chesars 8a85a2cf82 Merge branch 'litellm_oss_staging_02_27_2026' of https://github.com/BerriAI/litellm into litellm_oss_staging_02_27_2026 2026-02-28 09:54:56 -03:00
Julio Quinteros ProandClaude Opus 4.6 2ac5365e06 fix: update stale docstring to match guardrail voicing behavior
Addresses Greptile review feedback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 23:04:43 -03:00
Julio Quinteros ProandClaude Opus 4.6 9a48c8e36a fix(test): update realtime guardrail test assertions for voice violation behavior
Tests were asserting no response.create/conversation.item.create sent to
backend when guardrail blocks, but the implementation intentionally sends
these to have the LLM voice the guardrail violation message to the user.

Updated assertions to verify the correct guardrail flow:
- response.cancel is sent to stop any in-progress response
- conversation.item.create with violation message is injected
- response.create is sent to voice the violation
- original blocked content is NOT forwarded

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 22:53:09 -03:00
Cesar GarciaandGitHub acf2fd9828 Merge branch 'main' into fix/openrouter-stream-usage-no-stream-options 2026-02-27 17:41:13 -03:00
Sameer KankuteandGitHub 39e0fa9ea9 Merge pull request #22223 from emerzon/feat/vertex-gemini-3-1-flash-image-preview-pricing
feat(vertex): add gemini-3.1-flash-image-preview to model DB
2026-02-27 18:10:04 +05:30
Ishaan JaffandGitHub 48b9ecacad fix(realtime): fix guardrails not firing for Gemini/Vertex AI and provider_config realtime WebSocket sessions (#22168)
* fix(gemini): enable inputAudioTranscription and handle transcription events for realtime guardrails

Gemini sends inputTranscription/outputTranscription inside serverContent separately from modelTurn/turnComplete. This adds handling to convert them into OpenAI-compatible events so the guardrail pipeline can inspect voice input, and enables inputAudioTranscription in the session setup config.

Made-with: Cursor

* fix(vertex_ai): enable inputAudioTranscription in realtime session config

Add inputAudioTranscription to the Vertex AI realtime setup so the backend returns transcripts of user speech, allowing guardrails to inspect voice input.

Made-with: Cursor

* fix(realtime): pass user_api_key_dict and guardrail metadata through async_realtime handler

The base LLM HTTP handler's async_realtime method was not accepting or forwarding user_api_key_dict and litellm_metadata to RealTimeStreaming. This meant guardrails configured with default_on=false were silently skipped for all provider_config-based realtime connections (Gemini, Vertex AI, etc). Also fixes wss:// connections when SSL_VERIFY=False by overriding ssl=False for secure WebSocket URLs.

Made-with: Cursor

* fix(realtime): forward guardrail metadata for generic provider_config and vertex_ai paths

The _arealtime function was not passing user_api_key_dict or litellm_metadata to base_llm_http_handler.async_realtime() for the generic provider_config path and the vertex_ai-specific path. This broke guardrail resolution since RealTimeStreaming.request_data was empty, causing should_run_guardrail to return False.

Made-with: Cursor

* fix(realtime): voice guardrail responses and block duplicate response.create on text input

When a guardrail blocks voice input, send a conversation.item.create + response.create to the backend so the LLM voices the guardrail message as audio instead of only returning text. Also adds pending_guardrail_message tracking to suppress the automatic response.create the client sends after a blocked text message, and broadens _has_audio_transcription_guardrails to match pre_call/post_call modes.

Made-with: Cursor

* test(realtime): update guardrail tests for broadened audio transcription check and add integration tests

Update existing tests to reflect that pre_call guardrails now correctly trigger the audio/VAD session.update injection. Add integration test file for live OpenAI realtime guardrail testing.

Made-with: Cursor

* fix(realtime): instruct LLM to say exact guardrail message verbatim

The previous prompt gave the LLM creative freedom to paraphrase the guardrail violation message. Now it instructs the LLM to repeat the exact configured message word for word.

Made-with: Cursor

* fix(realtime): preserve wss ssl semantics and move live guardrail test

Keep TLS enabled for wss realtime sessions while honoring SSL_VERIFY=False via a no-verify SSLContext, move the OpenAI live guardrail test into llm_translation, and dedupe duplicated guardrail-detection helpers to prevent drift.

Made-with: Cursor
2026-02-26 17:06:07 -08:00
Emerson Gomes 702d5e88b8 fix(cost): use token usage for gemini/vertex image generation when available
- compute image_generation cost from usage token metadata for vertex/gemini\n- map ImageUsage to Usage and reuse generic_cost_per_token\n- fallback to output_cost_per_image when usage metadata missing\n- add tests for token-based path and fallback path
2026-02-26 14:57:11 -06:00
Emerson Gomes f24a41898b feat(vertex): add gemini-3.1-flash-image-preview model DB support
- add gemini-3.1-flash-image-preview + vertex_ai alias entries\n- set pricing to Gemini 3.1 Flash Image Preview rates\n- mirror updates in packaged backup model map\n- update llm cost calc regression test to cover new model
2026-02-26 14:41:59 -06:00
Ishaan JaffandGitHub cbdaaaeba4 [Feat] Add control for setting upperbound on chunk processing time (#22209)
* add LITELLM_MAX_STREAMING_DURATION_SECONDS

* add add LITELLM_MAX_STREAMING_DURATION_SECONDS

* fix: address Greptile review - rename constant, add sync check, add tests

- Rename MAX_STREAMING_CHUNK_DURATION_S → MAX_STREAMING_DURATION_S (misleading "CHUNK")
- Add _check_max_streaming_duration to SyncResponsesAPIStreamingIterator.__next__
- Add 8 unit tests covering both CustomStreamWrapper and ResponsesAPI paths
- Fix pre-existing pyright errors in streaming_handler.py

Made-with: Cursor

* add add LITELLM_MAX_STREAMING_DURATION_SECONDS
2026-02-26 11:39:09 -08:00
Ishaan JaffGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
965ca117bc feat(realtime guardrails): end_session_after_n_fails + Endpoint Settings wizard step (#22165)
* feat(realtime guardrails): end_session_after_n_fails + Endpoint Settings wizard step

Adds per-session violation thresholds and an optional endpoint-settings step
to the guardrail wizard for /v1/realtime.

Backend:
- Add end_session_after_n_fails, on_violation, realtime_violation_message fields
  to BaseLitellmParams (no DB migration — stored in existing JSON column)
- Store same fields on CustomGuardrail instance attrs
- Pass through in litellm_content_filter initializer
- Track _violation_count per RealTimeStreaming session; close backend_ws when
  on_violation=end_session OR violation count >= end_session_after_n_fails
- Use realtime_violation_message as the spoken text (falls back to guardrail
  error string if not configured)

UI (add_guardrail_form.tsx):
- Rename "Default Categories" step to "Topics"
- Add step 5 "Endpoint Settings (Optional)" for content filter guardrails
- Call type dropdown shows /v1/realtime
- Settings are in a collapsed accordion (closed by default)
- "End session after X violations" + on_violation radio + spoken message field

Tests: 2 new tests in test_realtime_streaming.py
- test_end_session_after_n_fails_closes_connection
- test_on_violation_end_session_closes_on_first_fail

* fix(test): move inline imports to module level in realtime streaming tests

* Update ui/litellm-dashboard/src/components/guardrails/add_guardrail_form.tsx

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

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-02-25 23:49:03 -08:00
Ishaan JaffandGitHub 819581f6bf fix(realtime): guardrails with pre_call/post_call mode now work on realtime WebSocket (#22161)
* fix(realtime): guardrails with pre_call/post_call mode now work on realtime WebSocket; return error directly to consumer

* fix(realtime guardrails): address code review feedback

- Restore session.update injection for audio/VAD path, but only when
  realtime_input_transcription guardrails are configured (not pre_call).
  Forward session.created to the client first so no error arrives before
  the client sees the session.
- Change _swallow_next_response_create bool to int counter so consecutive
  blocked items are handled correctly.
- Extract _build_litellm_metadata() helper to eliminate duplicated
  metadata-building logic across OpenAI/Azure/XAI provider branches.
- Plumb litellm_metadata and user_api_key_dict to Azure and XAI handlers
  so guardrails work for those providers too.
- Add tests for session.update injection, no-inject for pre_call-only,
  and consecutive-block counter.

* simplify: remove response.create swallowing after guardrail block

When an item is blocked, the error event is already sent to the client.
The subsequent response.create from the client is fine to forward through —
the LLM may respond to previous context which is acceptable behavior.
Removing the swallow counter eliminates unnecessary state tracking.
2026-02-25 23:43:13 -08:00
Chesars a4fc73f892 fix(completion): unify finish_reason mapping to OpenAI-compatible values
Replace if/elif chain in map_finish_reason() with _FINISH_REASON_MAP dict
covering all known provider values. Unknown values now default to "stop"
with a warning log. Fix Gemini FINISH_REASON_UNSPECIFIED and
MALFORMED_FUNCTION_CALL returning non-OpenAI values. Add missing Gemini
values (TOO_MANY_TOOL_CALLS, MALFORMED_RESPONSE). Clean
OpenAIChatCompletionFinishReason type and OPENAI_FINISH_REASONS constant.

Fixes #21744, #21041, #16651, #19744, #21348, #22003
2026-02-26 00:12:39 -03:00
adba088df2 Realtime API: spend log storage, playground UI, tools logging, and guardrail support (#22105)
Backend - Spend Log Storage for Realtime Calls:
- Collect user voice transcripts and text input during WebSocket sessions
- Store collected messages in spend logs when store_prompts_in_spend_logs enabled
- Capture tool definitions from session.update and tool calls from response.done
- Enrich proxy_server_request with tools and response with tool_calls for UI

Backend - WebSocket Auth:
- Support browser-based auth via Sec-WebSocket-Protocol subprotocol
- Echo back subprotocol on WebSocket accept

UI - Realtime Playground:
- New RealtimePlayground component with WebSocket voice+text chat
- Mic recording (PCM16 24kHz), server VAD, audio playback, text input
- Handle binary WebSocket frames (Blob/ArrayBuffer decoding)
- Add /v1/realtime endpoint option to playground endpoint selector

UI - Tools Section for Realtime Logs:
- Extract tool calls from realtime response format (response.tool_calls
  and response.results[].response.output[].type=function_call)

Tests:
- 15 new backend tests for realtime streaming and spend log storage
- 4 new UI tests for realtime tool call extraction

Fixes pre-existing build errors:
- ToolPolicies.tsx: duplicate import, antd styles type
- create_key_button.tsx: missing message import

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Ishaan Jaff <ishaan-jaff@users.noreply.github.com>
2026-02-25 14:55:27 -08:00
Ishaan JaffandGitHub c79d94fd16 feat(realtime): guardrail hook for voice transcription (#21976)
* feat(realtime): add guardrail hook for voice transcription in Realtime API

Adds a new `realtime_input_transcription` guardrail event hook that fires
after Whisper transcription completes, before the LLM generates a response.

When a guardrail blocks, a synthetic warning is sent to the client and
`response.create` is never forwarded — the LLM never responds.

Also rewrites `create_response: true` → `false` in client `session.update`
so the proxy controls when responses are triggered.

* feat(realtime): speak guardrail block message as audio via TTS

Instead of sending synthetic text events when a guardrail blocks,
send response.create with forced instructions so OpenAI's TTS speaks
the warning message — user hears the block instead of just seeing text.

* fix(realtime): speak exact content filter error message via TTS

Extract the human-readable error string from HTTPException.detail
so the spoken warning says e.g. "Content blocked: keyword 'system update'
detected" instead of the raw str(e) repr.

* fix(realtime): reliably enforce create_response=false for guardrails

- Proxy now injects session.update with create_response=false immediately
  on session.created (when guardrails are active), instead of rewriting
  the client's session.update — works regardless of what the client sends
- Add response.cancel before the warning response.create to kill any
  in-flight LLM response that snuck through before the guardrail fired

* refactor(realtime): call apply_guardrail directly, remove dedicated hook method

The async_realtime_input_transcription_hook in CustomGuardrail and
ContentFilterGuardrail was just a thin wrapper that called apply_guardrail —
the same interface used by /chat and /messages. Remove the wrapper and call
apply_guardrail directly from run_realtime_guardrails, keeping the pattern
consistent across all endpoints.

* docs: add Realtime API guardrails tutorial and flow diagram

* fix: address Greptile review comments

- Forward user_api_key_dict through realtime_api/main.py (_arealtime) so
  it actually reaches RealTimeStreaming instead of always being None
- Run guardrail interception in provider_config path too (e.g. Gemini),
  not only the OpenAI direct path
- Narrow exception catch to HTTPException/ValueError only; re-raise
  unexpected errors so programming bugs surface in logs rather than
  silently appearing as guardrail blocks
- Update tests: mock apply_guardrail directly (hook method was removed),
  replace session.update client-rewrite test with session.created
  injection test matching the new server-side approach

* fix: address latest Greptile review comments

- Remove fastapi import from SDK-layer file; check for status_code/detail
  attrs instead to identify guardrail-block exceptions vs programming errors
- Add store_message() before continue in transcription interception so
  transcription events are logged in the non-provider_config path
- Inject create_response=false on session.created in provider_config path
  (Gemini etc.) to match the OpenAI path — prevents LLM auto-responding
  before guardrail runs on VAD-detected turns
2026-02-23 21:04:40 -08:00
LeeJuOhandGitHub 50f36d9ca6 fix(budget): fix timezone config lookup and replace hardcoded timezone map with ZoneInfo (#21754)
* fix(budget): fix timezone config lookup and replace hardcoded timezone map with ZoneInfo

* fix(budget): update stale docstring on get_budget_reset_time
2026-02-21 19:35:06 -08:00
Ishaan Jaffer 26ea29afd3 test_get_usage_as_dict 2026-02-21 15:39:06 -08:00
Krish DholakiaandGitHub 9fc6fd647c Agent Builder - support new experimental agent builder, to ensure agents pass compliance checks (#21817)
* fix: feat: add litellm_system_prompt support

* feat: support new 'litellm_agent' model provider

* feat: ui/ - new agent builder ui

* fix(anthropic/chat/transformation.py): normalize max_tokens if decimal

* feat(agentbuilderview.tsx): run compliance datasets against litellm agent
2026-02-21 15:32:47 -08:00
Ishaan JaffandGitHub 9f459c5c57 fix(logging): preserve pass-through endpoint response_cost (#21844)
* fix(logging): preserve pass-through endpoint response_cost in async_success_handler

Two places in the logging pipeline were overwriting response_cost that
pass-through handlers (Gemini/Vertex) had already calculated:

1. _process_hidden_params_and_response_cost fell through to
   _response_cost_calculator which returns None for pass-through calls
2. async_success_handler pass-through branch unconditionally set
   response_cost = None (introduced in PR #19887)

Now both places check if response_cost is already set before overwriting.

* test: add regression test for pass-through endpoint response_cost preservation
2026-02-21 15:09:45 -08:00
Ryan Crabbe 5bcaeabfd8 Merge origin/main into litellm_fix_streaming_connection_pool_leak
Resolve conflict in test_proxy_server.py: keep both async_data_generator
cleanup tests and store_model_in_db DB config override tests.
2026-02-21 12:44:50 -08:00
0fe3145e83 Fix/presidio controls (#21798)
* check should_run_guardrail in sync logging hook path

* Add tests for CustomGuardrail logging behavior

Added tests to ensure CustomGuardrail logging behavior based on the guardrail execution state.

---------

Co-authored-by: Miguel Armenta <ma826r@att.com>
2026-02-21 12:39:17 -08:00
ryan-crabbeandGitHub 469951466e Merge pull request #20541 from ryan-crabbe/perf/cost-calculator-optimizations
Perf/cost calculator optimizations
2026-02-21 12:18:38 -08:00