@langchain/google-genai 0.1.4 → 0.1.6

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.
@@ -360,7 +360,9 @@ class ChatGoogleGenerativeAI extends chat_models_1.BaseChatModel {
360
360
  };
361
361
  }
362
362
  get _isMultimodalModel() {
363
- return this.model.includes("vision") || this.model.startsWith("gemini-1.5");
363
+ return (this.model.includes("vision") ||
364
+ this.model.startsWith("gemini-1.5") ||
365
+ this.model.startsWith("gemini-2"));
364
366
  }
365
367
  constructor(fields) {
366
368
  super(fields ?? {});
@@ -442,6 +444,12 @@ class ChatGoogleGenerativeAI extends chat_models_1.BaseChatModel {
442
444
  writable: true,
443
445
  value: true
444
446
  });
447
+ Object.defineProperty(this, "convertSystemMessageToHumanContent", {
448
+ enumerable: true,
449
+ configurable: true,
450
+ writable: true,
451
+ value: void 0
452
+ });
445
453
  Object.defineProperty(this, "client", {
446
454
  enumerable: true,
447
455
  configurable: true,
@@ -506,6 +514,35 @@ class ChatGoogleGenerativeAI extends chat_models_1.BaseChatModel {
506
514
  });
507
515
  this.streamUsage = fields?.streamUsage ?? this.streamUsage;
508
516
  }
