Commit graph

181 commits

Author SHA1 Message Date
mateo-berri
710ef81a80 fix(usage): keep responses usage SDK-parseable and complete streamed reasoning splits
An unknown reasoning split now falls back to reasoning_tokens=0 in the
chat-to-responses usage translation, since the OpenAI SDK requires
output_tokens_details with an int reasoning_tokens, and the streaming
chunk builder caps the tokenized reasoning estimate at completion_tokens
and fills text_tokens with the remainder
2026-08-19 14:57:19 -07:00
mateo-berri
46a4eda19e Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_fix_bedrock_adaptive_thinking_token_accounting
# Conflicts:
#	litellm/llms/bedrock/chat/invoke_handler.py
#	litellm/responses/litellm_completion_transformation/transformation.py
#	tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py
#	tests/test_litellm/responses/litellm_completion_transformation/test_reasoning_content_transformation.py
2026-08-19 14:10:53 -07:00
mateo-berri
c435c25da2 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_pr35110_itpm_otpm
# Conflicts:
#	type-discipline-budget.json
2026-08-18 16:11:12 -07:00
mateo-berri
39c5ccaed4 test(responses): inject a mocked http client instead of patching AsyncHTTPHandler.post 2026-08-18 13:45:48 -07:00
mateo-berri
61625723a7 fix(responses): strip the responses/ routing prefix on the Responses API path
openai/responses/<model> deployments reached OpenAI as the literal model id
responses/<model> on /v1/responses and on /v1/messages (which rides the
Responses API for the openai provider) and 400ed with model_not_found, while
/v1/chat/completions already stripped the prefix. Strip a leading responses/
right after provider resolution so every Responses API entrypoint (HTTP,
websocket, compaction, the /v1/messages adapter) sends the real model id
2026-08-18 13:28:22 -07:00
mateo-berri
842bb7e917 Merge branch 'litellm_internal_staging' into feature/bedrock-mantle-quota-project-itr1 2026-08-18 13:14:14 -07:00
Mateo Wang
3b6e56716a
Merge pull request #36978 from Scott-Wilson-ZocDoc/fix/mcp-guardrail-usage-monitor
fix(guardrails): record MCP tool guardrail evaluations and blocks in …
2026-08-17 13:18:03 -07:00
Shivi Jain
8a44c14928 Merge upstream/litellm_internal_staging and fix batch quota review comments
Resolves conflicts from the upstream merge and addresses the Veria-AI
review comment on this PR: batch rows could bypass a project's
per-model ITPM/OTPM quota when the batch's file-bound/routing model
had no quota configured. Charges each row's own model against its own
project quota instead of only the routing model's, and fixes rate
limit error messages to attribute the correct model via a new
descriptor_value field on RateLimitStatus/AtomicCounterMeta. Also
re-syncs the ruff-strict, type-discipline, and basedpyright budgets
against the correct (non-stale) merge base.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-16 15:47:46 +05:30
yucheng-berri
f9f5c03884
fix(mcp): drop caller host and configured upstream headers from logged metadata (#36901)
* fix(mcp): drop caller host and configured upstream headers from logged metadata

The synthetic request that carries MCP client headers into
add_litellm_data_to_request forwarded the caller's Host header, and
Request.url is built from it, so a caller chose the proxy_server_request
url and the metadata endpoint that every logging callback records.

_upstream_credential_headers also only knew the configured client side
auth header and the x-mcp- prefix family, so a header name declared in
mcp_servers.<name>.extra_headers reached logging metadata in cleartext.
Those names are admin chosen, so no prefix rule can recognize them; read
them off the server registry instead. The header is still forwarded
upstream, which is what extra_headers is for. authorization is left out
because clean_headers already strips it and claiming it here would move
authenticated_with_header on the oauth passthrough config.

The Responses bridge tests stub the server manager, so their fakes gain
the registry accessor the sanitizer now reads.

* fix(mcp): drop caller host from the sanitized header mapping too

The synthetic request stopped forwarding host, but the parallel sanitizer
did not, so a forged hostname still reached the guardrail payload and the
list_tools spend row. Drop it there as well.

Exempt the configured identity headers from the upstream credential set.
get_user_from_headers resolves end user attribution off the same request
this module reconstructs, and it only fills end_user_id when auth left it
unset, so claiming user_header_name or a user_header_mappings name would
lose attribution on the MCP paths that authenticate upstream.

Drop the isinstance guard on extra_headers entries: the field is typed
list[str], so the check is dead and basedpyright scores it.

* fix(mcp): accept a bare user_header_mappings entry when exempting identity headers

get_internal_user_header_from_mapping and get_customer_user_header_from_mapping
both normalize a single mapping to a one element list, and config_settings.md
documents the key as a dict. Iterating the bare form yields its keys instead,
so the exemption silently matched nothing and an identity header also named in
an MCP server's extra_headers was dropped after all.
2026-08-14 17:21:07 -07:00
Scott Wilson
9858d021ee fix(guardrails): record MCP tool guardrail evaluations and blocks in usage monitor
MCP tool calls run their guardrails against a throwaway LLM-shaped dict
built by `ProxyLogging._convert_mcp_to_llm_format`, not against the dict
the tool call is logged from. `@log_guardrail_information` therefore
appended `standard_logging_guardrail_information` to that throwaway
dict's metadata bucket, where `get_standard_logging_object_payload`
never saw it, so the Guardrails Monitor reported zero evaluations and
zero blocks for all MCP traffic.

Thread the request's `litellm_logging_obj` into `pre_call_tool_check`
and `_create_during_hook_task` and bridge the guardrail records onto it:

- Seed `data["litellm_logging_obj"]`, which unified guardrails read and
  pass into `apply_guardrail`.
- Call `_sync_guardrail_info_to_logging_obj` in a `finally`, which is
  what native guardrails need and what makes the block path work: a
  blocked call raises straight out of `pre_call_tool_check`, so the
  record has to be attached before the exception leaves the frame.

Only the guardrail evaluation records are copied. The synthetic
request's messages and tool arguments are deliberately left behind --
they can carry end-user data and nothing in the monitor needs them.

In `call_mcp_tool`, flush the failure handlers before
`post_call_failure_hook` so the `status="failure"` standard logging
object exists when `_ProxyDBLogger.async_post_call_failure_hook` writes
the spend-log row the monitor's "Total Blocked" counts. Both handlers
gate on `should_run_logging("sync_failure")` / `("async_failure")` and
then mark it, so the `@client` wrapper's own post-raise logging is a
no-op and nothing is double-counted -- the same pattern
`_fire_mcp_tool_call_logging` already uses for `isError=True`.

Threaded through every MCP tool entry point: the managed-server path,
the local-OpenAPI registry path, the legacy registry fallback, and the
Responses API's `_execute_tool_calls`.
2026-08-14 17:52:36 -04:00
Shivi Jain
312d12fe0c fix(proxy): enforce project ITPM/OTPM quota on every Responses WebSocket frame
The connection-level pre-call hook only ran once per WebSocket
connection, so a project caller could send unlimited high-token
response.create frames after a single minimal reservation. Adds
enforce_project_io_token_quota_for_frame to the v3 rate limiter and
wires it into both the native and managed WebSocket handlers via a
duck-typed litellm.callbacks lookup, so the SDK layer stays free of
proxy imports. A rejected frame gets an error event; the connection
stays open for the client to retry.

Also fixes the RET504 and BLE001 strict-lint-budget violations the
litellm_internal_staging merge introduced in
parallel_request_limiter_v3.py, which were failing the lint check.
2026-08-14 21:39:34 +05:30
devin-ai-integration[bot]
59eeae374c
fix(mcp): expose client HTTP headers to logging callbacks and hooks (#36724)
* fix(mcp): expose client HTTP headers to logging callbacks and hooks

MCP protocol tool calls built a synthetic Request with only content-type, so metadata.headers reaching logging callbacks and guardrails was empty while /mcp-rest/tools/call exposed the full set. Rebuild the synthetic request from the connection's raw headers (shared with the sampling path), and pass sanitized headers to the pre-call hook, the MCP to LLM guardrail bridge and the Responses API MCP bridge. Credential headers stay masked and proxy key headers stripped.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(mcp): strip custom proxy key and upstream MCP credential headers from logging copies

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* refactor(mcp): make client side auth header name accessor public

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(mcp): strip custom proxy key and client redaction opt-out from mcp headers

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(mcp): drop custom proxy key header in the synthetic request builder

Strips general_settings.litellm_key_header_name in build_synthetic_mcp_request so every caller, including sampling, is covered, and reverts passing general_settings into add_litellm_data_to_request on the tool call path since that also switches on enforced_params.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: shivam <shivam@berri.ai>
2026-08-13 20:07:16 -07:00
Emerson Gomes
4ea5749642
feat(azure-ai): add Grok 4.3 model metadata (#27932)
* Add Azure AI Grok 4.3 metadata

* Address Azure Grok 4.3 test feedback

* Drop empty tool choice in responses bridge

* style(azure-ai): update Grok metadata tests
2026-08-13 17:25:17 -07:00
yuneng-jiang
16ce5031f0
Merge branch 'litellm_internal_staging' into litellm_/remove-no-guard-mirror-tests 2026-08-12 10:38:24 -07:00
Mateo Wang
cfcd0cda8a fix(responses): leave namespace unset on non-namespace tool calls 2026-08-12 00:28:15 -07:00
Mateo Wang
a64a83bf36 fix(responses): keep custom_tool_call echoes on their advertised short name 2026-08-12 00:19:08 -07:00
Mateo Wang
ca14e52b08 fix(responses): requalify echoed namespace tool calls with their flattened name 2026-08-12 00:01:34 -07:00
Mateo Wang
397fcd0e6b fix(responses): serialize flattened namespace tools and keep tool results adjacent to tool_calls 2026-08-11 23:41:44 -07:00
Mateo Wang
ae2a1f4aba Merge branch 'litellm_internal_staging' into litellm_fix_codex_responses_namespace_tools 2026-08-11 23:16:34 -07:00
mateo-berri
6bce073520 fix(responses): keep chat-shaped usage extras from colliding in the bridge
Gemini image usage carries prompt_tokens and friends as extra fields on
ResponseAPIUsage, which collided with the bridge's explicit kwargs and
raised TypeError. Exclude keys the bridge already sets explicitly.
2026-08-11 18:34:27 -07:00
mateo-berri
52f9b4a6e1 fix(xai): keep Responses API usage schema while billing web search
Drop the transform overrides that swapped response.usage to the chat
shape, which broke the /v1/responses client contract. Provider extras
like server_side_tool_usage_details already survive validation via
ResponseAPIUsage extra fields, so the shared usage bridge now carries
them onto the bridged chat Usage generically. The web_search_call
output gate also reads dict output items, since items that fail SDK
validation stay plain dicts, and the chat path gains billing tests.
2026-08-11 17:16:43 -07:00
Yang Yang
749a8b0701 fix(xai): keep chat Usage through Responses completions bridge
xAI already converts Responses usage to chat Usage so web_search_calls survive
cost tracking. The chat completions bridge then re-ran the Responses usage
transform and crashed on missing input_tokens. Pass through already-chat Usage
and chat-shaped dumps instead
2026-08-08 16:49:09 -07:00
Yang Yang
3aea951e6c refactor(xai): keep Responses tool usage pass-through in llms/xai
Revert shared responses/utils.py extras forwarding. Attach
server_side_tool_usage_details on chat Usage inside XAIResponsesAPIConfig
so cost calc keeps web_search_calls without provider logic in shared utils.
2026-08-08 16:21:06 -07:00
Yang Yang
014d59f4c4 refactor(responses): pass through extra usage fields generically
Avoid hard-coding provider-specific usage keys in shared Responses
utilities; forward any non-standard usage attributes onto chat Usage
for provider cost tracking (e.g. server_side_tool_usage_details).
2026-08-08 16:20:37 -07:00
devin-ai-integration[bot]
f05d468769
fix(responses): forward allowed_openai_params through the chat completions bridge (#35885)
Resolves #35878

Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-07 19:57:26 -07:00
Daniel Cadenas
08d4a39f23
fix(responses): harden namespace tool mapping 2026-08-06 21:25:57 -03:00
Daniel Cadenas
bd1478e4ad
fix(responses): preserve Codex namespace tool calls 2026-08-06 20:53:05 -03:00
Devin AI
aadfa89ff6 Merge branch 'litellm_internal_staging' into litellm_fix_bedrock_adaptive_thinking_token_accounting
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-05 21:13:36 +00:00
Devin AI
af2246c5b8 fix(anthropic,bedrock): report provider thinking tokens instead of classifying them as text
Resolves LIT-5244

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-05 20:47:05 +00:00
mateo-berri
7288247682 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_fix_openai_cache_token_details_loss
# Conflicts:
#	litellm/litellm_core_utils/llm_cost_calc/utils.py
#	litellm/litellm_core_utils/streaming_chunk_builder_utils.py
#	litellm/litellm_core_utils/streaming_handler.py
#	tests/test_litellm/litellm_core_utils/test_streaming_chunk_builder_utils.py
2026-08-05 01:23:54 -07:00
mateo-berri
9eeff06263 Merge origin/litellm_internal_staging into litellm_lit4395_cursor_agent 2026-08-04 10:20:03 -07:00
Mateo Wang
f60e99c583
Merge pull request #34531 from BerriAI/litellm_forward_client_headers_responses_api
fix(responses): forward client headers to the provider on /v1/responses
2026-08-03 20:02:21 -07:00
Tin Chi Lo
b79b01e38a fix(proxy): translate custom tool grammar formats and tool_choice across API surfaces
Cursor's ApplyPatch is a grammar-constrained custom tool; the Responses
surface carries the grammar flat while chat completions wraps the same
fields in a grammar object, so the nested envelope from the previous
commit still 400d at OpenAI (tools[N].custom.format.grammar). Adds a
shared flat to nested format helper pair in prompt_templates/common_utils
used by the cursor messages arm and the chat-to-responses bridge, nests
flat Responses-style tool_choice objects on the cursor arm, flattens chat
custom tool_choice on the chat-to-responses bridge, and maps custom
tool_choice to function tool_choice on the responses-to-chat bridge to
match that bridge's custom-to-function tool downgrade
2026-08-01 11:26:09 -07:00
mateo-berri
43fad507de fix(responses): map all documented in-stream error codes to real HTTP statuses 2026-07-30 19:17:32 -07:00
Devin AI
c429a0e4a7 fix(cost_tracking): keep OpenAI prompt cache token details through usage reassembly 2026-07-27 18:36:26 +00:00
Yuneng Jiang
e4a0475263
test: remove four mirror test files that exercise none of their module
A second mutation batch scored the previously unmapped mirror files on
current staging. These four generate mutants for the module they are
named after, yet no test in the file executes any of them; their
test-context coverage lands on generic shared machinery or, for the
guardrail translation handler remainder, on no litellm line at all.
Eight sibling findings that do exercise a different real module are
kept for retargeting instead of removal.
2026-07-25 10:57:19 -07:00
mateo-berri
6ff88ba5e9 fix(responses): strip include_usage from stream_options instead of dropping the param 2026-07-24 16:46:49 -07:00
shivam
a376f72400 fix(responses): stop treating stream_options as a Responses API param
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-07-24 20:53:05 +00:00
milan
7716e47519 fix(responses): compare forwarded header names case-insensitively
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-07-24 20:16:25 +00:00
milan
fb9d30224b fix(responses): forward proxy client headers to the provider
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-07-24 19:04:22 +00:00
Krrish Dholakia
2f502a1bfc fix(cost_tracking): map cache_write_tokens on Responses API usage path
The Responses API (/v1/responses) usage transform rebuilt prompt token
details and dropped OpenAI's input_tokens_details.cache_write_tokens, so
gpt-5.6 cache-creation tokens were never logged or billed via that route.
Map it in the transform, and make PromptTokensDetailsWrapper keep
cache_write_tokens and cache_creation_tokens in sync on assignment.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-07-23 19:07:08 -07:00
Shivam Rawat
abf18f8760
Merge pull request #33422 from BerriAI/litellm_fix_responses_reasoning_items
fix(responses): preserve reasoning through prompt hooks
2026-07-22 19:42:09 -07:00
mateo-berri
354f3971a9 fix(bedrock_mantle): gate unsupported service_tier on drop_params for the Responses API 2026-07-20 19:49:42 -07:00
tin-berri
43e4af73f0
Merge pull request #33631 from BerriAI/litellm_lit4517_messages_mcp_gateway
feat(mcp): support MCP servers on the Anthropic /v1/messages API
2026-07-20 16:22:03 -07:00
devin-ai-integration[bot]
7891388975
feat(rust): 1:1 port of OpenAI Responses API WebSockets to litellm-rust (#33849)
* feat(rust): add OpenAI Responses WebSocket gateway

Co-Authored-By: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>

* test(rust): cover Responses WebSocket gateway behavior

Co-Authored-By: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>

* fix(rust): align Responses WebSocket parity

Co-Authored-By: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>

* feat(rust): expose Responses WebSockets through bridge

Co-Authored-By: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>

* fix(rust): reject non-openai responses deployments early

Co-Authored-By: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>

* fix(rust): align Responses WebSocket bridge semantics

Co-Authored-By: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>

* refactor(rust): move Responses instrumentation into core

Co-Authored-By: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>

* fix(rust): preserve Responses WebSocket callback dispatch

Co-Authored-By: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>

* build(deps): authorize vcrpy and locust licenses in liccheck

Co-Authored-By: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>
2026-07-19 01:55:35 +00:00
Tin Chi Lo
98bf25e8af Merge origin/litellm_internal_staging into litellm_mcp_aggregate_outcomes
Append-append conflict at the end of test_mcp_server.py between this branch's aggregate-outcome
tests and the mode-aware preemptive-401 tests from staging; both kept
2026-07-17 10:19:36 -07:00
Tin Chi Lo
ae952ce971 feat(mcp): support MCP servers on the Anthropic /v1/messages API
MCP tool calling worked on /v1/chat/completions and /v1/responses but not on
/v1/messages. Those are the only two surfaces with an MCP gateway entry point,
so a litellm_proxy MCP reference reached Anthropic verbatim inside tools and the
API rejected the request with "Input tag 'mcp' found using 'type' does not match
any of the expected tags". The playground never surfaced this because it dropped
the reference before sending, and disabled the MCP selector for the endpoint.

Add the third entry point in anthropic_messages_handler, ahead of the provider
branch so it covers the native path and both bridges from one place. The gateway
expands the reference against the caller's own credentials and access control,
which is the whole point of routing it through litellm rather than handing the
url to the provider.

/v1/messages needs Anthropic's own tool shape, so transform_mcp_tool_to_anthropic_tool
joins the OpenAI chat and Responses transforms alongside it. The tool loop speaks
tool_use and tool_result rather than OpenAI tool_calls, and reuses the existing
FakeAnthropicMessagesStreamIterator to re-stream the result, the same pattern the
websearch interception already uses on this route. Argument extraction moves into
the shared extractor: an Anthropic tool_use block carries its arguments under
`input`, and reading only `arguments` failed silently, executing the tool with
every argument dropped.

On the frontend the request builder declared selectedMCPTools and never read it,
so no tools key was ever sent. Wire it through a shared block builder and add the
endpoint to MCP_SUPPORTED_ENDPOINTS, which is what greys the selector out.

Resolves LIT-4517
Resolves LIT-4518
2026-07-16 18:35:58 -07:00
Krrish Dholakia
4db0bdf465 fix(responses): handle non-message-only prompt input
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-07-15 18:51:07 +00:00
Krrish Dholakia
4baee71bdd chore(responses): minimize regression test diff
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-07-15 18:41:02 +00:00
Krrish Dholakia
ebb0f7e4cf fix(responses): preserve reasoning through prompt hooks
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-07-15 18:40:32 +00:00