From de28eea11fe0e59d053fb4006beaeccd77348113 Mon Sep 17 00:00:00 2001 From: GongTengXY <1497404080@qq.com> Date: Wed, 9 Sep 2026 11:23:42 +0800 Subject: [PATCH] fix(openai): filter account test models by model mapping --- .../service/account_test_models_test.go | 31 +++++++++++++++++++ .../internal/service/account_test_service.go | 9 +++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/backend/internal/service/account_test_models_test.go b/backend/internal/service/account_test_models_test.go index 59af5edbd9..29cdcf94aa 100644 --- a/backend/internal/service/account_test_models_test.go +++ b/backend/internal/service/account_test_models_test.go @@ -72,6 +72,37 @@ func TestFetchOpenAIAccountModelsAPIKeyPopulatesPickerFields(t *testing.T) { require.Equal(t, "named-model", models[2].ID) } +func TestFetchOpenAIAccountModelsAPIKeyAppliesAccountModelMapping(t *testing.T) { + gateway := newCodexModelsAPIKeyTestService(&codexModelsHTTPUpstreamStub{do: func(_ *http.Request, _ string, _ int64, _ int) (*http.Response, error) { + return ordinaryModelsUpstreamResponse(`{"data":[ + {"id":"upstream-target","owned_by":"provider","created":123}, + {"id":"direct-model","owned_by":"provider"}, + {"id":"unconfigured-model","owned_by":"provider"} + ]}`), nil + }}) + svc := &AccountTestService{openaiGatewayService: gateway} + account := newCodexModelsAPIKeyTestAccount("https://models.example/v1") + account.Credentials["model_mapping"] = map[string]any{ + "configured-alias": "upstream-target", + "direct-model": "direct-model", + } + + models, err := svc.FetchOpenAIAccountModels(context.Background(), account) + require.NoError(t, err) + require.Len(t, models, 2) + ids := []string{models[0].ID, models[1].ID} + require.ElementsMatch(t, []string{"configured-alias", "direct-model"}, ids) + require.NotContains(t, ids, "unconfigured-model") + alias := models[0] + if alias.ID != "configured-alias" { + alias = models[1] + } + require.Equal(t, "configured-alias", alias.ID) + require.Equal(t, "configured-alias", alias.DisplayName) + require.Equal(t, "provider", alias.OwnedBy) + require.EqualValues(t, 123, alias.Created) +} + func TestFetchOpenAIAccountModelsPreservesEmptyCatalog(t *testing.T) { gateway := newCodexModelsAPIKeyTestService(&codexModelsHTTPUpstreamStub{do: func(_ *http.Request, _ string, _ int64, _ int) (*http.Response, error) { return ordinaryModelsUpstreamResponse(`{"data":[]}`), nil diff --git a/backend/internal/service/account_test_service.go b/backend/internal/service/account_test_service.go index b56861ebb6..421a982077 100644 --- a/backend/internal/service/account_test_service.go +++ b/backend/internal/service/account_test_service.go @@ -188,10 +188,17 @@ func (s *AccountTestService) FetchOpenAIAccountModels(ctx context.Context, accou if err != nil { return nil, err } + // The shared discovery response is the raw upstream catalog. Project it + // through the account mapping before exposing it in the admin picker so + // configured aliases remain public names and unconfigured models stay out. + projectedBody, err := projectAccountModelsBody(response.Body, account, nil, false) + if err != nil { + return nil, fmt.Errorf("project OpenAI account models: %w", err) + } var payload struct { Data []openai.Model `json:"data"` } - if err := json.Unmarshal(response.Body, &payload); err != nil { + if err := json.Unmarshal(projectedBody, &payload); err != nil { return nil, fmt.Errorf("decode OpenAI account models: %w", err) } // Every entry in the picker is labelled by the same rule: the upstream display