517
+ useCachedContent(cachedContent, modelParams, requestOptions) {
518
+ if (!this.apiKey)
519
+ return;
520
+ this.client = new generative_ai_1.GoogleGenerativeAI(this.apiKey).getGenerativeModelFromCachedContent(cachedContent, modelParams, requestOptions);
521
+ }
522
+ get useSystemInstruction() {
523
+ return typeof this.convertSystemMessageToHumanContent === "boolean"
524
+ ? !this.convertSystemMessageToHumanContent
525
+ : this.computeUseSystemInstruction;
526
+ }
527
+ get computeUseSystemInstruction() {
528
+ // This works on models from April 2024 and later
529
+ // Vertex AI: gemini-1.5-pro and gemini-1.0-002 and later
530
+ // AI Studio: gemini-1.5-pro-latest
531
+ if (this.modelName === "gemini-1.0-pro-001") {
532
+ return false;
533
+ }
534
+ else if (this.modelName.startsWith("gemini-pro-vision")) {
535
+ return false;
536
+ }
537
+ else if (this.modelName.startsWith("gemini-1.0-pro-vision")) {
538
+ return false;
539
+ }
540
+ else if (this.modelName === "gemini-pro") {
541
+ // on AI Studio gemini-pro is still pointing at gemini-1.0-pro-001
542
+ return false;
543
+ }
544
+ return true;
545
+ }
509
546
  getLsParams(options) {
510
547
  return {
511
548
  ls_provider: "google_genai",
@@ -540,7 +577,13 @@ class ChatGoogleGenerativeAI extends chat_models_1.BaseChatModel {
540
577
  };
541
578
  }
542
579
  async _generate(messages, options, runManager) {
543
- const prompt = (0, common_js_1.convertBaseMessagesToContent)(messages, this._isMultimodalModel);
580
+ const prompt = (0, common_js_1.convertBaseMessagesToContent)(messages, this._isMultimodalModel, this.useSystemInstruction);
581
+ let actualPrompt = prompt;
582
+ if (prompt[0].role === "system") {
583
+ const [systemInstruction] = prompt;
584
+ this.client.systemInstruction = systemInstruction;
585
+ actualPrompt = prompt.slice(1);
586
+ }
544
587
  const parameters = this.invocationParams(options);
545
588
  // Handle streaming
546
589
  if (this.streaming) {
@@ -563,7 +606,7 @@ class ChatGoogleGenerativeAI extends chat_models_1.BaseChatModel {
563
606
  }
564
607
  const res = await this.completionWithRetry({
565
608
  ...parameters,
566
- contents: prompt,
609
+ contents: actualPrompt,
567
610
  });
568
611
  let usageMetadata;
569
612
  if ("usageMetadata" in res.response) {
@@ -581,11 +624,17 @@ class ChatGoogleGenerativeAI extends chat_models_1.BaseChatModel {
581
624
  return generationResult;
582
625
  }
583
626
  async *_streamResponseChunks(messages, options, runManager) {
584
- const prompt = (0, common_js_1.convertBaseMessagesToContent)(messages, this._isMultimodalModel);
627
+ const prompt = (0, common_js_1.convertBaseMessagesToContent)(messages, this._isMultimodalModel, this.useSystemInstruction);
628
+ let actualPrompt = prompt;
629
+ if (prompt[0].role === "system") {
630
+ const [systemInstruction] = prompt;
631
+ this.client.systemInstruction = systemInstruction;
632
+ actualPrompt = prompt.slice(1);
633
+ }
585
634
  const parameters = this.invocationParams(options);
586
635
  const request = {
587
636
  ...parameters,
588
- contents: prompt,
637
+ contents: actualPrompt,
589
638
  };
590
639
  const stream = await this.caller.callWithOptions({ signal: options?.signal }, async () => {
591
640
  const { stream } = await this.client.generateContentStream(request);
@@ -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;
@@ -357,7 +357,9 @@ export class ChatGoogleGenerativeAI extends BaseChatModel {
357
357
  };
358
358
  }
359
359
  get _isMultimodalModel() {
360
- return this.model.includes("vision") || this.model.startsWith("gemini-1.5");
360
+ return (this.model.includes("vision") ||
361
+ this.model.startsWith("gemini-1.5") ||
362
+ this.model.startsWith("gemini-2"));
361
363
  }
362
364
  constructor(fields) {
363
365
  super(fields ?? {});
@@ -439,6 +441,12 @@ export class ChatGoogleGenerativeAI extends BaseChatModel {
439
441
  writable: true,
440
442
  value: true
441
443
  });
444
+ Object.defineProperty(this, "convertSystemMessageToHumanContent", {
445
+ enumerable: true,
446
+ configurable: true,
447
+ writable: true,
448
+ value: void 0
449
+ });
442
450
  Object.defineProperty(this, "client", {
443
451
  enumerable: true,
444
452
  configurable: true,
@@ -503,6 +511,35 @@ export class ChatGoogleGenerativeAI extends BaseChatModel {
503
511
  });
504
512
  this.streamUsage = fields?.streamUsage ?? this.streamUsage;
505
513
  }
514
+ useCachedContent(cachedContent, modelParams, requestOptions) {
515
+ if (!this.apiKey)
516
+ return;
517
+ this.client = new GenerativeAI(this.apiKey).getGenerativeModelFromCachedContent(cachedContent, modelParams, requestOptions);
518
+ }
519
+ get useSystemInstruction() {
520
+ return typeof this.convertSystemMessageToHumanContent === "boolean"
521
+ ? !this.convertSystemMessageToHumanContent
522
+ : this.computeUseSystemInstruction;
523
+ }
524
+ get computeUseSystemInstruction() {
525
+ // This works on models from April 2024 and later
526
+ // Vertex AI: gemini-1.5-pro and gemini-1.0-002 and later
527
+ // AI Studio: gemini-1.5-pro-latest
528
+ if (this.modelName === "gemini-1.0-pro-001") {
529
+ return false;
530
+ }
531
+ else if (this.modelName.startsWith("gemini-pro-vision")) {
532
+ return false;
533
+ }
534
+ else if (this.modelName.startsWith("gemini-1.0-pro-vision")) {
535
+ return false;
536
+ }
537
+ else if (this.modelName === "gemini-pro") {
538
+ // on AI Studio gemini-pro is still pointing at gemini-1.0-pro-001
539
+ return false;
540
+ }
541
+ return true;
542
+ }
506
543
  getLsParams(options) {
507
544
  return {
508
545
  ls_provider: "google_genai",
@@ -537,7 +574,13 @@ export class ChatGoogleGenerativeAI extends BaseChatModel {
537
574
  };
538
575
  }
539
576
  async _generate(messages, options, runManager) {
540
- const prompt = convertBaseMessagesToContent(messages, this._isMultimodalModel);
577
+ const prompt = convertBaseMessagesToContent(messages, this._isMultimodalModel, this.useSystemInstruction);
578
+ let actualPrompt = prompt;
579
+ if (prompt[0].role === "system") {
580
+ const [systemInstruction] = prompt;
581
+ this.client.systemInstruction = systemInstruction;
582
+ actualPrompt = prompt.slice(1);
583
+ }
541
584
  const parameters = this.invocationParams(options);
542
585
  // Handle streaming
543
586
  if (this.streaming) {
@@ -560,7 +603,7 @@ export class ChatGoogleGenerativeAI extends BaseChatModel {
560
603
  }
561
604
  const res = await this.completionWithRetry({
562
605
  ...parameters,
563
- contents: prompt,
606
+ contents: actualPrompt,
564
607
  });
565
608
  let usageMetadata;
566
609
  if ("usageMetadata" in res.response) {
@@ -578,11 +621,17 @@ export class ChatGoogleGenerativeAI extends BaseChatModel {
578
621
  return generationResult;
579
622
  }
580
623
  async *_streamResponseChunks(messages, options, runManager) {
581
- const prompt = convertBaseMessagesToContent(messages, this._isMultimodalModel);
624
+ const prompt = convertBaseMessagesToContent(messages, this._isMultimodalModel, this.useSystemInstruction);
625
+ let actualPrompt = prompt;
626
+ if (prompt[0].role === "system") {
627
+ const [systemInstruction] = prompt;
628
+ this.client.systemInstruction = systemInstruction;
629
+ actualPrompt = prompt.slice(1);
630
+ }
582
631
  const parameters = this.invocationParams(options);
583
632
  const request = {
584
633
  ...parameters,
585
- contents: prompt,
634
+ contents: actualPrompt,
586
635
  };
587
636
  const stream = await this.caller.callWithOptions({ signal: options?.signal }, async () => {
588
637
  const { stream } = await this.client.generateContentStream(request);
@@ -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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/google-genai",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Google Generative AI integration for LangChain.js",
5
5
  "type": "module",
6
6
  "engines": {