Skip to content

Commit 3747819

Browse files
miguelffjacoblee93
andauthored
google-common[patch]: Zod to Gemini params conversion when the schema contains arrays of items (#5553)
* Fix: [libs/langchain-google-common] already existing utils test * Fix: [lib/langchain-google-common] Add failing test for arrays containing additional properties * Fix: [lib/langchain-google-common] Fix failing test * Update int test * lint --------- Co-authored-by: jacoblee93 <[email protected]>
1 parent a320c93 commit 3747819

File tree

4 files changed

+45
-4
lines changed

4 files changed

+45
-4
lines changed

libs/langchain-google-common/src/tests/utils.test.ts

+36-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
12
import { expect, test } from "@jest/globals";
23
import { z } from "zod";
34
import { zodToGeminiParameters } from "../utils/zod_to_gemini_parameters.js";
@@ -18,7 +19,7 @@ test("zodToGeminiParameters can convert zod schema to gemini schema", () => {
1819

1920
expect(convertedSchema.type).toBe("object");
2021
expect(convertedSchema.description).toBe("A simple calculator tool");
21-
expect(convertedSchema).not.toContain("additionalProperties");
22+
expect((convertedSchema as any).additionalProperties).toBeUndefined();
2223
expect(convertedSchema.properties).toEqual({
2324
operation: {
2425
type: "string",
@@ -45,3 +46,37 @@ test("zodToGeminiParameters can convert zod schema to gemini schema", () => {
4546
"childObject",
4647
]);
4748
});
49+
50+
test("zodToGeminiParameters removes additional properties from arrays", () => {
51+
const zodSchema = z
52+
.object({
53+
people: z
54+
.object({
55+
name: z.string().describe("The name of a person"),
56+
})
57+
.array()
58+
.describe("person elements"),
59+
})
60+
.describe("A list of people");
61+
62+
const convertedSchema = zodToGeminiParameters(zodSchema);
63+
expect(convertedSchema.type).toBe("object");
64+
expect(convertedSchema.description).toBe("A list of people");
65+
expect((convertedSchema as any).additionalProperties).toBeUndefined();
66+
67+
const peopleSchema = convertedSchema?.properties?.people;
68+
expect(peopleSchema).not.toBeUndefined();
69+
70+
if (peopleSchema !== undefined) {
71+
expect(peopleSchema.type).toBe("array");
72+
expect((peopleSchema as any).additionalProperties).toBeUndefined();
73+
expect(peopleSchema.description).toBe("person elements");
74+
}
75+
76+
const arrayItemsSchema = peopleSchema?.items;
77+
expect(arrayItemsSchema).not.toBeUndefined();
78+
if (arrayItemsSchema !== undefined) {
79+
expect(arrayItemsSchema.type).toBe("object");
80+
expect((arrayItemsSchema as any).additionalProperties).toBeUndefined();
81+
}
82+
});

libs/langchain-google-common/src/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ export type GeminiJsonSchema = Record<string, unknown> & {
295295
};
296296

297297
export interface GeminiJsonSchemaDirty extends GeminiJsonSchema {
298+
items?: GeminiJsonSchemaDirty;
298299
properties?: Record<string, GeminiJsonSchemaDirty>;
299300
additionalProperties?: boolean;
300301
}

libs/langchain-google-common/src/utils/zod_to_gemini_parameters.ts

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ function removeAdditionalProperties(
1919
const keys = Object.keys(updatedSchema.properties);
2020
removeProperties(updatedSchema.properties, keys, 0);
2121
}
22+
if (Object.hasOwn(updatedSchema, "items") && updatedSchema.items) {
23+
updatedSchema.items = removeAdditionalProperties(updatedSchema.items);
24+
}
2225

2326
return updatedSchema;
2427
}

libs/langchain-google-vertexai-web/src/tests/chat_models.int.test.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ import { ChatVertexAI } from "../chat_models.js";
1818

1919
class WeatherTool extends StructuredTool {
2020
schema = z.object({
21-
location: z.string().describe("The name of city to get the weather for."),
21+
locations: z
22+
.array(z.object({ name: z.string() }))
23+
.describe("The name of cities to get the weather for."),
2224
});
2325

2426
description =
@@ -28,7 +30,7 @@ class WeatherTool extends StructuredTool {
2830

2931
async _call(input: z.infer<typeof this.schema>) {
3032
console.log(`WeatherTool called with input: ${input}`);
31-
return `The weather in ${input.location} is 25°C`;
33+
return `The weather in ${JSON.stringify(input.locations)} is 25°C`;
3234
}
3335
}
3436

@@ -128,7 +130,7 @@ describe("Google APIKey Chat", () => {
128130

129131
test("Tool call", async () => {
130132
const chat = new ChatVertexAI().bindTools([new WeatherTool()]);
131-
const res = await chat.invoke("What is the weather in SF");
133+
const res = await chat.invoke("What is the weather in SF and LA");
132134
console.log(res);
133135
expect(res.tool_calls?.length).toEqual(1);
134136
expect(res.tool_calls?.[0].args).toEqual(

0 commit comments

Comments
 (0)