Commit graph

14665 commits

Author SHA1 Message Date
mateo-berri
c02c81452c fix(proxy): reassemble split SSE frames before restamping anthropic message_start 2026-08-31 13:16:48 -07:00
mateo-berri
59732f068b Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_gigachat_passthrough_25886 2026-08-31 13:16:41 -07:00
mateo-berri
ed5ee51dd2 fix(passthrough): map sync streaming errors, keep router streaming responses unwrapped, and resolve gigachat from api base
- sync llm_passthrough_route: read and close an error-status streaming
  response before mapping it, so upstream 4xx/5xx surface as the provider
  error instead of httpx.ResponseNotRead
- AsyncPassthroughStreamingResponse: expose aiter_bytes() and carry
  _hidden_params so the router attaches headers in place instead of
  wrapping the stream in HiddenParamsAsyncIteratorWrapper, which 500'd
  every streaming azure router-model passthrough request
- logging: swap the passthrough httpx result for the transformed
  ModelResponse/EmbeddingResponse when firing success callbacks
- get_llm_provider: resolve gigachat from its api base and drop the dead
  gigachat_models elif branch
- constants: register the gigachat api base in openai_compatible_endpoints
2026-08-31 13:16:40 -07:00
mateo-berri
97e2aa9e7f Merge origin/litellm_internal_staging into litellm_anthropic_stream_model_alias
Adapts streaming_model_restamp.py to the LIT001/LIT010 gates that landed
on staging since this branch was cut (Final annotations, Mapping in
annotations instead of dict).
2026-08-31 13:09:37 -07:00
mateo-berri
fe90c6f6fc fix(count_tokens): keep assistant turns on the provider counting API
Assistant list content was forwarded to /v1/responses/input_tokens as chat
`text` blocks, which the Responses API rejects (it accepts only output_text
and refusal inside an assistant turn). The 400 sent the whole request to the
local tokenizer, so any conversation with an assistant turn silently lost
provider-exact counting, including the image counting added in 73ab647b1c.

