Merge branch 'main' into v2

This commit is contained in:
fullex 2025-12-28 18:08:30 +08:00
commit 6e25d12def
79 changed files with 3308 additions and 1740 deletions

View File

@ -7,7 +7,7 @@ index 8dd9b498050dbecd8dd6b901acf1aa8ca38a49af..ed644349c9d38fe2a66b2fb44214f7c1
type OllamaChatModelId = "athene-v2" | "athene-v2:72b" | "aya-expanse" | "aya-expanse:8b" | "aya-expanse:32b" | "codegemma" | "codegemma:2b" | "codegemma:7b" | "codellama" | "codellama:7b" | "codellama:13b" | "codellama:34b" | "codellama:70b" | "codellama:code" | "codellama:python" | "command-r" | "command-r:35b" | "command-r-plus" | "command-r-plus:104b" | "command-r7b" | "command-r7b:7b" | "deepseek-r1" | "deepseek-r1:1.5b" | "deepseek-r1:7b" | "deepseek-r1:8b" | "deepseek-r1:14b" | "deepseek-r1:32b" | "deepseek-r1:70b" | "deepseek-r1:671b" | "deepseek-coder-v2" | "deepseek-coder-v2:16b" | "deepseek-coder-v2:236b" | "deepseek-v3" | "deepseek-v3:671b" | "devstral" | "devstral:24b" | "dolphin3" | "dolphin3:8b" | "exaone3.5" | "exaone3.5:2.4b" | "exaone3.5:7.8b" | "exaone3.5:32b" | "falcon2" | "falcon2:11b" | "falcon3" | "falcon3:1b" | "falcon3:3b" | "falcon3:7b" | "falcon3:10b" | "firefunction-v2" | "firefunction-v2:70b" | "gemma" | "gemma:2b" | "gemma:7b" | "gemma2" | "gemma2:2b" | "gemma2:9b" | "gemma2:27b" | "gemma3" | "gemma3:1b" | "gemma3:4b" | "gemma3:12b" | "gemma3:27b" | "granite3-dense" | "granite3-dense:2b" | "granite3-dense:8b" | "granite3-guardian" | "granite3-guardian:2b" | "granite3-guardian:8b" | "granite3-moe" | "granite3-moe:1b" | "granite3-moe:3b" | "granite3.1-dense" | "granite3.1-dense:2b" | "granite3.1-dense:8b" | "granite3.1-moe" | "granite3.1-moe:1b" | "granite3.1-moe:3b" | "llama2" | "llama2:7b" | "llama2:13b" | "llama2:70b" | "llama3" | "llama3:8b" | "llama3:70b" | "llama3-chatqa" | "llama3-chatqa:8b" | "llama3-chatqa:70b" | "llama3-gradient" | "llama3-gradient:8b" | "llama3-gradient:70b" | "llama3.1" | "llama3.1:8b" | "llama3.1:70b" | "llama3.1:405b" | "llama3.2" | "llama3.2:1b" | "llama3.2:3b" | "llama3.2-vision" | "llama3.2-vision:11b" | "llama3.2-vision:90b" | "llama3.3" | "llama3.3:70b" | "llama4" | "llama4:16x17b" | "llama4:128x17b" | "llama-guard3" | "llama-guard3:1b" | "llama-guard3:8b" | "llava" | "llava:7b" | "llava:13b" | "llava:34b" | "llava-llama3" | "llava-llama3:8b" | "llava-phi3" | "llava-phi3:3.8b" | "marco-o1" | "marco-o1:7b" | "mistral" | "mistral:7b" | "mistral-large" | "mistral-large:123b" | "mistral-nemo" | "mistral-nemo:12b" | "mistral-small" | "mistral-small:22b" | "mixtral" | "mixtral:8x7b" | "mixtral:8x22b" | "moondream" | "moondream:1.8b" | "openhermes" | "openhermes:v2.5" | "nemotron" | "nemotron:70b" | "nemotron-mini" | "nemotron-mini:4b" | "olmo" | "olmo:7b" | "olmo:13b" | "opencoder" | "opencoder:1.5b" | "opencoder:8b" | "phi3" | "phi3:3.8b" | "phi3:14b" | "phi3.5" | "phi3.5:3.8b" | "phi4" | "phi4:14b" | "qwen" | "qwen:7b" | "qwen:14b" | "qwen:32b" | "qwen:72b" | "qwen:110b" | "qwen2" | "qwen2:0.5b" | "qwen2:1.5b" | "qwen2:7b" | "qwen2:72b" | "qwen2.5" | "qwen2.5:0.5b" | "qwen2.5:1.5b" | "qwen2.5:3b" | "qwen2.5:7b" | "qwen2.5:14b" | "qwen2.5:32b" | "qwen2.5:72b" | "qwen2.5-coder" | "qwen2.5-coder:0.5b" | "qwen2.5-coder:1.5b" | "qwen2.5-coder:3b" | "qwen2.5-coder:7b" | "qwen2.5-coder:14b" | "qwen2.5-coder:32b" | "qwen3" | "qwen3:0.6b" | "qwen3:1.7b" | "qwen3:4b" | "qwen3:8b" | "qwen3:14b" | "qwen3:30b" | "qwen3:32b" | "qwen3:235b" | "qwq" | "qwq:32b" | "sailor2" | "sailor2:1b" | "sailor2:8b" | "sailor2:20b" | "shieldgemma" | "shieldgemma:2b" | "shieldgemma:9b" | "shieldgemma:27b" | "smallthinker" | "smallthinker:3b" | "smollm" | "smollm:135m" | "smollm:360m" | "smollm:1.7b" | "tinyllama" | "tinyllama:1.1b" | "tulu3" | "tulu3:8b" | "tulu3:70b" | (string & {});
declare const ollamaProviderOptions: z.ZodObject<{
- think: z.ZodOptional<z.ZodBoolean>;
+ think: z.ZodOptional<z.ZodUnion<[z.ZodBoolean, z.ZodEnum<['low', 'medium', 'high']>]>>;
+ think: z.ZodOptional<z.ZodUnion<[z.ZodBoolean, z.ZodLiteral<"low">, z.ZodLiteral<"medium">, z.ZodLiteral<"high">]>>;
options: z.ZodOptional<z.ZodObject<{
num_ctx: z.ZodOptional<z.ZodNumber>;
repeat_last_n: z.ZodOptional<z.ZodNumber>;
@ -29,7 +29,7 @@ index 8dd9b498050dbecd8dd6b901acf1aa8ca38a49af..ed644349c9d38fe2a66b2fb44214f7c1
declare const ollamaCompletionProviderOptions: z.ZodObject<{
- think: z.ZodOptional<z.ZodBoolean>;
+ think: z.ZodOptional<z.ZodUnion<[z.ZodBoolean, z.ZodEnum<['low', 'medium', 'high']>]>>;
+ think: z.ZodOptional<z.ZodUnion<[z.ZodBoolean, z.ZodLiteral<"low">, z.ZodLiteral<"medium">, z.ZodLiteral<"high">]>>;
user: z.ZodOptional<z.ZodString>;
suffix: z.ZodOptional<z.ZodString>;
echo: z.ZodOptional<z.ZodBoolean>;
@ -42,7 +42,7 @@ index 35b5142ce8476ce2549ed7c2ec48e7d8c46c90d9..2ef64dc9a4c2be043e6af608241a6a83
// src/completion/ollama-completion-language-model.ts
var ollamaCompletionProviderOptions = import_v42.z.object({
- think: import_v42.z.boolean().optional(),
+ think: import_v42.z.union([import_v42.z.boolean(), import_v42.z.enum(['low', 'medium', 'high'])]).optional(),
+ think: import_v42.z.union([import_v42.z.boolean(), import_v42.z.literal('low'), import_v42.z.literal('medium'), import_v42.z.literal('high')]).optional(),
user: import_v42.z.string().optional(),
suffix: import_v42.z.string().optional(),
echo: import_v42.z.boolean().optional()
@ -64,7 +64,7 @@ index 35b5142ce8476ce2549ed7c2ec48e7d8c46c90d9..2ef64dc9a4c2be043e6af608241a6a83
* Only supported by certain models like DeepSeek R1 and Qwen 3.
*/
- think: import_v44.z.boolean().optional(),
+ think: import_v44.z.union([import_v44.z.boolean(), import_v44.z.enum(['low', 'medium', 'high'])]).optional(),
+ think: import_v44.z.union([import_v44.z.boolean(), import_v44.z.literal('low'), import_v44.z.literal('medium'), import_v44.z.literal('high')]).optional(),
options: import_v44.z.object({
num_ctx: import_v44.z.number().optional(),
repeat_last_n: import_v44.z.number().optional(),
@ -97,7 +97,7 @@ index e2a634a78d80ac9542f2cc4f96cf2291094b10cf..67b23efce3c1cf4f026693d3ff924698
// src/completion/ollama-completion-language-model.ts
var ollamaCompletionProviderOptions = z2.object({
- think: z2.boolean().optional(),
+ think: z2.union([z2.boolean(), z2.enum(['low', 'medium', 'high'])]).optional(),
+ think: z2.union([z2.boolean(), z2.literal('low'), z2.literal('medium'), z2.literal('high')]).optional(),
user: z2.string().optional(),
suffix: z2.string().optional(),
echo: z2.boolean().optional()
@ -119,7 +119,7 @@ index e2a634a78d80ac9542f2cc4f96cf2291094b10cf..67b23efce3c1cf4f026693d3ff924698
* Only supported by certain models like DeepSeek R1 and Qwen 3.
*/
- think: z4.boolean().optional(),
+ think: z4.union([z4.boolean(), z4.enum(['low', 'medium', 'high'])]).optional(),
+ think: z4.union([z4.boolean(), z4.literal('low'), z4.literal('medium'), z4.literal('high')]).optional(),
options: z4.object({
num_ctx: z4.number().optional(),
repeat_last_n: z4.number().optional(),

View File

@ -36,7 +36,7 @@ yarn install
### ENV
```bash
copy .env.example .env
cp .env.example .env
```
### Start

View File

@ -36,7 +36,7 @@ yarn install
### ENV
```bash
copy .env.example .env
cp .env.example .env
```
### Start

View File

@ -135,68 +135,38 @@ artifactBuildCompleted: scripts/artifact-build-completed.js
releaseInfo:
releaseNotes: |
<!--LANG:en-->
Cherry Studio 1.7.7 - New Models & UI Improvements
Cherry Studio 1.7.8 - Bug Fixes & Performance Improvements
This release adds new AI model support, OpenRouter integration, and UI redesigns.
This release focuses on bug fixes and performance optimizations.
✨ New Features
- [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
⚡ Performance
- [ModelList] Improve model list loading performance
🐛 Bug Fixes
- [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
- [Ollama] Fix new users unable to use Ollama models
- [Ollama] Improve reasoningEffort handling
- [Assistants] Prevent deleting last assistant and add error message
- [Shortcut] Fix shortcut icons sorting disorder
- [Memory] Fix global memory settings submit failure
- [Windows] Fix remember size not working for SelectionAction window
- [Anthropic] Fix API base URL handling
- [Files] Allow more file extensions
<!--LANG:zh-CN-->
Cherry Studio 1.7.7 - 新模型与界面改进
Cherry Studio 1.7.8 - 问题修复与性能优化
本次更新添加了新 AI 模型支持、OpenRouter 集成以及界面重新设计
本次更新专注于问题修复和性能优化
✨ 新功能
- [模型] 添加 GLM-4.7 和 MiniMax-M2.1 模型支持
- [服务商] 添加 OpenRouter 服务商支持
- [OVMS] 升级至 2025.4,新增 Qwen3-4B-int4-ov 预设模型
- [OVMS] 应用退出时关闭 OVMS 进程
- [搜索] 历史搜索显示关键词上下文片段
- [绘图] DMX 绘图添加扩展参数支持
- [界面] 添加 MCP 图标并替换锤子图标
🎨 界面改进
- [笔记] 将笔记设置移至笔记页弹窗,快速访问无需离开当前页面
- [网页搜索] 采用两栏布局重新设计设置界面,添加"设为默认"按钮
- [显示] 改进长字体名称的字体选择器
- [传输] LanDrop 重命名为 LanTransfer
⚡ 性能优化
- [模型列表] 提升模型列表加载性能
🐛 问题修复
- [API] 修复 aihubmix Anthropic API 路径
- [OpenRouter] 支持 GPT-5.1/5.2 reasoning effort 'none' 并改进错误处理
- [思考] 修复交错思考支持
- [记忆] 修复检索问题并启用数据库备份
- [设置] 更新默认助手设置禁用温度
- [OpenAI] 添加持久化服务器配置支持
- [Azure] 规范化 Azure 端点
- [MCP] 优先检查系统 npx/uvx 再回退到内置二进制文件
- [提示词] 改进语言指令清晰度
- [模型] GPT5.2 系列添加到 verbosity 检查
- [URL] 增强 urlContext 对支持的服务商和模型的验证
- [Ollama] 修复新用户无法使用 Ollama 模型的问题
- [Ollama] 改进推理参数处理
- [助手] 防止删除最后一个助手并添加错误提示
- [快捷方式] 修复快捷方式图标排序混乱
- [记忆] 修复全局记忆设置提交失败
- [窗口] 修复 SelectionAction 窗口记住尺寸不生效
- [Anthropic] 修复 API 地址处理
- [文件] 允许更多文件扩展名
<!--LANG:END-->

View File

@ -1,6 +1,6 @@
import react from '@vitejs/plugin-react-swc'
import { CodeInspectorPlugin } from 'code-inspector-plugin'
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
import { defineConfig } from 'electron-vite'
import { resolve } from 'path'
import { visualizer } from 'rollup-plugin-visualizer'
@ -17,7 +17,7 @@ const isProd = process.env.NODE_ENV === 'production'
export default defineConfig({
main: {
plugins: [externalizeDepsPlugin(), ...visualizerPlugin('main')],
plugins: [...visualizerPlugin('main')],
resolve: {
alias: {
'@main': resolve('src/main'),
@ -52,8 +52,7 @@ export default defineConfig({
plugins: [
react({
tsDecorators: true
}),
externalizeDepsPlugin()
})
],
resolve: {
alias: {

View File

@ -27,6 +27,7 @@
"scripts": {
"start": "electron-vite preview",
"dev": "dotenv electron-vite dev",
"dev:watch": "dotenv electron-vite dev -- -w",
"debug": "electron-vite -- --inspect --sourcemap --remote-debugging-port=9222",
"build": "npm run typecheck && electron-vite build",
"build:check": "yarn lint && yarn test",
@ -277,7 +278,7 @@
"electron-reload": "^2.0.0-alpha.1",
"electron-store": "^8.2.0",
"electron-updater": "patch:electron-updater@npm%3A6.7.0#~/.yarn/patches/electron-updater-npm-6.7.0-47b11bb0d4.patch",
"electron-vite": "4.0.1",
"electron-vite": "5.0.0",
"electron-window-state": "^5.0.3",
"emittery": "^1.0.3",
"emoji-picker-element": "^1.22.1",
@ -374,7 +375,7 @@
"undici": "6.21.2",
"unified": "^11.0.5",
"uuid": "^13.0.0",
"vite": "npm:rolldown-vite@7.1.5",
"vite": "npm:rolldown-vite@7.3.0",
"vitest": "^3.2.4",
"webdav": "^5.8.0",
"winston": "^3.17.0",
@ -404,7 +405,7 @@
"pkce-challenge@npm:^4.1.0": "patch:pkce-challenge@npm%3A4.1.0#~/.yarn/patches/pkce-challenge-npm-4.1.0-fbc51695a3.patch",
"tar-fs": "^2.1.4",
"undici": "6.21.2",
"vite": "npm:rolldown-vite@7.1.5",
"vite": "npm:rolldown-vite@7.3.0",
"tesseract.js@npm:*": "patch:tesseract.js@npm%3A6.0.1#~/.yarn/patches/tesseract.js-npm-6.0.1-2562a7e46d.patch",
"@ai-sdk/openai@npm:^2.0.52": "patch:@ai-sdk/openai@npm%3A2.0.52#~/.yarn/patches/@ai-sdk-openai-npm-2.0.52-b36d949c76.patch",
"@img/sharp-darwin-arm64": "0.34.3",

View File

@ -35,3 +35,56 @@ export const defaultAppHeaders = () => {
// return value
// }
// }
/**
* Extracts the trailing API version segment from a URL path.
*
* This function extracts API version patterns (e.g., `v1`, `v2beta`) from the end of a URL.
* Only versions at the end of the path are extracted, not versions in the middle.
* The returned version string does not include leading or trailing slashes.
*
* @param {string} url - The URL string to parse.
* @returns {string | undefined} The trailing API version found (e.g., 'v1', 'v2beta'), or undefined if none found.
*
* @example
* getTrailingApiVersion('https://api.example.com/v1') // 'v1'
* getTrailingApiVersion('https://api.example.com/v2beta/') // 'v2beta'
* getTrailingApiVersion('https://api.example.com/v1/chat') // undefined (version not at end)
* getTrailingApiVersion('https://gateway.ai.cloudflare.com/v1/xxx/v1beta') // 'v1beta'
* getTrailingApiVersion('https://api.example.com') // undefined
*/
export function getTrailingApiVersion(url: string): string | undefined {
const match = url.match(TRAILING_VERSION_REGEX)
if (match) {
// Extract version without leading slash and trailing slash
return match[0].replace(/^\//, '').replace(/\/$/, '')
}
return undefined
}
/**
* Matches an API version at the end of a URL (with optional trailing slash).
* Used to detect and extract versions only from the trailing position.
*/
const TRAILING_VERSION_REGEX = /\/v\d+(?:alpha|beta)?\/?$/i
/**
* Removes the trailing API version segment from a URL path.
*
* This function removes API version patterns (e.g., `/v1`, `/v2beta`) from the end of a URL.
* Only versions at the end of the path are removed, not versions in the middle.
*
* @param {string} url - The URL string to process.
* @returns {string} The URL with the trailing API version removed, or the original URL if no trailing version found.
*
* @example
* withoutTrailingApiVersion('https://api.example.com/v1') // 'https://api.example.com'
* withoutTrailingApiVersion('https://api.example.com/v2beta/') // 'https://api.example.com'
* withoutTrailingApiVersion('https://api.example.com/v1/chat') // 'https://api.example.com/v1/chat' (no change)
* withoutTrailingApiVersion('https://api.example.com') // 'https://api.example.com'
*/
export function withoutTrailingApiVersion(url: string): string {
return url.replace(TRAILING_VERSION_REGEX, '')
}

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import { loggerService } from '@logger'
import { IpcChannel } from '@shared/IpcChannel'
import type { WebDavConfig } from '@types'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import { ZOOM_SHORTCUTS } from '@shared/config/constant'
import type { Shortcut } from '@types'
import Store from 'electron-store'

View File

@ -1,7 +1,19 @@
/**
* @deprecated this file will be removed after v2 refactor
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import { loggerService } from '@logger'
import { IpcChannel } from '@shared/IpcChannel'
import { ipcMain } from 'electron'

View File

@ -1440,6 +1440,12 @@ export class SelectionService {
}
actionWindow.setBounds({ x, y, width, height })
// [Windows only] Update remembered window size for custom resize
// setBounds() may not trigger the 'resized' event, so we need to update manually
if (this.isRemeberWinSize) {
this.lastActionWindowSize = { width, height }
}
}
/**

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import { preferenceService } from '@data/PreferenceService'
import { loggerService } from '@logger'
import { handleZoomFactor } from '@main/utils/zoom'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import { IpcChannel } from '@shared/IpcChannel'
import type { StoreSyncAction } from '@types'
import { BrowserWindow, ipcMain } from 'electron'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import { type Client, createClient } from '@libsql/client'
import { loggerService } from '@logger'
import type { LibSQLDatabase } from 'drizzle-orm/libsql'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
/**
* Drizzle Kit configuration for agents database
*/

View File

@ -18,6 +18,7 @@ import { validateModelId } from '@main/apiServer/utils'
import { isWin } from '@main/constant'
import { autoDiscoverGitBash } from '@main/utils/process'
import getLoginShellEnvironment from '@main/utils/shell-env'
import { withoutTrailingApiVersion } from '@shared/utils'
import { app } from 'electron'
import type { GetAgentSessionResponse } from '../..'
@ -116,6 +117,13 @@ class ClaudeCodeService implements AgentServiceInterface {
// Auto-discover Git Bash path on Windows (already logs internally)
const customGitBashPath = isWin ? autoDiscoverGitBash() : null
// Claude Agent SDK builds the final endpoint as `${ANTHROPIC_BASE_URL}/v1/messages`.
// To avoid malformed URLs like `/v1/v1/messages`, we normalize the provider host
// by stripping any trailing API version (e.g. `/v1`).
const anthropicBaseUrl = withoutTrailingApiVersion(
modelInfo.provider.anthropicApiHost?.trim() || modelInfo.provider.apiHost
)
const env = {
...loginShellEnvWithoutProxies,
// TODO: fix the proxy api server
@ -124,7 +132,7 @@ class ClaudeCodeService implements AgentServiceInterface {
// ANTHROPIC_BASE_URL: `http://${apiConfig['feature.csaas.host']}:${apiConfig['feature.csaas.port']}/${modelInfo.provider.id}`,
ANTHROPIC_API_KEY: modelInfo.provider.apiKey,
ANTHROPIC_AUTH_TOKEN: modelInfo.provider.apiKey,
ANTHROPIC_BASE_URL: modelInfo.provider.anthropicApiHost?.trim() || modelInfo.provider.apiHost,
ANTHROPIC_BASE_URL: anthropicBaseUrl,
ANTHROPIC_MODEL: modelInfo.modelId,
ANTHROPIC_DEFAULT_OPUS_MODEL: modelInfo.modelId,
ANTHROPIC_DEFAULT_SONNET_MODEL: modelInfo.modelId,

View File

@ -46,7 +46,6 @@ import type {
GeminiSdkRawOutput,
GeminiSdkToolCall
} from '@renderer/types/sdk'
import { getTrailingApiVersion, withoutTrailingApiVersion } from '@renderer/utils'
import { isToolUseModeFunction } from '@renderer/utils/assistant'
import {
geminiFunctionCallToMcpTool,
@ -56,6 +55,7 @@ import {
} from '@renderer/utils/mcp-tools'
import { findFileBlocks, findImageBlocks, getMainTextContent } from '@renderer/utils/messageUtils/find'
import { defaultTimeout, MB } from '@shared/config/constant'
import { getTrailingApiVersion, withoutTrailingApiVersion } from '@shared/utils'
import { t } from 'i18next'
import type { GenericChunk } from '../../middleware/schemas'

View File

@ -2,7 +2,8 @@ import type OpenAI from '@cherrystudio/openai'
import { loggerService } from '@logger'
import { isSupportedModel } from '@renderer/config/models'
import { objectKeys, type Provider } from '@renderer/types'
import { formatApiHost, withoutTrailingApiVersion } from '@renderer/utils'
import { formatApiHost } from '@renderer/utils'
import { withoutTrailingApiVersion } from '@shared/utils'
import { OpenAIAPIClient } from '../openai/OpenAIApiClient'

View File

@ -580,8 +580,10 @@ function buildOllamaProviderOptions(
const reasoningEffort = assistant.settings?.reasoning_effort
if (enableReasoning) {
if (isOpenAIOpenWeightModel(model)) {
// @ts-ignore upstream type error
providerOptions.think = reasoningEffort as any
// For gpt-oss models, Ollama accepts: 'low' | 'medium' | 'high'
if (reasoningEffort === 'low' || reasoningEffort === 'medium' || reasoningEffort === 'high') {
providerOptions.think = reasoningEffort
}
} else {
providerOptions.think = !['none', undefined].includes(reasoningEffort)
}

View File

@ -680,7 +680,12 @@ describe('getThinkModelType - Comprehensive Coverage', () => {
expect(getThinkModelType(createModel({ id: 'o3' }))).toBe('o')
expect(getThinkModelType(createModel({ id: 'o3-mini' }))).toBe('o')
expect(getThinkModelType(createModel({ id: 'o4' }))).toBe('o')
expect(getThinkModelType(createModel({ id: 'gpt-oss-reasoning' }))).toBe('o')
})
it('should return gpt_oss for gpt-oss models', () => {
expect(getThinkModelType(createModel({ id: 'gpt-oss' }))).toBe('gpt_oss')
expect(getThinkModelType(createModel({ id: 'gpt-oss:20b' }))).toBe('gpt_oss')
expect(getThinkModelType(createModel({ id: 'gpt-oss-reasoning' }))).toBe('gpt_oss')
})
})
@ -1763,6 +1768,21 @@ describe('getModelSupportedReasoningEffortOptions', () => {
'medium',
'high'
])
})
it('should return correct options for gpt-oss models', () => {
expect(getModelSupportedReasoningEffortOptions(createModel({ id: 'gpt-oss' }))).toEqual([
'default',
'low',
'medium',
'high'
])
expect(getModelSupportedReasoningEffortOptions(createModel({ id: 'gpt-oss:20b' }))).toEqual([
'default',
'low',
'medium',
'high'
])
expect(getModelSupportedReasoningEffortOptions(createModel({ id: 'gpt-oss-reasoning' }))).toEqual([
'default',
'low',

View File

@ -17,6 +17,7 @@ import {
isGPT52ProModel,
isGPT52SeriesModel,
isOpenAIDeepResearchModel,
isOpenAIOpenWeightModel,
isOpenAIReasoningModel,
isSupportedReasoningEffortOpenAIModel
} from './openai'
@ -41,6 +42,7 @@ export const MODEL_SUPPORTED_REASONING_EFFORT = {
gpt5_2: ['none', 'low', 'medium', 'high', 'xhigh'] as const,
gpt5pro: ['high'] as const,
gpt52pro: ['medium', 'high', 'xhigh'] as const,
gpt_oss: ['low', 'medium', 'high'] as const,
grok: ['low', 'high'] as const,
grok4_fast: ['auto'] as const,
gemini2_flash: ['low', 'medium', 'high', 'auto'] as const,
@ -72,6 +74,7 @@ export const MODEL_SUPPORTED_OPTIONS: ThinkingOptionConfig = {
gpt5_2: ['default', ...MODEL_SUPPORTED_REASONING_EFFORT.gpt5_2] as const,
gpt5_1_codex_max: ['default', ...MODEL_SUPPORTED_REASONING_EFFORT.gpt5_1_codex_max] as const,
gpt52pro: ['default', ...MODEL_SUPPORTED_REASONING_EFFORT.gpt52pro] as const,
gpt_oss: ['default', ...MODEL_SUPPORTED_REASONING_EFFORT.gpt_oss] as const,
grok: ['default', ...MODEL_SUPPORTED_REASONING_EFFORT.grok] as const,
grok4_fast: ['default', 'none', ...MODEL_SUPPORTED_REASONING_EFFORT.grok4_fast] as const,
gemini2_flash: ['default', 'none', ...MODEL_SUPPORTED_REASONING_EFFORT.gemini2_flash] as const,
@ -127,6 +130,8 @@ const _getThinkModelType = (model: Model): ThinkingModelType => {
thinkingModelType = 'gpt5pro'
}
}
} else if (isOpenAIOpenWeightModel(model)) {
thinkingModelType = 'gpt_oss'
} else if (isSupportedReasoningEffortOpenAIModel(model)) {
thinkingModelType = 'o'
} else if (isGrok4FastReasoningModel(model)) {

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import type {
CustomTranslateLanguage,
FileMetadata,

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import { loggerService } from '@logger'
import { LanguagesEnum } from '@renderer/config/translate'
import type { LegacyMessage as OldMessage, Topic, TranslateLanguageCode } from '@renderer/types'

View File

@ -1,8 +1,19 @@
/**
* Data Refactor, notes by fullex
* //TODO @deprecated this file will be removed
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import { usePreference } from '@data/hooks/usePreference'
import { useAppSelector } from '@renderer/store'
import store from '@renderer/store'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import { isMac, isWin } from '@renderer/config/constant'
import { useAppSelector } from '@renderer/store'
import { orderBy } from 'lodash'

View File

@ -1,4 +1,20 @@
//FIXME @deprecated this file will be removed after data refactor
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import { usePreference } from '@data/hooks/usePreference'
import { CHERRYAI_PROVIDER } from '@renderer/config/providers'
import store from '@renderer/store'

View File

@ -420,6 +420,9 @@
},
"delete": {
"content": "Deleting an assistant will delete all topics and files under the assistant. Are you sure you want to delete it?",
"error": {
"remain_one": "Not allowed to delete the last one assistant"
},
"title": "Delete Assistant"
},
"edit": {

View File

@ -420,6 +420,9 @@
},
"delete": {
"content": "删除助手会删除所有该助手下的话题和文件,确定要继续吗?",
"error": {
"remain_one": "不允许删除最后一个助手"
},
"title": "删除助手"
},
"edit": {

View File

@ -420,6 +420,9 @@
},
"delete": {
"content": "刪除助手會刪除所有該助手下的話題和檔案,確定要繼續嗎?",
"error": {
"remain_one": "不允許刪除最後一個助手"
},
"title": "刪除助手"
},
"edit": {
@ -4805,7 +4808,7 @@
"content_limit_tooltip": "限制搜尋結果的內容長度;超過限制的內容將被截斷。",
"default_provider": "預設搜尋引擎",
"free": "免費",
"is_default": "[to be translated]:Default",
"is_default": "預設",
"local_provider": {
"hint": "登入網站以獲得更佳搜尋結果並個人化您的搜尋設定。",
"open_settings": "開啟 {{provider}} 設定",
@ -4822,7 +4825,7 @@
"search_provider": "搜尋供應商",
"search_provider_placeholder": "選擇一個搜尋供應商",
"search_with_time": "搜尋包含日期",
"set_as_default": "[to be translated]:Set as Default",
"set_as_default": "設為預設",
"subscribe": "黑名單訂閱",
"subscribe_add": "新增訂閱",
"subscribe_add_failed": "訂閱來源新增失敗",

View File

@ -420,6 +420,9 @@
},
"delete": {
"content": "Das Löschen des Assistenten löscht alle Themen und Dateien unter diesem Assistenten. Möchten Sie fortfahren?",
"error": {
"remain_one": "Man darf den letzten Assistenten nicht löschen."
},
"title": "Assistent löschen"
},
"edit": {
@ -4805,7 +4808,7 @@
"content_limit_tooltip": "Begrenzen Sie die Länge der Suchergebnisse, überschreitende Inhalte werden abgeschnitten",
"default_provider": "Standardanbieter",
"free": "Kostenlos",
"is_default": "[to be translated]:Default",
"is_default": "Standard",
"local_provider": {
"hint": "Melden Sie sich auf der Website an, um bessere Suchergebnisse zu erhalten und Ihre Sucheinstellungen zu personalisieren.",
"open_settings": "{{provider}}-Einstellungen öffnen",
@ -4822,7 +4825,7 @@
"search_provider": "Suchanbieter",
"search_provider_placeholder": "Einen Suchanbieter auswählen",
"search_with_time": "Suche mit Datum",
"set_as_default": "[to be translated]:Set as Default",
"set_as_default": "Als Standard festlegen",
"subscribe": "Schwarze Liste-Abonnement",
"subscribe_add": "Abonnement hinzufügen",
"subscribe_add_failed": "Abonnement-Quelle hinzufügen fehlgeschlagen",

View File

@ -420,6 +420,9 @@
},
"delete": {
"content": "Η διαγραφή του βοηθού θα διαγράψει όλα τα θέματα και τα αρχεία που είναι συνδεδεμένα με αυτόν. Είστε σίγουροι πως θέλετε να συνεχίσετε;",
"error": {
"remain_one": "Δεν επιτρέπεται η διαγραφή του τελευταίου βοηθού"
},
"title": "Διαγραφή βοηθού"
},
"edit": {
@ -4805,7 +4808,7 @@
"content_limit_tooltip": "Περιορίζει το μήκος του περιεχομένου των αποτελεσμάτων αναζήτησης, το περιεχόμενο πέραν του ορίου θα περικοπεί",
"default_provider": "Προεπιλεγμένος Πάροχος",
"free": "Δωρεάν",
"is_default": "[to be translated]:Default",
"is_default": "Προεπιλογή",
"local_provider": {
"hint": "Συνδεθείτε στην ιστοσελίδα για να λάβετε καλύτερα αποτελέσματα αναζήτησης και να εξατομικεύσετε τις ρυθμίσεις αναζήτησής σας.",
"open_settings": "Άνοιγμα Ρυθμίσεων {{provider}}",
@ -4822,7 +4825,7 @@
"search_provider": "Πάροχος αναζήτησης",
"search_provider_placeholder": "Επιλέξτε έναν πάροχο αναζήτησης",
"search_with_time": "Αναζήτηση με ημερομηνία",
"set_as_default": "[to be translated]:Set as Default",
"set_as_default": "Ορισμός ως προεπιλογή",
"subscribe": "Εγγραφή σε μαύρη λίστα",
"subscribe_add": "Προσθήκη εγγραφής",
"subscribe_add_failed": "Η προσθήκη της ροής συνδρομής απέτυχε",

View File

@ -420,6 +420,9 @@
},
"delete": {
"content": "Eliminar el asistente borrará todos los temas y archivos asociados. ¿Está seguro de que desea continuar?",
"error": {
"remain_one": "No se puede eliminar el último asistente"
},
"title": "Eliminar Asistente"
},
"edit": {
@ -4805,7 +4808,7 @@
"content_limit_tooltip": "Limita la longitud del contenido en los resultados de búsqueda; el contenido que exceda el límite será truncado",
"default_provider": "Proveedor Predeterminado",
"free": "Gratis",
"is_default": "[to be translated]:Default",
"is_default": "Por defecto",
"local_provider": {
"hint": "Inicia sesión en el sitio web para obtener mejores resultados de búsqueda y personalizar tu configuración de búsqueda.",
"open_settings": "Abrir configuración de {{provider}}",
@ -4822,7 +4825,7 @@
"search_provider": "Proveedor de búsqueda",
"search_provider_placeholder": "Seleccione un proveedor de búsqueda",
"search_with_time": "Buscar con fecha",
"set_as_default": "[to be translated]:Set as Default",
"set_as_default": "Establecer como predeterminado",
"subscribe": "Suscripción a lista negra",
"subscribe_add": "Añadir suscripción",
"subscribe_add_failed": "Error al agregar la fuente de suscripción",

View File

@ -420,6 +420,9 @@
},
"delete": {
"content": "La suppression de l'aide supprimera tous les sujets et fichiers sous l'aide. Êtes-vous sûr de vouloir la supprimer ?",
"error": {
"remain_one": "Interdiction de supprimer le dernier assistant"
},
"title": "Supprimer l'Aide"
},
"edit": {
@ -4805,7 +4808,7 @@
"content_limit_tooltip": "Limiter la longueur du contenu des résultats de recherche ; le contenu dépassant cette limite sera tronqué",
"default_provider": "Fournisseur par défaut",
"free": "Gratuit",
"is_default": "[to be translated]:Default",
"is_default": "Défaut",
"local_provider": {
"hint": "Connectez-vous au site Web pour obtenir de meilleurs résultats de recherche et personnaliser vos paramètres de recherche.",
"open_settings": "Ouvrir les paramètres de {{provider}}",
@ -4822,7 +4825,7 @@
"search_provider": "Fournisseur de recherche",
"search_provider_placeholder": "Sélectionnez un fournisseur de recherche",
"search_with_time": "Rechercher avec date",
"set_as_default": "[to be translated]:Set as Default",
"set_as_default": "Définir par défaut",
"subscribe": "Abonnement à la liste noire",
"subscribe_add": "Ajouter un abonnement",
"subscribe_add_failed": "Échec de l'ajout de la source d'abonnement",

View File

@ -420,6 +420,9 @@
},
"delete": {
"content": "アシスタントを削除すると、そのアシスタントのすべてのトピックとファイルが削除されます。削除しますか?",
"error": {
"remain_one": "最後の1人のアシスタントは削除できません"
},
"title": "アシスタントを削除"
},
"edit": {
@ -4805,7 +4808,7 @@
"content_limit_tooltip": "検索結果のコンテンツの長さを制限します。制限を超えるコンテンツは切り捨てられます。",
"default_provider": "デフォルトプロバイダー",
"free": "無料",
"is_default": "[to be translated]:Default",
"is_default": "デフォルト",
"local_provider": {
"hint": "ウェブサイトにログインして、より良い検索結果を得て、検索設定をパーソナライズしてください。",
"open_settings": "{{provider}}設定を開く",
@ -4822,7 +4825,7 @@
"search_provider": "検索サービスプロバイダー",
"search_provider_placeholder": "検索サービスプロバイダーを選択する",
"search_with_time": "日付を含む検索",
"set_as_default": "[to be translated]:Set as Default",
"set_as_default": "既定として設定",
"subscribe": "ブラックリスト購読",
"subscribe_add": "購読を追加",
"subscribe_add_failed": "購読ソースの追加に失敗しました",

View File

@ -420,6 +420,9 @@
},
"delete": {
"content": "Excluir o assistente removerá todos os tópicos e arquivos sob esse assistente. Tem certeza de que deseja continuar?",
"error": {
"remain_one": "Não é permitido apagar o último assistente."
},
"title": "Excluir Assistente"
},
"edit": {
@ -4805,7 +4808,7 @@
"content_limit_tooltip": "Limita o comprimento do conteúdo dos resultados de pesquisa; o conteúdo excedente será truncado",
"default_provider": "Provedor Padrão",
"free": "Grátis",
"is_default": "[to be translated]:Default",
"is_default": "Padrão",
"local_provider": {
"hint": "Faça login no site para obter melhores resultados de pesquisa e personalizar suas configurações de busca.",
"open_settings": "Abrir Configurações do {{provider}}",
@ -4822,7 +4825,7 @@
"search_provider": "Provedor de pesquisa",
"search_provider_placeholder": "Selecione um provedor de pesquisa",
"search_with_time": "Pesquisar com data",
"set_as_default": "[to be translated]:Set as Default",
"set_as_default": "Definir como Padrão",
"subscribe": "Assinatura de lista negra",
"subscribe_add": "Adicionar assinatura",
"subscribe_add_failed": "Falha ao adicionar a fonte de subscrição",

View File

@ -420,6 +420,9 @@
},
"delete": {
"content": "Удаление ассистента удалит все топики и файлы под ассистентом. Вы уверены, что хотите удалить его?",
"error": {
"remain_one": "Нельзя удалить последнего помощника"
},
"title": "Удалить ассистента"
},
"edit": {
@ -4805,7 +4808,7 @@
"content_limit_tooltip": "Ограничить длину контента в результатах поиска; контент, превышающий лимит, будет усечен.",
"default_provider": "Поставщик по умолчанию",
"free": "Бесплатно",
"is_default": "[to be translated]:Default",
"is_default": "По умолчанию",
"local_provider": {
"hint": "Войдите на сайт, чтобы получать более точные результаты поиска и настроить параметры поиска под себя.",
"open_settings": "Открыть настройки {{provider}}",
@ -4822,7 +4825,7 @@
"search_provider": "поиск сервисного провайдера",
"search_provider_placeholder": "Выберите поставщика поисковых услуг",
"search_with_time": "Поиск, содержащий дату",
"set_as_default": "[to be translated]:Set as Default",
"set_as_default": "Установить по умолчанию",
"subscribe": "Подписка на черный список",
"subscribe_add": "Добавить подписку",
"subscribe_add_failed": "Не удалось добавить источник подписки",

View File

@ -262,9 +262,12 @@ const InputbarTools = ({ scope, assistantId, session }: InputbarToolsNewProps) =
const sourceId = source.droppableId
const destinationId = destination.droppableId
const visibleKeys = visibleTools.map((t) => t.key)
const hiddenKeys = hiddenTools.map((t) => t.key)
const newToolOrder: ToolOrderConfig = {
visible: [...toolOrder.visible],
hidden: [...toolOrder.hidden]
visible: [...visibleKeys],
hidden: [...hiddenKeys]
}
const sourceArray = sourceId === 'inputbar-tools-visible' ? 'visible' : 'hidden'

View File

@ -10,6 +10,7 @@ import type { Assistant, Topic } from '@renderer/types'
import type { AssistantTabSortType } from '@shared/data/preference/preferenceTypes'
import type { FC } from 'react'
import { useCallback, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
import UnifiedAddButton from './components/UnifiedAddButton'
@ -32,6 +33,7 @@ const AssistantsTab: FC<AssistantsTabProps> = (props) => {
const containerRef = useRef<HTMLDivElement>(null)
const { apiServerConfig } = useApiServer()
const apiServerEnabled = apiServerConfig.enabled
const { t } = useTranslation()
// Agent related hooks
const { agents, deleteAgent, isLoading: agentsLoading, error: agentsError } = useAgents()
@ -75,13 +77,18 @@ const AssistantsTab: FC<AssistantsTabProps> = (props) => {
const onDeleteAssistant = useCallback(
(assistant: Assistant) => {
const remaining = assistants.filter((a) => a.id !== assistant.id)
if (remaining.length === 0) {
window.toast.error(t('assistants.delete.error.remain_one'))
return
}
if (assistant.id === activeAssistant?.id) {
const newActive = remaining[remaining.length - 1]
newActive ? setActiveAssistant(newActive) : onCreateDefaultAssistant()
setActiveAssistant(newActive)
}
removeAssistant(assistant.id)
},
[activeAssistant, assistants, removeAssistant, setActiveAssistant, onCreateDefaultAssistant]
[assistants, activeAssistant?.id, removeAssistant, t, setActiveAssistant]
)
const handleSortByChange = useCallback(

View File

@ -4,7 +4,7 @@ import { loggerService } from '@logger'
import InputEmbeddingDimension from '@renderer/components/InputEmbeddingDimension'
import ModelSelector from '@renderer/components/ModelSelector'
import { isEmbeddingModel, isRerankModel } from '@renderer/config/models'
import { getModel, useModel } from '@renderer/hooks/useModel'
import { useModel } from '@renderer/hooks/useModel'
import { useProviders } from '@renderer/hooks/useProvider'
import { getModelUniqId } from '@renderer/services/ModelService'
import { selectMemoryConfig, updateMemoryConfig } from '@renderer/store/memory'
@ -56,8 +56,12 @@ const MemorySettingsModal: FC<MemorySettingsModalProps> = ({ visible, onSubmit,
const handleFormSubmit = async (values: formValue) => {
try {
// Convert model IDs back to Model objects
const llmModel = getModel(values.llmModel)
const embeddingModel = getModel(values.embeddingModel)
// values.llmModel and values.embeddingModel are JSON strings from getModelUniqId()
// e.g., '{"id":"gpt-4","provider":"openai"}'
// We need to find models by comparing with getModelUniqId() result
const allModels = providers.flatMap((p) => p.models)
const llmModel = allModels.find((m) => getModelUniqId(m) === values.llmModel)
const embeddingModel = allModels.find((m) => getModelUniqId(m) === values.embeddingModel)
if (embeddingModel) {
setLoading(true)
@ -142,7 +146,9 @@ const MemorySettingsModal: FC<MemorySettingsModalProps> = ({ visible, onSubmit,
shouldUpdate={(prevValues, currentValues) => prevValues.embeddingModel !== currentValues.embeddingModel}>
{({ getFieldValue }) => {
const embeddingModelId = getFieldValue('embeddingModel')
const embeddingModel = getModel(embeddingModelId)
// embeddingModelId is a JSON string from getModelUniqId(), find model by comparing
const allModels = providers.flatMap((p) => p.models)
const embeddingModel = allModels.find((m) => getModelUniqId(m) === embeddingModelId)
return (
<Form.Item
label={

View File

@ -49,6 +49,9 @@ const ModelList: React.FC<ModelListProps> = ({ providerId }) => {
const { t } = useTranslation()
const { provider, models, removeModel } = useProvider(providerId)
// 稳定的编辑模型回调,避免内联函数导致子组件 memo 失效
const handleEditModel = useCallback((model: Model) => EditModelPopup.show({ provider, model }), [provider])
const providerConfig = PROVIDER_URLS[provider.id]
const docsWebsite = providerConfig?.websites?.docs
const modelsWebsite = providerConfig?.websites?.models
@ -63,6 +66,11 @@ const ModelList: React.FC<ModelListProps> = ({ providerId }) => {
const { isChecking: isHealthChecking, modelStatuses, runHealthCheck } = useHealthCheck(provider, models)
// 将 modelStatuses 数组转换为 Map实现 O(1) 查找
const modelStatusMap = useMemo(() => {
return new Map(modelStatuses.map((status) => [status.model.id, status]))
}, [modelStatuses])
const setSearchText = useCallback((text: string) => {
startTransition(() => {
_setSearchText(text)
@ -136,9 +144,9 @@ const ModelList: React.FC<ModelListProps> = ({ providerId }) => {
key={group}
groupName={group}
models={displayedModelGroups[group]}
modelStatuses={modelStatuses}
modelStatusMap={modelStatusMap}
defaultOpen={i <= 5}
onEditModel={(model) => EditModelPopup.show({ provider, model })}
onEditModel={handleEditModel}
onRemoveModel={removeModel}
onRemoveGroup={() => displayedModelGroups[group].forEach((model) => removeModel(model))}
/>

View File

@ -15,7 +15,8 @@ const MAX_SCROLLER_HEIGHT = 390
interface ModelListGroupProps {
groupName: string
models: Model[]
modelStatuses: ModelWithStatus[]
/** 使用 Map 实现 O(1) 查找,替代原来的数组线性搜索 */
modelStatusMap: Map<string, ModelWithStatus>
defaultOpen: boolean
disabled?: boolean
onEditModel: (model: Model) => void
@ -26,7 +27,7 @@ interface ModelListGroupProps {
const ModelListGroup: React.FC<ModelListGroupProps> = ({
groupName,
models,
modelStatuses,
modelStatusMap,
defaultOpen,
disabled,
onEditModel,
@ -89,7 +90,7 @@ const ModelListGroup: React.FC<ModelListGroupProps> = ({
{(model) => (
<ModelListItem
model={model}
modelStatus={modelStatuses.find((status) => status.model.id === model.id)}
modelStatus={modelStatusMap.get(model.id)}
onEdit={onEditModel}
onRemove={onRemoveModel}
disabled={disabled}

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import { loggerService } from '@logger'
import store from '@renderer/store'
import type { AgentPersistedMessage } from '@renderer/types/agent'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import { loggerService } from '@logger'
import store from '@renderer/store'
import type { Message, MessageBlock } from '@renderer/types/newMessage'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import { loggerService } from '@logger'
import db from '@renderer/databases'
import FileManager from '@renderer/services/FileManager'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
/**
* Unified data access layer for messages
* Provides a consistent API for accessing messages from different sources

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
// @ts-nocheck
import type { PayloadAction } from '@reduxjs/toolkit'
import { createSelector, createSlice } from '@reduxjs/toolkit'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import type { PayloadAction } from '@reduxjs/toolkit'
import { createSlice } from '@reduxjs/toolkit'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import type { PayloadAction } from '@reduxjs/toolkit'
import { createSlice } from '@reduxjs/toolkit'
import type { Model } from '@renderer/types'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import type { PayloadAction } from '@reduxjs/toolkit'
import { createSlice } from '@reduxjs/toolkit'

View File

@ -1,6 +1,18 @@
/**
* Data Refactor, notes by fullex
* //TODO @deprecated this file will be removed
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import { loggerService } from '@logger'
import { combineReducers, configureStore } from '@reduxjs/toolkit'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import type { PayloadAction } from '@reduxjs/toolkit'
import { createSlice } from '@reduxjs/toolkit'
import type { InputbarScope } from '@renderer/pages/home/Inputbar/types'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import { loggerService } from '@logger'
import type { PayloadAction } from '@reduxjs/toolkit'
import { createSlice } from '@reduxjs/toolkit'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import type { PayloadAction } from '@reduxjs/toolkit'
import { createSlice } from '@reduxjs/toolkit'
import { isLocalAi } from '@renderer/config/env'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import { loggerService } from '@logger'
import { createSlice, nanoid, type PayloadAction } from '@reduxjs/toolkit'
import { type BuiltinMCPServer, BuiltinMCPServerNames, type MCPConfig, type MCPServer } from '@renderer/types'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import { createSlice, type PayloadAction } from '@reduxjs/toolkit'
import { MEMORY_FACT_EXTRACTION_PROMPT, MEMORY_UPDATE_SYSTEM_PROMPT } from '@shared/config/prompts'
import type { MemoryConfig } from '@types'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import type { WebSearchResultBlock } from '@anthropic-ai/sdk/resources'
import type OpenAI from '@cherrystudio/openai'
import type { GroundingMetadata } from '@google/genai'

View File

@ -1,5 +1,18 @@
/**
* @deprecated this file will be removed after data refactor
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import { loggerService } from '@logger'
import { nanoid } from '@reduxjs/toolkit'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import type { PayloadAction } from '@reduxjs/toolkit'
import { createSlice } from '@reduxjs/toolkit'
import { DEFAULT_MIN_APPS } from '@renderer/config/minapps'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import { loggerService } from '@logger'
import type { EntityState, PayloadAction } from '@reduxjs/toolkit'
import { createEntityAdapter, createSlice } from '@reduxjs/toolkit'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import type { PayloadAction } from '@reduxjs/toolkit'
import { createSlice } from '@reduxjs/toolkit'
import type { RootState } from '@renderer/store/index'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import type { PayloadAction } from '@reduxjs/toolkit'
import { createSlice } from '@reduxjs/toolkit'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import type { PayloadAction } from '@reduxjs/toolkit'
import { createSlice } from '@reduxjs/toolkit'
import { BUILTIN_OCR_PROVIDERS, DEFAULT_OCR_PROVIDER } from '@renderer/config/ocr'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import { loggerService } from '@logger'
import type { PayloadAction } from '@reduxjs/toolkit'
import { createSlice } from '@reduxjs/toolkit'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import type { PayloadAction } from '@reduxjs/toolkit'
import { createSlice } from '@reduxjs/toolkit'
import type { PreprocessProvider } from '@renderer/types'

View File

@ -1,8 +1,20 @@
/**
* Data Refactor, notes by fullex
* //TODO @deprecated this file will be removed
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import type { PayloadAction } from '@reduxjs/toolkit'
import { createSlice } from '@reduxjs/toolkit'
// import type { Topic, WebSearchStatus } from '@renderer/types'

View File

@ -1,5 +1,18 @@
/**
* @deprecated The whole file will be removed after data refactoring
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import type { PayloadAction } from '@reduxjs/toolkit'
import { createSlice } from '@reduxjs/toolkit'

View File

@ -1,5 +1,18 @@
/**
* //TODO @deprecated this file will be removed after data refactor
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import type { PayloadAction } from '@reduxjs/toolkit'
import { createSlice } from '@reduxjs/toolkit'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import type { PayloadAction } from '@reduxjs/toolkit'
import { createSlice } from '@reduxjs/toolkit'
import type { Shortcut } from '@renderer/types'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import type { PayloadAction } from '@reduxjs/toolkit'
import { createSlice } from '@reduxjs/toolkit'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import { loggerService } from '@logger'
import { db } from '@renderer/databases'
import { addFiles as addFilesAction, addItem, updateNotes } from '@renderer/store/knowledge'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import { cacheService } from '@data/CacheService'
import { loggerService } from '@logger'
import { AiSdkToChunkAdapter } from '@renderer/aiCore/chunk/AiSdkToChunkAdapter'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
/**
* V2 implementations of message thunk functions using the unified DbService
* These implementations will be gradually rolled out using feature flags

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import type { PermissionUpdate } from '@anthropic-ai/claude-agent-sdk'
import type { PayloadAction } from '@reduxjs/toolkit'
import { createSlice } from '@reduxjs/toolkit'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import type { PayloadAction } from '@reduxjs/toolkit'
import { createSlice } from '@reduxjs/toolkit'

View File

@ -1,3 +1,19 @@
/**
* @deprecated Scheduled for removal in v2.0.0
* --------------------------------------------------------------------------
* NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
* --------------------------------------------------------------------------
* STOP: Feature PRs affecting this file are currently BLOCKED.
* Only critical bug fixes are accepted during this migration phase.
*
* This file is being refactored to v2 standards.
* Any non-critical changes will conflict with the ongoing work.
*
* 🔗 Context & Status:
* - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
* - v2 Refactor PR : https://github.com/CherryHQ/cherry-studio/pull/10162
* --------------------------------------------------------------------------
*/
import type { PayloadAction } from '@reduxjs/toolkit'
import { createSlice } from '@reduxjs/toolkit'
import { WEB_SEARCH_PROVIDERS } from '@renderer/config/webSearchProviders'

View File

@ -92,6 +92,7 @@ const ThinkModelTypes = [
'gpt5_2',
'gpt5pro',
'gpt52pro',
'gpt_oss',
'grok',
'grok4_fast',
'gemini2_flash',

View File

@ -1,5 +1,6 @@
import store from '@renderer/store'
import type { VertexProvider } from '@renderer/types'
import { getTrailingApiVersion, withoutTrailingApiVersion } from '@shared/utils'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import {
@ -8,14 +9,12 @@ import {
formatAzureOpenAIApiHost,
formatOllamaApiHost,
formatVertexApiHost,
getTrailingApiVersion,
hasAPIVersion,
isWithTrailingSharp,
maskApiKey,
routeToEndpoint,
splitApiKeyString,
validateApiHost,
withoutTrailingApiVersion,
withoutTrailingSharp
} from '../api'

View File

@ -19,12 +19,6 @@ export function formatApiKeys(value: string): string {
*/
const VERSION_REGEX_PATTERN = '\\/v\\d+(?:alpha|beta)?(?=\\/|$)'
/**
* Matches an API version at the end of a URL (with optional trailing slash).
* Used to detect and extract versions only from the trailing position.
*/
const TRAILING_VERSION_REGEX = /\/v\d+(?:alpha|beta)?\/?$/i
/**
* host path /v1/v2beta
*
@ -272,50 +266,3 @@ export function splitApiKeyString(keyStr: string): string[] {
.map((k) => k.replace(/\\,/g, ','))
.filter((k) => k)
}
/**
* Extracts the trailing API version segment from a URL path.
*
* This function extracts API version patterns (e.g., `v1`, `v2beta`) from the end of a URL.
* Only versions at the end of the path are extracted, not versions in the middle.
* The returned version string does not include leading or trailing slashes.
*
* @param {string} url - The URL string to parse.
* @returns {string | undefined} The trailing API version found (e.g., 'v1', 'v2beta'), or undefined if none found.
*
* @example
* getTrailingApiVersion('https://api.example.com/v1') // 'v1'
* getTrailingApiVersion('https://api.example.com/v2beta/') // 'v2beta'
* getTrailingApiVersion('https://api.example.com/v1/chat') // undefined (version not at end)
* getTrailingApiVersion('https://gateway.ai.cloudflare.com/v1/xxx/v1beta') // 'v1beta'
* getTrailingApiVersion('https://api.example.com') // undefined
*/
export function getTrailingApiVersion(url: string): string | undefined {
const match = url.match(TRAILING_VERSION_REGEX)
if (match) {
// Extract version without leading slash and trailing slash
return match[0].replace(/^\//, '').replace(/\/$/, '')
}
return undefined
}
/**
* Removes the trailing API version segment from a URL path.
*
* This function removes API version patterns (e.g., `/v1`, `/v2beta`) from the end of a URL.
* Only versions at the end of the path are removed, not versions in the middle.
*
* @param {string} url - The URL string to process.
* @returns {string} The URL with the trailing API version removed, or the original URL if no trailing version found.
*
* @example
* withoutTrailingApiVersion('https://api.example.com/v1') // 'https://api.example.com'
* withoutTrailingApiVersion('https://api.example.com/v2beta/') // 'https://api.example.com'
* withoutTrailingApiVersion('https://api.example.com/v1/chat') // 'https://api.example.com/v1/chat' (no change)
* withoutTrailingApiVersion('https://api.example.com') // 'https://api.example.com'
*/
export function withoutTrailingApiVersion(url: string): string {
return url.replace(TRAILING_VERSION_REGEX, '')
}

3925
yarn.lock

File diff suppressed because it is too large Load Diff