@langchain/google-genai 0.1.3 → 0.1.5

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.
@@ -442,6 +442,12 @@ class ChatGoogleGenerativeAI extends chat_models_1.BaseChatModel {
442
442
  writable: true,
443
443
  value: true
444
444
  });
445
+ Object.defineProperty(this, "convertSystemMessageToHumanContent", {
446
+ enumerable: true,
447
+ configurable: true,
448
+ writable: true,
449
+ value: void 0
450
+ });
445
451
  Object.defineProperty(this, "client", {
446
452
  enumerable: true,
447
453
  configurable: true,
@@ -506,6 +512,35 @@ class ChatGoogleGenerativeAI extends chat_models_1.BaseChatModel {
506
512
  });
507
513
  this.streamUsage = fields?.streamUsage ?? this.streamUsage;
508
514
  }
515
+ useCachedContent(cachedContent, modelParams, requestOptions) {
516
+ if (!this.apiKey)
517
+ return;
518
+ this.client = new generative_ai_1.GoogleGenerativeAI(this.apiKey).getGenerativeModelFromCachedContent(cachedContent, modelParams, requestOptions);
519
+ }
520
+ get useSystemInstruction() {
521
+ return typeof this.convertSystemMessageToHumanContent === "boolean"
522
+ ? !this.convertSystemMessageToHumanContent
523
+ : this.computeUseSystemInstruction;
524
+ }
525
+ get computeUseSystemInstruction() {
526
+ // This works on models from April 2024 and later
527
+ // Vertex AI: gemini-1.5-pro and gemini-1.0-002 and later
528
+ // AI Studio: gemini-1.5-pro-latest
529
+ if (this.modelName === "gemini-1.0-pro-001") {
530
+ return false;
531
+ }
532
+ else if (this.modelName.startsWith("gemini-pro-vision")) {
533
+ return false;
534
+ }
535
+ else if (this.modelName.startsWith("gemini-1.0-pro-vision")) {
536
+ return false;
537
+ }
538
+ else if (this.modelName === "gemini-pro") {
539
+ // on AI Studio gemini-pro is still pointing at gemini-1.0-pro-001
540
+ return false;
541
+ }
542
+ return true;
543
+ }
509
544
  getLsParams(options) {
510
545
  return {
511
546
  ls_provider: "google_genai",
@@ -540,7 +575,13 @@ class ChatGoogleGenerativeAI extends chat_models_1.BaseChatModel {
540
575
  };
541
576
  }
542
577
  async _generate(messages, options, runManager) {
543
- const prompt = (0, common_js_1.convertBaseMessagesToContent)(messages, this._isMultimodalModel);
578
+ const prompt = (0, common_js_1.convertBaseMessagesToContent)(messages, this._isMultimodalModel, this.useSystemInstruction);
579
+ let actualPrompt = prompt;
580
+ if (prompt[0].role === "system") {
581
+ const [systemInstruction] = prompt;
582
+ this.client.systemInstruction = systemInstruction;
583
+ actualPrompt = prompt.slice(1);
584
+ }
544
585
  const parameters = this.invocationParams(options);
545
586
  // Handle streaming
546
587
  if (this.streaming) {
@@ -563,7 +604,7 @@ class ChatGoogleGenerativeAI extends chat_models_1.BaseChatModel {
563
604
  }
564
605
  const res = await this.completionWithRetry({
565
606
  ...parameters,
566
- contents: prompt,
607
+ contents: actualPrompt,
567
608
  });
568
609
  let usageMetadata;
569
610
  if ("usageMetadata" in res.response) {
@@ -581,11 +622,17 @@ class ChatGoogleGenerativeAI extends chat_models_1.BaseChatModel {
581
622
  return generationResult;
582
623
  }
583
624
  async *_streamResponseChunks(messages, options, runManager) {
584
- const prompt = (0, common_js_1.convertBaseMessagesToContent)(messages, this._isMultimodalModel);
625
+ const prompt = (0, common_js_1.convertBaseMessagesToContent)(messages, this._isMultimodalModel, this.useSystemInstruction);
626
+ let actualPrompt = prompt;
627
+ if (prompt[0].role === "system") {
628
+ const [systemInstruction] = prompt;
629
+ this.client.systemInstruction = systemInstruction;
630
+ actualPrompt = prompt.slice(1);
631
+ }
585
632
  const parameters = this.invocationParams(options);
586
633
  const request = {
587
634
  ...parameters,
588
- contents: prompt,
635
+ contents: actualPrompt,
589
636
  };
590
637
  const stream = await this.caller.callWithOptions({ signal: options?.signal }, async () => {
591
638
  const { stream } = await this.client.generateContentStream(request);
@@ -702,6 +749,7 @@ class ChatGoogleGenerativeAI extends chat_models_1.BaseChatModel {
702
749
  }
703
750
  const llm = this.bind({
704
751
  tools,
752
+ tool_choice: functionName,
705
753
  });
706
754
  if (!includeRaw) {
707
755
  return llm.pipe(outputParser).withConfig({
@@ -1,4 +1,4 @@
1
- import { GenerateContentRequest, SafetySetting, Part as GenerativeAIPart } from "@google/generative-ai";
1
+ import { GenerateContentRequest, SafetySetting, Part as GenerativeAIPart, ModelParams, RequestOptions, type CachedContent } from "@google/generative-ai";
2
2
  import { CallbackManagerForLLMRun } from "@langchain/core/callbacks/manager";
3
3
  import { AIMessageChunk, BaseMessage } from "@langchain/core/messages";
4
4
  import { ChatGenerationChunk, ChatResult } from "@langchain/core/outputs";
@@ -120,6 +120,14 @@ export interface GoogleGenerativeAIChatInput extends BaseChatModelParams, Pick<G
120
120
  * @default false
121
121
  */
122
122
  json?: boolean;
123
+ /**
124
+ * Whether or not model supports system instructions.
125
+ * The following models support system instructions:
126
+ * - All Gemini 1.5 Pro model versions
127
+ * - All Gemini 1.5 Flash model versions
128
+ * - Gemini 1.0 Pro version gemini-1.0-pro-002
129
+ */
130
+ convertSystemMessageToHumanContent?: boolean | undefined;
123
131
  }
124
132
  /**
125
133
  * Google Generative AI chat model integration.
@@ -477,9 +485,13 @@ export declare class ChatGoogleGenerativeAI extends BaseChatModel<GoogleGenerati
477
485
  apiKey?: string;
478
486
  streaming: boolean;
479
487
  streamUsage: boolean;
488
+ convertSystemMessageToHumanContent: boolean | undefined;
480
489
  private client;
481
490
  get _isMultimodalModel(): boolean;
482
491
  constructor(fields?: GoogleGenerativeAIChatInput);
492
+ useCachedContent(cachedContent: CachedContent, modelParams?: ModelParams, requestOptions?: RequestOptions): void;
493
+ get useSystemInstruction(): boolean;
494
+ get computeUseSystemInstruction(): boolean;
483
495
  getLsParams(options: this["ParsedCallOptions"]): LangSmithParams;
484
496
  _combineLLMOutput(): never[];
485
497
  _llmType(): string;
@@ -439,6 +439,12 @@ export class ChatGoogleGenerativeAI extends BaseChatModel {
439
439
  writable: true,
440
440
  value: true
441
441
  });
442
+ Object.defineProperty(this, "convertSystemMessageToHumanContent", {
443
+ enumerable: true,
444
+ configurable: true,
445
+ writable: true,
446
+ value: void 0
447
+ });
442
448
  Object.defineProperty(this, "client", {
443
449
  enumerable: true,
444
450
  configurable: true,
@@ -503,6 +509,35 @@ export class ChatGoogleGenerativeAI extends BaseChatModel {
503
509
  });
504
510
  this.streamUsage = fields?.streamUsage ?? this.streamUsage;
505
511
  }
512
+ useCachedContent(cachedContent, modelParams, requestOptions) {
513
+ if (!this.apiKey)
514
+ return;
515
+ this.client = new GenerativeAI(this.apiKey).getGenerativeModelFromCachedContent(cachedContent, modelParams, requestOptions);
516
+ }
517
+ get useSystemInstruction() {
518
+ return typeof this.convertSystemMessageToHumanContent === "boolean"
519
+ ? !this.convertSystemMessageToHumanContent
520
+ : this.computeUseSystemInstruction;
521
+ }
522
+ get computeUseSystemInstruction() {
523
+ // This works on models from April 2024 and later
524
+ // Vertex AI: gemini-1.5-pro and gemini-1.0-002 and later
525
+ // AI Studio: gemini-1.5-pro-latest
526
+ if (this.modelName === "gemini-1.0-pro-001") {
527
+ return false;
528
+ }
529
+ else if (this.modelName.startsWith("gemini-pro-vision")) {
530
+ return false;
531
+ }
532
+ else if (this.modelName.startsWith("gemini-1.0-pro-vision")) {
533
+ return false;
534
+ }
535
+ else if (this.modelName === "gemini-pro") {
536
+ // on AI Studio gemini-pro is still pointing at gemini-1.0-pro-001
537
+ return false;
538
+ }
539
+ return true;
540
+ }
506
541
  getLsParams(options) {
507
542
  return {
508
543
  ls_provider: "google_genai",
@@ -537,7 +572,13 @@ export class ChatGoogleGenerativeAI extends BaseChatModel {
537
572
  };
538
573
  }
539
574
  async _generate(messages, options, runManager) {
540
- const prompt = convertBaseMessagesToContent(messages, this._isMultimodalModel);
575
+ const prompt = convertBaseMessagesToContent(messages, this._isMultimodalModel, this.useSystemInstruction);
576
+ let actualPrompt = prompt;
577
+ if (prompt[0].role === "system") {
578
+ const [systemInstruction] = prompt;
579
+ this.client.systemInstruction = systemInstruction;
580
+ actualPrompt = prompt.slice(1);
581
+ }
541
582
  const parameters = this.invocationParams(options);
542
583
  // Handle streaming
543
584
  if (this.streaming) {
@@ -560,7 +601,7 @@ export class ChatGoogleGenerativeAI extends BaseChatModel {
560
601
  }
561
602
  const res = await this.completionWithRetry({
562
603
  ...parameters,
563
- contents: prompt,
604
+ contents: actualPrompt,
564
605
  });
565
606
  let usageMetadata;
566
607
  if ("usageMetadata" in res.response) {
@@ -578,11 +619,17 @@ export class ChatGoogleGenerativeAI extends BaseChatModel {
578
619
  return generationResult;
579
620
  }
580
621
  async *_streamResponseChunks(messages, options, runManager) {
581
- const prompt = convertBaseMessagesToContent(messages, this._isMultimodalModel);
622
+ const prompt = convertBaseMessagesToContent(messages, this._isMultimodalModel, this.useSystemInstruction);
623
+ let actualPrompt = prompt;
624
+ if (prompt[0].role === "system") {
625
+ const [systemInstruction] = prompt;
626
+ this.client.systemInstruction = systemInstruction;
627
+ actualPrompt = prompt.slice(1);
628
+ }
582
629
  const parameters = this.invocationParams(options);
583
630
  const request = {
584
631
  ...parameters,
585
- contents: prompt,
632
+ contents: actualPrompt,
586
633
  };
587
634
  const stream = await this.caller.callWithOptions({ signal: options?.signal }, async () => {
588
635
  const { stream } = await this.client.generateContentStream(request);
@@ -699,6 +746,7 @@ export class ChatGoogleGenerativeAI extends BaseChatModel {
699
746
  }
700
747
  const llm = this.bind({
701
748
  tools,
749
+ tool_choice: functionName,
702
750
  });
703
751
  if (!includeRaw) {
704
752
  return llm.pipe(outputParser).withConfig({
@@ -33,6 +33,7 @@ function convertAuthorToRole(author) {
33
33
  case "model": // getMessageAuthor returns message.name. code ex.: return message.name ?? type;
34
34
  return "model";
35
35
  case "system":
36
+ return "system";
36
37
  case "human":
37
38
  return "user";
38
39
  case "tool":
@@ -144,7 +145,7 @@ function convertMessageContentToParts(message, isMultimodalModel) {
144
145
  return [...messageParts, ...functionCalls, ...functionResponses];
145
146
  }
146
147
  exports.convertMessageContentToParts = convertMessageContentToParts;
147
- function convertBaseMessagesToContent(messages, isMultimodalModel) {
148
+ function convertBaseMessagesToContent(messages, isMultimodalModel, convertSystemMessageToHumanContent = false) {
148
149
  return messages.reduce((acc, message, index) => {
149
150
  if (!(0, messages_1.isBaseMessage)(message)) {
150
151
  throw new Error("Unsupported message input");
@@ -173,7 +174,8 @@ function convertBaseMessagesToContent(messages, isMultimodalModel) {
173
174
  };
174
175
  }
175
176
  let actualRole = role;
176
- if (actualRole === "function") {
177
+ if (actualRole === "function" ||
178
+ (actualRole === "system" && !convertSystemMessageToHumanContent)) {
177
179
  // GenerativeAI API will throw an error if the role is not "user" or "model."
178
180
  actualRole = "user";
179
181
  }
@@ -182,7 +184,7 @@ function convertBaseMessagesToContent(messages, isMultimodalModel) {
182
184
  parts,
183
185
  };
184
186
  return {
185
- mergeWithPreviousContent: author === "system",
187
+ mergeWithPreviousContent: author === "system" && !convertSystemMessageToHumanContent,
186
188
  content: [...acc.content, content],
187
189
  };
188
190
  }, { content: [], mergeWithPreviousContent: false }).content;
@@ -11,7 +11,7 @@ export declare function getMessageAuthor(message: BaseMessage): string;
11
11
  */
12
12
  export declare function convertAuthorToRole(author: string): (typeof POSSIBLE_ROLES)[number];
13
13
  export declare function convertMessageContentToParts(message: BaseMessage, isMultimodalModel: boolean): Part[];
14
- export declare function convertBaseMessagesToContent(messages: BaseMessage[], isMultimodalModel: boolean): Content[];
14
+ export declare function convertBaseMessagesToContent(messages: BaseMessage[], isMultimodalModel: boolean, convertSystemMessageToHumanContent?: boolean): Content[];
15
15
  export declare function mapGenerateContentResultToChatResult(response: EnhancedGenerateContentResponse, extra?: {
16
16
  usageMetadata: UsageMetadata | undefined;
17
17
  }): ChatResult;
@@ -29,6 +29,7 @@ export function convertAuthorToRole(author) {
29
29
  case "model": // getMessageAuthor returns message.name. code ex.: return message.name ?? type;
30
30
  return "model";
31
31
  case "system":
32
+ return "system";
32
33
  case "human":
33
34
  return "user";
34
35
  case "tool":
@@ -138,7 +139,7 @@ export function convertMessageContentToParts(message, isMultimodalModel) {
138
139
  }
139
140
  return [...messageParts, ...functionCalls, ...functionResponses];
140
141
  }
141
- export function convertBaseMessagesToContent(messages, isMultimodalModel) {
142
+ export function convertBaseMessagesToContent(messages, isMultimodalModel, convertSystemMessageToHumanContent = false) {
142
143
  return messages.reduce((acc, message, index) => {
143
144
  if (!isBaseMessage(message)) {
144
145
  throw new Error("Unsupported message input");
@@ -167,7 +168,8 @@ export function convertBaseMessagesToContent(messages, isMultimodalModel) {
167
168
  };
168
169
  }
169
170
  let actualRole = role;
170
- if (actualRole === "function") {
171
+ if (actualRole === "function" ||
172
+ (actualRole === "system" && !convertSystemMessageToHumanContent)) {
171
173
  // GenerativeAI API will throw an error if the role is not "user" or "model."
172
174
  actualRole = "user";
173
175
  }
@@ -176,7 +178,7 @@ export function convertBaseMessagesToContent(messages, isMultimodalModel) {
176
178
  parts,
177
179
  };
178
180
  return {
179
- mergeWithPreviousContent: author === "system",
181
+ mergeWithPreviousContent: author === "system" && !convertSystemMessageToHumanContent,
180
182
  content: [...acc.content, content],
181
183
  };
182
184
  }, { content: [], mergeWithPreviousContent: false }).content;
@@ -3,7 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.convertToolsToGenAI = void 0;
4
4
  const generative_ai_1 = require("@google/generative-ai");
5
5
  const function_calling_1 = require("@langchain/core/utils/function_calling");
6
+ const base_1 = require("@langchain/core/language_models/base");
6
7
  const common_js_1 = require("./common.cjs");
8
+ const zod_to_genai_parameters_js_1 = require("./zod_to_genai_parameters.cjs");
7
9
  function convertToolsToGenAI(tools, extra) {
8
10
  // Extract function declaration processing to a separate function
9
11
  const genAITools = processTools(tools);
@@ -24,6 +26,15 @@ function processTools(tools) {
24
26
  functionDeclarationTools.push(...convertedTool.functionDeclarations);
25
27
  }
26
28
  }
29
+ else if ((0, base_1.isOpenAITool)(tool)) {
30
+ const { functionDeclarations } = convertOpenAIToolToGenAI(tool);
31
+ if (functionDeclarations) {
32
+ functionDeclarationTools.push(...functionDeclarations);
33
+ }
34
+ else {
35
+ throw new Error("Failed to convert OpenAI structured tool to GenerativeAI tool");
36
+ }
37
+ }
27
38
  else {
28
39
  genAITools.push(tool);
29
40
  }
@@ -57,6 +68,17 @@ function processTools(tools) {
57
68
  : []),
58
69
  ];
59
70
  }
71
+ function convertOpenAIToolToGenAI(tool) {
72
+ return {
73
+ functionDeclarations: [
74
+ {
75
+ name: tool.function.name,
76
+ description: tool.function.description,
77
+ parameters: (0, zod_to_genai_parameters_js_1.removeAdditionalProperties)(tool.function.parameters),
78
+ },
79
+ ],
80
+ };
81
+ }
60
82
  function createToolConfig(genAITools, extra) {
61
83
  if (!genAITools.length || !extra)
62
84
  return undefined;
@@ -1,6 +1,8 @@
1
1
  import { FunctionCallingMode, } from "@google/generative-ai";
2
2
  import { isLangChainTool } from "@langchain/core/utils/function_calling";
3
+ import { isOpenAITool, } from "@langchain/core/language_models/base";
3
4
  import { convertToGenerativeAITools } from "./common.js";
5
+ import { removeAdditionalProperties } from "./zod_to_genai_parameters.js";
4
6
  export function convertToolsToGenAI(tools, extra) {
5
7
  // Extract function declaration processing to a separate function
6
8
  const genAITools = processTools(tools);
@@ -20,6 +22,15 @@ function processTools(tools) {
20
22
  functionDeclarationTools.push(...convertedTool.functionDeclarations);
21
23
  }
22
24
  }
25
+ else if (isOpenAITool(tool)) {
26
+ const { functionDeclarations } = convertOpenAIToolToGenAI(tool);
27
+ if (functionDeclarations) {
28
+ functionDeclarationTools.push(...functionDeclarations);
29
+ }
30
+ else {
31
+ throw new Error("Failed to convert OpenAI structured tool to GenerativeAI tool");
32
+ }
33
+ }
23
34
  else {
24
35
  genAITools.push(tool);
25
36
  }
@@ -53,6 +64,17 @@ function processTools(tools) {
53
64
  : []),
54
65
  ];
55
66
  }
67
+ function convertOpenAIToolToGenAI(tool) {
68
+ return {
69
+ functionDeclarations: [
70
+ {
71
+ name: tool.function.name,
72
+ description: tool.function.description,
73
+ parameters: removeAdditionalProperties(tool.function.parameters),
74
+ },
75
+ ],
76
+ };
77
+ }
56
78
  function createToolConfig(genAITools, extra) {
57
79
  if (!genAITools.length || !extra)
58
80
  return undefined;
@@ -11,6 +11,9 @@ obj) {
11
11
  if ("additionalProperties" in newObj) {
12
12
  delete newObj.additionalProperties;
13
13
  }
14
+ if ("$schema" in newObj) {
15
+ delete newObj.$schema;
16
+ }
14
17
  for (const key in newObj) {
15
18
  if (key in newObj) {
16
19
  if (Array.isArray(newObj[key])) {
@@ -8,6 +8,9 @@ obj) {
8
8
  if ("additionalProperties" in newObj) {
9
9
  delete newObj.additionalProperties;
10
10
  }
11
+ if ("$schema" in newObj) {
12
+ delete newObj.$schema;
13
+ }
11
14
  for (const key in newObj) {
12
15
  if (key in newObj) {
13
16
  if (Array.isArray(newObj[key])) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/google-genai",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Google Generative AI integration for LangChain.js",
5
5
  "type": "module",
6
6
  "engines": {