Skip to content

Commit a4542a6

Browse files
committed
fix(google-genai): sanitize JSON schema by removing unsupported propertyNames and patternProperties for Gemini tool-calling
1 parent 6cecddf commit a4542a6

File tree

3 files changed

+29
-4
lines changed

3 files changed

+29
-4
lines changed

libs/providers/langchain-google-genai/src/chat_models.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ import {
6363
} from "./types.js";
6464
import { convertToolsToGenAI } from "./utils/tools.js";
6565
import PROFILES from "./profiles.js";
66+
import { cleanGeminiSchema } from "./cleanGeminiSchema";
6667

6768
interface TokenUsage {
6869
completionTokens?: number;
@@ -1093,7 +1094,7 @@ export class ChatGoogleGenerativeAI
10931094
name: functionName,
10941095
description:
10951096
jsonSchema.description ?? "A function available to call.",
1096-
parameters: jsonSchema as GenerativeAIFunctionDeclarationSchema,
1097+
parameters: cleanGeminiSchema(jsonSchema) as GenerativeAIFunctionDeclarationSchema,
10971098
},
10981099
],
10991100
},
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
export function cleanGeminiSchema(schema: any): any {
2+
if (!schema || typeof schema !== "object") {
3+
return schema;
4+
}
5+
6+
const cleaned: any = Array.isArray(schema)
7+
? schema.map((item) => cleanGeminiSchema(item))
8+
: { ...schema };
9+
10+
11+
delete cleaned.propertyNames;
12+
delete cleaned.patternProperties;
13+
14+
15+
for (const key of Object.keys(cleaned)) {
16+
if (typeof cleaned[key] === "object") {
17+
cleaned[key] = cleanGeminiSchema(cleaned[key]);
18+
}
19+
}
20+
21+
return cleaned;
22+
}

libs/providers/langchain-google-genai/src/utils/common.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import { isLangChainTool } from "@langchain/core/utils/function_calling";
3939
import { isOpenAITool } from "@langchain/core/language_models/base";
4040
import { ToolCallChunk } from "@langchain/core/messages/tool";
4141
import { v4 as uuidv4 } from "uuid";
42+
import { cleanGeminiSchema } from "../cleanGeminiSchema.js";
4243
import {
4344
jsonSchemaToGeminiParameters,
4445
schemaToGenerativeAIParameters,
@@ -358,8 +359,8 @@ export function convertMessageContentToParts(
358359

359360
const result = Array.isArray(message.content)
360361
? (message.content
361-
.map((c) => _convertLangChainContentToPart(c, isMultimodalModel))
362-
.filter((p) => p !== undefined) as Part[])
362+
.map((c) => _convertLangChainContentToPart(c, isMultimodalModel))
363+
.filter((p) => p !== undefined) as Part[])
363364
: message.content;
364365

365366
if (message.status === "error") {
@@ -799,7 +800,8 @@ export function convertToGenerativeAITools(
799800
return {
800801
name: tool.name,
801802
description: tool.description,
802-
parameters: jsonSchema,
803+
parameters: cleanGeminiSchema(jsonSchema),
804+
803805
};
804806
}
805807
if (isOpenAITool(tool)) {

0 commit comments

Comments
 (0)