Commit graph

51406 commits

Author SHA1 Message Date
yucheng
4cb4493fa7 fix(proxy): let the OTel trace id fallback fill a null litellm_trace_id
A body that serializes litellm_trace_id as null or an empty string carries no identity, so it must not
block the server span fallback. Also mark the nested metadata write as an out-param store

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 07:48:58 +00:00
yucheng
49417d4fa2 fix(proxy): ignore non-span parent_otel_span when deriving litellm_trace_id
UserAPIKeyAuth.parent_otel_span is Any at runtime (opentelemetry is an optional extra), so the OTel
trace-id fallback must only format an int trace id, otherwise an object that merely quacks like a span
turns the whole request into a 500

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 07:41:48 +00:00
yucheng
8899583d06 docs(otel): tighten inject_trace_context docstring
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 07:33:39 +00:00
yucheng
05ededf8a0 fix(otel): parent passthrough trace propagation on the legacy request span
Pass user_api_key_dict.parent_otel_span into the outgoing W3C injection so the
legacy otel callback propagates its litellm_request span, falling back to the
otel_v2 request root span and then the ambient span. Extend the mapped unit
tests to assert the propagated trace and span ids over real captured headers
for HTTP and WebSocket passthrough with forwarding on and off.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 07:24:52 +00:00
yucheng
f1fd1c8996 fix(proxy): default litellm_trace_id to the OTel server span trace id
When the otel callback is enabled and the client sends no trace or session identity, the request now inherits the W3C trace id of the proxy's server span as litellm_trace_id and metadata.trace_id. The missing_session_id policy and SpendLogs then persist that value as session_id, so a trace in the OTel backend and its row in the Logs UI carry the same id. Explicit x-litellm-trace-id, traceparent, body metadata.trace_id and litellm_trace_id keep priority.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 07:22:03 +00:00
Devin AI
c03a42a9c8 fix(azure): keep api-version query after vector store search path
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 07:17:27 +00:00
yucheng
9faaf7f4d4 refactor(proxy): assign the fallback model on the fresh snapshot instead of building a dict literal
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 07:15:13 +00:00
yucheng
2b6184d768 fix(proxy): resolve rate-limit fallbacks after model normalization and retry from a client-request snapshot
The fallback retry in _pre_call_with_fallbacks re-entered common_processing_pre_call_logic with data already enriched by the first pass, so add_litellm_data_to_request deep-copied a metadata dict holding the live OTel span and the request failed with a 500 (cannot pickle '_thread.RLock') instead of the intended 429 or fallback. Capture the configured fallbacks and a snapshot of the client request before the first pass, look up the fallback chain by the normalized model group after the limiter raises, and run each fallback attempt on a fresh copy of that snapshot. Replaces the mock-heavy tests with a rig that runs the real v3 limiter and a live OTel span through the proxy_logging_obj seam

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 07:08:24 +00:00
yucheng
2e699914e1 Merge remote-tracking branch 'origin/main' into litellm_lit_7470_rate_limit_fallback_pristine_data 2026-09-16 06:57:08 +00:00
shivam
7ba073aa26 test(otel): cover websocket trace propagation with forwarding on and off
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 06:55:06 +00:00
shivam
68cc12e848 test(otel): assert websocket forwarded header reaches upstream
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 06:55:06 +00:00
shivam
e4a12510f6 test(otel): cover websocket forwarded headers
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 06:55:06 +00:00
shivam
d2e8b9c656 fix(otel): keep passthrough working when opentelemetry is not installed
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 06:55:06 +00:00
shivam
7bcf848b39 refactor(passthrough): hoist websocket forwarded header set
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 06:55:06 +00:00
shivam
7bce15f7d8 fix(otel): propagate W3C trace context on passthrough upstream requests
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 06:55:06 +00:00
Yuneng Jiang
79cdcbf6c6
revert: drop the collection gate and keep the import fix 2026-09-15 23:25:33 -07:00
Joshua Valluru
ee676d59f2 fix(mcp): preserve browser OAuth for unrelated bearer tokens 2026-09-15 23:08:14 -07:00
Yuneng Jiang
3080ee8013
test: fail the integration gate on partial collection errors 2026-09-15 22:44:58 -07:00
Yuneng Jiang
a1bf948731
test: assert integration collection by summary, not exit code 2026-09-15 22:39:32 -07:00
Yuneng Jiang
d67c7894dd
fix(ui): keep recorded order when an untimed guardrail shares a phase 2026-09-15 22:25:30 -07:00
Yuneng Jiang
8bb496154a
test(ui): scope lifecycle assertions with within instead of parentElement
The four .parentElement reads in the new lifecycle tests pushed
testing-library/no-node-access to 712 against a 707 budget, failing
frontend-lint. The rows now carry data-testid="lifecycle-row" and the test
picks a row with within(), which keeps the assertion tied to the specific row
rather than the whole panel and takes the count back to 707.
2026-09-15 22:18:42 -07:00
Joshua Valluru
e035682ed1 refactor(auth): separate JWT identity and OAuth authorization 2026-09-15 22:15:57 -07:00
Yuneng Jiang
5bd27d1d99
Merge remote-tracking branch 'origin/main' into litellm_fix_integration_conftest_import 2026-09-15 21:45:12 -07:00
Yuneng Jiang
d20469b0dd
Merge remote-tracking branch 'origin/main' into litellm_fix_guardrail_lifecycle_untimed_entries 2026-09-15 21:44:22 -07:00
Yuneng Jiang
51a243e3ce
fix(ui): keep untimed guardrail entries on the request lifecycle
#39050 changed RequestLifecycle from sorting every entry with
(a.start_time ?? 0) to filtering on isTimed, which drops any entry whose
start_time/end_time are null. That was the right call for the not_run entries
the PR introduced, but it also drops entries that DID run and simply carry no
timing, and those are pre-existing: add_standard_logging_guardrail_information_to_request_data
defaults start_time, end_time and duration to None, and the conduct guardrail
passes none of them. One such entry used to draw the whole four-row lifecycle
and now draws nothing, so an admin opening that log sees an empty
Request Lifecycle panel.

