-
Notifications
You must be signed in to change notification settings - Fork 22.8k
fix(google): sanitize unsupported JSON Schema keywords for Gemini API #13666
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -880,8 +880,67 @@ export namespace ProviderTransform { | |
| return obj.map(sanitizeGemini) | ||
| } | ||
|
|
||
| // Convert anyOf/oneOf with const values to enum before processing | ||
| if (obj.anyOf || obj.oneOf) { | ||
| const variants = obj.anyOf || obj.oneOf | ||
| if (Array.isArray(variants)) { | ||
| const constValues = variants | ||
| .filter((v: any) => v && typeof v === "object" && "const" in v) | ||
| .map((v: any) => String(v.const)) | ||
| if (constValues.length === variants.length && constValues.length > 0) { | ||
| const merged: any = { ...obj, type: "string", enum: constValues } | ||
| delete merged.anyOf | ||
| delete merged.oneOf | ||
| delete merged.const | ||
| return sanitizeGemini(merged) | ||
| } | ||
| // If anyOf/oneOf contains type variants, pick the first valid one | ||
| const typeVariants = variants.filter((v: any) => v && typeof v === "object" && v.type) | ||
| if (typeVariants.length > 0) { | ||
| const merged: any = { ...obj, ...typeVariants[0] } | ||
| delete merged.anyOf | ||
| delete merged.oneOf | ||
| return sanitizeGemini(merged) | ||
| } | ||
|
||
| } | ||
| } | ||
|
Comment on lines
+1019
to
+1093
|
||
|
|
||
| const result: any = {} | ||
| for (const [key, value] of Object.entries(obj)) { | ||
| // Skip keywords unsupported by Gemini | ||
| if ( | ||
| key === "additionalProperties" || | ||
| key === "$ref" || | ||
|
||
| key === "$schema" || | ||
| key === "$id" || | ||
| key === "$defs" || | ||
| key === "definitions" || | ||
| key === "default" || | ||
|
||
| key === "const" || | ||
| key === "minItems" || | ||
| key === "maxItems" || | ||
| key === "minLength" || | ||
| key === "maxLength" || | ||
| key === "pattern" || | ||
| key === "patternProperties" || | ||
| key === "propertyNames" || | ||
| key === "uniqueItems" || | ||
| key === "minimum" || | ||
| key === "maximum" || | ||
| key === "exclusiveMinimum" || | ||
| key === "exclusiveMaximum" || | ||
| key === "multipleOf" || | ||
| key === "if" || | ||
| key === "then" || | ||
| key === "else" || | ||
| key === "not" || | ||
| key === "title" || | ||
| key === "allOf" || | ||
|
||
| key === "anyOf" || | ||
| key === "oneOf" | ||
| ) { | ||
| continue | ||
| } | ||
| if (key === "enum" && Array.isArray(value)) { | ||
| // Convert all enum values to strings | ||
| result[key] = value.map((v) => String(v)) | ||
|
|
@@ -896,6 +955,11 @@ export namespace ProviderTransform { | |
| } | ||
| } | ||
|
|
||
| // Infer type="object" when properties exist but type is missing | ||
| if (!result.type && (result.properties || result.required)) { | ||
| result.type = "object" | ||
| } | ||
|
Comment on lines
1018
to
+1147
|
||
|
|
||
| // Filter required array to only include fields that exist in properties | ||
| if (result.type === "object" && result.properties && Array.isArray(result.required)) { | ||
| result.required = result.required.filter((field: any) => field in result.properties) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When converting anyOf/oneOf with const values to enum, the description field from individual const objects is lost. For example, {"anyOf": [{"const": "append", "description": "Add to end"}, {"const": "prepend", "description": "Add to start"}]} becomes {"type": "string", "enum": ["append", "prepend"]} without preserving the descriptions for each enum value. Consider preserving the parent description if it exists, or documenting that per-value descriptions cannot be represented in Gemini's enum format.