@langchain/google-common 0.0.2 → 0.0.4

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.
@@ -22,6 +22,58 @@ function copyAIModelParamsInto(params, options, target) {
22
22
  ret.safetySettings =
23
23
  options?.safetySettings ?? params?.safetySettings ?? target.safetySettings;
24
24
  ret.tools = options?.tools;
25
+ // Ensure tools are formatted properly for Gemini
26
+ const geminiTools = options?.tools
27
+ ?.map((tool) => {
28
+ if ("function" in tool &&
29
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
30
+ "parameters" in tool.function) {
31
+ // Tool is in OpenAI format. Convert to Gemini then return.
32
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
33
+ const castTool = tool.function;
34
+ const cleanedParameters = castTool.parameters;
35
+ if ("$schema" in cleanedParameters) {
36
+ delete cleanedParameters.$schema;
37
+ }
38
+ if ("additionalProperties" in cleanedParameters) {
39
+ delete cleanedParameters.additionalProperties;
40
+ }
41
+ const toolInGeminiFormat = {
42
+ functionDeclarations: [
43
+ {
44
+ name: castTool.name,
45
+ description: castTool.description,
46
+ parameters: cleanedParameters,
47
+ },
48
+ ],
49
+ };
50
+ return toolInGeminiFormat;
51
+ }
52
+ else if ("functionDeclarations" in tool) {
53
+ return tool;
54
+ }
55
+ else {
56
+ return null;
57
+ }
58
+ })
59
+ .filter((tool) => tool !== null);
60
+ const structuredOutputTools = options?.tools
61
+ ?.map((tool) => {
62
+ if ("lc_namespace" in tool) {
63
+ return tool;
64
+ }
65
+ else {
66
+ return null;
67
+ }
68
+ })
69
+ .filter((tool) => tool !== null);
70
+ if (structuredOutputTools &&
71
+ structuredOutputTools.length > 0 &&
72
+ geminiTools &&
73
+ geminiTools.length > 0) {
74
+ throw new Error(`Cannot mix structured tools with Gemini tools.\nReceived ${structuredOutputTools.length} structured tools and ${geminiTools.length} Gemini tools.`);
75
+ }
76
+ ret.tools = geminiTools ?? structuredOutputTools;
25
77
  return ret;
26
78
  }
27
79
  exports.copyAIModelParamsInto = copyAIModelParamsInto;
@@ -18,6 +18,58 @@ export function copyAIModelParamsInto(params, options, target) {
18
18
  ret.safetySettings =
19
19
  options?.safetySettings ?? params?.safetySettings ?? target.safetySettings;
20
20
  ret.tools = options?.tools;
21
+ // Ensure tools are formatted properly for Gemini
22
+ const geminiTools = options?.tools
23
+ ?.map((tool) => {
24
+ if ("function" in tool &&
25
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
+ "parameters" in tool.function) {
27
+ // Tool is in OpenAI format. Convert to Gemini then return.
28
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
+ const castTool = tool.function;
30
+ const cleanedParameters = castTool.parameters;
31
+ if ("$schema" in cleanedParameters) {
32
+ delete cleanedParameters.$schema;
33
+ }
34
+ if ("additionalProperties" in cleanedParameters) {
35
+ delete cleanedParameters.additionalProperties;
36
+ }
37
+ const toolInGeminiFormat = {
38
+ functionDeclarations: [
39
+ {
40
+ name: castTool.name,
41
+ description: castTool.description,
42
+ parameters: cleanedParameters,
43
+ },
44
+ ],
45
+ };
46
+ return toolInGeminiFormat;
47
+ }
48
+ else if ("functionDeclarations" in tool) {
49
+ return tool;
50
+ }
51
+ else {
52
+ return null;
53
+ }
54
+ })
55
+ .filter((tool) => tool !== null);
56
+ const structuredOutputTools = options?.tools
57
+ ?.map((tool) => {
58
+ if ("lc_namespace" in tool) {
59
+ return tool;
60
+ }
61
+ else {
62
+ return null;
63
+ }
64
+ })
65
+ .filter((tool) => tool !== null);
66
+ if (structuredOutputTools &&
67
+ structuredOutputTools.length > 0 &&
68
+ geminiTools &&
69
+ geminiTools.length > 0) {
70
+ throw new Error(`Cannot mix structured tools with Gemini tools.\nReceived ${structuredOutputTools.length} structured tools and ${geminiTools.length} Gemini tools.`);
71
+ }
72
+ ret.tools = geminiTools ?? structuredOutputTools;
21
73
  return ret;
22
74
  }
