fix(antigravity): 只有 Gemini 模型支持 dummy thought signature

参考 Antigravity-Manager 的实现:
- 添加 allowDummyThought 参数,只有 gemini-* 模型才启用
- Claude 模型通过 Vertex API 需要有效的 thought signatures
- thinking block 保留原有 signature
- tool_use 只在 Gemini 模型时才使用 dummy signature
This commit is contained in:
song
2025-12-28 21:36:21 +08:00
parent ba9eb684ed
commit 635d7e77e1

View File

@@ -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
// 保留原有 signatureClaude 模型需要有效的 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)