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:
Srivatsa03 2026-10-11 22:05:22 -05:00
parent dc8b436ed5
commit cb4561e27b
5 changed files with 24 additions and 22 deletions

View file

@ -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):

View file

@ -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

View file

@ -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,

View file

@ -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(

View file

@ -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