mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-19 14:41:24 +08:00
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:
parent
155930ecf4
commit
28dff9dfe3
48
packages/shared/config/providers.ts
Normal file
48
packages/shared/config/providers.ts
Normal 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'
|
||||||
@ -1,6 +1,7 @@
|
|||||||
import { CacheService } from '@main/services/CacheService'
|
import { CacheService } from '@main/services/CacheService'
|
||||||
import { loggerService } from '@main/services/LoggerService'
|
import { loggerService } from '@main/services/LoggerService'
|
||||||
import { reduxService } from '@main/services/ReduxService'
|
import { reduxService } from '@main/services/ReduxService'
|
||||||
|
import { isSiliconAnthropicCompatibleModel } from '@shared/config/providers'
|
||||||
import type { ApiModel, Model, Provider } from '@types'
|
import type { ApiModel, Model, Provider } from '@types'
|
||||||
|
|
||||||
const logger = loggerService.withContext('ApiServerUtils')
|
const logger = loggerService.withContext('ApiServerUtils')
|
||||||
@ -287,6 +288,8 @@ export const getProviderAnthropicModelChecker = (providerId: string): ((m: Model
|
|||||||
return (m: Model) => m.endpoint_type === 'anthropic'
|
return (m: Model) => m.endpoint_type === 'anthropic'
|
||||||
case 'aihubmix':
|
case 'aihubmix':
|
||||||
return (m: Model) => m.id.includes('claude')
|
return (m: Model) => m.id.includes('claude')
|
||||||
|
case 'silicon':
|
||||||
|
return (m: Model) => isSiliconAnthropicCompatibleModel(m.id)
|
||||||
default:
|
default:
|
||||||
// allow all models when checker not configured
|
// allow all models when checker not configured
|
||||||
return () => true
|
return () => true
|
||||||
|
|||||||
@ -95,6 +95,7 @@ export const SYSTEM_PROVIDERS_CONFIG: Record<SystemProviderId, SystemProvider> =
|
|||||||
type: 'openai',
|
type: 'openai',
|
||||||
apiKey: '',
|
apiKey: '',
|
||||||
apiHost: 'https://api.siliconflow.cn',
|
apiHost: 'https://api.siliconflow.cn',
|
||||||
|
anthropicApiHost: 'https://api.siliconflow.cn',
|
||||||
models: SYSTEM_MODELS.silicon,
|
models: SYSTEM_MODELS.silicon,
|
||||||
isSystem: true,
|
isSystem: true,
|
||||||
enabled: false
|
enabled: false
|
||||||
@ -168,6 +169,7 @@ export const SYSTEM_PROVIDERS_CONFIG: Record<SystemProviderId, SystemProvider> =
|
|||||||
type: 'openai',
|
type: 'openai',
|
||||||
apiKey: '',
|
apiKey: '',
|
||||||
apiHost: 'https://www.dmxapi.cn',
|
apiHost: 'https://www.dmxapi.cn',
|
||||||
|
anthropicApiHost: 'https://www.dmxapi.cn',
|
||||||
models: SYSTEM_MODELS.dmxapi,
|
models: SYSTEM_MODELS.dmxapi,
|
||||||
isSystem: true,
|
isSystem: true,
|
||||||
enabled: false
|
enabled: false
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import type { EndpointType, Model } from '@renderer/types'
|
|||||||
import { getClaudeSupportedProviders } from '@renderer/utils/provider'
|
import { getClaudeSupportedProviders } from '@renderer/utils/provider'
|
||||||
import type { TerminalConfig } from '@shared/config/constant'
|
import type { TerminalConfig } from '@shared/config/constant'
|
||||||
import { codeTools, terminalApps } 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 { Alert, Avatar, Button, Checkbox, Input, Popover, Select, Space, Tooltip } from 'antd'
|
||||||
import { ArrowUpRight, Download, FolderOpen, HelpCircle, Terminal, X } from 'lucide-react'
|
import { ArrowUpRight, Download, FolderOpen, HelpCircle, Terminal, X } from 'lucide-react'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
@ -81,6 +82,10 @@ const CodeToolsPage: FC = () => {
|
|||||||
if (m.supported_endpoint_types) {
|
if (m.supported_endpoint_types) {
|
||||||
return m.supported_endpoint_types.includes('anthropic')
|
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)
|
return m.id.includes('claude') || CLAUDE_OFFICIAL_SUPPORTED_PROVIDERS.includes(m.provider)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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'
|
import { codeTools } from '@shared/config/constant'
|
||||||
|
|
||||||
export interface LaunchValidationResult {
|
export interface LaunchValidationResult {
|
||||||
@ -25,7 +25,18 @@ export const CLI_TOOLS = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
export const GEMINI_SUPPORTED_PROVIDERS = ['aihubmix', 'dmxapi', 'new-api', 'cherryin']
|
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 = [
|
export const CLAUDE_SUPPORTED_PROVIDERS = [
|
||||||
'aihubmix',
|
'aihubmix',
|
||||||
'dmxapi',
|
'dmxapi',
|
||||||
@ -79,6 +90,11 @@ export const getCodeToolsApiBaseUrl = (model: Model, type: EndpointType) => {
|
|||||||
anthropic: {
|
anthropic: {
|
||||||
api_base_url: 'https://api-inference.modelscope.cn'
|
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) {
|
switch (tool) {
|
||||||
case codeTools.claudeCode:
|
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
|
env.ANTHROPIC_MODEL = model.id
|
||||||
if (modelProvider.type === 'anthropic') {
|
if (modelProvider.type === 'anthropic') {
|
||||||
env.ANTHROPIC_API_KEY = apiKey
|
env.ANTHROPIC_API_KEY = apiKey
|
||||||
|
|||||||
@ -82,7 +82,10 @@ const ANTHROPIC_COMPATIBLE_PROVIDER_IDS = [
|
|||||||
SystemProviderIds.grok,
|
SystemProviderIds.grok,
|
||||||
SystemProviderIds.cherryin,
|
SystemProviderIds.cherryin,
|
||||||
SystemProviderIds.longcat,
|
SystemProviderIds.longcat,
|
||||||
SystemProviderIds.minimax
|
SystemProviderIds.minimax,
|
||||||
|
SystemProviderIds.silicon,
|
||||||
|
SystemProviderIds.qiniu,
|
||||||
|
SystemProviderIds.dmxapi
|
||||||
] as const
|
] as const
|
||||||
type AnthropicCompatibleProviderId = (typeof ANTHROPIC_COMPATIBLE_PROVIDER_IDS)[number]
|
type AnthropicCompatibleProviderId = (typeof ANTHROPIC_COMPATIBLE_PROVIDER_IDS)[number]
|
||||||
|
|
||||||
|
|||||||
@ -67,7 +67,7 @@ const persistedReducer = persistReducer(
|
|||||||
{
|
{
|
||||||
key: 'cherry-studio',
|
key: 'cherry-studio',
|
||||||
storage,
|
storage,
|
||||||
version: 178,
|
version: 179,
|
||||||
blacklist: ['runtime', 'messages', 'messageBlocks', 'tabs', 'toolPermissions'],
|
blacklist: ['runtime', 'messages', 'messageBlocks', 'tabs', 'toolPermissions'],
|
||||||
migrate
|
migrate
|
||||||
},
|
},
|
||||||
|
|||||||
@ -2884,6 +2884,28 @@ const migrateConfig = {
|
|||||||
logger.error('migrate 178 error', error as Error)
|
logger.error('migrate 178 error', error as Error)
|
||||||
return state
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user