mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-07 12:57:57 +08:00
fix(gemini): sanitize unsupported tool schema fields
This commit is contained in:
@@ -3587,12 +3587,20 @@ func cleanToolSchema(schema any) any {
|
||||
if key == "$schema" || key == "$id" || key == "$ref" ||
|
||||
key == "$defs" || key == "definitions" ||
|
||||
key == "additionalProperties" || key == "patternProperties" || key == "minLength" ||
|
||||
key == "maxLength" || key == "minItems" || key == "maxItems" || key == "exclusiveMinimum" {
|
||||
key == "maxLength" || key == "minItems" || key == "maxItems" || key == "exclusiveMinimum" ||
|
||||
key == "deprecated" {
|
||||
continue
|
||||
}
|
||||
// 递归清理嵌套对象
|
||||
cleaned[key] = cleanToolSchema(value)
|
||||
}
|
||||
if enum, ok := cleaned["enum"].([]any); ok {
|
||||
if normalized, ok := normalizeGeminiEnum(enum); ok {
|
||||
cleaned["enum"] = normalized
|
||||
} else {
|
||||
delete(cleaned, "enum")
|
||||
}
|
||||
}
|
||||
// 规范化 type 字段为大写
|
||||
if typeVal, ok := cleaned["type"].(string); ok {
|
||||
cleaned["type"] = strings.ToUpper(typeVal)
|
||||
@@ -3627,6 +3635,28 @@ func cleanToolSchema(schema any) any {
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeGeminiEnum(values []any) ([]any, bool) {
|
||||
normalized := make([]any, len(values))
|
||||
for i, value := range values {
|
||||
if stringValue, ok := value.(string); ok {
|
||||
normalized[i] = stringValue
|
||||
continue
|
||||
}
|
||||
|
||||
switch value.(type) {
|
||||
case nil, bool, float32, float64, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, json.Number:
|
||||
encoded, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
normalized[i] = string(encoded)
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
return normalized, true
|
||||
}
|
||||
|
||||
func incrementIntegralSchemaBound(value any) (any, bool) {
|
||||
switch v := value.(type) {
|
||||
case float64:
|
||||
|
||||
@@ -471,6 +471,44 @@ func TestCleanToolSchema_DropsAmbiguousExclusiveMinimumWithoutConversion(t *test
|
||||
}
|
||||
}
|
||||
|
||||
func TestCleanToolSchema_RemovesNestedDeprecatedAndNormalizesMixedScalarEnum(t *testing.T) {
|
||||
schema := map[string]any{
|
||||
"anyOf": []any{
|
||||
map[string]any{
|
||||
"type": "string",
|
||||
"deprecated": true,
|
||||
},
|
||||
map[string]any{
|
||||
"enum": []any{"enabled", false, float64(1), nil},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
cleaned, ok := cleanToolSchema(schema).(map[string]any)
|
||||
require.True(t, ok)
|
||||
anyOf, ok := cleaned["anyOf"].([]any)
|
||||
require.True(t, ok)
|
||||
require.Len(t, anyOf, 2)
|
||||
|
||||
deprecatedSchema, ok := anyOf[0].(map[string]any)
|
||||
require.True(t, ok)
|
||||
require.NotContains(t, deprecatedSchema, "deprecated")
|
||||
|
||||
enumSchema, ok := anyOf[1].(map[string]any)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, []any{"enabled", "false", "1", "null"}, enumSchema["enum"])
|
||||
}
|
||||
|
||||
func TestCleanToolSchema_DropsEnumWithNonScalarValue(t *testing.T) {
|
||||
schema := map[string]any{
|
||||
"enum": []any{"valid", map[string]any{"invalid": true}},
|
||||
}
|
||||
|
||||
cleaned, ok := cleanToolSchema(schema).(map[string]any)
|
||||
require.True(t, ok)
|
||||
require.NotContains(t, cleaned, "enum")
|
||||
}
|
||||
|
||||
func TestConvertClaudeToolsToGeminiTools_PreservesWebSearchAlongsideFunctions(t *testing.T) {
|
||||
tools := []any{
|
||||
map[string]any{
|
||||
|
||||
Reference in New Issue
Block a user