Commit graph

7532 commits

Author SHA1 Message Date
Yucheng Zhu
b728bba7e1 refactor(proxy): satisfy the type-discipline ceiling on the disclosure surface
One never-rebound name on the org info path carries Final, matching the ratchet the rest of the stack now sits under.
2026-08-12 22:52:58 -07:00
Yucheng Zhu
3a12f794b3 feat(proxy): disclose resolved destinations on team and organization info
Adds resolved_logging_exporters to /team/info and /organization/info, naming every destination whose access scope grants that identity and which actually builds.

Squashed onto the rebased export branch; the previous history conflicted with staging's Final-annotation pass.
2026-08-12 22:52:58 -07:00
Yucheng Zhu
29806dee16 refactor(otel/v2): satisfy the type-discipline and strict-lint ceilings
Some checks failed
Terraform Provider / gofmt, vet, build, test (push) Has been cancelled
Terraform Provider / Provider endpoints vs proxy OpenAPI schema (push) Has been cancelled
Never-rebound names carry Final, deliberate rebinds carry rebind-ok with the reason, and the endpoint suffix check collapses into one endswith call. Two hook parameters and the constructor kwargs move from Any to object, which is both stricter and what the bodies actually rely on.

The remaining constructions keep a mutable-ok naming what needs a concrete dict: pydantic model_copy payloads, the OTel SDK Resource call, and the LRU caches that are mutable by design.
2026-08-12 10:59:02 -07:00
Yucheng Zhu
93061061fa feat(otel): export the trace to the resolved destinations
Fans each request's trace out to the destinations its identity resolved, applies per-request credentials only to the exporter their own backend contributed, and caches tracer providers per credential, endpoint and transport.

Squashed onto the current staging tip; the previous history conflicted with staging's Final-annotation pass over the same OTEL v2 modules.
2026-08-12 10:45:55 -07:00
Yucheng Zhu
4588c3b3f0 refactor(otel/v2): satisfy the type-discipline and strict-lint ceilings
Some checks failed
Terraform Provider / gofmt, vet, build, test (push) Has been cancelled
Terraform Provider / Provider endpoints vs proxy OpenAPI schema (push) Has been cancelled
Same ratchet as the credential-model branch: never-rebound names carry Final, the request-state mirror logs at debug instead of swallowing silently, and the empty header and resource fallbacks share one immutable mapping.

Two constructions keep a mutable-ok with a reason: the dedup accumulator consumed on the next line, and the TypedDict rows the resolver returns.
2026-08-12 10:43:25 -07:00
Yucheng Zhu
fc1ef61826 fix(otel/v2): keep the request path off opentelemetry when the feature is not in use
Publishing the destination ContextVar imports the OTel context module, and opentelemetry ships only in the proxy-runtime extra. That call sat outside the resolver's try, so a litellm[proxy] install raised ModuleNotFoundError on every request over a feature it never enabled; the flag being off did not help, since the gate lives inside the resolver and an empty result still fell through.

The helper now returns before publishing when the flag is off, and a missing package with the flag on warns instead of raising, matching what instrument_fastapi_app already did.
2026-08-12 10:37:09 -07:00
Yucheng Zhu
d31b4a3fde perf(otel/v2): resolve the caller's org only when a destination is org-scoped
The org fallback loads the team, which on a cache miss is a Prisma read on the authentication path. It cannot change which destinations are selected unless some access names an org, so it now runs only then; the logging credentials are also parsed once instead of twice.
2026-08-12 10:37:09 -07:00
Yucheng Zhu
b5a51e72cd feat(otel): resolve a request's trace destinations from its identity 2026-08-12 10:37:09 -07:00
Yucheng Zhu
168a20b065 fix: bind GET /credentials to its handler, not the verdict helper
Some checks failed
Terraform Provider / gofmt, vet, build, test (push) Has been cancelled
Terraform Provider / Provider endpoints vs proxy OpenAPI schema (push) Has been cancelled
The type-discipline refactor inserted _destination_verdict between the
@router.get decorator and get_credentials, so FastAPI registered the helper
as the listing endpoint. It declares a CredentialItem parameter, which FastAPI
reads as a required request body, and every GET /credentials returned 422.

