fix(internal_user_endpoints.py): show remaining users when free SSO users is enabled

This commit is contained in:
Krrish Dholakia 2025-08-20 22:26:01 -07:00
parent a6380a4355
commit f6851db0eb
2 changed files with 30 additions and 21 deletions

View file

@ -2,6 +2,8 @@
Enterprise internal user management endpoints
"""
import os
from fastapi import APIRouter, Depends, HTTPException
from litellm.proxy._types import UserAPIKeyAuth
@ -21,7 +23,7 @@ async def available_enterprise_users(
"""
For keys with `max_users` set, return the list of users that are allowed to use the key.
"""
from litellm.proxy._types import CommonProxyErrors
from litellm.proxy._types import CommonProxyErrors, EnterpriseLicenseData
from litellm.proxy.proxy_server import (
premium_user,
premium_user_data,
@ -34,10 +36,14 @@ async def available_enterprise_users(
detail={"error": CommonProxyErrors.db_not_connected_error.value},
)
if premium_user is None:
raise HTTPException(
status_code=500, detail={"error": CommonProxyErrors.not_premium_user.value}
)
if not premium_user:
# check if SSO is enabled - show 5 user limit
from litellm.proxy.auth.auth_utils import _has_user_setup_sso
if _has_user_setup_sso():
premium_user_data = EnterpriseLicenseData(
max_users=5,
)
# Count number of rows in LiteLLM_UserTable
user_count = await prisma_client.db.litellm_usertable.count()

View file

@ -530,7 +530,7 @@ class LiteLLMRoutes(enum.Enum):
# Routes accessible by Admin Viewer (read-only admin access)
admin_viewer_routes = [
"/user/list",
"/user/available_users",
"/user/available_users",
"/user/available_roles",
"/user/daily/activity",
"/team/daily/activity",
@ -540,7 +540,10 @@ class LiteLLMRoutes(enum.Enum):
# All routes accesible by an Org Admin
org_admin_allowed_routes = (
org_admin_only_routes + management_routes + self_managed_routes + admin_viewer_routes
org_admin_only_routes
+ management_routes
+ self_managed_routes
+ admin_viewer_routes
)
@ -585,13 +588,14 @@ class LiteLLMPromptInjectionParams(LiteLLMPydanticObjectBase):
######### Request Class Definition ######
class ProxyChatCompletionRequest(LiteLLMPydanticObjectBase):
"""
Pydantic model for chat completion requests that includes both OpenAI standard fields
Pydantic model for chat completion requests that includes both OpenAI standard fields
and LiteLLM-specific parameters. This replaces the previous TypedDict version.
"""
# Required fields (from ChatCompletionRequest)
model: str
messages: List[AllMessageValues]
# Standard OpenAI completion parameters (all optional)
frequency_penalty: Optional[float] = None
logit_bias: Optional[Dict[str, float]] = None
@ -614,10 +618,10 @@ class ProxyChatCompletionRequest(LiteLLMPydanticObjectBase):
functions: Optional[List[Dict[str, Any]]] = None
user: Optional[str] = None
stream: Optional[bool] = None
# LiteLLM-specific metadata param (from original ChatCompletionRequest)
metadata: Optional[Dict[str, Any]] = None
# Optional LiteLLM params
guardrails: Optional[List[str]] = None
caching: Optional[bool] = None
@ -1873,7 +1877,8 @@ class UserAPIKeyAuth(
key_alias=LITTELM_INTERNAL_HEALTH_SERVICE_ACCOUNT_NAME,
team_alias=LITTELM_INTERNAL_HEALTH_SERVICE_ACCOUNT_NAME,
)
class UserInfoResponse(LiteLLMPydanticObjectBase):
user_id: Optional[str]
user_info: Optional[Union[dict, BaseModel]]
@ -2120,7 +2125,6 @@ class TokenCountRequest(LiteLLMPydanticObjectBase):
Anthropic token counting endpoint uses /messages
"""
contents: Optional[List[dict]] = None
"""
Google /countTokens endpoint expects contents to be a list of dicts with the following structure:
@ -2265,7 +2269,7 @@ class AllCallbacks(LiteLLMPydanticObjectBase):
braintrust: CallbackOnUI = CallbackOnUI(
litellm_callback_name="braintrust",
litellm_callback_params=["BRAINTRUST_API_KEY","BRAINTRUST_API_BASE"],
litellm_callback_params=["BRAINTRUST_API_KEY", "BRAINTRUST_API_BASE"],
ui_callback_name="Braintrust",
)
@ -2319,7 +2323,9 @@ class SpendLogsMetadata(TypedDict):
error_information: Optional[StandardLoggingPayloadErrorInformation]
usage_object: Optional[dict]
model_map_information: Optional[StandardLoggingModelInformation]
cold_storage_object_key: Optional[str] # S3/GCS object key for cold storage retrieval
cold_storage_object_key: Optional[
str
] # S3/GCS object key for cold storage retrieval
class SpendLogsPayload(TypedDict):
@ -2646,7 +2652,7 @@ class LiteLLM_TeamMembership(LiteLLMPydanticObjectBase):
if self.litellm_budget_table is not None:
return self.litellm_budget_table.rpm_limit
return None
def safe_get_team_member_tpm_limit(self) -> Optional[int]:
if self.litellm_budget_table is not None:
return self.litellm_budget_table.tpm_limit
@ -2763,14 +2769,11 @@ class TeamMemberUpdateRequest(TeamMemberDeleteRequest):
max_budget_in_team: Optional[float] = None
role: Optional[Literal["admin", "user"]] = None
tpm_limit: Optional[int] = Field(
default=None,
description="Tokens per minute limit for this team member"
default=None, description="Tokens per minute limit for this team member"
)
rpm_limit: Optional[int] = Field(
default=None,
description="Requests per minute limit for this team member"
default=None, description="Requests per minute limit for this team member"
)
class TeamMemberUpdateResponse(MemberUpdateResponse):