Skip to content

Commit fe1fd05

Browse files
committed
fix: sanitize Gemini tool schema required fields (openclaw#64284) (thanks @xxxxxmax)
1 parent 0dbcf81 commit fe1fd05

3 files changed

Lines changed: 18 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ Docs: https://docs.openclaw.ai
105105
- Plugins: treat duplicate `registerService` calls from the same plugin id as idempotent so snapshot and activation loads no longer emit spurious `service already registered` diagnostics. (#62033, #64128) Thanks @ly85206559.
106106
- Discord/TTS: route auto voice replies through the native voice-note path so Discord receives Opus voice messages instead of regular audio attachments. (#64096) Thanks @LiuHuaize.
107107
- Config/plugins: use plugin-owned command alias metadata when `plugins.allow` contains runtime command names like `dreaming`, and point users at the owning plugin instead of stale plugin-not-found guidance. (#64242) Thanks @feiskyer.
108+
- Agents/Gemini: strip orphaned `required` entries from Gemini tool schemas so provider validation no longer rejects tools after schema cleanup or union flattening. (#64284) Thanks @xxxxxmax.
108109

109110
## 2026.4.9
110111

src/agents/schema/clean-for-gemini.test.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,21 @@ describe("cleanSchemaForGemini", () => {
6868
expect(cleaned.required).toBeUndefined();
6969
});
7070

71-
it("leaves required as-is when properties is absent", () => {
71+
it("removes required from object schemas when properties is absent", () => {
7272
const cleaned = cleanSchemaForGemini({
7373
type: "object",
7474
required: ["a", "b"],
7575
}) as { required?: string[] };
7676

77+
expect(cleaned.required).toBeUndefined();
78+
});
79+
80+
it("leaves required as-is for non-object schemas when properties is absent", () => {
81+
const cleaned = cleanSchemaForGemini({
82+
type: "array",
83+
required: ["a", "b"],
84+
}) as { required?: string[] };
85+
7786
expect(cleaned.required).toEqual(["a", "b"]);
7887
});
7988

src/agents/schema/clean-for-gemini.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,12 +214,18 @@ function simplifyUnionVariants(params: { obj: Record<string, unknown>; variants:
214214

215215
// Gemini rejects object schemas whose `required` entries do not exist in `properties`.
216216
function sanitizeRequiredFields(schema: Record<string, unknown>): Record<string, unknown> {
217+
if (!Array.isArray(schema.required)) {
218+
return schema;
219+
}
220+
217221
if (
218-
!Array.isArray(schema.required) ||
219222
!schema.properties ||
220223
typeof schema.properties !== "object" ||
221224
Array.isArray(schema.properties)
222225
) {
226+
if (schema.type === "object") {
227+
delete schema.required;
228+
}
223229
return schema;
224230
}
225231

0 commit comments

Comments
 (0)