diff --git a/internal/translator/gemini-cli/claude/gemini-cli_claude_request.go b/internal/translator/gemini-cli/claude/gemini-cli_claude_request.go index e3753b03..18ce4495 100644 --- a/internal/translator/gemini-cli/claude/gemini-cli_claude_request.go +++ b/internal/translator/gemini-cli/claude/gemini-cli_claude_request.go @@ -6,10 +6,10 @@ package claude import ( - "bytes" "strings" "github.com/router-for-me/CLIProxyAPI/v6/internal/translator/gemini/common" + "github.com/router-for-me/CLIProxyAPI/v6/internal/util" "github.com/tidwall/gjson" "github.com/tidwall/sjson" ) @@ -36,7 +36,6 @@ const geminiCLIClaudeThoughtSignature = "skip_thought_signature_validator" // - []byte: The transformed request data in Gemini CLI API format func ConvertClaudeRequestToCLI(modelName string, inputRawJSON []byte, _ bool) []byte { rawJSON := inputRawJSON - rawJSON = bytes.Replace(rawJSON, []byte(`"url":{"type":"string","format":"uri",`), []byte(`"url":{"type":"string",`), -1) // Build output Gemini CLI request JSON out := `{"model":"","request":{"contents":[]}}` @@ -149,7 +148,7 @@ func ConvertClaudeRequestToCLI(modelName string, inputRawJSON []byte, _ bool) [] toolsResult.ForEach(func(_, toolResult gjson.Result) bool { inputSchemaResult := toolResult.Get("input_schema") if inputSchemaResult.Exists() && inputSchemaResult.IsObject() { - inputSchema := inputSchemaResult.Raw + inputSchema := util.CleanJSONSchemaForGemini(inputSchemaResult.Raw) tool, _ := sjson.Delete(toolResult.Raw, "input_schema") tool, _ = sjson.SetRaw(tool, "parametersJsonSchema", inputSchema) tool, _ = sjson.Delete(tool, "strict") @@ -157,6 +156,7 @@ func ConvertClaudeRequestToCLI(modelName string, inputRawJSON []byte, _ bool) [] tool, _ = sjson.Delete(tool, "type") tool, _ = sjson.Delete(tool, "cache_control") tool, _ = sjson.Delete(tool, "defer_loading") + tool, _ = sjson.Delete(tool, "eager_input_streaming") if gjson.Valid(tool) && gjson.Parse(tool).IsObject() { if !hasTools { out, _ = sjson.SetRaw(out, "request.tools", `[{"functionDeclarations":[]}]`) diff --git a/internal/translator/gemini-cli/gemini/gemini-cli_gemini_request.go b/internal/translator/gemini-cli/gemini/gemini-cli_gemini_request.go index a2af6f83..ee6c5b83 100644 --- a/internal/translator/gemini-cli/gemini/gemini-cli_gemini_request.go +++ b/internal/translator/gemini-cli/gemini/gemini-cli_gemini_request.go @@ -111,6 +111,23 @@ func ConvertGeminiRequestToGeminiCLI(_ string, inputRawJSON []byte, _ bool) []by return true }) + // Filter out contents with empty parts to avoid Gemini API error: + // "required oneof field 'data' must have one initialized field" + filteredContents := "[]" + hasFiltered := false + gjson.GetBytes(rawJSON, "request.contents").ForEach(func(_, content gjson.Result) bool { + parts := content.Get("parts") + if !parts.IsArray() || len(parts.Array()) == 0 { + hasFiltered = true + return true + } + filteredContents, _ = sjson.SetRaw(filteredContents, "-1", content.Raw) + return true + }) + if hasFiltered { + rawJSON, _ = sjson.SetRawBytes(rawJSON, "request.contents", []byte(filteredContents)) + } + return common.AttachDefaultSafetySettings(rawJSON, "request.safetySettings") }