mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 11:51:23 +00:00
fix: flatten nested anyOf/oneOf in Gemini schema cleaning (openclaw#22825) thanks @Oceanswave
Verified: - pnpm build - pnpm check - pnpm test:macmini Co-authored-by: Oceanswave <760674+Oceanswave@users.noreply.github.com> Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
@@ -339,9 +339,63 @@ function cleanSchemaForGeminiWithDefs(
|
||||
}
|
||||
}
|
||||
|
||||
// Cloud Code Assist API rejects anyOf/oneOf in nested schemas even after
|
||||
// simplifyUnionVariants runs above. Flatten remaining unions as a fallback:
|
||||
// pick the common type or use the first variant's type so the tool
|
||||
// declaration is accepted by Google's validation layer.
|
||||
if (cleaned.anyOf && Array.isArray(cleaned.anyOf)) {
|
||||
const flattened = flattenUnionFallback(cleaned, cleaned.anyOf);
|
||||
if (flattened) {
|
||||
return flattened;
|
||||
}
|
||||
}
|
||||
if (cleaned.oneOf && Array.isArray(cleaned.oneOf)) {
|
||||
const flattened = flattenUnionFallback(cleaned, cleaned.oneOf);
|
||||
if (flattened) {
|
||||
return flattened;
|
||||
}
|
||||
}
|
||||
|
||||
return cleaned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Last-resort flattening for anyOf/oneOf arrays that could not be simplified
|
||||
* by `simplifyUnionVariants`. Picks a representative type so the schema is
|
||||
* accepted by Google's restricted JSON Schema validation.
|
||||
*/
|
||||
function flattenUnionFallback(
|
||||
obj: Record<string, unknown>,
|
||||
variants: unknown[],
|
||||
): Record<string, unknown> | undefined {
|
||||
const objects = variants.filter(
|
||||
(v): v is Record<string, unknown> => !!v && typeof v === "object",
|
||||
);
|
||||
if (objects.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
const types = new Set(objects.map((v) => v.type).filter(Boolean));
|
||||
if (objects.length === 1) {
|
||||
const merged: Record<string, unknown> = { ...objects[0] };
|
||||
copySchemaMeta(obj, merged);
|
||||
return merged;
|
||||
}
|
||||
if (types.size === 1) {
|
||||
const merged: Record<string, unknown> = { type: Array.from(types)[0] };
|
||||
copySchemaMeta(obj, merged);
|
||||
return merged;
|
||||
}
|
||||
const first = objects[0];
|
||||
if (first?.type) {
|
||||
const merged: Record<string, unknown> = { type: first.type };
|
||||
copySchemaMeta(obj, merged);
|
||||
return merged;
|
||||
}
|
||||
const merged: Record<string, unknown> = {};
|
||||
copySchemaMeta(obj, merged);
|
||||
return merged;
|
||||
}
|
||||
|
||||
export function cleanSchemaForGemini(schema: unknown): unknown {
|
||||
if (!schema || typeof schema !== "object") {
|
||||
return schema;
|
||||
|
||||
Reference in New Issue
Block a user