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:
@@ -16,8 +16,12 @@ func TransformClaudeToGemini(claudeReq *ClaudeRequest, projectID, mappedModel st
|
|||||||
// 检测是否启用 thinking
|
// 检测是否启用 thinking
|
||||||
isThinkingEnabled := claudeReq.Thinking != nil && claudeReq.Thinking.Type == "enabled"
|
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
|
// 1. 构建 contents
|
||||||
contents, err := buildContents(claudeReq.Messages, toolIDToName, isThinkingEnabled)
|
contents, err := buildContents(claudeReq.Messages, toolIDToName, isThinkingEnabled, allowDummyThought)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("build contents: %w", err)
|
return nil, fmt.Errorf("build contents: %w", err)
|
||||||
}
|
}
|
||||||
@@ -115,7 +119,7 @@ func buildSystemInstruction(system json.RawMessage, modelName string) *GeminiCon
|
|||||||
}
|
}
|
||||||
|
|
||||||
// buildContents 构建 contents
|
// 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
|
var contents []GeminiContent
|
||||||
|
|
||||||
for i, msg := range messages {
|
for i, msg := range messages {
|
||||||
@@ -124,13 +128,15 @@ func buildContents(messages []ClaudeMessage, toolIDToName map[string]string, isT
|
|||||||
role = "model"
|
role = "model"
|
||||||
}
|
}
|
||||||
|
|
||||||
parts, err := buildParts(msg.Content, toolIDToName, isThinkingEnabled)
|
parts, err := buildParts(msg.Content, toolIDToName, allowDummyThought)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("build parts for message %d: %w", i, err)
|
return nil, fmt.Errorf("build parts for message %d: %w", i, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果 thinking 开启且是最后一条 assistant 消息,需要检查是否需要添加 dummy thinking
|
// 只有 Gemini 模型支持 dummy thinking block workaround
|
||||||
if role == "model" && isThinkingEnabled && i == len(messages)-1 {
|
// 只对最后一条 assistant 消息添加(Pre-fill 场景)
|
||||||
|
// 历史 assistant 消息不能添加没有 signature 的 dummy thinking block
|
||||||
|
if allowDummyThought && role == "model" && isThinkingEnabled && i == len(messages)-1 {
|
||||||
hasThoughtPart := false
|
hasThoughtPart := false
|
||||||
for _, p := range parts {
|
for _, p := range parts {
|
||||||
if p.Thought {
|
if p.Thought {
|
||||||
@@ -139,11 +145,10 @@ func buildContents(messages []ClaudeMessage, toolIDToName map[string]string, isT
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !hasThoughtPart && len(parts) > 0 {
|
if !hasThoughtPart && len(parts) > 0 {
|
||||||
// 在开头添加 dummy thinking block(需要 signature)
|
// 在开头添加 dummy thinking block
|
||||||
parts = append([]GeminiPart{{
|
parts = append([]GeminiPart{{
|
||||||
Text: "Thinking...",
|
Text: "Thinking...",
|
||||||
Thought: true,
|
Thought: true,
|
||||||
ThoughtSignature: dummyThoughtSignature,
|
|
||||||
}}, parts...)
|
}}, parts...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -166,7 +171,8 @@ func buildContents(messages []ClaudeMessage, toolIDToName map[string]string, isT
|
|||||||
const dummyThoughtSignature = "skip_thought_signature_validator"
|
const dummyThoughtSignature = "skip_thought_signature_validator"
|
||||||
|
|
||||||
// buildParts 构建消息的 parts
|
// 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
|
var parts []GeminiPart
|
||||||
|
|
||||||
// 尝试解析为字符串
|
// 尝试解析为字符串
|
||||||
@@ -196,10 +202,9 @@ func buildParts(content json.RawMessage, toolIDToName map[string]string, isThink
|
|||||||
Text: block.Thinking,
|
Text: block.Thinking,
|
||||||
Thought: true,
|
Thought: true,
|
||||||
}
|
}
|
||||||
// 历史 thinking block 的 signature 可能已过期,统一使用 dummy signature
|
// 保留原有 signature(Claude 模型需要有效的 signature)
|
||||||
// 参考: https://ai.google.dev/gemini-api/docs/thought-signatures
|
if block.Signature != "" {
|
||||||
if isThinkingEnabled {
|
part.ThoughtSignature = block.Signature
|
||||||
part.ThoughtSignature = dummyThoughtSignature
|
|
||||||
}
|
}
|
||||||
parts = append(parts, part)
|
parts = append(parts, part)
|
||||||
|
|
||||||
@@ -219,14 +224,18 @@ func buildParts(content json.RawMessage, toolIDToName map[string]string, isThink
|
|||||||
toolIDToName[block.ID] = block.Name
|
toolIDToName[block.ID] = block.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
// 与 proxycast 保持一致:function_call 无条件添加 thought_signature
|
|
||||||
part := GeminiPart{
|
part := GeminiPart{
|
||||||
FunctionCall: &GeminiFunctionCall{
|
FunctionCall: &GeminiFunctionCall{
|
||||||
Name: block.Name,
|
Name: block.Name,
|
||||||
Args: block.Input,
|
Args: block.Input,
|
||||||
ID: block.ID,
|
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)
|
parts = append(parts, part)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user