diff --git a/backend/internal/pkg/antigravity/claude_types.go b/backend/internal/pkg/antigravity/claude_types.go index 9cab4cea..01b805cd 100644 --- a/backend/internal/pkg/antigravity/claude_types.go +++ b/backend/internal/pkg/antigravity/claude_types.go @@ -37,8 +37,19 @@ type ClaudeMetadata struct { } // ClaudeTool Claude 工具定义 +// 支持两种格式: +// 1. 标准格式: { "name": "...", "description": "...", "input_schema": {...} } +// 2. Custom 格式 (MCP): { "type": "custom", "name": "...", "custom": { "description": "...", "input_schema": {...} } } type ClaudeTool struct { - Name string `json:"name"` + Type string `json:"type,omitempty"` // "custom" 或空(标准格式) + Name string `json:"name"` + Description string `json:"description,omitempty"` // 标准格式使用 + InputSchema map[string]any `json:"input_schema,omitempty"` // 标准格式使用 + Custom *CustomToolSpec `json:"custom,omitempty"` // custom 格式使用 +} + +// CustomToolSpec MCP custom 工具规格 +type CustomToolSpec struct { Description string `json:"description,omitempty"` InputSchema map[string]any `json:"input_schema"` } diff --git a/backend/internal/pkg/antigravity/request_transformer.go b/backend/internal/pkg/antigravity/request_transformer.go index 2ff0ec02..e0b5b886 100644 --- a/backend/internal/pkg/antigravity/request_transformer.go +++ b/backend/internal/pkg/antigravity/request_transformer.go @@ -3,6 +3,7 @@ package antigravity import ( "encoding/json" "fmt" + "log" "strings" "github.com/google/uuid" @@ -205,6 +206,13 @@ func buildParts(content json.RawMessage, toolIDToName map[string]string, allowDu // 保留原有 signature(Claude 模型需要有效的 signature) 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 + } else { + // Gemini 模型使用 dummy signature + part.ThoughtSignature = dummyThoughtSignature } parts = append(parts, part) @@ -379,12 +387,40 @@ func buildTools(tools []ClaudeTool) []GeminiToolDeclaration { // 普通工具 var funcDecls []GeminiFunctionDecl for _, tool := range tools { + // 跳过无效工具名称 + if tool.Name == "" { + log.Printf("Warning: skipping tool with empty name") + continue + } + + var description string + var inputSchema map[string]any + + // 检查是否为 custom 类型工具 (MCP) + if tool.Type == "custom" && tool.Custom != nil { + // Custom 格式: 从 custom 字段获取 description 和 input_schema + description = tool.Custom.Description + inputSchema = tool.Custom.InputSchema + } else { + // 标准格式: 从顶层字段获取 + description = tool.Description + inputSchema = tool.InputSchema + } + // 清理 JSON Schema - params := cleanJSONSchema(tool.InputSchema) + params := cleanJSONSchema(inputSchema) + + // 为 nil schema 提供默认值 + if params == nil { + params = map[string]any{ + "type": "OBJECT", + "properties": map[string]any{}, + } + } funcDecls = append(funcDecls, GeminiFunctionDecl{ Name: tool.Name, - Description: tool.Description, + Description: description, Parameters: params, }) } diff --git a/backend/internal/service/gemini_messages_compat_service.go b/backend/internal/service/gemini_messages_compat_service.go index ee3ade16..a0bf1b6a 100644 --- a/backend/internal/service/gemini_messages_compat_service.go +++ b/backend/internal/service/gemini_messages_compat_service.go @@ -2245,12 +2245,40 @@ func convertClaudeToolsToGeminiTools(tools any) []any { if !ok { continue } - name, _ := tm["name"].(string) - desc, _ := tm["description"].(string) - params := tm["input_schema"] + + var name, desc string + var params any + + // 检查是否为 custom 类型工具 (MCP) + toolType, _ := tm["type"].(string) + if toolType == "custom" { + // Custom 格式: 从 custom 字段获取 description 和 input_schema + custom, ok := tm["custom"].(map[string]any) + if !ok { + continue + } + name, _ = tm["name"].(string) + desc, _ = custom["description"].(string) + params = custom["input_schema"] + } else { + // 标准格式: 从顶层字段获取 + name, _ = tm["name"].(string) + desc, _ = tm["description"].(string) + params = tm["input_schema"] + } + if name == "" { continue } + + // 为 nil params 提供默认值 + if params == nil { + params = map[string]any{ + "type": "object", + "properties": map[string]any{}, + } + } + funcDecls = append(funcDecls, map[string]any{ "name": name, "description": desc,