chore: update release notes and version to 1.6.0-beta.6

- Refined performance optimizations for AI services and improved compatibility with various providers.
- Enhanced error handling and stability in the ModernAiProvider class.
- Updated version in package.json to 1.6.0-beta.6.
This commit is contained in:
MyPrototypeWhat 2025-09-03 17:10:41 +08:00
parent 976d246cac
commit 01c4777691
5 changed files with 62 additions and 40 deletions

View File

@ -121,26 +121,12 @@ afterSign: scripts/notarize.js
artifactBuildCompleted: scripts/artifact-build-completed.js artifactBuildCompleted: scripts/artifact-build-completed.js
releaseInfo: releaseInfo:
releaseNotes: | releaseNotes: |
✨ 重要更新:
- 增强Web搜索功能重构搜索结果处理和展示逻辑
- 优化知识库设置:默认关闭知识识别以提升性能
- 新增Gemini 2.5 Flash Image模型的自动图像生成功能
- 支持链接OG数据解析和预览展示
- 增强OCR服务的Linux兼容性
🔧 性能优化: 🔧 性能优化:
- 重构AI核心架构采用现代化的AI SDK 5.0 - 优化AI服务连接方式提升响应速度和稳定性
- 优化消息重试机制,新增"重试失败消息"按钮 - 改进模型列表获取功能,减少不必要的网络请求
- 改进侧边栏动画效果和用户交互体验 - 增强各AI服务商的兼容性和连接可靠性
- 优化Vite构建系统使用Rolldown引擎提升构建性能
- 重构参数处理和文件处理模块
- 优化API key轮转机制
🐛 修复问题: 🐛 问题修复:
- 修复tabs组件高度不足导致边框样式问题 - 修复部分AI服务商连接失败的问题
- 修复Gemini 2.5 Flash Image模型的图像生成按钮状态 - 修复模型配置加载时的潜在错误
- 修复ModelScope DeepSeek v3.1思考模式问题 - 提升应用整体稳定性和容错能力
- 修复PoeLogo在provider UI组件中的渲染问题
- 修复ASAR集成相关问题
- 移除加载状态阻塞输入的问题
- 修复多个UI组件和样式问题

View File

