From a7a36214253dc9151e1a6887a52694845ae6e26b Mon Sep 17 00:00:00 2001 From: mubashir1osmani Date: Mon, 13 Apr 2026 14:26:57 -0400 Subject: [PATCH] add total spend field --- .../litellm_proxy_extras/schema.prisma | 7 +++++ litellm/proxy/_types.py | 5 ++++ litellm/proxy/db/db_spend_update_writer.py | 26 +++++++++++++++---- litellm/proxy/schema.prisma | 7 +++++ litellm/proxy/utils.py | 6 ++++- schema.prisma | 7 +++++ 6 files changed, 52 insertions(+), 6 deletions(-) diff --git a/litellm-proxy-extras/litellm_proxy_extras/schema.prisma b/litellm-proxy-extras/litellm_proxy_extras/schema.prisma index fce95465b55..34575a08fe1 100644 --- a/litellm-proxy-extras/litellm_proxy_extras/schema.prisma +++ b/litellm-proxy-extras/litellm_proxy_extras/schema.prisma @@ -86,6 +86,7 @@ model LiteLLM_OrganizationTable { metadata Json @default("{}") models String[] spend Float @default(0.0) + total_spend Float @default(0.0) model_spend Json @default("{}") object_permission_id String? created_at DateTime @default(now()) @map("created_at") @@ -125,6 +126,7 @@ model LiteLLM_TeamTable { max_budget Float? soft_budget Float? spend Float @default(0.0) + total_spend Float @default(0.0) models String[] max_parallel_requests Int? tpm_limit BigInt? @@ -239,6 +241,7 @@ model LiteLLM_UserTable { user_role String? max_budget Float? spend Float @default(0.0) + total_spend Float @default(0.0) user_email String? models String[] metadata Json @default("{}") @@ -363,6 +366,7 @@ model LiteLLM_VerificationToken { key_alias String? soft_budget_cooldown Boolean @default(false) // key-level state on if budget alerts need to be cooled down spend Float @default(0.0) + total_spend Float @default(0.0) expires DateTime? models String[] aliases Json @default("{}") @@ -513,6 +517,7 @@ model LiteLLM_EndUserTable { user_id String @id alias String? // admin-facing alias spend Float @default(0.0) + total_spend Float @default(0.0) allowed_model_region String? // require all user requests to use models in this specific region default_model String? // use along with 'allowed_model_region'. if no available model in region, default to this model. budget_id String? @@ -611,6 +616,7 @@ model LiteLLM_TeamMembership { user_id String team_id String spend Float @default(0.0) + total_spend Float @default(0.0) budget_id String? litellm_budget_table LiteLLM_BudgetTable? @relation(fields: [budget_id], references: [budget_id]) @@id([user_id, team_id]) @@ -622,6 +628,7 @@ model LiteLLM_OrganizationMembership { organization_id String user_role String? spend Float? @default(0.0) + total_spend Float? @default(0.0) budget_id String? created_at DateTime? @default(now()) @map("created_at") updated_at DateTime? @default(now()) @updatedAt @map("updated_at") diff --git a/litellm/proxy/_types.py b/litellm/proxy/_types.py index 793742891fc..9710ee727d9 100644 --- a/litellm/proxy/_types.py +++ b/litellm/proxy/_types.py @@ -1876,6 +1876,7 @@ class LiteLLM_ObjectPermissionTable(LiteLLMPydanticObjectBase): class LiteLLM_TeamTable(TeamBase): team_id: str # type: ignore spend: Optional[float] = None + total_spend: Optional[float] = None max_parallel_requests: Optional[int] = None budget_duration: Optional[str] = None budget_reset_at: Optional[datetime] = None @@ -2347,6 +2348,7 @@ class LiteLLM_VerificationToken(LiteLLMPydanticObjectBase): key_name: Optional[str] = None key_alias: Optional[str] = None spend: float = 0.0 + total_spend: float = 0.0 max_budget: Optional[float] = None expires: Optional[Union[str, datetime]] = None models: List = [] @@ -2685,6 +2687,7 @@ class LiteLLM_UserTable(LiteLLMPydanticObjectBase): user_id: str max_budget: Optional[float] = None spend: float = 0.0 + total_spend: float = 0.0 model_max_budget: Optional[Dict] = {} model_spend: Optional[Dict] = {} user_email: Optional[str] = None @@ -2724,6 +2727,7 @@ class LiteLLM_OrganizationTable(LiteLLMPydanticObjectBase): organization_alias: Optional[str] = None budget_id: str spend: float = 0.0 + total_spend: float = 0.0 metadata: Optional[dict] = None models: List[str] created_by: str @@ -2896,6 +2900,7 @@ class LiteLLM_EndUserTable(LiteLLMPydanticObjectBase): blocked: bool alias: Optional[str] = None spend: float = 0.0 + total_spend: float = 0.0 allowed_model_region: Optional[AllowedModelRegion] = None default_model: Optional[str] = None litellm_budget_table: Optional[LiteLLM_BudgetTable] = None diff --git a/litellm/proxy/db/db_spend_update_writer.py b/litellm/proxy/db/db_spend_update_writer.py index 241b66bc0ae..28a2f6467cd 100644 --- a/litellm/proxy/db/db_spend_update_writer.py +++ b/litellm/proxy/db/db_spend_update_writer.py @@ -1134,7 +1134,10 @@ class DBSpendUpdateWriter: ) in user_list_transactions.items(): batcher.litellm_usertable.update_many( where={"user_id": user_id}, - data={"spend": {"increment": response_cost}}, + data={ + "spend": {"increment": response_cost}, + "total_spend": {"increment": response_cost}, + }, ) break except DB_CONNECTION_ERROR_TYPES as e: @@ -1191,6 +1194,7 @@ class DBSpendUpdateWriter: where={"token": token}, data={ "spend": {"increment": response_cost}, + "total_spend": {"increment": response_cost}, "last_active": datetime.now(timezone.utc), }, ) @@ -1238,7 +1242,10 @@ class DBSpendUpdateWriter: ) batcher.litellm_teamtable.update_many( # 'update_many' prevents error from being raised if no row exists where={"team_id": team_id}, - data={"spend": {"increment": response_cost}}, + data={ + "spend": {"increment": response_cost}, + "total_spend": {"increment": response_cost}, + }, ) break except DB_CONNECTION_ERROR_TYPES as e: @@ -1295,7 +1302,10 @@ class DBSpendUpdateWriter: batcher.litellm_teammembership.update_many( # 'update_many' prevents error from being raised if no row exists where={"team_id": team_id, "user_id": user_id}, - data={"spend": {"increment": response_cost}}, + data={ + "spend": {"increment": response_cost}, + "total_spend": {"increment": response_cost}, + }, ) # Transaction succeeded, break out of retry loop break @@ -1348,7 +1358,10 @@ class DBSpendUpdateWriter: ) in org_list_transactions.items(): batcher.litellm_organizationtable.update_many( # 'update_many' prevents error from being raised if no row exists where={"organization_id": org_id}, - data={"spend": {"increment": response_cost}}, + data={ + "spend": {"increment": response_cost}, + "total_spend": {"increment": response_cost}, + }, ) break except DB_CONNECTION_ERROR_TYPES as e: @@ -1439,7 +1452,10 @@ class DBSpendUpdateWriter: ) getattr(batcher, table_accessor).update_many( where={where_field: entity_id}, - data={"spend": {"increment": response_cost}}, + data={ + "spend": {"increment": response_cost}, + "total_spend": {"increment": response_cost}, + }, ) break except DB_CONNECTION_ERROR_TYPES as e: diff --git a/litellm/proxy/schema.prisma b/litellm/proxy/schema.prisma index fce95465b55..34575a08fe1 100644 --- a/litellm/proxy/schema.prisma +++ b/litellm/proxy/schema.prisma @@ -86,6 +86,7 @@ model LiteLLM_OrganizationTable { metadata Json @default("{}") models String[] spend Float @default(0.0) + total_spend Float @default(0.0) model_spend Json @default("{}") object_permission_id String? created_at DateTime @default(now()) @map("created_at") @@ -125,6 +126,7 @@ model LiteLLM_TeamTable { max_budget Float? soft_budget Float? spend Float @default(0.0) + total_spend Float @default(0.0) models String[] max_parallel_requests Int? tpm_limit BigInt? @@ -239,6 +241,7 @@ model LiteLLM_UserTable { user_role String? max_budget Float? spend Float @default(0.0) + total_spend Float @default(0.0) user_email String? models String[] metadata Json @default("{}") @@ -363,6 +366,7 @@ model LiteLLM_VerificationToken { key_alias String? soft_budget_cooldown Boolean @default(false) // key-level state on if budget alerts need to be cooled down spend Float @default(0.0) + total_spend Float @default(0.0) expires DateTime? models String[] aliases Json @default("{}") @@ -513,6 +517,7 @@ model LiteLLM_EndUserTable { user_id String @id alias String? // admin-facing alias spend Float @default(0.0) + total_spend Float @default(0.0) allowed_model_region String? // require all user requests to use models in this specific region default_model String? // use along with 'allowed_model_region'. if no available model in region, default to this model. budget_id String? @@ -611,6 +616,7 @@ model LiteLLM_TeamMembership { user_id String team_id String spend Float @default(0.0) + total_spend Float @default(0.0) budget_id String? litellm_budget_table LiteLLM_BudgetTable? @relation(fields: [budget_id], references: [budget_id]) @@id([user_id, team_id]) @@ -622,6 +628,7 @@ model LiteLLM_OrganizationMembership { organization_id String user_role String? spend Float? @default(0.0) + total_spend Float? @default(0.0) budget_id String? created_at DateTime? @default(now()) @map("created_at") updated_at DateTime? @default(now()) @updatedAt @map("updated_at") diff --git a/litellm/proxy/utils.py b/litellm/proxy/utils.py index 635204f3362..005b3968a70 100644 --- a/litellm/proxy/utils.py +++ b/litellm/proxy/utils.py @@ -4686,9 +4686,13 @@ class ProxyUpdateSpend: "create": { "user_id": end_user_id, "spend": response_cost, + "total_spend": response_cost, "blocked": False, }, - "update": {"spend": {"increment": response_cost}}, + "update": { + "spend": {"increment": response_cost}, + "total_spend": {"increment": response_cost}, + }, }, ) diff --git a/schema.prisma b/schema.prisma index fce95465b55..34575a08fe1 100644 --- a/schema.prisma +++ b/schema.prisma @@ -86,6 +86,7 @@ model LiteLLM_OrganizationTable { metadata Json @default("{}") models String[] spend Float @default(0.0) + total_spend Float @default(0.0) model_spend Json @default("{}") object_permission_id String? created_at DateTime @default(now()) @map("created_at") @@ -125,6 +126,7 @@ model LiteLLM_TeamTable { max_budget Float? soft_budget Float? spend Float @default(0.0) + total_spend Float @default(0.0) models String[] max_parallel_requests Int? tpm_limit BigInt? @@ -239,6 +241,7 @@ model LiteLLM_UserTable { user_role String? max_budget Float? spend Float @default(0.0) + total_spend Float @default(0.0) user_email String? models String[] metadata Json @default("{}") @@ -363,6 +366,7 @@ model LiteLLM_VerificationToken { key_alias String? soft_budget_cooldown Boolean @default(false) // key-level state on if budget alerts need to be cooled down spend Float @default(0.0) + total_spend Float @default(0.0) expires DateTime? models String[] aliases Json @default("{}") @@ -513,6 +517,7 @@ model LiteLLM_EndUserTable { user_id String @id alias String? // admin-facing alias spend Float @default(0.0) + total_spend Float @default(0.0) allowed_model_region String? // require all user requests to use models in this specific region default_model String? // use along with 'allowed_model_region'. if no available model in region, default to this model. budget_id String? @@ -611,6 +616,7 @@ model LiteLLM_TeamMembership { user_id String team_id String spend Float @default(0.0) + total_spend Float @default(0.0) budget_id String? litellm_budget_table LiteLLM_BudgetTable? @relation(fields: [budget_id], references: [budget_id]) @@id([user_id, team_id]) @@ -622,6 +628,7 @@ model LiteLLM_OrganizationMembership { organization_id String user_role String? spend Float? @default(0.0) + total_spend Float? @default(0.0) budget_id String? created_at DateTime? @default(now()) @map("created_at") updated_at DateTime? @default(now()) @updatedAt @map("updated_at")