fix: lazy import get_access_object to break cyclic import + short-circuit all-proxy-models display

- Remove get_access_object from module-level import in team_endpoints.py
  and use a lazy _get_access_object wrapper to avoid cyclic dependency
- Add _prisma_client is None early-exit guard in _resolve_access_group_resources
- Short-circuit UI to show "All Proxy Models" when team.models is empty
  or contains "all-proxy-models", skipping access group model resolution
This commit is contained in:
Ryan Crabbe 2026-04-02 16:14:34 -07:00
parent bbe708b093
commit f0bd33486e
No known key found for this signature in database
3 changed files with 21 additions and 6 deletions

View file

@ -64,7 +64,6 @@ from litellm.proxy._types import (
from litellm.proxy.auth.auth_checks import (
allowed_route_check_inside_route,
can_org_access_model,
get_access_object,
get_org_object,
get_team_object,
get_user_object,
@ -111,6 +110,16 @@ from litellm.types.proxy.management_endpoints.team_endpoints import (
router = APIRouter()
def _get_access_object(*args, **kwargs):
"""
Lazily import and delegate to `get_access_object` from
`litellm.proxy.auth.auth_checks` to avoid module-level cyclic imports.
"""
from litellm.proxy.auth.auth_checks import get_access_object as _inner_get_access_object
return _inner_get_access_object(*args, **kwargs)
class TeamMemberBudgetHandler:
"""Helper class to handle team member budget, RPM, and TPM limit operations"""
@ -3368,13 +3377,16 @@ async def _resolve_access_group_resources(
if _user_api_key_cache is None:
return empty
if _prisma_client is None:
return empty
models: List[str] = []
mcp_ids: List[str] = []
agent_ids: List[str] = []
for ag_id in access_group_ids:
try:
ag = await get_access_object(
ag = await _get_access_object(
access_group_id=ag_id,
prisma_client=_prisma_client,
user_api_key_cache=_user_api_key_cache,

View file

@ -16,8 +16,11 @@ interface ModelEntry {
const ModelsCell = ({ team }: ModelsCellProps) => {
const [expandedAccordion, setExpandedAccordion] = useState<boolean>(false);
const isAllModels = !team.models || team.models.length === 0 || team.models.includes("all-proxy-models");
const modelEntries: ModelEntry[] = useMemo(() => {
const entries: ModelEntry[] = (team.models || []).map((m) => ({
if (isAllModels) return [];
const entries: ModelEntry[] = team.models.map((m) => ({
name: m,
source: "direct" as const,
}));
@ -25,7 +28,7 @@ const ModelsCell = ({ team }: ModelsCellProps) => {
entries.push({ name: m, source: "access_group" });
}
return entries;
}, [team.models, team.access_group_models]);
}, [team.models, team.access_group_models, isAllModels]);
const renderBadge = (entry: ModelEntry, index: number) => {
if (entry.name === "all-proxy-models") {

View file

@ -655,7 +655,7 @@ const TeamInfoView: React.FC<TeamInfoProps> = ({
<Card>
<Text>Models</Text>
<div className="mt-2 flex flex-wrap gap-2">
{info.models.length === 0 && !(info.access_group_models?.length) ? (
{info.models.length === 0 || info.models.includes("all-proxy-models") ? (
<Badge color="red">All proxy models</Badge>
) : (
<>
@ -672,7 +672,7 @@ const TeamInfoView: React.FC<TeamInfoProps> = ({
</>
)}
</div>
{info.access_group_models && info.access_group_models.length > 0 && (
{info.models.length > 0 && !info.models.includes("all-proxy-models") && info.access_group_models && info.access_group_models.length > 0 && (
<div className="mt-2">
<Text className="text-xs text-gray-500">
<span className="inline-block w-2 h-2 rounded-full bg-blue-500 mr-1" />Direct