@langchain/google-common 0.1.8 → 0.2.0
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.
- package/dist/chat_models.cjs +5 -11
- package/dist/chat_models.js +5 -11
- package/dist/connection.cjs +22 -2
- package/dist/connection.d.ts +3 -0
- package/dist/connection.js +22 -2
- package/dist/utils/gemini.cjs +136 -34
- package/dist/utils/gemini.js +136 -34
- package/package.json +1 -1
package/dist/chat_models.cjs
CHANGED
|
@@ -131,25 +131,25 @@ class ChatGoogleBase extends chat_models_1.BaseChatModel {
|
|
|
131
131
|
enumerable: true,
|
|
132
132
|
configurable: true,
|
|
133
133
|
writable: true,
|
|
134
|
-
value: 0
|
|
134
|
+
value: void 0
|
|
135
135
|
});
|
|
136
136
|
Object.defineProperty(this, "maxOutputTokens", {
|
|
137
137
|
enumerable: true,
|
|
138
138
|
configurable: true,
|
|
139
139
|
writable: true,
|
|
140
|
-
value:
|
|
140
|
+
value: void 0
|
|
141
141
|
});
|
|
142
142
|
Object.defineProperty(this, "topP", {
|
|
143
143
|
enumerable: true,
|
|
144
144
|
configurable: true,
|
|
145
145
|
writable: true,
|
|
146
|
-
value: 0
|
|
146
|
+
value: void 0
|
|
147
147
|
});
|
|
148
148
|
Object.defineProperty(this, "topK", {
|
|
149
149
|
enumerable: true,
|
|
150
150
|
configurable: true,
|
|
151
151
|
writable: true,
|
|
152
|
-
value:
|
|
152
|
+
value: void 0
|
|
153
153
|
});
|
|
154
154
|
Object.defineProperty(this, "presencePenalty", {
|
|
155
155
|
enumerable: true,
|
|
@@ -246,13 +246,7 @@ class ChatGoogleBase extends chat_models_1.BaseChatModel {
|
|
|
246
246
|
return new auth_js_1.ApiKeyGoogleAuth(apiKey);
|
|
247
247
|
}
|
|
248
248
|
buildApiKey(fields) {
|
|
249
|
-
|
|
250
|
-
return fields?.apiKey ?? (0, env_1.getEnvironmentVariable)("GOOGLE_API_KEY");
|
|
251
|
-
}
|
|
252
|
-
else {
|
|
253
|
-
// GCP doesn't support API Keys
|
|
254
|
-
return undefined;
|
|
255
|
-
}
|
|
249
|
+
return fields?.apiKey ?? (0, env_1.getEnvironmentVariable)("GOOGLE_API_KEY");
|
|
256
250
|
}
|
|
257
251
|
buildClient(fields) {
|
|
258
252
|
const apiKey = this.buildApiKey(fields);
|
package/dist/chat_models.js
CHANGED
|
@@ -127,25 +127,25 @@ export class ChatGoogleBase extends BaseChatModel {
|
|
|
127
127
|
enumerable: true,
|
|
128
128
|
configurable: true,
|
|
129
129
|
writable: true,
|
|
130
|
-
value: 0
|
|
130
|
+
value: void 0
|
|
131
131
|
});
|
|
132
132
|
Object.defineProperty(this, "maxOutputTokens", {
|
|
133
133
|
enumerable: true,
|
|
134
134
|
configurable: true,
|
|
135
135
|
writable: true,
|
|
136
|
-
value:
|
|
136
|
+
value: void 0
|
|
137
137
|
});
|
|
138
138
|
Object.defineProperty(this, "topP", {
|
|
139
139
|
enumerable: true,
|
|
140
140
|
configurable: true,
|
|
141
141
|
writable: true,
|
|
142
|
-
value: 0
|
|
142
|
+
value: void 0
|
|
143
143
|
});
|
|
144
144
|
Object.defineProperty(this, "topK", {
|
|
145
145
|
enumerable: true,
|
|
146
146
|
configurable: true,
|
|
147
147
|
writable: true,
|
|
148
|
-
value:
|
|
148
|
+
value: void 0
|
|
149
149
|
});
|
|
150
150
|
Object.defineProperty(this, "presencePenalty", {
|
|
151
151
|
enumerable: true,
|
|
@@ -242,13 +242,7 @@ export class ChatGoogleBase extends BaseChatModel {
|
|
|
242
242
|
return new ApiKeyGoogleAuth(apiKey);
|
|
243
243
|
}
|
|
244
244
|
buildApiKey(fields) {
|
|
245
|
-
|
|
246
|
-
return fields?.apiKey ?? getEnvironmentVariable("GOOGLE_API_KEY");
|
|
247
|
-
}
|
|
248
|
-
else {
|
|
249
|
-
// GCP doesn't support API Keys
|
|
250
|
-
return undefined;
|
|
251
|
-
}
|
|
245
|
+
return fields?.apiKey ?? getEnvironmentVariable("GOOGLE_API_KEY");
|
|
252
246
|
}
|
|
253
247
|
buildClient(fields) {
|
|
254
248
|
const apiKey = this.buildApiKey(fields);
|
package/dist/connection.cjs
CHANGED
|
@@ -223,8 +223,14 @@ class GoogleAIConnection extends GoogleHostConnection {
|
|
|
223
223
|
throw new Error(`Unknown API: ${this.apiName}`);
|
|
224
224
|
}
|
|
225
225
|
}
|
|
226
|
+
get isApiKey() {
|
|
227
|
+
return this.client.clientType === "apiKey";
|
|
228
|
+
}
|
|
226
229
|
get computedPlatformType() {
|
|
227
|
-
|
|
230
|
+
// This is not a completely correct assumption, since GCP can
|
|
231
|
+
// have an API Key. But if so, then people need to set the platform
|
|
232
|
+
// type explicitly.
|
|
233
|
+
if (this.isApiKey) {
|
|
228
234
|
return "gai";
|
|
229
235
|
}
|
|
230
236
|
else {
|
|
@@ -246,13 +252,27 @@ class GoogleAIConnection extends GoogleHostConnection {
|
|
|
246
252
|
const url = `https://generativelanguage.googleapis.com/${this.apiVersion}/models/${this.model}:${method}`;
|
|
247
253
|
return url;
|
|
248
254
|
}
|
|
249
|
-
async
|
|
255
|
+
async buildUrlVertexExpress() {
|
|
256
|
+
const method = await this.buildUrlMethod();
|
|
257
|
+
const publisher = this.modelPublisher;
|
|
258
|
+
const url = `https://aiplatform.googleapis.com/${this.apiVersion}/publishers/${publisher}/models/${this.model}:${method}`;
|
|
259
|
+
return url;
|
|
260
|
+
}
|
|
261
|
+
async buildUrlVertexLocation() {
|
|
250
262
|
const projectId = await this.client.getProjectId();
|
|
251
263
|
const method = await this.buildUrlMethod();
|
|
252
264
|
const publisher = this.modelPublisher;
|
|
253
265
|
const url = `https://${this.endpoint}/${this.apiVersion}/projects/${projectId}/locations/${this.location}/publishers/${publisher}/models/${this.model}:${method}`;
|
|
254
266
|
return url;
|
|
255
267
|
}
|
|
268
|
+
async buildUrlVertex() {
|
|
269
|
+
if (this.isApiKey) {
|
|
270
|
+
return this.buildUrlVertexExpress();
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
return this.buildUrlVertexLocation();
|
|
274
|
+
}
|
|
275
|
+
}
|
|
256
276
|
async buildUrl() {
|
|
257
277
|
switch (this.platform) {
|
|
258
278
|
case "gai":
|
package/dist/connection.d.ts
CHANGED
|
@@ -50,10 +50,13 @@ export declare abstract class GoogleAIConnection<CallOptions extends AsyncCaller
|
|
|
50
50
|
get computedAPIName(): string;
|
|
51
51
|
get apiName(): string;
|
|
52
52
|
get api(): GoogleAIAPI;
|
|
53
|
+
get isApiKey(): boolean;
|
|
53
54
|
get computedPlatformType(): GooglePlatformType;
|
|
54
55
|
get computedLocation(): string;
|
|
55
56
|
abstract buildUrlMethod(): Promise<string>;
|
|
56
57
|
buildUrlGenerativeLanguage(): Promise<string>;
|
|
58
|
+
buildUrlVertexExpress(): Promise<string>;
|
|
59
|
+
buildUrlVertexLocation(): Promise<string>;
|
|
57
60
|
buildUrlVertex(): Promise<string>;
|
|
58
61
|
buildUrl(): Promise<string>;
|
|
59
62
|
abstract formatData(input: InputType, parameters: GoogleAIModelRequestParams): Promise<unknown>;
|
package/dist/connection.js
CHANGED
|
@@ -217,8 +217,14 @@ export class GoogleAIConnection extends GoogleHostConnection {
|
|
|
217
217
|
throw new Error(`Unknown API: ${this.apiName}`);
|
|
218
218
|
}
|
|
219
219
|
}
|
|
220
|
+
get isApiKey() {
|
|
221
|
+
return this.client.clientType === "apiKey";
|
|
222
|
+
}
|
|
220
223
|
get computedPlatformType() {
|
|
221
|
-
|
|
224
|
+
// This is not a completely correct assumption, since GCP can
|
|
225
|
+
// have an API Key. But if so, then people need to set the platform
|
|
226
|
+
// type explicitly.
|
|
227
|
+
if (this.isApiKey) {
|
|
222
228
|
return "gai";
|
|
223
229
|
}
|
|
224
230
|
else {
|
|
@@ -240,13 +246,27 @@ export class GoogleAIConnection extends GoogleHostConnection {
|
|
|
240
246
|
const url = `https://generativelanguage.googleapis.com/${this.apiVersion}/models/${this.model}:${method}`;
|
|
241
247
|
return url;
|
|
242
248
|
}
|
|
243
|
-
async
|
|
249
|
+
async buildUrlVertexExpress() {
|
|
250
|
+
const method = await this.buildUrlMethod();
|
|
251
|
+
const publisher = this.modelPublisher;
|
|
252
|
+
const url = `https://aiplatform.googleapis.com/${this.apiVersion}/publishers/${publisher}/models/${this.model}:${method}`;
|
|
253
|
+
return url;
|
|
254
|
+
}
|
|
255
|
+
async buildUrlVertexLocation() {
|
|
244
256
|
const projectId = await this.client.getProjectId();
|
|
245
257
|
const method = await this.buildUrlMethod();
|
|
246
258
|
const publisher = this.modelPublisher;
|
|
247
259
|
const url = `https://${this.endpoint}/${this.apiVersion}/projects/${projectId}/locations/${this.location}/publishers/${publisher}/models/${this.model}:${method}`;
|
|
248
260
|
return url;
|
|
249
261
|
}
|
|
262
|
+
async buildUrlVertex() {
|
|
263
|
+
if (this.isApiKey) {
|
|
264
|
+
return this.buildUrlVertexExpress();
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
return this.buildUrlVertexLocation();
|
|
268
|
+
}
|
|
269
|
+
}
|
|
250
270
|
async buildUrl() {
|
|
251
271
|
switch (this.platform) {
|
|
252
272
|
case "gai":
|
package/dist/utils/gemini.cjs
CHANGED
|
@@ -5,6 +5,7 @@ const uuid_1 = require("uuid");
|
|
|
5
5
|
const messages_1 = require("@langchain/core/messages");
|
|
6
6
|
const outputs_1 = require("@langchain/core/outputs");
|
|
7
7
|
const function_calling_1 = require("@langchain/core/utils/function_calling");
|
|
8
|
+
const stream_1 = require("@langchain/core/utils/stream");
|
|
8
9
|
const safety_js_1 = require("./safety.cjs");
|
|
9
10
|
const types_js_1 = require("../types.cjs");
|
|
10
11
|
const zod_to_gemini_parameters_js_1 = require("./zod_to_gemini_parameters.cjs");
|
|
@@ -604,9 +605,12 @@ function getGeminiAPI(config) {
|
|
|
604
605
|
function partToChatGeneration(part) {
|
|
605
606
|
const message = partToMessageChunk(part);
|
|
606
607
|
const text = partToText(part);
|
|
608
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
609
|
+
const generationInfo = {};
|
|
607
610
|
return new outputs_1.ChatGenerationChunk({
|
|
608
611
|
text,
|
|
609
612
|
message,
|
|
613
|
+
generationInfo,
|
|
610
614
|
});
|
|
611
615
|
}
|
|
612
616
|
function groundingSupportByPart(groundingSupports) {
|
|
@@ -657,43 +661,134 @@ function getGeminiAPI(config) {
|
|
|
657
661
|
});
|
|
658
662
|
return ret;
|
|
659
663
|
}
|
|
664
|
+
function combineContent(gen, forceComplex = false) {
|
|
665
|
+
const allString = gen.every((item) => typeof item.message.content === "string");
|
|
666
|
+
if (allString && !forceComplex) {
|
|
667
|
+
// Everything is a string, and we don't want to force it to return
|
|
668
|
+
// MessageContentComplex[], so concatenate the content into one string
|
|
669
|
+
return gen.map((item) => item.message.content).join("");
|
|
670
|
+
}
|
|
671
|
+
else {
|
|
672
|
+
// We either have complex types, or we want to force them, so turn
|
|
673
|
+
// it into an array of complex types.
|
|
674
|
+
const ret = [];
|
|
675
|
+
gen.forEach((item) => {
|
|
676
|
+
if (typeof item.message.content === "string") {
|
|
677
|
+
// If this is a string, turn it into a text type
|
|
678
|
+
ret.push({
|
|
679
|
+
text: item.message.content,
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
else {
|
|
683
|
+
// Otherwise, add all the complex types to what we're returning
|
|
684
|
+
item.message.content.forEach((c) => {
|
|
685
|
+
ret.push(c);
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
});
|
|
689
|
+
return ret;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
function combineText(gen) {
|
|
693
|
+
return gen.map((item) => item.text ?? "").join("");
|
|
694
|
+
}
|
|
695
|
+
/*
|
|
696
|
+
* We don't really need the entire AIMessageChunk here, but it is
|
|
697
|
+
* a conventient way to combine all the Tool Calling information.
|
|
698
|
+
*/
|
|
699
|
+
function combineToolCalls(gen) {
|
|
700
|
+
let ret = new messages_1.AIMessageChunk("");
|
|
701
|
+
gen.forEach((item) => {
|
|
702
|
+
const message = item?.message;
|
|
703
|
+
ret = (0, stream_1.concat)(ret, message);
|
|
704
|
+
});
|
|
705
|
+
return ret;
|
|
706
|
+
}
|
|
707
|
+
function combineAdditionalKwargs(gen) {
|
|
708
|
+
const ret = {};
|
|
709
|
+
gen.forEach((item) => {
|
|
710
|
+
const message = item?.message;
|
|
711
|
+
const kwargs = message?.additional_kwargs ?? {};
|
|
712
|
+
const keys = Object.keys(kwargs);
|
|
713
|
+
keys.forEach((key) => {
|
|
714
|
+
const value = kwargs[key];
|
|
715
|
+
if (Object.hasOwn(ret, key) &&
|
|
716
|
+
Array.isArray(ret[key]) &&
|
|
717
|
+
Array.isArray(value)) {
|
|
718
|
+
ret[key].push(...value);
|
|
719
|
+
}
|
|
720
|
+
else {
|
|
721
|
+
ret[key] = value;
|
|
722
|
+
}
|
|
723
|
+
});
|
|
724
|
+
});
|
|
725
|
+
return ret;
|
|
726
|
+
}
|
|
727
|
+
function combineGenerations(generations, response) {
|
|
728
|
+
const gen = splitGenerationTypes(generations, response);
|
|
729
|
+
const combinedContent = combineContent(gen.content);
|
|
730
|
+
const combinedText = combineText(gen.content);
|
|
731
|
+
const combinedToolCalls = combineToolCalls(gen.content);
|
|
732
|
+
const kwargs = combineAdditionalKwargs(gen.content);
|
|
733
|
+
const lastContent = gen.content[gen.content.length - 1];
|
|
734
|
+
// Add usage metadata
|
|
735
|
+
let usageMetadata;
|
|
736
|
+
if ("usageMetadata" in response.data) {
|
|
737
|
+
usageMetadata = {
|
|
738
|
+
input_tokens: response.data.usageMetadata.promptTokenCount,
|
|
739
|
+
output_tokens: response.data.usageMetadata
|
|
740
|
+
.candidatesTokenCount,
|
|
741
|
+
total_tokens: response.data.usageMetadata.totalTokenCount,
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
// Add thinking / reasoning
|
|
745
|
+
// if (gen.reasoning && gen.reasoning.length > 0) {
|
|
746
|
+
// kwargs.reasoning_content = combineContent(gen.reasoning, true);
|
|
747
|
+
// }
|
|
748
|
+
// Build the message and the generation chunk to return
|
|
749
|
+
const message = new messages_1.AIMessageChunk({
|
|
750
|
+
content: combinedContent,
|
|
751
|
+
additional_kwargs: kwargs,
|
|
752
|
+
usage_metadata: usageMetadata,
|
|
753
|
+
tool_calls: combinedToolCalls.tool_calls,
|
|
754
|
+
invalid_tool_calls: combinedToolCalls.invalid_tool_calls,
|
|
755
|
+
});
|
|
756
|
+
return [
|
|
757
|
+
new outputs_1.ChatGenerationChunk({
|
|
758
|
+
message,
|
|
759
|
+
text: combinedText,
|
|
760
|
+
generationInfo: lastContent.generationInfo,
|
|
761
|
+
}),
|
|
762
|
+
];
|
|
763
|
+
}
|
|
764
|
+
function splitGenerationTypes(generations, _response) {
|
|
765
|
+
const content = [];
|
|
766
|
+
const reasoning = [];
|
|
767
|
+
generations.forEach((gen) => {
|
|
768
|
+
if (gen?.generationInfo?.thought) {
|
|
769
|
+
reasoning.push(gen);
|
|
770
|
+
}
|
|
771
|
+
else {
|
|
772
|
+
content.push(gen);
|
|
773
|
+
}
|
|
774
|
+
});
|
|
775
|
+
return {
|
|
776
|
+
content,
|
|
777
|
+
reasoning,
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Although this returns an array, only the first (or maybe last)
|
|
782
|
+
* element in the array is used. So we need to combine them into
|
|
783
|
+
* just one element that contains everything we need.
|
|
784
|
+
* @param response
|
|
785
|
+
*/
|
|
660
786
|
function responseToChatGenerations(response) {
|
|
661
|
-
|
|
662
|
-
if (
|
|
787
|
+
const generations = responseToGroundedChatGenerations(response);
|
|
788
|
+
if (generations.length === 0) {
|
|
663
789
|
return [];
|
|
664
790
|
}
|
|
665
|
-
|
|
666
|
-
const combinedContent = ret.map((item) => item.message.content).join("");
|
|
667
|
-
const combinedText = ret.map((item) => item.text).join("");
|
|
668
|
-
const toolCallChunks = ret[ret.length - 1]?.message.additional_kwargs?.tool_calls?.map((toolCall, i) => ({
|
|
669
|
-
name: toolCall.function.name,
|
|
670
|
-
args: toolCall.function.arguments,
|
|
671
|
-
id: toolCall.id,
|
|
672
|
-
index: i,
|
|
673
|
-
type: "tool_call_chunk",
|
|
674
|
-
}));
|
|
675
|
-
let usageMetadata;
|
|
676
|
-
if ("usageMetadata" in response.data) {
|
|
677
|
-
usageMetadata = {
|
|
678
|
-
input_tokens: response.data.usageMetadata.promptTokenCount,
|
|
679
|
-
output_tokens: response.data.usageMetadata
|
|
680
|
-
.candidatesTokenCount,
|
|
681
|
-
total_tokens: response.data.usageMetadata.totalTokenCount,
|
|
682
|
-
};
|
|
683
|
-
}
|
|
684
|
-
ret = [
|
|
685
|
-
new outputs_1.ChatGenerationChunk({
|
|
686
|
-
message: new messages_1.AIMessageChunk({
|
|
687
|
-
content: combinedContent,
|
|
688
|
-
additional_kwargs: ret[ret.length - 1]?.message.additional_kwargs,
|
|
689
|
-
tool_call_chunks: toolCallChunks,
|
|
690
|
-
usage_metadata: usageMetadata,
|
|
691
|
-
}),
|
|
692
|
-
text: combinedText,
|
|
693
|
-
generationInfo: ret[ret.length - 1].generationInfo,
|
|
694
|
-
}),
|
|
695
|
-
];
|
|
696
|
-
}
|
|
791
|
+
const ret = combineGenerations(generations, response);
|
|
697
792
|
// Add logprobs information to the message
|
|
698
793
|
const candidate = response?.data
|
|
699
794
|
?.candidates?.[0];
|
|
@@ -847,6 +942,13 @@ function getGeminiAPI(config) {
|
|
|
847
942
|
ret.logprobs = parameters.topLogprobs;
|
|
848
943
|
}
|
|
849
944
|
}
|
|
945
|
+
// Remove any undefined properties, so we don't send them
|
|
946
|
+
let attribute;
|
|
947
|
+
for (attribute in ret) {
|
|
948
|
+
if (ret[attribute] === undefined) {
|
|
949
|
+
delete ret[attribute];
|
|
950
|
+
}
|
|
951
|
+
}
|
|
850
952
|
return ret;
|
|
851
953
|
}
|
|
852
954
|
function formatSafetySettings(parameters) {
|
package/dist/utils/gemini.js
CHANGED
|
@@ -2,6 +2,7 @@ import { v4 as uuidv4 } from "uuid";
|
|
|
2
2
|
import { AIMessage, AIMessageChunk, isAIMessage, } from "@langchain/core/messages";
|
|
3
3
|
import { ChatGenerationChunk, } from "@langchain/core/outputs";
|
|
4
4
|
import { isLangChainTool } from "@langchain/core/utils/function_calling";
|
|
5
|
+
import { concat } from "@langchain/core/utils/stream";
|
|
5
6
|
import { GoogleAISafetyError } from "./safety.js";
|
|
6
7
|
import { GeminiSearchToolAttributes, } from "../types.js";
|
|
7
8
|
import { zodToGeminiParameters } from "./zod_to_gemini_parameters.js";
|
|
@@ -599,9 +600,12 @@ export function getGeminiAPI(config) {
|
|
|
599
600
|
function partToChatGeneration(part) {
|
|
600
601
|
const message = partToMessageChunk(part);
|
|
601
602
|
const text = partToText(part);
|
|
603
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
604
|
+
const generationInfo = {};
|
|
602
605
|
return new ChatGenerationChunk({
|
|
603
606
|
text,
|
|
604
607
|
message,
|
|
608
|
+
generationInfo,
|
|
605
609
|
});
|
|
606
610
|
}
|
|
607
611
|
function groundingSupportByPart(groundingSupports) {
|
|
@@ -652,43 +656,134 @@ export function getGeminiAPI(config) {
|
|
|
652
656
|
});
|
|
653
657
|
return ret;
|
|
654
658
|
}
|
|
659
|
+
function combineContent(gen, forceComplex = false) {
|
|
660
|
+
const allString = gen.every((item) => typeof item.message.content === "string");
|
|
661
|
+
if (allString && !forceComplex) {
|
|
662
|
+
// Everything is a string, and we don't want to force it to return
|
|
663
|
+
// MessageContentComplex[], so concatenate the content into one string
|
|
664
|
+
return gen.map((item) => item.message.content).join("");
|
|
665
|
+
}
|
|
666
|
+
else {
|
|
667
|
+
// We either have complex types, or we want to force them, so turn
|
|
668
|
+
// it into an array of complex types.
|
|
669
|
+
const ret = [];
|
|
670
|
+
gen.forEach((item) => {
|
|
671
|
+
if (typeof item.message.content === "string") {
|
|
672
|
+
// If this is a string, turn it into a text type
|
|
673
|
+
ret.push({
|
|
674
|
+
text: item.message.content,
|
|
675
|
+
});
|
|
676
|
+
}
|
|
677
|
+
else {
|
|
678
|
+
// Otherwise, add all the complex types to what we're returning
|
|
679
|
+
item.message.content.forEach((c) => {
|
|
680
|
+
ret.push(c);
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
});
|
|
684
|
+
return ret;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
function combineText(gen) {
|
|
688
|
+
return gen.map((item) => item.text ?? "").join("");
|
|
689
|
+
}
|
|
690
|
+
/*
|
|
691
|
+
* We don't really need the entire AIMessageChunk here, but it is
|
|
692
|
+
* a conventient way to combine all the Tool Calling information.
|
|
693
|
+
*/
|
|
694
|
+
function combineToolCalls(gen) {
|
|
695
|
+
let ret = new AIMessageChunk("");
|
|
696
|
+
gen.forEach((item) => {
|
|
697
|
+
const message = item?.message;
|
|
698
|
+
ret = concat(ret, message);
|
|
699
|
+
});
|
|
700
|
+
return ret;
|
|
701
|
+
}
|
|
702
|
+
function combineAdditionalKwargs(gen) {
|
|
703
|
+
const ret = {};
|
|
704
|
+
gen.forEach((item) => {
|
|
705
|
+
const message = item?.message;
|
|
706
|
+
const kwargs = message?.additional_kwargs ?? {};
|
|
707
|
+
const keys = Object.keys(kwargs);
|
|
708
|
+
keys.forEach((key) => {
|
|
709
|
+
const value = kwargs[key];
|
|
710
|
+
if (Object.hasOwn(ret, key) &&
|
|
711
|
+
Array.isArray(ret[key]) &&
|
|
712
|
+
Array.isArray(value)) {
|
|
713
|
+
ret[key].push(...value);
|
|
714
|
+
}
|
|
715
|
+
else {
|
|
716
|
+
ret[key] = value;
|
|
717
|
+
}
|
|
718
|
+
});
|
|
719
|
+
});
|
|
720
|
+
return ret;
|
|
721
|
+
}
|
|
722
|
+
function combineGenerations(generations, response) {
|
|
723
|
+
const gen = splitGenerationTypes(generations, response);
|
|
724
|
+
const combinedContent = combineContent(gen.content);
|
|
725
|
+
const combinedText = combineText(gen.content);
|
|
726
|
+
const combinedToolCalls = combineToolCalls(gen.content);
|
|
727
|
+
const kwargs = combineAdditionalKwargs(gen.content);
|
|
728
|
+
const lastContent = gen.content[gen.content.length - 1];
|
|
729
|
+
// Add usage metadata
|
|
730
|
+
let usageMetadata;
|
|
731
|
+
if ("usageMetadata" in response.data) {
|
|
732
|
+
usageMetadata = {
|
|
733
|
+
input_tokens: response.data.usageMetadata.promptTokenCount,
|
|
734
|
+
output_tokens: response.data.usageMetadata
|
|
735
|
+
.candidatesTokenCount,
|
|
736
|
+
total_tokens: response.data.usageMetadata.totalTokenCount,
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
// Add thinking / reasoning
|
|
740
|
+
// if (gen.reasoning && gen.reasoning.length > 0) {
|
|
741
|
+
// kwargs.reasoning_content = combineContent(gen.reasoning, true);
|
|
742
|
+
// }
|
|
743
|
+
// Build the message and the generation chunk to return
|
|
744
|
+
const message = new AIMessageChunk({
|
|
745
|
+
content: combinedContent,
|
|
746
|
+
additional_kwargs: kwargs,
|
|
747
|
+
usage_metadata: usageMetadata,
|
|
748
|
+
tool_calls: combinedToolCalls.tool_calls,
|
|
749
|
+
invalid_tool_calls: combinedToolCalls.invalid_tool_calls,
|
|
750
|
+
});
|
|
751
|
+
return [
|
|
752
|
+
new ChatGenerationChunk({
|
|
753
|
+
message,
|
|
754
|
+
text: combinedText,
|
|
755
|
+
generationInfo: lastContent.generationInfo,
|
|
756
|
+
}),
|
|
757
|
+
];
|
|
758
|
+
}
|
|
759
|
+
function splitGenerationTypes(generations, _response) {
|
|
760
|
+
const content = [];
|
|
761
|
+
const reasoning = [];
|
|
762
|
+
generations.forEach((gen) => {
|
|
763
|
+
if (gen?.generationInfo?.thought) {
|
|
764
|
+
reasoning.push(gen);
|
|
765
|
+
}
|
|
766
|
+
else {
|
|
767
|
+
content.push(gen);
|
|
768
|
+
}
|
|
769
|
+
});
|
|
770
|
+
return {
|
|
771
|
+
content,
|
|
772
|
+
reasoning,
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* Although this returns an array, only the first (or maybe last)
|
|
777
|
+
* element in the array is used. So we need to combine them into
|
|
778
|
+
* just one element that contains everything we need.
|
|
779
|
+
* @param response
|
|
780
|
+
*/
|
|
655
781
|
function responseToChatGenerations(response) {
|
|
656
|
-
|
|
657
|
-
if (
|
|
782
|
+
const generations = responseToGroundedChatGenerations(response);
|
|
783
|
+
if (generations.length === 0) {
|
|
658
784
|
return [];
|
|
659
785
|
}
|
|
660
|
-
|
|
661
|
-
const combinedContent = ret.map((item) => item.message.content).join("");
|
|
662
|
-
const combinedText = ret.map((item) => item.text).join("");
|
|
663
|
-
const toolCallChunks = ret[ret.length - 1]?.message.additional_kwargs?.tool_calls?.map((toolCall, i) => ({
|
|
664
|
-
name: toolCall.function.name,
|
|
665
|
-
args: toolCall.function.arguments,
|
|
666
|
-
id: toolCall.id,
|
|
667
|
-
index: i,
|
|
668
|
-
type: "tool_call_chunk",
|
|
669
|
-
}));
|
|
670
|
-
let usageMetadata;
|
|
671
|
-
if ("usageMetadata" in response.data) {
|
|
672
|
-
usageMetadata = {
|
|
673
|
-
input_tokens: response.data.usageMetadata.promptTokenCount,
|
|
674
|
-
output_tokens: response.data.usageMetadata
|
|
675
|
-
.candidatesTokenCount,
|
|
676
|
-
total_tokens: response.data.usageMetadata.totalTokenCount,
|
|
677
|
-
};
|
|
678
|
-
}
|
|
679
|
-
ret = [
|
|
680
|
-
new ChatGenerationChunk({
|
|
681
|
-
message: new AIMessageChunk({
|
|
682
|
-
content: combinedContent,
|
|
683
|
-
additional_kwargs: ret[ret.length - 1]?.message.additional_kwargs,
|
|
684
|
-
tool_call_chunks: toolCallChunks,
|
|
685
|
-
usage_metadata: usageMetadata,
|
|
686
|
-
}),
|
|
687
|
-
text: combinedText,
|
|
688
|
-
generationInfo: ret[ret.length - 1].generationInfo,
|
|
689
|
-
}),
|
|
690
|
-
];
|
|
691
|
-
}
|
|
786
|
+
const ret = combineGenerations(generations, response);
|
|
692
787
|
// Add logprobs information to the message
|
|
693
788
|
const candidate = response?.data
|
|
694
789
|
?.candidates?.[0];
|
|
@@ -842,6 +937,13 @@ export function getGeminiAPI(config) {
|
|
|
842
937
|
ret.logprobs = parameters.topLogprobs;
|
|
843
938
|
}
|
|
844
939
|
}
|
|
940
|
+
// Remove any undefined properties, so we don't send them
|
|
941
|
+
let attribute;
|
|
942
|
+
for (attribute in ret) {
|
|
943
|
+
if (ret[attribute] === undefined) {
|
|
944
|
+
delete ret[attribute];
|
|
945
|
+
}
|
|
946
|
+
}
|
|
845
947
|
return ret;
|
|
846
948
|
}
|
|
847
949
|
function formatSafetySettings(parameters) {
|