From 4ba0f2d25c7746fd1215892412a4ebc6b597311e Mon Sep 17 00:00:00 2001 From: fullex <106392080+0xfullex@users.noreply.github.com> Date: Thu, 25 Dec 2025 13:26:32 +0800 Subject: [PATCH 1/5] fix: correct aihubmix anthropic API path (#12115) Remove incorrect /anthropic suffix from aihubmix provider's anthropicApiHost configuration. The correct API endpoint should be https://aihubmix.com/v1/messages, not https://aihubmix.com/anthropic/v1/messages. Fixes issue where Claude API requests to aihubmix provider were failing due to incorrect URL path. --- src/renderer/src/config/providers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/src/config/providers.ts b/src/renderer/src/config/providers.ts index 1adeb58ad0..ed618f909c 100644 --- a/src/renderer/src/config/providers.ts +++ b/src/renderer/src/config/providers.ts @@ -107,7 +107,7 @@ export const SYSTEM_PROVIDERS_CONFIG: Record = type: 'openai', apiKey: '', apiHost: 'https://aihubmix.com', - anthropicApiHost: 'https://aihubmix.com/anthropic', + anthropicApiHost: 'https://aihubmix.com', models: SYSTEM_MODELS.aihubmix, isSystem: true, enabled: false From 0669253abbada00fe81742b166bea8cc43bf0042 Mon Sep 17 00:00:00 2001 From: Caelan <79105826+jin-wang-c@users.noreply.github.com> Date: Thu, 25 Dec 2025 13:46:33 +0800 Subject: [PATCH 2/5] feat:dmx-painting-add-extend_params (#12098) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * dmx-painting-add-extend_params * format-code * 更新类型 --- .../src/pages/paintings/DmxapiPage.tsx | 31 +++++++++++++------ .../pages/paintings/config/DmxapiConfig.ts | 2 +- src/renderer/src/types/index.ts | 1 + 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/renderer/src/pages/paintings/DmxapiPage.tsx b/src/renderer/src/pages/paintings/DmxapiPage.tsx index 560e3857ba..e4f8323655 100644 --- a/src/renderer/src/pages/paintings/DmxapiPage.tsx +++ b/src/renderer/src/pages/paintings/DmxapiPage.tsx @@ -140,11 +140,14 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => { let model = '' let priceModel = '' let image_size = '' + let extend_params = {} + for (const provider of Object.keys(modelGroups)) { if (modelGroups[provider] && modelGroups[provider].length > 0) { model = modelGroups[provider][0].id priceModel = modelGroups[provider][0].price image_size = modelGroups[provider][0].image_sizes[0].value + extend_params = modelGroups[provider][0].extend_params break } } @@ -153,7 +156,8 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => { model, priceModel, image_size, - modelGroups + modelGroups, + extend_params } } @@ -162,7 +166,7 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => { const generationMode = params?.generationMode || painting?.generationMode || MODEOPTIONS[0].value - const { model, priceModel, image_size, modelGroups } = getFirstModelInfo(generationMode) + const { model, priceModel, image_size, modelGroups, extend_params } = getFirstModelInfo(generationMode) return { ...DEFAULT_PAINTING, @@ -173,6 +177,7 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => { modelGroups, priceModel, image_size, + extend_params, ...params } } @@ -190,7 +195,12 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => { const onSelectModel = (modelId: string) => { const model = allModels.find((m) => m.id === modelId) if (model) { - updatePaintingState({ model: modelId, priceModel: model.price, image_size: model.image_sizes[0].value }) + updatePaintingState({ + model: modelId, + priceModel: model.price, + image_size: model.image_sizes[0].value, + extend_params: model.extend_params + }) } } @@ -293,7 +303,7 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => { clearImages() - const { model, priceModel, image_size, modelGroups } = getFirstModelInfo(v) + const { model, priceModel, image_size, modelGroups, extend_params } = getFirstModelInfo(v) setModelOptions(modelGroups) @@ -309,9 +319,10 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => { // 否则更新当前painting updatePaintingState({ generationMode: v, - model: model, - image_size: image_size, - priceModel: priceModel + model, + image_size, + priceModel, + extend_params }) } } @@ -355,7 +366,8 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => { const params = { prompt, model: painting.model, - n: painting.n + n: painting.n, + ...painting?.extend_params } const headerExpand = { @@ -397,7 +409,8 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => { const params = { prompt, n: painting.n, - model: painting.model + model: painting.model, + ...painting?.extend_params } if (painting.image_size) { diff --git a/src/renderer/src/pages/paintings/config/DmxapiConfig.ts b/src/renderer/src/pages/paintings/config/DmxapiConfig.ts index 7880f6305c..52af9490c8 100644 --- a/src/renderer/src/pages/paintings/config/DmxapiConfig.ts +++ b/src/renderer/src/pages/paintings/config/DmxapiConfig.ts @@ -84,7 +84,7 @@ export const MODEOPTIONS = [ // 获取模型分组数据 export const GetModelGroup = async (): Promise => { try { - const response = await fetch('https://dmxapi.cn/cherry_painting_models_v2.json') + const response = await fetch('https://dmxapi.cn/cherry_painting_models_v3.json') if (response.ok) { const data = await response.json() diff --git a/src/renderer/src/types/index.ts b/src/renderer/src/types/index.ts index 126c97686e..a75fc1ed3e 100644 --- a/src/renderer/src/types/index.ts +++ b/src/renderer/src/types/index.ts @@ -395,6 +395,7 @@ export interface DmxapiPainting extends PaintingParams { autoCreate?: boolean generationMode?: generationModeType priceModel?: string + extend_params?: Record } export interface TokenFluxPainting extends PaintingParams { From 05dfb459a6c8faf52868e57bf5c2bc40f928157a Mon Sep 17 00:00:00 2001 From: kangfenmao Date: Thu, 25 Dec 2025 14:41:52 +0800 Subject: [PATCH 3/5] chore: release v1.7.7 --- electron-builder.yml | 74 +++++++++++++++++++++++++++++++------------- package.json | 2 +- 2 files changed, 53 insertions(+), 23 deletions(-) diff --git a/electron-builder.yml b/electron-builder.yml index f362542b9a..11dce735c5 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -134,38 +134,68 @@ artifactBuildCompleted: scripts/artifact-build-completed.js releaseInfo: releaseNotes: | - Cherry Studio 1.7.6 - New Models & MCP Enhancements + Cherry Studio 1.7.7 - New Models & UI Improvements - This release adds support for new AI models and includes a new MCP server for memory management. + This release adds new AI model support, OpenRouter integration, and UI redesigns. ✨ New Features - - [Models] Add support for Xiaomi MiMo model - - [Models] Add support for Gemini 3 Flash and Pro model detection - - [Models] Add support for Volcengine Doubao-Seed-1.8 model - - [MCP] Add Nowledge Mem builtin MCP server for memory management - - [Settings] Add default reasoning effort option to resolve confusion between undefined and none + - [Models] Add GLM-4.7 and MiniMax-M2.1 model support + - [Provider] Add OpenRouter provider support + - [OVMS] Upgrade to 2025.4 with Qwen3-4B-int4-ov preset model + - [OVMS] Close OVMS process when app quits + - [Search] Show keyword-adjacent snippets in history search + - [Painting] Add extend_params support for DMX painting + - [UI] Add MCP logo and replace Hammer icon + + 🎨 UI Improvements + - [Notes] Move notes settings to popup in NotesPage for quick access + - [WebSearch] Redesign settings with two-column layout and "Set as Default" button + - [Display] Improve font selector for long font names + - [Transfer] Rename LanDrop to LanTransfer 🐛 Bug Fixes - - [Azure] Restore deployment-based URLs for non-v1 apiVersion - - [Translation] Disable reasoning mode for translation to improve efficiency - - [Image] Update API path for image generation requests in OpenAIBaseClient - - [Windows] Auto-discover and persist Git Bash path on Windows for scoop users + - [API] Correct aihubmix Anthropic API path + - [OpenRouter] Support GPT-5.1/5.2 reasoning effort 'none' and improve error handling + - [Thinking] Fix interleaved thinking support + - [Memory] Fix retrieval issues and enable database backup + - [Settings] Update default assistant settings to disable temperature + - [OpenAI] Add persistent server configuration support + - [Azure] Normalize Azure endpoint + - [MCP] Check system npx/uvx before falling back to bundled binaries + - [Prompt] Improve language instruction clarity + - [Models] Include GPT5.2 series in verbosity check + - [URL] Enhance urlContext validation for supported providers and models - Cherry Studio 1.7.6 - 新模型与 MCP 增强 + Cherry Studio 1.7.7 - 新模型与界面改进 - 本次更新添加了多个新 AI 模型支持,并新增记忆管理 MCP 服务器。 + 本次更新添加了新 AI 模型支持、OpenRouter 集成以及界面重新设计。 ✨ 新功能 - - [模型] 添加小米 MiMo 模型支持 - - [模型] 添加 Gemini 3 Flash 和 Pro 模型检测支持 - - [模型] 添加火山引擎 Doubao-Seed-1.8 模型支持 - - [MCP] 新增 Nowledge Mem 内置 MCP 服务器,用于记忆管理 - - [设置] 添加默认推理强度选项,解决 undefined 和 none 之间的混淆 + - [模型] 添加 GLM-4.7 和 MiniMax-M2.1 模型支持 + - [服务商] 添加 OpenRouter 服务商支持 + - [OVMS] 升级至 2025.4,新增 Qwen3-4B-int4-ov 预设模型 + - [OVMS] 应用退出时关闭 OVMS 进程 + - [搜索] 历史搜索显示关键词上下文片段 + - [绘图] DMX 绘图添加扩展参数支持 + - [界面] 添加 MCP 图标并替换锤子图标 + + 🎨 界面改进 + - [笔记] 将笔记设置移至笔记页弹窗,快速访问无需离开当前页面 + - [网页搜索] 采用两栏布局重新设计设置界面,添加"设为默认"按钮 + - [显示] 改进长字体名称的字体选择器 + - [传输] LanDrop 重命名为 LanTransfer 🐛 问题修复 - - [Azure] 修复非 v1 apiVersion 的部署 URL 问题 - - [翻译] 禁用翻译时的推理模式以提高效率 - - [图像] 更新 OpenAIBaseClient 中图像生成请求的 API 路径 - - [Windows] 自动发现并保存 Windows scoop 用户的 Git Bash 路径 + - [API] 修复 aihubmix Anthropic API 路径 + - [OpenRouter] 支持 GPT-5.1/5.2 reasoning effort 'none' 并改进错误处理 + - [思考] 修复交错思考支持 + - [记忆] 修复检索问题并启用数据库备份 + - [设置] 更新默认助手设置禁用温度 + - [OpenAI] 添加持久化服务器配置支持 + - [Azure] 规范化 Azure 端点 + - [MCP] 优先检查系统 npx/uvx 再回退到内置二进制文件 + - [提示词] 改进语言指令清晰度 + - [模型] GPT5.2 系列添加到 verbosity 检查 + - [URL] 增强 urlContext 对支持的服务商和模型的验证 diff --git a/package.json b/package.json index 3cf60b9f18..7ad4140af7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "CherryStudio", - "version": "1.7.6", + "version": "1.7.7", "private": true, "description": "A powerful AI assistant for producer.", "main": "./out/main/index.js", From 4ae9bf8ff49fd910402bd38b6e91d3ee27ff122b Mon Sep 17 00:00:00 2001 From: jardel Date: Thu, 25 Dec 2025 16:59:13 +0800 Subject: [PATCH 4/5] fix: allow more file extensions (#12099) Co-authored-by: icarus --- src/main/services/FileStorage.ts | 38 +++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/main/services/FileStorage.ts b/src/main/services/FileStorage.ts index 78bffa6692..f0b7ce32b0 100644 --- a/src/main/services/FileStorage.ts +++ b/src/main/services/FileStorage.ts @@ -2,7 +2,7 @@ import { loggerService } from '@logger' import { checkName, getFilesDir, - getFileType, + getFileType as getFileTypeByExt, getName, getNotesDir, getTempDir, @@ -11,13 +11,13 @@ import { } from '@main/utils/file' import { documentExts, imageExts, KB, MB } from '@shared/config/constant' import type { FileMetadata, NotesTreeNode } from '@types' +import { FileTypes } from '@types' import chardet from 'chardet' import type { FSWatcher } from 'chokidar' import chokidar from 'chokidar' import * as crypto from 'crypto' import type { OpenDialogOptions, OpenDialogReturnValue, SaveDialogOptions, SaveDialogReturnValue } from 'electron' -import { app } from 'electron' -import { dialog, net, shell } from 'electron' +import { app, dialog, net, shell } from 'electron' import * as fs from 'fs' import { writeFileSync } from 'fs' import { readFile } from 'fs/promises' @@ -185,7 +185,7 @@ class FileStorage { }) } - findDuplicateFile = async (filePath: string): Promise => { + private findDuplicateFile = async (filePath: string): Promise => { const stats = fs.statSync(filePath) logger.debug(`stats: ${stats}, filePath: ${filePath}`) const fileSize = stats.size @@ -204,6 +204,8 @@ class FileStorage { if (originalHash === storedHash) { const ext = path.extname(file) const id = path.basename(file, ext) + const type = await this.getFileType(filePath) + return { id, origin_name: file, @@ -212,7 +214,7 @@ class FileStorage { created_at: storedStats.birthtime.toISOString(), size: storedStats.size, ext, - type: getFileType(ext), + type, count: 2 } } @@ -222,6 +224,13 @@ class FileStorage { return null } + public getFileType = async (filePath: string): Promise => { + const ext = path.extname(filePath) + const fileType = getFileTypeByExt(ext) + + return fileType === FileTypes.OTHER && (await this._isTextFile(filePath)) ? FileTypes.TEXT : fileType + } + public selectFile = async ( _: Electron.IpcMainInvokeEvent, options?: OpenDialogOptions @@ -241,7 +250,7 @@ class FileStorage { const fileMetadataPromises = result.filePaths.map(async (filePath) => { const stats = fs.statSync(filePath) const ext = path.extname(filePath) - const fileType = getFileType(ext) + const fileType = await this.getFileType(filePath) return { id: uuidv4(), @@ -307,7 +316,7 @@ class FileStorage { } const stats = await fs.promises.stat(destPath) - const fileType = getFileType(ext) + const fileType = await this.getFileType(destPath) const fileMetadata: FileMetadata = { id: uuid, @@ -332,8 +341,7 @@ class FileStorage { } const stats = fs.statSync(filePath) - const ext = path.extname(filePath) - const fileType = getFileType(ext) + const fileType = await this.getFileType(filePath) return { id: uuidv4(), @@ -342,7 +350,7 @@ class FileStorage { path: filePath, created_at: stats.birthtime.toISOString(), size: stats.size, - ext: ext, + ext: path.extname(filePath), type: fileType, count: 1 } @@ -690,7 +698,7 @@ class FileStorage { created_at: new Date().toISOString(), size: buffer.length, ext: ext.slice(1), - type: getFileType(ext), + type: getFileTypeByExt(ext), count: 1 } } catch (error) { @@ -740,7 +748,7 @@ class FileStorage { created_at: new Date().toISOString(), size: stats.size, ext: ext.slice(1), - type: getFileType(ext), + type: getFileTypeByExt(ext), count: 1 } } catch (error) { @@ -1317,7 +1325,7 @@ class FileStorage { await fs.promises.writeFile(destPath, buffer) const stats = await fs.promises.stat(destPath) - const fileType = getFileType(ext) + const fileType = await this.getFileType(destPath) return { id: uuid, @@ -1604,6 +1612,10 @@ class FileStorage { } public isTextFile = async (_: Electron.IpcMainInvokeEvent, filePath: string): Promise => { + return this._isTextFile(filePath) + } + + private _isTextFile = async (filePath: string): Promise => { try { const isBinary = await isBinaryFile(filePath) if (isBinary) { From 0f0e18231d1e384a6c0962390f5625a3cf4bb11d Mon Sep 17 00:00:00 2001 From: kangfenmao Date: Fri, 26 Dec 2025 11:44:30 +0800 Subject: [PATCH 5/5] fix: update ollama provider type and increment store version to 190 - Changed ollama provider type from 'openai' to 'ollama' in SYSTEM_PROVIDERS_CONFIG. - Incremented persisted reducer version from 189 to 190. - Added migration logic for version 190 to update existing provider types in state. --- src/renderer/src/config/providers.ts | 2 +- src/renderer/src/store/index.ts | 2 +- src/renderer/src/store/migrate.ts | 15 +++++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/renderer/src/config/providers.ts b/src/renderer/src/config/providers.ts index ed618f909c..bae473a7d7 100644 --- a/src/renderer/src/config/providers.ts +++ b/src/renderer/src/config/providers.ts @@ -289,7 +289,7 @@ export const SYSTEM_PROVIDERS_CONFIG: Record = ollama: { id: 'ollama', name: 'Ollama', - type: 'openai', + type: 'ollama', apiKey: '', apiHost: 'http://localhost:11434', models: SYSTEM_MODELS.ollama, diff --git a/src/renderer/src/store/index.ts b/src/renderer/src/store/index.ts index 15f45648dc..8d8c793c21 100644 --- a/src/renderer/src/store/index.ts +++ b/src/renderer/src/store/index.ts @@ -67,7 +67,7 @@ const persistedReducer = persistReducer( { key: 'cherry-studio', storage, - version: 189, + version: 190, blacklist: ['runtime', 'messages', 'messageBlocks', 'tabs', 'toolPermissions'], migrate }, diff --git a/src/renderer/src/store/migrate.ts b/src/renderer/src/store/migrate.ts index 4b9d41b9e4..e0d3524f68 100644 --- a/src/renderer/src/store/migrate.ts +++ b/src/renderer/src/store/migrate.ts @@ -3098,6 +3098,21 @@ const migrateConfig = { logger.error('migrate 189 error', error as Error) return state } + }, + // 1.7.8 + '190': (state: RootState) => { + try { + state.llm.providers.forEach((provider) => { + if (provider.id === SystemProviderIds.ollama) { + provider.type = 'ollama' + } + }) + logger.info('migrate 190 success') + return state + } catch (error) { + logger.error('migrate 190 error', error as Error) + return state + } } }