From 97a63ea5b2959f3a4a63744a5cf0ba79d345e80d Mon Sep 17 00:00:00 2001 From: Phantom <59059173+EurFelux@users.noreply.github.com> Date: Fri, 8 Aug 2025 16:58:31 +0800 Subject: [PATCH] fix: user custom params should always overwrite other params (#8907) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(aws-bedrock): 未支持自定义参数 * refactor(AnthropicAPIClient): 简化消息创建参数逻辑 移除不必要的MessageCreateParams类型,直接在commonParams中设置stream参数 * refactor(openai): 简化API客户端参数处理逻辑 移除冗余的stream参数分支逻辑,直接在commonParams中设置stream相关参数 * docs(aiCore): 添加注释说明用户自定义参数应覆盖其他参数 * feat(openai): 添加流式输出选项支持 当流式输出启用且提供者支持时,包含stream_options以包含使用情况信息 * fix(openai): 移除冗余的逻辑判断 --- .../clients/anthropic/AnthropicAPIClient.ts | 15 ++-------- .../aiCore/clients/aws/AwsBedrockAPIClient.ts | 5 +++- .../aiCore/clients/gemini/GeminiAPIClient.ts | 1 + .../aiCore/clients/openai/OpenAIApiClient.ts | 30 +++++++------------ .../clients/openai/OpenAIResponseAPIClient.ts | 18 +++++------ 5 files changed, 26 insertions(+), 43 deletions(-) diff --git a/src/renderer/src/aiCore/clients/anthropic/AnthropicAPIClient.ts b/src/renderer/src/aiCore/clients/anthropic/AnthropicAPIClient.ts index 5157eb95c8..f286b40d59 100644 --- a/src/renderer/src/aiCore/clients/anthropic/AnthropicAPIClient.ts +++ b/src/renderer/src/aiCore/clients/anthropic/AnthropicAPIClient.ts @@ -11,7 +11,6 @@ import { import { ContentBlock, ContentBlockParam, - MessageCreateParams, MessageCreateParamsBase, RedactedThinkingBlockParam, ServerToolUseBlockParam, @@ -495,22 +494,14 @@ export class AnthropicAPIClient extends BaseApiClient< system: systemMessage ? [systemMessage] : undefined, thinking: this.getBudgetToken(assistant, model), tools: tools.length > 0 ? tools : undefined, + stream: streamOutput, // 只在对话场景下应用自定义参数,避免影响翻译、总结等其他业务逻辑 + // 注意:用户自定义参数总是应该覆盖其他参数 ...(coreRequest.callType === 'chat' ? this.getCustomParameters(assistant) : {}) } - const finalParams: MessageCreateParams = streamOutput - ? { - ...commonParams, - stream: true - } - : { - ...commonParams, - stream: false - } - const timeout = this.getTimeout(model) - return { payload: finalParams, messages: sdkMessages, metadata: { timeout } } + return { payload: commonParams, messages: sdkMessages, metadata: { timeout } } } } } diff --git a/src/renderer/src/aiCore/clients/aws/AwsBedrockAPIClient.ts b/src/renderer/src/aiCore/clients/aws/AwsBedrockAPIClient.ts index 678c0c5f05..de9c7c2c17 100644 --- a/src/renderer/src/aiCore/clients/aws/AwsBedrockAPIClient.ts +++ b/src/renderer/src/aiCore/clients/aws/AwsBedrockAPIClient.ts @@ -418,7 +418,10 @@ export class AwsBedrockAPIClient extends BaseApiClient< temperature: this.getTemperature(assistant, model), topP: this.getTopP(assistant, model), stream: streamOutput !== false, - tools: tools.length > 0 ? tools : undefined + tools: tools.length > 0 ? tools : undefined, + // 只在对话场景下应用自定义参数,避免影响翻译、总结等其他业务逻辑 + // 注意:用户自定义参数总是应该覆盖其他参数 + ...(coreRequest.callType === 'chat' ? this.getCustomParameters(assistant) : {}) } const timeout = this.getTimeout(model) diff --git a/src/renderer/src/aiCore/clients/gemini/GeminiAPIClient.ts b/src/renderer/src/aiCore/clients/gemini/GeminiAPIClient.ts index 7047298655..bdd7689d6f 100644 --- a/src/renderer/src/aiCore/clients/gemini/GeminiAPIClient.ts +++ b/src/renderer/src/aiCore/clients/gemini/GeminiAPIClient.ts @@ -532,6 +532,7 @@ export class GeminiAPIClient extends BaseApiClient< ...(enableGenerateImage ? this.getGenerateImageParameter() : {}), ...this.getBudgetToken(assistant, model), // 只在对话场景下应用自定义参数,避免影响翻译、总结等其他业务逻辑 + // 注意:用户自定义参数总是应该覆盖其他参数 ...(coreRequest.callType === 'chat' ? this.getCustomParameters(assistant) : {}) } diff --git a/src/renderer/src/aiCore/clients/openai/OpenAIApiClient.ts b/src/renderer/src/aiCore/clients/openai/OpenAIApiClient.ts index eac3741d1c..46e01d06d6 100644 --- a/src/renderer/src/aiCore/clients/openai/OpenAIApiClient.ts +++ b/src/renderer/src/aiCore/clients/openai/OpenAIApiClient.ts @@ -564,6 +564,10 @@ export class OpenAIAPIClient extends OpenAIBaseClient< reqMessages = processReqMessages(model, reqMessages) // 5. 创建通用参数 + // Create the appropriate parameters object based on whether streaming is enabled + // Note: Some providers like Mistral don't support stream_options + const shouldIncludeStreamOptions = streamOutput && isSupportStreamOptionsProvider(this.provider) + const commonParams: OpenAISdkParams = { model: model.id, messages: @@ -574,36 +578,24 @@ export class OpenAIAPIClient extends OpenAIBaseClient< top_p: this.getTopP(assistant, model), max_tokens: maxTokens, tools: tools.length > 0 ? tools : undefined, + stream: streamOutput, + ...(shouldIncludeStreamOptions ? { stream_options: { include_usage: true } } : {}), // groq 有不同的 service tier 配置,不符合 openai 接口类型 service_tier: this.getServiceTier(model) as OpenAIServiceTier, ...this.getProviderSpecificParameters(assistant, model), ...this.getReasoningEffort(assistant, model), ...getOpenAIWebSearchParams(model, enableWebSearch), - // 只在对话场景下应用自定义参数,避免影响翻译、总结等其他业务逻辑 - ...(coreRequest.callType === 'chat' ? this.getCustomParameters(assistant) : {}), // OpenRouter usage tracking ...(this.provider.id === 'openrouter' ? { usage: { include: true } } : {}), - ...(isQwenMTModel(model) ? extra_body : {}) + ...(isQwenMTModel(model) ? extra_body : {}), + // 只在对话场景下应用自定义参数,避免影响翻译、总结等其他业务逻辑 + // 注意:用户自定义参数总是应该覆盖其他参数 + ...(coreRequest.callType === 'chat' ? this.getCustomParameters(assistant) : {}) } - // Create the appropriate parameters object based on whether streaming is enabled - // Note: Some providers like Mistral don't support stream_options - const shouldIncludeStreamOptions = streamOutput && isSupportStreamOptionsProvider(this.provider) - - const sdkParams: OpenAISdkParams = streamOutput - ? { - ...commonParams, - stream: true, - ...(shouldIncludeStreamOptions ? { stream_options: { include_usage: true } } : {}) - } - : { - ...commonParams, - stream: false - } - const timeout = this.getTimeout(model) - return { payload: sdkParams, messages: reqMessages, metadata: { timeout } } + return { payload: commonParams, messages: reqMessages, metadata: { timeout } } } } } diff --git a/src/renderer/src/aiCore/clients/openai/OpenAIResponseAPIClient.ts b/src/renderer/src/aiCore/clients/openai/OpenAIResponseAPIClient.ts index de9ddafef8..f740c5bdcf 100644 --- a/src/renderer/src/aiCore/clients/openai/OpenAIResponseAPIClient.ts +++ b/src/renderer/src/aiCore/clients/openai/OpenAIResponseAPIClient.ts @@ -7,7 +7,7 @@ import { isSupportedReasoningEffortOpenAIModel, isVisionModel } from '@renderer/config/models' -import { isSupportDeveloperRoleProvider } from '@renderer/config/providers' +import { isSupportDeveloperRoleProvider, isSupportStreamOptionsProvider } from '@renderer/config/providers' import { estimateTextTokens } from '@renderer/services/TokenService' import { FileMetadata, @@ -441,6 +441,9 @@ export class OpenAIResponseAPIClient extends OpenAIBaseClient< } tools = tools.concat(extraTools) + + const shouldIncludeStreamOptions = streamOutput && isSupportStreamOptionsProvider(this.provider) + const commonParams: OpenAIResponseSdkParams = { model: model.id, input: @@ -451,24 +454,17 @@ export class OpenAIResponseAPIClient extends OpenAIBaseClient< top_p: this.getTopP(assistant, model), max_output_tokens: maxTokens, stream: streamOutput, + ...(shouldIncludeStreamOptions ? { stream_options: { include_usage: true } } : {}), tools: !isEmpty(tools) ? tools : undefined, // groq 有不同的 service tier 配置,不符合 openai 接口类型 service_tier: this.getServiceTier(model) as OpenAIServiceTier, ...(this.getReasoningEffort(assistant, model) as OpenAI.Reasoning), // 只在对话场景下应用自定义参数,避免影响翻译、总结等其他业务逻辑 + // 注意:用户自定义参数总是应该覆盖其他参数 ...(coreRequest.callType === 'chat' ? this.getCustomParameters(assistant) : {}) } - const sdkParams: OpenAIResponseSdkParams = streamOutput - ? { - ...commonParams, - stream: true - } - : { - ...commonParams, - stream: false - } const timeout = this.getTimeout(model) - return { payload: sdkParams, messages: reqMessages, metadata: { timeout } } + return { payload: commonParams, messages: reqMessages, metadata: { timeout } } } } }