From 635d7e77e1672452578934f6e23509cd221e241d Mon Sep 17 00:00:00 2001 From: song Date: Sun, 28 Dec 2025 21:36:21 +0800 Subject: [PATCH] =?UTF-8?q?fix(antigravity):=20=E5=8F=AA=E6=9C=89=20Gemini?= =?UTF-8?q?=20=E6=A8=A1=E5=9E=8B=E6=94=AF=E6=8C=81=20dummy=20thought=20sig?= =?UTF-8?q?nature?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 参考 Antigravity-Manager 的实现: - 添加 allowDummyThought 参数,只有 gemini-* 模型才启用 - Claude 模型通过 Vertex API 需要有效的 thought signatures - thinking block 保留原有 signature - tool_use 只在 Gemini 模型时才使用 dummy signature --- .../pkg/antigravity/request_transformer.go | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/backend/internal/pkg/antigravity/request_transformer.go b/backend/internal/pkg/antigravity/request_transformer.go index 25d54714..f72deb10 100644 --- a/backend/internal/pkg/antigravity/request_transformer.go +++ b/backend/internal/pkg/antigravity/request_transformer.go @@ -16,8 +16,12 @@ func TransformClaudeToGemini(claudeReq *ClaudeRequest, projectID, mappedModel st // 检测是否启用 thinking isThinkingEnabled := claudeReq.Thinking != nil && claudeReq.Thinking.Type == "enabled" + // 只有 Gemini 模型支持 dummy thought workaround + // Claude 模型通过 Vertex/Google API 需要有效的 thought signatures + allowDummyThought := strings.HasPrefix(mappedModel, "gemini-") + // 1. 构建 contents - contents, err := buildContents(claudeReq.Messages, toolIDToName, isThinkingEnabled) + contents, err := buildContents(claudeReq.Messages, toolIDToName, isThinkingEnabled, allowDummyThought) if err != nil { return nil, fmt.Errorf("build contents: %w", err) } @@ -115,7 +119,7 @@ func buildSystemInstruction(system json.RawMessage, modelName string) *GeminiCon } // buildContents 构建 contents -func buildContents(messages []ClaudeMessage, toolIDToName map[string]string, isThinkingEnabled bool) ([]GeminiContent, error) { +func buildContents(messages []ClaudeMessage, toolIDToName map[string]string, isThinkingEnabled, allowDummyThought bool) ([]GeminiContent, error) { var contents []GeminiContent for i, msg := range messages { @@ -124,13 +128,15 @@ func buildContents(messages []ClaudeMessage, toolIDToName map[string]string, isT role = "model" } - parts, err := buildParts(msg.Content, toolIDToName, isThinkingEnabled) + parts, err := buildParts(msg.Content, toolIDToName, allowDummyThought) if err != nil { return nil, fmt.Errorf("build parts for message %d: %w", i, err) } - // 如果 thinking 开启且是最后一条 assistant 消息,需要检查是否需要添加 dummy thinking - if role == "model" && isThinkingEnabled && i == len(messages)-1 { + // 只有 Gemini 模型支持 dummy thinking block workaround + // 只对最后一条 assistant 消息添加(Pre-fill 场景) + // 历史 assistant 消息不能添加没有 signature 的 dummy thinking block + if allowDummyThought && role == "model" && isThinkingEnabled && i == len(messages)-1 { hasThoughtPart := false for _, p := range parts { if p.Thought { @@ -139,11 +145,10 @@ func buildContents(messages []ClaudeMessage, toolIDToName map[string]string, isT } } if !hasThoughtPart && len(parts) > 0 { - // 在开头添加 dummy thinking block(需要 signature) + // 在开头添加 dummy thinking block parts = append([]GeminiPart{{ - Text: "Thinking...", - Thought: true, - ThoughtSignature: dummyThoughtSignature, + Text: "Thinking...", + Thought: true, }}, parts...) } } @@ -166,7 +171,8 @@ func buildContents(messages []ClaudeMessage, toolIDToName map[string]string, isT const dummyThoughtSignature = "skip_thought_signature_validator" // buildParts 构建消息的 parts -func buildParts(content json.RawMessage, toolIDToName map[string]string, isThinkingEnabled bool) ([]GeminiPart, error) { +// allowDummyThought: 只有 Gemini 模型支持 dummy thought signature +func buildParts(content json.RawMessage, toolIDToName map[string]string, allowDummyThought bool) ([]GeminiPart, error) { var parts []GeminiPart // 尝试解析为字符串 @@ -196,10 +202,9 @@ func buildParts(content json.RawMessage, toolIDToName map[string]string, isThink Text: block.Thinking, Thought: true, } - // 历史 thinking block 的 signature 可能已过期,统一使用 dummy signature - // 参考: https://ai.google.dev/gemini-api/docs/thought-signatures - if isThinkingEnabled { - part.ThoughtSignature = dummyThoughtSignature + // 保留原有 signature(Claude 模型需要有效的 signature) + if block.Signature != "" { + part.ThoughtSignature = block.Signature } parts = append(parts, part) @@ -219,14 +224,18 @@ func buildParts(content json.RawMessage, toolIDToName map[string]string, isThink toolIDToName[block.ID] = block.Name } - // 与 proxycast 保持一致:function_call 无条件添加 thought_signature part := GeminiPart{ FunctionCall: &GeminiFunctionCall{ Name: block.Name, Args: block.Input, ID: block.ID, }, - ThoughtSignature: dummyThoughtSignature, + } + // 保留原有 signature,或对 Gemini 模型使用 dummy signature + if block.Signature != "" { + part.ThoughtSignature = block.Signature + } else if allowDummyThought { + part.ThoughtSignature = dummyThoughtSignature } parts = append(parts, part)