Add the GET routing regression test alongside the existing PATCH one; the
other tests call get_credentials directly and stay green while the route is
dead.
2026-08-12 10:33:53 -07:00
Yucheng Zhu
04457114cc fix(otel/v2): pin the generic passthrough to HTTP and report whether a destination builds
An `arize` credential carrying only `otel_endpoint` is built by the generic passthrough but
resolved under the `arize` name, so the router applied Arize's intrinsic gRPC transport to
the plain HTTP URL the admin typed. The destination delivered nothing while `/team/info`
kept advertising it as active, which is the invariant `resolved_logging_exporter_names`
exists to hold. The passthrough now pins `otlp_http`, which is what it has always meant;
adapter-built Arize destinations keep their gRPC default, covered by its own test.

`GET /credentials` now reports `resolves_to_destination` for logging credentials, computed
by `destination_for_credential` so it cannot drift from the resolver or the disclosure. The
dashboard's Scope column needs this verdict; recomputing the adapter rules there would drift
from them, and that drift is what let a dead destination read as live.

Both regression tests were mutation-checked by reverting their own fix in isolation.
2026-08-12 10:33:53 -07:00
Yucheng Zhu
6897201b4f feat(credentials): admin-owned logging credential, access shape, and destination mapping 2026-08-12 10:33:53 -07:00
Yassin Kortam
b0626cad8c
perf(proxy): stagger scheduled background jobs across jobs and pods (#36589)
APScheduler anchors an interval job at now + interval, so every scheduled
background job registered in one proxy startup shares a single firing instant
for the life of the process, and every replica a rollout brought up together
shares that instant too. Each tick the spend flushes, budget reset sweep,
config-in-DB reload, credential reload and cost pollers all hit Postgres at the
same moment, on every pod, competing with request-path auth and budget queries.

Shift each eligible job by a deterministic offset derived from
sha256(job_id, identity), where identity covers the pod and the worker process.
The offset lives in the trigger rather than in a one-off next_run_time, because
a cron trigger recomputes each fire from the wall clock and would otherwise snap
straight back onto the shared instant. An interval job is never offset by more
than one of its own periods.

Only schedules LiteLLM chose are shifted: interval jobs always, cron jobs only
when the id is one of the product's own defaults, so an operator-supplied
crontab keeps the instant it asks for. general_settings.scheduled_job_stagger
turns it off, widens the window, replaces the identity, or pins a job. The
applied offsets are logged once at startup and each fire logs its scheduled
instant against its actual start.

Resolves LIT-5433
2026-08-12 09:17:31 -07:00
Mateo Wang
8c2edbfc66
Merge pull request #36590 from BerriAI/litellm_lit012_readonly_typeddict
feat(lint): gate writable TypedDict fields with LIT012
2026-08-12 08:39:34 -07:00
Praveen11558
0ca0fa22b8
fix: refactor HTTP handler initialization with client support (#30952)
* bug: Refactor HTTP handler initialization with client support

* Update transformation.py

* bug: fixing the passing of clientID for the psc calls

* Update llm_http_handler.py

* Update llm_http_handler.py

* Update transformation.py

* Remove duplicate 'plugins' field definition

Removed duplicate definition of 'plugins' field.

* Update proxy_server.py

* Update transformation.py

* Update transformation.py

* Update test_vertex_gemma_transformation.py

* Refactor HTTP client handling for Vertex Gemma

* Refactor tests to use mock_get_client for HTTP calls

* Update transformation.py

* Update transformation.py

* Refactor patches for async HTTP client in tests

* fix: refactor HTTP handler initialization with client support

---------

Co-authored-by: michelligabriele <gabriele.michelli@icloud.com>
2026-08-12 15:17:51 +02:00
Mateo Wang
f64479e74d
Merge pull request #34177 from atomic/fix/nvidia-nim-ranking-image-passages-top-n
fix(nvidia_nim): preserve image passages and stop sending top_k to /v1/ranking
2026-08-12 01:42:00 -07:00
Mateo Wang
f8caaf4d2d
Merge pull request #32536 from dcadenas/litellm_fix_codex_responses_namespace_tools
fix(responses): preserve Codex namespace tool calls
2026-08-12 01:10:30 -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
9cc5a818c3
Merge pull request #36154 from BerriAI/devin_ai_sse_keepalive_openai_routes
feat(proxy): global SSE keepalive ping interval for OpenAI-shaped streaming routes
2026-08-12 00:19:13 -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
9bfe593241
Merge pull request #35880 from BerriAI/devin_ai_fix_cost_estimate_onprem_provider_35210
fix(proxy): forward resolved provider and deployment pricing in /cost/estimate
2026-08-12 00:08:40 -07:00
Mateo Wang
23b805d5a4
Merge pull request #36447 from BerriAI/litellm_anthropic_fast_mode_speed_usage
fix(anthropic): preserve speed=fast in usage for /v1/messages and pass-through
2026-08-12 00:05:59 -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-berri
1d7c23a424 Merge branch 'litellm_internal_staging' into fix/nvidia-nim-ranking-image-passages-top-n 2026-08-11 23:41:54 -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-berri
e53f044d20 fix(proxy): resolve the global SSE keepalive interval through the per-deployment engine
The outer wrap_sse_stream_with_keepalive_pings layer duplicated the
keepalive engine that PR #34423 already runs inside async_data_generator
for chat completions and responses streams, and it kept pinging
deployments whose operator set keepalive_seconds: 0 as a hard disable.
sse_keepalive_ping_interval_seconds is now the global fallback inside
_resolve_keepalive_seconds, so deployment and request values keep
precedence, an explicit 0 still disables, the [1, 300]s clamp applies,
and router-less proxies arm the wrap when the global default is set.
2026-08-11 23:37:43 -07:00
mateo-berri
d5a1896cf4 test: drop rerank package marker colliding with voyage test package 2026-08-11 23:37:27 -07:00
mateo-berri
0fdbe03c50 fix(proxy): honor model_info custom pricing in /cost/estimate 2026-08-11 23:25:01 -07:00
mateo-berri
d9ad21699c fix(anthropic): preserve fast-mode speed on parsed messages responses
The Rust messages bridge logs a parsed Anthropic response without an
httpx_response, so the fallback transform dropped the request speed and
billed fast-mode calls at the standard rate. Thread optional_params
speed into transform_parsed_response and add a regression test for the
parsed-response branch.
2026-08-11 23:21:23 -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
22088138ca test(nvidia_nim): move ranking transform regressions to the covered unit tree 2026-08-11 23:08:46 -07:00
mateo-berri
464a4cf207 Merge remote-tracking branch 'origin/litellm_internal_staging' into pr35880_local 2026-08-11 23:01:05 -07:00
Mateo Wang
7e80e094c4
Merge pull request #36529 from william-xue/fix-responses-passthrough-stream-cost
fix(proxy): track streamed passthrough Responses cost
2026-08-11 21:58:42 -07:00
mateo-berri
08a73740ec fix(passthrough): keep prompt/completion token split for streamed OpenAI rows 2026-08-11 21:28:55 -07:00
mateo-berri
5e14649c54 fix(passthrough): bill streamed Responses calls that end failed
A stream can terminate with a response.failed event that still reports
consumed tokens; those were rebuilt as None and logged at zero spend.
Parse response.failed alongside completed and incomplete, matching the
buffered path, which prices any terminal response that reports usage.
2026-08-11 21:01:18 -07:00
yucheng-berri
8bfb7772e4
fix(batches): attribute Anthropic passthrough batch cost to the creating key, team and tags (#36468)
The Anthropic batch create never persisted the creating key's hashed token or its
request tags on the managed object, so when CheckBatchCost billed the batch hours
later there was nothing to attribute it to. Key spend, key budgets and tag spend
never moved for batch usage.

Persist both from the create, the way the Vertex passthrough already does, and
register the batch only from the collection route. An id-scoped route cannot
rebuild the unified object id, because it embeds the model and the model comes
from the create's request body, so it could only claim a row it did not create or
fail the model_object_id unique constraint.

The shared metadata helpers, the route predicate and the registration-result
logging now live in batch_attribution instead of being copied per provider. The
Anthropic write previously logged success unconditionally, before the
fire-and-forget task had run.

Resolves LIT-5288
2026-08-11 20:52:43 -07:00
mateo-berri
2df121c821 fix(passthrough): bill streamed Responses calls that end incomplete
Streams that terminate with response.incomplete (e.g. max_output_tokens
reached) carry real usage in the terminal event but were rebuilt as None
and logged at zero spend, letting callers bypass budget enforcement.
Parse response.incomplete alongside response.completed when
reconstructing the streamed response.
2026-08-11 20:21:17 -07:00
mateo-berri
dc30e1816d refactor(passthrough): move Responses stream terminal-event parsing into OpenAI provider config
Addresses review feedback: the ResponseCompletedEvent SSE parsing now lives
in OpenAIResponsesAPIConfig next to the other Responses stream event handling,
and the proxy logging handler calls it. Adds coverage for streams that end
without a response.completed event.
2026-08-11 20:11:53 -07:00
Mateo Wang
b4f5e46a44
Merge pull request #30817 from geraint0923/litellm_fix_xai_web_search_cost_billing
Some checks are pending
Unit Tests: LLM Provider Transformations / All Other Providers (push) Waiting to run
Unit Tests: MCP, Secrets, Containers & Misc / misc (push) Waiting to run
Unit Tests: Proxy Auth & Key Management / proxy-auth (push) Waiting to run
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 / endpoints-and-responses (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-utils (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 Infrastructure / proxy-infra (push) Waiting to run
Unit Tests: Proxy Legacy Tests / auth-and-jwt (push) Waiting to run
Unit Tests: Proxy Legacy Tests / key-generation (push) Waiting to run
Unit Tests: Proxy Legacy Tests / proxy-config (push) Waiting to run
Unit Tests: Proxy Legacy Tests / proxy-response-and-misc (push) Waiting to run
Unit Tests: Proxy DB Operations / proxy-server-core (push) Blocked by required conditions
Unit Tests: Proxy API Endpoints / proxy-endpoints (push) Waiting to run
Unit Tests: Proxy API Endpoints / proxy-server (push) Waiting to run
Unit Tests: Proxy Legacy Tests / proxy-server (push) Waiting to run
Unit Tests: Proxy Legacy Tests / proxy-server-extras (push) Waiting to run
Unit Tests: Proxy Legacy Tests / proxy-token-counter (push) Waiting to run
Unit Tests: Proxy Legacy Tests / proxy-user-auth-and-spend (push) Waiting to run
Unit Tests: Proxy Legacy Tests / proxy-utils (push) Waiting to run
Unit Tests: Responses, Caching & Types / responses-caching-types (push) Waiting to run
GitHub Actions Security Analysis / zizmor (push) Waiting to run
fix(xai): bill web_search from server_side_tool_usage_details
2026-08-11 19:40:27 -07:00
mateo-berri
d96f76ca66 fix(cost-tracking): bill web searches reported only in server_side_tool_usage_details 2026-08-11 19:24:53 -07:00
tin-berri
06943b6468
feat(router): make routing groups callable as virtual models and list them in /v1/models (#36519)
* feat(router): make routing groups callable as virtual models and list them in /v1/models

* fix(router): traffic-scoped cooldown exemption, live model_names on delete, group-info cache invalidation

* fix(router): share one recognized-model predicate across proxy gates, resolve aliases in group cooldown, read metadata via the dual-bucket owner

* fix(router): close the gate and cache families for callable groups, strip member access_groups from group rows, prove cooldown wiring end to end

* refactor(router): cache materialized group rows under the model-group cache owner and drop the redundant wiring test

* fix(router): warn-and-shadow on group name collisions, name-level test coverage for group helpers, faithful router doubles in a2a and cursor tests

* test(router): pin group cooldown metadata across the retry path
2026-08-11 18:41:19 -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
7b39fd6614 feat(lint): gate writable TypedDict fields with LIT012
Every TypedDict field must carry a ReadOnly[...] qualifier (PEP 705),
nesting freely with Required/NotRequired/Annotated. Detection covers the
class form (including same-module transitive subclasses) and the
functional form. The 4519 existing violations across litellm/ are
grandfathered via type-discipline-budget.json; suppress deliberate
writable keys with # writable-ok: <reason>.
2026-08-11 17:57:34 -07:00
yucheng-berri
417c70589f
fix(bedrock_guardrails): skip ApplyGuardrail when there is no content to scan (#36441) 2026-08-11 17:30:54 -07:00
mateo-berri
280844c2f5 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_fix_xai_web_search_cost_billing 2026-08-11 17:23:00 -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
Devin AI
634a452c9e merge: litellm_internal_staging into devin_ai_sse_keepalive_openai_routes
Some checks failed
Terraform Provider / gofmt, vet, build, test (push) Has been cancelled
Terraform Provider / Provider endpoints vs proxy OpenAPI schema (push) Has been cancelled
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-11 21:05:41 +00:00
Mateo Wang
422d925334
Merge pull request #36499 from BerriAI/litellm_bedrock_converse_pdf_text_block_fix
fix(bedrock): add text block to converse user messages carrying documents
2026-08-11 12:59:00 -07:00
ryan-crabbe-berri
be71a8fdbf
fix(alerting): dedupe scheduled Slack spend reports across pods (#36489)
* fix(alerting): dedupe scheduled Slack spend reports across pods

Every pod ran its own weekly/monthly spend report jobs, prometheus
fallback stats cron, and daily report loop, so deployments with
multiple replicas or uvicorn workers received one copy per pod.

Gate each scheduled send behind the shared PodLockManager redis lock.
The lock is never released: its TTL (the full reporting window for the
weekly interval job, whose per-pod anchors drift by boot time and
jitter) doubles as a sent-this-window marker. acquire_lock returning
None (no redis wired) proceeds, preserving single-pod behavior.

Also generalize the pod lock could-not-acquire log line, which claimed
to be about spend tracking for every consumer.

Fixes #14809

* fix(alerting): harden spend report locks after adversarial review

Weekly lock TTL gets an hour haircut: with ttl equal to the interval,
the winner re-fires just before its own key expires, reacquires without
a TTL refresh, and the key then lapses in time for a trailing pod to
re-send. Job/lock ids move to litellm/constants.py per convention, and
spend_report_frequency now rejects non-positive day counts, which
previously coerced to an every-second schedule and would now compute a
negative lock TTL that silently never sends.

Adds the missing test coverage the review flagged: startup_event's
pod_lock_manager wiring (identity-asserted), the prometheus closure's
positive path, and the ungated immediate prometheus send pinned to
exactly one await.

* test(alerting): consolidate spend_report_frequency validator coverage

Drops a duplicate non-positive-days test and parametrizes the survivor
over the suffix half of the validator too

* fix(alerting): route the startup prometheus fallback send through the pod lock

Greptile caught that the boot-time send still ran once per pod when
PROMETHEUS_URL is set, the same duplication class this PR removes

* fix(alerting): make report lock acquisition non-reentrant

Greptile caught that a pod booting within an hour of the fallback stats
cron sent twice: the startup send takes the lock, then the cron fire
hits acquire_lock's reacquire branch, which returns True for the
holder. Window-marker gates now pass allow_reentrant=False so a live
lock blocks everyone including its holder; leader-election consumers
keep the reentrant default

* test(proxy): give spec'd ProxyLogging mocks a db_spend_update_writer

_initialize_slack_alerting_jobs now reads it for the pod lock manager,
and spec=ProxyLogging blocks instance-only attributes
2026-08-11 12:41:11 -07:00
Mateo Wang
7b34a6c632
Merge pull request #36507 from BerriAI/litellm_bedrock_converse_thinking_stream_fix
fix(bedrock): preserve adaptive thinking effort through the /v1/messages bridge
2026-08-11 12:23:29 -07:00
Mateo Wang
5c704055c6
Merge pull request #36502 from BerriAI/litellm_bedrock_invoke_tool_search_fix
fix(bedrock): send tool-search beta header for Haiku 4.5 on Invoke /v1/messages
2026-08-11 12:21:46 -07:00