@langchain/core 0.3.74 β†’ 0.3.76

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # 🦜🍎️ @langchain/core
2
2
 
3
- [![CI](https://github.com/langchain-ai/langchainjs/actions/workflows/ci.yml/badge.svg)](https://github.com/langchain-ai/langchainjs/actions/workflows/ci.yml) ![npm](https://img.shields.io/npm/dm/@langchain/core) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Twitter](https://img.shields.io/twitter/url/https/twitter.com/langchainai.svg?style=social&label=Follow%20%40LangChainAI)](https://twitter.com/langchainai)
3
+ ![npm](https://img.shields.io/npm/dm/@langchain/core) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Twitter](https://img.shields.io/twitter/url/https/twitter.com/langchainai.svg?style=social&label=Follow%20%40LangChainAI)](https://twitter.com/langchainai)
4
4
 
5
5
  `@langchain/core` contains the core abstractions and schemas of LangChain.js, including base classes for language models,
6
6
  chat models, vectorstores, retrievers, and runnables.
@@ -8,7 +8,7 @@ chat models, vectorstores, retrievers, and runnables.
8
8
  ## πŸ’Ύ Quick Install
9
9
 
10
10
  ```bash
11
- $ yarn add @langchain/core
11
+ yarn add @langchain/core
12
12
  ```
13
13
 
14
14
  ## πŸ€” What is this?
@@ -21,7 +21,7 @@ The benefit of having these abstractions is that any provider can implement the
21
21
  For example, you can install other provider-specific packages like this:
22
22
 
23
23
  ```bash
24
- $ yarn add @langchain/openai
24
+ yarn add @langchain/openai
25
25
  ```
26
26
 
27
27
  And use them as follows:
@@ -72,22 +72,6 @@ leigh
72
72
  Note that for compatibility, all used LangChain packages (including the base LangChain package, which itself depends on core!) must share the same version of `@langchain/core`.
73
73
  This means that you may need to install/resolve a specific version of `@langchain/core` that matches the dependencies of your used packages.
74
74
 
75
- ## πŸ”— What is LangChain Expression Language?
76
-
77
- LangChain Core also contains LangChain Expression Language, or LCEL, a runtime that allows users to compose arbitrary sequences together and get several benefits that are important when building LLM applications.
78
- We call these sequences β€œrunnables”.
79
-
80
- All runnables expose the same interface with single-invocation, batch, streaming and async methods.
81
- This design is useful because it is not enough to have a single sync interface when building an LLM application.
82
- Batch is needed for efficient processing of many inputs.
83
- Streaming (and streaming of intermediate steps) is needed to show the user that progress is being made.
84
- Async interfaces are nice when moving into production.
85
- Rather than having to write multiple implementations for all of those, LCEL allows you to write a runnable once and invoke it in many different ways.
86
-
87
- For more check out the [LCEL docs](https://js.langchain.com/docs/concepts/lcel).
88
-
89
- ![LangChain Stack](../docs/core_docs/static/svg/langchain_stack_062024.svg)
90
-
91
75
  ## πŸ“• Releases & Versioning
92
76
 
93
77
  `@langchain/core` is currently on version `0.3.x`.
@@ -765,9 +765,12 @@ class CallbackManager extends BaseCallbackManager {
765
765
  if (tracingV2Enabled) {
766
766
  // handoff between langchain and langsmith/traceable
767
767
  // override the parent run ID
768
- callbackManager._parentRunId =
769
- tracer_langchain_js_1.LangChainTracer.getTraceableRunTree()?.id ??
770
- callbackManager._parentRunId;
768
+ const implicitRunTree = tracer_langchain_js_1.LangChainTracer.getTraceableRunTree();
769
+ if (implicitRunTree && callbackManager._parentRunId === undefined) {
770
+ callbackManager._parentRunId = implicitRunTree.id;
771
+ const tracerV2 = callbackManager.handlers.find((handler) => handler.name === "langchain_tracer");
772
+ tracerV2?.updateFromRunTree(implicitRunTree);
773
+ }
771
774
  }
772
775
  }
773
776
  for (const { contextVar, inheritable = true, handlerClass, envVar, } of (0, context_js_1._getConfigureHooks)()) {
@@ -753,9 +753,12 @@ export class CallbackManager extends BaseCallbackManager {
753
753
  if (tracingV2Enabled) {
754
754
  // handoff between langchain and langsmith/traceable
755
755
  // override the parent run ID
756
- callbackManager._parentRunId =
757
- LangChainTracer.getTraceableRunTree()?.id ??
758
- callbackManager._parentRunId;
756
+ const implicitRunTree = LangChainTracer.getTraceableRunTree();
757
+ if (implicitRunTree && callbackManager._parentRunId === undefined) {
758
+ callbackManager._parentRunId = implicitRunTree.id;
759
+ const tracerV2 = callbackManager.handlers.find((handler) => handler.name === "langchain_tracer");
760
+ tracerV2?.updateFromRunTree(implicitRunTree);
761
+ }
759
762
  }
760
763
  }
761
764
  for (const { contextVar, inheritable = true, handlerClass, envVar, } of _getConfigureHooks()) {
@@ -4,7 +4,7 @@ import { AsyncCaller, AsyncCallerParams } from "./utils/async_caller.js";
4
4
  * class.
5
5
  */
6
6
  export type EmbeddingsParams = AsyncCallerParams;
7
- export interface EmbeddingsInterface {
7
+ export interface EmbeddingsInterface<TOutput = number[]> {
8
8
  /**
9
9
  * An abstract method that takes an array of documents as input and
10
10
  * returns a promise that resolves to an array of vectors for each
@@ -12,20 +12,20 @@ export interface EmbeddingsInterface {
12
12
  * @param documents An array of documents to be embedded.
13
13
  * @returns A promise that resolves to an array of vectors for each document.
14
14
  */
15
- embedDocuments(documents: string[]): Promise<number[][]>;
15
+ embedDocuments(documents: string[]): Promise<TOutput[]>;
16
16
  /**
17
17
  * An abstract method that takes a single document as input and returns a
18
18
  * promise that resolves to a vector for the query document.
19
19
  * @param document A single document to be embedded.
20
20
  * @returns A promise that resolves to a vector for the query document.
21
21
  */
22
- embedQuery(document: string): Promise<number[]>;
22
+ embedQuery(document: string): Promise<TOutput>;
23
23
  }
24
24
  /**
25
25
  * An abstract class that provides methods for embedding documents and
26
26
  * queries using LangChain.
27
27
  */
28
- export declare abstract class Embeddings implements EmbeddingsInterface {
28
+ export declare abstract class Embeddings<TOutput = number[]> implements EmbeddingsInterface<TOutput> {
29
29
  /**
30
30
  * The async caller should be used by subclasses to make any async calls,
31
31
  * which will thus benefit from the concurrency and retry logic.
@@ -39,12 +39,12 @@ export declare abstract class Embeddings implements EmbeddingsInterface {
39
39
  * @param documents An array of documents to be embedded.
40
40
  * @returns A promise that resolves to an array of vectors for each document.
41
41
  */
42
- abstract embedDocuments(documents: string[]): Promise<number[][]>;
42
+ abstract embedDocuments(documents: string[]): Promise<TOutput[]>;
43
43
  /**
44
44
  * An abstract method that takes a single document as input and returns a
45
45
  * promise that resolves to a vector for the query document.
46
46
  * @param document A single document to be embedded.
47
47
  * @returns A promise that resolves to a vector for the query document.
48
48
  */
49
- abstract embedQuery(document: string): Promise<number[]>;
49
+ abstract embedQuery(document: string): Promise<TOutput>;
50
50
  }
@@ -285,7 +285,13 @@ right
285
285
  // Do not merge 'type' fields
286
286
  continue;
287
287
  }
288
- merged[key] += value;
288
+ else if (["id", "output_version", "model_provider"].includes(key)) {
289
+ // Keep the incoming value for these fields
290
+ merged[key] = value;
291
+ }
292
+ else {
293
+ merged[key] += value;
294
+ }
289
295
  }
290
296
  else if (typeof merged[key] === "object" && !Array.isArray(merged[key])) {
291
297
  merged[key] = _mergeDicts(merged[key], value);
@@ -302,7 +308,6 @@ right
302
308
  }
303
309
  return merged;
304
310
  }
305
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
306
311
  function _mergeLists(left, right) {
307
312
  if (left === undefined && right === undefined) {
308
313
  return undefined;
@@ -314,10 +319,20 @@ function _mergeLists(left, right) {
314
319
  const merged = [...left];
315
320
  for (const item of right) {
316
321
  if (typeof item === "object" &&
322
+ item !== null &&
317
323
  "index" in item &&
318
324
  typeof item.index === "number") {
319
- const toMerge = merged.findIndex((leftItem) => leftItem.index === item.index);
320
- if (toMerge !== -1) {
325
+ const toMerge = merged.findIndex((leftItem) => leftItem !== null &&
326
+ typeof leftItem === "object" &&
327
+ "index" in leftItem &&
328
+ leftItem.index === item.index &&
329
+ // Only merge if IDs match (or both are undefined)
330
+ ("id" in leftItem && "id" in item
331
+ ? leftItem.id === item.id
332
+ : !("id" in leftItem) && !("id" in item)));
333
+ if (toMerge !== -1 &&
334
+ typeof merged[toMerge] === "object" &&
335
+ merged[toMerge] !== null) {
321
336
  merged[toMerge] = _mergeDicts(merged[toMerge], item);
322
337
  }
323
338
  else {
@@ -325,6 +340,7 @@ function _mergeLists(left, right) {
325
340
  }
326
341
  }
327
342
  else if (typeof item === "object" &&
343
+ item !== null &&
328
344
  "text" in item &&
329
345
  item.text === "") {
330
346
  // No-op - skip empty text blocks
@@ -156,7 +156,7 @@ export type OpenAIToolCall = {
156
156
  };
157
157
  export declare function isOpenAIToolCallArray(value?: unknown): value is OpenAIToolCall[];
158
158
  export declare function _mergeDicts(left: Record<string, any>, right: Record<string, any>): Record<string, any>;
159
- export declare function _mergeLists(left?: any[], right?: any[]): any[] | undefined;
159
+ export declare function _mergeLists<Content extends MessageContentComplex>(left?: Content[], right?: Content[]): Content[] | undefined;
160
160
  export declare function _mergeObj<T = any>(left: T | undefined, right: T | undefined): T;
161
161
  /**
162
162
  * Represents a chunk of a message, which can be concatenated with other
@@ -272,7 +272,13 @@ right
272
272
  // Do not merge 'type' fields
273
273
  continue;
274
274
  }
275
- merged[key] += value;
275
+ else if (["id", "output_version", "model_provider"].includes(key)) {
276
+ // Keep the incoming value for these fields
277
+ merged[key] = value;
278
+ }
279
+ else {
280
+ merged[key] += value;
281
+ }
276
282
  }
277
283
  else if (typeof merged[key] === "object" && !Array.isArray(merged[key])) {
278
284
  merged[key] = _mergeDicts(merged[key], value);
@@ -289,7 +295,6 @@ right
289
295
  }
290
296
  return merged;
291
297
  }
292
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
293
298
  export function _mergeLists(left, right) {
294
299
  if (left === undefined && right === undefined) {
295
300
  return undefined;
@@ -301,10 +306,20 @@ export function _mergeLists(left, right) {
301
306
  const merged = [...left];
302
307
  for (const item of right) {
303
308
  if (typeof item === "object" &&
309
+ item !== null &&
304
310
  "index" in item &&
305
311
  typeof item.index === "number") {
306
- const toMerge = merged.findIndex((leftItem) => leftItem.index === item.index);
307
- if (toMerge !== -1) {
312
+ const toMerge = merged.findIndex((leftItem) => leftItem !== null &&
313
+ typeof leftItem === "object" &&
314
+ "index" in leftItem &&
315
+ leftItem.index === item.index &&
316
+ // Only merge if IDs match (or both are undefined)
317
+ ("id" in leftItem && "id" in item
318
+ ? leftItem.id === item.id
319
+ : !("id" in leftItem) && !("id" in item)));
320
+ if (toMerge !== -1 &&
321
+ typeof merged[toMerge] === "object" &&
322
+ merged[toMerge] !== null) {
308
323
  merged[toMerge] = _mergeDicts(merged[toMerge], item);
309
324
  }
310
325
  else {
@@ -312,6 +327,7 @@ export function _mergeLists(left, right) {
312
327
  }
313
328
  }
314
329
  else if (typeof item === "object" &&
330
+ item !== null &&
315
331
  "text" in item &&
316
332
  item.text === "") {
317
333
  // No-op - skip empty text blocks
@@ -182,7 +182,7 @@ async function _firstMaxTokens(messages, options) {
182
182
  break;
183
183
  }
184
184
  }
185
- if (idx < messagesCopy.length - 1 && partialStrategy) {
185
+ if (idx < messagesCopy.length && partialStrategy) {
186
186
  let includedPartial = false;
187
187
  if (Array.isArray(messagesCopy[idx].content)) {
188
188
  const excluded = messagesCopy[idx];
@@ -176,7 +176,7 @@ async function _firstMaxTokens(messages, options) {
176
176
  break;
177
177
  }
178
178
  }
179
- if (idx < messagesCopy.length - 1 && partialStrategy) {
179
+ if (idx < messagesCopy.length && partialStrategy) {
180
180
  let includedPartial = false;
181
181
  if (Array.isArray(messagesCopy[idx].content)) {
182
182
  const excluded = messagesCopy[idx];
@@ -13,6 +13,7 @@ const base_js_1 = require("./base.cjs");
13
13
  const chat_js_1 = require("./chat.cjs");
14
14
  const function_js_1 = require("./function.cjs");
15
15
  const human_js_1 = require("./human.cjs");
16
+ const modifier_js_1 = require("./modifier.cjs");
16
17
  const system_js_1 = require("./system.cjs");
17
18
  const tool_js_1 = require("./tool.cjs");
18
19
  function _coerceToolCall(toolCall) {
@@ -113,6 +114,9 @@ function _constructMessageFromParams(params) {
113
114
  name: rest.name,
114
115
  });
115
116
  }
117
+ else if (type === "remove" && "id" in rest && typeof rest.id === "string") {
118
+ return new modifier_js_1.RemoveMessage({ ...rest, id: rest.id });
119
+ }
116
120
  else {
117
121
  const error = (0, index_js_1.addLangChainErrorFields)(new Error(`Unable to coerce message from array: only human, AI, system, developer, or tool message coercion is currently supported.\n\nReceived: ${JSON.stringify(params, null, 2)}`), "MESSAGE_COERCION_FAILURE");
118
122
  throw error;
@@ -5,6 +5,7 @@ import { isBaseMessage, _isMessageFieldWithRole, } from "./base.js";
5
5
  import { ChatMessage, ChatMessageChunk, } from "./chat.js";
6
6
  import { FunctionMessage, FunctionMessageChunk, } from "./function.js";
7
7
  import { HumanMessage, HumanMessageChunk } from "./human.js";
8
+ import { RemoveMessage } from "./modifier.js";
8
9
  import { SystemMessage, SystemMessageChunk } from "./system.js";
9
10
  import { ToolMessage, } from "./tool.js";
10
11
  function _coerceToolCall(toolCall) {
@@ -105,6 +106,9 @@ function _constructMessageFromParams(params) {
105
106
  name: rest.name,
106
107
  });
107
108
  }
109
+ else if (type === "remove" && "id" in rest && typeof rest.id === "string") {
110
+ return new RemoveMessage({ ...rest, id: rest.id });
111
+ }
108
112
  else {
109
113
  const error = addLangChainErrorFields(new Error(`Unable to coerce message from array: only human, AI, system, developer, or tool message coercion is currently supported.\n\nReceived: ${JSON.stringify(params, null, 2)}`), "MESSAGE_COERCION_FAILURE");
110
114
  throw error;
@@ -75,9 +75,14 @@ ${JSON.stringify((0, json_schema_js_1.toJsonSchema)(this.schema))}
75
75
  */
76
76
  async parse(text) {
77
77
  try {
78
- const json = text.includes("```")
79
- ? text.trim().split(/```(?:json)?/)[1]
80
- : text.trim();
78
+ const trimmedText = text.trim();
79
+ const json =
80
+ // first case: if back ticks appear at the start of the text
81
+ trimmedText.match(/^```(?:json)?\s*([\s\S]*?)```/)?.[1] ||
82
+ // second case: if back ticks with `json` appear anywhere in the text
83
+ trimmedText.match(/```json\s*([\s\S]*?)```/)?.[1] ||
84
+ // otherwise, return the trimmed text
85
+ trimmedText;
81
86
  const escapedJson = json
82
87
  .replace(/"([^"\\]*(\\.[^"\\]*)*)"/g, (_match, capturedGroup) => {
83
88
  const escapedInsideQuotes = capturedGroup.replace(/\n/g, "\\n");
@@ -72,9 +72,14 @@ ${JSON.stringify(toJsonSchema(this.schema))}
72
72
  */
73
73
  async parse(text) {
74
74
  try {
75
- const json = text.includes("```")
76
- ? text.trim().split(/```(?:json)?/)[1]
77
- : text.trim();
75
+ const trimmedText = text.trim();
76
+ const json =
77
+ // first case: if back ticks appear at the start of the text
78
+ trimmedText.match(/^```(?:json)?\s*([\s\S]*?)```/)?.[1] ||
79
+ // second case: if back ticks with `json` appear anywhere in the text
80
+ trimmedText.match(/```json\s*([\s\S]*?)```/)?.[1] ||
81
+ // otherwise, return the trimmed text
82
+ trimmedText;
78
83
  const escapedJson = json
79
84
  .replace(/"([^"\\]*(\\.[^"\\]*)*)"/g, (_match, capturedGroup) => {
80
85
  const escapedInsideQuotes = capturedGroup.replace(/\n/g, "\\n");
@@ -723,15 +723,21 @@ class ChatPromptTemplate extends BaseChatPromptTemplate {
723
723
  resultMessages.push(await this._parseImagePrompts(promptMessage, allValues));
724
724
  }
725
725
  else {
726
- const inputValues = promptMessage.inputVariables.reduce((acc, inputVariable) => {
727
- if (!(inputVariable in allValues) &&
728
- !(isMessagesPlaceholder(promptMessage) && promptMessage.optional)) {
729
- const error = (0, index_js_2.addLangChainErrorFields)(new Error(`Missing value for input variable \`${inputVariable.toString()}\``), "INVALID_PROMPT_INPUT");
730
- throw error;
731
- }
732
- acc[inputVariable] = allValues[inputVariable];
733
- return acc;
734
- }, {});
726
+ let inputValues;
727
+ if (this.templateFormat === "mustache") {
728
+ inputValues = { ...allValues };
729
+ }
730
+ else {
731
+ inputValues = promptMessage.inputVariables.reduce((acc, inputVariable) => {
732
+ if (!(inputVariable in allValues) &&
733
+ !(isMessagesPlaceholder(promptMessage) && promptMessage.optional)) {
734
+ const error = (0, index_js_2.addLangChainErrorFields)(new Error(`Missing value for input variable \`${inputVariable.toString()}\``), "INVALID_PROMPT_INPUT");
735
+ throw error;
736
+ }
737
+ acc[inputVariable] = allValues[inputVariable];
738
+ return acc;
739
+ }, {});
740
+ }
735
741
  const message = await promptMessage.formatMessages(inputValues);
736
742
  resultMessages = resultMessages.concat(message);
737
743
  }
@@ -712,15 +712,21 @@ export class ChatPromptTemplate extends BaseChatPromptTemplate {
712
712
  resultMessages.push(await this._parseImagePrompts(promptMessage, allValues));
713
713
  }
714
714
  else {
715
- const inputValues = promptMessage.inputVariables.reduce((acc, inputVariable) => {
716
- if (!(inputVariable in allValues) &&
717
- !(isMessagesPlaceholder(promptMessage) && promptMessage.optional)) {
718
- const error = addLangChainErrorFields(new Error(`Missing value for input variable \`${inputVariable.toString()}\``), "INVALID_PROMPT_INPUT");
719
- throw error;
720
- }
721
- acc[inputVariable] = allValues[inputVariable];
722
- return acc;
723
- }, {});
715
+ let inputValues;
716
+ if (this.templateFormat === "mustache") {
717
+ inputValues = { ...allValues };
718
+ }
719
+ else {
720
+ inputValues = promptMessage.inputVariables.reduce((acc, inputVariable) => {
721
+ if (!(inputVariable in allValues) &&
722
+ !(isMessagesPlaceholder(promptMessage) && promptMessage.optional)) {
723
+ const error = addLangChainErrorFields(new Error(`Missing value for input variable \`${inputVariable.toString()}\``), "INVALID_PROMPT_INPUT");
724
+ throw error;
725
+ }
726
+ acc[inputVariable] = allValues[inputVariable];
727
+ return acc;
728
+ }, {});
729
+ }
724
730
  const message = await promptMessage.formatMessages(inputValues);
725
731
  resultMessages = resultMessages.concat(message);
726
732
  }
@@ -65,9 +65,10 @@ exports.parseFString = parseFString;
65
65
  * to make it compatible with other LangChain string parsing template formats.
66
66
  *
67
67
  * @param {mustache.TemplateSpans} template The result of parsing a mustache template with the mustache.js library.
68
+ * @param {string[]} context Array of section variable names for nested context
68
69
  * @returns {ParsedTemplateNode[]}
69
70
  */
70
- const mustacheTemplateToNodes = (template) => {
71
+ const mustacheTemplateToNodes = (template, context = []) => {
71
72
  const nodes = [];
72
73
  for (const temp of template) {
73
74
  if (temp[0] === "name") {
@@ -80,7 +81,8 @@ const mustacheTemplateToNodes = (template) => {
80
81
  nodes.push({ type: "variable", name: temp[1] });
81
82
  // If this is a section with nested content, recursively process it
82
83
  if (temp[0] === "#" && temp.length > 4 && Array.isArray(temp[4])) {
83
- const nestedNodes = mustacheTemplateToNodes(temp[4]);
84
+ const newContext = [...context, temp[1]];
85
+ const nestedNodes = mustacheTemplateToNodes(temp[4], newContext);
84
86
  nodes.push(...nestedNodes);
85
87
  }
86
88
  }
@@ -58,9 +58,10 @@ export const parseFString = (template) => {
58
58
  * to make it compatible with other LangChain string parsing template formats.
59
59
  *
60
60
  * @param {mustache.TemplateSpans} template The result of parsing a mustache template with the mustache.js library.
61
+ * @param {string[]} context Array of section variable names for nested context
61
62
  * @returns {ParsedTemplateNode[]}
62
63
  */
63
- const mustacheTemplateToNodes = (template) => {
64
+ const mustacheTemplateToNodes = (template, context = []) => {
64
65
  const nodes = [];
65
66
  for (const temp of template) {
66
67
  if (temp[0] === "name") {
@@ -73,7 +74,8 @@ const mustacheTemplateToNodes = (template) => {
73
74
  nodes.push({ type: "variable", name: temp[1] });
74
75
  // If this is a section with nested content, recursively process it
75
76
  if (temp[0] === "#" && temp.length > 4 && Array.isArray(temp[4])) {
76
- const nestedNodes = mustacheTemplateToNodes(temp[4]);
77
+ const newContext = [...context, temp[1]];
78
+ const nestedNodes = mustacheTemplateToNodes(temp[4], newContext);
77
79
  nodes.push(...nestedNodes);
78
80
  }
79
81
  }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.drawMermaid = drawMermaid;
4
4
  exports.drawMermaidPng = drawMermaidPng;
5
+ exports.drawMermaidImage = drawMermaidImage;
5
6
  function _escapeNodeLabel(nodeLabel) {
6
7
  // Escapes the node label for Mermaid syntax.
7
8
  return nodeLabel.replace(/[^a-zA-Z-_0-9]/g, "_");
@@ -124,10 +125,33 @@ function drawMermaid(nodes, edges, config) {
124
125
  return mermaidGraph;
125
126
  }
126
127
  /**
127
- * Renders Mermaid graph using the Mermaid.INK API.
128
+ * @deprecated Use `drawMermaidImage` instead.
128
129
  */
129
130
  async function drawMermaidPng(mermaidSyntax, config) {
130
- let { backgroundColor = "white" } = config ?? {};
131
+ return drawMermaidImage(mermaidSyntax, {
132
+ ...config,
133
+ imageType: "png",
134
+ });
135
+ }
136
+ /**
137
+ * Renders Mermaid graph using the Mermaid.INK API.
138
+ *
139
+ * @example
140
+ * ```javascript
141
+ * const image = await drawMermaidImage(mermaidSyntax, {
142
+ * backgroundColor: "white",
143
+ * imageType: "png",
144
+ * });
145
+ * fs.writeFileSync("image.png", image);
146
+ * ```
147
+ *
148
+ * @param mermaidSyntax - The Mermaid syntax to render.
149
+ * @param config - The configuration for the image.
150
+ * @returns The image as a Blob.
151
+ */
152
+ async function drawMermaidImage(mermaidSyntax, config) {
153
+ let backgroundColor = config?.backgroundColor ?? "white";
154
+ const imageType = config?.imageType ?? "png";
131
155
  // Use btoa for compatibility, assume ASCII
132
156
  const mermaidSyntaxEncoded = btoa(mermaidSyntax);
133
157
  // Check if the background color is a hexadecimal color code using regex
@@ -137,7 +161,7 @@ async function drawMermaidPng(mermaidSyntax, config) {
137
161
  backgroundColor = `!${backgroundColor}`;
138
162
  }
139
163
  }
140
- const imageUrl = `https://mermaid.ink/img/${mermaidSyntaxEncoded}?bgColor=${backgroundColor}`;
164
+ const imageUrl = `https://mermaid.ink/img/${mermaidSyntaxEncoded}?bgColor=${backgroundColor}&type=${imageType}`;
141
165
  const res = await fetch(imageUrl);
142
166
  if (!res.ok) {
143
167
  throw new Error([
@@ -11,8 +11,32 @@ export declare function drawMermaid(nodes: Record<string, Node>, edges: Edge[],
11
11
  wrapLabelNWords?: number;
12
12
  }): string;
13
13
  /**
14
- * Renders Mermaid graph using the Mermaid.INK API.
14
+ * @deprecated Use `drawMermaidImage` instead.
15
15
  */
16
16
  export declare function drawMermaidPng(mermaidSyntax: string, config?: {
17
17
  backgroundColor?: string;
18
18
  }): Promise<Blob>;
19
+ /**
20
+ * Renders Mermaid graph using the Mermaid.INK API.
21
+ *
22
+ * @example
23
+ * ```javascript
24
+ * const image = await drawMermaidImage(mermaidSyntax, {
25
+ * backgroundColor: "white",
26
+ * imageType: "png",
27
+ * });
28
+ * fs.writeFileSync("image.png", image);
29
+ * ```
30
+ *
31
+ * @param mermaidSyntax - The Mermaid syntax to render.
32
+ * @param config - The configuration for the image.
33
+ * @returns The image as a Blob.
34
+ */
35
+ export declare function drawMermaidImage(mermaidSyntax: string, config?: {
36
+ /**
37
+ * The type of image to render.
38
+ * @default "png"
39
+ */
40
+ imageType?: "png" | "jpeg" | "webp";
41
+ backgroundColor?: string;
42
+ }): Promise<Blob>;
@@ -120,10 +120,33 @@ export function drawMermaid(nodes, edges, config) {
120
120
  return mermaidGraph;
121
121
  }
122
122
  /**
123
- * Renders Mermaid graph using the Mermaid.INK API.
123
+ * @deprecated Use `drawMermaidImage` instead.
124
124
  */
125
125
  export async function drawMermaidPng(mermaidSyntax, config) {
126
- let { backgroundColor = "white" } = config ?? {};
126
+ return drawMermaidImage(mermaidSyntax, {
127
+ ...config,
128
+ imageType: "png",
129
+ });
130
+ }
131
+ /**
132
+ * Renders Mermaid graph using the Mermaid.INK API.
133
+ *
134
+ * @example
135
+ * ```javascript
136
+ * const image = await drawMermaidImage(mermaidSyntax, {
137
+ * backgroundColor: "white",
138
+ * imageType: "png",
139
+ * });
140
+ * fs.writeFileSync("image.png", image);
141
+ * ```
142
+ *
143
+ * @param mermaidSyntax - The Mermaid syntax to render.
144
+ * @param config - The configuration for the image.
145
+ * @returns The image as a Blob.
146
+ */
147
+ export async function drawMermaidImage(mermaidSyntax, config) {
148
+ let backgroundColor = config?.backgroundColor ?? "white";
149
+ const imageType = config?.imageType ?? "png";
127
150
  // Use btoa for compatibility, assume ASCII
128
151
  const mermaidSyntaxEncoded = btoa(mermaidSyntax);
129
152
  // Check if the background color is a hexadecimal color code using regex
@@ -133,7 +156,7 @@ export async function drawMermaidPng(mermaidSyntax, config) {
133
156
  backgroundColor = `!${backgroundColor}`;
134
157
  }
135
158
  }
136
- const imageUrl = `https://mermaid.ink/img/${mermaidSyntaxEncoded}?bgColor=${backgroundColor}`;
159
+ const imageUrl = `https://mermaid.ink/img/${mermaidSyntaxEncoded}?bgColor=${backgroundColor}&type=${imageType}`;
137
160
  const res = await fetch(imageUrl);
138
161
  if (!res.ok) {
139
162
  throw new Error([
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/core",
3
- "version": "0.3.74",
3
+ "version": "0.3.76",
4
4
  "description": "Core LangChain.js abstractions and schemas",
5
5
  "type": "module",
6
6
  "engines": {
@@ -38,7 +38,7 @@
38
38
  "camelcase": "6",
39
39
  "decamelize": "1.2.0",
40
40
  "js-tiktoken": "^1.0.12",
41
- "langsmith": "^0.3.46",
41
+ "langsmith": "^0.3.67",
42
42
  "mustache": "^4.2.0",
43
43
  "p-queue": "^6.6.2",
44
44
  "p-retry": "4",