Skip to content

feat(usage): search team keys beyond the top-N in the Team usage view - #42857

Merged
yassin-berriai merged 13 commits into
mainfrom
litellm_team_usage_key_search_beyond_top_n
Sep 24, 2026
Merged

yassin-berriai merged 13 commits into
mainfrom
litellm_team_usage_key_search_beyond_top_n

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

What's the problem?

The Team usage page only loads the top 100 keys by spend for the selected teams and the key search box filters that loaded page in the browser. A team key that has spend in the range but sits below the top 100 can never be found, even when you paste its exact hash or alias. This is the Team view sibling of LIT-8497 (fixed for the user view in #42827)

What's the solution?

Add a server side key search for the Team usage view that resolves the search term against every key the caller is allowed to see and aggregates only the matching keys, and have the Team usage page call it instead of filtering the loaded page

How does it fix it?

A new GET /team/daily/activity/aggregated/search endpoint takes the same team, date range, exclusion and timezone parameters as the aggregated endpoint plus a search term. It matches an exact token hash or a case-insensitive substring of the key alias or owning user id, with the caller's team membership and own-key restriction applied inside the same database filter before the result is limited, so a non-admin can never crowd out their visible matches with keys they may not see. The matched hashes then go through the existing team aggregation, so the response shape is identical to the aggregated endpoint. The route is registered for admins, internal users and view-only users alongside the existing team activity routes, and the Team usage page passes a searchKeys callback to the key activity panel, which already knows how to swap in remote results (added in #42827)

How does the product experience change?

Before: on Usage > Team Usage, typing an alias or hash of a low-spend team key into the API Keys search returned nothing. After: the same search finds the key and shows its spend, tokens and request counts for the selected range

What caveats are there, if any?

This PR is stacked on #42827's branch because the key panel's searchKeys support only exists there. GitHub retargets it to main once that merges. Excluded teams (exclude_team_ids, which the dashboard always sets to litellm-dashboard) are filtered inside the same database query as the search term, so their keys cannot use up the 100 match limit. % and _ in the search term act as SQL LIKE wildcards inside the caller's scope (same as the user sibling), which turns into a match-all within scope rather than a leak

Linear ticket

Resolves LIT-8509

How did you test this?

Live proxy on :4000 from this branch and a second proxy on :4100 from the base commit, both against the same real Postgres and Redis and a scripted upstream, seeded with two teams and six keys with real daily spend rows

Before, on the unfixed base:

curl -s -o /dev/null -w "%{http_code}\n" "http://127.0.0.1:4000/team/daily/activity/aggregated/search?search=x&start_date=2026-09-23&end_date=2026-09-25" -H "Authorization: Bearer $MASTER"
404

After, searching a team alias that only one of the three keys in the team carries:

curl -s "http://127.0.0.1:4000/team/daily/activity/aggregated/search?search=lit8509-needle&team_ids=lit8509-t1&start_date=2026-09-23&end_date=2026-09-25&timezone=0" -H "Authorization: Bearer $MASTER"
200 {"results":[{"date":"2026-09-24","metrics":{"spend":0.06,...,"total_tokens":52,"successful_requests":1,...},"breakdown":{...,"entities":{"lit8509-t1":{...,"api_key_breakdown":{"b81b3138a3a2...":{"metrics":{"spend":0.06,...}}}}}}}],"metadata":{"total_spend":0.06,...,"api_key_limit":100,"total_api_keys":1}}

The base vs head A/B kept /team/daily/activity/aggregated and /team/daily/activity byte-identical for master, a team member and a view-only member. On the head, a member without the team activity permission searching the same alias gets 200 with empty results and finds their own key when searching their user id, requesting a foreign team returns 404 "User does not belong to Team= lit8509-t2", a team admin sees the whole team, exclude_team_ids drops that team's matches, an empty search is 422, a 5000 character search and a reversed or 500 day range return 200 [], 400, 400, and 20 concurrent searches return one identical body

Integration test tests/integration/spend/test_team_daily_activity_key_search.py (real proxy, Postgres, Redis, scripted upstream) failed on the unfixed code with assert 404 == 200 and passes on this branch (3 passed, including a case where a higher-spend key in an excluded team carries the same alias and only the included team's key comes back). Unit tests in test_team_endpoints.py and test_route_checks.py were mutation checked: dropping the own-key filter from the where, removing the take limit, removing the empty-match early return, and dropping the excluded-team filter each made exactly one test fail (4 of 4 killed)

Admin UI, both dashboards logged in as admin against a Postgres seeded with 118 team keys so the needle key sits below the top 100 by spend. Steps: open http://localhost:3000/ui/ then Usage in the sidebar, pick Team Usage in the Usage View selector, open the Key Activity tab, type lit8509-needle in the API Keys search box

Before (dashboard on the base commit): the search only filters the 100 loaded keys and reports no match

Team usage key search before

After (this branch): the same search finds both needle keys with their spend and request counts

Team usage key search after

Link to Devin session: https://app.devin.ai/sessions/921009cdef674333b88e29e14f3debdc
Open in Devin Desktop: https://app.devin.ai/desktop/session/921009cdef674333b88e29e14f3debdc?variant=devin
Requested by: @yassin-berriai

yassin-berriai and others added 4 commits September 23, 2026 23:53
The Key Activity panel on the Usage page only searched the top-spend
keys the aggregated endpoint loads. A new /user/daily/activity/aggregated/search
route matches verification tokens by hash, alias, or user id and aggregates
spend for the matches; the panel debounces to it when the loaded set is
truncated. Entity panels stay local-only.

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

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Adds GET /team/daily/activity/aggregated/search, which resolves a search term against the
verification tokens the caller may see (team membership and own-key scoping applied inside the
Prisma where before take) and aggregates litellm_dailyteamspend for the matched hashes. The Team
usage view passes a searchKeys callback to KeyActivityPanel so keys outside the loaded top-N are
found server side

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

Copy link
Copy Markdown
Contributor Author

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@greptile-apps

greptile-apps Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

The PR appears safe to merge; no actionable new issue or outstanding previous finding remains.

Summary

Adds server-side API-key search to the Team usage view so authorized users can find keys beyond the top-spend subset.

  • Introduces a scoped team activity search endpoint with team, own-key, and exclusion filters applied before limiting matches.
  • Connects the Team usage dashboard’s key search to the new endpoint.
  • Registers the route for applicable roles and adds unit, authorization, integration, and UI-facing API coverage.
  • Changes since the previous review only trim the endpoint documentation and regenerate the corresponding schema description.

Reviews (3) · Last reviewed commit: "chore(usage): regenerate dashboard api t..."

Comment thread litellm/proxy/management_endpoints/team_endpoints.py
@codecov

codecov Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.66667% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...tellm/proxy/management_endpoints/team_endpoints.py 88.88% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

…rch call under max-params

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

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

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

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

Copy link
Copy Markdown
Contributor Author

@greptileai

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

bugbot run

Comment thread litellm/proxy/management_endpoints/team_endpoints.py Outdated
Comment thread litellm/proxy/management_endpoints/team_endpoints.py
…mary

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

Copy link
Copy Markdown
Contributor Author

@greptileai

Base automatically changed from litellm_usage_key_search_beyond_top_n to main September 24, 2026 20:04
@yassin-berriai
yassin-berriai requested a review from a team September 24, 2026 20:04
@yassin-berriai
yassin-berriai merged commit c2eb549 into main Sep 24, 2026
94 of 95 checks passed
@yassin-berriai
yassin-berriai deleted the litellm_team_usage_key_search_beyond_top_n branch September 24, 2026 20:04
yuneng-berri added a commit that referenced this pull request Sep 27, 2026
… global spend rollup code from rc/1.104.0 (#43385)

* Revert "feat(proxy): server-side Team Usage export beyond the top-N key cap (#42996)"

This reverts commit 77eccac.

* Revert "feat(usage): search team keys beyond the top-N in the Team usage view (#42857)"

This reverts commit c2eb549.

* Revert "feat(usage): search keys beyond the top-N usage subset (#42827)"

This reverts commit 5a8ec13.

* Revert "Merge pull request #41324 from BerriAI/litellm_daily_global_spend_table"

Removes the daily global spend rollup job and its reads. Keeps the
LiteLLM_DailyGlobalSpend model and migration so databases that already
applied it are untouched and no new proxy-extras version is needed.

This reverts commit 87694c2, reversing changes made to its first parent.

* Revert "Merge pull request #41293 from BerriAI/litellm_usage_key_free_aggregate_split"

Restores the aggregated usage query without the top-N key cap, so the
Usage pages, per-key widgets and exports cover every key again.
CacheLeakageCard keeps the date picker removal from #42055.

This reverts commit 2e46b10, reversing changes made to its first parent.

* chore: update Next.js build artifacts (2026-09-27 00:33 UTC, node v24.19.0)
devin-ai-integration Bot added a commit that referenced this pull request Sep 28, 2026
…age view (#42857)"

This reverts commit c2eb549.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
devin-ai-integration Bot added a commit that referenced this pull request Sep 28, 2026
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
yuneng-berri pushed a commit that referenced this pull request Sep 28, 2026
…sage view (#42857)" (#43377)

* Revert "feat(usage): search team keys beyond the top-N in the Team usage view (#42857)"

* revert: "feat(usage): search keys beyond the top-N usage subset (#42827)" (#43378)

* Revert "feat(usage): search keys beyond the top-N usage subset (#42827)"

* revert: "feat(proxy): add LiteLLM_DailyGlobalSpend key-free rollup for the usage dashboard (#41324)" (#43595)

* Revert "Merge pull request #41324 from BerriAI/litellm_daily_global_spend_table"

* Revert "Merge pull request #41293 from BerriAI/litellm_usage_key_free_aggregate_split" (#43596)

Co-authored-by: yassin <yassin@berri.ai>

---------

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

---------

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

---------

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

This branch is waiting to be deployed

1 waiting deployment
e2e-changed — ffc9cb4f Waiting Sep 24, 2026 by devin-ai-integration[bot] via oauth #738
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants