fix: scrub tuple items schemas for Gemini tools (#926) — thanks @grp06

Co-authored-by: George Pickett <gpickett00@gmail.com>
This commit is contained in:
Peter Steinberger
2026-01-15 02:59:23 +00:00
parent eaace34233
commit e569f15631
3 changed files with 35 additions and 2 deletions

View File

@@ -156,6 +156,30 @@ describe("createClawdbotCodingTools", () => {
enum: ["a", "b"],
});
});
it("cleans tuple items schemas", () => {
const cleaned = __testing.cleanToolSchemaForGemini({
type: "object",
properties: {
tuples: {
type: "array",
items: [
{ type: "string", format: "uuid" },
{ type: "number", minimum: 1 },
],
},
},
}) as {
properties?: Record<string, unknown>;
};
const tuples = cleaned.properties?.tuples as { items?: unknown } | undefined;
const items = Array.isArray(tuples?.items) ? tuples?.items : [];
const first = items[0] as { format?: unknown } | undefined;
const second = items[1] as { minimum?: unknown } | undefined;
expect(first?.format).toBeUndefined();
expect(second?.minimum).toBeUndefined();
});
it("drops null-only union variants without flattening other unions", () => {
const cleaned = __testing.cleanToolSchemaForGemini({
type: "object",

View File

@@ -280,8 +280,16 @@ function cleanSchemaForGeminiWithDefs(
cleanSchemaForGeminiWithDefs(v, nextDefs, refStack),
]),
);
} else if (key === "items" && value && typeof value === "object") {
cleaned[key] = cleanSchemaForGeminiWithDefs(value, nextDefs, refStack);
} else if (key === "items" && value) {
if (Array.isArray(value)) {
cleaned[key] = value.map((entry) =>
cleanSchemaForGeminiWithDefs(entry, nextDefs, refStack),
);
} else if (typeof value === "object") {
cleaned[key] = cleanSchemaForGeminiWithDefs(value, nextDefs, refStack);
} else {
cleaned[key] = value;
}
} else if (key === "anyOf" && Array.isArray(value)) {
cleaned[key] =
cleanedAnyOf ??