Merge pull request #7793 from wucm667/fix/issue-7784-composite-route-model-list

fix(models): list composite exact route aliases
This commit is contained in:
Wesley Liddick
2026-10-08 11:39:51 +08:00
committed by GitHub
5 changed files with 423 additions and 13 deletions
+21 -11
View File
@@ -1166,7 +1166,7 @@ func (h *GatewayHandler) Models(c *gin.Context) {
}
if platform == service.PlatformComposite {
availableModels := h.compositeAvailableModels(c.Request.Context(), groupID, true)
availableModels := h.compositeAvailableModels(c.Request.Context(), groupID, "", true)
if apiKey != nil && apiKey.Group != nil && apiKey.Group.ModelAllowlistEnabled() {
source := availableModels
if len(source) == 0 {
@@ -1265,19 +1265,19 @@ func (h *GatewayHandler) codexModelIDsForGroup(ctx context.Context, group *servi
platform = group.Platform
}
if platform == service.PlatformComposite {
availableModels := h.compositeAvailableModels(ctx, groupID, false)
availableModels := h.compositeAvailableModels(ctx, groupID, service.CompositeRouteEndpointResponses, false)
fallbackModels := defaultCodexModelIDsForPlatform(service.PlatformComposite)
models := availableModels
if len(models) == 0 {
models = fallbackModels
}
if group.ModelAllowlistEnabled() {
source := availableModels
if len(source) == 0 {
source = fallbackModels
}
return group.ModelAllowlist.FilterForListing(source)
models = group.ModelAllowlist.FilterForListing(models)
}
if len(availableModels) > 0 {
return availableModels
if filtered, err := h.gatewayService.FilterCompositeCodexModels(ctx, group.ID, models); err == nil {
return filtered
}
return fallbackModels
return models
}
availableModels := h.gatewayService.GetAvailableModels(ctx, groupID, platform)
@@ -1294,7 +1294,7 @@ func (h *GatewayHandler) codexModelIDsForGroup(ctx context.Context, group *servi
// compositeAvailableModels lists the models the composite group can serve.
// includeSystemOne adds TypeSafe models, which only work through /v1/systemone;
// LLM client catalogs (Codex) must exclude them.
func (h *GatewayHandler) compositeAvailableModels(ctx context.Context, groupID *int64, includeSystemOne bool) []string {
func (h *GatewayHandler) compositeAvailableModels(ctx context.Context, groupID *int64, endpoint string, includeSystemOne bool) []string {
if h == nil || h.gatewayService == nil {
return nil
}
@@ -1325,6 +1325,16 @@ func (h *GatewayHandler) compositeAvailableModels(ctx context.Context, groupID *
models = append(models, model)
}
}
// A route can expose a public ID that no account model mapping contains.
// On lookup failure, retain the existing account-derived catalog only.
if routeModels, err := h.gatewayService.GetCompositeRouteModels(ctx, groupID, endpoint, includeSystemOne); err == nil {
for _, model := range routeModels {
if _, ok := seen[model]; !ok {
seen[model] = struct{}{}
models = append(models, model)
}
}
}
return models
}
+262 -2
View File
@@ -3,6 +3,7 @@ package handler
import (
"context"
"encoding/json"
"errors"
"net/http"
"net/http/httptest"
"strings"
@@ -22,6 +23,16 @@ type gatewayModelsAccountRepoStub struct {
byGroup map[int64][]service.Account
}
type gatewayModelsRouteRepoStub struct {
service.CompositeModelRouteRepository
routes []service.CompositeModelRoute
err error
}
func (s *gatewayModelsRouteRepoStub) ListByGroup(_ context.Context, _ int64, _ bool) ([]service.CompositeModelRoute, error) {
return s.routes, s.err
}
type gatewayModelsResponseForTest struct {
Object string `json:"object"`
Data []gatewayModelItemForTest `json:"data"`
@@ -81,16 +92,80 @@ func (s *gatewayModelsAccountRepoStub) ListModelAvailabilityCandidates(ctx conte
return s.ListSchedulableByGroupID(ctx, *groupID)
}
func newGatewayModelsHandlerForTest(repo service.AccountRepository) *GatewayHandler {
func newGatewayModelsHandlerForTest(repo service.AccountRepository, routeRepo ...service.CompositeModelRouteRepository) *GatewayHandler {
var resolver *service.CompositeRouteResolver
if len(routeRepo) > 0 {
resolver = service.NewCompositeRouteResolver(routeRepo[0])
}
return &GatewayHandler{
gatewayService: service.NewGatewayService(
repo,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, resolver, nil, nil,
),
}
}
func TestGatewayCompositeRouteModelsAppearInBothCatalogs(t *testing.T) {
gin.SetMode(gin.TestMode)
const groupID int64 = 7784
accounts := &gatewayModelsAccountRepoStub{byGroup: map[int64][]service.Account{
groupID: {{ID: 1, Platform: service.PlatformOpenAI, Credentials: map[string]any{
"model_mapping": map[string]any{"mapped-model": "upstream"},
}}},
}}
routes := &gatewayModelsRouteRepoStub{routes: []service.CompositeModelRoute{
{PublicModel: "route-only", MatchType: service.CompositeRouteMatchExact, Enabled: true},
{PublicModel: "route-only", MatchType: service.CompositeRouteMatchExact, Enabled: true},
{PublicModel: "mapped-model", MatchType: service.CompositeRouteMatchExact, Enabled: true},
{PublicModel: "image-only", MatchType: service.CompositeRouteMatchExact, Endpoint: service.CompositeRouteEndpointImages, Enabled: true},
{PublicModel: "prefix-", MatchType: service.CompositeRouteMatchPrefix, Enabled: true},
{PublicModel: "disabled", MatchType: service.CompositeRouteMatchExact, Enabled: false},
}}
for _, tc := range []struct {
name string
repo service.CompositeModelRouteRepository
allowlist []string
want []string
}{
{"routes", routes, nil, []string{"mapped-model", "route-only", "image-only"}},
{"allowlist", routes, []string{"route-only", "disabled", "unknown"}, []string{"route-only"}},
{"lookup failure", &gatewayModelsRouteRepoStub{err: errors.New("unavailable")}, nil, []string{"mapped-model"}},
{"allowlisted lookup failure", &gatewayModelsRouteRepoStub{err: errors.New("unavailable")}, []string{"mapped-model", "unknown"}, []string{"mapped-model"}},
{"no route repo", nil, nil, []string{"mapped-model"}},
} {
t.Run(tc.name, func(t *testing.T) {
h := newGatewayModelsHandlerForTest(accounts, tc.repo)
group := &service.Group{ID: groupID, Platform: service.PlatformComposite}
if tc.allowlist != nil {
group.ModelAllowlist = service.GroupModelAllowlist{Enabled: true, Models: tc.allowlist}
}
for _, endpoint := range []string{"models", "codex"} {
rec := httptest.NewRecorder()
c, _ := gin.CreateTestContext(rec)
c.Request = httptest.NewRequest(http.MethodGet, "/v1/models", nil)
c.Set(string(middleware2.ContextKeyAPIKey), &service.APIKey{Group: group})
if endpoint == "models" {
h.Models(c)
var got gatewayModelsResponseForTest
require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &got))
require.Equal(t, tc.want, modelIDsForTest(got.Data))
} else {
h.CodexModels(c)
var got codexModelsResponseForTest
require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &got))
want := tc.want
if tc.name == "routes" {
want = []string{"mapped-model", "route-only"}
}
require.ElementsMatch(t, want, codexModelSlugsForTest(got.Models))
}
require.Equal(t, http.StatusOK, rec.Code)
}
})
}
}
func TestDefaultModelIDsForCompositeIncludesAntigravityDefaults(t *testing.T) {
antigravityIDs := defaultModelIDsForPlatform(service.PlatformAntigravity)
require.NotEmpty(t, antigravityIDs)
@@ -1570,3 +1645,188 @@ func TestDefaultModelIDsForPlatform_CompositeFallbackExcludesTypeSafe(t *testing
require.NotContains(t, defaultModelIDsForPlatform(service.PlatformComposite), "jev-latest")
require.NotContains(t, defaultCodexModelIDsForPlatform(service.PlatformComposite), "jev-latest")
}
func TestGatewayModels_CompositeExactRoutesRespectTypeSafeIsolation(t *testing.T) {
gin.SetMode(gin.TestMode)
const groupID int64 = 7784
routes := &gatewayModelsRouteRepoStub{routes: []service.CompositeModelRoute{
{PublicModel: "systemone-any-alias", TargetPlatform: service.PlatformTypeSafe, MatchType: service.CompositeRouteMatchExact, Endpoint: service.CompositeRouteEndpointAny, Enabled: true},
{PublicModel: "systemone-responses-alias", TargetPlatform: service.PlatformTypeSafe, MatchType: service.CompositeRouteMatchExact, Endpoint: service.CompositeRouteEndpointResponses, Enabled: true},
{PublicModel: "systemone-legacy-alias", TargetPlatform: service.PlatformTypeSafe, MatchType: service.CompositeRouteMatchExact, Enabled: true},
{PublicModel: "jev-latest", TargetPlatform: service.PlatformTypeSafe, MatchType: service.CompositeRouteMatchExact, Enabled: true},
{PublicModel: "responses-alias", TargetPlatform: service.PlatformOpenAI, MatchType: service.CompositeRouteMatchExact, Endpoint: service.CompositeRouteEndpointResponses, Enabled: true},
{PublicModel: "image-alias", TargetPlatform: service.PlatformOpenAI, MatchType: service.CompositeRouteMatchExact, Endpoint: service.CompositeRouteEndpointImages, Enabled: true},
}}
h := newGatewayModelsHandlerForTest(&gatewayModelsAccountRepoStub{}, routes)
wantModels := make([]string, 0, len(routes.routes))
for _, route := range routes.routes {
wantModels = append(wantModels, route.PublicModel)
}
for _, allowlisted := range []bool{false, true} {
name := "unrestricted"
if allowlisted {
name = "allowlisted"
}
t.Run(name, func(t *testing.T) {
group := &service.Group{ID: groupID, Platform: service.PlatformComposite}
if allowlisted {
group.ModelAllowlist = service.GroupModelAllowlist{Enabled: true, Models: []string{
"systemone-any-alias", "systemone-responses-alias", "systemone-legacy-alias", "jev-latest", "responses-alias", "image-alias",
}}
}
for _, codex := range []bool{false, true} {
rec := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(rec)
ctx.Request = httptest.NewRequest(http.MethodGet, "/v1/models", nil)
ctx.Set(string(middleware2.ContextKeyAPIKey), &service.APIKey{Group: group})
if codex {
h.CodexModels(ctx)
var manifest codexModelsResponseForTest
require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &manifest))
require.Equal(t, []string{"responses-alias"}, codexModelSlugsForTest(manifest.Models))
} else {
h.Models(ctx)
var models gatewayModelsResponseForTest
require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &models))
require.ElementsMatch(t, wantModels, modelIDsForTest(models.Data))
}
require.Equal(t, http.StatusOK, rec.Code)
}
})
}
}
func TestGatewayModels_CompositeCodexFiltersEffectiveResponsesRoutes(t *testing.T) {
gin.SetMode(gin.TestMode)
const groupID int64 = 7793
defaultModel := defaultModelIDsForPlatform(service.PlatformOpenAI)[0]
for _, scenario := range []struct {
name string
model string
accounts []service.Account
routes []service.CompositeModelRoute
}{
{
name: "colliding exact routes",
model: "shared-alias",
routes: []service.CompositeModelRoute{
{PublicModel: "shared-alias", TargetPlatform: service.PlatformOpenAI, MatchType: service.CompositeRouteMatchExact, Endpoint: service.CompositeRouteEndpointAny, Priority: 1, Enabled: true},
{PublicModel: "shared-alias", TargetPlatform: service.PlatformTypeSafe, MatchType: service.CompositeRouteMatchExact, Endpoint: service.CompositeRouteEndpointResponses, Priority: 100, Enabled: true},
},
},
{
name: "account alias exact override",
model: "account-alias",
accounts: []service.Account{{ID: 1, Platform: service.PlatformOpenAI, Credentials: map[string]any{
"model_mapping": map[string]any{"account-alias": "gpt-5"},
}}},
routes: []service.CompositeModelRoute{
{PublicModel: "account-alias", TargetPlatform: service.PlatformTypeSafe, MatchType: service.CompositeRouteMatchExact, Endpoint: service.CompositeRouteEndpointResponses, Enabled: true},
},
},
{
name: "account alias prefix override",
model: "account-alias",
accounts: []service.Account{{ID: 1, Platform: service.PlatformOpenAI, Credentials: map[string]any{
"model_mapping": map[string]any{"account-alias": "gpt-5"},
}}},
routes: []service.CompositeModelRoute{
{PublicModel: "account-", TargetPlatform: service.PlatformTypeSafe, MatchType: service.CompositeRouteMatchPrefix, Endpoint: service.CompositeRouteEndpointResponses, Enabled: true},
},
},
{
name: "account default override",
model: defaultModel,
accounts: []service.Account{{ID: 1, Platform: service.PlatformOpenAI}},
routes: []service.CompositeModelRoute{
{PublicModel: defaultModel, TargetPlatform: service.PlatformTypeSafe, MatchType: service.CompositeRouteMatchExact, Endpoint: service.CompositeRouteEndpointResponses, Enabled: true},
},
},
{
name: "fallback default override",
model: defaultModel,
routes: []service.CompositeModelRoute{
{PublicModel: defaultModel, TargetPlatform: service.PlatformTypeSafe, MatchType: service.CompositeRouteMatchPrefix, Endpoint: service.CompositeRouteEndpointResponses, Enabled: true},
},
},
} {
t.Run(scenario.name, func(t *testing.T) {
for _, allowlisted := range []bool{false, true} {
name := "unrestricted"
if allowlisted {
name = "allowlisted"
}
t.Run(name, func(t *testing.T) {
routes := append([]service.CompositeModelRoute(nil), scenario.routes...)
if scenario.name != "fallback default override" {
routes = append(routes, service.CompositeModelRoute{
PublicModel: "responses-control", TargetPlatform: service.PlatformOpenAI, MatchType: service.CompositeRouteMatchExact, Endpoint: service.CompositeRouteEndpointResponses, Enabled: true,
})
}
h := newGatewayModelsHandlerForTest(&gatewayModelsAccountRepoStub{
byGroup: map[int64][]service.Account{groupID: scenario.accounts},
}, &gatewayModelsRouteRepoStub{routes: routes})
group := &service.Group{ID: groupID, Platform: service.PlatformComposite}
if allowlisted {
group.ModelAllowlist = service.GroupModelAllowlist{Enabled: true, Models: []string{scenario.model, "responses-control"}}
}
for _, codex := range []bool{false, true} {
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx.Request = httptest.NewRequest(http.MethodGet, "/v1/models", nil)
ctx.Set(string(middleware2.ContextKeyAPIKey), &service.APIKey{Group: group})
if codex {
h.CodexModels(ctx)
var manifest codexModelsResponseForTest
require.NoError(t, json.Unmarshal(recorder.Body.Bytes(), &manifest))
slugs := codexModelSlugsForTest(manifest.Models)
require.NotContains(t, slugs, scenario.model)
if scenario.name != "fallback default override" {
require.Contains(t, slugs, "responses-control")
} else if allowlisted {
require.Empty(t, slugs)
}
} else {
h.Models(ctx)
var models gatewayModelsResponseForTest
require.NoError(t, json.Unmarshal(recorder.Body.Bytes(), &models))
require.Contains(t, modelIDsForTest(models.Data), scenario.model)
}
require.Equal(t, http.StatusOK, recorder.Code)
}
})
}
})
}
}
func TestGatewayModels_CompositeCodexRouteLookupErrorKeepsFallback(t *testing.T) {
gin.SetMode(gin.TestMode)
const groupID int64 = 7793
model := defaultCodexModelIDsForPlatform(service.PlatformComposite)[0]
for _, allowlisted := range []bool{false, true} {
name := "unrestricted"
if allowlisted {
name = "allowlisted"
}
t.Run(name, func(t *testing.T) {
h := newGatewayModelsHandlerForTest(&gatewayModelsAccountRepoStub{}, &gatewayModelsRouteRepoStub{err: errors.New("unavailable")})
group := &service.Group{ID: groupID, Platform: service.PlatformComposite}
if allowlisted {
group.ModelAllowlist = service.GroupModelAllowlist{Enabled: true, Models: []string{model}}
}
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx.Request = httptest.NewRequest(http.MethodGet, "/v1/models", nil)
ctx.Set(string(middleware2.ContextKeyAPIKey), &service.APIKey{Group: group})
h.CodexModels(ctx)
require.Equal(t, http.StatusOK, recorder.Code)
var manifest codexModelsResponseForTest
require.NoError(t, json.Unmarshal(recorder.Body.Bytes(), &manifest))
require.Contains(t, codexModelSlugsForTest(manifest.Models), model)
if allowlisted {
require.Len(t, manifest.Models, 1)
}
})
}
}
@@ -22,6 +22,52 @@ func (r *CompositeRouteResolver) SetModelOwnershipResolver(resolver CompositeMod
}
}
// ListExactPublicModels returns enabled, concrete route IDs suitable for a model catalog.
func (r *CompositeRouteResolver) ListExactPublicModels(ctx context.Context, groupID int64, endpoint string, includeSystemOne bool) ([]string, error) {
if r == nil || r.repo == nil || groupID <= 0 {
return nil, nil
}
routes, err := r.repo.ListByGroup(ctx, groupID, false)
if err != nil {
return nil, err
}
models := make([]string, 0, len(routes))
for _, route := range routes {
if route.Enabled && route.MatchType == CompositeRouteMatchExact &&
(endpoint == "" || normalizeCompositeRouteEndpoint(route.Endpoint) == CompositeRouteEndpointAny || normalizeCompositeRouteEndpoint(route.Endpoint) == endpoint) {
if model := strings.TrimSpace(route.PublicModel); model != "" {
models = append(models, model)
}
}
}
if !includeSystemOne {
models = filterSystemOneRouteModels(routes, models, endpoint)
}
return models, nil
}
func (r *CompositeRouteResolver) FilterCodexModels(ctx context.Context, groupID int64, models []string) ([]string, error) {
if r == nil || r.repo == nil || groupID <= 0 {
return models, nil
}
routes, err := r.repo.ListByGroup(ctx, groupID, false)
if err != nil {
return nil, err
}
return filterSystemOneRouteModels(routes, models, CompositeRouteEndpointResponses), nil
}
func filterSystemOneRouteModels(routes []CompositeModelRoute, models []string, endpoint string) []string {
filtered := make([]string, 0, len(models))
for _, model := range models {
route, matched := matchCompositeRoute(routes, model, normalizeCompositeRouteEndpoint(endpoint))
if !matched || route.TargetPlatform != PlatformTypeSafe {
filtered = append(filtered, model)
}
}
return filtered
}
func (r *CompositeRouteResolver) Resolve(ctx context.Context, groupID int64, model, endpoint string) (CompositeRouteDecision, error) {
model = strings.TrimSpace(model)
endpoint = normalizeCompositeRouteEndpoint(endpoint)
@@ -12,6 +12,85 @@ type compositeRouteRepoStub struct {
routes []CompositeModelRoute
}
func TestCompositeRouteResolverCodexFilteringMatchesProductionPriority(t *testing.T) {
for _, scenario := range []struct {
name string
routes []CompositeModelRoute
want []string
}{
{
name: "endpoint beats priority",
routes: []CompositeModelRoute{
{ID: 1, PublicModel: "alias", MatchType: CompositeRouteMatchExact, Endpoint: CompositeRouteEndpointAny, TargetPlatform: PlatformOpenAI, Priority: 1},
{ID: 2, PublicModel: "alias", MatchType: CompositeRouteMatchExact, Endpoint: CompositeRouteEndpointResponses, TargetPlatform: PlatformTypeSafe, Priority: 100},
},
want: []string{"unrouted"},
},
{
name: "Responses OpenAI overrides any TypeSafe",
routes: []CompositeModelRoute{
{ID: 1, PublicModel: "alias", MatchType: CompositeRouteMatchExact, Endpoint: CompositeRouteEndpointAny, TargetPlatform: PlatformTypeSafe, Priority: 1},
{ID: 2, PublicModel: "alias", MatchType: CompositeRouteMatchExact, Endpoint: CompositeRouteEndpointResponses, TargetPlatform: PlatformOpenAI, Priority: 100},
},
want: []string{"alias", "unrouted"},
},
{
name: "longer prefix beats priority",
routes: []CompositeModelRoute{
{ID: 1, PublicModel: "a", MatchType: CompositeRouteMatchPrefix, TargetPlatform: PlatformOpenAI, Priority: 1},
{ID: 2, PublicModel: "ali", MatchType: CompositeRouteMatchPrefix, TargetPlatform: PlatformTypeSafe, Priority: 100},
},
want: []string{"unrouted"},
},
{
name: "exact beats endpoint prefix",
routes: []CompositeModelRoute{
{ID: 1, PublicModel: "alias", MatchType: CompositeRouteMatchPrefix, Endpoint: CompositeRouteEndpointResponses, TargetPlatform: PlatformTypeSafe},
{ID: 2, PublicModel: "alias", MatchType: CompositeRouteMatchExact, Endpoint: CompositeRouteEndpointAny, TargetPlatform: PlatformOpenAI},
},
want: []string{"alias", "unrouted"},
},
{
name: "lower priority wins",
routes: []CompositeModelRoute{
{ID: 1, PublicModel: "alias", MatchType: CompositeRouteMatchExact, TargetPlatform: PlatformTypeSafe, Priority: 100},
{ID: 2, PublicModel: "alias", MatchType: CompositeRouteMatchExact, TargetPlatform: PlatformOpenAI, Priority: 1},
},
want: []string{"alias", "unrouted"},
},
{
name: "lower ID breaks tie",
routes: []CompositeModelRoute{
{ID: 2, PublicModel: "alias", MatchType: CompositeRouteMatchExact, TargetPlatform: PlatformOpenAI},
{ID: 1, PublicModel: "alias", MatchType: CompositeRouteMatchExact, TargetPlatform: PlatformTypeSafe},
},
want: []string{"unrouted"},
},
} {
t.Run(scenario.name, func(t *testing.T) {
for index := range scenario.routes {
scenario.routes[index].Enabled = true
scenario.routes[index].GroupID = 7
}
resolver := NewCompositeRouteResolver(compositeRouteRepoStub{routes: scenario.routes})
models, err := resolver.FilterCodexModels(context.Background(), 7, []string{"alias", "unrouted"})
require.NoError(t, err)
require.Equal(t, scenario.want, models)
decision, err := resolver.Resolve(context.Background(), 7, "alias", CompositeRouteEndpointResponses)
require.NoError(t, err)
require.True(t, decision.Matched)
require.Equal(t, decision.TargetPlatform != PlatformTypeSafe, len(models) == 2)
exactModels, err := resolver.ListExactPublicModels(context.Background(), 7, CompositeRouteEndpointResponses, false)
require.NoError(t, err)
if decision.TargetPlatform == PlatformTypeSafe {
require.Empty(t, exactModels)
} else {
require.Contains(t, exactModels, "alias")
}
})
}
}
func (s compositeRouteRepoStub) ListByGroup(ctx context.Context, groupID int64, includeDisabled bool) ([]CompositeModelRoute, error) {
routes := make([]CompositeModelRoute, 0, len(s.routes))
for _, route := range s.routes {
@@ -1535,6 +1535,21 @@ func explicitModelMappingClaims(account Account, model string) bool {
return ok && strings.TrimSpace(mapped) != ""
}
// GetCompositeRouteModels returns public IDs from enabled exact composite routes.
func (s *GatewayService) GetCompositeRouteModels(ctx context.Context, groupID *int64, endpoint string, includeSystemOne bool) ([]string, error) {
if s == nil || s.compositeResolver == nil || groupID == nil {
return nil, nil
}
return s.compositeResolver.ListExactPublicModels(ctx, *groupID, endpoint, includeSystemOne)
}
func (s *GatewayService) FilterCompositeCodexModels(ctx context.Context, groupID int64, models []string) ([]string, error) {
if s == nil || s.compositeResolver == nil {
return models, nil
}
return s.compositeResolver.FilterCodexModels(ctx, groupID, models)
}
// GetSchedulablePlatforms returns the concrete platforms that currently have
// schedulable accounts in the target group.
func (s *GatewayService) GetSchedulablePlatforms(ctx context.Context, groupID *int64) map[string]struct{} {