From 6eee878574dbb0d88a451fc36016a5b6f58b3f70 Mon Sep 17 00:00:00 2001 From: hex2077 Date: Sun, 29 Mar 2026 20:40:45 +0800 Subject: [PATCH] =?UTF-8?q?fix(gemini):=20=E7=A1=AE=E4=BF=9D=E8=AF=B7?= =?UTF-8?q?=E6=B1=82thinking=E6=97=B6=E5=A7=8B=E7=BB=88=E5=8C=85=E5=90=ABi?= =?UTF-8?q?ncludeThoughts=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 当上游请求gemini-3的thinking功能时,可能未显式设置includeThoughts字段, 导致无法稳定接收thought parts。添加兜底逻辑,在检测到thinkingLevel或 thinkingBudget非零时自动设置includeThoughts=true,确保思考功能正常工作。 --- VERSION | 2 +- src/providers/gemini/antigravity-core.js | 11 ++++++ src/providers/gemini/gemini-core.js | 44 ++++++++++++++++++++++-- 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/VERSION b/VERSION index d8b6989..3cf561c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.12.0 +2.12.1 diff --git a/src/providers/gemini/antigravity-core.js b/src/providers/gemini/antigravity-core.js index 2cd0fd6..3b34ba0 100644 --- a/src/providers/gemini/antigravity-core.js +++ b/src/providers/gemini/antigravity-core.js @@ -183,7 +183,18 @@ function normalizeAntigravityThinking(modelName, payload, isClaudeModel) { const thinkingConfig = payload?.request?.generationConfig?.thinkingConfig; if (!thinkingConfig) return payload; + const thinkingLevel = thinkingConfig.thinkingLevel; const budget = thinkingConfig.thinkingBudget; + const thinkingRequested = + thinkingLevel !== undefined || + (budget !== undefined && budget !== 0); + + // Antigravity 只有在 includeThoughts=true 时才会回传 thought parts。 + // 上游对 gemini-3 thinkingLevel 的请求不一定会显式带上这个字段,这里兜底补齐。 + if (thinkingRequested && thinkingConfig.includeThoughts === undefined) { + thinkingConfig.includeThoughts = true; + } + if (budget === undefined) return payload; let normalizedBudget = normalizeThinkingBudget(modelName, budget); diff --git a/src/providers/gemini/gemini-core.js b/src/providers/gemini/gemini-core.js index 7a497ca..0033cbf 100644 --- a/src/providers/gemini/gemini-core.js +++ b/src/providers/gemini/gemini-core.js @@ -102,6 +102,35 @@ function extract_model_from_anti_model(model) { return model; // 如果不是anti-前缀或不在原模型列表中,则返回原模型名 } +function modelSupportsThinking(modelName) { + if (!modelName) return false; + const name = String(modelName).toLowerCase(); + return name.startsWith('gemini-3') || + name.startsWith('gemini-2.5-') || + name.includes('-thinking'); +} + +function normalizeGeminiThinkingRequest(modelName, requestBody) { + if (!modelSupportsThinking(modelName)) return requestBody; + + const thinkingConfig = requestBody?.generationConfig?.thinkingConfig; + if (!thinkingConfig) return requestBody; + + const thinkingLevel = thinkingConfig.thinkingLevel; + const budget = thinkingConfig.thinkingBudget; + const thinkingRequested = + thinkingLevel !== undefined || + (budget !== undefined && budget !== 0); + + // Gemini 只有在 includeThoughts=true 时才会稳定返回 thought parts。 + // 上游在 gemini-3 thinkingLevel 场景下可能没有显式传这个字段,这里兜底补齐。 + if (thinkingRequested && thinkingConfig.includeThoughts === undefined) { + thinkingConfig.includeThoughts = true; + } + + return requestBody; +} + function toGeminiApiResponse(codeAssistResponse) { if (!codeAssistResponse) return null; const compliantResponse = { candidates: codeAssistResponse.candidates }; @@ -740,7 +769,10 @@ export class GeminiApiService { baseModel = GEMINI_MODELS[0]; } - const processedRequestBody = ensureRolesInContents({ ...requestBody }); + const processedRequestBody = normalizeGeminiThinkingRequest( + baseModel, + ensureRolesInContents({ ...requestBody }) + ); const apiRequest = { model: baseModel, project: this.projectId, request: processedRequestBody }; const response = await this.callApi(API_ACTIONS.GENERATE_CONTENT, apiRequest, false, 0, baseModel); @@ -775,7 +807,10 @@ export class GeminiApiService { // 从防截断模型名中提取实际模型名 const actualModel = extract_model_from_anti_model(model); // 使用防截断流处理 - const processedRequestBody = ensureRolesInContents({ ...requestBody }); + const processedRequestBody = normalizeGeminiThinkingRequest( + actualModel, + ensureRolesInContents({ ...requestBody }) + ); yield* apply_anti_truncation_to_stream(this, actualModel, processedRequestBody); return; } @@ -786,7 +821,10 @@ export class GeminiApiService { baseModel = GEMINI_MODELS[0]; } - const processedRequestBody = ensureRolesInContents({ ...requestBody }); + const processedRequestBody = normalizeGeminiThinkingRequest( + baseModel, + ensureRolesInContents({ ...requestBody }) + ); const apiRequest = { model: baseModel, project: this.projectId, request: processedRequestBody }; const stream = this.streamApi(API_ACTIONS.STREAM_GENERATE_CONTENT, apiRequest, false, 0, baseModel);