@ -1,6 +1,6 @@
{ {
"name": "CherryStudio", "name": "CherryStudio",
"version": "1.6.0-beta.5", "version": "1.6.0-beta.6",
"private": true, "private": true,
"description": "A powerful AI assistant for producer.", "description": "A powerful AI assistant for producer.",
"main": "./out/main/index.js", "main": "./out/main/index.js",

View File

@ -42,18 +42,36 @@ export type ModernAiProviderConfig = AiSdkMiddlewareConfig & {
export default class ModernAiProvider { export default class ModernAiProvider {
private legacyProvider: LegacyAiProvider private legacyProvider: LegacyAiProvider
private config: ReturnType<typeof providerToAiSdkConfig> private config?: ReturnType<typeof providerToAiSdkConfig>
private actualProvider: Provider private actualProvider: Provider
private model: Model private model?: Model
private localProvider: Awaited<AiSdkProvider> | null = null private localProvider: Awaited<AiSdkProvider> | null = null
constructor(model: Model, provider?: Provider) { // 构造函数重载签名
this.actualProvider = provider || getActualProvider(model) constructor(model: Model, provider?: Provider)
this.legacyProvider = new LegacyAiProvider(this.actualProvider) constructor(provider: Provider)
this.model = model constructor(modelOrProvider: Model | Provider, provider?: Provider)
constructor(modelOrProvider: Model | Provider, provider?: Provider) {
if (this.isModel(modelOrProvider)) {
// 传入的是 Model
this.model = modelOrProvider
this.actualProvider = provider || getActualProvider(modelOrProvider)
// 只保存配置不预先创建executor
this.config = providerToAiSdkConfig(this.actualProvider, modelOrProvider)
} else {
// 传入的是 Provider
this.actualProvider = modelOrProvider
// model为可选某些操作如fetchModels不需要model
}
// 只保存配置不预先创建executor this.legacyProvider = new LegacyAiProvider(this.actualProvider)
this.config = providerToAiSdkConfig(this.actualProvider, model) }
/**
* provider Model Provider
*/
private isModel(obj: Model | Provider): obj is Model {
return 'provider' in obj && typeof obj.provider === 'string'
} }
public getActualProvider() { public getActualProvider() {
@ -61,6 +79,16 @@ export default class ModernAiProvider {
} }
public async completions(modelId: string, params: StreamTextParams, config: ModernAiProviderConfig) { public async completions(modelId: string, params: StreamTextParams, config: ModernAiProviderConfig) {
// 检查model是否存在
if (!this.model) {
throw new Error('Model is required for completions. Please use constructor with model parameter.')
}
// 确保配置存在
if (!this.config) {
this.config = providerToAiSdkConfig(this.actualProvider, this.model)
}
// 准备特殊配置 // 准备特殊配置
await prepareSpecialProviderConfig(this.actualProvider, this.config) await prepareSpecialProviderConfig(this.actualProvider, this.config)
@ -127,7 +155,7 @@ export default class ModernAiProvider {
params: StreamTextParams, params: StreamTextParams,
config: ModernAiProviderConfig & { topicId: string } config: ModernAiProviderConfig & { topicId: string }
): Promise<CompletionsResult> { ): Promise<CompletionsResult> {
const modelId = this.model.id const modelId = this.model!.id
const traceName = `${this.actualProvider.name}.${modelId}.${config.callType}` const traceName = `${this.actualProvider.name}.${modelId}.${config.callType}`
const traceParams: StartSpanParams = { const traceParams: StartSpanParams = {
name: traceName, name: traceName,
@ -211,10 +239,10 @@ export default class ModernAiProvider {
params: StreamTextParams, params: StreamTextParams,
config: ModernAiProviderConfig config: ModernAiProviderConfig
): Promise<CompletionsResult> { ): Promise<CompletionsResult> {
const modelId = this.model.id const modelId = this.model!.id
logger.info('Starting modernCompletions', { logger.info('Starting modernCompletions', {
modelId, modelId,
providerId: this.config.providerId, providerId: this.config!.providerId,
topicId: config.topicId, topicId: config.topicId,
hasOnChunk: !!config.onChunk, hasOnChunk: !!config.onChunk,
hasTools: !!params.tools && Object.keys(params.tools).length > 0, hasTools: !!params.tools && Object.keys(params.tools).length > 0,
@ -225,11 +253,11 @@ export default class ModernAiProvider {
const plugins = buildPlugins(config) const plugins = buildPlugins(config)
// 用构建好的插件数组创建executor // 用构建好的插件数组创建executor
const executor = createExecutor(this.config.providerId, this.config.options, plugins) const executor = createExecutor(this.config!.providerId, this.config!.options, plugins)
// 创建带有中间件的执行器 // 创建带有中间件的执行器
if (config.onChunk) { if (config.onChunk) {
const accumulate = this.model.supported_text_delta !== false // true and undefined const accumulate = this.model!.supported_text_delta !== false // true and undefined
const adapter = new AiSdkToChunkAdapter(config.onChunk, config.mcpTools, accumulate) const adapter = new AiSdkToChunkAdapter(config.onChunk, config.mcpTools, accumulate)
const streamResult = await executor.streamText({ const streamResult = await executor.streamText({
@ -308,7 +336,7 @@ export default class ModernAiProvider {
} }
// 调用新 AI SDK 的图像生成功能 // 调用新 AI SDK 的图像生成功能
const executor = createExecutor(this.config.providerId, this.config.options, []) const executor = createExecutor(this.config!.providerId, this.config!.options, [])
const result = await executor.generateImage({ const result = await executor.generateImage({
model, model,
...imageParams ...imageParams
@ -428,7 +456,7 @@ export default class ModernAiProvider {
...(signal && { abortSignal: signal }) ...(signal && { abortSignal: signal })
} }
const executor = createExecutor(this.config.providerId, this.config.options, []) const executor = createExecutor(this.config!.providerId, this.config!.options, [])
const result = await executor.generateImage({ const result = await executor.generateImage({
model: this.localProvider?.imageModel(model) as ImageModel, model: this.localProvider?.imageModel(model) as ImageModel,
...aiSdkParams ...aiSdkParams

View File

@ -131,12 +131,21 @@ export function providerToAiSdkConfig(
// 添加额外headers // 添加额外headers
if (actualProvider.extra_headers) { if (actualProvider.extra_headers) {
extraOptions.headers = actualProvider.extra_headers extraOptions.headers = actualProvider.extra_headers
// copy from openaiBaseClient/openaiResponseApiClient
if (aiSdkProviderId === 'openai') {
extraOptions.headers = {
...extraOptions.headers,
'HTTP-Referer': 'https://cherry-ai.com',
'X-Title': 'Cherry Studio',
'X-Api-Key': baseConfig.apiKey
}
}
} }
// copilot // copilot
if (actualProvider.id === 'copilot') { if (actualProvider.id === 'copilot') {
extraOptions.headers = { extraOptions.headers = {
...extraOptions.extra_headers, ...extraOptions.headers,
'editor-version': 'vscode/1.97.2', 'editor-version': 'vscode/1.97.2',
'copilot-vision-request': 'true' 'copilot-vision-request': 'true'
} }
@ -183,7 +192,6 @@ export function providerToAiSdkConfig(
} else if (baseConfig.baseURL.endsWith('/v1')) { } else if (baseConfig.baseURL.endsWith('/v1')) {
baseConfig.baseURL = baseConfig.baseURL.slice(0, -3) baseConfig.baseURL = baseConfig.baseURL.slice(0, -3)
} }
baseConfig.baseURL = isEmpty(baseConfig.baseURL) ? '' : baseConfig.baseURL baseConfig.baseURL = isEmpty(baseConfig.baseURL) ? '' : baseConfig.baseURL
} }

View File

@ -350,7 +350,7 @@ export function hasApiKey(provider: Provider) {
// } // }
export async function fetchModels(provider: Provider): Promise<SdkModel[]> { export async function fetchModels(provider: Provider): Promise<SdkModel[]> {
const AI = new AiProviderNew({} as Model, provider) const AI = new AiProviderNew(provider)
try { try {
return await AI.models() return await AI.models()