mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-01 07:03:02 +00:00
fix(proxy): satisfy type-discipline ratchet for token-budget code
Keep the custom LIT rule counts at their merge-base ceiling: - _extract_total_tokens: single-assignment Final locals (no rebinding) and Mapping[str, object] for the read-only kwargs param - team_update_data: build the payload functionally under a Final binding - max_tokens_budget / reset data: declare Final - DBSpendUpdateTransactions.team_token_list_transactions and SpendUpdateQueueItem.tokens: mark the in-place accumulators mutable-ok / writable-ok (they are reassigned by the queue, mirroring their spend siblings)
This commit is contained in:
parent
dc8b436ed5
commit
cb4561e27b
5 changed files with 24 additions and 22 deletions
|
|
@ -5114,7 +5114,7 @@ class DBSpendUpdateTransactions(TypedDict):
|
|||
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, float] | None
|
||||
team_token_list_transactions: dict[str, float] | None # mutable-ok: accumulator # writable-ok: queue-reassigned
|
||||
team_member_list_transactions: dict[str, float] | None
|
||||
org_list_transactions: dict[str, float] | None
|
||||
org_member_list_transactions: ReadOnly[dict[str, float] | None]
|
||||
|
|
@ -5128,7 +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
|
||||
tokens: int | None # writable-ok: total request tokens; dedup accumulates in place
|
||||
|
||||
|
||||
class ToolDiscoveryQueueItem(TypedDict, total=False):
|
||||
|
|
|
|||
|
|
@ -6537,7 +6537,7 @@ async def team_max_tokens_check(
|
|||
back to the ``tokens_used`` column loaded in auth. No budget set on the team
|
||||
means the check is skipped, so existing teams are unaffected.
|
||||
"""
|
||||
max_tokens_budget = getattr(team_object, "max_tokens_budget", None)
|
||||
max_tokens_budget: Final = getattr(team_object, "max_tokens_budget", None)
|
||||
if team_object is None or max_tokens_budget is None:
|
||||
return
|
||||
|
||||
|
|
|
|||
|
|
@ -2187,9 +2187,14 @@ class DBSpendUpdateWriter:
|
|||
response_cost,
|
||||
token_increment,
|
||||
)
|
||||
team_update_data: dict = {"spend": {"increment": response_cost}}
|
||||
if token_increment:
|
||||
team_update_data["tokens_used"] = {"increment": token_increment}
|
||||
team_update_data: Final = (
|
||||
{
|
||||
"spend": {"increment": response_cost},
|
||||
"tokens_used": {"increment": token_increment},
|
||||
}
|
||||
if token_increment
|
||||
else {"spend": {"increment": response_cost}}
|
||||
)
|
||||
batcher.litellm_teamtable.update_many( # 'update_many' prevents error from being raised if no row exists
|
||||
where={"team_id": team_id},
|
||||
data=team_update_data,
|
||||
|
|
|
|||
|
|
@ -733,27 +733,24 @@ class _IncrementSpendCounters(Protocol):
|
|||
) -> None: ...
|
||||
|
||||
|
||||
def _extract_total_tokens(kwargs: dict, completion_response: object) -> int:
|
||||
def _extract_total_tokens(kwargs: Mapping[str, object], completion_response: object) -> int:
|
||||
"""Total tokens for this request, for the team token-budget counter.
|
||||
|
||||
Prefers the StandardLoggingPayload (always populated for a billed call),
|
||||
falling back to the response usage. Returns 0 when unknown, which leaves the
|
||||
token counter untouched.
|
||||
"""
|
||||
sl_object = kwargs.get("standard_logging_object") or {}
|
||||
total = sl_object.get("total_tokens")
|
||||
if total:
|
||||
return int(total)
|
||||
usage = getattr(completion_response, "usage", None)
|
||||
if usage is None and isinstance(completion_response, dict):
|
||||
usage = completion_response.get("usage")
|
||||
if usage is not None:
|
||||
total = getattr(usage, "total_tokens", None)
|
||||
if total is None and isinstance(usage, dict):
|
||||
total = usage.get("total_tokens")
|
||||
if total:
|
||||
return int(total)
|
||||
return 0
|
||||
sl_object: Final = kwargs.get("standard_logging_object") or {}
|
||||
sl_total: Final = sl_object.get("total_tokens")
|
||||
if sl_total:
|
||||
return int(sl_total)
|
||||
usage: Final = (
|
||||
completion_response.get("usage")
|
||||
if isinstance(completion_response, dict)
|
||||
else getattr(completion_response, "usage", None)
|
||||
)
|
||||
usage_total: Final = usage.get("total_tokens") if isinstance(usage, dict) else getattr(usage, "total_tokens", None)
|
||||
return int(usage_total) if usage_total else 0
|
||||
|
||||
|
||||
async def _update_database_and_spend_counters(
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ class TeamSpendResetWrites:
|
|||
table: BatchTable
|
||||
|
||||
def queue_spend_reset(self, team_id: str, budget_reset_at: datetime | None, spend_decrement: float) -> None:
|
||||
data = dict(_spend_reset_data(budget_reset_at, spend_decrement))
|
||||
data: Final = dict(_spend_reset_data(budget_reset_at, spend_decrement))
|
||||
# Token budgets are team-only, so zero the cumulative tokens_used on the
|
||||
# same tick that resets spend. A hard reset (vs spend's decrement) is
|
||||
# acceptable at a budget boundary: a token allowance need not carry the
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue