diff --git a/backend/internal/pkg/antigravity/request_transformer.go b/backend/internal/pkg/antigravity/request_transformer.go index ab9a6f09..2ef474e9 100644 --- a/backend/internal/pkg/antigravity/request_transformer.go +++ b/backend/internal/pkg/antigravity/request_transformer.go @@ -4,8 +4,11 @@ import ( "encoding/json" "fmt" "log" + "os" "strings" + "sync" + "github.com/gin-gonic/gin" "github.com/google/uuid" ) @@ -462,7 +465,7 @@ func cleanJSONSchema(schema map[string]any) map[string]any { if schema == nil { return nil } - cleaned := cleanSchemaValue(schema) + cleaned := cleanSchemaValue(schema, "$") result, ok := cleaned.(map[string]any) if !ok { return nil @@ -500,6 +503,56 @@ func cleanJSONSchema(schema map[string]any) map[string]any { return result } +var schemaValidationKeys = map[string]bool{ + "minLength": true, + "maxLength": true, + "pattern": true, + "minimum": true, + "maximum": true, + "exclusiveMinimum": true, + "exclusiveMaximum": true, + "multipleOf": true, + "uniqueItems": true, + "minItems": true, + "maxItems": true, + "minProperties": true, + "maxProperties": true, + "patternProperties": true, + "propertyNames": true, + "dependencies": true, + "dependentSchemas": true, + "dependentRequired": true, +} + +var warnedSchemaKeys sync.Map + +func schemaCleaningWarningsEnabled() bool { + // 可通过环境变量强制开关,方便排查:SUB2API_SCHEMA_CLEAN_WARN=true/false + if v := strings.TrimSpace(os.Getenv("SUB2API_SCHEMA_CLEAN_WARN")); v != "" { + switch strings.ToLower(v) { + case "1", "true", "yes", "on": + return true + case "0", "false", "no", "off": + return false + } + } + // 默认:非 release 模式下输出(debug/test) + return gin.Mode() != gin.ReleaseMode +} + +func warnSchemaKeyRemovedOnce(key, path string) { + if !schemaCleaningWarningsEnabled() { + return + } + if !schemaValidationKeys[key] { + return + } + if _, loaded := warnedSchemaKeys.LoadOrStore(key, struct{}{}); loaded { + return + } + log.Printf("[SchemaClean] removed unsupported JSON Schema validation field key=%q path=%q", key, path) +} + // excludedSchemaKeys 不支持的 schema 字段 // 基于 Claude API (Vertex AI) 的实际支持情况 // 支持: type, description, enum, properties, required, additionalProperties, items @@ -562,13 +615,14 @@ var excludedSchemaKeys = map[string]bool{ } // cleanSchemaValue 递归清理 schema 值 -func cleanSchemaValue(value any) any { +func cleanSchemaValue(value any, path string) any { switch v := value.(type) { case map[string]any: result := make(map[string]any) for k, val := range v { // 跳过不支持的字段 if excludedSchemaKeys[k] { + warnSchemaKeyRemovedOnce(k, path) continue } @@ -602,15 +656,15 @@ func cleanSchemaValue(value any) any { } // 递归清理所有值 - result[k] = cleanSchemaValue(val) + result[k] = cleanSchemaValue(val, path+"."+k) } return result case []any: // 递归处理数组中的每个元素 cleaned := make([]any, 0, len(v)) - for _, item := range v { - cleaned = append(cleaned, cleanSchemaValue(item)) + for i, item := range v { + cleaned = append(cleaned, cleanSchemaValue(item, fmt.Sprintf("%s[%d]", path, i))) } return cleaned