mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-29 06:33:28 +00:00
feat(budgets): schema + queue plumbing for per-team token budgets
Mirror the existing dollar budget (max_budget/spend) with a cumulative token budget: a nullable max_tokens_budget cap and a tokens_used accumulator on LiteLLM_TeamTable, reusing budget_duration/budget_reset_at for the window. A team with no max_tokens_budget set is untouched. Thread an optional per-request token delta through the spend update queue: SpendUpdateQueueItem.tokens, summed per team into a parallel team_token_list_transactions map alongside the existing spend sum, so tokens_used is flushed on the same batch cadence as spend rather than one DB write per request.
This commit is contained in:
parent
c0ca4a51f7
commit
5d06961b86
7 changed files with 33 additions and 0 deletions
|
|
@ -0,0 +1,6 @@
|
|||
-- AlterTable
|
||||
-- Cumulative per-team token budget, mirroring the existing dollar budget
|
||||
-- (max_budget / spend). max_tokens_budget is the cap (null = untracked);
|
||||
-- tokens_used is the accumulator reset on the shared budget_reset_at tick.
|
||||
ALTER TABLE "LiteLLM_TeamTable" ADD COLUMN IF NOT EXISTS "max_tokens_budget" BIGINT;
|
||||
ALTER TABLE "LiteLLM_TeamTable" ADD COLUMN IF NOT EXISTS "tokens_used" BIGINT NOT NULL DEFAULT 0;
|
||||
|
|
@ -197,6 +197,8 @@ model LiteLLM_TeamTable {
|
|||
tpd_limit BigInt?
|
||||
budget_duration String?
|
||||
budget_reset_at DateTime?
|
||||
max_tokens_budget BigInt? // cumulative token cap over budget_duration; null = untracked (mirrors max_budget)
|
||||
tokens_used BigInt @default(0) // cumulative tokens consumed in the current window (mirrors spend)
|
||||
blocked Boolean @default(false)
|
||||
created_at DateTime @default(now()) @map("created_at")
|
||||
updated_at DateTime @default(now()) @updatedAt @map("updated_at")
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@ class TeamBase(LiteLLMPydanticObjectBase):
|
|||
tpd_limit: int | None = None
|
||||
max_budget: float | None = None
|
||||
soft_budget: float | None = None
|
||||
# cumulative token cap over budget_duration (mirrors max_budget); null = untracked
|
||||
max_tokens_budget: int | None = None
|
||||
budget_duration: str | None = None
|
||||
budget_limits: list[BudgetLimitEntry] | None = None
|
||||
models: list[str] = []
|
||||
|
|
@ -86,6 +88,7 @@ class TeamBase(LiteLLMPydanticObjectBase):
|
|||
class LiteLLM_TeamTable(TeamBase):
|
||||
team_id: str
|
||||
spend: float | None = None
|
||||
tokens_used: int | None = None # cumulative tokens consumed this window (mirrors spend)
|
||||
max_parallel_requests: int | None = None
|
||||
budget_duration: str | None = None
|
||||
budget_reset_at: datetime | None = None
|
||||
|
|
|
|||
|
|
@ -1947,6 +1947,7 @@ class UpdateTeamRequest(LiteLLMPydanticObjectBase):
|
|||
tpd_limit: int | None = None
|
||||
max_budget: float | None = None
|
||||
soft_budget: float | None = None
|
||||
max_tokens_budget: int | None = None # cumulative token cap over budget_duration
|
||||
models: list | None = None
|
||||
blocked: bool | None = None
|
||||
budget_duration: str | None = None
|
||||
|
|
@ -5111,6 +5112,9 @@ class DBSpendUpdateTransactions(TypedDict):
|
|||
end_user_list_transactions: dict[str, float] | None
|
||||
key_list_transactions: dict[str, float] | None
|
||||
team_list_transactions: dict[str, float] | None
|
||||
# cumulative token deltas per team, flushed to LiteLLM_TeamTable.tokens_used
|
||||
# alongside team_list_transactions (spend). Tokens budgets only apply to teams.
|
||||
team_token_list_transactions: dict[str, int] | None
|
||||
team_member_list_transactions: dict[str, float] | None
|
||||
org_list_transactions: dict[str, float] | None
|
||||
org_member_list_transactions: ReadOnly[dict[str, float] | None]
|
||||
|
|
@ -5124,6 +5128,7 @@ class SpendUpdateQueueItem(TypedDict, total=False):
|
|||
entity_type: Litellm_EntityType
|
||||
entity_id: str
|
||||
response_cost: float | None
|
||||
tokens: int | None # total tokens for this request; summed into tokens_used for TEAM updates
|
||||
|
||||
|
||||
class ToolDiscoveryQueueItem(TypedDict, total=False):
|
||||
|
|
|
|||
|
|
@ -118,6 +118,9 @@ class SpendUpdateQueue(BaseUpdateQueue):
|
|||
current_cost = _in_memory_map[_key].get("response_cost", 0) or 0
|
||||
update_cost = update.get("response_cost", 0) or 0
|
||||
_in_memory_map[_key]["response_cost"] = current_cost + update_cost
|
||||
current_tokens = _in_memory_map[_key].get("tokens", 0) or 0
|
||||
update_tokens = update.get("tokens", 0) or 0
|
||||
_in_memory_map[_key]["tokens"] = current_tokens + update_tokens
|
||||
|
||||
for _key, update in _in_memory_map.items():
|
||||
aggregated_spend_updates.append(update)
|
||||
|
|
@ -135,6 +138,7 @@ class SpendUpdateQueue(BaseUpdateQueue):
|
|||
end_user_list_transactions={},
|
||||
key_list_transactions={},
|
||||
team_list_transactions={},
|
||||
team_token_list_transactions={},
|
||||
team_member_list_transactions={},
|
||||
org_list_transactions={},
|
||||
org_member_list_transactions={},
|
||||
|
|
@ -216,6 +220,15 @@ class SpendUpdateQueue(BaseUpdateQueue):
|
|||
|
||||
transactions_dict[entity_id] += response_cost or 0
|
||||
|
||||
# Tokens budgets only apply to teams, so sum the token delta into a
|
||||
# parallel map flushed to LiteLLM_TeamTable.tokens_used beside spend.
|
||||
if entity_type == Litellm_EntityType.TEAM:
|
||||
team_tokens = db_spend_update_transactions["team_token_list_transactions"]
|
||||
if team_tokens is None:
|
||||
team_tokens = {}
|
||||
db_spend_update_transactions["team_token_list_transactions"] = team_tokens
|
||||
team_tokens[entity_id] = (team_tokens.get(entity_id) or 0) + (update.get("tokens") or 0)
|
||||
|
||||
return db_spend_update_transactions
|
||||
|
||||
async def _emit_new_item_added_to_queue_event(
|
||||
|
|
|
|||
|
|
@ -197,6 +197,8 @@ model LiteLLM_TeamTable {
|
|||
tpd_limit BigInt?
|
||||
budget_duration String?
|
||||
budget_reset_at DateTime?
|
||||
max_tokens_budget BigInt? // cumulative token cap over budget_duration; null = untracked (mirrors max_budget)
|
||||
tokens_used BigInt @default(0) // cumulative tokens consumed in the current window (mirrors spend)
|
||||
blocked Boolean @default(false)
|
||||
created_at DateTime @default(now()) @map("created_at")
|
||||
updated_at DateTime @default(now()) @updatedAt @map("updated_at")
|
||||
|
|
|
|||
|
|
@ -197,6 +197,8 @@ model LiteLLM_TeamTable {
|
|||
tpd_limit BigInt?
|
||||
budget_duration String?
|
||||
budget_reset_at DateTime?
|
||||
max_tokens_budget BigInt? // cumulative token cap over budget_duration; null = untracked (mirrors max_budget)
|
||||
tokens_used BigInt @default(0) // cumulative tokens consumed in the current window (mirrors spend)
|
||||
blocked Boolean @default(false)
|
||||
created_at DateTime @default(now()) @map("created_at")
|
||||
updated_at DateTime @default(now()) @updatedAt @map("updated_at")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue