@langchain/google-common 0.0.0 → 0.0.2

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.
@@ -1,12 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isModelGemini = exports.validateGeminiParams = exports.responseToChatResult = exports.responseToBaseMessage = exports.responseToMessageContent = exports.responseToChatGenerations = exports.partToChatGeneration = exports.partToMessage = exports.responseToChatGeneration = exports.responseToGeneration = exports.responseToString = exports.partToText = exports.responseToParts = exports.responseToGenerateContentResponseData = exports.partsToMessageContent = exports.baseMessageToContent = exports.messageContentToParts = void 0;
3
+ exports.MessageGeminiSafetyHandler = exports.DefaultGeminiSafetyHandler = exports.isModelGemini = exports.validateGeminiParams = exports.safeResponseToChatResult = exports.responseToChatResult = exports.safeResponseToBaseMessage = exports.responseToBaseMessage = exports.partsToBaseMessageFields = exports.responseToBaseMessageFields = exports.responseToChatGenerations = exports.partToChatGeneration = exports.partToMessage = exports.chunkToString = exports.safeResponseToChatGeneration = exports.responseToChatGeneration = exports.safeResponseToGeneration = exports.responseToGeneration = exports.safeResponseToString = exports.responseToString = exports.partToText = exports.responseToParts = exports.responseToGenerateContentResponseData = exports.toolsRawToTools = exports.partsToToolsRaw = exports.partsToMessageContent = exports.baseMessageToContent = exports.messageContentToParts = void 0;
4
4
  const messages_1 = require("@langchain/core/messages");
5
5
  const outputs_1 = require("@langchain/core/outputs");
6
+ const safety_js_1 = require("./safety.cjs");
6
7
  function messageContentText(content) {
7
- return {
8
- text: content.text,
9
- };
8
+ if (content?.text && content?.text.length > 0) {
9
+ return {
10
+ text: content.text,
11
+ };
12
+ }
13
+ else {
14
+ return null;
15
+ }
10
16
  }
11
17
  function messageContentImageUrl(content) {
12
18
  const url = typeof content.image_url === "string"
@@ -17,15 +23,19 @@ function messageContentImageUrl(content) {
17
23
  }
18
24
  if (url.startsWith("data:")) {
19
25
  return {
20
- mimeType: url.split(":")[1].split(";")[0],
21
- data: url.split(",")[1],
26
+ inlineData: {
27
+ mimeType: url.split(":")[1].split(";")[0],
28
+ data: url.split(",")[1],
29
+ },
22
30
  };
23
31
  }
24
32
  else {
25
33
  // FIXME - need some way to get mime type
26
34
  return {
27
- mimeType: "image/png",
28
- fileUri: url,
35
+ fileData: {
36
+ mimeType: "image/png",
37
+ fileUri: url,
38
+ },
29
39
  };
30
40
  }
31
41
  }
@@ -40,23 +50,61 @@ function messageContentToParts(content) {
40
50
  ]
41
51
  : content;
42
52
  // eslint-disable-next-line array-callback-return
43
- const parts = messageContent.map((content) => {
44
- // eslint-disable-next-line default-case
53
+ const parts = messageContent
54
+ .map((content) => {
45
55
  switch (content.type) {
46
56
  case "text":
47
57
  return messageContentText(content);
48
58
  case "image_url":
49
59
  return messageContentImageUrl(content);
60
+ default:
61
+ throw new Error(`Unsupported type received while converting message to message parts`);
50
62
  }
51
- });
63
+ })
64
+ .reduce((acc, val) => {
65
+ if (val) {
66
+ return [...acc, val];
67
+ }
68
+ else {
69
+ return acc;
70
+ }
71
+ }, []);
52
72
  return parts;
53
73
  }
54
74
  exports.messageContentToParts = messageContentToParts;
75
+ function messageToolCallsToParts(toolCalls) {
76
+ if (!toolCalls || toolCalls.length === 0) {
77
+ return [];
78
+ }
79
+ return toolCalls.map((tool) => {
80
+ let args = {};
81
+ if (tool?.function?.arguments) {
82
+ const argStr = tool.function.arguments;
83
+ args = JSON.parse(argStr);
84
+ }
85
+ return {
86
+ functionCall: {
87
+ name: tool.function.name,
88
+ args,
89
+ },
90
+ };
91
+ });
92
+ }
93
+ function messageKwargsToParts(kwargs) {
94
+ const ret = [];
95
+ if (kwargs?.tool_calls) {
96
+ ret.push(...messageToolCallsToParts(kwargs.tool_calls));
97
+ }
98
+ return ret;
99
+ }
55
100
  function roleMessageToContent(role, message) {
101
+ const contentParts = messageContentToParts(message.content);
102
+ const toolParts = messageKwargsToParts(message.additional_kwargs);
103
+ const parts = [...contentParts, ...toolParts];
56
104
  return [
57
105
  {
58
106
  role,
59
- parts: messageContentToParts(message.content),
107
+ parts,
60
108
  },
61
109
  ];
62
110
  }
@@ -66,6 +114,32 @@ function systemMessageToContent(message) {
66
114
  ...roleMessageToContent("model", new messages_1.AIMessage("Ok")),
67
115
  ];
68
116
  }
117
+ function toolMessageToContent(message) {
118
+ const contentStr = typeof message.content === "string"
119
+ ? message.content
120
+ : message.content.reduce((acc, content) => {
121
+ if (content.type === "text") {
122
+ return acc + content.text;
123
+ }
124
+ else {
125
+ return acc;
126
+ }
127
+ }, "");
128
+ const content = JSON.parse(contentStr);
129
+ return [
130
+ {
131
+ role: "function",
132
+ parts: [
133
+ {
134
+ functionResponse: {
135
+ name: message.tool_call_id,
136
+ response: content,
137
+ },
138
+ },
139
+ ],
140
+ },
141
+ ];
142
+ }
69
143
  function baseMessageToContent(message) {
70
144
  const type = message._getType();
71
145
  switch (type) {
@@ -75,6 +149,8 @@ function baseMessageToContent(message) {
75
149
  return roleMessageToContent("user", message);
76
150
  case "ai":
77
151
  return roleMessageToContent("model", message);
152
+ case "tool":
153
+ return toolMessageToContent(message);
78
154
  default:
79
155
  console.log(`Unsupported message type: ${type}`);
80
156
  return [];
@@ -90,25 +166,28 @@ function textPartToMessageContent(part) {
90
166
  function inlineDataPartToMessageContent(part) {
91
167
  return {
92
168
  type: "image_url",
93
- image_url: `data:${part.mimeType};base64,${part.data}`,
169
+ image_url: `data:${part.inlineData.mimeType};base64,${part.inlineData.data}`,
94
170
  };
95
171
  }
96
172
  function fileDataPartToMessageContent(part) {
97
173
  return {
98
174
  type: "image_url",
99
- image_url: part.fileUri,
175
+ image_url: part.fileData.fileUri,
100
176
  };
101
177
  }
102
178
  function partsToMessageContent(parts) {
103
179
  return parts
104
180
  .map((part) => {
105
- if ("text" in part) {
181
+ if (part === undefined || part === null) {
182
+ return null;
183
+ }
184
+ else if ("text" in part) {
106
185
  return textPartToMessageContent(part);
107
186
  }
108
- else if ("mimeType" in part && "data" in part) {
187
+ else if ("inlineData" in part) {
109
188
  return inlineDataPartToMessageContent(part);
110
189
  }
111
- else if ("mimeType" in part && "fileUri" in part) {
190
+ else if ("fileData" in part) {
112
191
  return fileDataPartToMessageContent(part);
113
192
  }
114
193
  else {
@@ -123,6 +202,51 @@ function partsToMessageContent(parts) {
123
202
  }, []);
124
203
  }
125
204
  exports.partsToMessageContent = partsToMessageContent;
205
+ function toolRawToTool(raw) {
206
+ return {
207
+ id: raw.id,
208
+ type: raw.type,
209
+ function: {
210
+ name: raw.function.name,
211
+ arguments: JSON.stringify(raw.function.arguments),
212
+ },
213
+ };
214
+ }
215
+ function functionCallPartToToolRaw(part) {
216
+ return {
217
+ id: part?.functionCall?.name ?? "",
218
+ type: "function",
219
+ function: {
220
+ name: part.functionCall.name,
221
+ arguments: part.functionCall.args ?? {},
222
+ },
223
+ };
224
+ }
225
+ function partsToToolsRaw(parts) {
226
+ return parts
227
+ .map((part) => {
228
+ if (part === undefined || part === null) {
229
+ return null;
230
+ }
231
+ else if ("functionCall" in part) {
232
+ return functionCallPartToToolRaw(part);
233
+ }
234
+ else {
235
+ return null;
236
+ }
237
+ })
238
+ .reduce((acc, content) => {
239
+ if (content) {
240
+ acc.push(content);
241
+ }
242
+ return acc;
243
+ }, []);
244
+ }
245
+ exports.partsToToolsRaw = partsToToolsRaw;
246
+ function toolsRawToTools(raws) {
247
+ return raws.map((raw) => toolRawToTool(raw));
248
+ }
249
+ exports.toolsRawToTools = toolsRawToTools;
126
250
  function responseToGenerateContentResponseData(response) {
127
251
  if ("nextChunk" in response.data) {
128
252
  throw new Error("Cannot convert Stream to GenerateContentResponseData");
@@ -163,6 +287,24 @@ function responseToString(response) {
163
287
  return ret;
164
288
  }
165
289
  exports.responseToString = responseToString;
290
+ function safeResponseTo(response, safetyHandler, responseTo) {
291
+ try {
292
+ const safeResponse = safetyHandler.handle(response);
293
+ return responseTo(safeResponse);
294
+ }
295
+ catch (xx) {
296
+ // eslint-disable-next-line no-instanceof/no-instanceof
297
+ if (xx instanceof safety_js_1.GoogleAISafetyError) {
298
+ const ret = responseTo(xx.response);
299
+ xx.reply = ret;
300
+ }
301
+ throw xx;
302
+ }
303
+ }
304
+ function safeResponseToString(response, safetyHandler) {
305
+ return safeResponseTo(response, safetyHandler, responseToString);
306
+ }
307
+ exports.safeResponseToString = safeResponseToString;
166
308
  function responseToGeneration(response) {
167
309
  return {
168
310
  text: responseToString(response),
@@ -170,6 +312,10 @@ function responseToGeneration(response) {
170
312
  };
171
313
  }
172
314
  exports.responseToGeneration = responseToGeneration;
315
+ function safeResponseToGeneration(response, safetyHandler) {
316
+ return safeResponseTo(response, safetyHandler, responseToGeneration);
317
+ }
318
+ exports.safeResponseToGeneration = safeResponseToGeneration;
173
319
  function responseToChatGeneration(response) {
174
320
  return new outputs_1.ChatGenerationChunk({
175
321
  text: responseToString(response),
@@ -178,9 +324,31 @@ function responseToChatGeneration(response) {
178
324
  });
179
325
  }
180
326
  exports.responseToChatGeneration = responseToChatGeneration;
327
+ function safeResponseToChatGeneration(response, safetyHandler) {
328
+ return safeResponseTo(response, safetyHandler, responseToChatGeneration);
329
+ }
330
+ exports.safeResponseToChatGeneration = safeResponseToChatGeneration;
331
+ function chunkToString(chunk) {
332
+ if (chunk === null) {
333
+ return "";
334
+ }
335
+ else if (typeof chunk.content === "string") {
336
+ return chunk.content;
337
+ }
338
+ else if (chunk.content.length === 0) {
339
+ return "";
340
+ }
341
+ else if (chunk.content[0].type === "text") {
342
+ return chunk.content[0].text;
343
+ }
344
+ else {
345
+ throw new Error(`Unexpected chunk: ${chunk}`);
346
+ }
347
+ }
348
+ exports.chunkToString = chunkToString;
181
349
  function partToMessage(part) {
182
- const content = partsToMessageContent([part]);
183
- return new messages_1.AIMessageChunk({ content });
350
+ const fields = partsToBaseMessageFields([part]);
351
+ return new messages_1.AIMessageChunk(fields);
184
352
  }
185
353
  exports.partToMessage = partToMessage;
186
354
  function partToChatGeneration(part) {
@@ -198,17 +366,34 @@ function responseToChatGenerations(response) {
198
366
  return ret;
199
367
  }
200
368
  exports.responseToChatGenerations = responseToChatGenerations;
201
- function responseToMessageContent(response) {
369
+ function responseToBaseMessageFields(response) {
202
370
  const parts = responseToParts(response);
203
- return partsToMessageContent(parts);
371
+ return partsToBaseMessageFields(parts);
204
372
  }
205
- exports.responseToMessageContent = responseToMessageContent;
373
+ exports.responseToBaseMessageFields = responseToBaseMessageFields;
374
+ function partsToBaseMessageFields(parts) {
375
+ const fields = {
376
+ content: partsToMessageContent(parts),
377
+ };
378
+ const rawTools = partsToToolsRaw(parts);
379
+ if (rawTools.length > 0) {
380
+ const tools = toolsRawToTools(rawTools);
381
+ fields.additional_kwargs = {
382
+ tool_calls: tools,
383
+ };
384
+ }
385
+ return fields;
386
+ }
387
+ exports.partsToBaseMessageFields = partsToBaseMessageFields;
206
388
  function responseToBaseMessage(response) {
207
- return new messages_1.AIMessage({
208
- content: responseToMessageContent(response),
209
- });
389
+ const fields = responseToBaseMessageFields(response);
390
+ return new messages_1.AIMessage(fields);
210
391
  }
211
392
  exports.responseToBaseMessage = responseToBaseMessage;
393
+ function safeResponseToBaseMessage(response, safetyHandler) {
394
+ return safeResponseTo(response, safetyHandler, responseToBaseMessage);
395
+ }
396
+ exports.safeResponseToBaseMessage = safeResponseToBaseMessage;
212
397
  function responseToChatResult(response) {
213
398
  const generations = responseToChatGenerations(response);
214
399
  return {
@@ -217,6 +402,10 @@ function responseToChatResult(response) {
217
402
  };
218
403
  }
219
404
  exports.responseToChatResult = responseToChatResult;
405
+ function safeResponseToChatResult(response, safetyHandler) {
406
+ return safeResponseTo(response, safetyHandler, responseToChatResult);
407
+ }
408
+ exports.safeResponseToChatResult = safeResponseToChatResult;
220
409
  function validateGeminiParams(params) {
221
410
  if (params.maxOutputTokens && params.maxOutputTokens < 0) {
222
411
  throw new Error("`maxOutputTokens` must be a positive integer");
@@ -237,3 +426,110 @@ function isModelGemini(modelName) {
237
426
  return modelName.toLowerCase().startsWith("gemini");
238
427
  }
239
428
  exports.isModelGemini = isModelGemini;
429
+ class DefaultGeminiSafetyHandler {
430
+ constructor(settings) {
431
+ Object.defineProperty(this, "errorFinish", {
432
+ enumerable: true,
433
+ configurable: true,
434
+ writable: true,
435
+ value: ["SAFETY", "RECITATION", "OTHER"]
436
+ });
437
+ this.errorFinish = settings?.errorFinish ?? this.errorFinish;
438
+ }
439
+ handleDataPromptFeedback(response, data) {
440
+ // Check to see if our prompt was blocked in the first place
441
+ const promptFeedback = data?.promptFeedback;
442
+ const blockReason = promptFeedback?.blockReason;
443
+ if (blockReason) {
444
+ throw new safety_js_1.GoogleAISafetyError(response, `Prompt blocked: ${blockReason}`);
445
+ }
446
+ return data;
447
+ }
448
+ handleDataFinishReason(response, data) {
449
+ const firstCandidate = data?.candidates?.[0];
450
+ const finishReason = firstCandidate?.finishReason;
451
+ if (this.errorFinish.includes(finishReason)) {
452
+ throw new safety_js_1.GoogleAISafetyError(response, `Finish reason: ${finishReason}`);
453
+ }
454
+ return data;
455
+ }
456
+ handleData(response, data) {
457
+ let ret = data;
458
+ ret = this.handleDataPromptFeedback(response, ret);
459
+ ret = this.handleDataFinishReason(response, ret);
460
+ return ret;
461
+ }
462
+ handle(response) {
463
+ let newdata;
464
+ if ("nextChunk" in response.data) {
465
+ // TODO: This is a stream. How to handle?
466
+ newdata = response.data;
467
+ }
468
+ else if (Array.isArray(response.data)) {
469
+ // If it is an array, try to handle every item in the array
470
+ try {
471
+ newdata = response.data.map((item) => this.handleData(response, item));
472
+ }
473
+ catch (xx) {
474
+ // eslint-disable-next-line no-instanceof/no-instanceof
475
+ if (xx instanceof safety_js_1.GoogleAISafetyError) {
476
+ throw new safety_js_1.GoogleAISafetyError(response, xx.message);
477
+ }
478
+ else {
479
+ throw xx;
480
+ }
481
+ }
482
+ }
483
+ else {
484
+ const data = response.data;
485
+ newdata = this.handleData(response, data);
486
+ }
487
+ return {
488
+ ...response,
489
+ data: newdata,
490
+ };
491
+ }
492
+ }
493
+ exports.DefaultGeminiSafetyHandler = DefaultGeminiSafetyHandler;
494
+ class MessageGeminiSafetyHandler extends DefaultGeminiSafetyHandler {
495
+ constructor(settings) {
496
+ super(settings);
497
+ Object.defineProperty(this, "msg", {
498
+ enumerable: true,
499
+ configurable: true,
500
+ writable: true,
501
+ value: ""
502
+ });
503
+ Object.defineProperty(this, "forceNewMessage", {
504
+ enumerable: true,
505
+ configurable: true,
506
+ writable: true,
507
+ value: false
508
+ });
509
+ this.msg = settings?.msg ?? this.msg;
510
+ this.forceNewMessage = settings?.forceNewMessage ?? this.forceNewMessage;
511
+ }
512
+ setMessage(data) {
513
+ const ret = data;
514
+ if (this.forceNewMessage ||
515
+ !data?.candidates?.[0]?.content?.parts?.length) {
516
+ ret.candidates = data.candidates ?? [];
517
+ ret.candidates[0] = data.candidates[0] ?? {};
518
+ ret.candidates[0].content = data.candidates[0].content ?? {};
519
+ ret.candidates[0].content = {
520
+ role: "model",
521
+ parts: [{ text: this.msg }],
522
+ };
523
+ }
524
+ return ret;
525
+ }
526
+ handleData(response, data) {
527
+ try {
528
+ return super.handleData(response, data);
529
+ }
530
+ catch (xx) {
531
+ return this.setMessage(data);
532
+ }
533
+ }
534
+ }
535
+ exports.MessageGeminiSafetyHandler = MessageGeminiSafetyHandler;
@@ -1,20 +1,70 @@
1
- import { BaseMessage, BaseMessageChunk, MessageContent } from "@langchain/core/messages";
1
+ import { BaseMessage, BaseMessageChunk, BaseMessageFields, MessageContent } from "@langchain/core/messages";
2
2
  import { ChatGeneration, ChatGenerationChunk, ChatResult, Generation } from "@langchain/core/outputs";
3
- import type { GoogleLLMResponse, GoogleAIModelParams, GeminiPart, GeminiContent, GenerateContentResponseData } from "../types.js";
3
+ import type { GoogleLLMResponse, GoogleAIModelParams, GeminiPart, GeminiContent, GenerateContentResponseData, GoogleAISafetyHandler } from "../types.js";
4
4
  export declare function messageContentToParts(content: MessageContent): GeminiPart[];
5
5
  export declare function baseMessageToContent(message: BaseMessage): GeminiContent[];
6
6
  export declare function partsToMessageContent(parts: GeminiPart[]): MessageContent;
7
+ interface FunctionCall {
8
+ name: string;
9
+ arguments: string;
10
+ }
11
+ interface ToolCall {
12
+ id: string;
13
+ type: "function";
14
+ function: FunctionCall;
15
+ }
16
+ interface FunctionCallRaw {
17
+ name: string;
18
+ arguments: object;
19
+ }
20
+ interface ToolCallRaw {
21
+ id: string;
22
+ type: "function";
23
+ function: FunctionCallRaw;
24
+ }
25
+ export declare function partsToToolsRaw(parts: GeminiPart[]): ToolCallRaw[];
26
+ export declare function toolsRawToTools(raws: ToolCallRaw[]): ToolCall[];
7
27
  export declare function responseToGenerateContentResponseData(response: GoogleLLMResponse): GenerateContentResponseData;
8
28
  export declare function responseToParts(response: GoogleLLMResponse): GeminiPart[];
9
29
  export declare function partToText(part: GeminiPart): string;
10
30
  export declare function responseToString(response: GoogleLLMResponse): string;
31
+ export declare function safeResponseToString(response: GoogleLLMResponse, safetyHandler: GoogleAISafetyHandler): string;
11
32
  export declare function responseToGeneration(response: GoogleLLMResponse): Generation;
33
+ export declare function safeResponseToGeneration(response: GoogleLLMResponse, safetyHandler: GoogleAISafetyHandler): Generation;
12
34
  export declare function responseToChatGeneration(response: GoogleLLMResponse): ChatGenerationChunk;
35
+ export declare function safeResponseToChatGeneration(response: GoogleLLMResponse, safetyHandler: GoogleAISafetyHandler): ChatGenerationChunk;
36
+ export declare function chunkToString(chunk: BaseMessageChunk): string;
13
37
  export declare function partToMessage(part: GeminiPart): BaseMessageChunk;
14
38
  export declare function partToChatGeneration(part: GeminiPart): ChatGeneration;
15
39
  export declare function responseToChatGenerations(response: GoogleLLMResponse): ChatGeneration[];
16
- export declare function responseToMessageContent(response: GoogleLLMResponse): MessageContent;
40
+ export declare function responseToBaseMessageFields(response: GoogleLLMResponse): BaseMessageFields;
41
+ export declare function partsToBaseMessageFields(parts: GeminiPart[]): BaseMessageFields;
17
42
  export declare function responseToBaseMessage(response: GoogleLLMResponse): BaseMessage;
43
+ export declare function safeResponseToBaseMessage(response: GoogleLLMResponse, safetyHandler: GoogleAISafetyHandler): BaseMessage;
18
44
  export declare function responseToChatResult(response: GoogleLLMResponse): ChatResult;
45
+ export declare function safeResponseToChatResult(response: GoogleLLMResponse, safetyHandler: GoogleAISafetyHandler): ChatResult;
19
46
  export declare function validateGeminiParams(params: GoogleAIModelParams): void;
20
47
  export declare function isModelGemini(modelName: string): boolean;
48
+ export interface DefaultGeminiSafetySettings {
49
+ errorFinish?: string[];
50
+ }
51
+ export declare class DefaultGeminiSafetyHandler implements GoogleAISafetyHandler {
52
+ errorFinish: string[];
53
+ constructor(settings?: DefaultGeminiSafetySettings);
54
+ handleDataPromptFeedback(response: GoogleLLMResponse, data: GenerateContentResponseData): GenerateContentResponseData;
55
+ handleDataFinishReason(response: GoogleLLMResponse, data: GenerateContentResponseData): GenerateContentResponseData;
56
+ handleData(response: GoogleLLMResponse, data: GenerateContentResponseData): GenerateContentResponseData;
57
+ handle(response: GoogleLLMResponse): GoogleLLMResponse;
58
+ }
59
+ export interface MessageGeminiSafetySettings extends DefaultGeminiSafetySettings {
60
+ msg?: string;
61
+ forceNewMessage?: boolean;
62
+ }
63
+ export declare class MessageGeminiSafetyHandler extends DefaultGeminiSafetyHandler {
64
+ msg: string;
65
+ forceNewMessage: boolean;
66
+ constructor(settings?: MessageGeminiSafetySettings);
67
+ setMessage(data: GenerateContentResponseData): GenerateContentResponseData;
68
+ handleData(response: GoogleLLMResponse, data: GenerateContentResponseData): GenerateContentResponseData;
69
+ }
70
+ export {};