Skip to content

Commit 00e4938

Browse files
Litellm UI qa 04 12 2025 p1 (#9955)
* fix(model_info_view.tsx): cleanup text * fix(key_management_endpoints.py): fix filtering litellm-dashboard keys for internal users * fix(proxy_track_cost_callback.py): prevent flooding spend logs with admin endpoint errors * test: add unit testing for logic * test(test_auth_exception_handler.py): add more unit testing * fix(router.py): correctly handle retrieving model info on get_model_group_info fixes issue where model hub was showing None prices * fix: fix linting errors
1 parent f8d52e2 commit 00e4938

File tree

13 files changed

+249
-80
lines changed

13 files changed

+249
-80
lines changed

litellm/litellm_core_utils/get_model_cost_map.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import httpx
1414

1515

16-
def get_model_cost_map(url: str):
16+
def get_model_cost_map(url: str) -> dict:
1717
if (
1818
os.getenv("LITELLM_LOCAL_MODEL_COST_MAP", False)
1919
or os.getenv("LITELLM_LOCAL_MODEL_COST_MAP", False) == "True"

litellm/proxy/_experimental/out/onboarding.html

Lines changed: 0 additions & 1 deletion
This file was deleted.

litellm/proxy/_types.py

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -644,9 +644,9 @@ class GenerateRequestBase(LiteLLMPydanticObjectBase):
644644
allowed_cache_controls: Optional[list] = []
645645
config: Optional[dict] = {}
646646
permissions: Optional[dict] = {}
647-
model_max_budget: Optional[dict] = (
648-
{}
649-
) # {"gpt-4": 5.0, "gpt-3.5-turbo": 5.0}, defaults to {}
647+
model_max_budget: Optional[
648+
dict
649+
] = {} # {"gpt-4": 5.0, "gpt-3.5-turbo": 5.0}, defaults to {}
650650

651651
model_config = ConfigDict(protected_namespaces=())
652652
model_rpm_limit: Optional[dict] = None
@@ -902,12 +902,12 @@ class NewCustomerRequest(BudgetNewRequest):
902902
alias: Optional[str] = None # human-friendly alias
903903
blocked: bool = False # allow/disallow requests for this end-user
904904
budget_id: Optional[str] = None # give either a budget_id or max_budget
905-
allowed_model_region: Optional[AllowedModelRegion] = (
906-
None # require all user requests to use models in this specific region
907-
)
908-
default_model: Optional[str] = (
909-
None # if no equivalent model in allowed region - default all requests to this model
910-
)
905+
allowed_model_region: Optional[
906+
AllowedModelRegion
907+
] = None # require all user requests to use models in this specific region
908+
default_model: Optional[
909+
str
910+
] = None # if no equivalent model in allowed region - default all requests to this model
911911

912912
@model_validator(mode="before")
913913
@classmethod
@@ -929,12 +929,12 @@ class UpdateCustomerRequest(LiteLLMPydanticObjectBase):
929929
blocked: bool = False # allow/disallow requests for this end-user
930930
max_budget: Optional[float] = None
931931
budget_id: Optional[str] = None # give either a budget_id or max_budget
932-
allowed_model_region: Optional[AllowedModelRegion] = (
933-
None # require all user requests to use models in this specific region
934-
)
935-
default_model: Optional[str] = (
936-
None # if no equivalent model in allowed region - default all requests to this model
937-
)
932+
allowed_model_region: Optional[
933+
AllowedModelRegion
934+
] = None # require all user requests to use models in this specific region
935+
default_model: Optional[
936+
str
937+
] = None # if no equivalent model in allowed region - default all requests to this model
938938

939939

940940
class DeleteCustomerRequest(LiteLLMPydanticObjectBase):
@@ -1070,9 +1070,9 @@ class BlockKeyRequest(LiteLLMPydanticObjectBase):
10701070

10711071
class AddTeamCallback(LiteLLMPydanticObjectBase):
10721072
callback_name: str
1073-
callback_type: Optional[Literal["success", "failure", "success_and_failure"]] = (
1074-
"success_and_failure"
1075-
)
1073+
callback_type: Optional[
1074+
Literal["success", "failure", "success_and_failure"]
1075+
] = "success_and_failure"
10761076
callback_vars: Dict[str, str]
10771077

10781078
@model_validator(mode="before")
@@ -1329,9 +1329,9 @@ class ConfigList(LiteLLMPydanticObjectBase):
13291329
stored_in_db: Optional[bool]
13301330
field_default_value: Any
13311331
premium_field: bool = False
1332-
nested_fields: Optional[List[FieldDetail]] = (
1333-
None # For nested dictionary or Pydantic fields
1334-
)
1332+
nested_fields: Optional[
1333+
List[FieldDetail]
1334+
] = None # For nested dictionary or Pydantic fields
13351335

13361336

13371337
class ConfigGeneralSettings(LiteLLMPydanticObjectBase):
@@ -1558,6 +1558,7 @@ class UserAPIKeyAuth(
15581558
user_tpm_limit: Optional[int] = None
15591559
user_rpm_limit: Optional[int] = None
15601560
user_email: Optional[str] = None
1561+
request_route: Optional[str] = None
15611562

15621563
model_config = ConfigDict(arbitrary_types_allowed=True)
15631564

@@ -1597,9 +1598,9 @@ class LiteLLM_OrganizationMembershipTable(LiteLLMPydanticObjectBase):
15971598
budget_id: Optional[str] = None
15981599
created_at: datetime
15991600
updated_at: datetime
1600-
user: Optional[Any] = (
1601-
None # You might want to replace 'Any' with a more specific type if available
1602-
)
1601+
user: Optional[
1602+
Any
1603+
] = None # You might want to replace 'Any' with a more specific type if available
16031604
litellm_budget_table: Optional[LiteLLM_BudgetTable] = None
16041605

16051606
model_config = ConfigDict(protected_namespaces=())
@@ -2345,9 +2346,9 @@ class TeamModelDeleteRequest(BaseModel):
23452346
# Organization Member Requests
23462347
class OrganizationMemberAddRequest(OrgMemberAddRequest):
23472348
organization_id: str
2348-
max_budget_in_organization: Optional[float] = (
2349-
None # Users max budget within the organization
2350-
)
2349+
max_budget_in_organization: Optional[
2350+
float
2351+
] = None # Users max budget within the organization
23512352

23522353

23532354
class OrganizationMemberDeleteRequest(MemberDeleteRequest):
@@ -2536,9 +2537,9 @@ class ProviderBudgetResponse(LiteLLMPydanticObjectBase):
25362537
Maps provider names to their budget configs.
25372538
"""
25382539

2539-
providers: Dict[str, ProviderBudgetResponseObject] = (
2540-
{}
2541-
) # Dictionary mapping provider names to their budget configurations
2540+
providers: Dict[
2541+
str, ProviderBudgetResponseObject
2542+
] = {} # Dictionary mapping provider names to their budget configurations
25422543

25432544

25442545
class ProxyStateVariables(TypedDict):
@@ -2666,9 +2667,9 @@ class LiteLLM_JWTAuth(LiteLLMPydanticObjectBase):
26662667
enforce_rbac: bool = False
26672668
roles_jwt_field: Optional[str] = None # v2 on role mappings
26682669
role_mappings: Optional[List[RoleMapping]] = None
2669-
object_id_jwt_field: Optional[str] = (
2670-
None # can be either user / team, inferred from the role mapping
2671-
)
2670+
object_id_jwt_field: Optional[
2671+
str
2672+
] = None # can be either user / team, inferred from the role mapping
26722673
scope_mappings: Optional[List[ScopeMapping]] = None
26732674
enforce_scope_based_access: bool = False
26742675
enforce_team_based_model_access: bool = False

litellm/proxy/auth/auth_exception_handler.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ async def _handle_authentication_error(
6868
key_name="failed-to-connect-to-db",
6969
token="failed-to-connect-to-db",
7070
user_id=litellm_proxy_admin_name,
71+
request_route=route,
7172
)
7273
else:
7374
# raise the exception to the caller
@@ -87,6 +88,7 @@ async def _handle_authentication_error(
8788
user_api_key_dict = UserAPIKeyAuth(
8889
parent_otel_span=parent_otel_span,
8990
api_key=api_key,
91+
request_route=route,
9092
)
9193
asyncio.create_task(
9294
proxy_logging_obj.post_call_failure_hook(

litellm/proxy/auth/user_api_key_auth.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,7 @@ async def user_api_key_auth(
10231023
"""
10241024

10251025
request_data = await _read_request_body(request=request)
1026+
route: str = get_request_route(request=request)
10261027

10271028
user_api_key_auth_obj = await _user_api_key_auth_builder(
10281029
request=request,
@@ -1038,6 +1039,8 @@ async def user_api_key_auth(
10381039
if end_user_id is not None:
10391040
user_api_key_auth_obj.end_user_id = end_user_id
10401041

1042+
user_api_key_auth_obj.request_route = route
1043+
10411044
return user_api_key_auth_obj
10421045

10431046

litellm/proxy/hooks/proxy_track_cost_callback.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from litellm.litellm_core_utils.litellm_logging import StandardLoggingPayloadSetup
1414
from litellm.proxy._types import UserAPIKeyAuth
1515
from litellm.proxy.auth.auth_checks import log_db_metrics
16+
from litellm.proxy.auth.route_checks import RouteChecks
1617
from litellm.proxy.utils import ProxyUpdateSpend
1718
from litellm.types.utils import (
1819
StandardLoggingPayload,
@@ -33,8 +34,13 @@ async def async_post_call_failure_hook(
3334
original_exception: Exception,
3435
user_api_key_dict: UserAPIKeyAuth,
3536
):
37+
request_route = user_api_key_dict.request_route
3638
if _ProxyDBLogger._should_track_errors_in_db() is False:
3739
return
40+
elif request_route is not None and not RouteChecks.is_llm_api_route(
41+
route=request_route
42+
):
43+
return
3844

3945
from litellm.proxy.proxy_server import proxy_logging_obj
4046

litellm/proxy/management_endpoints/key_management_endpoints.py

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -577,9 +577,9 @@ async def generate_key_fn( # noqa: PLR0915
577577
request_type="key", **data_json, table_name="key"
578578
)
579579

580-
response["soft_budget"] = (
581-
data.soft_budget
582-
) # include the user-input soft budget in the response
580+
response[
581+
"soft_budget"
582+
] = data.soft_budget # include the user-input soft budget in the response
583583

584584
response = GenerateKeyResponse(**response)
585585

@@ -1467,10 +1467,10 @@ async def delete_verification_tokens(
14671467
try:
14681468
if prisma_client:
14691469
tokens = [_hash_token_if_needed(token=key) for key in tokens]
1470-
_keys_being_deleted: List[LiteLLM_VerificationToken] = (
1471-
await prisma_client.db.litellm_verificationtoken.find_many(
1472-
where={"token": {"in": tokens}}
1473-
)
1470+
_keys_being_deleted: List[
1471+
LiteLLM_VerificationToken
1472+
] = await prisma_client.db.litellm_verificationtoken.find_many(
1473+
where={"token": {"in": tokens}}
14741474
)
14751475

14761476
# Assuming 'db' is your Prisma Client instance
@@ -1572,9 +1572,9 @@ async def _rotate_master_key(
15721572
from litellm.proxy.proxy_server import proxy_config
15731573

15741574
try:
1575-
models: Optional[List] = (
1576-
await prisma_client.db.litellm_proxymodeltable.find_many()
1577-
)
1575+
models: Optional[
1576+
List
1577+
] = await prisma_client.db.litellm_proxymodeltable.find_many()
15781578
except Exception:
15791579
models = None
15801580
# 2. process model table
@@ -1861,11 +1861,11 @@ async def validate_key_list_check(
18611861
param="user_id",
18621862
code=status.HTTP_403_FORBIDDEN,
18631863
)
1864-
complete_user_info_db_obj: Optional[BaseModel] = (
1865-
await prisma_client.db.litellm_usertable.find_unique(
1866-
where={"user_id": user_api_key_dict.user_id},
1867-
include={"organization_memberships": True},
1868-
)
1864+
complete_user_info_db_obj: Optional[
1865+
BaseModel
1866+
] = await prisma_client.db.litellm_usertable.find_unique(
1867+
where={"user_id": user_api_key_dict.user_id},
1868+
include={"organization_memberships": True},
18691869
)
18701870

18711871
if complete_user_info_db_obj is None:
@@ -1926,10 +1926,10 @@ async def get_admin_team_ids(
19261926
if complete_user_info is None:
19271927
return []
19281928
# Get all teams that user is an admin of
1929-
teams: Optional[List[BaseModel]] = (
1930-
await prisma_client.db.litellm_teamtable.find_many(
1931-
where={"team_id": {"in": complete_user_info.teams}}
1932-
)
1929+
teams: Optional[
1930+
List[BaseModel]
1931+
] = await prisma_client.db.litellm_teamtable.find_many(
1932+
where={"team_id": {"in": complete_user_info.teams}}
19331933
)
19341934
if teams is None:
19351935
return []
@@ -2080,7 +2080,6 @@ async def _list_key_helper(
20802080
"total_pages": int,
20812081
}
20822082
"""
2083-
20842083
# Prepare filter conditions
20852084
where: Dict[str, Union[str, Dict[str, Any], List[Dict[str, Any]]]] = {}
20862085
where.update(_get_condition_to_filter_out_ui_session_tokens())
@@ -2110,7 +2109,7 @@ async def _list_key_helper(
21102109

21112110
# Combine conditions with OR if we have multiple conditions
21122111
if len(or_conditions) > 1:
2113-
where["OR"] = or_conditions
2112+
where = {"AND": [where, {"OR": or_conditions}]}
21142113
elif len(or_conditions) == 1:
21152114
where.update(or_conditions[0])
21162115

0 commit comments

Comments
 (0)