Commit graph

38575 commits

Author SHA1 Message Date
yuneng-jiang
57dd3891fb
Merge pull request #27024 from BerriAI/litellm_yj_may1
[Infra] Merge dev branch
2026-05-01 16:36:24 -07:00
Mateo Wang
628ce9d5ef
Merge pull request #25856 from BerriAI/litellm_clean_litellm_oss_staging_04_01_2026
Litellm clean litellm oss staging 04 01 2026
2026-05-01 16:10:15 -07:00
yuneng-jiang
fba38d0e94
Merge pull request #26929 from BerriAI/litellm_fix_service_account_user_id_bypass
fix(proxy): reject user_id=None on non-admin analytics endpoints (cross-tenant disclosure)
2026-05-01 16:08:35 -07:00
yuneng-jiang
d1fc398f44
Merge pull request #26924 from BerriAI/litellm_fix_ui_session_fixation_url_token
fix(ui): remove insecure ?token= URL handler from LoginPage to close session-fixation
2026-05-01 16:06:49 -07:00
yuneng-jiang
4ebe782134
Merge pull request #27021 from BerriAI/litellm_/vigilant-bohr-3adf26
[Fix] Proxy: Skip Personal Budget Hook When Reservation Covers Counter
2026-05-01 16:00:17 -07:00
Yuneng Jiang
a12b4249bd
[Fix] Proxy: Skip Personal Budget Hook When Reservation Covers Counter
The reservation path (PR #26845) atomically pre-fills `spend:user:{user_id}`
and admits at the strict-`<` boundary. The legacy `_PROXY_MaxBudgetLimiter`
pre-call hook re-reads the same counter with `>=`, so a reservation that
fills the counter to exactly `max_budget` (e.g. a request without a
`max_tokens` cap that falls back to reserving the smallest remaining
headroom) is rejected by the hook even though the reservation already
admitted it.

Skip the hook when the request's active `budget_reservation` covers
`spend:user:{user_id}`. The reservation is the source of truth for that
counter cross-pod; the legacy `>=` path remains in place for requests
without a reservation (e.g. paths that bypass the reservation entirely).

Reproduces as `tests/otel_tests/test_prometheus.py::test_user_budget_metrics`
on a fresh user with `max_budget=10` calling `fake-openai-endpoint` without
`max_tokens`. Adds focused unit coverage in
`tests/test_litellm/proxy/hooks/test_max_budget_limiter.py`.
2026-05-01 15:57:42 -07:00
mateo-berri
04e96a9bdc Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_clean_litellm_oss_staging_04_01_2026 2026-05-01 15:54:10 -07:00
Mateo Wang
6458fe15fd
Merge pull request #26077 from BerriAI/litellm_vertex_cached_content_mutual_exclusion
fix(vertex_ai): omit system_instruction/tools/toolConfig when cachedContent set
2026-05-01 15:52:47 -07:00
ryan-crabbe-berri
4503dd18bb
Merge pull request #27012 from BerriAI/litellm_fix-post-call-guardrail
fix(guardrails): post-call guardrail must only fire once
2026-05-01 15:51:55 -07:00
Mateo Wang
0b87bdff3d
Merge pull request #26976 from BerriAI/litellm_default_embedding_encoding_format
feat(embedding): default OpenAI-path encoding_format to float
2026-05-01 15:37:59 -07:00
yuneng-jiang
2573fcdbb2
Merge pull request #27017 from BerriAI/fix/bedrock-count-tokens-url-encoded-test-assertions
[Fix] Tests: Align Bedrock count-tokens endpoint assertions with URL-encoded model id
2026-05-01 15:34:21 -07:00
Yuneng Jiang
8eca93470c
[Fix] Tests: Align Bedrock count-tokens endpoint assertions with URL-encoded model id
The endpoint builder in BedrockCountTokensConfig.get_bedrock_count_tokens_endpoint
percent-encodes the model id as a single path segment (d4dd865b1a, path-traversal
hardening). Update the four endpoint-URL assertions in TestBedrockCountTokensEndpoint
to expect `amazon.nova-lite-v1%3A0` instead of the literal `:0`, matching production
behavior already covered by test_count_tokens_endpoint_encodes_model_id.
2026-05-01 15:22:40 -07:00
yuneng-jiang
d07cdd4481
Merge pull request #26838 from BerriAI/litellm_vcr-cassette-llm-tests-af37
tests(vcr): redis-backed vcrpy cache for offline LLM e2e replay
2026-05-01 15:16:52 -07:00
Yuneng Jiang
61a3923b71
[Fix] Proxy: Repair Stale HTTP_METHODS Reference In Lazy OpenAPI Snapshot
_normalize_operation_ids referenced HTTP_METHODS but only HTTP_METHOD_SUFFIXES is defined, raising NameError on snapshot generation and failing test_lazy_openapi_snapshot. The constant was renamed in an earlier merge without updating these two references; values are identical sets of HTTP method names.
2026-05-01 15:11:56 -07:00
yuneng-jiang
8363fe00e1
Merge pull request #26841 from stuxf/fix/mcp-xff-trust-gate
chore(mcp): require trusted-proxy gate before honouring X-Forwarded-* on OAuth discovery
2026-05-01 15:08:40 -07:00
yuneng-jiang
3583ac1159
Merge pull request #26860 from stuxf/fix/provider-path-traversal
chore(security): encode upstream URL path identifiers
2026-05-01 14:47:52 -07:00
yuneng-jiang
dc681b9eb2
Merge pull request #26954 from BerriAI/claude/lucid-margulis-e99b6b
refactor(rate-limit): consolidate batch + dynamic limiter check/increment
2026-05-01 14:46:25 -07:00
yuneng-jiang
ae9065137c
Merge pull request #26921 from stuxf/codex/integration-host-credential-guard
chore(callbacks): guard dynamic integration hosts
2026-05-01 14:42:32 -07:00
yuneng-jiang
eca6feb6a6
Merge branch 'litellm_yj_may1' into codex/integration-host-credential-guard 2026-05-01 14:42:23 -07:00
Yuneng Jiang
d8f556e18c
[Fix] Auth: Restore Request-Context Model Resolution In Skip-Budget Helper
Merge of #26845 kept the PR's _should_skip_budget_checks helper but lost staging's upgrade to _get_model_from_request_context, so zero-cost models resolved from request headers/query params no longer skipped budget checks. Route the helper through _get_model_from_request_context so this path matches the other 8 model-resolution sites in the file.
2026-05-01 14:39:24 -07:00
Mateo Wang
05439530c2
Merge branch 'litellm_internal_staging' into litellm_vcr-cassette-llm-tests-af37 2026-05-01 14:37:48 -07:00
mateo-berri
80415b472e tests(vcr): drop redundant comments and docstrings
Remove explanatory comments that restated what the code already says.
Kept only those that document non-obvious external contracts (the aiohttp
record-path patch's reason for re-feeding the body, and the warning
messages inside save_cassette that reach the user).
2026-05-01 14:36:48 -07:00
yuneng-jiang
ebd335da67
Merge pull request #27000 from BerriAI/litellm_fix_pdf_file_id_test
[Test] Anthropic: Use jsDelivr CDN For PDF Fixture URL
2026-05-01 14:36:25 -07:00
yuneng-jiang
b25732f38b
Merge pull request #26845 from stuxf/codex/budget-race-enforcement
chore(proxy): tighten budget spend admission
2026-05-01 14:32:29 -07:00
yuneng-jiang
c2cea58567
Merge branch 'litellm_yj_may1' into codex/budget-race-enforcement 2026-05-01 14:32:18 -07:00
mateo-berri
53f71fbf4d tests(vcr): emit per-test verdicts via xdist controller's terminalreporter
Previous attempt wrote to sys.__stderr__ from the test fixture. Under
xdist, fixtures run inside worker subprocesses whose stderr is captured
by the controller and only released to the live log on test failure —
so passing tests' verdicts were silently swallowed.

Round-trip via report.user_properties: the worker-side fixture stashes
the verdict on user_properties, xdist serializes it onto the report,
and a controller-side pytest_runtest_logreport hook writes it via the
TerminalReporter (the same plugin that emits PASSED/FAILED markers).
TerminalReporter is resolved lazily on first hook call because it's
not yet registered when conftest's pytest_configure runs.

Verified locally in both serial and xdist modes.
2026-05-01 14:29:06 -07:00
Ryan Crabbe
a1fd150b98
style: black format test_deferred_guardrail_logging.py
Strip a trailing-whitespace line introduced by PR #26109. Black-only
change, no behavior impact — unblocks the lint check on this branch.
2026-05-01 14:28:20 -07:00
ryan-crabbe-berri
5e96120553
Merge pull request #26109 from mubashir1osmani/kaboom
fix: post call guardrail must be called once
2026-05-01 14:27:08 -07:00
yuneng-jiang
df17ffc386
Merge pull request #26930 from stuxf/codex/vector-store-tenant-guard
chore(vector stores): tighten managed store access
2026-05-01 14:25:51 -07:00
yuneng-jiang
058d717b61
Merge pull request #27010 from BerriAI/yj/fix-lazy-openapi-snapshot-merge
[Fix] Tests: Move Misplaced Import in Lazy OpenAPI Snapshot Test
2026-05-01 14:25:23 -07:00
Yuneng Jiang
4825d94a9d
[Fix] Tests: Move Misplaced Import in Lazy OpenAPI Snapshot Test
The GitHub merge conflict resolver concatenated both test sets but left
`from litellm.proxy._lazy_openapi_snapshot import _normalize_operation_ids`
stranded between functions instead of at the top of the file.
2026-05-01 14:24:53 -07:00
yuneng-jiang
38fae659b5
Merge branch 'litellm_yj_may1' into codex/vector-store-tenant-guard 2026-05-01 14:24:48 -07:00
ryan-crabbe-berri
610f79dc03
Merge pull request #27003 from BerriAI/litellm_health-endpoint-non200-on-failure
fix(health): return 503 when targeted model is unhealthy or DB is disconnected
2026-05-01 14:23:37 -07:00
yuneng-jiang
2fca7ad3ef
Merge pull request #26963 from stuxf/codex/file-endpoint-model-auth
chore(proxy): align resource model auth checks
2026-05-01 14:22:27 -07:00
yuneng-jiang
9e501edece
Merge branch 'litellm_yj_may1' into codex/file-endpoint-model-auth 2026-05-01 14:22:18 -07:00
yuneng-jiang
42122b83f5
Merge pull request #26969 from stuxf/codex/tool-permission-guardrail-fix
chore(guardrails): tighten tool permission checks
2026-05-01 14:17:55 -07:00
mateo-berri
965185c106 fix(tests): host PDF fixture via jsDelivr with proper application/pdf MIME
Raw github serves application/octet-stream which OpenAI/Gemini reject
when LiteLLM fetches the URL client-side. jsDelivr serves the same
file with content-type: application/pdf. Pin to a commit SHA so the
asset is immutable and jsDelivr can cache it for a year.
2026-05-01 14:16:57 -07:00
yuneng-jiang
f34a2752f6
Merge pull request #26996 from stuxf/chore/ssrf-polling-and-nested-config
chore(security): close two unaddressed SSRF cases
2026-05-01 14:16:39 -07:00
mateo-berri
c05c865a1c tests(vcr): emit verbose verdicts to un-redirected stderr
Previously, the per-test [VCR HIT/MISS/...] line was written via
TerminalReporter.write_line from inside fixture teardown. Pytest
captures that stream by default and only surfaces it on FAILED tests
(under 'Captured stdout teardown'), so passing tests' verdicts were
invisible in CI logs and the user couldn't tell whether the cache
was working.

Write directly to sys.__stderr__ so the line bypasses pytest's
capture entirely. Under xdist each worker has its own __stderr__
which CircleCI aggregates into the live job log alongside the
PASSED/FAILED markers.
2026-05-01 14:14:44 -07:00
Ryan Crabbe
038b180315
fix(health): validate model_id against scoped model_list in cache-path resolver
A non-admin scoped to ["model-a"] could call /health?model_id=id-b
(where id-b belongs to a deployment outside their scope) and the
background-cache code path would return id-b's cached health entry. The
helper returned {model_id} unconditionally, so the cache filter was
driven by an unvalidated id and the global cache leaked the entry — the
ternary `targeted_ids if not None else allowed_model_ids` skipped any
intersection with the caller's allowed deployments.

Make _resolve_targeted_model_ids walk the supplied model_list for both
the model and model_id branches. Callers pass an already-scoped list
(filtered to allowed model_names for non-admins, full list for admins),
so an out-of-scope model_id resolves to an empty set and the cache
filter drops every entry — matching the live path's existing behavior.
2026-05-01 14:11:51 -07:00
Yuneng Jiang
5cd1272eda
Revert "[Fix] Image Handling: Fall Back To URL Extension When Server Returns Octet-Stream"
This reverts commit 019f5eeed7.
2026-05-01 14:09:47 -07:00
Yuneng Jiang
019f5eeed7
[Fix] Image Handling: Fall Back To URL Extension When Server Returns Octet-Stream
GitHub serves PDFs from raw.githubusercontent.com, github.com/.../raw/..., LFS, and Releases as application/octet-stream by deliberate anti-hotlinking policy. Anyone who passes a GitHub-hosted PDF URL as an OpenAI / Gemini / Bedrock file_id hits "unsupported MIME type 'application/octet-stream'" because _process_image_response inlines the URL with whatever Content-Type the server sent.

When the server-provided Content-Type is application/octet-stream or binary/octet-stream and the URL extension maps to a known MIME type (.pdf, .png, .jpg, etc.), trust the extension instead. Specific Content-Types (image/png, application/pdf) still win over the extension; the override only applies to generic binary types.

Also restores the Greptile SHA-pinned raw.githubusercontent.com URL on the file_id integration test so we test against the same hosting real users hit, no third-party CDN.
2026-05-01 14:08:15 -07:00
mateo-berri
225d01cb4f fix(tests): use github-hosted PDF fixture for Anthropic Files API test
Anthropic's URL fetcher intermittently returns 400 'Unable to download
the file' for the Wikipedia URL the test was using. Point it at the
repo's existing tests/llm_translation/fixtures/dummy.pdf via raw
GitHub instead — small, deterministic, reliably fetchable.

With a stable URL the test no longer needs to be opted out of VCR;
remove it from the incompatible list so it can replay from cassette.
2026-05-01 14:07:32 -07:00
Yuneng Jiang
42cc765593
Merge remote-tracking branch 'origin/litellm_fix_pdf_file_id_test' into litellm_fix_pdf_file_id_test
Resolve URL conflict: keep Greptile's commit-SHA pin for immutability, but route through jsDelivr (cdn.jsdelivr.net/gh/BerriAI/litellm@<sha>/...) so the response Content-Type is application/pdf instead of application/octet-stream. Without this, OpenAI / Gemini / Router PDF tests reject the inlined file_data with "unsupported MIME type 'application/octet-stream'".
2026-05-01 14:02:35 -07:00
Ryan Crabbe
21e19bf3a5
test(health): tighten happy-path 200 assertions to exact equality
Per review: `assert response.status_code != 503` is satisfied by 404,
500, or any other non-503 code, so a regression that returned the wrong
non-503 status would slip through. Switch to `== 200` so the assertions
verify the actual expected status, not just the absence of one specific
failure.
2026-05-01 13:59:10 -07:00
mateo-berri
a47c4e7d1b tests(vcr): refuse to persist cassettes past 50 episodes
A test that produces non-deterministic request bodies (e.g. uuid in
the prompt) under record_mode=new_episodes never replays — every CI
run appends fresh unmatched episodes. The cassette grows unbounded
over time and silently inflates Redis (we observed one cassette at
22 episodes / ~860KB after ~5 CI runs).

Refuse the save when episode count exceeds MAX_EPISODES_PER_CASSETTE
so the pathology surfaces with a loud warning that points to the
opt-out fix instead of festering invisibly.
2026-05-01 13:56:20 -07:00
Yuneng Jiang
f13b7af2fa
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_fix_pdf_file_id_test 2026-05-01 13:54:50 -07:00
Yuneng Jiang
feb238bce9
[Test] Anthropic: Use jsDelivr CDN For PDF Fixture URL To Preserve Content-Type
The previous URL switch to raw.githubusercontent.com fixed Anthropic's "Unable to download" failure but caused OpenAI / Gemini / Router PDF tests to fail with "unsupported MIME type 'application/octet-stream'": those providers download the URL and inline it as data:<Content-Type>;base64,..., and raw.githubusercontent.com serves PDFs as application/octet-stream.

jsDelivr proxies the same in-repo fixture (cdn.jsdelivr.net/gh/BerriAI/litellm@main/...) and returns the correct Content-Type: application/pdf, so all providers (Anthropic forwards the URL natively; OpenAI/Gemini/Bedrock fetch and inline) get the right MIME type without changing transformer code.
2026-05-01 13:54:44 -07:00
mateo-berri
8c01b02779 tests(vcr): opt out tests that observe live cross-call provider state
Some tests can't benefit from cassette replay because they assert on
state that only exists in the live provider between two calls (e.g.
prompt-cache propagation, intermittent provider quirks). Marking them
with @pytest.mark.vcr just wastes cycles trying to record cassettes
they will never replay against successfully.

Opt-out by nodeid suffix so subclassed/parametrized variants are
covered:

- ::test_prompt_caching — Anthropic/Bedrock prompt-cache propagation
  isn't deterministic in the 0–1s window the test gives it.
- ::test_async_pdf_handling_with_file_id — flaky upstream Wikipedia
  fetch through the Anthropic Files API.
- TestBedrockInvokeNovaJson::test_json_response_pydantic_obj —
  Bedrock Nova returns tool_call vs JSON nondeterministically (other
  providers' subclasses are healthy).
- ::test_bedrock_converse__streaming_passthrough — Bedrock streaming
  response_cost calc returns None intermittently.

These tests keep their existing @pytest.mark.flaky retry behavior.
2026-05-01 13:50:34 -07:00
Ryan Crabbe
3340533cfb
fix(health): filter background-cache result by targeted model before 503 check
When use_background_health_checks is enabled, /health?model=foo returned
the full cached aggregate across every model — so an unhealthy foo
combined with any other healthy deployment kept healthy_count > 0 and
the targeted-503 path never fired.

Resolve the targeted model/model_id to a deployment-id set first
(mirroring perform_health_check's match-on-model_name-or-litellm_model
semantics) and narrow the cache to those IDs before _post_process
evaluates healthy_count, so the 503 contract holds for both the live
and cache code paths.
2026-05-01 13:50:03 -07:00