diff --git a/.yarn/patches/@ai-sdk-huggingface-npm-0.0.4-8080836bc1.patch b/.yarn/patches/@ai-sdk-huggingface-npm-0.0.4-8080836bc1.patch new file mode 100644 index 0000000000..7aeb4ea9cf --- /dev/null +++ b/.yarn/patches/@ai-sdk-huggingface-npm-0.0.4-8080836bc1.patch @@ -0,0 +1,131 @@ +diff --git a/dist/index.mjs b/dist/index.mjs +index b3f018730a93639aad7c203f15fb1aeb766c73f4..ade2a43d66e9184799d072153df61ef7be4ea110 100644 +--- a/dist/index.mjs ++++ b/dist/index.mjs +@@ -296,7 +296,14 @@ var HuggingFaceResponsesLanguageModel = class { + metadata: huggingfaceOptions == null ? void 0 : huggingfaceOptions.metadata, + instructions: huggingfaceOptions == null ? void 0 : huggingfaceOptions.instructions, + ...preparedTools && { tools: preparedTools }, +- ...preparedToolChoice && { tool_choice: preparedToolChoice } ++ ...preparedToolChoice && { tool_choice: preparedToolChoice }, ++ ...(huggingfaceOptions?.reasoningEffort != null && { ++ reasoning: { ++ ...(huggingfaceOptions?.reasoningEffort != null && { ++ effort: huggingfaceOptions.reasoningEffort, ++ }), ++ }, ++ }), + }; + return { args: baseArgs, warnings }; + } +@@ -365,6 +372,20 @@ var HuggingFaceResponsesLanguageModel = class { + } + break; + } ++ case 'reasoning': { ++ for (const contentPart of part.content) { ++ content.push({ ++ type: 'reasoning', ++ text: contentPart.text, ++ providerMetadata: { ++ huggingface: { ++ itemId: part.id, ++ }, ++ }, ++ }); ++ } ++ break; ++ } + case "mcp_call": { + content.push({ + type: "tool-call", +@@ -519,6 +540,11 @@ var HuggingFaceResponsesLanguageModel = class { + id: value.item.call_id, + toolName: value.item.name + }); ++ } else if (value.item.type === 'reasoning') { ++ controller.enqueue({ ++ type: 'reasoning-start', ++ id: value.item.id, ++ }); + } + return; + } +@@ -570,6 +596,22 @@ var HuggingFaceResponsesLanguageModel = class { + }); + return; + } ++ if (isReasoningDeltaChunk(value)) { ++ controller.enqueue({ ++ type: 'reasoning-delta', ++ id: value.item_id, ++ delta: value.delta, ++ }); ++ return; ++ } ++ ++ if (isReasoningEndChunk(value)) { ++ controller.enqueue({ ++ type: 'reasoning-end', ++ id: value.item_id, ++ }); ++ return; ++ } + }, + flush(controller) { + controller.enqueue({ +@@ -593,7 +635,8 @@ var HuggingFaceResponsesLanguageModel = class { + var huggingfaceResponsesProviderOptionsSchema = z2.object({ + metadata: z2.record(z2.string(), z2.string()).optional(), + instructions: z2.string().optional(), +- strictJsonSchema: z2.boolean().optional() ++ strictJsonSchema: z2.boolean().optional(), ++ reasoningEffort: z2.string().optional(), + }); + var huggingfaceResponsesResponseSchema = z2.object({ + id: z2.string(), +@@ -727,12 +770,31 @@ var responseCreatedChunkSchema = z2.object({ + model: z2.string() + }) + }); ++var reasoningTextDeltaChunkSchema = z2.object({ ++ type: z2.literal('response.reasoning_text.delta'), ++ item_id: z2.string(), ++ output_index: z2.number(), ++ content_index: z2.number(), ++ delta: z2.string(), ++ sequence_number: z2.number(), ++}); ++ ++var reasoningTextEndChunkSchema = z2.object({ ++ type: z2.literal('response.reasoning_text.done'), ++ item_id: z2.string(), ++ output_index: z2.number(), ++ content_index: z2.number(), ++ text: z2.string(), ++ sequence_number: z2.number(), ++}); + var huggingfaceResponsesChunkSchema = z2.union([ + responseOutputItemAddedSchema, + responseOutputItemDoneSchema, + textDeltaChunkSchema, + responseCompletedChunkSchema, + responseCreatedChunkSchema, ++ reasoningTextDeltaChunkSchema, ++ reasoningTextEndChunkSchema, + z2.object({ type: z2.string() }).loose() + // fallback for unknown chunks + ]); +@@ -751,6 +813,12 @@ function isResponseCompletedChunk(chunk) { + function isResponseCreatedChunk(chunk) { + return chunk.type === "response.created"; + } ++function isReasoningDeltaChunk(chunk) { ++ return chunk.type === 'response.reasoning_text.delta'; ++} ++function isReasoningEndChunk(chunk) { ++ return chunk.type === 'response.reasoning_text.done'; ++} + + // src/huggingface-provider.ts + function createHuggingFace(options = {}) { diff --git a/package.json b/package.json index d846f69d3a..8da959d182 100644 --- a/package.json +++ b/package.json @@ -103,6 +103,7 @@ "@agentic/tavily": "^7.3.3", "@ai-sdk/amazon-bedrock": "^3.0.35", "@ai-sdk/google-vertex": "^3.0.40", + "@ai-sdk/huggingface": "patch:@ai-sdk/huggingface@npm%3A0.0.4#~/.yarn/patches/@ai-sdk-huggingface-npm-0.0.4-8080836bc1.patch", "@ai-sdk/mistral": "^2.0.19", "@ai-sdk/perplexity": "^2.0.13", "@ant-design/v5-patch-for-react-19": "^1.0.3", diff --git a/packages/aiCore/src/core/providers/schemas.ts b/packages/aiCore/src/core/providers/schemas.ts index f5a8b60a29..0d507d5cc6 100644 --- a/packages/aiCore/src/core/providers/schemas.ts +++ b/packages/aiCore/src/core/providers/schemas.ts @@ -7,6 +7,7 @@ import { createAzure } from '@ai-sdk/azure' import { type AzureOpenAIProviderSettings } from '@ai-sdk/azure' import { createDeepSeek } from '@ai-sdk/deepseek' import { createGoogleGenerativeAI } from '@ai-sdk/google' +import { createHuggingFace } from '@ai-sdk/huggingface' import { createOpenAI, type OpenAIProviderSettings } from '@ai-sdk/openai' import { createOpenAICompatible } from '@ai-sdk/openai-compatible' import { LanguageModelV2 } from '@ai-sdk/provider' @@ -28,7 +29,8 @@ export const baseProviderIds = [ 'azure', 'azure-responses', 'deepseek', - 'openrouter' + 'openrouter', + 'huggingface' ] as const /** @@ -132,6 +134,12 @@ export const baseProviders = [ name: 'OpenRouter', creator: createOpenRouter, supportsImageGeneration: true + }, + { + id: 'huggingface', + name: 'HuggingFace', + creator: createHuggingFace, + supportsImageGeneration: true } ] as const satisfies BaseProvider[] diff --git a/src/renderer/src/aiCore/plugins/telemetryPlugin.ts b/src/renderer/src/aiCore/plugins/telemetryPlugin.ts index 75bf6e116c..0f06091c5a 100644 --- a/src/renderer/src/aiCore/plugins/telemetryPlugin.ts +++ b/src/renderer/src/aiCore/plugins/telemetryPlugin.ts @@ -49,7 +49,7 @@ class AdapterTracer { this.cachedParentContext = undefined } - logger.info('AdapterTracer created with parent context info', { + logger.debug('AdapterTracer created with parent context info', { topicId, modelName, parentTraceId: this.parentSpanContext?.traceId, @@ -62,7 +62,7 @@ class AdapterTracer { startActiveSpan any>(name: string, options: any, fn: F): ReturnType startActiveSpan any>(name: string, options: any, context: any, fn: F): ReturnType startActiveSpan any>(name: string, arg2?: any, arg3?: any, arg4?: any): ReturnType { - logger.info('AdapterTracer.startActiveSpan called', { + logger.debug('AdapterTracer.startActiveSpan called', { spanName: name, topicId: this.topicId, modelName: this.modelName, @@ -88,7 +88,7 @@ class AdapterTracer { // 包装span的end方法 const originalEnd = span.end.bind(span) span.end = (endTime?: any) => { - logger.info('AI SDK span.end() called in startActiveSpan - about to convert span', { + logger.debug('AI SDK span.end() called in startActiveSpan - about to convert span', { spanName: name, spanId: span.spanContext().spanId, traceId: span.spanContext().traceId, @@ -101,14 +101,14 @@ class AdapterTracer { // 转换并保存 span 数据 try { - logger.info('Converting AI SDK span to SpanEntity (from startActiveSpan)', { + logger.debug('Converting AI SDK span to SpanEntity (from startActiveSpan)', { spanName: name, spanId: span.spanContext().spanId, traceId: span.spanContext().traceId, topicId: this.topicId, modelName: this.modelName }) - logger.info('span', span) + logger.silly('span', span) const spanEntity = AiSdkSpanAdapter.convertToSpanEntity({ span, topicId: this.topicId, @@ -118,7 +118,7 @@ class AdapterTracer { // 保存转换后的数据 window.api.trace.saveEntity(spanEntity) - logger.info('AI SDK span converted and saved successfully (from startActiveSpan)', { + logger.debug('AI SDK span converted and saved successfully (from startActiveSpan)', { spanName: name, spanId: span.spanContext().spanId, traceId: span.spanContext().traceId, @@ -151,7 +151,7 @@ class AdapterTracer { if (this.parentSpanContext) { try { const ctx = trace.setSpanContext(otelContext.active(), this.parentSpanContext) - logger.info('Created active context with parent SpanContext for startActiveSpan', { + logger.debug('Created active context with parent SpanContext for startActiveSpan', { spanName: name, parentTraceId: this.parentSpanContext.traceId, parentSpanId: this.parentSpanContext.spanId, @@ -218,7 +218,7 @@ export function createTelemetryPlugin(config: TelemetryPluginConfig) { if (effectiveTopicId) { try { // 从 SpanManagerService 获取当前的 span - logger.info('Attempting to find parent span', { + logger.debug('Attempting to find parent span', { topicId: effectiveTopicId, requestId: context.requestId, modelName: modelName, @@ -230,7 +230,7 @@ export function createTelemetryPlugin(config: TelemetryPluginConfig) { if (parentSpan) { // 直接使用父 span 的 SpanContext,避免手动拼装字段遗漏 parentSpanContext = parentSpan.spanContext() - logger.info('Found active parent span for AI SDK', { + logger.debug('Found active parent span for AI SDK', { parentSpanId: parentSpanContext.spanId, parentTraceId: parentSpanContext.traceId, topicId: effectiveTopicId, @@ -302,7 +302,7 @@ export function createTelemetryPlugin(config: TelemetryPluginConfig) { logger.debug('Updated active context with parent span') }) - logger.info('Set parent context for AI SDK spans', { + logger.debug('Set parent context for AI SDK spans', { parentSpanId: parentSpanContext?.spanId, parentTraceId: parentSpanContext?.traceId, hasActiveContext: !!activeContext, @@ -313,7 +313,7 @@ export function createTelemetryPlugin(config: TelemetryPluginConfig) { } } - logger.info('Injecting AI SDK telemetry config with adapter', { + logger.debug('Injecting AI SDK telemetry config with adapter', { requestId: context.requestId, topicId: effectiveTopicId, modelId: context.modelId, diff --git a/src/renderer/src/aiCore/provider/providerInitialization.ts b/src/renderer/src/aiCore/provider/providerInitialization.ts index 9942ffa405..665f2bd05c 100644 --- a/src/renderer/src/aiCore/provider/providerInitialization.ts +++ b/src/renderer/src/aiCore/provider/providerInitialization.ts @@ -63,6 +63,14 @@ export const NEW_PROVIDER_CONFIGS: ProviderConfig[] = [ creatorFunctionName: 'createMistral', supportsImageGeneration: false, aliases: ['mistral'] + }, + { + id: 'huggingface', + name: 'HuggingFace', + import: () => import('@ai-sdk/huggingface'), + creatorFunctionName: 'createHuggingFace', + supportsImageGeneration: true, + aliases: ['hf', 'hugging-face'] } ] as const diff --git a/src/renderer/src/aiCore/utils/options.ts b/src/renderer/src/aiCore/utils/options.ts index d151b57029..087a9ef157 100644 --- a/src/renderer/src/aiCore/utils/options.ts +++ b/src/renderer/src/aiCore/utils/options.ts @@ -90,7 +90,9 @@ export function buildProviderOptions( serviceTier: serviceTierSetting } break - + case 'huggingface': + providerSpecificOptions = buildOpenAIProviderOptions(assistant, model, capabilities) + break case 'anthropic': providerSpecificOptions = buildAnthropicProviderOptions(assistant, model, capabilities) break diff --git a/src/renderer/src/aiCore/utils/reasoning.ts b/src/renderer/src/aiCore/utils/reasoning.ts index 6e57074980..86a762897f 100644 --- a/src/renderer/src/aiCore/utils/reasoning.ts +++ b/src/renderer/src/aiCore/utils/reasoning.ts @@ -10,6 +10,7 @@ import { isGrok4FastReasoningModel, isGrokReasoningModel, isOpenAIDeepResearchModel, + isOpenAIModel, isOpenAIReasoningModel, isQwenAlwaysThinkModel, isQwenReasoningModel, @@ -319,6 +320,20 @@ export function getOpenAIReasoningParams(assistant: Assistant, model: Model): Re if (!isReasoningModel(model)) { return {} } + + let reasoningEffort = assistant?.settings?.reasoning_effort + + if (!reasoningEffort) { + return {} + } + + // 非OpenAI模型,但是Provider类型是responses/azure openai的情况 + if (!isOpenAIModel(model)) { + return { + reasoningEffort + } + } + const openAI = getStoreSetting('openAI') as SettingsState['openAI'] const summaryText = openAI?.summaryText || 'off' @@ -330,16 +345,10 @@ export function getOpenAIReasoningParams(assistant: Assistant, model: Model): Re reasoningSummary = summaryText } - let reasoningEffort = assistant?.settings?.reasoning_effort - if (isOpenAIDeepResearchModel(model)) { reasoningEffort = 'medium' } - if (!reasoningEffort) { - return {} - } - // OpenAI 推理参数 if (isSupportedReasoningEffortOpenAIModel(model)) { return { diff --git a/src/renderer/src/assets/images/providers/huggingface.webp b/src/renderer/src/assets/images/providers/huggingface.webp new file mode 100644 index 0000000000..72413f893e Binary files /dev/null and b/src/renderer/src/assets/images/providers/huggingface.webp differ diff --git a/src/renderer/src/config/models/default.ts b/src/renderer/src/config/models/default.ts index c3a40e6ef7..f3e63e631d 100644 --- a/src/renderer/src/config/models/default.ts +++ b/src/renderer/src/config/models/default.ts @@ -1837,5 +1837,6 @@ export const SYSTEM_MODELS: Record = provider: 'longcat', group: 'LongCat' } - ] + ], + huggingface: [] } diff --git a/src/renderer/src/config/providers.ts b/src/renderer/src/config/providers.ts index 7f8d95dcd1..0008013af4 100644 --- a/src/renderer/src/config/providers.ts +++ b/src/renderer/src/config/providers.ts @@ -22,6 +22,7 @@ import GoogleProviderLogo from '@renderer/assets/images/providers/google.png' import GPUStackProviderLogo from '@renderer/assets/images/providers/gpustack.svg' import GrokProviderLogo from '@renderer/assets/images/providers/grok.png' import GroqProviderLogo from '@renderer/assets/images/providers/groq.png' +import HuggingfaceProviderLogo from '@renderer/assets/images/providers/huggingface.webp' import HyperbolicProviderLogo from '@renderer/assets/images/providers/hyperbolic.png' import InfiniProviderLogo from '@renderer/assets/images/providers/infini.png' import IntelOvmsLogo from '@renderer/assets/images/providers/intel.png' @@ -653,6 +654,16 @@ export const SYSTEM_PROVIDERS_CONFIG: Record = models: SYSTEM_MODELS.longcat, isSystem: true, enabled: false + }, + huggingface: { + id: 'huggingface', + name: 'Hugging Face', + type: 'openai-response', + apiKey: '', + apiHost: 'https://router.huggingface.co/v1/', + models: [], + isSystem: true, + enabled: false } } as const @@ -717,7 +728,8 @@ export const PROVIDER_LOGO_MAP: AtLeast = { 'aws-bedrock': AwsProviderLogo, poe: 'poe', // use svg icon component aionly: AiOnlyProviderLogo, - longcat: LongCatProviderLogo + longcat: LongCatProviderLogo, + huggingface: HuggingfaceProviderLogo } as const export function getProviderLogo(providerId: string) { @@ -1344,6 +1356,17 @@ export const PROVIDER_URLS: Record = { docs: 'https://longcat.chat/platform/docs/zh/', models: 'https://longcat.chat/platform/docs/zh/APIDocs.html' } + }, + huggingface: { + api: { + url: 'https://router.huggingface.co/v1/' + }, + websites: { + official: 'https://huggingface.co/', + apiKey: 'https://huggingface.co/settings/tokens', + docs: 'https://huggingface.co/docs', + models: 'https://huggingface.co/models' + } } } diff --git a/src/renderer/src/i18n/label.ts b/src/renderer/src/i18n/label.ts index 51edc964b6..e679200804 100644 --- a/src/renderer/src/i18n/label.ts +++ b/src/renderer/src/i18n/label.ts @@ -88,7 +88,9 @@ const providerKeyMap = { zhinao: 'provider.zhinao', zhipu: 'provider.zhipu', poe: 'provider.poe', - aionly: 'provider.aionly' + aionly: 'provider.aionly', + longcat: 'provider.longcat', + huggingface: 'provider.huggingface' } as const /** diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index ab3bedef6a..a5a93e4356 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -2345,12 +2345,14 @@ "gpustack": "GPUStack", "grok": "Grok", "groq": "Groq", + "huggingface": "Hugging Face", "hunyuan": "Tencent Hunyuan", "hyperbolic": "Hyperbolic", "infini": "Infini", "jina": "Jina", "lanyun": "LANYUN", "lmstudio": "LM Studio", + "longcat": "LongCat AI", "minimax": "MiniMax", "mistral": "Mistral", "modelscope": "ModelScope", diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index ed728ef2c3..44f051be07 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -2345,12 +2345,14 @@ "gpustack": "GPUStack", "grok": "Grok", "groq": "Groq", + "huggingface": "Hugging Face", "hunyuan": "腾讯混元", "hyperbolic": "Hyperbolic", "infini": "无问芯穹", "jina": "Jina", "lanyun": "蓝耘科技", "lmstudio": "LM Studio", + "longcat": "龙猫", "minimax": "MiniMax", "mistral": "Mistral", "modelscope": "ModelScope 魔搭", diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json index 89b51d5c1b..d933db01d5 100644 --- a/src/renderer/src/i18n/locales/zh-tw.json +++ b/src/renderer/src/i18n/locales/zh-tw.json @@ -2345,12 +2345,14 @@ "gpustack": "GPUStack", "grok": "Grok", "groq": "Groq", + "huggingface": "Hugging Face", "hunyuan": "騰訊混元", "hyperbolic": "Hyperbolic", "infini": "無問芯穹", "jina": "Jina", "lanyun": "藍耘", "lmstudio": "LM Studio", + "longcat": "龍貓", "minimax": "MiniMax", "mistral": "Mistral", "modelscope": "ModelScope 魔搭", diff --git a/src/renderer/src/i18n/translate/de-de.json b/src/renderer/src/i18n/translate/de-de.json index 3d9de52588..3a44387d5d 100644 --- a/src/renderer/src/i18n/translate/de-de.json +++ b/src/renderer/src/i18n/translate/de-de.json @@ -2345,12 +2345,14 @@ "gpustack": "GPUStack", "grok": "Grok", "groq": "Groq", + "huggingface": "Hugging Face", "hunyuan": "Tencent Hunyuan", "hyperbolic": "Hyperbolic", "infini": "Infini-AI", "jina": "Jina", "lanyun": "Lanyun Technologie", "lmstudio": "LM Studio", + "longcat": "Meißner Riesenhamster", "minimax": "MiniMax", "mistral": "Mistral", "modelscope": "ModelScope", diff --git a/src/renderer/src/i18n/translate/el-gr.json b/src/renderer/src/i18n/translate/el-gr.json index c740b1b106..59b25aea2d 100644 --- a/src/renderer/src/i18n/translate/el-gr.json +++ b/src/renderer/src/i18n/translate/el-gr.json @@ -2345,12 +2345,14 @@ "gpustack": "GPUStack", "grok": "Grok", "groq": "Groq", + "huggingface": "Hugging Face", "hunyuan": "Tencent Hunyuan", "hyperbolic": "Υπερβολικός", "infini": "Χωρίς Ερώτημα Xin Qiong", "jina": "Jina", "lanyun": "Λανιούν Τεχνολογία", "lmstudio": "LM Studio", + "longcat": "Τσίρο", "minimax": "MiniMax", "mistral": "Mistral", "modelscope": "ModelScope Magpie", diff --git a/src/renderer/src/i18n/translate/es-es.json b/src/renderer/src/i18n/translate/es-es.json index 654510415e..70defe51da 100644 --- a/src/renderer/src/i18n/translate/es-es.json +++ b/src/renderer/src/i18n/translate/es-es.json @@ -2345,12 +2345,14 @@ "gpustack": "GPUStack", "grok": "Grok", "groq": "Groq", + "huggingface": "Hugging Face", "hunyuan": "Tencent Hùnyuán", "hyperbolic": "Hiperbólico", "infini": "Infini", "jina": "Jina", "lanyun": "Tecnología Lanyun", "lmstudio": "Estudio LM", + "longcat": "Totoro", "minimax": "Minimax", "mistral": "Mistral", "modelscope": "ModelScope Módulo", diff --git a/src/renderer/src/i18n/translate/fr-fr.json b/src/renderer/src/i18n/translate/fr-fr.json index 65b7bd6d12..305378447e 100644 --- a/src/renderer/src/i18n/translate/fr-fr.json +++ b/src/renderer/src/i18n/translate/fr-fr.json @@ -2345,12 +2345,14 @@ "gpustack": "GPUStack", "grok": "Grok", "groq": "Groq", + "huggingface": "Hugging Face", "hunyuan": "Tencent HunYuan", "hyperbolic": "Hyperbolique", "infini": "Sans Frontières Céleste", "jina": "Jina", "lanyun": "Technologie Lan Yun", "lmstudio": "Studio LM", + "longcat": "Mon voisin Totoro", "minimax": "MiniMax", "mistral": "Mistral", "modelscope": "ModelScope MoDa", diff --git a/src/renderer/src/i18n/translate/ja-jp.json b/src/renderer/src/i18n/translate/ja-jp.json index 1ee2139df7..6e66ace09f 100644 --- a/src/renderer/src/i18n/translate/ja-jp.json +++ b/src/renderer/src/i18n/translate/ja-jp.json @@ -2345,12 +2345,14 @@ "gpustack": "GPUStack", "grok": "Grok", "groq": "Groq", + "huggingface": "ハギングフェイス", "hunyuan": "腾讯混元", "hyperbolic": "Hyperbolic", "infini": "Infini", "jina": "Jina", "lanyun": "LANYUN", "lmstudio": "LM Studio", + "longcat": "トトロ", "minimax": "MiniMax", "mistral": "Mistral", "modelscope": "ModelScope", diff --git a/src/renderer/src/i18n/translate/pt-pt.json b/src/renderer/src/i18n/translate/pt-pt.json index e5231a07e9..4a6dc5b2b6 100644 --- a/src/renderer/src/i18n/translate/pt-pt.json +++ b/src/renderer/src/i18n/translate/pt-pt.json @@ -2345,12 +2345,14 @@ "gpustack": "GPUStack", "grok": "Compreender", "groq": "Groq", + "huggingface": "Hugging Face", "hunyuan": "Tencent Hún Yuán", "hyperbolic": "Hiperbólico", "infini": "Infinito", "jina": "Jina", "lanyun": "Lanyun Tecnologia", "lmstudio": "Estúdio LM", + "longcat": "Totoro", "minimax": "Minimax", "mistral": "Mistral", "modelscope": "ModelScope MôDá", diff --git a/src/renderer/src/i18n/translate/ru-ru.json b/src/renderer/src/i18n/translate/ru-ru.json index 59df9b25f7..477fcb0a28 100644 --- a/src/renderer/src/i18n/translate/ru-ru.json +++ b/src/renderer/src/i18n/translate/ru-ru.json @@ -2345,12 +2345,14 @@ "gpustack": "GPUStack", "grok": "Grok", "groq": "Groq", + "huggingface": "Hugging Face", "hunyuan": "Tencent Hunyuan", "hyperbolic": "Hyperbolic", "infini": "Infini", "jina": "Jina", "lanyun": "LANYUN", "lmstudio": "LM Studio", + "longcat": "Тоторо", "minimax": "MiniMax", "mistral": "Mistral", "modelscope": "ModelScope", diff --git a/src/renderer/src/store/index.ts b/src/renderer/src/store/index.ts index c9ec0d5e81..85afd68cb9 100644 --- a/src/renderer/src/store/index.ts +++ b/src/renderer/src/store/index.ts @@ -65,7 +65,7 @@ const persistedReducer = persistReducer( { key: 'cherry-studio', storage, - version: 166, + version: 167, blacklist: ['runtime', 'messages', 'messageBlocks', 'tabs'], migrate }, diff --git a/src/renderer/src/store/migrate.ts b/src/renderer/src/store/migrate.ts index b0b4e36a81..7b7a834838 100644 --- a/src/renderer/src/store/migrate.ts +++ b/src/renderer/src/store/migrate.ts @@ -2720,6 +2720,15 @@ const migrateConfig = { logger.error('migrate 166 error', error as Error) return state } + }, + '167': (state: RootState) => { + try { + addProvider(state, 'huggingface') + return state + } catch (error) { + logger.error('migrate 167 error', error as Error) + return state + } } } diff --git a/src/renderer/src/types/provider.ts b/src/renderer/src/types/provider.ts index 782d8e98fd..95461d14e9 100644 --- a/src/renderer/src/types/provider.ts +++ b/src/renderer/src/types/provider.ts @@ -162,7 +162,8 @@ export const SystemProviderIds = { 'aws-bedrock': 'aws-bedrock', poe: 'poe', aionly: 'aionly', - longcat: 'longcat' + longcat: 'longcat', + huggingface: 'huggingface' } as const export type SystemProviderId = keyof typeof SystemProviderIds diff --git a/yarn.lock b/yarn.lock index 79909f1781..432a846a47 100644 --- a/yarn.lock +++ b/yarn.lock @@ -180,6 +180,32 @@ __metadata: languageName: node linkType: hard +"@ai-sdk/huggingface@npm:0.0.4": + version: 0.0.4 + resolution: "@ai-sdk/huggingface@npm:0.0.4" + dependencies: + "@ai-sdk/openai-compatible": "npm:1.0.22" + "@ai-sdk/provider": "npm:2.0.0" + "@ai-sdk/provider-utils": "npm:3.0.12" + peerDependencies: + zod: ^3.25.76 || ^4 + checksum: 10c0/756b8f820b89bf9550c9281dfe2a1a813477dec82be5557e236e8b5eaaf0204b65a65925ad486b7576c687f33c709f6d99fd4fc87a46b1add210435b08834986 + languageName: node + linkType: hard + +"@ai-sdk/huggingface@patch:@ai-sdk/huggingface@npm%3A0.0.4#~/.yarn/patches/@ai-sdk-huggingface-npm-0.0.4-8080836bc1.patch": + version: 0.0.4 + resolution: "@ai-sdk/huggingface@patch:@ai-sdk/huggingface@npm%3A0.0.4#~/.yarn/patches/@ai-sdk-huggingface-npm-0.0.4-8080836bc1.patch::version=0.0.4&hash=ceb48e" + dependencies: + "@ai-sdk/openai-compatible": "npm:1.0.22" + "@ai-sdk/provider": "npm:2.0.0" + "@ai-sdk/provider-utils": "npm:3.0.12" + peerDependencies: + zod: ^3.25.76 || ^4 + checksum: 10c0/4726a10de7a6fd554b58d62f79cd6514c2cc5166052e035ba1517e224a310ddb355a5d2922ee8507fb8d928d6d5b2b102d3d221af5a44b181e436e6b64382087 + languageName: node + linkType: hard + "@ai-sdk/mistral@npm:^2.0.19": version: 2.0.19 resolution: "@ai-sdk/mistral@npm:2.0.19" @@ -13853,6 +13879,7 @@ __metadata: "@agentic/tavily": "npm:^7.3.3" "@ai-sdk/amazon-bedrock": "npm:^3.0.35" "@ai-sdk/google-vertex": "npm:^3.0.40" + "@ai-sdk/huggingface": "patch:@ai-sdk/huggingface@npm%3A0.0.4#~/.yarn/patches/@ai-sdk-huggingface-npm-0.0.4-8080836bc1.patch" "@ai-sdk/mistral": "npm:^2.0.19" "@ai-sdk/perplexity": "npm:^2.0.13" "@ant-design/v5-patch-for-react-19": "npm:^1.0.3"