feat: add silicon provider support for Anthropic API compatibility (#11468)

* feat: add silicon provider support for Anthropic API compatibility

* fix: update handling of ANTHROPIC_BASE_URL for silicon provider compatibility

* fix: update anthropicApiHost for silicon provider to use the correct endpoint

* fix: remove silicon from CLAUDE_OFFICIAL_SUPPORTED_PROVIDERS

* chore: add comment to clarify silicon model fallback logic in CLAUDE_OFFICIAL_SUPPORTED_PROVIDERS
This commit is contained in:
SuYao
2025-11-26 19:19:34 +08:00
committed by GitHub
parent 155930ecf4
commit 28dff9dfe3
8 changed files with 105 additions and 5 deletions

View File

@@ -0,0 +1,48 @@
/**
* @fileoverview Shared provider configuration for Claude Code and Anthropic API compatibility
*
* This module defines which models from specific providers support the Anthropic API endpoint.
* Used by both the Code Tools page and the Anthropic SDK client.
*/
/**
* Silicon provider models that support Anthropic API endpoint.
* These models can be used with Claude Code via the Anthropic-compatible API.
*
* @see https://docs.siliconflow.cn/cn/api-reference/chat-completions/messages
*/
export const SILICON_ANTHROPIC_COMPATIBLE_MODELS: readonly string[] = [
// DeepSeek V3.1 series
'Pro/deepseek-ai/DeepSeek-V3.1-Terminus',
'deepseek-ai/DeepSeek-V3.1',
'Pro/deepseek-ai/DeepSeek-V3.1',
// DeepSeek V3 series
'deepseek-ai/DeepSeek-V3',
'Pro/deepseek-ai/DeepSeek-V3',
// Moonshot/Kimi series
'moonshotai/Kimi-K2-Instruct-0905',
'Pro/moonshotai/Kimi-K2-Instruct-0905',
'moonshotai/Kimi-Dev-72B',
// Baidu ERNIE
'baidu/ERNIE-4.5-300B-A47B'
]
/**
* Creates a Set for efficient lookup of silicon Anthropic-compatible model IDs.
*/
const SILICON_ANTHROPIC_COMPATIBLE_MODEL_SET = new Set(SILICON_ANTHROPIC_COMPATIBLE_MODELS)
/**
* Checks if a model ID is compatible with Anthropic API on Silicon provider.
*
* @param modelId - The model ID to check
* @returns true if the model supports Anthropic API endpoint
*/
export function isSiliconAnthropicCompatibleModel(modelId: string): boolean {
return SILICON_ANTHROPIC_COMPATIBLE_MODEL_SET.has(modelId)
}
/**
* Silicon provider's Anthropic API host URL.
*/
export const SILICON_ANTHROPIC_API_HOST = 'https://api.siliconflow.cn'

View File

@@ -1,6 +1,7 @@
import { CacheService } from '@main/services/CacheService'
import { loggerService } from '@main/services/LoggerService'
import { reduxService } from '@main/services/ReduxService'
import { isSiliconAnthropicCompatibleModel } from '@shared/config/providers'
import type { ApiModel, Model, Provider } from '@types'
const logger = loggerService.withContext('ApiServerUtils')
@@ -287,6 +288,8 @@ export const getProviderAnthropicModelChecker = (providerId: string): ((m: Model
return (m: Model) => m.endpoint_type === 'anthropic'
case 'aihubmix':
return (m: Model) => m.id.includes('claude')
case 'silicon':
return (m: Model) => isSiliconAnthropicCompatibleModel(m.id)
default:
// allow all models when checker not configured
return () => true

View File

@@ -95,6 +95,7 @@ export const SYSTEM_PROVIDERS_CONFIG: Record<SystemProviderId, SystemProvider> =
type: 'openai',
apiKey: '',
apiHost: 'https://api.siliconflow.cn',
anthropicApiHost: 'https://api.siliconflow.cn',
models: SYSTEM_MODELS.silicon,
isSystem: true,
enabled: false
@@ -168,6 +169,7 @@ export const SYSTEM_PROVIDERS_CONFIG: Record<SystemProviderId, SystemProvider> =
type: 'openai',
apiKey: '',
apiHost: 'https://www.dmxapi.cn',
anthropicApiHost: 'https://www.dmxapi.cn',
models: SYSTEM_MODELS.dmxapi,
isSystem: true,
enabled: false

View File

@@ -17,6 +17,7 @@ import type { EndpointType, Model } from '@renderer/types'
import { getClaudeSupportedProviders } from '@renderer/utils/provider'
import type { TerminalConfig } from '@shared/config/constant'
import { codeTools, terminalApps } from '@shared/config/constant'
import { isSiliconAnthropicCompatibleModel } from '@shared/config/providers'
import { Alert, Avatar, Button, Checkbox, Input, Popover, Select, Space, Tooltip } from 'antd'
import { ArrowUpRight, Download, FolderOpen, HelpCircle, Terminal, X } from 'lucide-react'
import type { FC } from 'react'
@@ -81,6 +82,10 @@ const CodeToolsPage: FC = () => {
if (m.supported_endpoint_types) {
return m.supported_endpoint_types.includes('anthropic')
}
// Special handling for silicon provider: only specific models support Anthropic API
if (m.provider === 'silicon') {
return isSiliconAnthropicCompatibleModel(m.id)
}
return m.id.includes('claude') || CLAUDE_OFFICIAL_SUPPORTED_PROVIDERS.includes(m.provider)
}

View File

@@ -1,4 +1,4 @@
import type { EndpointType, Model, Provider } from '@renderer/types'
import { type EndpointType, type Model, type Provider, SystemProviderIds } from '@renderer/types'
import { codeTools } from '@shared/config/constant'
export interface LaunchValidationResult {
@@ -25,7 +25,18 @@ export const CLI_TOOLS = [
]
export const GEMINI_SUPPORTED_PROVIDERS = ['aihubmix', 'dmxapi', 'new-api', 'cherryin']
export const CLAUDE_OFFICIAL_SUPPORTED_PROVIDERS = ['deepseek', 'moonshot', 'zhipu', 'dashscope', 'modelscope']
export const CLAUDE_OFFICIAL_SUPPORTED_PROVIDERS = [
'deepseek',
'moonshot',
'zhipu',
'dashscope',
'modelscope',
'minimax',
'longcat',
SystemProviderIds.qiniu
// If silicon is in this list, the fallback logic above will return true for all silicon models,
// potentially bypassing the specific model filtering you added above.
]
export const CLAUDE_SUPPORTED_PROVIDERS = [
'aihubmix',
'dmxapi',
@@ -79,6 +90,11 @@ export const getCodeToolsApiBaseUrl = (model: Model, type: EndpointType) => {
anthropic: {
api_base_url: 'https://api-inference.modelscope.cn'
}
},
minimax: {
anthropic: {
api_base_url: 'https://api.minimaxi.com/anthropic'
}
}
}
@@ -125,7 +141,8 @@ export const generateToolEnvironment = ({
switch (tool) {
case codeTools.claudeCode:
env.ANTHROPIC_BASE_URL = getCodeToolsApiBaseUrl(model, 'anthropic') || modelProvider.apiHost
env.ANTHROPIC_BASE_URL =
getCodeToolsApiBaseUrl(model, 'anthropic') || modelProvider.anthropicApiHost || modelProvider.apiHost
env.ANTHROPIC_MODEL = model.id
if (modelProvider.type === 'anthropic') {
env.ANTHROPIC_API_KEY = apiKey

View File

@@ -82,7 +82,10 @@ const ANTHROPIC_COMPATIBLE_PROVIDER_IDS = [
SystemProviderIds.grok,
SystemProviderIds.cherryin,
SystemProviderIds.longcat,
SystemProviderIds.minimax
SystemProviderIds.minimax,
SystemProviderIds.silicon,
SystemProviderIds.qiniu,
SystemProviderIds.dmxapi
] as const
type AnthropicCompatibleProviderId = (typeof ANTHROPIC_COMPATIBLE_PROVIDER_IDS)[number]

View File

@@ -67,7 +67,7 @@ const persistedReducer = persistReducer(
{
key: 'cherry-studio',
storage,
version: 178,
version: 179,
blacklist: ['runtime', 'messages', 'messageBlocks', 'tabs', 'toolPermissions'],
migrate
},

View File

@@ -2884,6 +2884,28 @@ const migrateConfig = {
logger.error('migrate 178 error', error as Error)
return state
}
},
'179': (state: RootState) => {
try {
state.llm.providers.forEach((provider) => {
switch (provider.id) {
case SystemProviderIds.silicon:
provider.anthropicApiHost = 'https://api.siliconflow.cn'
break
case SystemProviderIds.qiniu:
provider.anthropicApiHost = 'https://api.qnaigc.com'
break
case SystemProviderIds.dmxapi:
provider.anthropicApiHost = provider.apiHost
break
}
})
logger.info('migrate 179 success')
return state
} catch (error) {
logger.error('migrate 179 error', error as Error)
return state
}
}
}