Assistant content now collapses to the plain string the Responses API counts
identically, and image parts are kept to user turns where they are legal.
2026-08-31 12:59:40 -07:00
devin-ai-integration[bot]
1249f84b10
fix(vertex_ai): graft default vertex path when api_base has a version-only path (#38986)
* fix(vertex_ai): graft default vertex path when api_base has a version-only path

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

* fix(vertex_ai): keep query and fragment placement when grafting vertex path

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

* fix(vertex_ai): merge alt=sse into existing query when streaming

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

---------

Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-31 12:56:34 -07:00
Cursor Agent
ae83444a3e
fix(openai): treat empty api_key as unset for WIF resolution 2026-08-31 19:55:29 +00:00
mateo-berri
e7dc0213bd fix(openai): treat empty api key values as unset for workload identity 2026-08-31 12:52:55 -07:00
Mateo Wang
0c21b30cb7
feat(spend_tracking): persist router metadata in spend logs for internal router models (#39001)
* feat(spend_tracking): persist router metadata in spend logs for internal router models

* test(spend_tracking): expect router_metadata key in exact-payload tests, type the routed-kwargs helper
2026-08-31 12:52:34 -07:00
Ashton Sidhu
9f9236e8d5
fix(guardrails): exclude images from HiddenLayer v1 scans (#29210)
* Don't scan images

* Fix failing tests

* Fix lint: typed image-part filter, restore monkeypatch-based tests

---------

Co-authored-by: Yucheng Zhu <yucheng@berri.ai>
2026-08-31 12:50:42 -07:00
mateo-berri
46e090d2f3 fix(anthropic_messages): bill partial spend when a queued pump error is never consumed
When the upstream errors while the client is still connected, the pump
forwards the exception through the relay queue so the proxy's failure
handling re-raises it. If the client disconnects before consuming that
queued exception, neither the failure hook nor billing ran and the spend
row was lost. The pump now waits for client detach and, if the exception
was never consumed, salvages partial spend like the post-disconnect
error path.

Also rewrites the bedrock disconnect logging test to the detached-pump
contract: billing fires after the upstream drain completes, not
synchronously at aclose().
2026-08-31 12:47:26 -07:00
mateo-berri
73ab647b1c fix(count_tokens): preserve image inputs when counting Responses API tokens
The chat-to-Responses reverse transform kept only text blocks, so an image
input was dropped before the count went to OpenAI. A 256x256 image request
counted 13 tokens instead of 268.
2026-08-31 12:43:17 -07:00
mateo-berri
ef72e7b37d fix(openai): require https for workload identity api_base targets 2026-08-31 12:32:00 -07:00
mateo-berri
6b7159323b fix(proxy): match OpenAI on empty input and skip budget reservation for token counting
/v1/responses/input_tokens returned 200 with a count for an empty
"input" ("" or []), while OpenAI returns a 400 missing_required_parameter.
The route also went through optimistic budget reservation, which is only
released by LLM success/failure callbacks that a token count never
reaches, so every call leaked a reservation until TTL expiry and could
429 real traffic. Both routes plus the /openai alias now join
/utils/token_counter in the reservation exemption set.
2026-08-31 12:25:45 -07:00
mateo-berri
b134dbfe73 test: exempt _resolved_provider in router_code_coverage gate 2026-08-31 12:19:51 -07:00
Mateo Wang
a73e770798
Merge pull request #38993 from BerriAI/litellm_fix_converse_duplicate_guardrailconfig
fix(bedrock): stop duplicating Converse config blocks inside inferenceConfig
2026-08-31 12:19:41 -07:00
mateo-berri
72adeda9ce fix(openai): scope workload identity to the openai provider and env-resolved base/key 2026-08-31 12:15:52 -07:00
mateo-berri
779b3010d4 fix(proxy): never run OAuth device flows when resolving model names
Resolving github_copilot/chatgpt names through get_llm_provider runs the
provider's OAuth device flow synchronously on the event loop. Adopt the
declared provider in PatternMatchRouter.get_pattern, which the auth
layer's zero-cost budget check walks on every request against wildcard
routers, and in /utils/supported_openai_params.
2026-08-31 12:06:35 -07:00
davida-ps
9f67a58198
fix(guardrails): configure Prompt Security file timeout policy (#38083)
* fix(guardrails): fail open on Prompt Security file timeouts

* fix(guardrails): configure Prompt Security timeout policy
2026-08-31 12:05:57 -07:00
mateo-berri
c7c382402a feat(proxy): add /v1/responses/input_tokens token counting endpoint 2026-08-31 12:04:44 -07:00
mateo-berri
ae945f4fa3 feat(openai): support workload identity federation (OIDC token exchange) 2026-08-31 11:54:04 -07:00
mateo-berri
cf1b431d58 fix(bedrock): stop duplicating Converse config blocks inside inferenceConfig 2026-08-31 11:50:45 -07:00
mateo-berri
6b2ada2a78 fix(bedrock): per-response realtime usage deltas, spend-log event filter, single transcript completed 2026-08-31 11:49:09 -07:00
milan
9125a5b7a0 fix(responses): json-encode object tool call arguments in the chat completions bridge
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-31 18:43:36 +00:00
mateo-berri
797848dd82 fix(cost): bill OCR annotation pages via annotation_cost_per_page 2026-08-31 11:18:59 -07:00
mateo-berri
11a7471902 refactor(proxy): resolve supported_openai_params aliases via Router.resolved_litellm_models 2026-08-31 11:08:31 -07:00
mateo-berri
0e78c5bff7 fix(anthropic_messages): dispatch deferred spend logging when the client disconnects mid-relay
When the pump finishes draining while the client is still connected,
billing is deferred to the proxy's post-response hook, which only fires
on a normally completed response. A client disconnect before the relay
consumed the queued tail tore the generator down past that hook, so the
request logged no spend at all. The relay teardown now dispatches the
stored deferred billing whenever it never reached the end-of-stream
sentinel.

Also drops the live pass_through_tests script: that CI job runs against
a fixed config with no Bedrock model or AWS credentials, so it could
only fail there. The scenario is covered by unit tests on the
relay/pump seam.
2026-08-31 10:17:27 -07:00
mateo-berri
8a6f47a6d4 merge: litellm_internal_staging into litellm_fix_nova_sonic_realtime_user_asr_usage 2026-08-31 10:17:12 -07:00
yucheng-berri
30f3228510
test(newrelic): cover static default_team_settings per-team routing (#38857)
* test(newrelic): cover static default_team_settings per-team routing

The dynamic POST /team/{team_id}/callback path for New Relic is tested, but
the static default_team_settings twin had no regression coverage. Add a test
that drives default_team_settings -> add_team_based_callbacks_from_config and
asserts the resolved trusted vars dispatch to BOTH the per-team metrics logger
(cost/usage) and the trace logger (LLM/agent spans), so a config-file customer
gets the same per-team routing as the API customer.

Also correct the /team/callback docstring: callback_name is a str validated
against the credential-capable callbacks, not a fixed langfuse/langsmith/gcs
Literal, and document the newrelic_api_key / newrelic_region vars.

* chore(ui): sync schema.d.ts with the /team/callback docstring

Regenerate the dashboard OpenAPI types for the add_team_callbacks description
change: callback_name is a validated str (not a langfuse/langsmith/gcs
Literal) and the newrelic_api_key / newrelic_region vars are documented.

* docs(newrelic): note LITELLM_OTEL_V2 prerequisite, trim test comments

Address review: team-scoped New Relic config is rejected with a 400 unless the
proxy runs with LITELLM_OTEL_V2=true, so document that in the /team/callback
endpoint and sync schema.d.ts. Drop the narrative setup comments in the new
test per the repo comment convention; the test name and docstring already say why.
2026-08-31 16:58:35 +00:00
mateo-berri
6e59ce1773 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_pr36008_head
# Conflicts:
#	basedpyright-code-budget.json
#	type-discipline-budget.json
2026-08-31 09:41:15 -07:00
devin-ai-integration[bot]
f079e4061b
fix(proxy): deliver budget alerts on webhook-only alerting and accept ALERTING_WEBHOOK_URL (#38441)
* fix(proxy): deliver budget alerts on webhook-only alerting and accept ALERTING_WEBHOOK_URL

ProxyLogging.budget_alerts forwarded to the alerting pipeline only when
'slack' was in general_settings.alerting, so alerting: ['webhook'] plus
WEBHOOK_URL silently never delivered a budget alert (the config
/health/services?service=webhook exists to test). Forward when 'webhook'
is present too; SlackAlerting.send_alert already fans out per channel.

Also accept a provider-neutral ALERTING_WEBHOOK_URL env fallback for the
Slack-format channel (any Slack-compatible receiver works), mark it as a
sensitive var, and de-brand the admin UI alerting copy.

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

* fix(ui): format settings.tsx with prettier

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

* chore(ui): regenerate schema.d.ts for updated alerting description

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

* ci: retrigger checks after ALERTING_WEBHOOK_URL docs merged

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

---------

Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-31 09:22:36 -07:00
nuernber
79fd2f4872 test(anthropic): cover ANTHROPIC_MESSAGES_MAX_DETACHED_STREAM_DRAINS=0 fallback to partial billing 2026-08-31 09:15:36 -07:00
nuernber
e1fece511a test(anthropic): fix PT012 lint violation in upstream-error regression test 2026-08-31 09:11:51 -07:00
nuernber
95a2586228 Merge remote-tracking branch 'origin/main' into litellm_bedrock_messages_disconnect_billing
# Conflicts:
#	basedpyright-code-budget.json
#	litellm/llms/anthropic/experimental_pass_through/messages/streaming_iterator.py
#	tests/test_litellm/llms/anthropic/experimental_pass_through/messages/test_streaming_iterator.py
#	type-discipline-budget.json
2026-08-31 08:58:37 -07:00
Emerson Gomes
f7b1cc1f41
fix(router): copy kwargs instead of popping target order
Lint required a specific exception on the empty-order-2 regression.
Provider calls now omit _target_order by constructing a new kwargs dict.
2026-08-31 10:35:10 -05:00
Srivatsa03
27aefade5f fix(cost): treat an equal-ended off-peak window as the whole day
A window whose start equals its end is the natural way to spell off-peak all
day, and the docstring's promise that a window may wrap past midnight invites
it. It took the non-wrap branch instead, where start <= now < end can never
hold, so it matched nothing. It parses cleanly, so it never reached the branch
that ignores malformed windows: no exception, no log, and the model billed at
standard rates around the clock while the config said otherwise. Let equality
fall through to the wrap branch, which covers every instant, and say so in the
docstring.

Reported by @xyzs996 in review.
2026-08-31 10:29:10 -05:00
Srivatsa03
4f174ffdd1 fix(cost): apply off-peak rates on the tiered-pricing path
Tiered pricing resolves its own base rates and returns early, before the
off-peak swap ran, so a model carrying both tiered_pricing and off_peak_pricing
billed the tier rate around the clock. Route every base-cost path through one
helper so the window applies wherever the rates came from, and say plainly in
the docstring that an off-peak rate replaces the rate it lands on rather than
discounting it
2026-08-31 10:29:10 -05:00
Srivatsa03
d302301a4e test(cost): move off-peak tests beside the related cost tests
They sat at the end of the file, which is where everyone else appends
too, so this branch picked up a conflict there on nearly every rebase.
Grouping them with the other _get_token_base_cost test keeps them clear
of that churn and next to the code they cover. Pure move, no test changes
2026-08-31 10:29:09 -05:00
Srivatsa03
f2c663515c fix(cost): evaluate off-peak windows in UTC for timezone-aware inputs
_is_within_off_peak_window used current_time.time(), which drops tzinfo, so a caller passing a non-UTC aware datetime had the window compared against local wall-clock instead of UTC. That silently mispriced off-peak requests. Normalize aware datetimes to UTC before comparing; naive datetimes stay as-is per the documented UTC contract. Added a regression test with a UTC+8 datetime that fails without the fix
2026-08-31 10:27:30 -05:00
Srivatsa03
9fc77f1222 feat(cost): support time-based off-peak pricing in cost calculation
Some providers charge different per-token rates depending on the time of
day. DeepSeek, for example, has historically discounted its chat and
reasoner models during an off-peak window (16:30-00:30 UTC). LiteLLM's
cost map only modeled static per-token pricing, so cost tracking could
not stay accurate for these providers.

This adds optional off-peak pricing to a model entry: input_cost_per_token_off_peak,
output_cost_per_token_off_peak, cache_read_input_token_cost_off_peak, and an
off_peak_hours_utc window expressed as "HH:MM-HH:MM" in UTC (the window may
wrap past midnight). When the current UTC time falls inside the window, the
cost calculator uses the off-peak rates and otherwise falls back to the
standard rates, so existing models are unaffected. The fields are also
accepted as custom pricing on a deployment, so they can be set from the
proxy config or the SDK.

The window check is a pure function that takes the current time as an
argument, which keeps the regression tests deterministic without patching
the clock.
2026-08-31 10:27:29 -05:00
Emerson Gomes
bd0b9c78bd
fix(router): keep order fallback on the requested order level
When a pre-call filter left no order-2 deployments, target_order matching
fell through to the remaining healthy list and reselected the failed
primary. Prompt-cache and deployment affinity also pinned that hop back
to order 1. Match the requested order strictly, skip those pins while
target_order is set, and keep target_order across retries of that hop.
2026-08-31 10:21:22 -05:00
Devin AI
2d01397e4d test: pin llm_router in supported_openai_params tests
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-31 15:03:52 +00:00
Devin AI
1bf3ab5388 fix(proxy): resolve router model aliases in /utils/supported_openai_params
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-31 14:45:31 +00:00
Devin AI
dd031f1036 fix(ci): parse paginated gh api output without splitting on unicode line breaks
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-31 09:42:07 +00:00
Devin AI
b81bca2696 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_deflake_20260830 2026-08-31 09:18:31 +00:00
Cursor Agent
43c64e2471
fix(cli): keep an existing ENABLE_TOOL_SEARCH value
Default remains true so lite claude turns tool search back on through
a proxy. An explicit false or auto in the env or settings is left alone

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
2026-08-31 06:00:45 +00:00
Cursor Agent
cafdfda8ba
feat(cli): set ENABLE_TOOL_SEARCH=true for lite claude
Claude Code turns tool search off when ANTHROPIC_BASE_URL is a proxy.
lite claude, lite up, login --config-claude, and autoroute now force
ENABLE_TOOL_SEARCH=true so MCP tools stay deferred through the proxy

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
2026-08-31 05:52:17 +00:00
feng.tsai
bb51c121cf docs: reference the source union by type instead of a line number
The line number went stale when the base moved.
2026-08-31 12:21:24 +08:00
samtsai15
0e7562dbc6 test(guardrails): cover every Anthropic image source shape in the extractor's own suite
_image_sources had no test asserting what it extracts. The existing image tests
live on the Bedrock side and all use base64 without a media_type, which is the one
path the fix left unchanged, so both behaviors it does change went unverified: the
url shape reaching the guardrail at all, and base64 arriving as a data URI.

Against the pre-fix extractor the url case sees [] and the media_type case sees
['AAAA'] instead of ['data:image/png;base64,AAAA'].

The remaining three assert behavior the fix deliberately preserves -- bare base64
passed through, a file source yielding nothing, a malformed source dropped rather
than handed on for a consumer to choke on.

Each message carries a text block because a message with no text never reaches the
guardrail, which would make every source shape look equally dropped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-31 10:37:51 +08:00
mateo-berri
de1f38820a fix(passthrough): flush interrupted streams on client disconnect and reuse cached gigachat http clients 2026-08-30 13:36:51 -07:00