revert(antigravity): 恢复 Claude 模型 thinking 功能
还原 b6d1e7a 中错误禁用 Claude thinking 的逻辑:
- 移除 isThinkingEnabled 对 allowDummyThought 的依赖
- 移除非 Gemini 模型时清除 Thinking 配置的代码
- 恢复 buildParts 中 thinking block 的原始处理逻辑
- 移除不再使用的 isValidThoughtSignature 函数
This commit is contained in:
@@ -14,16 +14,13 @@ func TransformClaudeToGemini(claudeReq *ClaudeRequest, projectID, mappedModel st
|
|||||||
// 用于存储 tool_use id -> name 映射
|
// 用于存储 tool_use id -> name 映射
|
||||||
toolIDToName := make(map[string]string)
|
toolIDToName := make(map[string]string)
|
||||||
|
|
||||||
|
// 检测是否启用 thinking
|
||||||
|
isThinkingEnabled := claudeReq.Thinking != nil && claudeReq.Thinking.Type == "enabled"
|
||||||
|
|
||||||
// 只有 Gemini 模型支持 dummy thought workaround
|
// 只有 Gemini 模型支持 dummy thought workaround
|
||||||
// Claude 模型通过 Vertex/Google API 需要有效的 thought signatures
|
// Claude 模型通过 Vertex/Google API 需要有效的 thought signatures
|
||||||
allowDummyThought := strings.HasPrefix(mappedModel, "gemini-")
|
allowDummyThought := strings.HasPrefix(mappedModel, "gemini-")
|
||||||
|
|
||||||
// 检测是否启用 thinking
|
|
||||||
requestedThinkingEnabled := claudeReq.Thinking != nil && claudeReq.Thinking.Type == "enabled"
|
|
||||||
// 为避免 Claude 模型的 thought signature/消息块约束导致 400(上游要求 thinking 块开头等),
|
|
||||||
// 非 Gemini 模型默认不启用 thinking(除非未来支持完整签名链路)。
|
|
||||||
isThinkingEnabled := requestedThinkingEnabled && allowDummyThought
|
|
||||||
|
|
||||||
// 1. 构建 contents
|
// 1. 构建 contents
|
||||||
contents, err := buildContents(claudeReq.Messages, toolIDToName, isThinkingEnabled, allowDummyThought)
|
contents, err := buildContents(claudeReq.Messages, toolIDToName, isThinkingEnabled, allowDummyThought)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -34,15 +31,7 @@ func TransformClaudeToGemini(claudeReq *ClaudeRequest, projectID, mappedModel st
|
|||||||
systemInstruction := buildSystemInstruction(claudeReq.System, claudeReq.Model)
|
systemInstruction := buildSystemInstruction(claudeReq.System, claudeReq.Model)
|
||||||
|
|
||||||
// 3. 构建 generationConfig
|
// 3. 构建 generationConfig
|
||||||
reqForGen := claudeReq
|
generationConfig := buildGenerationConfig(claudeReq)
|
||||||
if requestedThinkingEnabled && !allowDummyThought {
|
|
||||||
log.Printf("[Warning] Disabling thinking for non-Gemini model in antigravity transform: model=%s", mappedModel)
|
|
||||||
// shallow copy to avoid mutating caller's request
|
|
||||||
clone := *claudeReq
|
|
||||||
clone.Thinking = nil
|
|
||||||
reqForGen = &clone
|
|
||||||
}
|
|
||||||
generationConfig := buildGenerationConfig(reqForGen)
|
|
||||||
|
|
||||||
// 4. 构建 tools
|
// 4. 构建 tools
|
||||||
tools := buildTools(claudeReq.Tools)
|
tools := buildTools(claudeReq.Tools)
|
||||||
@@ -183,34 +172,6 @@ func buildContents(messages []ClaudeMessage, toolIDToName map[string]string, isT
|
|||||||
// 参考: https://ai.google.dev/gemini-api/docs/thought-signatures
|
// 参考: https://ai.google.dev/gemini-api/docs/thought-signatures
|
||||||
const dummyThoughtSignature = "skip_thought_signature_validator"
|
const dummyThoughtSignature = "skip_thought_signature_validator"
|
||||||
|
|
||||||
// isValidThoughtSignature 验证 thought signature 是否有效
|
|
||||||
// Claude API 要求 signature 必须是 base64 编码的字符串,长度至少 32 字节
|
|
||||||
func isValidThoughtSignature(signature string) bool {
|
|
||||||
// 空字符串无效
|
|
||||||
if signature == "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// signature 应该是 base64 编码,长度至少 40 个字符(约 30 字节)
|
|
||||||
// 参考 Claude API 文档和实际观察到的有效 signature
|
|
||||||
if len(signature) < 40 {
|
|
||||||
log.Printf("[Debug] Signature too short: len=%d", len(signature))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查是否是有效的 base64 字符
|
|
||||||
// base64 字符集: A-Z, a-z, 0-9, +, /, =
|
|
||||||
for i, c := range signature {
|
|
||||||
if (c < 'A' || c > 'Z') && (c < 'a' || c > 'z') &&
|
|
||||||
(c < '0' || c > '9') && c != '+' && c != '/' && c != '=' {
|
|
||||||
log.Printf("[Debug] Invalid base64 character at position %d: %c (code=%d)", i, c, c)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// buildParts 构建消息的 parts
|
// buildParts 构建消息的 parts
|
||||||
// allowDummyThought: 只有 Gemini 模型支持 dummy thought signature
|
// allowDummyThought: 只有 Gemini 模型支持 dummy thought signature
|
||||||
func buildParts(content json.RawMessage, toolIDToName map[string]string, allowDummyThought bool) ([]GeminiPart, error) {
|
func buildParts(content json.RawMessage, toolIDToName map[string]string, allowDummyThought bool) ([]GeminiPart, error) {
|
||||||
@@ -239,30 +200,22 @@ func buildParts(content json.RawMessage, toolIDToName map[string]string, allowDu
|
|||||||
}
|
}
|
||||||
|
|
||||||
case "thinking":
|
case "thinking":
|
||||||
if allowDummyThought {
|
part := GeminiPart{
|
||||||
// Gemini 模型可以使用 dummy signature
|
Text: block.Thinking,
|
||||||
parts = append(parts, GeminiPart{
|
Thought: true,
|
||||||
Text: block.Thinking,
|
}
|
||||||
Thought: true,
|
// 保留原有 signature(Claude 模型需要有效的 signature)
|
||||||
ThoughtSignature: dummyThoughtSignature,
|
if block.Signature != "" {
|
||||||
})
|
part.ThoughtSignature = block.Signature
|
||||||
|
} else if !allowDummyThought {
|
||||||
|
// Claude 模型需要有效 signature,跳过无 signature 的 thinking block
|
||||||
|
log.Printf("Warning: skipping thinking block without signature for Claude model")
|
||||||
continue
|
continue
|
||||||
|
} else {
|
||||||
|
// Gemini 模型使用 dummy signature
|
||||||
|
part.ThoughtSignature = dummyThoughtSignature
|
||||||
}
|
}
|
||||||
|
parts = append(parts, part)
|
||||||
// Claude 模型:仅在提供有效 signature 时保留 thinking block;否则跳过以避免上游校验失败。
|
|
||||||
signature := strings.TrimSpace(block.Signature)
|
|
||||||
if signature == "" || signature == dummyThoughtSignature {
|
|
||||||
log.Printf("[Warning] Skipping thinking block for Claude model (missing or dummy signature)")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !isValidThoughtSignature(signature) {
|
|
||||||
log.Printf("[Debug] Thinking signature may be invalid (passing through anyway): len=%d", len(signature))
|
|
||||||
}
|
|
||||||
parts = append(parts, GeminiPart{
|
|
||||||
Text: block.Thinking,
|
|
||||||
Thought: true,
|
|
||||||
ThoughtSignature: signature,
|
|
||||||
})
|
|
||||||
|
|
||||||
case "image":
|
case "image":
|
||||||
if block.Source != nil && block.Source.Type == "base64" {
|
if block.Source != nil && block.Source.Type == "base64" {
|
||||||
|
|||||||
Reference in New Issue
Block a user