An entry now stays on the lifecycle when it is timed OR when it ran, so not_run
keeps the exclusion #39050 wanted and every other shape comes back. Offsets are
number | null and render as an em dash rather than a fabricated T+0ms, which is
what a null minus a null used to produce on the base. Entries without timing
sort after the timed ones and the base time comes from the timed entries, so
real offsets are unchanged.

The two new tests fail on the base component and pass here; #39050's own
not_run tests keep passing untouched, which is what makes this additive rather
than a revert.
2026-09-15 21:44:19 -07:00
kerry
415b06f5ff test(e2e): assert the real bill for the four fixed cost gaps
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 04:42:07 +00:00
yassin
252c69b532 fix(router): snapshot shadow kwargs per target so concurrent shadows never share metadata
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 04:31:43 +00:00
kerry
bb6d7bf243 Merge remote-tracking branch 'origin/main' into litellm_e2e_cost_calculation_scripted_provider 2026-09-16 04:22:11 +00:00
tin-berri
a8979fe054
Merge pull request #41371 from BerriAI/litellm_forecast_simplify_advanced_ui
fix(ui): simplify Capability and Fuse advanced routing options
2026-09-15 21:19:50 -07:00
kerry-berri
5960881640
Merge pull request #41337 from BerriAI/litellm_fix_responses_stream_absent_usage_recount
fix(responses): recount tokens when a streamed response completes without usage
2026-09-15 21:19:42 -07:00
yuneng-jiang
bbffddd517
Merge pull request #41366 from BerriAI/litellm_/back-002-litellm-e2e-replay-8de5b1
fix(e2e): record cookie-setting provider responses and keep prompt-caching tests live
2026-09-15 21:18:14 -07:00
Yuneng Jiang
3b0fbc426d
fix(tests): resolve the integration support package without run.py's PYTHONPATH
tests/integration/conftest.py imported the bare `integration` package. Because
tests/__init__.py and tests/integration/__init__.py both exist, pytest's default
prepend import mode puts only the repo root on sys.path, so that name resolved
only under the PYTHONPATH that tests/integration/run.py injects. Every other
invocation died at conftest import with
ModuleNotFoundError: No module named 'integration' and exit 4, including the
command test_oci_integration.py documents in its own docstring.

The imports now use the tests.integration._support path that pytest actually
resolves, matching the 120 other `from tests.` imports in the suite. run.py's
PYTHONPATH still works because it already puts the repo root on the path.

