From 40c26f343a396a748a960f9727491c6ae2ef6c66 Mon Sep 17 00:00:00 2001 From: zcxads666 <1316510990@qq.com> Date: Wed, 12 Aug 2026 14:54:08 +0800 Subject: [PATCH] =?UTF-8?q?fix(openai):=20=E7=A9=BA=20openai=5Fcapabilitie?= =?UTF-8?q?s=20=E4=B8=8D=E5=86=8D=E6=8E=92=E9=99=A4=20OAuth=20=E8=B4=A6?= =?UTF-8?q?=E5=8F=B7=E7=9A=84=E6=96=87=E6=9C=AC=E8=B0=83=E5=BA=A6=EF=BC=88?= =?UTF-8?q?#5530=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/internal/service/account.go | 15 +++++ .../internal/service/openai_images_test.go | 61 +++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/backend/internal/service/account.go b/backend/internal/service/account.go index 44c8845e4..b30c6829a 100644 --- a/backend/internal/service/account.go +++ b/backend/internal/service/account.go @@ -1861,18 +1861,30 @@ func (a *Account) openAIEndpointCapabilitySet() (map[string]bool, bool) { result[value] = true } + // 空容器({} / [])与未配置一致:不限制任何能力。 + // 避免 OAuth 账号因 API 直写/导入/历史数据遗留的空对象而被调度器静默排除(#5530)。 + // 注意:非空但全 false / 类型异常的数据仍视为「已配置且不含能力」,保持原行为。 switch capabilities := raw.(type) { case []any: + if len(capabilities) == 0 { + return nil, false + } for _, item := range capabilities { if value, ok := item.(string); ok { add(value) } } case []string: + if len(capabilities) == 0 { + return nil, false + } for _, value := range capabilities { add(value) } case map[string]any: + if len(capabilities) == 0 { + return nil, false + } for key, value := range capabilities { enabled, ok := value.(bool) if ok && enabled { @@ -1880,6 +1892,9 @@ func (a *Account) openAIEndpointCapabilitySet() (map[string]bool, bool) { } } case map[string]bool: + if len(capabilities) == 0 { + return nil, false + } for key, enabled := range capabilities { if enabled { add(key) diff --git a/backend/internal/service/openai_images_test.go b/backend/internal/service/openai_images_test.go index cb2fdf1b5..99afeba6a 100644 --- a/backend/internal/service/openai_images_test.go +++ b/backend/internal/service/openai_images_test.go @@ -593,6 +593,67 @@ func TestAccountSupportsOpenAIEndpointCapability(t *testing.T) { require.True(t, account.SupportsOpenAIEndpointCapability(OpenAIEndpointCapabilityEmbeddings)) }) + t.Run("空 openai_capabilities({})与未配置一致,不排除 OAuth 文本调度", func(t *testing.T) { + account := &Account{ + Platform: PlatformOpenAI, + Type: AccountTypeOAuth, + Credentials: map[string]any{ + "openai_capabilities": map[string]any{}, + }, + } + + require.True(t, account.SupportsOpenAIEndpointCapability(OpenAIEndpointCapabilityChatCompletions)) + require.True(t, account.SupportsOpenAIEndpointCapability(OpenAIEndpointCapabilityResponses)) + }) + + t.Run("空 openai_capabilities([]any)与未配置一致,不排除 OAuth 文本调度", func(t *testing.T) { + account := &Account{ + Platform: PlatformOpenAI, + Type: AccountTypeOAuth, + Credentials: map[string]any{ + "openai_capabilities": []any{}, + }, + } + + require.True(t, account.SupportsOpenAIEndpointCapability(OpenAIEndpointCapabilityChatCompletions)) + }) + + t.Run("空 openai_capabilities([]string)与未配置一致,不排除 OAuth 文本调度", func(t *testing.T) { + account := &Account{ + Platform: PlatformOpenAI, + Type: AccountTypeOAuth, + Credentials: map[string]any{ + "openai_capabilities": []string{}, + }, + } + + require.True(t, account.SupportsOpenAIEndpointCapability(OpenAIEndpointCapabilityChatCompletions)) + }) + + t.Run("非空但全 false 的 map 仍按显式禁用处理,不默认放行", func(t *testing.T) { + account := &Account{ + Platform: PlatformOpenAI, + Type: AccountTypeOAuth, + Credentials: map[string]any{ + "openai_capabilities": map[string]any{"chat_completions": false}, + }, + } + + require.False(t, account.SupportsOpenAIEndpointCapability(OpenAIEndpointCapabilityChatCompletions)) + }) + + t.Run("类型异常(字符串)仍视为已配置但不含能力,不默认放行", func(t *testing.T) { + account := &Account{ + Platform: PlatformOpenAI, + Type: AccountTypeOAuth, + Credentials: map[string]any{ + "openai_capabilities": "chat_completions", + }, + } + + require.False(t, account.SupportsOpenAIEndpointCapability(OpenAIEndpointCapabilityChatCompletions)) + }) + t.Run("未知能力不应默认放行", func(t *testing.T) { account := &Account{ Platform: PlatformOpenAI,