23
75
  export function modelToFamily(modelName) {
@@ -54,12 +54,20 @@ function messageContentToParts(content) {
54
54
  .map((content) => {
55
55
  switch (content.type) {
56
56
  case "text":
57
- return messageContentText(content);
57
+ if ("text" in content) {
58
+ return messageContentText(content);
59
+ }
60
+ break;
58
61
  case "image_url":
59
- return messageContentImageUrl(content);
62
+ if ("image_url" in content) {
63
+ // Type guard for MessageContentImageUrl
64
+ return messageContentImageUrl(content);
65
+ }
66
+ break;
60
67
  default:
61
68
  throw new Error(`Unsupported type received while converting message to message parts`);
62
69
  }
70
+ throw new Error(`Cannot coerce "${content.type}" message part into a string.`);
63
71
  })
64
72
  .reduce((acc, val) => {
65
73
  if (val) {
@@ -125,20 +133,39 @@ function toolMessageToContent(message) {
125
133
  return acc;
126
134
  }
127
135
  }, "");
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,
136
+ try {
137
+ const content = JSON.parse(contentStr);
138
+ return [
139
+ {
140
+ role: "function",
141
+ parts: [
142
+ {
143
+ functionResponse: {
144
+ name: message.tool_call_id,
145
+ response: content,
146
+ },
137
147
  },
138
- },
139
- ],
140
- },
141
- ];
148
+ ],
149
+ },
150
+ ];
151
+ }
152
+ catch (_) {
153
+ return [
154
+ {
155
+ role: "function",
156
+ parts: [
157
+ {
158
+ functionResponse: {
159
+ name: message.tool_call_id,
160
+ response: {
161
+ response: contentStr,
162
+ },
163
+ },
164
+ },
165
+ ],
166
+ },
167
+ ];
168
+ }
142
169
  }
