@langchain/google-genai 0.0.14 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,7 +4,11 @@ exports.ChatGoogleGenerativeAI = void 0;
4
4
  const generative_ai_1 = require("@google/generative-ai");
5
5
  const env_1 = require("@langchain/core/utils/env");
6
6
  const chat_models_1 = require("@langchain/core/language_models/chat_models");
7
- const utils_js_1 = require("./utils.cjs");
7
+ const runnables_1 = require("@langchain/core/runnables");
8
+ const types_1 = require("@langchain/core/utils/types");
9
+ const zod_to_genai_parameters_js_1 = require("./utils/zod_to_genai_parameters.cjs");
10
+ const common_js_1 = require("./utils/common.cjs");
11
+ const output_parsers_js_1 = require("./output_parsers.cjs");
8
12
  /**
9
13
  * A class that wraps the Google Palm chat model.
10
14
  * @example
@@ -36,7 +40,7 @@ const utils_js_1 = require("./utils.cjs");
36
40
  */
37
41
  class ChatGoogleGenerativeAI extends chat_models_1.BaseChatModel {
38
42
  static lc_name() {
39
- return "googlegenerativeai";
43
+ return "ChatGoogleGenerativeAI";
40
44
  }
41
45
  get lc_secrets() {
42
46
  return {
@@ -108,18 +112,6 @@ class ChatGoogleGenerativeAI extends chat_models_1.BaseChatModel {
108
112
  writable: true,
109
113
  value: void 0
110
114
  });
111
- Object.defineProperty(this, "apiVersion", {
112
- enumerable: true,
113
- configurable: true,
114
- writable: true,
115
- value: "v1"
116
- });
117
- Object.defineProperty(this, "baseUrl", {
118
- enumerable: true,
119
- configurable: true,
120
- writable: true,
121
- value: "https://generativeai.googleapis.com"
122
- });
123
115
  Object.defineProperty(this, "streaming", {
124
116
  enumerable: true,
125
117
  configurable: true,
@@ -184,18 +176,47 @@ class ChatGoogleGenerativeAI extends chat_models_1.BaseChatModel {
184
176
  topK: this.topK,
185
177
  },
186
178
  }, {
187
- apiVersion: this.apiVersion,
188
- baseUrl: this.baseUrl,
179
+ apiVersion: fields?.apiVersion,
180
+ baseUrl: fields?.baseUrl,
189
181
  });
190
182
  }
183
+ getLsParams(options) {
184
+ return {
185
+ ls_provider: "google_genai",
186
+ ls_model_name: this.model,
187
+ ls_model_type: "chat",
188
+ ls_temperature: this.client.generationConfig.temperature,
189
+ ls_max_tokens: this.client.generationConfig.maxOutputTokens,
190
+ ls_stop: options.stop,
191
+ };
192
+ }
191
193
  _combineLLMOutput() {
192
194
  return [];
193
195
  }
194
196
  _llmType() {
195
197
  return "googlegenerativeai";
196
198
  }
199
+ bindTools(tools, kwargs) {
200
+ return this.bind({ tools: (0, common_js_1.convertToGenerativeAITools)(tools), ...kwargs });
201
+ }
202
+ invocationParams(options) {
203
+ const tools = options?.tools;
204
+ if (Array.isArray(tools) &&
205
+ !tools.some(
206
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
207
+ (t) => !("lc_namespace" in t))) {
208
+ // Tools are in StructuredToolInterface format. Convert to GenAI format
209
+ return {
210
+ tools: (0, common_js_1.convertToGenerativeAITools)(options?.tools),
211
+ };
212
+ }
213
+ return {
214
+ tools: options?.tools,
215
+ };
216
+ }
197
217
  async _generate(messages, options, runManager) {
198
- const prompt = (0, utils_js_1.convertBaseMessagesToContent)(messages, this._isMultimodalModel);
218
+ const prompt = (0, common_js_1.convertBaseMessagesToContent)(messages, this._isMultimodalModel);
219
+ const parameters = this.invocationParams(options);
199
220
  // Handle streaming
200
221
  if (this.streaming) {
201
222
  const tokenUsage = {};
@@ -219,6 +240,7 @@ class ChatGoogleGenerativeAI extends chat_models_1.BaseChatModel {
219
240
  let output;
220
241
  try {
221
242
  output = await this.client.generateContent({
243
+ ...parameters,
222
244
  contents: prompt,
223
245
  });
224
246
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -232,20 +254,22 @@ class ChatGoogleGenerativeAI extends chat_models_1.BaseChatModel {
232
254
  }
233
255
  return output;
234
256
  });
235
- const generationResult = (0, utils_js_1.mapGenerateContentResultToChatResult)(res.response);
257
+ const generationResult = (0, common_js_1.mapGenerateContentResultToChatResult)(res.response);
236
258
  await runManager?.handleLLMNewToken(generationResult.generations[0].text ?? "");
237
259
  return generationResult;
238
260
  }
239
261
  async *_streamResponseChunks(messages, options, runManager) {
240
- const prompt = (0, utils_js_1.convertBaseMessagesToContent)(messages, this._isMultimodalModel);
262
+ const prompt = (0, common_js_1.convertBaseMessagesToContent)(messages, this._isMultimodalModel);
263
+ const parameters = this.invocationParams(options);
241
264
  const stream = await this.caller.callWithOptions({ signal: options?.signal }, async () => {
242
265
  const { stream } = await this.client.generateContentStream({
266
+ ...parameters,
243
267
  contents: prompt,
244
268
  });
245
269
  return stream;
246
270
  });
247
271
  for await (const response of stream) {
248
- const chunk = (0, utils_js_1.convertResponseContentToChatGenerationChunk)(response);
272
+ const chunk = (0, common_js_1.convertResponseContentToChatGenerationChunk)(response);
249
273
  if (!chunk) {
250
274
  continue;
251
275
  }
@@ -253,5 +277,88 @@ class ChatGoogleGenerativeAI extends chat_models_1.BaseChatModel {
253
277
  await runManager?.handleLLMNewToken(chunk.text ?? "");
254
278
  }
255
279
  }
280
+ withStructuredOutput(outputSchema, config) {
281
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
282
+ const schema = outputSchema;
283
+ const name = config?.name;
284
+ const method = config?.method;
285
+ const includeRaw = config?.includeRaw;
286
+ if (method === "jsonMode") {
287
+ throw new Error(`ChatGoogleGenerativeAI only supports "functionCalling" as a method.`);
288
+ }
289
+ let functionName = name ?? "extract";
290
+ let outputParser;
291
+ let tools;
292
+ if ((0, types_1.isZodSchema)(schema)) {
293
+ const jsonSchema = (0, zod_to_genai_parameters_js_1.zodToGenerativeAIParameters)(schema);
294
+ tools = [
295
+ {
296
+ functionDeclarations: [
297
+ {
298
+ name: functionName,
299
+ description: jsonSchema.description ?? "A function available to call.",
300
+ parameters: jsonSchema,
301
+ },
302
+ ],
303
+ },
304
+ ];
305
+ outputParser = new output_parsers_js_1.GoogleGenerativeAIToolsOutputParser({
306
+ returnSingle: true,
307
+ keyName: functionName,
308
+ zodSchema: schema,
309
+ });
310
+ }
311
+ else {
312
+ let geminiFunctionDefinition;
313
+ if (typeof schema.name === "string" &&
314
+ typeof schema.parameters === "object" &&
315
+ schema.parameters != null) {
316
+ geminiFunctionDefinition = schema;
317
+ functionName = schema.name;
318
+ }
319
+ else {
320
+ geminiFunctionDefinition = {
321
+ name: functionName,
322
+ description: schema.description ?? "",
323
+ parameters: schema,
324
+ };
325
+ }
326
+ tools = [
327
+ {
328
+ functionDeclarations: [geminiFunctionDefinition],
329
+ },
330
+ ];
331
+ outputParser = new output_parsers_js_1.GoogleGenerativeAIToolsOutputParser({
332
+ returnSingle: true,
333
+ keyName: functionName,
334
+ });
335
+ }
336
+ const llm = this.bind({
337
+ tools,
338
+ });
339
+ if (!includeRaw) {
340
+ return llm.pipe(outputParser).withConfig({
341
+ runName: "ChatGoogleGenerativeAIStructuredOutput",
342
+ });
343
+ }
344
+ const parserAssign = runnables_1.RunnablePassthrough.assign({
345
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
346
+ parsed: (input, config) => outputParser.invoke(input.raw, config),
347
+ });
348
+ const parserNone = runnables_1.RunnablePassthrough.assign({
349
+ parsed: () => null,
350
+ });
351
+ const parsedWithFallback = parserAssign.withFallbacks({
352
+ fallbacks: [parserNone],
353
+ });
354
+ return runnables_1.RunnableSequence.from([
355
+ {
356
+ raw: llm,
357
+ },
358
+ parsedWithFallback,
359
+ ]).withConfig({
360
+ runName: "StructuredOutputRunnable",
361
+ });
362
+ }
256
363
  }
257
364
  exports.ChatGoogleGenerativeAI = ChatGoogleGenerativeAI;
@@ -1,12 +1,19 @@
1
- import type { SafetySetting } from "@google/generative-ai";
1
+ import { FunctionDeclarationsTool as GoogleGenerativeAIFunctionDeclarationsTool, GenerateContentRequest, SafetySetting } from "@google/generative-ai";
2
2
  import { CallbackManagerForLLMRun } from "@langchain/core/callbacks/manager";
3
- import { BaseMessage } from "@langchain/core/messages";
3
+ import { AIMessageChunk, BaseMessage } from "@langchain/core/messages";
4
4
  import { ChatGenerationChunk, ChatResult } from "@langchain/core/outputs";
5
- import { BaseChatModel, type BaseChatModelParams } from "@langchain/core/language_models/chat_models";
5
+ import { BaseChatModel, LangSmithParams, type BaseChatModelParams } from "@langchain/core/language_models/chat_models";
6
+ import { BaseLanguageModelCallOptions, BaseLanguageModelInput, StructuredOutputMethodOptions } from "@langchain/core/language_models/base";
7
+ import { StructuredToolInterface } from "@langchain/core/tools";
8
+ import { Runnable } from "@langchain/core/runnables";
9
+ import type { z } from "zod";
6
10
  export type BaseMessageExamplePair = {
7
11
  input: BaseMessage;
8
12
  output: BaseMessage;
9
13
  };
14
+ export interface GoogleGenerativeAIChatCallOptions extends BaseLanguageModelCallOptions {
15
+ tools?: StructuredToolInterface[] | GoogleGenerativeAIFunctionDeclarationsTool[];
16
+ }
10
17
  /**
11
18
  * An interface defining the input to the ChatGoogleGenerativeAI class.
12
19
  */
@@ -124,7 +131,7 @@ export interface GoogleGenerativeAIChatInput extends BaseChatModelParams {
124
131
  * console.log({ res });
125
132
  * ```
126
133
  */
127
- export declare class ChatGoogleGenerativeAI extends BaseChatModel implements GoogleGenerativeAIChatInput {
134
+ export declare class ChatGoogleGenerativeAI extends BaseChatModel<GoogleGenerativeAIChatCallOptions, AIMessageChunk> implements GoogleGenerativeAIChatInput {
128
135
  static lc_name(): string;
129
136
  lc_serializable: boolean;
130
137
  get lc_secrets(): {
@@ -139,14 +146,20 @@ export declare class ChatGoogleGenerativeAI extends BaseChatModel implements Goo
139
146
  stopSequences: string[];
140
147
  safetySettings?: SafetySetting[];
141
148
  apiKey?: string;
142
- apiVersion?: string;
143
- baseUrl?: string;
144
149
  streaming: boolean;
145
150
  private client;
146
151
  get _isMultimodalModel(): boolean;
147
152
  constructor(fields?: GoogleGenerativeAIChatInput);
153
+ protected getLsParams(options: this["ParsedCallOptions"]): LangSmithParams;
148
154
  _combineLLMOutput(): never[];
149
155
  _llmType(): string;
156
+ bindTools(tools: (StructuredToolInterface | Record<string, unknown>)[], kwargs?: Partial<GoogleGenerativeAIChatCallOptions>): Runnable<BaseLanguageModelInput, AIMessageChunk, GoogleGenerativeAIChatCallOptions>;
157
+ invocationParams(options?: this["ParsedCallOptions"]): Omit<GenerateContentRequest, "contents">;
150
158
  _generate(messages: BaseMessage[], options: this["ParsedCallOptions"], runManager?: CallbackManagerForLLMRun): Promise<ChatResult>;
151
159
  _streamResponseChunks(messages: BaseMessage[], options: this["ParsedCallOptions"], runManager?: CallbackManagerForLLMRun): AsyncGenerator<ChatGenerationChunk>;
160
+ withStructuredOutput<RunOutput extends Record<string, any> = Record<string, any>>(outputSchema: z.ZodType<RunOutput> | Record<string, any>, config?: StructuredOutputMethodOptions<false>): Runnable<BaseLanguageModelInput, RunOutput>;
161
+ withStructuredOutput<RunOutput extends Record<string, any> = Record<string, any>>(outputSchema: z.ZodType<RunOutput> | Record<string, any>, config?: StructuredOutputMethodOptions<true>): Runnable<BaseLanguageModelInput, {
162
+ raw: BaseMessage;
163
+ parsed: RunOutput;
164
+ }>;
152
165
  }
@@ -1,7 +1,11 @@
1
1
  import { GoogleGenerativeAI as GenerativeAI, } from "@google/generative-ai";
2
2
  import { getEnvironmentVariable } from "@langchain/core/utils/env";
3
3
  import { BaseChatModel, } from "@langchain/core/language_models/chat_models";
4
- import { convertBaseMessagesToContent, convertResponseContentToChatGenerationChunk, mapGenerateContentResultToChatResult, } from "./utils.js";
4
+ import { RunnablePassthrough, RunnableSequence, } from "@langchain/core/runnables";
5
+ import { isZodSchema } from "@langchain/core/utils/types";
6
+ import { zodToGenerativeAIParameters } from "./utils/zod_to_genai_parameters.js";
7
+ import { convertBaseMessagesToContent, convertResponseContentToChatGenerationChunk, convertToGenerativeAITools, mapGenerateContentResultToChatResult, } from "./utils/common.js";
8
+ import { GoogleGenerativeAIToolsOutputParser } from "./output_parsers.js";
5
9
  /**
6
10
  * A class that wraps the Google Palm chat model.
7
11
  * @example
@@ -33,7 +37,7 @@ import { convertBaseMessagesToContent, convertResponseContentToChatGenerationChu
33
37
  */
34
38
  export class ChatGoogleGenerativeAI extends BaseChatModel {
35
39
  static lc_name() {
36
- return "googlegenerativeai";
40
+ return "ChatGoogleGenerativeAI";
37
41
  }
38
42
  get lc_secrets() {
39
43
  return {
@@ -105,18 +109,6 @@ export class ChatGoogleGenerativeAI extends BaseChatModel {
105
109
  writable: true,
106
110
  value: void 0
107
111
  });
108
- Object.defineProperty(this, "apiVersion", {
109
- enumerable: true,
110
- configurable: true,
111
- writable: true,
112
- value: "v1"
113
- });
114
- Object.defineProperty(this, "baseUrl", {
115
- enumerable: true,
116
- configurable: true,
117
- writable: true,
118
- value: "https://generativeai.googleapis.com"
119
- });
120
112
  Object.defineProperty(this, "streaming", {
121
113
  enumerable: true,
122
114
  configurable: true,
@@ -181,18 +173,47 @@ export class ChatGoogleGenerativeAI extends BaseChatModel {
181
173
  topK: this.topK,
182
174
  },
183
175
  }, {
184
- apiVersion: this.apiVersion,
185
- baseUrl: this.baseUrl,
176
+ apiVersion: fields?.apiVersion,
177
+ baseUrl: fields?.baseUrl,
186
178
  });
187
179
  }
180
+ getLsParams(options) {
181
+ return {
182
+ ls_provider: "google_genai",
183
+ ls_model_name: this.model,
184
+ ls_model_type: "chat",
185
+ ls_temperature: this.client.generationConfig.temperature,
186
+ ls_max_tokens: this.client.generationConfig.maxOutputTokens,
187
+ ls_stop: options.stop,
188
+ };
189
+ }
188
190
  _combineLLMOutput() {
189
191
  return [];
190
192
  }
191
193
  _llmType() {
192
194
  return "googlegenerativeai";
193
195
  }
196
+ bindTools(tools, kwargs) {
197
+ return this.bind({ tools: convertToGenerativeAITools(tools), ...kwargs });
198
+ }
199
+ invocationParams(options) {
200
+ const tools = options?.tools;
201
+ if (Array.isArray(tools) &&
202
+ !tools.some(
203
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
204
+ (t) => !("lc_namespace" in t))) {
205
+ // Tools are in StructuredToolInterface format. Convert to GenAI format
206
+ return {
207
+ tools: convertToGenerativeAITools(options?.tools),
208
+ };
209
+ }
210
+ return {
211
+ tools: options?.tools,
212
+ };
213
+ }
194
214
  async _generate(messages, options, runManager) {
195
215
  const prompt = convertBaseMessagesToContent(messages, this._isMultimodalModel);
216
+ const parameters = this.invocationParams(options);
196
217
  // Handle streaming
197
218
  if (this.streaming) {
198
219
  const tokenUsage = {};
@@ -216,6 +237,7 @@ export class ChatGoogleGenerativeAI extends BaseChatModel {
216
237
  let output;
217
238
  try {
218
239
  output = await this.client.generateContent({
240
+ ...parameters,
219
241
  contents: prompt,
220
242
  });
221
243
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -235,8 +257,10 @@ export class ChatGoogleGenerativeAI extends BaseChatModel {
235
257
  }
236
258
  async *_streamResponseChunks(messages, options, runManager) {
237
259
  const prompt = convertBaseMessagesToContent(messages, this._isMultimodalModel);
260
+ const parameters = this.invocationParams(options);
238
261
  const stream = await this.caller.callWithOptions({ signal: options?.signal }, async () => {
239
262
  const { stream } = await this.client.generateContentStream({
263
+ ...parameters,
240
264
  contents: prompt,
241
265
  });
242
266
  return stream;
@@ -250,4 +274,87 @@ export class ChatGoogleGenerativeAI extends BaseChatModel {
250
274
  await runManager?.handleLLMNewToken(chunk.text ?? "");
251
275
  }
252
276
  }
277
+ withStructuredOutput(outputSchema, config) {
278
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
279
+ const schema = outputSchema;
280
+ const name = config?.name;
281
+ const method = config?.method;
282
+ const includeRaw = config?.includeRaw;
283
+ if (method === "jsonMode") {
284
+ throw new Error(`ChatGoogleGenerativeAI only supports "functionCalling" as a method.`);
285
+ }
286
+ let functionName = name ?? "extract";
287
+ let outputParser;
288
+ let tools;
289
+ if (isZodSchema(schema)) {
290
+ const jsonSchema = zodToGenerativeAIParameters(schema);
291
+ tools = [
292
+ {
293
+ functionDeclarations: [
294
+ {
295
+ name: functionName,
296
+ description: jsonSchema.description ?? "A function available to call.",
297
+ parameters: jsonSchema,
298
+ },
299
+ ],
300
+ },
301
+ ];
302
+ outputParser = new GoogleGenerativeAIToolsOutputParser({
303
+ returnSingle: true,
304
+ keyName: functionName,
305
+ zodSchema: schema,
306
+ });
307
+ }
308
+ else {
309
+ let geminiFunctionDefinition;
310
+ if (typeof schema.name === "string" &&
311
+ typeof schema.parameters === "object" &&
312
+ schema.parameters != null) {
313
+ geminiFunctionDefinition = schema;
314
+ functionName = schema.name;
315
+ }
316
+ else {
317
+ geminiFunctionDefinition = {
318
+ name: functionName,
319
+ description: schema.description ?? "",
320
+ parameters: schema,
321
+ };
322
+ }
323
+ tools = [
324
+ {
325
+ functionDeclarations: [geminiFunctionDefinition],
326
+ },
327
+ ];
328
+ outputParser = new GoogleGenerativeAIToolsOutputParser({
329
+ returnSingle: true,
330
+ keyName: functionName,
331
+ });
332
+ }
333
+ const llm = this.bind({
334
+ tools,
335
+ });
336
+ if (!includeRaw) {
337
+ return llm.pipe(outputParser).withConfig({
338
+ runName: "ChatGoogleGenerativeAIStructuredOutput",
339
+ });
340
+ }
341
+ const parserAssign = RunnablePassthrough.assign({
342
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
343
+ parsed: (input, config) => outputParser.invoke(input.raw, config),
344
+ });
345
+ const parserNone = RunnablePassthrough.assign({
346
+ parsed: () => null,
347
+ });
348
+ const parsedWithFallback = parserAssign.withFallbacks({
349
+ fallbacks: [parserNone],
350
+ });
351
+ return RunnableSequence.from([
352
+ {
353
+ raw: llm,
354
+ },
355
+ parsedWithFallback,
356
+ ]).withConfig({
357
+ runName: "StructuredOutputRunnable",
358
+ });
359
+ }
253
360
  }
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GoogleGenerativeAIToolsOutputParser = void 0;
4
+ const output_parsers_1 = require("@langchain/core/output_parsers");
5
+ class GoogleGenerativeAIToolsOutputParser extends output_parsers_1.BaseLLMOutputParser {
6
+ static lc_name() {
7
+ return "GoogleGenerativeAIToolsOutputParser";
8
+ }
9
+ constructor(params) {
10
+ super(params);
11
+ Object.defineProperty(this, "lc_namespace", {
12
+ enumerable: true,
13
+ configurable: true,
14
+ writable: true,
15
+ value: ["langchain", "google_genai", "output_parsers"]
16
+ });
17
+ Object.defineProperty(this, "returnId", {
18
+ enumerable: true,
19
+ configurable: true,
20
+ writable: true,
21
+ value: false
22
+ });
23
+ /** The type of tool calls to return. */
24
+ Object.defineProperty(this, "keyName", {
25
+ enumerable: true,
26
+ configurable: true,
27
+ writable: true,
28
+ value: void 0
29
+ });
30
+ /** Whether to return only the first tool call. */
31
+ Object.defineProperty(this, "returnSingle", {
32
+ enumerable: true,
33
+ configurable: true,
34
+ writable: true,
35
+ value: false
36
+ });
37
+ Object.defineProperty(this, "zodSchema", {
38
+ enumerable: true,
39
+ configurable: true,
40
+ writable: true,
41
+ value: void 0
42
+ });
43
+ this.keyName = params.keyName;
44
+ this.returnSingle = params.returnSingle ?? this.returnSingle;
45
+ this.zodSchema = params.zodSchema;
46
+ }
47
+ async _validateResult(result) {
48
+ if (this.zodSchema === undefined) {
49
+ return result;
50
+ }
51
+ const zodParsedResult = await this.zodSchema.safeParseAsync(result);
52
+ if (zodParsedResult.success) {
53
+ return zodParsedResult.data;
54
+ }
55
+ else {
56
+ throw new output_parsers_1.OutputParserException(`Failed to parse. Text: "${JSON.stringify(result, null, 2)}". Error: ${JSON.stringify(zodParsedResult.error.errors)}`, JSON.stringify(result, null, 2));
57
+ }
58
+ }
59
+ async parseResult(generations) {
60
+ const tools = generations.flatMap((generation) => {
61
+ const { message } = generation;
62
+ if (!("tool_calls" in message) || !Array.isArray(message.tool_calls)) {
63
+ return [];
64
+ }
65
+ return message.tool_calls;
66
+ });
67
+ if (tools[0] === undefined) {
68
+ throw new Error("No parseable tool calls provided to GoogleGenerativeAIToolsOutputParser.");
69
+ }
70
+ const [tool] = tools;
71
+ const validatedResult = await this._validateResult(tool.args);
72
+ return validatedResult;
73
+ }
74
+ }
75
+ exports.GoogleGenerativeAIToolsOutputParser = GoogleGenerativeAIToolsOutputParser;
@@ -0,0 +1,20 @@
1
+ import type { z } from "zod";
2
+ import { BaseLLMOutputParser } from "@langchain/core/output_parsers";
3
+ import { JsonOutputKeyToolsParserParams } from "@langchain/core/output_parsers/openai_tools";
4
+ import { ChatGeneration } from "@langchain/core/outputs";
5
+ interface GoogleGenerativeAIToolsOutputParserParams<T extends Record<string, any>> extends JsonOutputKeyToolsParserParams<T> {
6
+ }
7
+ export declare class GoogleGenerativeAIToolsOutputParser<T extends Record<string, any> = Record<string, any>> extends BaseLLMOutputParser<T> {
8
+ static lc_name(): string;
9
+ lc_namespace: string[];
10
+ returnId: boolean;
11
+ /** The type of tool calls to return. */
12
+ keyName: string;
13
+ /** Whether to return only the first tool call. */
14
+ returnSingle: boolean;
15
+ zodSchema?: z.ZodType<T>;
16
+ constructor(params: GoogleGenerativeAIToolsOutputParserParams<T>);
17
+ protected _validateResult(result: unknown): Promise<T>;
18
+ parseResult(generations: ChatGeneration[]): Promise<T>;
19
+ }
20
+ export {};
@@ -0,0 +1,71 @@
1
+ import { BaseLLMOutputParser, OutputParserException, } from "@langchain/core/output_parsers";
2
+ export class GoogleGenerativeAIToolsOutputParser extends BaseLLMOutputParser {
3
+ static lc_name() {
4
+ return "GoogleGenerativeAIToolsOutputParser";
5
+ }
6
+ constructor(params) {
7
+ super(params);
8
+ Object.defineProperty(this, "lc_namespace", {
9
+ enumerable: true,
10
+ configurable: true,
11
+ writable: true,
12
+ value: ["langchain", "google_genai", "output_parsers"]
13
+ });
14
+ Object.defineProperty(this, "returnId", {
15
+ enumerable: true,
16
+ configurable: true,
17
+ writable: true,
18
+ value: false
19
+ });
20
+ /** The type of tool calls to return. */
21
+ Object.defineProperty(this, "keyName", {
22
+ enumerable: true,
23
+ configurable: true,
24
+ writable: true,
25
+ value: void 0
26
+ });
27
+ /** Whether to return only the first tool call. */
28
+ Object.defineProperty(this, "returnSingle", {
29
+ enumerable: true,
30
+ configurable: true,
31
+ writable: true,
32
+ value: false
33
+ });
34
+ Object.defineProperty(this, "zodSchema", {
35
+ enumerable: true,
36
+ configurable: true,
37
+ writable: true,
38
+ value: void 0
39
+ });
40
+ this.keyName = params.keyName;
41
+ this.returnSingle = params.returnSingle ?? this.returnSingle;
42
+ this.zodSchema = params.zodSchema;
43
+ }
44
+ async _validateResult(result) {
45
+ if (this.zodSchema === undefined) {
46
+ return result;
47
+ }
48
+ const zodParsedResult = await this.zodSchema.safeParseAsync(result);
49
+ if (zodParsedResult.success) {
50
+ return zodParsedResult.data;
51
+ }
52
+ else {
53
+ throw new OutputParserException(`Failed to parse. Text: "${JSON.stringify(result, null, 2)}". Error: ${JSON.stringify(zodParsedResult.error.errors)}`, JSON.stringify(result, null, 2));
54
+ }
55
+ }
56
+ async parseResult(generations) {
57
+ const tools = generations.flatMap((generation) => {
58
+ const { message } = generation;
59
+ if (!("tool_calls" in message) || !Array.isArray(message.tool_calls)) {
60
+ return [];
61
+ }
62
+ return message.tool_calls;
63
+ });
64
+ if (tools[0] === undefined) {
65
+ throw new Error("No parseable tool calls provided to GoogleGenerativeAIToolsOutputParser.");
66
+ }
67
+ const [tool] = tools;
68
+ const validatedResult = await this._validateResult(tool.args);
69
+ return validatedResult;
70
+ }
71
+ }
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.convertResponseContentToChatGenerationChunk = exports.mapGenerateContentResultToChatResult = exports.convertBaseMessagesToContent = exports.convertMessageContentToParts = exports.convertAuthorToRole = exports.getMessageAuthor = void 0;
3
+ exports.convertToGenerativeAITools = exports.convertResponseContentToChatGenerationChunk = exports.mapGenerateContentResultToChatResult = exports.convertBaseMessagesToContent = exports.convertMessageContentToParts = exports.convertAuthorToRole = exports.getMessageAuthor = void 0;
4
4
  const messages_1 = require("@langchain/core/messages");
5
5
  const outputs_1 = require("@langchain/core/outputs");
6
+ const function_calling_1 = require("@langchain/core/utils/function_calling");
7
+ const zod_to_genai_parameters_js_1 = require("./zod_to_genai_parameters.cjs");
6
8
  function getMessageAuthor(message) {
7
9
  const type = message._getType();
8
10
  if (messages_1.ChatMessage.isInstance(message)) {
@@ -142,6 +144,7 @@ function mapGenerateContentResultToChatResult(response) {
142
144
  },
143
145
  };
144
146
  }
147
+ const functionCalls = response.functionCalls();
145
148
  const [candidate] = response.candidates;
146
149
  const { content, ...generationInfo } = candidate;
147
150
  const text = content?.parts[0]?.text ?? "";
@@ -149,8 +152,10 @@ function mapGenerateContentResultToChatResult(response) {
149
152
  text,
150
153
  message: new messages_1.AIMessage({
151
154
  content: text,
152
- name: !content ? undefined : content.role,
153
- additional_kwargs: generationInfo,
155
+ tool_calls: functionCalls,
156
+ additional_kwargs: {
157
+ ...generationInfo,
158
+ },
154
159
  }),
155
160
  generationInfo,
156
161
  };
@@ -179,3 +184,25 @@ function convertResponseContentToChatGenerationChunk(response) {
179
184
  });
180
185
  }
181
186
  exports.convertResponseContentToChatGenerationChunk = convertResponseContentToChatGenerationChunk;
187
+ function convertToGenerativeAITools(structuredTools) {
188
+ if (structuredTools.every((tool) => "functionDeclarations" in tool &&
189
+ Array.isArray(tool.functionDeclarations))) {
190
+ return structuredTools;
191
+ }
192
+ return [
193
+ {
194
+ functionDeclarations: structuredTools.map((structuredTool) => {
195
+ if ((0, function_calling_1.isStructuredTool)(structuredTool)) {
196
+ const jsonSchema = (0, zod_to_genai_parameters_js_1.zodToGenerativeAIParameters)(structuredTool.schema);
197
+ return {
198
+ name: structuredTool.name,
199
+ description: structuredTool.description,
200
+ parameters: jsonSchema,
201
+ };
202
+ }
203
+ return structuredTool;
204
+ }),
205
+ },
206
+ ];
207
+ }
208
+ exports.convertToGenerativeAITools = convertToGenerativeAITools;
@@ -1,6 +1,7 @@
1
- import { EnhancedGenerateContentResponse, Content, Part } from "@google/generative-ai";
1
+ import { EnhancedGenerateContentResponse, Content, Part, type FunctionDeclarationsTool as GoogleGenerativeAIFunctionDeclarationsTool } from "@google/generative-ai";
2
2
  import { BaseMessage, MessageContent } from "@langchain/core/messages";
3
3
  import { ChatGenerationChunk, ChatResult } from "@langchain/core/outputs";
4
+ import { StructuredToolInterface } from "@langchain/core/tools";
4
5
  export declare function getMessageAuthor(message: BaseMessage): string;
5
6
  /**
6
7
  * Maps a message type to a Google Generative AI chat author.
@@ -13,3 +14,4 @@ export declare function convertMessageContentToParts(content: MessageContent, is
13
14
  export declare function convertBaseMessagesToContent(messages: BaseMessage[], isMultimodalModel: boolean): Content[];
14
15
  export declare function mapGenerateContentResultToChatResult(response: EnhancedGenerateContentResponse): ChatResult;
15
16
  export declare function convertResponseContentToChatGenerationChunk(response: EnhancedGenerateContentResponse): ChatGenerationChunk | null;
17
+ export declare function convertToGenerativeAITools(structuredTools: (StructuredToolInterface | Record<string, unknown>)[]): GoogleGenerativeAIFunctionDeclarationsTool[];
@@ -1,5 +1,7 @@
1
1
  import { AIMessage, AIMessageChunk, ChatMessage, isBaseMessage, } from "@langchain/core/messages";
2
2
  import { ChatGenerationChunk, } from "@langchain/core/outputs";
3
+ import { isStructuredTool } from "@langchain/core/utils/function_calling";
4
+ import { zodToGenerativeAIParameters } from "./zod_to_genai_parameters.js";
3
5
  export function getMessageAuthor(message) {
4
6
  const type = message._getType();
5
7
  if (ChatMessage.isInstance(message)) {
@@ -135,6 +137,7 @@ export function mapGenerateContentResultToChatResult(response) {
135
137
  },
136
138
  };
137
139
  }
140
+ const functionCalls = response.functionCalls();
138
141
  const [candidate] = response.candidates;
139
142
  const { content, ...generationInfo } = candidate;
140
143
  const text = content?.parts[0]?.text ?? "";
@@ -142,8 +145,10 @@ export function mapGenerateContentResultToChatResult(response) {
142
145
  text,
143
146
  message: new AIMessage({
144
147
  content: text,
145
- name: !content ? undefined : content.role,
146
- additional_kwargs: generationInfo,
148
+ tool_calls: functionCalls,
149
+ additional_kwargs: {
150
+ ...generationInfo,
151
+ },
147
152
  }),
148
153
  generationInfo,
149
154
  };
@@ -170,3 +175,24 @@ export function convertResponseContentToChatGenerationChunk(response) {
170
175
  generationInfo,
171
176
  });
172
177
  }
178
+ export function convertToGenerativeAITools(structuredTools) {
179
+ if (structuredTools.every((tool) => "functionDeclarations" in tool &&
180
+ Array.isArray(tool.functionDeclarations))) {
181
+ return structuredTools;
182
+ }
183
+ return [
184
+ {
185
+ functionDeclarations: structuredTools.map((structuredTool) => {
186
+ if (isStructuredTool(structuredTool)) {
187
+ const jsonSchema = zodToGenerativeAIParameters(structuredTool.schema);
188
+ return {
189
+ name: structuredTool.name,
190
+ description: structuredTool.description,
191
+ parameters: jsonSchema,
192
+ };
193
+ }
194
+ return structuredTool;
195
+ }),
196
+ },
197
+ ];
198
+ }
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ /* eslint-disable @typescript-eslint/no-unused-vars */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.zodToGenerativeAIParameters = void 0;
5
+ const zod_to_json_schema_1 = require("zod-to-json-schema");
6
+ function removeAdditionalProperties(schema) {
7
+ const updatedSchema = { ...schema };
8
+ if (Object.hasOwn(updatedSchema, "additionalProperties")) {
9
+ delete updatedSchema.additionalProperties;
10
+ }
11
+ if (updatedSchema.properties) {
12
+ const keys = Object.keys(updatedSchema.properties);
13
+ removeProperties(updatedSchema.properties, keys, 0);
14
+ }
15
+ return updatedSchema;
16
+ }
17
+ function removeProperties(properties, keys, index) {
18
+ if (index >= keys.length || !properties) {
19
+ return;
20
+ }
21
+ const key = keys[index];
22
+ // eslint-disable-next-line no-param-reassign
23
+ properties[key] = removeAdditionalProperties(properties[key]);
24
+ removeProperties(properties, keys, index + 1);
25
+ }
26
+ function zodToGenerativeAIParameters(
27
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
+ zodObj) {
29
+ // GenerativeAI doesn't accept either the $schema or additionalProperties
30
+ // attributes, so we need to explicitly remove them.
31
+ const jsonSchema = removeAdditionalProperties((0, zod_to_json_schema_1.zodToJsonSchema)(zodObj));
32
+ const { $schema, ...rest } = jsonSchema;
33
+ return rest;
34
+ }
35
+ exports.zodToGenerativeAIParameters = zodToGenerativeAIParameters;
@@ -0,0 +1,11 @@
1
+ import type { z } from "zod";
2
+ import { type FunctionDeclarationSchema as GenerativeAIFunctionDeclarationSchema, FunctionDeclarationSchemaType } from "@google/generative-ai";
3
+ export interface GenerativeAIJsonSchema extends Record<string, unknown> {
4
+ properties?: Record<string, GenerativeAIJsonSchema>;
5
+ type: FunctionDeclarationSchemaType;
6
+ }
7
+ export interface GenerativeAIJsonSchemaDirty extends GenerativeAIJsonSchema {
8
+ properties?: Record<string, GenerativeAIJsonSchemaDirty>;
9
+ additionalProperties?: boolean;
10
+ }
11
+ export declare function zodToGenerativeAIParameters(zodObj: z.ZodType<any>): GenerativeAIFunctionDeclarationSchema;
@@ -0,0 +1,31 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */
2
+ import { zodToJsonSchema } from "zod-to-json-schema";
3
+ function removeAdditionalProperties(schema) {
4
+ const updatedSchema = { ...schema };
5
+ if (Object.hasOwn(updatedSchema, "additionalProperties")) {
6
+ delete updatedSchema.additionalProperties;
7
+ }
8
+ if (updatedSchema.properties) {
9
+ const keys = Object.keys(updatedSchema.properties);
10
+ removeProperties(updatedSchema.properties, keys, 0);
11
+ }
12
+ return updatedSchema;
13
+ }
14
+ function removeProperties(properties, keys, index) {
15
+ if (index >= keys.length || !properties) {
16
+ return;
17
+ }
18
+ const key = keys[index];
19
+ // eslint-disable-next-line no-param-reassign
20
+ properties[key] = removeAdditionalProperties(properties[key]);
21
+ removeProperties(properties, keys, index + 1);
22
+ }
23
+ export function zodToGenerativeAIParameters(
24
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
25
+ zodObj) {
26
+ // GenerativeAI doesn't accept either the $schema or additionalProperties
27
+ // attributes, so we need to explicitly remove them.
28
+ const jsonSchema = removeAdditionalProperties(zodToJsonSchema(zodObj));
29
+ const { $schema, ...rest } = jsonSchema;
30
+ return rest;
31
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/google-genai",
3
- "version": "0.0.14",
3
+ "version": "0.0.16",
4
4
  "description": "Sample integration for LangChain.js",
5
5
  "type": "module",
6
6
  "engines": {
@@ -26,10 +26,10 @@
26
26
  "lint:fix": "yarn lint:eslint --fix && yarn lint:dpdm",
27
27
  "clean": "rm -rf dist/ && NODE_OPTIONS=--max-old-space-size=4096 yarn lc-build --config ./langchain.config.js --create-entrypoints --pre",
28
28
  "prepack": "yarn build",
29
- "test": "NODE_OPTIONS=--experimental-vm-modules jest --testPathIgnorePatterns=\\.int\\.test.ts --testTimeout 30000 --maxWorkers=50%",
30
- "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch --testPathIgnorePatterns=\\.int\\.test.ts",
31
- "test:single": "NODE_OPTIONS=--experimental-vm-modules yarn run jest --config jest.config.cjs --testTimeout 100000",
32
- "test:int": "NODE_OPTIONS=--experimental-vm-modules jest --testPathPattern=\\.int\\.test.ts --testTimeout 100000 --maxWorkers=50%",
29
+ "test": "yarn build:deps && NODE_OPTIONS=--experimental-vm-modules jest --testPathIgnorePatterns=\\.int\\.test.ts --testTimeout 30000 --maxWorkers=50%",
30
+ "test:watch": "yarn build:deps && NODE_OPTIONS=--experimental-vm-modules jest --watch --testPathIgnorePatterns=\\.int\\.test.ts",
31
+ "test:single": "yarn build:deps && NODE_OPTIONS=--experimental-vm-modules yarn run jest --config jest.config.cjs --testTimeout 100000",
32
+ "test:int": "yarn build:deps && NODE_OPTIONS=--experimental-vm-modules jest --testPathPattern=\\.int\\.test.ts --testTimeout 100000 --maxWorkers=50%",
33
33
  "format": "prettier --config .prettierrc --write \"src\"",
34
34
  "format:check": "prettier --config .prettierrc --check \"src\"",
35
35
  "move-cjs-to-dist": "yarn lc-build --config ./langchain.config.js --move-cjs-dist",
@@ -40,11 +40,12 @@
40
40
  "license": "MIT",
41
41
  "dependencies": {
42
42
  "@google/generative-ai": "^0.7.0",
43
- "@langchain/core": ">0.1.5 <0.3.0"
43
+ "@langchain/core": ">0.1.5 <0.3.0",
44
+ "zod-to-json-schema": "^3.22.4"
44
45
  },
45
46
  "devDependencies": {
46
47
  "@jest/globals": "^29.5.0",
47
- "@langchain/scripts": "~0.0",
48
+ "@langchain/scripts": "~0.0.14",
48
49
  "@swc/core": "^1.3.90",
49
50
  "@swc/jest": "^0.2.29",
50
51
  "@tsconfig/recommended": "^1.0.3",
@@ -65,7 +66,8 @@
65
66
  "release-it": "^15.10.1",
66
67
  "rollup": "^4.5.2",
67
68
  "ts-jest": "^29.1.0",
68
- "typescript": "<5.2.0"
69
+ "typescript": "<5.2.0",
70
+ "zod": "^3.22.4"
69
71
  },
70
72
  "publishConfig": {
71
73
  "access": "public"