diff --git a/src/renderer/src/aiCore/clients/anthropic/AnthropicAPIClient.ts b/src/renderer/src/aiCore/clients/anthropic/AnthropicAPIClient.ts index 73a5bb61c..e18b20889 100644 --- a/src/renderer/src/aiCore/clients/anthropic/AnthropicAPIClient.ts +++ b/src/renderer/src/aiCore/clients/anthropic/AnthropicAPIClient.ts @@ -524,9 +524,18 @@ export class AnthropicAPIClient extends BaseApiClient< switch (rawChunk.type) { case 'message': { let i = 0 + let hasTextContent = false + let hasThinkingContent = false + for (const content of rawChunk.content) { switch (content.type) { case 'text': { + if (!hasTextContent) { + controller.enqueue({ + type: ChunkType.TEXT_START + } as TextStartChunk) + hasTextContent = true + } controller.enqueue({ type: ChunkType.TEXT_DELTA, text: content.text @@ -539,6 +548,12 @@ export class AnthropicAPIClient extends BaseApiClient< break } case 'thinking': { + if (!hasThinkingContent) { + controller.enqueue({ + type: ChunkType.THINKING_START + } as ThinkingStartChunk) + hasThinkingContent = true + } controller.enqueue({ type: ChunkType.THINKING_DELTA, text: content.thinking diff --git a/src/renderer/src/aiCore/clients/openai/OpenAIApiClient.ts b/src/renderer/src/aiCore/clients/openai/OpenAIApiClient.ts index b08f179fb..393e8733d 100644 --- a/src/renderer/src/aiCore/clients/openai/OpenAIApiClient.ts +++ b/src/renderer/src/aiCore/clients/openai/OpenAIApiClient.ts @@ -5,6 +5,7 @@ import { GEMINI_FLASH_MODEL_REGEX, getOpenAIWebSearchParams, isDoubaoThinkingAutoModel, + isQwenReasoningModel, isReasoningModel, isSupportedReasoningEffortGrokModel, isSupportedReasoningEffortModel, @@ -166,10 +167,17 @@ export class OpenAIAPIClient extends OpenAIBaseClient< // Qwen models if (isSupportedThinkingTokenQwenModel(model)) { - return { + const thinkConfig = { enable_thinking: true, thinking_budget: budgetTokens } + if (this.provider.id === 'dashscope') { + return { + ...thinkConfig, + incremental_output: true + } + } + return thinkConfig } // Grok models @@ -436,7 +444,14 @@ export class OpenAIAPIClient extends OpenAIBaseClient< messages: OpenAISdkMessageParam[] metadata: Record }> => { - const { messages, mcpTools, maxTokens, streamOutput, enableWebSearch } = coreRequest + const { messages, mcpTools, maxTokens, enableWebSearch } = coreRequest + let { streamOutput } = coreRequest + + // Qwen3商业版(思考模式)、Qwen3开源版、QwQ、QVQ只支持流式输出。 + if (isQwenReasoningModel(model)) { + streamOutput = true + } + // 1. 处理系统消息 let systemMessage = { role: 'system', content: assistant.prompt || '' } diff --git a/src/renderer/src/store/thunk/messageThunk.ts b/src/renderer/src/store/thunk/messageThunk.ts index 1cd98aa31..ad2e63e55 100644 --- a/src/renderer/src/store/thunk/messageThunk.ts +++ b/src/renderer/src/store/thunk/messageThunk.ts @@ -446,7 +446,7 @@ const fetchAndProcessAssistantResponseImpl = async ( content: accumulatedContent, status: MessageBlockStatus.STREAMING } - smartBlockUpdate(initialPlaceholderBlockId, changes, MessageBlockType.MAIN_TEXT) + smartBlockUpdate(initialPlaceholderBlockId, changes, MessageBlockType.MAIN_TEXT, true) mainTextBlockId = initialPlaceholderBlockId initialPlaceholderBlockId = null } else if (!mainTextBlockId) { @@ -496,7 +496,7 @@ const fetchAndProcessAssistantResponseImpl = async ( } thinkingBlockId = initialPlaceholderBlockId initialPlaceholderBlockId = null - smartBlockUpdate(thinkingBlockId, changes, MessageBlockType.THINKING) + smartBlockUpdate(thinkingBlockId, changes, MessageBlockType.THINKING, true) } else if (!thinkingBlockId) { const newBlock = createThinkingBlock(assistantMsgId, accumulatedThinking, { status: MessageBlockStatus.STREAMING, diff --git a/src/renderer/src/types/sdk.ts b/src/renderer/src/types/sdk.ts index ae7d823d4..1eaf74d86 100644 --- a/src/renderer/src/types/sdk.ts +++ b/src/renderer/src/types/sdk.ts @@ -54,6 +54,7 @@ export type ReasoningEffortOptionalParams = { reasoning_effort?: OpenAI.Chat.Completions.ChatCompletionCreateParams['reasoning_effort'] | 'none' | 'auto' enable_thinking?: boolean thinking_budget?: number + incremental_output?: boolean enable_reasoning?: boolean extra_body?: Record // Add any other potential reasoning-related keys here if they exist