refactor(proxy): name the team members schemas TeamMemberResponse and TeamMembersQueryParams

This commit is contained in:
ryan-crabbe-berri 2026-10-06 13:54:06 -07:00
parent 5f6ae44ae0
commit a753694a07
6 changed files with 48 additions and 48 deletions

View file

@ -10,7 +10,7 @@ from litellm.proxy.list_api.common import PROBLEM_TYPE_BASE, ManagementProblem
from litellm.proxy.list_api.list_framework import QueryPlan, plan_list_query, reject_repeated_params
from litellm.proxy.management.teams.authz import TeamAccess
from litellm.proxy.management.teams.exceptions import members_not_readable, team_not_found
from litellm.proxy.management.teams.schemas import TeamMembersQuery
from litellm.proxy.management.teams.schemas import TeamMembersQueryParams
from litellm.proxy.management.teams.service import TEAM_MEMBERS_LIST_SPEC, team_members_list_query
from litellm.proxy.management.users.service import PrismaOrgRoles
from litellm.repositories.team_repository import TeamRepository
@ -69,7 +69,7 @@ async def get_readable_team(
def get_team_members_plan(
query: Annotated[TeamMembersQuery, Query()],
query: Annotated[TeamMembersQueryParams, Query()],
request: Request,
caller: Annotated[UserAPIKeyAuth, Depends(user_api_key_auth)],
) -> QueryPlan:

View file

@ -7,7 +7,7 @@ from litellm.proxy.auth.user_api_key_auth import user_api_key_auth
from litellm.proxy.list_api.list_framework import QueryPlan, list_response
from litellm.proxy.management.teams.dependencies import get_readable_team, get_roster_db, get_team_members_plan
from litellm.proxy.management.teams.repository import RawQuery
from litellm.proxy.management.teams.schemas import TeamMemberListItem
from litellm.proxy.management.teams.schemas import TeamMemberResponse
from litellm.proxy.management.teams.service import get_team_members_list
from litellm.proxy.management_endpoints.management_v1.common import MANAGEMENT_V1_PREFIX
from litellm.types.proxy.management_endpoints.management_v1 import ListResponse
@ -19,14 +19,14 @@ router: Final = APIRouter(prefix=MANAGEMENT_V1_PREFIX)
"/teams/{team_id}/members",
tags=["team management"],
dependencies=(Depends(user_api_key_auth),),
response_model=ListResponse[TeamMemberListItem],
response_model=ListResponse[TeamMemberResponse],
)
async def list_team_members(
request: Request,
team: Annotated[LiteLLM_TeamTable, Depends(get_readable_team)],
plan: Annotated[QueryPlan, Depends(get_team_members_plan)],
roster_db: Annotated[RawQuery, Depends(get_roster_db)],
) -> ListResponse[TeamMemberListItem]:
) -> ListResponse[TeamMemberResponse]:
"""
List a team's members one page at a time, with each member's spend and budget limits in the team.

View file

@ -6,7 +6,7 @@ from pydantic import BaseModel, ConfigDict, Field
from litellm.proxy._types import TeamMemberBudgetSource
class TeamMemberListItem(BaseModel):
class TeamMemberResponse(BaseModel):
"""One roster entry with the member's spend in the team and the budget row their membership points at.
The limits are that row's, exactly as `/team/info` returns it under `team_memberships`, so a member
@ -31,7 +31,7 @@ class TeamMemberListItem(BaseModel):
allowed_models: tuple[str, ...]
class TeamMembersQuery(BaseModel):
class TeamMembersQueryParams(BaseModel):
model_config = ConfigDict(frozen=True, extra="forbid")
q: str | None = Field(

View file

@ -7,7 +7,7 @@ from typing import Final
from litellm.proxy._types import TeamMemberBudgetSource, UserAPIKeyAuth
from litellm.proxy.list_api.list_framework import Compare, ListQuery, ListSpec, QueryPlan, Scope, ScopeAll, Within
from litellm.proxy.management.teams.repository import RawQuery, TeamMemberRow, TeamMemberRows
from litellm.proxy.management.teams.schemas import TeamMemberListItem, TeamMembersQuery
from litellm.proxy.management.teams.schemas import TeamMemberResponse, TeamMembersQueryParams
def member_budget_source(budget_id: str | None, team_default_budget_id: str | None) -> TeamMemberBudgetSource:
@ -16,8 +16,8 @@ def member_budget_source(budget_id: str | None, team_default_budget_id: str | No
return "team_default" if team_default_budget_id is not None else "none"
def _team_member_item(row: TeamMemberRow) -> TeamMemberListItem:
return TeamMemberListItem(
def _team_member_item(row: TeamMemberRow) -> TeamMemberResponse:
return TeamMemberResponse(
user_id=row.user_id,
user_email=row.user_email,
user_alias=row.user_alias,
@ -40,7 +40,7 @@ def _roster_reader_scope(_caller: UserAPIKeyAuth) -> Scope:
return ScopeAll()
TEAM_MEMBERS_LIST_SPEC: Final[ListSpec[TeamMemberRow, TeamMemberListItem]] = ListSpec(
TEAM_MEMBERS_LIST_SPEC: Final[ListSpec[TeamMemberRow, TeamMemberResponse]] = ListSpec(
resource="team members",
sortable=frozenset(
("user_alias", "user_email", "user_id", "role", "spend", "total_spend", "max_budget_in_team", "budget_reset_at")
@ -56,7 +56,7 @@ TEAM_MEMBERS_LIST_SPEC: Final[ListSpec[TeamMemberRow, TeamMemberListItem]] = Lis
)
def team_members_list_query(query: TeamMembersQuery) -> ListQuery:
def team_members_list_query(query: TeamMembersQueryParams) -> ListQuery:
return ListQuery(
page=query.page,
page_size=query.page_size,
@ -75,7 +75,7 @@ def team_members_list_query(query: TeamMembersQuery) -> ListQuery:
@dataclass(frozen=True, slots=True)
class TeamMembersPage:
members: tuple[TeamMemberListItem, ...]
members: tuple[TeamMemberResponse, ...]
total_count: int

View file

@ -10,7 +10,7 @@ import pytest
from litellm.proxy._types import TeamMemberBudgetSource
from litellm.proxy.list_api.list_framework import Compare, ListQuery, QueryPlan, SortKey, Within
from litellm.proxy.management.teams.repository import TeamMemberRow
from litellm.proxy.management.teams.schemas import TeamMembersQuery
from litellm.proxy.management.teams.schemas import TeamMembersQueryParams
from litellm.proxy.management.teams.service import (
TEAM_MEMBERS_LIST_SPEC,
TeamMembersPage,
@ -96,7 +96,7 @@ def test_list_item_carries_the_member_row_and_derives_its_budget_source() -> Non
def test_team_members_list_query_carries_every_declared_param_with_roles_as_roster_filters() -> None:
declared: Final = TeamMembersQuery.model_validate(
declared: Final = TeamMembersQueryParams.model_validate(
{
"q": "ada",
"filter[role]": "admin",
@ -117,4 +117,4 @@ def test_team_members_list_query_carries_every_declared_param_with_roles_as_rost
def test_team_members_list_query_with_no_params_filters_nothing() -> None:
assert team_members_list_query(TeamMembersQuery()) == ListQuery()
assert team_members_list_query(TeamMembersQueryParams()) == ListQuery()

View file

@ -33899,10 +33899,10 @@ export interface components {
links: components["schemas"]["ListLinks"];
meta: components["schemas"]["ListMeta"];
};
/** ListResponse[TeamMemberListItem] */
ListResponse_TeamMemberListItem_: {
/** ListResponse[TeamMemberResponse] */
ListResponse_TeamMemberResponse_: {
/** Data */
data: components["schemas"]["TeamMemberListItem"][];
data: components["schemas"]["TeamMemberResponse"][];
links: components["schemas"]["ListLinks"];
meta: components["schemas"]["ListMeta"];
};
@ -45926,13 +45926,39 @@ export interface components {
user_id: string;
};
/**
* TeamMemberListItem
* TeamMemberRef
* @description One member, named by exactly one of `user_id` or `user_email`.
*/
TeamMemberRef: {
/** User Email */
user_email?: string | null;
/** User Id */
user_id?: string | null;
};
/** TeamMemberResetBudgetResponse */
TeamMemberResetBudgetResponse: {
/** Budget Id */
budget_id: string | null;
/**
* Budget Source
* @enum {string}
*/
budget_source: "team_default" | "custom" | "none";
/** Previous Budget Id */
previous_budget_id: string | null;
/** Team Id */
team_id: string;
/** User Id */
user_id: string;
};
/**
* TeamMemberResponse
* @description One roster entry with the member's spend in the team and the budget row their membership points at.
*
* The limits are that row's, exactly as `/team/info` returns it under `team_memberships`, so a member
* with no row of their own reads null limits even when `budget_source` is `team_default`.
*/
TeamMemberListItem: {
TeamMemberResponse: {
/** Allowed Models */
allowed_models: string[];
/** Budget Duration */
@ -45968,32 +45994,6 @@ export interface components {
/** User Id */
user_id: string | null;
};
/**
* TeamMemberRef
* @description One member, named by exactly one of `user_id` or `user_email`.
*/
TeamMemberRef: {
/** User Email */
user_email?: string | null;
/** User Id */
user_id?: string | null;
};
/** TeamMemberResetBudgetResponse */
TeamMemberResetBudgetResponse: {
/** Budget Id */
budget_id: string | null;
/**
* Budget Source
* @enum {string}
*/
budget_source: "team_default" | "custom" | "none";
/** Previous Budget Id */
previous_budget_id: string | null;
/** Team Id */
team_id: string;
/** User Id */
user_id: string;
};
/** TeamMemberUpdateRequest */
TeamMemberUpdateRequest: {
/**
@ -62990,7 +62990,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ListResponse_TeamMemberListItem_"];
"application/json": components["schemas"]["ListResponse_TeamMemberResponse_"];
};
};
/** @description Validation Error */