fix(team): apply team_member_budget updates to members still on the team default - #41347
Conversation
…/update applies to them Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…tion end to end Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
bugbot run |
…udget_link_default Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> # Conflicts: # litellm/proxy/management_helpers/utils.py # tests/test_litellm/proxy/management_helpers/test_management_helpers_utils.py
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit b4c5f6f. Configure here.
fix(team): apply team_member_budget updates to members still on the team default (backport of #41347 to rc/1.102.0)
…eam default Backport of BerriAI#41347 to rc/1.102.0. Cherry-picked from merge commit 4bb1ae1 (main), originally by app/devin-ai-integration. Conflicts: main's BerriAI#41349 (membership rows written through upsert) is not on this line, so add_new_member keeps its create call and still writes no membership row when no budget resolves. The picked tests are adapted to that and to this line's _check_team_member_budget, which loads the membership itself.
TLDR
Problem this solves:
/team/updatewithteam_member_budgetsilently skips existing members/team/infoshowed the new oneHow it solves it:
/team/member_addlinks members to the shared team default again/team/member_updatestill clones that row on first per-member editmax_budget_in_team,allowed_models, orbudget_durationkeep a private rowtest_team_update_reaches_inherited_members_but_not_overridden_oneswalks the whole flow throughadd_new_member,_upsert_budget_and_membership,upsert_team_member_budget_tableand_check_team_member_budgetagainst an in-memory table double, so it fails onmain(the inherited member gets a private row) and passes here (the inherited member is capped at the new team value while the overridden member keeps its own cap)User Flow
Before: an admin lowers the team's default member budget and nothing changes for the people already on the team
{"team_alias": "lit7716", "team_member_budget": 100}and get back ateam_idbudget_idandmax_budget: 100{"team_id": "...", "team_member_budget": 0.000001}and gets 200max_budget: 100After: the same update reaches every member who is still on the team default
{"team_alias": "lit7716", "team_member_budget": 100}and get back ateam_idteam-lit7716-budget-...id atmax_budget: 100{"team_id": "...", "team_member_budget": 0.000001}and gets 200max_budget: 1e-06; a member who was givenmax_budget_in_team: 50through/team/member_updatestays at 50Budget has been exceeded! TeamMember=..., and the member with their own budget still gets 200Relevant issues
Fixes #40783
Affected release
regression in v1.83.11 (#29119)
Linear ticket
Resolves LIT-7716
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
uv run pytest tests/test_litellm/<your_test_file>.py -v. Leave the suites (make test-unit-*,make test-unit) to CI: it finishes in ~15 minutes where a laptop takes an hour or more@greptileaito re-request a review after pushing changes)Delays in PR merge?
If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).
Screenshots / Proof of Fix
Shared setup: proxy on localhost:4000 with
master_key: sk-1234, oneopenai/gpt-5.4-minideployment namedgpt-5.4-mini, Postgres attached.$AUTHbelow is-H "Authorization: Bearer sk-1234" -H "Content-Type: application/json". Every chat call is a real OpenAI requestChat body used in every step:
{"model":"gpt-5.4-mini","messages":[{"role":"user","content":"say hi"}],"max_tokens":5}Before (113a416)
team-lit7716-budget-...id"content":"Hi!"), then check spend landedAfter (b4c5f6f, the merge with main)
team-lit7716-budget-...id"content":"Hi!"), then check spend landedThe merge with main picks up the membership upsert from main, which still writes the membership row when the team default budget row is gone, so
test_add_new_member_no_budget_when_default_budget_row_is_missingnow checks that the row is written without abudget_idinstead of not at allType
🐛 Bug Fix
Caveats (if any)
Medium
/team/member_updateper member or the bulk member budget UI, or re-add thembudget_durationstill gets a private clone, so later team-level changes do not reach themFinal Attestation
Link to Devin session: https://app.devin.ai/sessions/5d1eee9e522749968ae46d78e845be94
Open in Devin Desktop: https://app.devin.ai/desktop/session/5d1eee9e522749968ae46d78e845be94?variant=devin
Note
Medium Risk
Changes team member budget linking and spend enforcement semantics; members on shared rows now follow team default updates, though explicit per-member budgets and duration-only clones are unchanged.
Overview
Fixes a regression where
/team/member_addgave each member a private copy of the team default budget, so later/team/updatechanges toteam_member_budgetdid not affect them._resolve_member_budget_idnow links memberships to the team's shareddefault_team_budget_idwhen there is no explicit per-member cap or model list and nobudget_duration(after confirming the default row still exists). Cloning is kept only when a member needs a private row—explicit limits,budget_durationalone (override reset window while keeping the default's cap), or the existing window-only path when there is no team default.Docs and tests are aligned with that model: add-member cases assert no budget
create, a missing default still creates membership without abudget_id, andtest_team_update_reaches_inherited_members_but_not_overridden_oneschecks that a team-wide budget update caps inherited members while/team/member_updateoverrides stay on their own budget.Reviewed by Cursor Bugbot for commit b4c5f6f. Bugbot is set up for automated code reviews on this repo. Configure here.