Commit graph

43876 commits

Author SHA1 Message Date
Tin Chi Lo
6959d9de69 test(mcp): pin the token and register wall messages for url-less servers 2026-07-21 13:53:14 -07:00
Tin Chi Lo
930676a9bf fix(mcp): let an admin-pinned issuer drive OAuth discovery for url-less servers 2026-07-21 13:53:14 -07:00
tin-berri
1d36290551
Merge pull request #34063 from BerriAI/litellm_lit4629_openapi_oauth_egress
fix(mcp): attach resolved OAuth credentials to OpenAPI spec_path tool calls
2026-07-21 13:51:17 -07:00
ryan-crabbe-berri
d2819baf0a
feat(ui): add block/unblock key action to key info page (#34116)
Adds a Block Key / Unblock Key action to the key info page, wired to the
existing /key/block and /key/unblock endpoints which previously had no UI.
The Reset Spend and Delete Key buttons move together with it into a new
overflow dropdown next to Regenerate Key, and a red Blocked tag shows next
to the key alias while the key is blocked.
2026-07-21 13:41:10 -07:00
Mateo Wang
a7e4c83013
Merge pull request #34154 from BerriAI/litellm_a2a_protocol_version_semver
fix(a2a): accept semver protocolVersion values like 0.3.0 in agent cards
2026-07-21 13:37:05 -07:00
ryan-crabbe-berri
ee0028a841
feat(ui): surface key budget_reset_at in key info and keys table (#34113)
* feat(budgets): add configurable budget_reset_time of day

Budgets reset at midnight in the configured timezone with no way to control
the time of day, so a drained daily budget surfaces as an overnight incident.
Add a litellm_settings.budget_reset_time option (e.g. "12:00") that shifts
day/week/month resets to a configurable wall-clock time in the existing
timezone, so the end of the budget window lands during business hours.

The reset time is parsed once into an immutable BudgetResetSettings and
injected into the reset job (constructor) and computation, rather than read
from a module-level global at call time. A malformed value fails fast at
startup. Sub-day durations ignore the offset. Unset preserves midnight resets.

* feat(ui): surface key budget_reset_at in key info and keys table
2026-07-21 13:35:14 -07:00
ryan-crabbe-berri
efa997dfe0
feat(budgets): add configurable budget_reset_time of day (#31007)
Budgets reset at midnight in the configured timezone with no way to control
the time of day, so a drained daily budget surfaces as an overnight incident.
Add a litellm_settings.budget_reset_time option (e.g. "12:00") that shifts
day/week/month resets to a configurable wall-clock time in the existing
timezone, so the end of the budget window lands during business hours.

The reset time is parsed once into an immutable BudgetResetSettings and
injected into the reset job (constructor) and computation, rather than read
from a module-level global at call time. A malformed value fails fast at
startup. Sub-day durations ignore the offset. Unset preserves midnight resets.
2026-07-21 13:35:01 -07:00
mateo-berri
2310211531 fix(a2a): reject malformed protocolVersion suffixes while keeping semver prereleases 2026-07-21 13:24:58 -07:00
yassin
1315ebd1f9 test(e2e): guard 0.3.0-style semver protocolVersion registration
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-07-21 20:14:21 +00:00
mateo-berri
062e58fb1d fix(a2a): accept semver protocolVersion values like 0.3.0 in agent cards 2026-07-21 13:03:47 -07:00
yuneng-jiang
257ada88cc
chore(deps): bump pypdf to 6.14.2 and pyasn1 to 0.6.4 (#34148)
Both are lock-only moves. pypdf stays inside the existing
>=6.12.0,<7.0 constraint and pyasn1 is transitive, so pyproject.toml
is unchanged.

pypdf 6.13.3 carries CVE-2026-59935 / 59936 / 59937 / 59938, resolved
across 6.14.0 through 6.14.2. pyasn1 0.6.3 carries CVE-2026-59884 /
59885 / 59886, resolved in 0.6.4. All seven are resource-exhaustion
issues reachable through parsing untrusted input; pypdf is used for
page text extraction in the RAG ingestion file parser.

Scanning the lock before and after with CPE matching enabled takes the
count for these two packages from seven to zero.
2026-07-21 13:01:18 -07:00
yuneng-jiang
ae2f276d19
ci(image-scan): match Python packages against CPE data (#34136)
grype defaults match.python.using-cpes to false, so PyPI packages are
matched only against the GitHub Advisory Database. When a CVE is
published to NVD but its GHSA has not propagated to the global advisory
database, the scan reports clean even though grype's own database
already carries the NVD record with the correct version ranges.

The pypdf CVEs (CVE-2026-59935 / 59936 / 59937 / 59938, analyzed in NVD
since 2026-07-08) are the case that exposed this; their GHSA IDs are
still repo-level and return 404 from the global advisory API, so the
ecosystem matcher has nothing to match on.

Enabling CPE matching for Python closes that gap. Measured against a
v1.91.1 build the finding count goes from 28 to 38; the additions are
mostly actionable, and the few cross-product CPE collisions cannot fail
the build because --only-fixed drops the ones carrying no fix version
and the remainder land below the --fail-on high threshold.
2026-07-21 12:56:56 -07:00
yuneng-jiang
fcd236097e
fix(interactions): add queued to the Interaction status enum (#34135)
Google added a queued value to Interaction.status in the live Interactions
OpenAPI spec, so the compliance canary test_status_enum_values started
failing on every open PR. The exact-match assertion is deliberate; it is
how we find out the spec moved, so this adds the new value rather than
loosening the check, and mirrors it into the generated Status enums so
InteractionStatus stays truthful.
2026-07-21 12:36:21 -07:00
ryan-crabbe-berri
01d624e860
fix(ui): add tooltip to the Active key status badge (#34109) 2026-07-21 12:01:17 -07:00
yuneng-jiang
212a9213c4
refactor(ui): migrate agents table onto the shared DataTable (#34089)
* refactor(ui): migrate agents table onto the shared DataTable

Replace the hand-rolled tremor table inside AgentsPanel with the shared
DataTable, splitting the surface into a data-owning panel, a thin
AgentsTable consumer, and a getAgentsTableColumns definition composed
from the shared cell library.

Row delete moves from an inline icon button into the per-row overflow
menu, and the health-check toggle moves into the table toolbar since it
controls which rows the server returns. The loading skeleton is now
initial-load-only, so refetches keep the current rows on screen.

Drops the last @tremor/react import from AgentsPanel, so its
grandfathered eslint suppressions are pruned from the baseline.

* fix(ui): keep agents ordering and token changes correct in the migrated table

Sorting by created_at went through a raw accessor, and TanStack places
undefined ahead of real values, so an agent with no created_at jumped to
the top of the newest-first list. The pre-migration sort coerced a
missing date to epoch 0 and sorted it last; restore that by sorting on a
derived timestamp.

Reload the list when the access token changes rather than leaving the
previous token's rows on screen: show the skeleton for the new token,
drop the rows if that load fails, and ignore a superseded response so a
slow earlier request cannot overwrite newer rows. Refetches triggered by
delete or the health-check toggle still keep their rows.

Tests also reset the networking mocks between cases so an unconsumed
mockResolvedValueOnce queue cannot leak into the next test.
2026-07-21 10:28:49 -07:00
yucheng-berri
049c6836d2
fix(model_armor): sanitize error details by default (#33908)
* fix(model_armor): sanitize error details by default

Generated with AI

Co-Authored-By: Claude Code

* fix(model_armor): sanitize handler-raised HTTP errors and redact scanned content in guardrail logging

The async HTTP handler raises MaskedHTTPStatusError on any non-2xx via
raise_for_status, so the non-200 branch in make_model_armor_request never ran
against a live API and the raw upstream body reached callers and logs. Catch
the raised error and build the sanitized detail from the response status

Replace the empty-dict guardrail logging payload with field-level redaction of
the keys that echo scanned content (text, sanitizedText, findings) so guardrail
traces keep filter states and block reasons while scanned content stays out

Restore the upstream status code in the sanitized error detail, read guardrail
metadata from the same key the hooks write, and keep guardrail_status within
its typed literal values

* fix(model_armor): bound redactor recursion depth and allowlist it in the recursion detector

_redact_scanned_content walks provider JSON bounded by _REDACT_MAX_DEPTH=20 and
fails closed by returning the redaction sentinel at the cap

* fix(model_armor): honor fail_on_error for upstream API failures

API failures now raise a dedicated ModelArmorAPIError so hooks can tell them
apart from content-block HTTPExceptions; fail_on_error=False lets the request
proceed on a Model Armor outage again while fail-closed configs get the same
sanitized 400 as before

Also addresses review notes: sanitize_error_detail constructor annotation
matches the nullable config field, redaction is owned by the metadata write
sites so _process_response no longer re-applies it, and the request and
response debug log branches move into helpers

* test(model_armor): cover fail_on_error routing on during-call, post-call, streaming, and file-scan paths

* chore: remove accidentally committed pytest cache files

* fix(model_armor): keep sanitize_error_detail coerced across in-memory config reloads

update_in_memory_litellm_params assigns raw LitellmParams fields, so a hot
reloaded config carrying an explicit null would silently disable sanitization;
re-apply the only-explicit-False-opts-out coercion after the update

* fix(model_armor): redact matched malicious URIs and reuse the shared recursion depth constant

maliciousUriMatchedItems echoes the caller-supplied URL including path and
query, so it joins the scanned-content key set; the redactor depth cap now
comes from DEFAULT_MAX_RECURSE_DEPTH in litellm constants instead of a local
literal

* fix(model_armor): keep API failures out of the intervention trace status

Fail-closed upstream failures re-raise ModelArmorAPIError instead of
converting to HTTPException(400), so the shared guardrail logging keeps
recording them as guardrail_failed_to_respond while content blocks stay
guardrail_intervened. Callers see the same 500 shape as before this PR,
with the sanitized message

* chore(model_armor): drop explanatory comment per repository comment policy

---------

Co-authored-by: eugene-yao-zocdoc <eugene.yao@zocdoc.com>
2026-07-21 10:28:24 -07:00
yuneng-jiang
4647f85958
Merge pull request #34078 from BerriAI/litellm_/elated-thompson-4a0c84
refactor(ui): migrate access groups table to shared DataTable
2026-07-21 10:28:21 -07:00
yuneng-jiang
5beb0a735d
Merge pull request #34079 from BerriAI/litellm_/wizardly-bardeen-a47430
refactor(ui): migrate memory table onto shared DataTable
2026-07-21 10:28:10 -07:00
yuneng-jiang
0b4851dd81
Merge pull request #34081 from BerriAI/litellm_/gallant-kapitsa-a809e0
refactor(ui): migrate organizations table onto shared DataTable
2026-07-21 10:27:59 -07:00
yuneng-jiang
925beda06d
Merge pull request #34080 from BerriAI/litellm_/brave-bell-58da35
refactor(ui): migrate audit logs table onto shared DataTable
2026-07-21 10:27:48 -07:00
Mateo Wang
59ebe043c2
Merge pull request #34106 from BerriAI/litellm_gemini_36_flash_35_lite_day0
feat(gemini): day-0 pricing for gemini-3.6-flash and gemini-3.5-flash-lite
2026-07-21 10:23:14 -07:00
ryan-crabbe-berri
e20d3d4ecc
fix(ui): serve /ui/assets from the nginx image instead of SPA fallback (#34066) 2026-07-21 09:22:02 -07:00
mateo-berri
e411d637b3 feat(gemini): day-0 pricing for gemini-3.6-flash and gemini-3.5-flash-lite 2026-07-21 08:50:40 -07:00
CrypticDriver
b61484e6c9 feat: add Amazon Bedrock AgentCore Web Search as a native search provider
Adds 'agentcore' to SearchProviders, backed by an AgentCore Gateway
web-search connector target (MCP tools/call over Streamable HTTP).

Web Search on Amazon Bedrock AgentCore is an AWS-managed web index
(GA June 2026). Exposing it as a native search provider lets Bedrock
users enable Claude Code / Anthropic-native WebSearch through
websearch_interception with a pure-YAML config and AWS-native auth,
keeping the whole search path inside AWS.

Implementation:
- New AgentCoreSearchConfig (litellm/llms/bedrock/search/) reusing
  BaseAWSLLM credential resolution. Auth follows the gateway's inbound
  authorizer type: AWS_IAM gateways get a SigV4-signed request
  (explicit aws_access_key_id/aws_secret_access_key params or the
  default credential chain); CUSTOM_JWT gateways get an OAuth2 bearer
  token via api_key / AGENTCORE_GATEWAY_TOKEN
- SigV4 signing region is derived from the gateway URL so callers
  don't need aws_region_name to match their default region
- Adds an optional sign_request() hook to BaseSearchConfig (no-op by
  default) and teaches the search HTTP handler to send a signed body
  verbatim, mirroring the existing anthropic_messages/chat pattern
- Handles both plain-JSON and SSE-framed MCP responses, propagates
  MCP errors, truncates queries to the 200-char gateway limit

Tested:
- 13 unit tests: payload/signing, explicit AKSK passthrough, bearer
  token via api_key and env, query truncation, SSE frames, MCP error
  propagation, region derivation
- Verified end-to-end against real AWS_IAM and CUSTOM_JWT gateways,
  including full Claude Code CLI WebSearch round-trips through the
  proxy with websearch_interception
2026-07-21 15:30:47 +00:00
Yuneng Jiang
ff8d8797dd
test(ui): pin memory table page-size behavior on the last page
Changing rows-per-page while on the last page recomputes the page
index from the top visible row, so the table lands on the new last
page instead of an out-of-range one. Pin that, since it depends on
the parent holding the full PaginationState rather than just the
page index.
2026-07-20 23:26:27 -07:00
Arjun Pakhan
163ab6e34b fix(batches): refine bedrock cancel_batch type hints and validation error handling 2026-07-21 06:24:17 +00:00
Arjun Pakhan
fc36825dfd fix(batches): support AWS Bedrock batch cancellation via StopModelInvocationJob (#33986) 2026-07-21 06:16:02 +00:00
Yuneng Jiang
879a287ba9
refactor(ui): migrate organizations table onto shared DataTable
The organizations admin table was a hand-rolled tremor/antd table in a single
snake_case file. This moves it onto the shared DataTable and cell library the other
migrated tables use, splitting it into a data-owning OrganizationsPanel, a thin
OrganizationsTable consumer, and a getOrganizationsTableColumns module

The models column no longer uses a per-row accordion whose expand state lived in the
parent; it renders the shared ModelsCell with truncation and a "+N more" tooltip,
matching every other table with a models column. Row actions (Edit, Delete) move into
a per-row overflow menu gated to proxy admins, while the detail view, create modal,
and delete modal stay in the panel. The server-side org id / org alias search stays
wired to the useOrganizations hook, and the table gains an initial-load skeleton plus
a search-aware empty state. The dead sort_by / sort_order filter fields, the misnamed
"Info" column that only ever showed a member count, and an unused refresh affordance
are dropped; the default created_at descending sort is preserved
2026-07-20 22:24:28 -07:00
Yuneng Jiang
e3b453fd0a
refactor(ui): migrate audit logs table onto shared DataTable
Move the Audit Logs table off the hand-rolled antd Table/Pagination onto the
shared DataTable and cell library, matching the other migrated admin tables
(Teams, Virtual Keys, Guardrails)

The single audit_logs.tsx is split into three PascalCase files: AuditLogsPanel
owns the data (server useQuery, pagination and filter state, the row-detail
drawer, and the enterprise preview gate), AuditLogsTable is a thin DataTable
consumer, and AuditLogsTableColumns exposes getAuditLogsTableColumns. The
AuditLogEntry type moves out of the request-logs columns.tsx into the audit
columns file, and AuditLogDrawer stays in the parent unchanged

Server pagination is wired through paginationMode="server" with the shared
footer replacing the standalone antd Pagination, keeping keepPreviousData
semantics so page flips keep rows visible and only the initial load shows the
skeleton. The six filters (Object ID, Changed By, Team ID, Key Hash, Action,
Table) move into a DataTableFilterDrawer plus toolbar with active-filter chips,
each resetting the page to the first. The Object ID cell is the clickable
identity cell that opens the drawer; there is no whole-row navigation, no
selection, and no per-row actions since the table is read-only

The enterprise query is now also gated on premiumUser so the preview path no
longer fires a doomed request for non-premium users
2026-07-20 22:23:54 -07:00
Yuneng Jiang
3a55dda7ec
refactor(ui): migrate memory table onto shared DataTable
Move the admin dashboard Memory table off the hand-rolled antd
<Table> onto the shared DataTable and cell library, matching the
pattern already used by Teams, Virtual Keys, and Guardrails.

MemoryView keeps the data (server useQuery, mutations) and owns the
detail drawer, edit modal, and delete modal; it now renders a thin
MemoryTable consumer plus a getMemoryTableColumns columns file. The
server pagination moves the full PaginationState up to the parent so
the shared footer's rows-per-page selector works, the key-prefix
search runs through the shared toolbar and resets the page on change,
and per-row view/edit/delete collapse into a single overflow menu.
Sorting stays off since the backend returns updated_at DESC.

The old page-reset effect is gone (the page now resets inside the
search handler), so its react-hooks/set-state-in-effect suppression
is pruned. The detail drawer moves into its own MemoryDetailDrawer
component to keep the parent under the complexity budget.
2026-07-20 22:22:28 -07:00
yuneng-jiang
c1b6c4062e
Merge pull request #34070 from BerriAI/litellm_/remaining-table-complexity-053477
refactor(ui): migrate available teams table onto shared DataTable
2026-07-20 21:52:34 -07:00
Mateo Wang
7e66f00fca
Merge pull request #34068 from BerriAI/litellm_codex_auto_drop_params 2026-07-20 23:45:29 -04:00
Mateo Wang
e3f7019fee
Merge pull request #34058 from BerriAI/litellm_mantle_codex_additional_tools
fix(bedrock_mantle): gate unsupported service_tier on drop_params for the Responses API
2026-07-20 23:41:53 -04:00
Yuneng Jiang
484cc12ab6
fix(ui): ignore stale available-teams fetch on unmount or token change 2026-07-20 20:35:51 -07:00
mateo-berri
fadec17a0f Merge origin/litellm_internal_staging into litellm_mantle_codex_additional_tools (resolve overlap with #33228 hoist) 2026-07-20 20:30:34 -07:00
Mateo Wang
07a355e867
Merge pull request #33228 from lyb0307/litellm_bedrock_mantle_codex_additional_tools
fix(bedrock_mantle): hoist Codex additional_tools input items to top-level tools
2026-07-20 23:14:47 -04:00
Yuneng Jiang
fe57eedb5c
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_/remaining-table-complexity-053477 2026-07-20 20:08:50 -07:00
Yuneng Jiang
99f215df68
refactor(ui): migrate available teams table onto shared DataTable 2026-07-20 20:08:42 -07:00
tin-berri
c9b50120ae
Merge pull request #34059 from BerriAI/litellm_lit4629_google_registry
fix(mcp): add Google Sheets, Drive, Calendar, and Docs to the OpenAPI registry
2026-07-20 20:08:21 -07:00
Mateo Wang
464537a12d
Merge pull request #34047 from BerriAI/litellm_shared_key_capability_flags
fix(router): propagate capability flags to shared backend cost map key
2026-07-20 23:05:58 -04:00
mateo-berri
d2b573c37d feat(proxy): auto-enable drop_params for Codex user agents 2026-07-20 19:58:47 -07:00
mateo-berri
354f3971a9 fix(bedrock_mantle): gate unsupported service_tier on drop_params for the Responses API 2026-07-20 19:49:42 -07:00
Tin Chi Lo
8441ff3a6c style(mcp): wrap the resolve_openapi_upstream_auth call to the 120 col limit 2026-07-20 19:40:59 -07:00
Tin Chi Lo
040aa9d896 fix(mcp): never promote caller oauth2 headers to the resolved credential on the v1 arm 2026-07-20 19:33:46 -07:00
mateo-berri
8745f355a4 fix(bedrock_mantle): log additional_tools hoist at debug level 2026-07-20 19:33:31 -07:00
yucheng-berri
9ad8698aab
feat: add deepkeep as custom guardrail (#33844)
* adding deepkeep as custom guardrail

* adding deepkeep as a custom guardrail

* adding deepkeep as a custom guardrail (hooks)

* adding litellm/proxy/_experimental/out/ to .gitignore

* adding deepkeep as custom guardrail in litellm

* removing sentinel_fortress

* comparing schema.prisma files

* fix(deepkeep): address greptile review comments

- extra_headers: fix type annotation (list -> Dict[str, str]) and actually
  merge them into _build_request_headers() so user-configured headers
  reach the DeepKeep API
- user_api_key_hash: only fall back to user_api_key_token when no
  explicit hash is already set, avoiding silent overwrite
- apply_guardrail: preserve tool_calls and structured_messages in the
  return value so downstream callers don't lose that content

Adds tests for all four fixes.

* fix(deepkeep): address greptile review comments

- extra_headers: fix type annotation (list -> Dict[str, str]) and actually
  merge them into _build_request_headers() so user-configured headers
  reach the DeepKeep API
- user_api_key_hash: only fall back to user_api_key_token when no
  explicit hash is already set, avoiding silent overwrite
- apply_guardrail: preserve tool_calls and structured_messages in the
  return value so downstream callers don't lose that content

Adds tests for all four fixes.

* fix: add missing __init__.py and allowlist entries for upstream merge

- tests/test_litellm/proxy/client/__init__.py: fixes pytest collection
  collision with tests/test_litellm/models/test_models.py (same basename)
- tests/test_litellm/models/__init__.py: same fix
- backend/routes/allowlist.py: add /config_overrides/ and /v1/unified_access_group
  prefixes for new routes added by upstream

* fix(ui/tests): resolve frontend-lint failures in new test files

- useLogDetails.test.ts: add Wrapper.displayName, replace 'null as any'
  with null, type resolveCall promise resolver properly
- usePaginatedDailyActivity.test.ts: remove unused waitFor import,
  add Wrapper.displayName, change Record<string,any> to Record<string,unknown>
- UsageViewSelect.adminFiltering.test.tsx: replace all props:any with
  explicit SelectProps/BadgeProps/SelectOption types, replace (X as any).displayName
  with direct X.displayName assignment

no-explicit-any count: 2034 (budget: 2040). Prettier check: clean.

* fix(ui): sync proxy/_experimental/out/ exactly to upstream

245 stale JS chunk files from earlier merges were left in the out/
directory but had been deleted in upstream. The Docker image in CI is
built by copying this directory verbatim, so the stale artifacts caused
the SERVER_ROOT_PATH redirect E2E to fail.

Synced by: git checkout upstream/litellm_internal_staging -- out/ (adds
new files) + git rm on every file present in HEAD but absent from
upstream.

* Update litellm/proxy/guardrails/guardrail_hooks/deepkeep/deepkeep.py

Co-authored-by: veria-ai[bot] <224490171+veria-ai[bot]@users.noreply.github.com>

* fix(makefile): fall back to upstream/litellm_internal_staging for strict-budget gate

origin/litellm_internal_staging exists on BerriAI's CI but not on forks
that use a different remote name (e.g. Azure DevOps as origin).  Fall
back to upstream/litellm_internal_staging when the origin ref is absent.

* linter reformat

* fix(deepkeep): apply guardrail tool/tool_call redactions from API response

When DeepKeep returns GUARDRAIL_INTERVENED with redacted tools or
tool_calls, the previous code ignored those redactions and forwarded
the original (potentially sensitive) values to the model — a guardrail
bypass for content embedded in tool schemas or function arguments.

Fix: prefer response_json["tools"] / response_json["tool_calls"] when
present, falling back to the originals only when the guardrail did not
return replacements — consistent with the existing pattern for texts and
images.

Refactor _build_return_inputs() into a private static helper to keep
apply_guardrail() under the PLR0915 statement limit (50).

Adds test_apply_guardrail_applies_tool_redactions_from_response to
assert that redacted tool payloads from the API response are used.

* Update litellm/proxy/guardrails/guardrail_hooks/deepkeep/deepkeep.py

Co-authored-by: veria-ai[bot] <224490171+veria-ai[bot]@users.noreply.github.com>

* fix(lint): move base-ref fallback into ruff_strict_gate.py; revert Makefile

The previous Makefile fix had a shell bug: 'git rev-parse --verify'
writes the resolved SHA to stdout, so the $$(...) substitution captured
both the SHA and the echo output, handing '--base <sha>\norigin/...' as
two tokens to the Python script, causing exit code 1 in CI.

Fix: revert Makefile to its original single-line invocation and add
_resolve_base() to ruff_strict_gate.py. The function checks whether the
requested ref resolves; if not, it tries the 'upstream/' equivalent
before falling back to the original ref (letting git emit a clear error).

Behaviour in BerriAI CI: origin/litellm_internal_staging resolves → used
as before, no change.
Behaviour on forks with a different 'origin': falls back to
upstream/litellm_internal_staging transparently.

* fix(lint): fix UP006/UP045/F401 in changed files; add depth guard to check_any_discipline

- Replace Dict/List/Optional/Tuple typing imports with built-in equivalents
  (UP006, UP045) across files touched in this PR diff, then clean up
  the now-unused typing imports (F401).
- Add _MAX_CONTAINS_ANY_DEPTH guard to check_any_discipline.contains_any()
  to prevent RecursionError on deeply-nested mypy types.

* fix(lint): resolve all three CI lint job failures

1. lint (ruff_strict_gate) — UP006/UP045/F401 violations introduced on
   changed lines. Fixed Dict/List/Optional/Tuple → built-in equivalents
   across every file in the PR diff; cleaned up now-unused typing imports.

2. any-discipline — RecursionError in check_any_discipline.contains_any()
   on deeply-nested mypy types. Upstream fixed this by converting to an
   iterative stack-based algorithm (merged). Also added deepkeep.py to
   any-discipline-budget.json via 'make lint-any-budget-update' so the
   new file's Any count is baselined instead of failing against the
   zero-baseline default.

3. basedpyright reportMissingParameterType — **kwargs in DeepKeepGuardrail
   __init__ lacked a type annotation. Added **kwargs: Any.

* Update litellm/deepkeep_tilt_config.yaml

Co-authored-by: veria-ai[bot] <224490171+veria-ai[bot]@users.noreply.github.com>

* fix(lint): black reformat after merge

* fix(deepkeep): honour empty-list replacements in _build_return_inputs

When DeepKeep returns GUARDRAIL_INTERVENED with an intentional empty
replacement (e.g. texts:[], tool_calls:[]) the previous truthiness check
treated [] as absent and forwarded the original content downstream —
a guardrail bypass for any case where the firewall wants to fully clear
a field.

Fix: replace all response_json.get(field) truthiness checks with
'is not None' comparisons so that an empty list is respected as a
deliberate replacement. Applies to texts, images, tools, tool_calls,
and the original-input fallback guards.

Adds test_apply_guardrail_honours_empty_list_replacements.

* fix(test): replace live httpbin.org call with mocked transport in test_pass_through_with_httpbin_redirect

Root cause of OOM: the test made a real HTTP request to https://httpbin.org
inside a pytest-xdist worker. Under memory pressure the worker's httpx client
and redirect-following logic allocated enough virtual memory to trip the OOM
killer (confirmed by ulimit -v 16GB reproducing the crash with 'node down: Not
properly terminated' on this exact test).

Fix: replace the real network call with a custom httpx.AsyncBaseTransport that
returns a pre-built 302 -> 200 response sequence in-memory. The test now runs
hermetically with no network dependency and no excess memory allocation.

ulimit -v 16GB: 24,284 passed (0 crashes) after this fix.

* fix: merge upstream/litellm_internal_staging (197 commits), resolve conflicts

7 conflicts resolved:
- 6 Python files: upstream added new code with old-style typing (Optional,
  Dict, List) on lines where we had ruff-fixed modern syntax (str | None,
  dict, list). Took upstream's version then re-ran ruff UP006/UP045/F401
  --fix to keep both the new content and ruff compliance.
- test_openapi_compliance.py: upstream replaced 'role' with 'steps' in
  output_fields and updated the spec comment. Took upstream's version.

Also: added _resolve_base() fallback to type_check_gate.py and removed
the hard 'git fetch origin litellm_internal_staging' from the Makefile's
lint-basedpyright target (same pattern as ruff_strict_gate.py fix).

* fix: merge upstream (41 commits), resolve .gitignore conflict, fix BLE001

- .gitignore: upstream removed package.json/out/ ignore entries; took theirs
- deepkeep.py: added '# noqa: BLE001' on catch-all Exception handler
  (BLE001 rule newly enforced in ruff-strict-budget)
- type_check_gate.py: added _resolve_base() fallback for basedpyright gate
- Makefile: removed hard 'git fetch origin' from lint-basedpyright target

* fix: merge upstream (57 commits), resolve conflicts

- Makefile: upstream added lint-fetch-base target; made it tolerant of
  missing origin/litellm_internal_staging (git fetch || true)
- test_websearch_chat_completion.py: took upstream's new assertions and
  skipif marker
- anthropic_cache_control_hook.py: upstream added new code using List/Dict/Tuple
  which were undefined after our earlier UP006 cleanup; replaced with
  built-in list/dict/tuple

* fix(coverage): revert ruff UP006/UP045 changes on upstream files

The previous ruff fixes (Dict→dict, Optional→X|None) on 7 upstream files
added ~500 changed lines of pure type-annotation no-ops to our PR diff.
codecov/patch penalised these uncovered lines, dropping patch coverage
to 51.35% (target 61.83%).

Fix: revert these files to exactly match upstream/litellm_internal_staging.
The ruff_strict_gate still passes because the violations exist equally in
both the base and HEAD (total == base_count → no breach).

* fix: merge upstream (130 commits), resolve Makefile + base_email conflicts

- Makefile: upstream changed lint deps to $(LINT_DEP_INSTALL)/$(LINT_DEP_BASE);
  kept our --base removal (handled by _resolve_base in Python scripts)
- base_email.py: took upstream's dedup cache addition
- deepkeep.py: ruff format after merge

* chore: remove lint/format-only changes and non-feature files

Revert all lint-infra and black/ruff-reformat-only changes back to
upstream/litellm_internal_staging so the PR diff shows only the DeepKeep
guardrail feature:
- Makefile, scripts/ruff_strict_gate.py, scripts/type_check_gate.py
  (lint-gate infra)
- credential_migration.py + enterprise/* + assorted test files
  (black-reformat / xdist test-isolation drift)
- backend/routes/allowlist.py (merge glue)
Remove non-feature local artifacts: build-and-push.sh,
deepkeep_tilt_config.yaml, stray __init__.py collision shims, and
unrelated UI test files.

* fix(lint): add reason to BLE001 noqa to satisfy type-discipline gate (LIT003)

The type-discipline budget ratcheted LIT003's ceiling to 292 as upstream
fixed reasonless suppressions, so our '# noqa: BLE001' (code but no
reason) tipped the total to 293 and failed CI. Add a reason per the
required '# noqa: CODE  # <reason>' shape.

* fix(deepkeep): apply structured_messages redactions returned by the guardrail API

_build_return_inputs dropped any structured_messages the DeepKeep API returned and
always forwarded the original input, so redactions on that field never took effect.
Check the response first, same as texts/images/tools/tool_calls

* chore(ui): drop redundant preserve prop from the guardrail form

preserve defaults to true in rc-field-form (isMergedPreserve falls back to true when
unset), so the explicit prop changed nothing and only widened this PR's blast radius
to every guardrail provider in the shared form

* fix(deepkeep): stop extra_headers list from crashing the guardrail call and name the real firewall id config key

litellm_params.extra_headers is a list of header names to forward, so passing it
straight into dict.update raised ValueError and, under fail_closed, took the request
down with it. Only merge mapping values and warn otherwise

The docstring example and the missing-secret error both said firewall_id, but
initialize_guardrail only reads deepkeep_firewall_id, so anyone following them
had their value silently ignored

* refactor(proxy): drop normalize_callback change; split to its own PR (#33905)

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

---------

Co-authored-by: Yaniv Israel <yaniv@deepkeep.ai>
Co-authored-by: DK-yaniv <164404355+DK-yaniv@users.noreply.github.com>
Co-authored-by: veria-ai[bot] <224490171+veria-ai[bot]@users.noreply.github.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-07-20 19:27:40 -07:00
bingbing
8307e3ee32 fix(bedrock_mantle): hoist Codex additional_tools input items to top-level tools 2026-07-20 19:27:33 -07:00
Tin Chi Lo
48572c9516 fix(mcp): attach resolved OAuth credentials to OpenAPI spec_path tool calls 2026-07-20 19:20:34 -07:00
Tin Chi Lo
39cdfbdd28 test(mcp): pin all four Google registry entries in the shape test 2026-07-20 19:18:42 -07:00
tin-berri
7df76fc0d8
Merge pull request #33756 from BerriAI/litellm_mcp_dcr_client_redirect_33699
fix(mcp): return the DCR client's own redirect_uris to stop the /callback self-redirect loop
2026-07-20 19:16:45 -07:00