diff --git a/backend/internal/service/gemini_messages_compat_service.go b/backend/internal/service/gemini_messages_compat_service.go index d56df59e4d..a50a7fc80c 100644 --- a/backend/internal/service/gemini_messages_compat_service.go +++ b/backend/internal/service/gemini_messages_compat_service.go @@ -3419,6 +3419,7 @@ func cleanToolSchema(schema any) any { for key, value := range v { // 跳过不支持的字段 if key == "$schema" || key == "$id" || key == "$ref" || + key == "$defs" || key == "definitions" || key == "additionalProperties" || key == "patternProperties" || key == "minLength" || key == "maxLength" || key == "minItems" || key == "maxItems" { continue @@ -3429,6 +3430,17 @@ func cleanToolSchema(schema any) any { // 规范化 type 字段为大写 if typeVal, ok := cleaned["type"].(string); ok { cleaned["type"] = strings.ToUpper(typeVal) + } else if typeValues, ok := cleaned["type"].([]any); ok { + for _, typeValue := range typeValues { + typeName, ok := typeValue.(string) + if ok && !strings.EqualFold(typeName, "null") { + cleaned["type"] = strings.ToUpper(typeName) + break + } + } + if _, ok := cleaned["type"].([]any); ok { + delete(cleaned, "type") + } } return cleaned case []any: diff --git a/backend/internal/service/gemini_messages_compat_service_test.go b/backend/internal/service/gemini_messages_compat_service_test.go index 79db633aae..b2fc1c110b 100644 --- a/backend/internal/service/gemini_messages_compat_service_test.go +++ b/backend/internal/service/gemini_messages_compat_service_test.go @@ -293,6 +293,50 @@ func TestConvertClaudeToolsToGeminiTools_CustomType(t *testing.T) { } } +func TestCleanToolSchema_NormalizesGeminiUnsupportedSchemaFields(t *testing.T) { + schema := map[string]any{ + "type": "object", + "$defs": map[string]any{ + "unused": map[string]any{"type": "string"}, + }, + "definitions": map[string]any{ + "legacy": map[string]any{"type": "number"}, + }, + "properties": map[string]any{ + "path": map[string]any{ + "type": []any{"string", "null"}, + }, + "count": map[string]any{ + "type": []any{"null", "integer"}, + }, + "empty": map[string]any{ + "type": []any{"null"}, + }, + }, + } + + cleaned, ok := cleanToolSchema(schema).(map[string]any) + require.True(t, ok) + require.Equal(t, "OBJECT", cleaned["type"]) + require.NotContains(t, cleaned, "$defs") + require.NotContains(t, cleaned, "definitions") + + properties, ok := cleaned["properties"].(map[string]any) + require.True(t, ok) + + pathSchema, ok := properties["path"].(map[string]any) + require.True(t, ok) + require.Equal(t, "STRING", pathSchema["type"]) + + countSchema, ok := properties["count"].(map[string]any) + require.True(t, ok) + require.Equal(t, "INTEGER", countSchema["type"]) + + emptySchema, ok := properties["empty"].(map[string]any) + require.True(t, ok) + require.NotContains(t, emptySchema, "type") +} + func TestConvertClaudeToolsToGeminiTools_PreservesWebSearchAlongsideFunctions(t *testing.T) { tools := []any{ map[string]any{