143
170
  function baseMessageToContent(message) {
144
171
  const type = message._getType();
@@ -348,6 +375,18 @@ function chunkToString(chunk) {
348
375
  exports.chunkToString = chunkToString;
349
376
  function partToMessage(part) {
350
377
  const fields = partsToBaseMessageFields([part]);
378
+ if (typeof fields.content === "string") {
379
+ return new messages_1.AIMessageChunk(fields);
380
+ }
381
+ else if (fields.content.every((item) => item.type === "text")) {
382
+ const newContent = fields.content
383
+ .map((item) => ("text" in item ? item.text : ""))
384
+ .join("");
385
+ return new messages_1.AIMessageChunk({
386
+ ...fields,
387
+ content: newContent,
388
+ });
389
+ }
351
390
  return new messages_1.AIMessageChunk(fields);
352
391
  }
353
392
  exports.partToMessage = partToMessage;
@@ -362,7 +401,21 @@ function partToChatGeneration(part) {
362
401
  exports.partToChatGeneration = partToChatGeneration;
363
402
  function responseToChatGenerations(response) {
364
403
  const parts = responseToParts(response);
365
- const ret = parts.map((part) => partToChatGeneration(part));
404
+ let ret = parts.map((part) => partToChatGeneration(part));
405
+ if (ret.every((item) => typeof item.message.content === "string")) {
406
+ const combinedContent = ret.map((item) => item.message.content).join("");
407
+ const combinedText = ret.map((item) => item.text).join("");
408
+ ret = [
409
+ new outputs_1.ChatGenerationChunk({
410
+ message: new messages_1.AIMessageChunk({
411
+ content: combinedContent,
412
+ additional_kwargs: ret[ret.length - 1].message.additional_kwargs,
413
+ }),
414
+ text: combinedText,
415
+ generationInfo: ret[ret.length - 1].generationInfo,
416
+ }),
417
+ ];
418
+ }
366
419
  return ret;
367
420
  }
368
421
  exports.responseToChatGenerations = responseToChatGenerations;
@@ -51,12 +51,20 @@ export function messageContentToParts(content) {
51
51
  .map((content) => {
52
52
  switch (content.type) {
53
53
  case "text":
54
- return messageContentText(content);
54
+ if ("text" in content) {
55
+ return messageContentText(content);
56
+ }
57
+ break;
55
58
  case "image_url":
56
- return messageContentImageUrl(content);
59
+ if ("image_url" in content) {
60
+ // Type guard for MessageContentImageUrl
61
+ return messageContentImageUrl(content);
62
+ }
63
+ break;
57
64
  default:
58
65
  throw new Error(`Unsupported type received while converting message to message parts`);
59
66
  }
67
+ throw new Error(`Cannot coerce "${content.type}" message part into a string.`);
60
68
  })
61
69
  .reduce((acc, val) => {
62
70
  if (val) {
@@ -121,20 +129,39 @@ function toolMessageToContent(message) {
121
129
  return acc;
122
130
  }
123
131
  }, "");
124
- const content = JSON.parse(contentStr);
125
- return [
126
- {
127
- role: "function",
128
- parts: [
129
- {
130
- functionResponse: {
131
- name: message.tool_call_id,
132
- response: content,
132
+ try {
133
+ const content = JSON.parse(contentStr);
134
+ return [
135
+ {
136
+ role: "function",
137
+ parts: [
138
+ {
139
+ functionResponse: {
140
+ name: message.tool_call_id,
141
+ response: content,
142
+ },
133
143
  },
134
- },
135
- ],
136
- },
137
- ];
144
+ ],
145
+ },
146
+ ];
147
+ }
148
+ catch (_) {
149
+ return [
150
+ {
151
+ role: "function",
152
+ parts: [
153
+ {
154
+ functionResponse: {
155
+ name: message.tool_call_id,
156
+ response: {
157
+ response: contentStr,
158
+ },
159
+ },
160
+ },
161
+ ],
162
+ },
163
+ ];
164
+ }
138
165
  }
139
166
  export function baseMessageToContent(message) {
140
167
  const type = message._getType();
@@ -330,6 +357,18 @@ export function chunkToString(chunk) {
330
357
  }
331
358
  export function partToMessage(part) {
332
359
  const fields = partsToBaseMessageFields([part]);
360
+ if (typeof fields.content === "string") {
361
+ return new AIMessageChunk(fields);
362
+ }
363
+ else if (fields.content.every((item) => item.type === "text")) {
364
+ const newContent = fields.content
365
+ .map((item) => ("text" in item ? item.text : ""))
366
+ .join("");
367
+ return new AIMessageChunk({
368
+ ...fields,
369
+ content: newContent,
370
+ });
371
+ }
333
372
  return new AIMessageChunk(fields);
334
373
  }
335
374
  export function partToChatGeneration(part) {
@@ -342,7 +381,21 @@ export function partToChatGeneration(part) {
342
381
  }
343
382
  export function responseToChatGenerations(response) {
344
383
  const parts = responseToParts(response);
345
- const ret = parts.map((part) => partToChatGeneration(part));
384
+ let ret = parts.map((part) => partToChatGeneration(part));
385
+ if (ret.every((item) => typeof item.message.content === "string")) {
386
+ const combinedContent = ret.map((item) => item.message.content).join("");
387
+ const combinedText = ret.map((item) => item.text).join("");
388
+ ret = [
389
+ new ChatGenerationChunk({
390
+ message: new AIMessageChunk({
391
+ content: combinedContent,
392
+ additional_kwargs: ret[ret.length - 1].message.additional_kwargs,
393
+ }),
394
+ text: combinedText,
395
+ generationInfo: ret[ret.length - 1].generationInfo,
396
+ }),
397
+ ];
398
+ }
346
399
  return ret;
347
400
  }
348
401
  export function responseToBaseMessageFields(response) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/google-common",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Core types and classes for Google services.",
5
5
  "type": "module",
6
6
  "engines": {