@langchain/google-common 0.2.5 → 0.2.7

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.
@@ -114,17 +114,17 @@ class GoogleHostConnection extends GoogleConnection {
114
114
  writable: true,
115
115
  value: void 0
116
116
  });
117
- Object.defineProperty(this, "apiVersion", {
117
+ Object.defineProperty(this, "_apiVersion", {
118
118
  enumerable: true,
119
119
  configurable: true,
120
120
  writable: true,
121
- value: "v1"
121
+ value: void 0
122
122
  });
123
123
  this.caller = caller;
124
124
  this.platformType = fields?.platformType;
125
125
  this._endpoint = fields?.endpoint;
126
126
  this._location = fields?.location;
127
- this.apiVersion = fields?.apiVersion ?? this.apiVersion;
127
+ this._apiVersion = fields?.apiVersion;
128
128
  this.client = client;
129
129
  }
130
130
  get platform() {
@@ -133,6 +133,12 @@ class GoogleHostConnection extends GoogleConnection {
133
133
  get computedPlatformType() {
134
134
  return "gcp";
135
135
  }
136
+ get computedApiVersion() {
137
+ return "v1";
138
+ }
139
+ get apiVersion() {
140
+ return this._apiVersion ?? this.computedApiVersion;
141
+ }
136
142
  get location() {
137
143
  return this._location ?? this.computedLocation;
138
144
  }
@@ -238,6 +244,14 @@ class GoogleAIConnection extends GoogleHostConnection {
238
244
  return "gcp";
239
245
  }
240
246
  }
247
+ get computedApiVersion() {
248
+ switch (this.platform) {
249
+ case "gai":
250
+ return "v1beta";
251
+ default:
252
+ return "v1";
253
+ }
254
+ }
241
255
  get computedLocation() {
242
256
  switch (this.apiName) {
243
257
  case "google":
@@ -25,10 +25,12 @@ export declare abstract class GoogleHostConnection<CallOptions extends AsyncCall
25
25
  platformType: GooglePlatformType | undefined;
26
26
  _endpoint: string | undefined;
27
27
  _location: string | undefined;
28
- apiVersion: string;
28
+ _apiVersion: string | undefined;
29
29
  constructor(fields: GoogleConnectionParams<AuthOptions> | undefined, caller: AsyncCaller, client: GoogleAbstractedClient, streaming?: boolean);
30
30
  get platform(): GooglePlatformType;
31
31
  get computedPlatformType(): GooglePlatformType;
32
+ get computedApiVersion(): string;
33
+ get apiVersion(): string;
32
34
  get location(): string;
33
35
  get computedLocation(): string;
34
36
  get endpoint(): string;
@@ -52,6 +54,7 @@ export declare abstract class GoogleAIConnection<CallOptions extends AsyncCaller
52
54
  get api(): GoogleAIAPI;
53
55
  get isApiKey(): boolean;
54
56
  get computedPlatformType(): GooglePlatformType;
57
+ get computedApiVersion(): string;
55
58
  get computedLocation(): string;
56
59
  abstract buildUrlMethod(): Promise<string>;
57
60
  buildUrlGenerativeLanguage(): Promise<string>;
@@ -110,17 +110,17 @@ export class GoogleHostConnection extends GoogleConnection {
110
110
  writable: true,
111
111
  value: void 0
112
112
  });
113
- Object.defineProperty(this, "apiVersion", {
113
+ Object.defineProperty(this, "_apiVersion", {
114
114
  enumerable: true,
115
115
  configurable: true,
116
116
  writable: true,
117
- value: "v1"
117
+ value: void 0
118
118
  });
119
119
  this.caller = caller;
120
120
  this.platformType = fields?.platformType;
121
121
  this._endpoint = fields?.endpoint;
122
122
  this._location = fields?.location;
123
- this.apiVersion = fields?.apiVersion ?? this.apiVersion;
123
+ this._apiVersion = fields?.apiVersion;
124
124
  this.client = client;
125
125
  }
126
126
  get platform() {
@@ -129,6 +129,12 @@ export class GoogleHostConnection extends GoogleConnection {
129
129
  get computedPlatformType() {
130
130
  return "gcp";
131
131
  }
132
+ get computedApiVersion() {
133
+ return "v1";
134
+ }
135
+ get apiVersion() {
136
+ return this._apiVersion ?? this.computedApiVersion;
137
+ }
132
138
  get location() {
133
139
  return this._location ?? this.computedLocation;
134
140
  }
@@ -232,6 +238,14 @@ export class GoogleAIConnection extends GoogleHostConnection {
232
238
  return "gcp";
233
239
  }
234
240
  }
241
+ get computedApiVersion() {
242
+ switch (this.platform) {
243
+ case "gai":
244
+ return "v1beta";
245
+ default:
246
+ return "v1";
247
+ }
248
+ }
235
249
  get computedLocation() {
236
250
  switch (this.apiName) {
237
251
  case "google":
@@ -328,14 +328,8 @@ class AIStudioMediaBlob extends media_core_js_1.MediaBlob {
328
328
  }
329
329
  exports.AIStudioMediaBlob = AIStudioMediaBlob;
330
330
  class AIStudioFileUploadConnection extends GoogleMultipartUploadConnection {
331
- constructor() {
332
- super(...arguments);
333
- Object.defineProperty(this, "apiVersion", {
334
- enumerable: true,
335
- configurable: true,
336
- writable: true,
337
- value: "v1beta"
338
- });
331
+ get computedApiVersion() {
332
+ return "v1beta";
339
333
  }
340
334
  async buildUrl() {
341
335
  return `https://generativelanguage.googleapis.com/upload/${this.apiVersion}/files`;
@@ -357,15 +351,12 @@ class AIStudioFileDownloadConnection extends GoogleDownloadConnection {
357
351
  writable: true,
358
352
  value: void 0
359
353
  });
360
- Object.defineProperty(this, "apiVersion", {
361
- enumerable: true,
362
- configurable: true,
363
- writable: true,
364
- value: "v1beta"
365
- });
366
354
  this.method = fields.method;
367
355
  this.name = fields.name;
368
356
  }
357
+ get computedApiVersion() {
358
+ return "v1beta";
359
+ }
369
360
  buildMethod() {
370
361
  return this.method;
371
362
  }
@@ -166,7 +166,7 @@ export interface AIStudioFileConnectionParams {
166
166
  export interface AIStudioFileUploadConnectionParams<AuthOptions> extends GoogleUploadConnectionParams<AuthOptions>, AIStudioFileConnectionParams {
167
167
  }
168
168
  export declare class AIStudioFileUploadConnection<AuthOptions> extends GoogleMultipartUploadConnection<AsyncCallerCallOptions, AIStudioFileSaveResponse, AuthOptions> {
169
- apiVersion: string;
169
+ get computedApiVersion(): string;
170
170
  buildUrl(): Promise<string>;
171
171
  }
172
172
  export interface AIStudioFileDownloadConnectionParams<AuthOptions> extends AIStudioFileConnectionParams, GoogleConnectionParams<AuthOptions> {
@@ -176,8 +176,8 @@ export interface AIStudioFileDownloadConnectionParams<AuthOptions> extends AIStu
176
176
  export declare class AIStudioFileDownloadConnection<ResponseType extends GoogleResponse, AuthOptions> extends GoogleDownloadConnection<AsyncCallerCallOptions, ResponseType, AuthOptions> {
177
177
  method: GoogleAbstractedClientOpsMethod;
178
178
  name: string;
179
- apiVersion: string;
180
179
  constructor(fields: AIStudioFileDownloadConnectionParams<AuthOptions>, caller: AsyncCaller, client: GoogleAbstractedClient);
180
+ get computedApiVersion(): string;
181
181
  buildMethod(): GoogleAbstractedClientOpsMethod;
182
182
  buildUrl(): Promise<string>;
183
183
  }
@@ -315,14 +315,8 @@ export class AIStudioMediaBlob extends MediaBlob {
315
315
  }
316
316
  }
317
317
  export class AIStudioFileUploadConnection extends GoogleMultipartUploadConnection {
318
- constructor() {
319
- super(...arguments);
320
- Object.defineProperty(this, "apiVersion", {
321
- enumerable: true,
322
- configurable: true,
323
- writable: true,
324
- value: "v1beta"
325
- });
318
+ get computedApiVersion() {
319
+ return "v1beta";
326
320
  }
327
321
  async buildUrl() {
328
322
  return `https://generativelanguage.googleapis.com/upload/${this.apiVersion}/files`;
@@ -343,15 +337,12 @@ export class AIStudioFileDownloadConnection extends GoogleDownloadConnection {
343
337
  writable: true,
344
338
  value: void 0
345
339
  });
346
- Object.defineProperty(this, "apiVersion", {
347
- enumerable: true,
348
- configurable: true,
349
- writable: true,
350
- value: "v1beta"
351
- });
352
340
  this.method = fields.method;
353
341
  this.name = fields.name;
354
342
  }
343
+ get computedApiVersion() {
344
+ return "v1beta";
345
+ }
355
346
  buildMethod() {
356
347
  return this.method;
357
348
  }
package/dist/types.d.ts CHANGED
@@ -451,10 +451,28 @@ interface GeminiResponsePromptFeedback {
451
451
  blockReason?: string;
452
452
  safetyRatings: GeminiSafetyRating[];
453
453
  }
454
+ export type ModalityEnum = "TEXT" | "IMAGE" | "VIDEO" | "AUDIO" | "DOCUMENT" | string;
455
+ export interface ModalityTokenCount {
456
+ modality: ModalityEnum;
457
+ tokenCount: number;
458
+ }
459
+ export interface GenerateContentResponseUsageMetadata {
460
+ promptTokenCount: number;
461
+ toolUsePromptTokenCount: number;
462
+ cachedContentTokenCount: number;
463
+ thoughtsTokenCount: number;
464
+ candidatesTokenCount: number;
465
+ totalTokenCount: number;
466
+ promptTokensDetails: ModalityTokenCount[];
467
+ toolUsePromptTokensDetails: ModalityTokenCount[];
468
+ cacheTokensDetails: ModalityTokenCount[];
469
+ candidatesTokensDetails: ModalityTokenCount[];
470
+ [key: string]: unknown;
471
+ }
454
472
  export interface GenerateContentResponseData {
455
473
  candidates: GeminiResponseCandidate[];
456
474
  promptFeedback: GeminiResponsePromptFeedback;
457
- usageMetadata: Record<string, unknown>;
475
+ usageMetadata: GenerateContentResponseUsageMetadata;
458
476
  }
459
477
  export type GoogleLLMModelFamily = null | "palm" | "gemini" | "gemma";
460
478
  export type VertexModelFamily = GoogleLLMModelFamily | "claude";
@@ -639,6 +639,42 @@ function getGeminiAPI(config) {
639
639
  content,
640
640
  };
641
641
  }
642
+ function addModalityCounts(modalityTokenCounts, details) {
643
+ modalityTokenCounts?.forEach((modalityTokenCount) => {
644
+ const { modality, tokenCount } = modalityTokenCount;
645
+ const modalityLc = modality.toLowerCase();
646
+ const currentCount = details[modalityLc] ?? 0;
647
+ // eslint-disable-next-line no-param-reassign
648
+ details[modalityLc] = currentCount + tokenCount;
649
+ });
650
+ }
651
+ function responseToUsageMetadata(response) {
652
+ if ("usageMetadata" in response.data) {
653
+ const data = response?.data;
654
+ const usageMetadata = data?.usageMetadata;
655
+ const input_tokens = usageMetadata.promptTokenCount ?? 0;
656
+ const candidatesTokenCount = usageMetadata.candidatesTokenCount ?? 0;
657
+ const thoughtsTokenCount = usageMetadata.thoughtsTokenCount ?? 0;
658
+ const output_tokens = candidatesTokenCount + thoughtsTokenCount;
659
+ const total_tokens = usageMetadata.totalTokenCount ?? input_tokens + output_tokens;
660
+ const input_token_details = {};
661
+ addModalityCounts(usageMetadata.promptTokensDetails, input_token_details);
662
+ const output_token_details = {};
663
+ addModalityCounts(usageMetadata?.candidatesTokensDetails, output_token_details);
664
+ if (typeof usageMetadata?.thoughtsTokenCount === "number") {
665
+ output_token_details.reasoning = usageMetadata.thoughtsTokenCount;
666
+ }
667
+ const ret = {
668
+ input_tokens,
669
+ output_tokens,
670
+ total_tokens,
671
+ input_token_details,
672
+ output_token_details,
673
+ };
674
+ return ret;
675
+ }
676
+ return undefined;
677
+ }
642
678
  function responseToGenerationInfo(response) {
643
679
  const data =
644
680
  // eslint-disable-next-line no-nested-ternary
@@ -651,12 +687,9 @@ function getGeminiAPI(config) {
651
687
  if (!data) {
652
688
  return {};
653
689
  }
654
- return {
655
- usage_metadata: {
656
- prompt_token_count: data.usageMetadata?.promptTokenCount,
657
- candidates_token_count: data.usageMetadata?.candidatesTokenCount,
658
- total_token_count: data.usageMetadata?.totalTokenCount,
659
- },
690
+ const finish_reason = data.candidates[0]?.finishReason;
691
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
692
+ const ret = {
660
693
  safety_ratings: data.candidates[0]?.safetyRatings?.map((rating) => ({
661
694
  category: rating.category,
662
695
  probability: rating.probability,
@@ -666,11 +699,17 @@ function getGeminiAPI(config) {
666
699
  })),
667
700
  citation_metadata: data.candidates[0]?.citationMetadata,
668
701
  grounding_metadata: data.candidates[0]?.groundingMetadata,
669
- finish_reason: data.candidates[0]?.finishReason,
702
+ finish_reason,
670
703
  finish_message: data.candidates[0]?.finishMessage,
671
704
  avgLogprobs: data.candidates[0]?.avgLogprobs,
672
705
  logprobs: candidateToLogprobs(data.candidates[0]),
673
706
  };
707
+ // Only add the usage_metadata on the last chunk
708
+ // sent while streaming (see issue 8102).
709
+ if (typeof finish_reason === "string") {
710
+ ret.usage_metadata = responseToUsageMetadata(response);
711
+ }
712
+ return ret;
674
713
  }
675
714
  function responseToChatGeneration(response) {
676
715
  return new outputs_1.ChatGenerationChunk({
@@ -845,15 +884,7 @@ function getGeminiAPI(config) {
845
884
  const kwargs = combineAdditionalKwargs(gen.content);
846
885
  const lastContent = gen.content[gen.content.length - 1];
847
886
  // Add usage metadata
848
- let usageMetadata;
849
- if ("usageMetadata" in response.data) {
850
- usageMetadata = {
851
- input_tokens: response.data.usageMetadata.promptTokenCount,
852
- output_tokens: response.data.usageMetadata
853
- .candidatesTokenCount,
854
- total_tokens: response.data.usageMetadata.totalTokenCount,
855
- };
856
- }
887
+ const usage_metadata = responseToUsageMetadata(response);
857
888
  // Add thinking / reasoning
858
889
  // if (gen.reasoning && gen.reasoning.length > 0) {
859
890
  // kwargs.reasoning_content = combineContent(gen.reasoning, true);
@@ -862,7 +893,7 @@ function getGeminiAPI(config) {
862
893
  const message = new messages_1.AIMessageChunk({
863
894
  content: combinedContent,
864
895
  additional_kwargs: kwargs,
865
- usage_metadata: usageMetadata,
896
+ usage_metadata,
866
897
  tool_calls: combinedToolCalls.tool_calls,
867
898
  invalid_tool_calls: combinedToolCalls.invalid_tool_calls,
868
899
  });
@@ -1057,10 +1088,12 @@ function getGeminiAPI(config) {
1057
1088
  }
1058
1089
  }
1059
1090
  // Add thinking configuration if explicitly set
1060
- if (typeof parameters.maxReasoningTokens !== "undefined") {
1091
+ if (typeof parameters.maxReasoningTokens !== "undefined" &&
1092
+ parameters.maxReasoningTokens !== 0) {
1061
1093
  ret.thinkingConfig = {
1062
1094
  thinkingBudget: parameters.maxReasoningTokens,
1063
- includeThoughts: true,
1095
+ // TODO: Expose this configuration to the user once google fully supports it
1096
+ includeThoughts: false,
1064
1097
  };
1065
1098
  }
1066
1099
  // Remove any undefined properties, so we don't send them
@@ -634,6 +634,42 @@ export function getGeminiAPI(config) {
634
634
  content,
635
635
  };
636
636
  }
637
+ function addModalityCounts(modalityTokenCounts, details) {
638
+ modalityTokenCounts?.forEach((modalityTokenCount) => {
639
+ const { modality, tokenCount } = modalityTokenCount;
640
+ const modalityLc = modality.toLowerCase();
641
+ const currentCount = details[modalityLc] ?? 0;
642
+ // eslint-disable-next-line no-param-reassign
643
+ details[modalityLc] = currentCount + tokenCount;
644
+ });
645
+ }
646
+ function responseToUsageMetadata(response) {
647
+ if ("usageMetadata" in response.data) {
648
+ const data = response?.data;
649
+ const usageMetadata = data?.usageMetadata;
650
+ const input_tokens = usageMetadata.promptTokenCount ?? 0;
651
+ const candidatesTokenCount = usageMetadata.candidatesTokenCount ?? 0;
652
+ const thoughtsTokenCount = usageMetadata.thoughtsTokenCount ?? 0;
653
+ const output_tokens = candidatesTokenCount + thoughtsTokenCount;
654
+ const total_tokens = usageMetadata.totalTokenCount ?? input_tokens + output_tokens;
655
+ const input_token_details = {};
656
+ addModalityCounts(usageMetadata.promptTokensDetails, input_token_details);
657
+ const output_token_details = {};
658
+ addModalityCounts(usageMetadata?.candidatesTokensDetails, output_token_details);
659
+ if (typeof usageMetadata?.thoughtsTokenCount === "number") {
660
+ output_token_details.reasoning = usageMetadata.thoughtsTokenCount;
661
+ }
662
+ const ret = {
663
+ input_tokens,
664
+ output_tokens,
665
+ total_tokens,
666
+ input_token_details,
667
+ output_token_details,
668
+ };
669
+ return ret;
670
+ }
671
+ return undefined;
672
+ }
637
673
  function responseToGenerationInfo(response) {
638
674
  const data =
639
675
  // eslint-disable-next-line no-nested-ternary
@@ -646,12 +682,9 @@ export function getGeminiAPI(config) {
646
682
  if (!data) {
647
683
  return {};
648
684
  }
649
- return {
650
- usage_metadata: {
651
- prompt_token_count: data.usageMetadata?.promptTokenCount,
652
- candidates_token_count: data.usageMetadata?.candidatesTokenCount,
653
- total_token_count: data.usageMetadata?.totalTokenCount,
654
- },
685
+ const finish_reason = data.candidates[0]?.finishReason;
686
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
687
+ const ret = {
655
688
  safety_ratings: data.candidates[0]?.safetyRatings?.map((rating) => ({
656
689
  category: rating.category,
657
690
  probability: rating.probability,
@@ -661,11 +694,17 @@ export function getGeminiAPI(config) {
661
694
  })),
662
695
  citation_metadata: data.candidates[0]?.citationMetadata,
663
696
  grounding_metadata: data.candidates[0]?.groundingMetadata,
664
- finish_reason: data.candidates[0]?.finishReason,
697
+ finish_reason,
665
698
  finish_message: data.candidates[0]?.finishMessage,
666
699
  avgLogprobs: data.candidates[0]?.avgLogprobs,
667
700
  logprobs: candidateToLogprobs(data.candidates[0]),
668
701
  };
702
+ // Only add the usage_metadata on the last chunk
703
+ // sent while streaming (see issue 8102).
704
+ if (typeof finish_reason === "string") {
705
+ ret.usage_metadata = responseToUsageMetadata(response);
706
+ }
707
+ return ret;
669
708
  }
670
709
  function responseToChatGeneration(response) {
671
710
  return new ChatGenerationChunk({
@@ -840,15 +879,7 @@ export function getGeminiAPI(config) {
840
879
  const kwargs = combineAdditionalKwargs(gen.content);
841
880
  const lastContent = gen.content[gen.content.length - 1];
842
881
  // Add usage metadata
843
- let usageMetadata;
844
- if ("usageMetadata" in response.data) {
845
- usageMetadata = {
846
- input_tokens: response.data.usageMetadata.promptTokenCount,
847
- output_tokens: response.data.usageMetadata
848
- .candidatesTokenCount,
849
- total_tokens: response.data.usageMetadata.totalTokenCount,
850
- };
851
- }
882
+ const usage_metadata = responseToUsageMetadata(response);
852
883
  // Add thinking / reasoning
853
884
  // if (gen.reasoning && gen.reasoning.length > 0) {
854
885
  // kwargs.reasoning_content = combineContent(gen.reasoning, true);
@@ -857,7 +888,7 @@ export function getGeminiAPI(config) {
857
888
  const message = new AIMessageChunk({
858
889
  content: combinedContent,
859
890
  additional_kwargs: kwargs,
860
- usage_metadata: usageMetadata,
891
+ usage_metadata,
861
892
  tool_calls: combinedToolCalls.tool_calls,
862
893
  invalid_tool_calls: combinedToolCalls.invalid_tool_calls,
863
894
  });
@@ -1052,10 +1083,12 @@ export function getGeminiAPI(config) {
1052
1083
  }
1053
1084
  }
1054
1085
  // Add thinking configuration if explicitly set
1055
- if (typeof parameters.maxReasoningTokens !== "undefined") {
1086
+ if (typeof parameters.maxReasoningTokens !== "undefined" &&
1087
+ parameters.maxReasoningTokens !== 0) {
1056
1088
  ret.thinkingConfig = {
1057
1089
  thinkingBudget: parameters.maxReasoningTokens,
1058
- includeThoughts: true,
1090
+ // TODO: Expose this configuration to the user once google fully supports it
1091
+ includeThoughts: false,
1059
1092
  };
1060
1093
  }
1061
1094
  // Remove any undefined properties, so we don't send them
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/google-common",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "description": "Core types and classes for Google services.",
5
5
  "type": "module",
6
6
  "engines": {
@@ -36,11 +36,11 @@
36
36
  "zod-to-json-schema": "^3.22.4"
37
37
  },
38
38
  "peerDependencies": {
39
- "@langchain/core": ">=0.3.48 <0.4.0"
39
+ "@langchain/core": ">=0.3.55 <0.4.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@jest/globals": "^29.5.0",
43
- "@langchain/core": "0.3.48",
43
+ "@langchain/core": "0.3.55",
44
44
  "@langchain/scripts": ">=0.1.0 <0.2.0",
45
45
  "@swc/core": "^1.3.90",
46
46
  "@swc/jest": "^0.2.29",