Skip to content

Commit f7f2493

Browse files
committed
feat(models): enforce provider policy on reads
1 parent 2dbc928 commit f7f2493

9 files changed

Lines changed: 449 additions & 49 deletions

File tree

.secrets.baseline

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6589,7 +6589,7 @@
65896589
"filename": "src/lfx/src/lfx/base/models/unified_models/model_catalog.py",
65906590
"hashed_secret": "665b1e3851eefefa3fb878654292f16597d25155",
65916591
"is_verified": false,
6592-
"line_number": 498,
6592+
"line_number": 502,
65936593
"is_secret": false
65946594
}
65956595
],
@@ -7203,5 +7203,5 @@
72037203
}
72047204
]
72057205
},
7206-
"generated_at": "2026-07-29T00:40:06Z"
7206+
"generated_at": "2026-07-29T21:58:24Z"
72077207
}
Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,93 @@
1-
from fastapi import APIRouter
2-
from lfx.base.models.unified_models import get_embedding_model_options, get_language_model_options
1+
from typing import Annotated, Literal
2+
3+
from fastapi import APIRouter, Query
4+
from lfx.base.models.provider_registry import resolve_provider_id
5+
from lfx.base.models.unified_models import (
6+
get_embedding_model_options,
7+
get_language_model_options,
8+
get_model_providers,
9+
)
10+
from lfx.services.model_provider_policy import (
11+
ModelProviderPolicyPurpose,
12+
ModelProviderPolicySnapshot,
13+
aresolve_model_provider_policy,
14+
)
315

416
from langflow.api.utils import CurrentActiveUser
517

618
router = APIRouter(prefix="/model_options", tags=["Model Options"], include_in_schema=False)
719

20+
ProviderReadPurpose = Literal["use", "configure"]
21+
22+
23+
async def _resolve_option_policy(
24+
current_user: CurrentActiveUser,
25+
purpose: ProviderReadPurpose | None,
26+
) -> ModelProviderPolicySnapshot:
27+
providers = get_model_providers()
28+
baseline = await aresolve_model_provider_policy(
29+
user_id=current_user.id,
30+
providers=providers,
31+
purpose=ModelProviderPolicyPurpose.USE,
32+
attributes={"is_superuser": bool(getattr(current_user, "is_superuser", False))},
33+
)
34+
requested = ModelProviderPolicyPurpose(purpose) if purpose is not None else ModelProviderPolicyPurpose.USE
35+
if requested is ModelProviderPolicyPurpose.USE:
36+
return baseline
37+
requested_snapshot = await aresolve_model_provider_policy(
38+
user_id=current_user.id,
39+
providers=providers,
40+
purpose=requested,
41+
attributes={"is_superuser": bool(getattr(current_user, "is_superuser", False))},
42+
)
43+
return ModelProviderPolicySnapshot(
44+
context=baseline.context,
45+
purpose=requested,
46+
candidate_provider_ids=baseline.candidate_provider_ids,
47+
allowed_provider_ids=baseline.allowed_provider_ids & requested_snapshot.allowed_provider_ids,
48+
)
49+
50+
51+
def _annotate_options(
52+
options: list[dict],
53+
provider_policy: ModelProviderPolicySnapshot,
54+
) -> list[dict]:
55+
annotated_options = []
56+
for option in options:
57+
provider = option.get("provider")
58+
if not isinstance(provider, str) or not provider_policy.allows(provider):
59+
continue
60+
annotated_options.append(
61+
{
62+
**option,
63+
"provider_id": resolve_provider_id(provider),
64+
"is_allowed": True,
65+
}
66+
)
67+
return annotated_options
68+
869

970
@router.get("/language", status_code=200)
1071
async def get_language_model_options_endpoint(
1172
current_user: CurrentActiveUser,
73+
purpose: Annotated[ProviderReadPurpose | None, Query()] = None,
1274
):
1375
"""Get language model options filtered by user's enabled providers and models."""
14-
return get_language_model_options(user_id=current_user.id)
76+
provider_policy = await _resolve_option_policy(current_user, purpose)
77+
return _annotate_options(
78+
get_language_model_options(user_id=current_user.id, provider_policy=provider_policy),
79+
provider_policy,
80+
)
1581

1682

1783
@router.get("/embedding", status_code=200)
1884
async def get_embedding_model_options_endpoint(
1985
current_user: CurrentActiveUser,
86+
purpose: Annotated[ProviderReadPurpose | None, Query()] = None,
2087
):
2188
"""Get embedding model options filtered by user's enabled providers and models."""
22-
return get_embedding_model_options(user_id=current_user.id)
89+
provider_policy = await _resolve_option_policy(current_user, purpose)
90+
return _annotate_options(
91+
get_embedding_model_options(user_id=current_user.id, provider_policy=provider_policy),
92+
provider_policy,
93+
)

0 commit comments

Comments
 (0)