tests/code_coverage_tests/test_integration_suite_imports.py collects every file
under tests/integration with PYTHONPATH scrubbed and asserts a non-zero
collection count, so an unresolvable import fails the code-quality job instead
of only the developers who run these files by hand. CI runs the three
pre-existing files through the allowlist rather than executing them, which is
why nothing caught this.
2026-09-15 21:10:08 -07:00
yuneng-jiang
e3c1f78e28
Merge branch 'main' into litellm_/back-002-litellm-e2e-replay-8de5b1 2026-09-15 21:08:29 -07:00
yassin
0f7ed4433b fix(router): snapshot shadow kwargs before fan-out so shadows never see primary mutations
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 04:04:01 +00:00
Tin Chi Lo
9d640b86ed fix(ui): simplify Capability and Fuse routing options 2026-09-15 20:58:38 -07:00
kerry
ff878e7df0 refactor(responses): copy the terminal event instead of mutating stubbed chunks
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 03:54:04 +00:00
yassin
9cabde90dd test(router): cover _run_silent_experiment directly for router coverage gate
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 03:48:32 +00:00
kerry
7cc07d437a fix(responses): build the billed terminal response immutably and guard the cache dump
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 03:47:03 +00:00
berriai-litellm-provider-info-sync[bot]
641dcd5f8f
chore(prices): sync Google Gemini prices: 1 model
gemini/gemini-robotics-er-2-preview: input_cost_per_token, output_cost_per_token, cache_read_input_token_cost, input_cost_per_token_batches, output_cost_per_token_batches
2026-09-16 03:46:34 +00:00
Joshua Valluru
258176de76 fix(mcp): validate rendered static credential payloads 2026-09-15 20:32:25 -07:00
yuneng-jiang
174c1ac4ed
Merge pull request #41348 from BerriAI/litellm_fix_models_reload_test
fix(e2e): expect models filters to persist after reload
2026-09-15 20:31:47 -07:00
yassin
06fcc1f733 feat(router): stream shadow traffic and fan out silent_model to multiple targets
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 03:28:08 +00:00
yuneng-jiang
9d54c2e159
Merge pull request #41359 from BerriAI/litellm_fix_budget_reset_decrement_tests
test(proxy): assert budget resets decrement the cleared spend
2026-09-15 20:27:35 -07:00
yuneng-jiang
ef06790e39
Merge pull request #41358 from BerriAI/litellm_fix_stale_router_tests
test(router): ignore deployment-selection logs in the fallback log assertion
2026-09-15 20:27:21 -07:00
Yuneng Jiang
a6fb21c3f8
fix(e2e): record cookie-setting provider responses and keep prompt-caching tests live
The first cache-enabled litellm-e2e build (211) showed three gaps in the shared provider cache:

Every OpenAI response carries Cloudflare bot-management Set-Cookie headers, and the capture rejected any response with Set-Cookie, so no OpenAI response was ever recorded (179 of 372 misses rejected). The edge already withholds Set-Cookie from the proxy, so drop it before validating and storing instead of rejecting.

The provider prompt-caching tests need fresh provider state: a replayed priming response reports cache creation rather than a cache read, and the TPM test then trips the key limit. Mark both modules provider_live.

TestApiBaseSeam::test_live_mode_returns_none ran inside the cache-enabled runner and saw the shared edge; isolate it from E2E_PROVIDER_CACHE.
2026-09-15 20:26:20 -07:00
kerry-berri
4b84fa9230
Merge pull request #41336 from BerriAI/litellm_fix_anthropic_stream_absent_usage
fix(anthropic): tolerate message_delta events without usage when streaming
2026-09-15 20:23:01 -07:00
Yuneng Jiang
8c046e13bd
test(together_ai): move request-shape checks to the mapped file, drop the live ones
Together moved openai/gpt-oss-20b off serverless and three tests in
test_completion.py died on a live 400. None of them needed Together to be up:
streaming is already covered live by tests/e2e/llm_translation/test_together_ai_e2e.py,
which picks its model from the cost map instead of pinning one, and the other
two are request-shape questions. Delete all three and assert the two shapes in
the mapped transformation file: the provider prefix is stripped without eating
the rest of a slashed model name, and custom role wrappers never reach the
request.
2026-09-15 20:17:42 -07:00
tin-berri
3b14631f06
Merge pull request #41315 from BerriAI/litellm_capability_fuse_classifier_ui
feat(ui): configure capability and Fuse v2 classifiers
2026-09-15 20:13:57 -07:00
kerry
7121e64db4 fix(responses): type the dict terminal response so the estimated usage is billed
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 03:13:53 +00:00
yucheng
581c613f66 fix(proxy): keep litellm_call_id on shaped errors and list_batches failure hook
Already shaped ProxyException and HTTPException errors passing through the moderations, audio speech, Anthropic Messages, and handle_exception_on_proxy paths now answer with the x-litellm-call-id header the route logged under, without overwriting a header the exception was raised with. The GET /v1/batches failure hook receives the resolved request data so the spend log request_id matches the response header and the error log

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 03:02:50 +00:00