Commit graph

38709 commits

Author SHA1 Message Date
Cursor Agent
039b26626f fix(anthropic,bedrock): reject unmapped reasoning_effort at mapping site
Both the chat completion path (AnthropicConfig.map_openai_params) and the
Bedrock Converse path (_handle_reasoning_effort_parameter) used
REASONING_EFFORT_TO_OUTPUT_CONFIG_EFFORT.get(value, value) which falls
back to the raw input on unmapped keys. Combined with _map_reasoning_effort
returning type='adaptive' for any string on Claude 4.6/4.7, garbage values
(e.g. 'disabled') could leak into optional_params['output_config']['effort']
unvalidated if map_openai_params ran without the downstream transform_request
or _validate_anthropic_adaptive_effort check.

Mirror the /v1/messages pattern: use .get(value) (no fallback) and raise
BadRequestError immediately when the value is unmapped, co-locating
validation with the mapping for defense in depth.
2026-05-03 04:18:50 -07:00
Claude
e400de4654 fix(anthropic): translate reasoning_effort on /v1/messages route
Closes the remaining QA-sweep gap on PR #27074: Bedrock Invoke
/v1/messages was silently ignoring ``reasoning_effort`` because the
shared param filter only kept native Anthropic keys, so every effort
tier collapsed to the same behavior on the wire (27/231 cells failing
across opus-4-5 / opus-4-6 / sonnet-4-6).

Map ``reasoning_effort`` to native Anthropic ``thinking`` /
``output_config.effort`` at the ``AnthropicMessagesConfig`` layer so
all four /v1/messages routes (direct Anthropic, Azure AI, Vertex AI,
Bedrock Invoke) inherit the same translation:

- Add ``reasoning_effort`` to ``AnthropicMessagesRequestOptionalParams``
  so the param filter in
  ``AnthropicMessagesRequestUtils.get_requested_anthropic_messages_optional_param``
  no longer drops it before the transformation runs.

- Add ``_translate_reasoning_effort_to_anthropic`` and call it from
  ``transform_anthropic_messages_request``. Mirrors
  ``AnthropicConfig.map_openai_params`` on the chat completion path
  (re-uses ``_map_reasoning_effort`` and
  ``REASONING_EFFORT_TO_OUTPUT_CONFIG_EFFORT``) so the two routes
  cannot drift. Pops ``reasoning_effort`` so it never reaches the wire.

- Caller-supplied native ``thinking`` / ``output_config.effort`` always
  win — same precedence as
  ``_translate_legacy_thinking_for_adaptive_model``.

- Garbage values (``""``, ``"disabled"``, ``"invalid"``) raise
  ``AnthropicError(status_code=400)`` instead of falling through and
  surfacing as 500s from the provider.

- ``"none"`` clears thinking + output_config so callers can opt out
  per request.

Also restores the non-adaptive-model test coverage on Bedrock Invoke
/v1/messages that the previous commit lost when
``test_bedrock_messages_strips_output_config`` was renamed to the
``forwards`` variant on Opus 4.7.

Adds a new test file
``test_reasoning_effort_translation.py`` covering the translation at
the shared config level (adaptive + non-adaptive models, none, garbage,
caller precedence) so all four /v1/messages routes are exercised by a
single suite.

Adds parametrized + behavioral tests on the Bedrock Invoke /v1/messages
suite covering: minimal/low/medium/high/xhigh/max mapping for adaptive
models, thinking-budget mapping for non-adaptive Opus 4.5, ``none``
clears both, garbage raises 400, explicit ``output_config`` wins.

Refs: https://github.com/BerriAI/litellm/pull/27074
2026-05-03 04:18:50 -07:00
Cursor Agent
ec022fd1bb fix(anthropic,bedrock): correct effort error message and dedupe effort_map
- Remove 'none' from the Bedrock _validate_anthropic_adaptive_effort error
  message; it was listed as a valid value but rejected by the membership
  check, leaving users in a feedback loop if they tried 'none'.
- Hoist the duplicated reasoning_effort -> output_config.effort mapping
  out of AnthropicConfig.map_openai_params and
  AmazonConverseConfig._handle_reasoning_effort_parameter into a single
  AnthropicConfig.REASONING_EFFORT_TO_OUTPUT_CONFIG_EFFORT class constant
  so the two routes cannot drift.
2026-05-03 04:18:50 -07:00
Cursor Agent
13714586b6 fix(constants): make ANTHROPIC_MIN_THINKING_BUDGET_TOKENS a plain constant
The documentation CI test (tests/documentation_tests/test_env_keys.py)
asserts every os.getenv() key in the source has a matching entry in the
litellm-docs config_settings.md table. ANTHROPIC_MIN_THINKING_BUDGET_TOKENS
tracks Anthropic's published wire-protocol minimum (1024) — it's not a
user-tunable, so making it env-overridable was wrong anyway. Drop the
os.getenv() wrapper; the value is now a plain literal.

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
2026-05-03 04:18:50 -07:00
Cursor Agent
a6c673e7b9 fix(anthropic,bedrock,vertex): forward output_config.effort + 400 on garbage reasoning_effort
Follow-up bugs surfaced by the QA sweep on PR #27039
(https://github.com/BerriAI/litellm/pull/27039#issuecomment-4363363610).

1. Stop stripping output_config.effort on Bedrock + Vertex adaptive routes.
   - Vertex AI Claude 4.6/4.7 accepts output_config.effort on rawPredict
     (verified end-to-end against us-east5 / global). The strip helper now
     no-ops for effort.
   - Bedrock Converse routes output_config into additionalModelRequestFields
     for anthropic base models so the requested adaptive tier (low/medium/
     high/xhigh/max) actually reaches the wire instead of all collapsing to
     identical thinking.
   - Bedrock Invoke chat transformation (AmazonAnthropicClaudeConfig) stops
     popping output_config from the post-AnthropicConfig request body.
   - Bedrock Invoke /v1/messages allowlist (BedrockInvokeAnthropicMessagesRequest)
     now lists output_config so the runtime allowlist filter forwards it.

2. Validate effort across Bedrock Converse so 'disabled' / 'invalid' / '' /
   unsupported tiers (xhigh/max on Sonnet 4.6 or budget-mode 4.5 models)
   surface as a clean 400 BadRequestError instead of 500.

3. ValueError -> BadRequestError throughout (AnthropicConfig.map_openai_params,
   _apply_output_config, AmazonConverseConfig._handle_reasoning_effort_parameter).
   Empty-string effort is now rejected (was silently passing the
   'if effort and ...' short-circuit).

4. Floor reasoning_effort='minimal' at the Anthropic provider minimum
   (1024 budget_tokens) via new ANTHROPIC_MIN_THINKING_BUDGET_TOKENS so it's
   a usable tier on direct Anthropic / Azure AI Anthropic / Vertex AI Anthropic /
   Bedrock Invoke (all of which 400 below 1024).

5. model_prices: dedupe duplicate supports_max_reasoning_effort key on
   claude-opus-4-7 / claude-opus-4-7-20260416.

Adds regression tests across all five affected paths; existing tests asserting
the silent-strip behavior were updated to reflect the new pass-through and
clean 400 surfaces.

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
2026-05-03 04:18:50 -07:00
Cursor Agent
2e6965381e
test(responses): replace legacy claude-4-sonnet alias in multiturn tool-call test
Anthropic's main API no longer resolves the non-canonical 'claude-4-sonnet-20250514'
alias for freshly issued keys, returning 404 not_found_error. PR #27031 already
swept three other live tests pinned to this alias to claude-haiku-4-5-20251001
but missed test_multiturn_tool_calls in the responses API suite, which is now
failing reliably on PR CI runs (e.g. PR #27074, job 1603363).

Bump the two model references in test_multiturn_tool_calls to the same
claude-haiku-4-5-20251001 snapshot used by PR #27031 -- it covers everything
this test exercises (tool calling, multi-turn) and isn't on a deprecation
schedule.

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
2026-05-03 07:48:56 +00:00
Mateo Wang
c94a8d6514
Merge pull request #27039 from BerriAI/litellm_fix_reasoning_effort_none_anthropic
Some checks are pending
Unit Tests: Caching (Redis) / caching-redis (push) Waiting to run
Unit Tests: Proxy DB Operations / auth-checks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Waiting to run
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 / 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 DB Operations / proxy-server-core (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / schema-migration (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-utils (push) Blocked by required conditions
Unit Tests: Security / security (push) Waiting to run
fix(anthropic,bedrock): omit thinking/output_config when reasoning_effort="none"
2026-05-02 01:42:50 -07:00
mateo-berri
7f3d7616b7
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_fix_reasoning_effort_none_anthropic
Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
2026-05-02 08:37:07 +00:00
Mateo Wang
4953b9e296
Merge pull request #26456 from BerriAI/litellm_hotfix_gpt-5.5-minimal-flag 2026-05-02 01:23:14 -07:00
Mateo Wang
6dd04357f6
Merge pull request #25627 from BerriAI/litellm_vertex-batch-output-transformation
feat(vertex-ai): transform batch prediction outputs to OpenAI format
2026-05-02 01:10:09 -07:00
mateo-berri
3835306c83 fix(anthropic,bedrock): omit thinking/output_config when reasoning_effort="none"
Setting reasoning_effort="none" on Anthropic chat models (direct, Bedrock
Invoke, Bedrock Converse, Vertex AI Anthropic, Azure AI Anthropic) crashed
LiteLLM with:

  litellm.APIConnectionError: 'NoneType' object has no attribute 'get'

Both the Anthropic chat transformation and Bedrock Converse called
``AnthropicConfig._map_reasoning_effort`` and assigned the ``None`` it returns
for ``"none"`` directly to ``optional_params["thinking"]``. Downstream
``is_thinking_enabled`` then did ``optional_params["thinking"].get("type")``
and crashed.

Pop ``thinking`` (and on Claude 4.6/4.7, ``output_config``) instead of
assigning ``None``, restoring the documented contract that
``reasoning_effort="none"`` means "do not enable thinking". This also
prevents downstream Anthropic 400s ("thinking: Input should be an object",
"output_config.effort: Input should be ...") if the bug were ever masked.

Verified end-to-end against the live Anthropic API and Bedrock Converse
on claude-opus-4-{5,6,7} and claude-sonnet-4-6, plus Bedrock Invoke for
Claude 4.5/4.6. Vertex AI Anthropic and Azure AI Anthropic inherit the
fixed ``map_openai_params`` from ``AnthropicConfig`` and need no further
changes.
2026-05-02 01:08:07 -07:00
mateo-berri
439217511a
feat: add opt-out flag for Vertex batch output transformation
Adds litellm.disable_vertex_batch_output_transformation (default False).
When True, afile_content returns raw Vertex predictions.jsonl untouched
so users that parse candidates/modelVersion directly are not broken.
2026-05-02 07:39:17 +00:00
Cursor Agent
480bea2111
fix: don't mutate caller's logging_obj in _try_transform_vertex_batch_output_to_openai
The method was overwriting logging_obj.optional_params, logging_obj.model,
and logging_obj.start_time on the caller's Logging instance. When invoked
from llm_http_handler.py's generic framework path, the framework's own
logging_obj (which already went through pre_call) had its properties
clobbered, causing model and start_time to reflect the last batch line's
values rather than the original call context.

Fix: create a fresh local Logging instance for the per-line transformation
instead of mutating the incoming logging_obj. The caller's object is now
left entirely untouched regardless of whether a logging_obj was passed in
or not.

Regression tests added to verify model, start_time, and optional_params
are not mutated on the caller's logging_obj.

Co-authored-by: Sameer Kankute <Sameerlite@users.noreply.github.com>
2026-05-02 07:13:25 +00:00
Cursor Agent
04133ba07d
Fix Vertex batch output logging mutation 2026-05-02 07:11:55 +00:00
Cursor Agent
12ecac6f46
test vertex file content logging forwarding
Co-authored-by: Sameer Kankute <Sameerlite@users.noreply.github.com>
2026-05-02 07:00:55 +00:00
Cursor Agent
10261e4f90
Forward Vertex file content logging context 2026-05-02 06:57:55 +00:00
Cursor Agent
9d51706502
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_vertex-batch-output-transformation
Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
2026-05-02 06:20:43 +00:00
Cursor Agent
9275eea131
Address bugbot: drop dead encode/decode helpers; preserve empty custom_id
- Remove unused _encode_gcp_label_value / _decode_gcp_label_value singular
  helpers; only the _chunks variants are actually called.
- Use 'is not None' check for custom_id so empty-string custom_ids are
  still labeled and round-trip through batch outputs.

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
2026-05-02 06:13:44 +00:00
Mateo Wang
cfa058c3e9
Merge pull request #26530 from BerriAI/litellm_oss_staging_04_25_2026
chore(staging): roll oss_staging_04_25_2026 into internal staging (output_config fix + 4 upstream sync fixes)
2026-05-01 23:10:58 -07:00
Sameer Kankute
2ba009a435
Merge pull request #26878 from BerriAI/litellm_presidio-responses-stream-passthrough
fix(guardrails): preserve responses event streams in presidio output masking
2026-05-02 11:39:11 +05:30
Cursor Agent
1ce92da9e8
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_oss_staging_04_25_2026
Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
2026-05-02 06:04:39 +00:00
Sameer Kankute
891445783c
Fix code qa 2026-05-02 11:31:31 +05:30
Cursor Agent
b07908133b
fix(cloudflare): support response_text in streaming chunk parser
Newer Cloudflare Workers AI models (e.g. Nemotron) emit 'response_text'
instead of 'response' on streamed chunks. The non-streaming path was
already updated to fall back to 'response_text' (#26385), but the
streaming chunk parser still only read 'response', which caused
streaming requests against those models to silently produce empty
content.

Mirror the non-streaming fallback in CloudflareChatResponseIterator.chunk_parser
and add a streaming test for the response_text shape.

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
2026-05-02 05:59:15 +00:00
Sameer Kankute
a5a8f39845
Merge pull request #27036 from BerriAI/litellm_internal_staging
merge main
2026-05-02 11:26:44 +05:30
Sameer Kankute
f576eb3228
Merge pull request #26960 from BerriAI/litellm_org_mcp_permissions
feat(mcp): enforce org-level MCP server and toolset permissions
2026-05-02 11:25:55 +05:30
Cursor Agent
a30bcc9a41
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_hotfix_gpt-5.5-minimal-flag
# Conflicts:
#	tests/test_litellm/llms/vertex_ai/test_vertex_ai_common_utils.py

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
2026-05-02 05:55:51 +00:00
Mateo Wang
d493606ad6
Merge pull request #25764 from BerriAI/litellm_gemini_provider_default_thinking
fix(gemini): follow provider defaults for Gemini 3 thinking
2026-05-01 22:52:21 -07:00
Sameer Kankute
d2015f0baf
Merge pull request #26161 from BerriAI/litellm_access-group-routing-fix
fix(router): constrain same-name deployment routing by access groups
2026-05-02 11:19:51 +05:30
yuneng-jiang
c3f7158b2b
Merge pull request #27008 from stuxf/fix/jwt-audience-and-issuer-verification
Some checks are pending
Unit Tests: Proxy DB Operations / proxy-runtime (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 / 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-server-core (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / schema-migration (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-utils (push) Blocked by required conditions
Unit Tests: Security / security (push) Waiting to run
Unit Tests: Caching (Redis) / caching-redis (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
fix(auth): support JWT issuer verification + warn when unscoped
2026-05-01 19:58:52 -07:00
yuneng-jiang
5d73c31b27
Merge pull request #27031 from BerriAI/litellm_/inspiring-euclid-41919d
[Test] Anthropic: Replace Legacy Claude-4-Sonnet Alias With Haiku 4.5
2026-05-01 19:42:26 -07:00
shin-berri
38ddcdabdb
Merge pull request #27032 from BerriAI/litellm_yj_may1_2
[Infra] Merge dev branch
2026-05-01 19:39:42 -07:00
Yuneng Jiang
abfaab5dc3
[Test] Anthropic Passthrough: Bump Thinking Tests Off Legacy Sonnet 4 Alias
base_anthropic_messages_test.test_anthropic_messages_with_thinking and
test_anthropic_streaming_with_thinking still pinned to
claude-4-sonnet-20250514 — the same legacy alias Anthropic no longer
recognizes under freshly issued keys. The other four tests in this base
class already use claude-sonnet-4-5-20250929; these two were missed.

Bump to claude-haiku-4-5-20251001 (supports_reasoning=true, no upcoming
deprecation). Subclasses including TestAnthropicPassthroughBasic
inherit these methods.
2026-05-01 19:33:08 -07:00
shin-berri
3372b151d0
Merge pull request #26966 from BerriAI/litellm_fix_create_release_prerelease_detection
[Fix] Release Workflow: Detect SemVer-Style Pre-Release Dev Tags
2026-05-01 19:25:19 -07:00
Yuneng Jiang
1e63be7a72
[Test] Anthropic Passthrough: Bump Streaming Cost-Injection Test To Haiku 4.5
test_anthropic_messages_streaming_cost_injection hits the proxy's
/v1/messages route, which routes via the anthropic/* wildcard to
api.anthropic.com. The 404 surfaced in the test was Anthropic's own
not_found_error propagated back through the proxy (visible from the
x-litellm-model-id hash on the response — the proxy did route).

Same root cause as the prior commit: the legacy claude-4-sonnet-20250514
alias is no longer recognized by Anthropic's main API under the new key.
Swap to claude-haiku-4-5-20251001 — same routing path, canonical model.
2026-05-01 19:22:39 -07:00
Yuneng Jiang
95ccfee7ca
[Chore] Proxy/UI: Drop stray _experimental/out/chat/index.html
This file is a regenerable UI build artifact that should not be tracked
in source. Removing so the merge into litellm_internal_staging stays clean.
2026-05-01 19:22:30 -07:00
Yuneng Jiang
e3917c9d08
[Test] Anthropic: Replace Legacy Claude-4-Sonnet Alias With Haiku 4.5
Three live-API tests pinned to claude-4-sonnet-20250514, which is a
non-canonical alias of claude-sonnet-4-20250514. Anthropic's main API
no longer resolves the legacy form under freshly issued keys, so the
tests fail with not_found_error. The token counter test pinned to
claude-sonnet-4-20250514 itself (deprecation_date 2026-05-14, two weeks
out) was on borrowed time too.

Bump all four to claude-haiku-4-5-20251001 — capability superset for what
these tests exercise (streaming, parallel tool calling, extended thinking,
token counting), no upcoming deprecation, cheaper per-token.
2026-05-01 19:10:27 -07:00
yuneng-jiang
0ff9d65f8d
Merge pull request #26944 from stuxf/fix/sso-state-cookie-binding
chore(sso): bind generic SSO state to a session cookie
2026-05-01 18:52:02 -07:00
yuneng-jiang
5614469f22
Merge pull request #26825 from stuxf/fix/oauth2-proxy-header-forgery
chore(auth): require trusted proxy for header identity auth
2026-05-01 18:47:58 -07:00
ryan-crabbe-berri
85d426c6b5
Merge pull request #26275 from BerriAI/litellm_fix-ag-not-resolved 2026-05-01 18:37:38 -07:00
Yuneng Jiang
92d3bdbb27
[Fix] Proxy/Key Management: Align Key-Org Membership Checks On Generate And Regenerate
Mirrors the membership rule on /key/update so that /key/generate and
/key/{key}/regenerate apply the same `_validate_caller_can_assign_key_org`
gate when the caller specifies an `organization_id`. Proxy admins bypass.
The check no-ops when `organization_id` is not being set.
2026-05-01 18:19:24 -07:00
yuneng-jiang
e78d87ee00
Merge pull request #27011 from stuxf/fix/project-update-cross-team-hijack
fix(proxy): close project hijacking and key org IDOR (VERIA-55)
2026-05-01 18:01:06 -07:00
Yassin Kortam
9ed2fc24bf
Merge pull request #27018 from BerriAI/litellm_otelDualHandlerSpans
[Fix] Isolate dual OTEL handlers
2026-05-01 17:59:15 -07:00
Michael Riad Zaky
10659e725f isolate dual OTEL handlers 2026-05-01 17:50:39 -07:00
yuneng-jiang
502ad94538
Merge pull request #27013 from stuxf/fix/promql-injection-spend-logs
fix(prometheus): escape api_key for PromQL string literal (VERIA-53)
2026-05-01 17:50:19 -07:00
Yuneng Jiang
b484c51a1c
[Fix] Proxy: Repair Merge Fallout In Router-Override Fallback Auth
Conflict resolution for #26968 dropped the `Iterator` typing import
(NameError at module load), left a dead `fallback_models = cast(...)`
block, and the new tests called `_enforce_key_and_fallback_model_access`
without the now-required `request` kwarg.
2026-05-01 17:48:51 -07:00
yuneng-jiang
c7c7c8f07a
Merge pull request #27028 from BerriAI/litellm_policy_does_not_work
Fix runtime policy attachment initialization
2026-05-01 17:39:56 -07:00
yuneng-jiang
c154b0df24
Merge pull request #27016 from stuxf/fix/mcp-openapi-tool-auth-bypass
fix(mcp): run pre_call_tool_check on OpenAPI/local-registry path (VERIA-7)
2026-05-01 17:38:40 -07:00
stuxf
e8818d69e0
fix(proxy): re-validate user_id after /user/info re-parses query (#27009)
* fix(proxy): re-validate user_id ownership after /user/info re-parses query

The route-level access check in `RouteChecks.non_proxy_admin_allowed_routes_check`
reads `request.query_params.get("user_id")`, which decodes literal `+` to
spaces. The endpoint then re-parses the raw query string with `urllib.unquote`
in `get_user_id_from_request` to preserve `+` characters (so plus-addressed
emails work as user_ids). Those two paths produce different ids: a caller
who registered a user_id containing a literal space could pass the route
check and then read another user's row by sending the encoded `+` form.

Add `_enforce_user_info_access` and call it after `_normalize_user_info_user_id`
returns the final id. Proxy admin / view-only admin still bypass; everyone
else must match the resolved user_id (or have no user_id, which falls back
to the caller's own id later in the handler).

Tests cover the admin bypass, owner-match path, and the cross-user lookup
that this change blocks.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(proxy): apply user_info ownership check to PROXY_ADMIN_VIEW_ONLY

`_enforce_user_info_access` was bypassing both PROXY_ADMIN and
PROXY_ADMIN_VIEW_ONLY, but the upstream route check in
`RouteChecks.non_proxy_admin_allowed_routes_check` only treats
PROXY_ADMIN as a true admin for the `/user/info` route — view-only
admins go through the `user_id == valid_token.user_id` enforcement
along with regular users. Mirroring that asymmetry left the same
encoded-`+` bypass open for view-only admins whose user_id contains a
literal space.

Drop the PROXY_ADMIN_VIEW_ONLY exemption so the post-decode re-check
matches the upstream rule. Update tests: a view-only admin must now
be blocked from cross-user lookups but still allowed to read their
own row.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: yuneng-jiang <yuneng@berri.ai>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 17:38:14 -07:00
stuxf
b80246971b
fix(batches): count non-chat tokens, validate batch-file model access (VERIA-39) (#27015)
* fix(batches): count non-chat tokens and validate every model in batch file

Two security control bypasses on POST /v1/batches:

1. `_get_batch_job_input_file_usage` only summed tokens for
   `body.messages` (chat completions). Embedding (`input`) and text
   completion (`prompt`) batches reported zero, letting massive
   non-chat workloads slip past TPM rate limits. Extend the counter
   to handle string and list shapes for both fields.

2. The batch input file was forwarded to the upstream provider
   without inspecting the models named inside the JSONL — only the
   outer `model` query parameter was checked against the caller's
   allowlist. A caller restricted to gpt-3.5 could submit a batch
   targeting gpt-4o and the upstream would execute it under the
   proxy's shared API key.

Add `_get_models_from_batch_input_file_content` (returns the
distinct `body.model` values) and call it from
`_enforce_batch_file_model_access` in the pre-call hook, which runs
each model through `can_key_call_model` so the same allowlist
semantics (wildcards, access groups, all-proxy-models, team aliases)
the proxy enforces on `/chat/completions` apply here too. Any
unauthorized model raises a 403 before the file is forwarded.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(batches): count pre-tokenized prompt/input shapes, classify 403 logs

Two follow-ups from the Greptile review on the batch validation PR:

1. P1 TPM bypass via integer token arrays. The OpenAI batch schema
   accepts ``prompt`` and ``input`` as ``list[int]`` (a single
   pre-tokenized prompt) or ``list[list[int]]`` (multiple) in addition
   to the string and ``list[str]`` shapes. Pre-fix only the string
   shapes were counted, so a caller could submit a batch with hundreds
   of millions of pre-tokenized tokens and the rate limiter would
   record zero. Extract the per-field logic into
   ``_count_prompt_or_input_tokens`` and count each int as one token.

2. P2 access-denial logs were indistinguishable from I/O failures.
   ``count_input_file_usage`` caught every exception under a generic
   "Error counting input file usage" message, so an intentional 403
   from ``_enforce_batch_file_model_access`` looked the same in the
   logs as a missing file or a Prisma timeout. Catch ``HTTPException``
   separately and log 403s at WARNING level with a security-relevant
   message before re-raising.

Tests cover the new shapes: single ``list[int]``, ``list[list[int]]``
(the worst-case bypass vector), and embeddings ``input`` with
pre-tokenized arrays.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 17:36:12 -07:00
yuneng-jiang
dbc3b1935f
Merge pull request #26968 from stuxf/chore/router-override-trust
chore(proxy): tighten router-settings-override and mock-testing trust
2026-05-01 17:26:13 -07:00