Commit graph

249 commits

Author SHA1 Message Date
devin-ai-integration[bot]
ae01882535
feat(proxy): offload spend tracking to a pod-local collector sidecar (#40545)
* feat(proxy): offload spend tracking to a pod-local spend worker sidecar

py-spy on the gateway showed the post-response _PROXY_track_cost_callback,
spend-log and DBSpendUpdateWriter work running on the inference workers'
event loop, so a DB or Redis stall backed up the request path.

When LITELLM_SPEND_WORKER_ENABLED=true, _ProxyDBLogger serializes one compact
typed SpendEvent per success and hands it to a SpendEventProducer that ships
it over a unix socket (default) or loopback-only TCP to a sidecar started as
`python -m gateway.spend_worker`. The sidecar runs the unchanged
_ProxyDBLogger pipeline against the pod's PgBouncer (pooled_database_url).
When the sidecar is unreachable, the buffer is full, or the gateway shuts
down with events still queued or in flight, the producer applies
LITELLM_SPEND_WORKER_ON_UNAVAILABLE (fallback in-process, or drop). The
sidecar half-closes producers on SIGTERM and drains, the producer treats
EOF as unavailable, and the gateway flushes buffered spend counters on
shutdown. The sidecar honors LITELLM_LOG so its writes are visible in its
own process log.

Helm: both charts gain an opt-in spend-worker sidecar container sharing an
emptyDir socket dir, and the componentized chart's HPA uses a
ContainerResource CPU metric scoped to the gateway container so sidecar
CPU does not drive inference scaling.

* feat(terraform): opt-in spend-worker sidecar for the AWS and GCP gateway stacks

Adds spend_worker_* inputs to both modules. On ECS Fargate the sidecar is a second, non-essential container in the gateway task; on Cloud Run it is a second container in the gateway service. Both listen on loopback TCP, share the gateway's DB/Redis/secret env, and set LITELLM_JOB_ROLE=spend_worker. Disabled by default. Plan-only tests cover both, and the terraform CI workflow now runs the gcp module too

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

* test(proxy): retrieve a completed batch in the in-process spend path test

The base now defers cost tracking for batches that are still in flight, so an in_progress batch never reaches update_database

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

* refactor(proxy): rename the spend worker sidecar to collector

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

* fix(proxy): run the collector from the installed litellm package and finish in-flight fallbacks on shutdown

The sidecar command becomes python -m litellm.proxy.collector so the classic image, whose runtime
stage copies only the installed package, can run it. The module now assembles DATABASE_URL and the
pod-local pgbouncer URL itself, replacing gateway/collector.py

The componentized collector sidecar inherits gateway.volumeMounts so custom CA mounts reach it.
SpendEventProducer shields an in-progress fallback from the writer task cancellation so close()
no longer loses an event already handed to the in-process pipeline

Helpers used across modules (address_argument, should_store_prompts_and_responses_in_spend_logs,
flush_spend_counters_on_shutdown) become public so the change adds no reportPrivateUsage errors

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

* ci(terraform): drop the gcp job duplicated by the aws/gcp matrix

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

* fix(collector): keep metrics env off the classic sidecar and reject shared loopback ports

The classic chart no longer hands PROMETHEUS_METRICS_PORT and the billing metrics env to the collector container, and gives it the same /.npm scratch mount as the proxy on a read-only root. AWS and GCP now refuse a plan where the spend collector and the metrics sidecar bind the same loopback port. A regression test drives a sidecar crash mid-stream on asyncio and uvloop and checks no event is billed by both the sidecar and the in-process fallback; the producer docstring spells out why a failed drain() cannot double count

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

* style(proxy): format pooled_database_url after the pgbouncer rebase

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

* fix(proxy): keep the cache-hit preset key and survive dead producers on collector drain

Cache hits updated the logging object after the early return, so the offloaded spend event carried
preset_cache_key=None and the collector re-hashed reconstructed kwargs. Also guard write_eof() against
producer transports uvloop already closed so one dead connection cannot abort the drain

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

* fix(terraform): keep the gcp collector port off the metrics sidecar health port

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

* fix(proxy): collector connects to Postgres directly under IAM or Entra token auth

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

* fix(proxy): mark the collector's DATABASE_URL as pooled when it uses the pod's pgbouncer

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

---------

Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-10 17:14:13 -07:00
Mateo Wang
dce2991085
Merge pull request #40622 from BerriAI/litellm_sanitize_unknown_model_spend_rows
fix(proxy): log rejected unknown-model requests under a placeholder model name
2026-09-10 16:21:10 -07:00
moe-berri
a36b912b45
Merge pull request #40604 from BerriAI/litellm_lit7490_classifier_audit
feat(router): log exact classifier input and masked source request
2026-09-10 15:48:05 -07:00
mateo-berri
3a0dce6bc4 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_sanitize_unknown_model_spend_rows 2026-09-10 15:47:55 -07:00
mateo-berri
a93753e73b fix(proxy): keep the model on failed rows that resolved to a configured model group 2026-09-10 15:43:27 -07:00
mateo-berri
098bfe0bbc fix(proxy): only remap prompt-shaped model strings on failed spend rows 2026-09-10 15:36:32 -07:00
mateo-berri
368de5df68 fix(proxy): log prompt-shaped model strings on pass-through failures under the placeholder model 2026-09-10 15:30:16 -07:00
Kishorekarthik P
6632e8b74f fix(proxy): let internal users read request/response for their own spend logs
The Logs drawer gets messages/response from GET /spend/logs/ui/{request_id};
the list endpoint omits those heavy columns for every caller, admins included.
That detail route was missing from LiteLLMRoutes.spend_tracking_routes, and
check_route_access anchors patterns, so /spend/logs/ui never matched it. Every
internal_user got a 403 before the handler ran and the UI fell back to the
"Request/Response Data Not Available" banner, even on their own requests

Adds the route to spend_tracking_routes so internal_user, internal_user_view_only,
admin_viewer and org_admin all inherit it, and drops the now-redundant explicit
entry from admin_viewer_routes. The handler already authorizes non-admins per row
via _assert_user_can_view_request_id, so no handler-side scoping change is needed

That helper returned silently when no spend-log row existed, which the detail
handler treats as authorized before asking every custom logger for the payload by
raw request_id. With retention pruning the row can be gone while the payload is
still in cold storage, so opening the route would have let a non-admin read
another tenant's prompt out of S3/GCS. A missing row now falls through to the
same 403 as a foreign row, which also removes the exists-but-not-yours oracle

Fixes #34099
2026-09-10 15:04:15 -07:00
moe-berri
73013124b9 fix(router): merge staging and retain native classifier audits 2026-09-10 14:24:56 -07:00
mateo-berri
fe6f615c7a fix(proxy): log rejected unknown-model requests under a placeholder model name
A request whose model field matched no configured model was rejected with 400 but its failure row still persisted the raw client string as the model, so a client that concatenated its prompt into the model field wrote that prompt into LiteLLM_SpendLogs and the daily spend tables, where /user/daily/activity/aggregated returned it as a breakdown.models key. The spend log payload now records such rejections under the constant unknown-model, keeping the failed request counted without persisting client input as a model name.
2026-09-10 14:18:54 -07:00
devin-ai-integration[bot]
46a185d3cd
feat(rust_bridge): count budget-check input tokens in Rust on all LLM routes (#40381)
* feat(rust_bridge): count budget-check input tokens in Rust on all LLM routes

Rust counts input tokens from the raw JSON body with the GIL released inside the existing budget reservation, covering every LLM route the auth dependency guards. It only fires for models on the Anthropic tokenizer when a budget is set, and Python counts whenever Rust is off, missing, or declines a body shape.

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

* perf(rust): count byte-level BPE tokens without the GPT-2 split regex (#40594)

The oniguruma run of the ByteLevel pre-tokenizer regex is about 90% of
encode_fast on a 100k token body (100 ms of the ~110 ms Rust admission
count in the gateway pod). A hand-written scanner that yields the same
pieces, then feeds the model directly, counts the same text in 10 ms.
It only engages for tokenizers with the Anthropic shape (optional NFKC,
ByteLevel without prefix space, no post-processor) and falls back to the
full encoder when the text contains an added token. Parity with
encode_fast is tested on random texts, the pieces are compared with the
real pre-tokenizer, and the \p{L}/\p{N}/\s tables are checked against
oniguruma for every code point.

NFKC runs through unicode-normalization-alignments, the crate and
Unicode tables NormalizedString::nfkc already uses, so the fast path
normalizes exactly what the full encoder would. Using the newer
unicode-normalization crate changed the count for 171 code points that
gained compatibility decompositions after Unicode 9 (U+32FF, U+A7F1..).
The fast normalizer is compared with the tokenizer's for every scalar
value and on random texts.

The scanner is built without mutable state: byte_char and mapped_len replace the const table builders and the reusable mapped buffer, and iter::successors replaces the stateful piece iterator. byte_chars_match_the_byte_level_alphabet checks the byte mapping against ByteLevel for every scalar value.

Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(rust_bridge): bound concurrent token-count encodes and share the Anthropic tokenizer predicate

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

---------

Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-10 13:56:30 -07:00
moe-berri
153c962e15 feat(router): log classifier input and masked source request 2026-09-10 12:00:18 -07:00
devin-ai-integration[bot]
6c69dd0f72
perf(proxy): reuse cached model group and deployment info in budget reservation (#40593)
Profiling the sidecar-enabled gateway at 700 rps showed ~2.4% of all samples
in get_model_group_info called per request from budget reservation, plus
get_deployment_model_info for tiered pricing tables. Both are read-only lookups
over the model list, so serve them from the Router's lru caches and clear the
deployment cache alongside the group cache when the model list changes.

The deployment-info cache is a per-router lru_cache built in __init__ rather
than a class-level decorated method, so it does not pin Router instances in a
process-wide cache and is dropped with the router.

A price data reload replaces litellm.model_cost without touching model_list, so
the reload replay also clears both caches; otherwise reservation would keep
pricing against the old catalog until an unrelated model-list change.

Co-authored-by: yassin <yassin@berri.ai>
2026-09-10 11:22:46 -07:00
devin-ai-integration[bot]
f84034f500
feat(mock): report admission-time input token count in mock_response usage (#40590)
* feat(mock): report admission-time input token count in mock_response usage

Mock completions always reported prompt_tokens=10, so spend tracking, TPM metrics, budgets and the tokens-per-minute autoscaling signal saw 10 tokens for a 100k-token request. Budget reservation now carries the admission-time input token count in the reservation record, and mock_completion reads it back so mock traffic exercises the same spend and TPM paths as real traffic without any extra tokenizer work.

* fix(mock): keep a zero admission input token count instead of falling back to 10

---------

Co-authored-by: yassin <yassin@berri.ai>
2026-09-10 11:22:26 -07:00
devin-ai-integration[bot]
996ee5635a
perf(proxy): pipeline spend counter increments into one Redis call per request (#40371)
* perf(proxy): pipeline spend counter increments into one redis call

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

* fix(proxy): apply surviving spend increments before raising scope error

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

* style(proxy): ruff format spend counter helpers

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

* fix(proxy): settle inner spend counter gathers and fall back per key on pipeline failure

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

* fix(proxy): suppress BLE001 on pipeline fallback catch

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

* fix(proxy): invalidate all batched spend counters on pipeline failure

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

---------

Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-09 10:35:50 -07:00
Mateo Wang
f8e456d105
Merge pull request #40275 from BerriAI/litellm_lit6852_spend_attribution
fix(spend-tracking): recover key alias for session tokens from spend logs
2026-09-08 19:05:43 -07:00
Mateo Wang
599daea985
Merge pull request #36718 from BerriAI/litellm_fix_count_tokens_budget_reservation_leak
fix(budget_reservation): don't reserve budget on token counting routes
2026-09-08 17:29:27 -07:00
mateo-berri
268b944081 fix(spend-tracking): bound the spend-log scan with a statement timeout and name only unanimous alias, team, and owner 2026-09-08 17:24:22 -07:00
mateo-berri
7a6c0cbf08 fix(spend-tracking): drop the owner of a digest shared by several users and back off failed scans 2026-09-08 16:43:28 -07:00
Mateo Wang
5b2b5420af
Merge pull request #39626 from BerriAI/litellm_batch_ui_logs
Some checks failed
Unit Tests / proxy-extras (push) Waiting to run
Unit Tests / proxy-infra (push) Waiting to run
Unit Tests / proxy-server (push) Waiting to run
GitHub Actions Security Analysis / zizmor (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 / proxy-utils (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / key-generation (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / logging-misc (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-runtime (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-server-core (push) Blocked by required conditions
Unit Tests / caching-local (push) Waiting to run
Unit Tests / core-utils (push) Waiting to run
Unit Tests / enterprise-package (push) Waiting to run
Unit Tests / enterprise-routing (push) Waiting to run
Unit Tests / integrations (push) Waiting to run
Unit Tests / All Other Providers (push) Waiting to run
Unit Tests / Vertex AI (push) Waiting to run
Unit Tests / misc (push) Waiting to run
Unit Tests / proxy-auth (push) Waiting to run
Unit Tests / proxy-endpoints (push) Waiting to run
Unit Tests / responses-caching-types (push) Waiting to run
Terraform Modules / fmt, validate, test (aws) (push) Has been cancelled
Terraform Modules / fmt, validate, test (gcp) (push) Has been cancelled
Terraform Provider / gofmt, vet, build, test (push) Has been cancelled
Terraform Provider / Provider endpoints vs proxy OpenAPI schema (push) Has been cancelled
feat(ui): batch observability on the logs page
2026-09-08 15:19:25 -07:00
mateo-berri
907c200b31 fix(spend-tracking): run one spend-log scan at a time and back off repeated misses
Concurrent usage reads on one worker now share a single spend-log query
instead of each scanning the same window, and a digest that comes back
nameless a second time is remembered for the full ten minutes rather than
thirty seconds, so a key that never resolves costs at most two scans per
worker per window per ten minutes. The first miss still expires after
thirty seconds so a read that lands between the daily spend flush and the
spend-log flush recovers on the next read
2026-09-08 15:00:56 -07:00
mateo-berri
0c2d0f4777 fix(spend-tracking): forget an empty spend-log lookup after thirty seconds
The daily spend rows and the spend logs of one batch are written a moment apart, so a usage read landing between them used to remember the session as nameless for ten minutes on that worker. Found identities keep the ten minute entry
2026-09-08 13:28:13 -07:00
mateo-berri
550e733bf3 perf(spend-tracking): recover key identity in one bounded spend-log pass with a per-worker cache
The spend-log lookup for permanently unresolvable digests is back to a single DISTINCT ON scan over the requested window, keeping only rows that carry an alias, user, or team so a newer nameless row cannot hide an older named one. Results and misses are cached per worker for ten minutes keyed by digest and window, failed queries are not cached, and JWT rows keyed hashed-jwt-<sha256> now pass the digest gate. Tests cover the JWT gate, cache reuse and partial misses, window changes, error handling, the with-window guard, and the daily activity wiring
2026-09-08 13:09:43 -07:00
mateo-berri
cf0488316e fix(spend-tracking): take each unresolved key's newest spend row and drop docstrings 2026-09-08 12:40:28 -07:00
mateo-berri
2285640eea fix(spend-tracking): recover key alias for session tokens from spend logs
CLI session tokens are in-memory only and never get a LiteLLM_VerificationToken
row, so the usage APIs could not resolve key_alias, team_id, or user_email for
their spend rows: the exact join and the reverse-hash recovery both miss. The
owner is written to LiteLLM_SpendLogs.metadata at request time under the same
hashed api_key, so read it back from there for keys still unresolved after the
token-table passes.

The lookup is sha256-gated like the existing reverse-hash recovery and bounded
to the records' startTime window (min date minus one day, max date plus two) so
it stays on the startTime index. No migration.

Also guard the window parser against the date=None rollup rows GROUPING SETS
aggregation emits, which raised TypeError from strptime and turned the
aggregated usage endpoints into HTTP 500s.
2026-09-08 12:02:39 -07:00
tin-berri
1a6aa98230
fix(spend): compare auto-router targets by deployment identity (#40206)
Preserve deployment identity through savings calculation, with canonical model fallback only when either ID is absent. Cover negotiated rates, unchanged deployments, alias/base-model cache accounting and missing IDs.

Fixes #38811. Based on the deployment-identity approach proposed by @QuantumBreakz in #38834.

Co-authored-by: Claude Code <noreply@anthropic.com>
2026-09-07 23:29:42 -07:00
mateo-berri
9c980b96d6 fix(budget_reservation): exempt vertex and bedrock count-tokens routes from budget reservation
Some checks failed
LiteLLM Rust / rust-lint (push) Has been cancelled
LiteLLM Rust / rust-test (push) Has been cancelled
Terraform Modules / fmt, validate, test (aws) (push) Has been cancelled
Terraform Modules / fmt, validate, test (gcp) (push) Has been cancelled
Terraform Provider / gofmt, vet, build, test (push) Has been cancelled
Terraform Provider / Provider endpoints vs proxy OpenAPI schema (push) Has been cancelled
2026-09-07 18:44:04 -07:00
mateo-berri
fb7d06da4b test(budget_reservation): type the tiny-budget reservation helper 2026-09-07 17:45:53 -07:00
mateo-berri
31bd00dad9 fix(budget_reservation): merge staging and cover count_tokens routes in the mapped test 2026-09-07 17:11:33 -07:00
tin-berri
c5ec2eedc1
fix(spend): price caching savings on the billed request basis (#40160)
Resolves LIT-7137

Co-authored-by: Claude Code <noreply@anthropic.com>
2026-09-07 21:41:05 +00:00
Mateo Wang
2cfe106f9f
Merge pull request #39660 from BerriAI/litellm_bedrock_passthrough_model_access
fix(proxy): enforce key and team model access on Bedrock passthrough routes (internal copy of #34244)
2026-09-07 12:11:15 -07:00
Mateo Wang
9b64f8367e
Merge branch 'litellm_internal_staging' into litellm_batch_ui_logs 2026-09-04 20:07:32 -07:00
mateo-berri
01dd000ccb Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_spend_logs_keep_service_account_key_readable 2026-09-04 16:33:45 -07:00
mateo
93abc3a0cd Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_registry_audit_2026_09_02 2026-09-04 19:02:44 +00:00
mateo-berri
7e51fbc819 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_batch_ui_logs
# Conflicts:
#	tests/proxy_unit_tests/test_check_batch_cost.py
2026-09-04 12:00:14 -07:00
Mateo Wang
04a198e3e3
Merge pull request #39568 from BerriAI/litellm_fix-batch-spend-key-double-hash-bcae
fix(spend-tracking): keep batch spend keys joinable after v1.99 provenance gate
2026-09-04 10:47:34 -07:00
mateo
08bfdadb10 chore: merge litellm_internal_staging into litellm_registry_audit_2026_09_02, drop the deleted ocr ledger
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-04 04:18:09 +00:00
Cursor Agent
048499cdf5
fix(spend): only reverse-hash export rows whose key alias join missed
Team and service keys often have no user_email after a successful token
join. Treating empty email as a miss hashed every verification token on
routine CloudZero and Focus exports.

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
2026-09-04 01:44:18 +00:00
Cursor Agent
33815682bc
fix(spend): keep CloudZero and Focus spend-user email when filling alias
Export rows already join user_email from DailyUserSpend.user_id. Recovered
key-owner email must not replace that when only the alias join missed.

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
2026-09-04 01:38:26 +00:00
mateo-berri
ce95afe2bd fix(spend-tracking): reverse-hash dirty spend keys in Postgres instead of paging token tables 2026-09-03 17:58:17 -07:00
mateo-berri
533a1c959c fix(proxy): reserve budget for the Bedrock Converse prompt, not the context window
Resolving the model from the /bedrock path sends passthrough calls through
optimistic budget reservation, whose tokenizer cannot walk Converse content
blocks and so fell back to the model's max_input_tokens. Count those messages
as text and read inferenceConfig.maxTokens so a budgeted key reserves the
request's cost.
2026-09-03 17:42:46 -07:00
devin-ai-integration[bot]
cf3af0f486
perf(spend): group /spend/logs summary by day in Postgres instead of per-row Prisma group_by (#39351)
* perf(spend): group /spend/logs summary by day in Postgres instead of per-row Prisma group_by

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

* refactor(spend): simplify /spend/logs daily summary aggregation

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

* fix(spend): preserve spend logs response schema

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

* chore: ratchet lint budgets after merge

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

* chore: ratchet lint budgets after merge

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

* fix(spend): compare spend log range bounds as naive UTC timestamps

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

* chore: ratchet lint budgets after merge

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

* chore: ratchet lint budgets after merge

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

* chore: ratchet lint budgets after merge

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

* chore: ratchet lint budgets after merge

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

* test: cover spend logs summary edge cases

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

* chore: ratchet lint budgets after merge

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

* test: cover spend summary request filters

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

* chore: ratchet lint budgets after merge

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

* chore: ratchet lint budgets after merge

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

---------

Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-03 23:53:59 +00:00
mubashir1osmani
bb5a960317 Merge remote-tracking branch 'berri/litellm_internal_staging' into litellm_batch_ui_logs 2026-09-03 19:45:38 -04:00
mateo-berri
f1f0294796 Merge branch 'litellm_internal_staging' of https://github.com/BerriAI/litellm into litellm_fix-batch-spend-key-double-hash-bcae 2026-09-03 16:36:12 -07:00
ryan-crabbe-berri
a53c550951
Merge pull request #39661 from BerriAI/litellm_lit_4741_copy_id_search
feat(ui): find rows by a pasted ID on keys, agents, memory, audit, and request logs
2026-09-03 16:17:59 -07:00
ryan-crabbe-berri
9464888ee9 test(proxy): pass search=None in direct ui_view_spend_logs calls
Calling the endpoint without going through FastAPI leaves the new search param set to its Query default object, which is not None, so the grouped-session and request_id lookup tests started taking the search branch

Claude-Session: https://claude.ai/code/session_01Q5sbiogJzPcCRmYSbaHxZf
2026-09-03 16:04:41 -07:00
ryan-crabbe-berri
9baa19c7d1 fix(proxy): stop hashing raw sk- values in list searches
The search= param on /key/list, /audit, and /spend/logs/ui, plus key_hash= on /key/list, now compare the pasted value verbatim. Only a copied key ID (the hash) matches, so a raw virtual key never needs to travel in a GET query string

Claude-Session: https://claude.ai/code/session_01Q5sbiogJzPcCRmYSbaHxZf
2026-09-03 15:54:42 -07:00
ryan-crabbe-berri
4811041048 feat(proxy): add a search param to key, memory, audit, and spend log listings
GET /key/list?search= matches the key hash (a raw sk- key is hashed
first) or a case-insensitive alias substring, and key_hash= now hashes a
raw sk- value too. GET /v1/memory?search= matches a key prefix or an
exact memory_id. GET /audit?search= matches id, object_id, changed_by,
or changed_by_api_key. GET /spend/logs/ui?search= matches request_id
across all time and api_key, team_id, user, end_user, session_id, or
model_id inside the date window; session grouping is skipped while a
search is active.

Claude-Session: https://claude.ai/code/session_01Q5sbiogJzPcCRmYSbaHxZf
2026-09-03 15:20:13 -07:00
Mateo Wang
117ef33a41
Merge pull request #39541 from BerriAI/litellm_spend_logs_bridged_streaming_message_id
fix(anthropic_messages): key bridged streaming spend rows on the streamed msg_ id
2026-09-03 14:36:51 -07:00
Mateo Wang
0c8510d47c
Merge pull request #39511 from BerriAI/litellm_spend_logs_provider_response_id
fix(spend_tracking): key /v1/messages spend rows on the msg_ id the client received
2026-09-03 14:35:50 -07:00