feat(aiCore): enhance dynamic provider registration and refactor HubProvider
- Introduced dynamic provider registration functionality, allowing for flexible management of providers through a new registry system. - Refactored HubProvider to streamline model resolution and improve error handling for unsupported models. - Added utility functions for managing dynamic providers, including registration, cleanup, and alias resolution. - Updated index exports to include new dynamic provider APIs, enhancing overall usability and integration. - Removed outdated provider files and simplified the provider management structure for better maintainability.
This commit is contained in:
@@ -284,6 +284,12 @@ export class AiSdkToChunkAdapter {
|
||||
}
|
||||
})
|
||||
break
|
||||
case 'abort':
|
||||
this.onChunk({
|
||||
type: ChunkType.ERROR,
|
||||
error: new DOMException('Request was aborted', 'AbortError')
|
||||
})
|
||||
break
|
||||
case 'error':
|
||||
this.onChunk({
|
||||
type: ChunkType.ERROR,
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
InvokeModelWithResponseStreamCommand
|
||||
} from '@aws-sdk/client-bedrock-runtime'
|
||||
import { loggerService } from '@logger'
|
||||
import { GenericChunk } from '@renderer/aiCore/middleware/schemas'
|
||||
import { GenericChunk } from '@renderer/aiCore/legacy/middleware/schemas'
|
||||
import { DEFAULT_MAX_TOKENS } from '@renderer/config/constant'
|
||||
import { findTokenLimit, isReasoningModel } from '@renderer/config/models'
|
||||
import {
|
||||
|
||||
@@ -1,109 +1,124 @@
|
||||
import { AiCore, ProviderConfigFactory, type ProviderId, type ProviderSettingsMap } from '@cherrystudio/ai-core'
|
||||
import { isDedicatedImageGenerationModel } from '@renderer/config/models'
|
||||
import { createVertexProvider, isVertexAIConfigured, isVertexProvider } from '@renderer/hooks/useVertexAI'
|
||||
import { getProviderByModel } from '@renderer/services/AssistantService'
|
||||
import type { Model, Provider } from '@renderer/types'
|
||||
import { formatApiHost } from '@renderer/utils/api'
|
||||
import { cloneDeep } from 'lodash'
|
||||
|
||||
import { createAihubmixProvider } from './aihubmix'
|
||||
import { aihubmixProviderCreator, newApiResolverCreator } from './config'
|
||||
import { getAiSdkProviderId } from './factory'
|
||||
|
||||
export function getActualProvider(model: Model): Provider {
|
||||
const provider = getProviderByModel(model)
|
||||
// 如果是 vertexai 类型且没有 googleCredentials,转换为 VertexProvider
|
||||
let actualProvider = cloneDeep(provider)
|
||||
/**
|
||||
* 处理特殊provider的转换逻辑
|
||||
*/
|
||||
function handleSpecialProviders(model: Model, provider: Provider): Provider {
|
||||
if (provider.type === 'vertexai' && !isVertexProvider(provider)) {
|
||||
if (!isVertexAIConfigured()) {
|
||||
throw new Error('VertexAI is not configured. Please configure project, location and service account credentials.')
|
||||
}
|
||||
actualProvider = createVertexProvider(provider)
|
||||
return createVertexProvider(provider)
|
||||
}
|
||||
|
||||
if (provider.id === 'aihubmix') {
|
||||
actualProvider = createAihubmixProvider(model, actualProvider)
|
||||
return aihubmixProviderCreator(model, provider)
|
||||
}
|
||||
if (actualProvider.type === 'gemini') {
|
||||
actualProvider.apiHost = formatApiHost(actualProvider.apiHost, 'v1beta')
|
||||
if (provider.id === 'newapi') {
|
||||
return newApiResolverCreator(model, provider)
|
||||
}
|
||||
return provider
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化provider的API Host
|
||||
*/
|
||||
function formatProviderApiHost(provider: Provider): Provider {
|
||||
const formatted = { ...provider }
|
||||
if (formatted.type === 'gemini') {
|
||||
formatted.apiHost = formatApiHost(formatted.apiHost, 'v1beta')
|
||||
} else {
|
||||
actualProvider.apiHost = formatApiHost(actualProvider.apiHost)
|
||||
formatted.apiHost = formatApiHost(formatted.apiHost)
|
||||
}
|
||||
return formatted
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实际的Provider配置
|
||||
* 简化版:将逻辑分解为小函数
|
||||
*/
|
||||
export function getActualProvider(model: Model): Provider {
|
||||
const baseProvider = getProviderByModel(model)
|
||||
|
||||
// 按顺序处理各种转换
|
||||
let actualProvider = cloneDeep(baseProvider)
|
||||
actualProvider = handleSpecialProviders(model, actualProvider)
|
||||
actualProvider = formatProviderApiHost(actualProvider)
|
||||
|
||||
return actualProvider
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 Provider 配置转换为新 AI SDK 格式
|
||||
* 简化版:利用新的别名映射系统
|
||||
*/
|
||||
export function providerToAiSdkConfig(actualProvider: Provider): {
|
||||
providerId: ProviderId | 'openai-compatible'
|
||||
options: ProviderSettingsMap[keyof ProviderSettingsMap]
|
||||
} {
|
||||
const aiSdkProviderId = getAiSdkProviderId(actualProvider)
|
||||
const actualProviderType = actualProvider.type
|
||||
const openaiResponseOptions =
|
||||
actualProviderType === 'openai-response'
|
||||
? {
|
||||
mode: 'responses'
|
||||
}
|
||||
: aiSdkProviderId === 'openai'
|
||||
? {
|
||||
mode: 'chat'
|
||||
}
|
||||
: undefined
|
||||
console.log('openaiResponseOptions', openaiResponseOptions)
|
||||
console.log('actualProvider', actualProvider)
|
||||
console.log('aiSdkProviderId', aiSdkProviderId)
|
||||
if (AiCore.isSupported(aiSdkProviderId) && aiSdkProviderId !== 'openai-compatible') {
|
||||
const options = ProviderConfigFactory.fromProvider(
|
||||
aiSdkProviderId,
|
||||
{
|
||||
baseURL: actualProvider.apiHost,
|
||||
apiKey: actualProvider.apiKey
|
||||
},
|
||||
{ ...openaiResponseOptions, headers: actualProvider.extra_headers }
|
||||
)
|
||||
|
||||
// 构建基础配置
|
||||
const baseConfig = {
|
||||
baseURL: actualProvider.apiHost,
|
||||
apiKey: actualProvider.apiKey
|
||||
}
|
||||
|
||||
// 处理OpenAI模式(简化逻辑)
|
||||
const extraOptions: any = {}
|
||||
if (actualProvider.type === 'openai-response') {
|
||||
extraOptions.mode = 'responses'
|
||||
} else if (aiSdkProviderId === 'openai') {
|
||||
extraOptions.mode = 'chat'
|
||||
}
|
||||
|
||||
// 添加额外headers
|
||||
if (actualProvider.extra_headers) {
|
||||
extraOptions.headers = actualProvider.extra_headers
|
||||
}
|
||||
|
||||
// 如果AI SDK支持该provider,使用原生配置
|
||||
if (AiCore.isSupported(aiSdkProviderId) && aiSdkProviderId !== 'openai-compatible') {
|
||||
const options = ProviderConfigFactory.fromProvider(aiSdkProviderId, baseConfig, extraOptions)
|
||||
return {
|
||||
providerId: aiSdkProviderId as ProviderId,
|
||||
options
|
||||
}
|
||||
} else {
|
||||
console.log(`Using openai-compatible fallback for provider: ${actualProvider.type}`)
|
||||
const options = ProviderConfigFactory.createOpenAICompatible(actualProvider.apiHost, actualProvider.apiKey)
|
||||
}
|
||||
|
||||
return {
|
||||
providerId: 'openai-compatible',
|
||||
options: {
|
||||
...options,
|
||||
name: actualProvider.id
|
||||
}
|
||||
// 否则fallback到openai-compatible
|
||||
const options = ProviderConfigFactory.createOpenAICompatible(baseConfig.baseURL, baseConfig.apiKey)
|
||||
return {
|
||||
providerId: 'openai-compatible',
|
||||
options: {
|
||||
...options,
|
||||
name: actualProvider.id,
|
||||
...extraOptions
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否支持使用新的AI SDK
|
||||
* 简化版:利用新的别名映射和动态provider系统
|
||||
*/
|
||||
export function isModernSdkSupported(provider: Provider, model?: Model): boolean {
|
||||
// 目前支持主要的providers
|
||||
const supportedProviders = ['openai', 'anthropic', 'gemini', 'azure-openai', 'vertexai']
|
||||
|
||||
// 检查provider类型
|
||||
if (!supportedProviders.includes(provider.type)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 对于 vertexai,检查配置是否完整
|
||||
export function isModernSdkSupported(provider: Provider): boolean {
|
||||
// 特殊检查:vertexai需要配置完整
|
||||
if (provider.type === 'vertexai' && !isVertexAIConfigured()) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 图像生成模型现在支持新的 AI SDK
|
||||
// (但需要确保 provider 是支持的
|
||||
// 使用getAiSdkProviderId获取映射后的providerId,然后检查AI SDK是否支持
|
||||
const aiSdkProviderId = getAiSdkProviderId(provider)
|
||||
|
||||
if (model && isDedicatedImageGenerationModel(model)) {
|
||||
return true
|
||||
}
|
||||
|
||||
return true
|
||||
// 如果映射到了支持的provider,则支持现代SDK
|
||||
return AiCore.isSupported(aiSdkProviderId)
|
||||
}
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
import { ProviderId } from '@cherrystudio/ai-core/types'
|
||||
import { isOpenAIModel } from '@renderer/config/models'
|
||||
import { Model, Provider } from '@renderer/types'
|
||||
|
||||
export function getAiSdkProviderIdForAihubmix(model: Model): ProviderId | 'openai-compatible' {
|
||||
console.log('getAiSdkProviderIdForAihubmix', model)
|
||||
const id = model.id.toLowerCase()
|
||||
|
||||
if (id.startsWith('claude')) {
|
||||
return 'anthropic'
|
||||
}
|
||||
// TODO:暂时注释,不清楚为什么排除,webSearch时会导致gemini模型走openai的逻辑
|
||||
if ((id.startsWith('gemini') || id.startsWith('imagen')) && !id.endsWith('-nothink') && !id.endsWith('-search')) {
|
||||
return 'google'
|
||||
}
|
||||
|
||||
if (isOpenAIModel(model)) {
|
||||
return 'openai'
|
||||
}
|
||||
|
||||
return 'openai-compatible'
|
||||
}
|
||||
|
||||
export function createAihubmixProvider(model: Model, provider: Provider): Provider {
|
||||
const providerId = getAiSdkProviderIdForAihubmix(model)
|
||||
provider = {
|
||||
...provider,
|
||||
extra_headers: {
|
||||
...provider.extra_headers,
|
||||
'APP-Code': 'MLTG2087'
|
||||
}
|
||||
}
|
||||
if (providerId === 'google') {
|
||||
return {
|
||||
...provider,
|
||||
type: 'gemini',
|
||||
apiHost: 'https://aihubmix.com/gemini'
|
||||
}
|
||||
}
|
||||
|
||||
if (providerId === 'openai') {
|
||||
return {
|
||||
...provider,
|
||||
type: 'openai-response'
|
||||
}
|
||||
}
|
||||
|
||||
if (providerId === 'anthropic') {
|
||||
return {
|
||||
...provider,
|
||||
type: 'anthropic'
|
||||
}
|
||||
}
|
||||
|
||||
return provider
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* AiHubMix规则集
|
||||
*/
|
||||
import { isOpenAIModel } from '@renderer/config/models'
|
||||
import { Provider } from '@renderer/types'
|
||||
|
||||
import { startsWith } from './helper'
|
||||
import { provider2Provider } from './helper'
|
||||
import type { ModelRule } from './types'
|
||||
|
||||
const extraProviderConfig = (provider: Provider) => {
|
||||
return {
|
||||
...provider,
|
||||
extra_headers: {
|
||||
...provider.extra_headers,
|
||||
'APP-Code': 'MLTG2087'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const AIHUBMIX_RULES: ModelRule[] = [
|
||||
{
|
||||
name: 'claude',
|
||||
match: startsWith('claude'),
|
||||
provider: (provider: Provider) => {
|
||||
return extraProviderConfig({
|
||||
...provider,
|
||||
type: 'anthropic'
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'gemini',
|
||||
match: (model) =>
|
||||
(startsWith('gemini')(model) || startsWith('imagen')(model)) &&
|
||||
!model.id.endsWith('-nothink') &&
|
||||
!model.id.endsWith('-search'),
|
||||
provider: (provider: Provider) => {
|
||||
return extraProviderConfig({
|
||||
...provider,
|
||||
apiHost: 'https://aihubmix.com/gemini'
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'openai',
|
||||
match: isOpenAIModel,
|
||||
provider: (provider: Provider) => {
|
||||
return extraProviderConfig({
|
||||
...provider,
|
||||
type: 'openai-response'
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
export const aihubmixProviderCreator = provider2Provider.bind(null, AIHUBMIX_RULES)
|
||||
@@ -0,0 +1,22 @@
|
||||
import type { Model, Provider } from '@renderer/types'
|
||||
|
||||
import type { ModelRule } from './types'
|
||||
|
||||
export const startsWith = (prefix: string) => (model: Model) => model.id.toLowerCase().startsWith(prefix.toLowerCase())
|
||||
export const endpointIs = (type: string) => (model: Model) => model.endpoint_type === type
|
||||
|
||||
/**
|
||||
* 解析模型对应的Provider ID
|
||||
* @param model 模型对象
|
||||
* @param rules 匹配规则数组
|
||||
* @param fallback 默认fallback的providerId
|
||||
* @returns 解析出的providerId
|
||||
*/
|
||||
export function provider2Provider(rules: ModelRule[], model: Model, provider: Provider): Provider {
|
||||
for (const rule of rules) {
|
||||
if (rule.match(model)) {
|
||||
return rule.provider(provider)
|
||||
}
|
||||
}
|
||||
return provider
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// /**
|
||||
// * Provider解析规则模块导出
|
||||
// */
|
||||
|
||||
// // 导出类型
|
||||
// export type { ModelRule } from './types'
|
||||
|
||||
// // 导出匹配函数和解析器
|
||||
// export { endpointIs, resolveProvider, startsWith } from './helper'
|
||||
|
||||
// // 导出规则集
|
||||
// export { AIHUBMIX_RULES } from './aihubmix'
|
||||
// export { NEWAPI_RULES } from './newApi'
|
||||
|
||||
export { aihubmixProviderCreator } from './aihubmix'
|
||||
export { newApiResolverCreator } from './newApi'
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* NewAPI规则集
|
||||
*/
|
||||
import { Provider } from '@renderer/types'
|
||||
|
||||
import { endpointIs, provider2Provider } from './helper'
|
||||
import type { ModelRule } from './types'
|
||||
|
||||
const NEWAPI_RULES: ModelRule[] = [
|
||||
{
|
||||
name: 'anthropic',
|
||||
match: endpointIs('anthropic'),
|
||||
provider: (provider: Provider) => {
|
||||
return {
|
||||
...provider,
|
||||
type: 'anthropic'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'gemini',
|
||||
match: endpointIs('gemini'),
|
||||
provider: (provider: Provider) => {
|
||||
return {
|
||||
...provider,
|
||||
type: 'gemini'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'openai-response',
|
||||
match: endpointIs('openai-response'),
|
||||
provider: (provider: Provider) => {
|
||||
return {
|
||||
...provider,
|
||||
type: 'openai-response'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'openai',
|
||||
match: (model) => endpointIs('openai')(model) || endpointIs('image-generation')(model),
|
||||
provider: (provider: Provider) => {
|
||||
return {
|
||||
...provider,
|
||||
type: 'openai'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
export const newApiResolverCreator = provider2Provider.bind(null, NEWAPI_RULES)
|
||||
@@ -0,0 +1,7 @@
|
||||
import type { Model, Provider } from '@renderer/types'
|
||||
|
||||
export interface ModelRule {
|
||||
name: string
|
||||
match: (model: Model) => boolean
|
||||
provider: (provider: Provider) => Provider
|
||||
}
|
||||
@@ -1,49 +1,75 @@
|
||||
import { AiCore, type ProviderId } from '@cherrystudio/ai-core'
|
||||
import { AiCore, getProviderMapping, type ProviderId } from '@cherrystudio/ai-core'
|
||||
import { loggerService } from '@logger'
|
||||
import { Provider } from '@renderer/types'
|
||||
|
||||
// TODO
|
||||
// 初始化新的Provider注册系统
|
||||
// initializeNewProviders()
|
||||
import { initializeNewProviders } from './providerConfigs'
|
||||
|
||||
// 静态Provider映射 - 核心providers
|
||||
const logger = loggerService.withContext('ProviderFactory')
|
||||
|
||||
/**
|
||||
* 初始化动态Provider系统
|
||||
* 在模块加载时自动注册新的providers
|
||||
*/
|
||||
;(async () => {
|
||||
try {
|
||||
await initializeNewProviders()
|
||||
} catch (error) {
|
||||
logger.warn('Failed to initialize new providers:', error as Error)
|
||||
}
|
||||
})()
|
||||
|
||||
/**
|
||||
* 静态Provider映射表
|
||||
* 处理Cherry Studio特有的provider ID到AI SDK标准ID的映射
|
||||
*/
|
||||
const STATIC_PROVIDER_MAPPING: Record<string, ProviderId> = {
|
||||
// anthropic: 'anthropic',
|
||||
gemini: 'google',
|
||||
'azure-openai': 'azure',
|
||||
'openai-response': 'openai',
|
||||
grok: 'xai'
|
||||
gemini: 'google', // Google Gemini -> google
|
||||
'azure-openai': 'azure', // Azure OpenAI -> azure
|
||||
'openai-response': 'openai', // OpenAI Responses -> openai
|
||||
grok: 'xai' // Grok -> xai
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试解析provider标识符(支持静态映射和动态映射)
|
||||
*/
|
||||
function tryResolveProviderId(identifier: string): ProviderId | null {
|
||||
// 1. 检查静态映射
|
||||
const staticMapping = STATIC_PROVIDER_MAPPING[identifier]
|
||||
if (staticMapping) {
|
||||
return staticMapping
|
||||
}
|
||||
|
||||
// 2. 检查动态映射
|
||||
const dynamicMapping = getProviderMapping(identifier)
|
||||
if (dynamicMapping && dynamicMapping !== identifier) {
|
||||
return dynamicMapping as ProviderId
|
||||
}
|
||||
|
||||
// 3. 检查AiCore是否直接支持
|
||||
if (AiCore.isSupported(identifier)) {
|
||||
return identifier as ProviderId
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取AI SDK Provider ID
|
||||
* 简化版:减少重复逻辑,利用通用解析函数
|
||||
*/
|
||||
export function getAiSdkProviderId(provider: Provider): ProviderId | 'openai-compatible' {
|
||||
// 1. 首先检查静态映射
|
||||
const staticProviderId = STATIC_PROVIDER_MAPPING[provider.id]
|
||||
if (staticProviderId) {
|
||||
return staticProviderId
|
||||
}
|
||||
// TODO
|
||||
// 2. 检查动态注册的provider映射(使用aiCore的函数)
|
||||
// const dynamicProviderId = getProviderMapping(provider.id)
|
||||
// if (dynamicProviderId) {
|
||||
// return dynamicProviderId as ProviderId
|
||||
// }
|
||||
|
||||
// 3. 检查provider.type的静态映射
|
||||
const staticProviderType = STATIC_PROVIDER_MAPPING[provider.type]
|
||||
if (staticProviderType) {
|
||||
return staticProviderType
|
||||
}
|
||||
// TODO
|
||||
// 4. 检查provider.type的动态映射
|
||||
// const dynamicProviderType = getProviderMapping(provider.type)
|
||||
// if (dynamicProviderType) {
|
||||
// return dynamicProviderType as ProviderId
|
||||
// }
|
||||
|
||||
// 5. 检查AiCore是否直接支持
|
||||
if (AiCore.isSupported(provider.id)) {
|
||||
return provider.id as ProviderId
|
||||
// 1. 尝试解析provider.id
|
||||
const resolvedFromId = tryResolveProviderId(provider.id)
|
||||
if (resolvedFromId) {
|
||||
return resolvedFromId
|
||||
}
|
||||
|
||||
// 6. 最后的fallback
|
||||
// 2. 尝试解析provider.type
|
||||
const resolvedFromType = tryResolveProviderId(provider.type)
|
||||
if (resolvedFromType) {
|
||||
return resolvedFromType
|
||||
}
|
||||
|
||||
// 3. 最后的fallback(通常会成为openai-compatible)
|
||||
return provider.id as ProviderId
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type ProviderConfig } from '@cherrystudio/ai-core'
|
||||
import { type ProviderConfig, registerMultipleProviders } from '@cherrystudio/ai-core'
|
||||
import { loggerService } from '@logger'
|
||||
|
||||
const logger = loggerService.withContext('ProviderConfigs')
|
||||
@@ -43,19 +43,29 @@ export const NEW_PROVIDER_CONFIGS: (ProviderConfig & {
|
||||
}
|
||||
] as const
|
||||
|
||||
// TODO
|
||||
// /**
|
||||
// * 初始化新的Providers
|
||||
// * 使用aiCore的动态注册功能
|
||||
// */
|
||||
// export async function initializeNewProviders(): Promise<void> {
|
||||
// try {
|
||||
// const successCount = registerMultipleProviders(NEW_PROVIDER_CONFIGS)
|
||||
/**
|
||||
* 初始化新的Providers
|
||||
* 使用aiCore的动态注册功能
|
||||
*/
|
||||
export async function initializeNewProviders(): Promise<void> {
|
||||
try {
|
||||
logger.info('Starting to register new providers', {
|
||||
providerCount: NEW_PROVIDER_CONFIGS.length,
|
||||
providerIds: NEW_PROVIDER_CONFIGS.map((p) => p.id)
|
||||
})
|
||||
|
||||
// if (successCount < NEW_PROVIDER_CONFIGS.length) {
|
||||
// logger.warn('Some providers failed to register. Check previous error logs.')
|
||||
// }
|
||||
// } catch (error) {
|
||||
// logger.error('Failed to initialize new providers:', error as Error)
|
||||
// }
|
||||
// }
|
||||
const successCount = registerMultipleProviders(NEW_PROVIDER_CONFIGS)
|
||||
|
||||
logger.info('Provider registration completed', {
|
||||
successCount,
|
||||
totalCount: NEW_PROVIDER_CONFIGS.length,
|
||||
failedCount: NEW_PROVIDER_CONFIGS.length - successCount
|
||||
})
|
||||
|
||||
if (successCount < NEW_PROVIDER_CONFIGS.length) {
|
||||
logger.warn('Some providers failed to register. Check previous error logs.')
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Failed to initialize new providers:', error as Error)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ export function buildProviderOptions(
|
||||
}
|
||||
): Record<string, any> {
|
||||
const providerId = getAiSdkProviderId(actualProvider)
|
||||
|
||||
// 构建 provider 特定的选项
|
||||
let providerSpecificOptions: Record<string, any> = {}
|
||||
|
||||
@@ -37,11 +36,8 @@ export function buildProviderOptions(
|
||||
case 'openai':
|
||||
case 'azure':
|
||||
providerSpecificOptions = {
|
||||
...buildOpenAIProviderOptions(assistant, model, capabilities),
|
||||
// 函数内有对于真实provider.id的判断,应该不会影响原生provider
|
||||
...buildGenericProviderOptions(assistant, model, capabilities)
|
||||
...buildOpenAIProviderOptions(assistant, model, capabilities)
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
case 'anthropic':
|
||||
|
||||
Reference in New Issue
Block a user