@langchain/core 0.1.44 → 0.1.45

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.
@@ -26,6 +26,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.BaseCallbackHandler = void 0;
27
27
  const uuid = __importStar(require("uuid"));
28
28
  const serializable_js_1 = require("../load/serializable.cjs");
29
+ const env_js_1 = require("../utils/env.cjs");
29
30
  /**
30
31
  * Abstract class that provides a set of optional methods that can be
31
32
  * overridden in derived classes to handle various events during the
@@ -112,10 +113,7 @@ class BaseCallbackHandler extends BaseCallbackHandlerMethodsClass {
112
113
  enumerable: true,
113
114
  configurable: true,
114
115
  writable: true,
115
- value: typeof process !== "undefined"
116
- ? // eslint-disable-next-line no-process-env
117
- process.env?.LANGCHAIN_CALLBACKS_BACKGROUND !== "true"
118
- : true
116
+ value: (0, env_js_1.getEnvironmentVariable)("LANGCHAIN_CALLBACKS_BACKGROUND") !== "true"
119
117
  });
120
118
  this.lc_kwargs = input || {};
121
119
  if (input) {
@@ -123,6 +121,7 @@ class BaseCallbackHandler extends BaseCallbackHandlerMethodsClass {
123
121
  this.ignoreChain = input.ignoreChain ?? this.ignoreChain;
124
122
  this.ignoreAgent = input.ignoreAgent ?? this.ignoreAgent;
125
123
  this.ignoreRetriever = input.ignoreRetriever ?? this.ignoreRetriever;
124
+ this.awaitHandlers = input._awaitHandler ?? this.awaitHandlers;
126
125
  }
127
126
  }
128
127
  copy() {
@@ -16,6 +16,7 @@ export interface BaseCallbackHandlerInput {
16
16
  ignoreChain?: boolean;
17
17
  ignoreAgent?: boolean;
18
18
  ignoreRetriever?: boolean;
19
+ _awaitHandler?: boolean;
19
20
  }
20
21
  /**
21
22
  * Interface for the indices of a new token produced by an LLM or Chat
@@ -1,5 +1,6 @@
1
1
  import * as uuid from "uuid";
2
2
  import { Serializable, get_lc_unique_name, } from "../load/serializable.js";
3
+ import { getEnvironmentVariable } from "../utils/env.js";
3
4
  /**
4
5
  * Abstract class that provides a set of optional methods that can be
5
6
  * overridden in derived classes to handle various events during the
@@ -86,10 +87,7 @@ export class BaseCallbackHandler extends BaseCallbackHandlerMethodsClass {
86
87
  enumerable: true,
87
88
  configurable: true,
88
89
  writable: true,
89
- value: typeof process !== "undefined"
90
- ? // eslint-disable-next-line no-process-env
91
- process.env?.LANGCHAIN_CALLBACKS_BACKGROUND !== "true"
92
- : true
90
+ value: getEnvironmentVariable("LANGCHAIN_CALLBACKS_BACKGROUND") !== "true"
93
91
  });
94
92
  this.lc_kwargs = input || {};
95
93
  if (input) {
@@ -97,6 +95,7 @@ export class BaseCallbackHandler extends BaseCallbackHandlerMethodsClass {
97
95
  this.ignoreChain = input.ignoreChain ?? this.ignoreChain;
98
96
  this.ignoreAgent = input.ignoreAgent ?? this.ignoreAgent;
99
97
  this.ignoreRetriever = input.ignoreRetriever ?? this.ignoreRetriever;
98
+ this.awaitHandlers = input._awaitHandler ?? this.awaitHandlers;
100
99
  }
101
100
  }
102
101
  copy() {
@@ -9,6 +9,16 @@ const index_js_1 = require("../messages/index.cjs");
9
9
  const env_js_1 = require("../utils/env.cjs");
10
10
  const tracer_langchain_js_1 = require("../tracers/tracer_langchain.cjs");
11
11
  const promises_js_1 = require("./promises.cjs");
12
+ if (
13
+ /* #__PURE__ */ (0, env_js_1.getEnvironmentVariable)("LANGCHAIN_TRACING_V2") === "true" &&
14
+ /* #__PURE__ */ (0, env_js_1.getEnvironmentVariable)("LANGCHAIN_CALLBACKS_BACKGROUND") !==
15
+ "true") {
16
+ /* #__PURE__ */ console.warn([
17
+ "[WARN]: You have enabled LangSmith tracing without backgrounding callbacks.",
18
+ "[WARN]: If you are not using a serverless environment where you must wait for tracing calls to finish,",
19
+ `[WARN]: we suggest setting "process.env.LANGCHAIN_CALLBACKS_BACKGROUND=true" to avoid additional latency.`,
20
+ ].join("\n"));
21
+ }
12
22
  function parseCallbackConfigArg(arg) {
13
23
  if (!arg) {
14
24
  return {};
@@ -6,6 +6,16 @@ import { getBufferString } from "../messages/index.js";
6
6
  import { getEnvironmentVariable } from "../utils/env.js";
7
7
  import { LangChainTracer, } from "../tracers/tracer_langchain.js";
8
8
  import { consumeCallback } from "./promises.js";
9
+ if (
10
+ /* #__PURE__ */ getEnvironmentVariable("LANGCHAIN_TRACING_V2") === "true" &&
11
+ /* #__PURE__ */ getEnvironmentVariable("LANGCHAIN_CALLBACKS_BACKGROUND") !==
12
+ "true") {
13
+ /* #__PURE__ */ console.warn([
14
+ "[WARN]: You have enabled LangSmith tracing without backgrounding callbacks.",
15
+ "[WARN]: If you are not using a serverless environment where you must wait for tracing calls to finish,",
16
+ `[WARN]: we suggest setting "process.env.LANGCHAIN_CALLBACKS_BACKGROUND=true" to avoid additional latency.`,
17
+ ].join("\n"));
18
+ }
9
19
  export function parseCallbackConfigArg(arg) {
10
20
  if (!arg) {
11
21
  return {};
@@ -3,6 +3,8 @@ export interface BaseSerialized<T extends string> {
3
3
  lc: number;
4
4
  type: T;
5
5
  id: string[];
6
+ name?: string;
7
+ graph?: Record<string, any>;
6
8
  }
7
9
  export interface SerializedConstructor extends BaseSerialized<"constructor"> {
8
10
  kwargs: SerializedFields;
@@ -17,7 +19,10 @@ export type Serialized = SerializedConstructor | SerializedSecret | SerializedNo
17
19
  * Should not be subclassed, subclass lc_name above instead.
18
20
  */
19
21
  export declare function get_lc_unique_name(serializableClass: typeof Serializable): string;
20
- export declare abstract class Serializable {
22
+ export interface SerializableInterface {
23
+ get lc_id(): string[];
24
+ }
25
+ export declare abstract class Serializable implements SerializableInterface {
21
26
  lc_serializable: boolean;
22
27
  lc_kwargs: SerializedFields;
23
28
  /**
@@ -19,6 +19,14 @@ class BaseLLMOutputParser extends index_js_1.Runnable {
19
19
  parseResultWithPrompt(generations, _prompt, callbacks) {
20
20
  return this.parseResult(generations, callbacks);
21
21
  }
22
+ _baseMessageToString(message) {
23
+ return typeof message.content === "string"
24
+ ? message.content
25
+ : this._baseMessageContentToString(message.content);
26
+ }
27
+ _baseMessageContentToString(content) {
28
+ return JSON.stringify(content);
29
+ }
22
30
  /**
23
31
  * Calls the parser with a given input and optional configuration options.
24
32
  * If the input is a string, it creates a generation with the input as
@@ -37,9 +45,7 @@ class BaseLLMOutputParser extends index_js_1.Runnable {
37
45
  return this._callWithConfig(async (input) => this.parseResult([
38
46
  {
39
47
  message: input,
40
- text: typeof input.content === "string"
41
- ? input.content
42
- : JSON.stringify(input.content),
48
+ text: this._baseMessageToString(input),
43
49
  },
44
50
  ]), input, { ...options, runType: "parser" });
45
51
  }
@@ -1,7 +1,7 @@
1
1
  import { Runnable } from "../runnables/index.js";
2
2
  import type { RunnableConfig } from "../runnables/config.js";
3
3
  import type { BasePromptValueInterface } from "../prompt_values.js";
4
- import type { BaseMessage } from "../messages/index.js";
4
+ import type { BaseMessage, MessageContentComplex } from "../messages/index.js";
5
5
  import type { Callbacks } from "../callbacks/manager.js";
6
6
  import type { Generation, ChatGeneration } from "../outputs.js";
7
7
  /**
@@ -33,6 +33,8 @@ export declare abstract class BaseLLMOutputParser<T = unknown> extends Runnable<
33
33
  * @returns A promise of the parsed output.
34
34
  */
35
35
  parseResultWithPrompt(generations: Generation[] | ChatGeneration[], _prompt: BasePromptValueInterface, callbacks?: Callbacks): Promise<T>;
36
+ protected _baseMessageToString(message: BaseMessage): string;
37
+ protected _baseMessageContentToString(content: MessageContentComplex[]): string;
36
38
  /**
37
39
  * Calls the parser with a given input and optional configuration options.
38
40
  * If the input is a string, it creates a generation with the input as
@@ -16,6 +16,14 @@ export class BaseLLMOutputParser extends Runnable {
16
16
  parseResultWithPrompt(generations, _prompt, callbacks) {
17
17
  return this.parseResult(generations, callbacks);
18
18
  }
19
+ _baseMessageToString(message) {
20
+ return typeof message.content === "string"
21
+ ? message.content
22
+ : this._baseMessageContentToString(message.content);
23
+ }
24
+ _baseMessageContentToString(content) {
25
+ return JSON.stringify(content);
26
+ }
19
27
  /**
20
28
  * Calls the parser with a given input and optional configuration options.
21
29
  * If the input is a string, it creates a generation with the input as
@@ -34,9 +42,7 @@ export class BaseLLMOutputParser extends Runnable {
34
42
  return this._callWithConfig(async (input) => this.parseResult([
35
43
  {
36
44
  message: input,
37
- text: typeof input.content === "string"
38
- ? input.content
39
- : JSON.stringify(input.content),
45
+ text: this._baseMessageToString(input),
40
46
  },
41
47
  ]), input, { ...options, runType: "parser" });
42
48
  }
@@ -53,5 +53,26 @@ class StringOutputParser extends transform_js_1.BaseTransformOutputParser {
53
53
  getFormatInstructions() {
54
54
  return "";
55
55
  }
56
+ _textContentToString(content) {
57
+ return content.text;
58
+ }
59
+ _imageUrlContentToString(_content) {
60
+ throw new Error(`Cannot coerce a multimodal "image_url" message part into a string.`);
61
+ }
62
+ _messageContentComplexToString(content) {
63
+ switch (content.type) {
64
+ case "text":
65
+ return this._textContentToString(content);
66
+ case "image_url":
67
+ return this._imageUrlContentToString(content);
68
+ default:
69
+ throw new Error(
70
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
71
+ `Cannot coerce "${content.type}" message part into a string.`);
72
+ }
73
+ }
74
+ _baseMessageContentToString(content) {
75
+ return content.reduce((acc, item) => acc + this._messageContentComplexToString(item), "");
76
+ }
56
77
  }
57
78
  exports.StringOutputParser = StringOutputParser;
@@ -1,4 +1,5 @@
1
1
  import { BaseTransformOutputParser } from "./transform.js";
2
+ import { MessageContentComplex, MessageContentImageUrl, MessageContentText } from "../messages/index.js";
2
3
  /**
3
4
  * OutputParser that parses LLMResult into the top likely string.
4
5
  * @example
@@ -31,4 +32,8 @@ export declare class StringOutputParser extends BaseTransformOutputParser<string
31
32
  */
32
33
  parse(text: string): Promise<string>;
33
34
  getFormatInstructions(): string;
35
+ protected _textContentToString(content: MessageContentText): string;
36
+ protected _imageUrlContentToString(_content: MessageContentImageUrl): string;
37
+ protected _messageContentComplexToString(content: MessageContentComplex): string;
38
+ protected _baseMessageContentToString(content: MessageContentComplex[]): string;
34
39
  }
@@ -50,4 +50,25 @@ export class StringOutputParser extends BaseTransformOutputParser {
50
50
  getFormatInstructions() {
51
51
  return "";
52
52
  }
53
+ _textContentToString(content) {
54
+ return content.text;
55
+ }
56
+ _imageUrlContentToString(_content) {
57
+ throw new Error(`Cannot coerce a multimodal "image_url" message part into a string.`);
58
+ }
59
+ _messageContentComplexToString(content) {
60
+ switch (content.type) {
61
+ case "text":
62
+ return this._textContentToString(content);
63
+ case "image_url":
64
+ return this._imageUrlContentToString(content);
65
+ default:
66
+ throw new Error(
67
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
68
+ `Cannot coerce "${content.type}" message part into a string.`);
69
+ }
70
+ }
71
+ _baseMessageContentToString(content) {
72
+ return content.reduce((acc, item) => acc + this._messageContentComplexToString(item), "");
73
+ }
53
74
  }
@@ -18,9 +18,7 @@ class BaseTransformOutputParser extends base_js_1.BaseOutputParser {
18
18
  yield this.parseResult([
19
19
  {
20
20
  message: chunk,
21
- text: typeof chunk.content === "string"
22
- ? chunk.content
23
- : JSON.stringify(chunk.content),
21
+ text: this._baseMessageToString(chunk),
24
22
  },
25
23
  ]);
26
24
  }
@@ -15,9 +15,7 @@ export class BaseTransformOutputParser extends BaseOutputParser {
15
15
  yield this.parseResult([
16
16
  {
17
17
  message: chunk,
18
- text: typeof chunk.content === "string"
19
- ? chunk.content
20
- : JSON.stringify(chunk.content),
18
+ text: this._baseMessageToString(chunk),
21
19
  },
22
20
  ]);
23
21
  }
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.RunnablePick = exports.RunnableAssign = exports._coerceToRunnable = exports.RunnableWithFallbacks = exports.RunnableParallel = exports.RunnableLambda = exports.RunnableMap = exports.RunnableSequence = exports.RunnableRetry = exports.RunnableEach = exports.RunnableBinding = exports.Runnable = exports._coerceToDict = void 0;
7
+ const zod_1 = require("zod");
7
8
  const p_retry_1 = __importDefault(require("p-retry"));
8
9
  const manager_js_1 = require("../callbacks/manager.cjs");
9
10
  const log_stream_js_1 = require("../tracers/log_stream.cjs");
@@ -14,6 +15,7 @@ const async_caller_js_1 = require("../utils/async_caller.cjs");
14
15
  const root_listener_js_1 = require("../tracers/root_listener.cjs");
15
16
  const utils_js_1 = require("./utils.cjs");
16
17
  const index_js_1 = require("../singletons/index.cjs");
18
+ const graph_js_1 = require("./graph.cjs");
17
19
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
20
  function _coerceToDict(value, defaultKey) {
19
21
  return value &&
@@ -291,6 +293,23 @@ class Runnable extends serializable_js_1.Serializable {
291
293
  }
292
294
  await runManager?.handleChainEnd(finalOutput ?? {}, undefined, undefined, undefined, { inputs: _coerceToDict(finalInput, "input") });
293
295
  }
296
+ getGraph(_) {
297
+ const graph = new graph_js_1.Graph();
298
+ // TODO: Add input schema for runnables
299
+ const inputNode = graph.addNode({
300
+ name: `${this.getName()}Input`,
301
+ schema: zod_1.z.any(),
302
+ });
303
+ const runnableNode = graph.addNode(this);
304
+ // TODO: Add output schemas for runnables
305
+ const outputNode = graph.addNode({
306
+ name: `${this.getName()}Output`,
307
+ schema: zod_1.z.any(),
308
+ });
309
+ graph.addEdge(inputNode, runnableNode);
310
+ graph.addEdge(runnableNode, outputNode);
311
+ return graph;
312
+ }
294
313
  /**
295
314
  * Create a new runnable sequence that runs each individual runnable in series,
296
315
  * piping the output of one runnable into another runnable or runnable-like.
@@ -593,7 +612,7 @@ class Runnable extends serializable_js_1.Serializable {
593
612
  }
594
613
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
595
614
  static isRunnable(thing) {
596
- return thing ? thing.lc_runnable : false;
615
+ return (0, utils_js_1.isRunnableInterface)(thing);
597
616
  }
598
617
  /**
599
618
  * Bind lifecycle listeners to a Runnable, returning a new Runnable.
@@ -1106,6 +1125,30 @@ class RunnableSequence extends Runnable {
1106
1125
  }
1107
1126
  await runManager?.handleChainEnd(_coerceToDict(finalOutput, "output"));
1108
1127
  }
1128
+ getGraph(config) {
1129
+ const graph = new graph_js_1.Graph();
1130
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1131
+ let currentLastNode = null;
1132
+ this.steps.forEach((step, index) => {
1133
+ const stepGraph = step.getGraph(config);
1134
+ if (index !== 0) {
1135
+ stepGraph.trimFirstNode();
1136
+ }
1137
+ if (index !== this.steps.length - 1) {
1138
+ stepGraph.trimLastNode();
1139
+ }
1140
+ graph.extend(stepGraph);
1141
+ const stepFirstNode = stepGraph.firstNode();
1142
+ if (!stepFirstNode) {
1143
+ throw new Error(`Runnable ${step} has no first node`);
1144
+ }
1145
+ if (currentLastNode) {
1146
+ graph.addEdge(currentLastNode, stepFirstNode);
1147
+ }
1148
+ currentLastNode = stepGraph.lastNode();
1149
+ });
1150
+ return graph;
1151
+ }
1109
1152
  pipe(coerceable) {
1110
1153
  if (RunnableSequence.isRunnableSequence(coerceable)) {
1111
1154
  return new RunnableSequence({
@@ -1,28 +1,12 @@
1
+ import type { RunnableInterface, RunnableBatchOptions } from "./types.js";
1
2
  import { CallbackManagerForChainRun } from "../callbacks/manager.js";
2
3
  import { LogStreamCallbackHandler, LogStreamCallbackHandlerInput, RunLogPatch, StreamEvent } from "../tracers/log_stream.js";
3
4
  import { Serializable } from "../load/serializable.js";
4
- import { IterableReadableStream, type IterableReadableStreamInterface } from "../utils/stream.js";
5
+ import { IterableReadableStream } from "../utils/stream.js";
5
6
  import { RunnableConfig } from "./config.js";
6
7
  import { Run } from "../tracers/base.js";
7
- /**
8
- * Base interface implemented by all runnables.
9
- * Used for cross-compatibility between different versions of LangChain core.
10
- *
11
- * Should not change on patch releases.
12
- */
13
- export interface RunnableInterface<RunInput = any, RunOutput = any, CallOptions extends RunnableConfig = RunnableConfig> {
14
- lc_serializable: boolean;
15
- invoke(input: RunInput, options?: Partial<CallOptions>): Promise<RunOutput>;
16
- batch(inputs: RunInput[], options?: Partial<CallOptions> | Partial<CallOptions>[], batchOptions?: RunnableBatchOptions & {
17
- returnExceptions?: false;
18
- }): Promise<RunOutput[]>;
19
- batch(inputs: RunInput[], options?: Partial<CallOptions> | Partial<CallOptions>[], batchOptions?: RunnableBatchOptions & {
20
- returnExceptions: true;
21
- }): Promise<(RunOutput | Error)[]>;
22
- batch(inputs: RunInput[], options?: Partial<CallOptions> | Partial<CallOptions>[], batchOptions?: RunnableBatchOptions): Promise<(RunOutput | Error)[]>;
23
- stream(input: RunInput, options?: Partial<CallOptions>): Promise<IterableReadableStreamInterface<RunOutput>>;
24
- transform(generator: AsyncGenerator<RunInput>, options: Partial<CallOptions>): AsyncGenerator<RunOutput>;
25
- }
8
+ import { Graph } from "./graph.js";
9
+ export { type RunnableInterface, RunnableBatchOptions };
26
10
  export type RunnableFunc<RunInput, RunOutput> = (input: RunInput, options?: ({
27
11
  config?: RunnableConfig;
28
12
  } & RunnableConfig) | Record<string, any> | (Record<string, any> & {
@@ -32,11 +16,6 @@ export type RunnableMapLike<RunInput, RunOutput> = {
32
16
  [K in keyof RunOutput]: RunnableLike<RunInput, RunOutput[K]>;
33
17
  };
34
18
  export type RunnableLike<RunInput = any, RunOutput = any> = RunnableInterface<RunInput, RunOutput> | RunnableFunc<RunInput, RunOutput> | RunnableMapLike<RunInput, RunOutput>;
35
- export type RunnableBatchOptions = {
36
- /** @deprecated Pass in via the standard runnable config object instead */
37
- maxConcurrency?: number;
38
- returnExceptions?: boolean;
39
- };
40
19
  export type RunnableRetryFailedAttemptHandler = (error: any) => any;
41
20
  export declare function _coerceToDict(value: any, defaultKey: string): any;
42
21
  /**
@@ -141,6 +120,7 @@ export declare abstract class Runnable<RunInput = any, RunOutput = any, CallOpti
141
120
  protected _transformStreamWithConfig<I extends RunInput, O extends RunOutput>(inputGenerator: AsyncGenerator<I>, transformer: (generator: AsyncGenerator<I>, runManager?: CallbackManagerForChainRun, options?: Partial<CallOptions>) => AsyncGenerator<O>, options?: CallOptions & {
142
121
  runType?: string;
143
122
  }): AsyncGenerator<O>;
123
+ getGraph(_?: RunnableConfig): Graph;
144
124
  /**
145
125
  * Create a new runnable sequence that runs each individual runnable in series,
146
126
  * piping the output of one runnable into another runnable or runnable-like.
@@ -413,6 +393,7 @@ export declare class RunnableSequence<RunInput = any, RunOutput = any> extends R
413
393
  }): Promise<(RunOutput | Error)[]>;
414
394
  batch(inputs: RunInput[], options?: Partial<RunnableConfig> | Partial<RunnableConfig>[], batchOptions?: RunnableBatchOptions): Promise<(RunOutput | Error)[]>;
415
395
  _streamIterator(input: RunInput, options?: RunnableConfig): AsyncGenerator<RunOutput>;
396
+ getGraph(config?: RunnableConfig): Graph;
416
397
  pipe<NewRunOutput>(coerceable: RunnableLike<RunOutput, NewRunOutput>): RunnableSequence<RunInput, Exclude<NewRunOutput, Error>>;
417
398
  static isRunnableSequence(thing: any): thing is RunnableSequence;
418
399
  static from<RunInput = any, RunOutput = any>([first, ...runnables]: [
@@ -1,3 +1,4 @@
1
+ import { z } from "zod";
1
2
  import pRetry from "p-retry";
2
3
  import { CallbackManager, } from "../callbacks/manager.js";
3
4
  import { LogStreamCallbackHandler, RunLog, RunLogPatch, } from "../tracers/log_stream.js";
@@ -6,8 +7,9 @@ import { IterableReadableStream, concat, atee, pipeGeneratorWithSetup, AsyncGene
6
7
  import { DEFAULT_RECURSION_LIMIT, ensureConfig, getCallbackManagerForConfig, mergeConfigs, patchConfig, } from "./config.js";
7
8
  import { AsyncCaller } from "../utils/async_caller.js";
8
9
  import { RootListenersTracer } from "../tracers/root_listener.js";
9
- import { _RootEventFilter } from "./utils.js";
10
+ import { _RootEventFilter, isRunnableInterface } from "./utils.js";
10
11
  import { AsyncLocalStorageProviderSingleton } from "../singletons/index.js";
12
+ import { Graph } from "./graph.js";
11
13
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
14
  export function _coerceToDict(value, defaultKey) {
13
15
  return value &&
@@ -284,6 +286,23 @@ export class Runnable extends Serializable {
284
286
  }
285
287
  await runManager?.handleChainEnd(finalOutput ?? {}, undefined, undefined, undefined, { inputs: _coerceToDict(finalInput, "input") });
286
288
  }
289
+ getGraph(_) {
290
+ const graph = new Graph();
291
+ // TODO: Add input schema for runnables
292
+ const inputNode = graph.addNode({
293
+ name: `${this.getName()}Input`,
294
+ schema: z.any(),
295
+ });
296
+ const runnableNode = graph.addNode(this);
297
+ // TODO: Add output schemas for runnables
298
+ const outputNode = graph.addNode({
299
+ name: `${this.getName()}Output`,
300
+ schema: z.any(),
301
+ });
302
+ graph.addEdge(inputNode, runnableNode);
303
+ graph.addEdge(runnableNode, outputNode);
304
+ return graph;
305
+ }
287
306
  /**
288
307
  * Create a new runnable sequence that runs each individual runnable in series,
289
308
  * piping the output of one runnable into another runnable or runnable-like.
@@ -586,7 +605,7 @@ export class Runnable extends Serializable {
586
605
  }
587
606
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
588
607
  static isRunnable(thing) {
589
- return thing ? thing.lc_runnable : false;
608
+ return isRunnableInterface(thing);
590
609
  }
591
610
  /**
592
611
  * Bind lifecycle listeners to a Runnable, returning a new Runnable.
@@ -1095,6 +1114,30 @@ export class RunnableSequence extends Runnable {
1095
1114
  }
1096
1115
  await runManager?.handleChainEnd(_coerceToDict(finalOutput, "output"));
1097
1116
  }
1117
+ getGraph(config) {
1118
+ const graph = new Graph();
1119
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1120
+ let currentLastNode = null;
1121
+ this.steps.forEach((step, index) => {
1122
+ const stepGraph = step.getGraph(config);
1123
+ if (index !== 0) {
1124
+ stepGraph.trimFirstNode();
1125
+ }
1126
+ if (index !== this.steps.length - 1) {
1127
+ stepGraph.trimLastNode();
1128
+ }
1129
+ graph.extend(stepGraph);
1130
+ const stepFirstNode = stepGraph.firstNode();
1131
+ if (!stepFirstNode) {
1132
+ throw new Error(`Runnable ${step} has no first node`);
1133
+ }
1134
+ if (currentLastNode) {
1135
+ graph.addEdge(currentLastNode, stepFirstNode);
1136
+ }
1137
+ currentLastNode = stepGraph.lastNode();
1138
+ });
1139
+ return graph;
1140
+ }
1098
1141
  pipe(coerceable) {
1099
1142
  if (RunnableSequence.isRunnableSequence(coerceable)) {
1100
1143
  return new RunnableSequence({
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Graph = exports.nodeDataStr = void 0;
4
+ const zod_to_json_schema_1 = require("zod-to-json-schema");
5
+ const uuid_1 = require("uuid");
6
+ const utils_js_1 = require("./utils.cjs");
7
+ const MAX_DATA_DISPLAY_NAME_LENGTH = 42;
8
+ function nodeDataStr(node) {
9
+ if (!(0, uuid_1.validate)(node.id)) {
10
+ return node.id;
11
+ }
12
+ else if ((0, utils_js_1.isRunnableInterface)(node.data)) {
13
+ try {
14
+ let data = node.data.toString();
15
+ if (data.startsWith("<") ||
16
+ data[0] !== data[0].toUpperCase() ||
17
+ data.split("\n").length > 1) {
18
+ data = node.data.getName();
19
+ }
20
+ else if (data.length > MAX_DATA_DISPLAY_NAME_LENGTH) {
21
+ data = `${data.substring(0, MAX_DATA_DISPLAY_NAME_LENGTH)}...`;
22
+ }
23
+ return data.startsWith("Runnable") ? data.slice("Runnable".length) : data;
24
+ }
25
+ catch (error) {
26
+ return node.data.getName();
27
+ }
28
+ }
29
+ else {
30
+ return node.data.name ?? "UnknownSchema";
31
+ }
32
+ }
33
+ exports.nodeDataStr = nodeDataStr;
34
+ function nodeDataJson(node) {
35
+ // if node.data is implements Runnable
36
+ if ((0, utils_js_1.isRunnableInterface)(node.data)) {
37
+ return {
38
+ type: "runnable",
39
+ data: {
40
+ id: node.data.lc_id,
41
+ name: node.data.getName(),
42
+ },
43
+ };
44
+ }
45
+ else {
46
+ return {
47
+ type: "schema",
48
+ data: { ...(0, zod_to_json_schema_1.zodToJsonSchema)(node.data.schema), title: node.data.name },
49
+ };
50
+ }
51
+ }
52
+ class Graph {
53
+ constructor() {
54
+ Object.defineProperty(this, "nodes", {
55
+ enumerable: true,
56
+ configurable: true,
57
+ writable: true,
58
+ value: {}
59
+ });
60
+ Object.defineProperty(this, "edges", {
61
+ enumerable: true,
62
+ configurable: true,
63
+ writable: true,
64
+ value: []
65
+ });
66
+ }
67
+ // Convert the graph to a JSON-serializable format.
68
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
69
+ toJSON() {
70
+ const stableNodeIds = {};
71
+ Object.values(this.nodes).forEach((node, i) => {
72
+ stableNodeIds[node.id] = (0, uuid_1.validate)(node.id) ? i : node.id;
73
+ });
74
+ return {
75
+ nodes: Object.values(this.nodes).map((node) => ({
76
+ id: stableNodeIds[node.id],
77
+ ...nodeDataJson(node),
78
+ })),
79
+ edges: this.edges.map((edge) => edge.data
80
+ ? {
81
+ source: stableNodeIds[edge.source],
82
+ target: stableNodeIds[edge.target],
83
+ data: edge.data,
84
+ }
85
+ : {
86
+ source: stableNodeIds[edge.source],
87
+ target: stableNodeIds[edge.target],
88
+ }),
89
+ };
90
+ }
91
+ addNode(data, id) {
92
+ if (id !== undefined && this.nodes[id] !== undefined) {
93
+ throw new Error(`Node with id ${id} already exists`);
94
+ }
95
+ const nodeId = id || (0, uuid_1.v4)();
96
+ const node = { id: nodeId, data };
97
+ this.nodes[nodeId] = node;
98
+ return node;
99
+ }
100
+ removeNode(node) {
101
+ // Remove the node from the nodes map
102
+ delete this.nodes[node.id];
103
+ // Filter out edges connected to the node
104
+ this.edges = this.edges.filter((edge) => edge.source !== node.id && edge.target !== node.id);
105
+ }
106
+ addEdge(source, target, data) {
107
+ if (this.nodes[source.id] === undefined) {
108
+ throw new Error(`Source node ${source.id} not in graph`);
109
+ }
110
+ if (this.nodes[target.id] === undefined) {
111
+ throw new Error(`Target node ${target.id} not in graph`);
112
+ }
113
+ const edge = { source: source.id, target: target.id, data };
114
+ this.edges.push(edge);
115
+ return edge;
116
+ }
117
+ firstNode() {
118
+ const targets = new Set(this.edges.map((edge) => edge.target));
119
+ const found = [];
120
+ Object.values(this.nodes).forEach((node) => {
121
+ if (!targets.has(node.id)) {
122
+ found.push(node);
123
+ }
124
+ });
125
+ return found[0];
126
+ }
127
+ lastNode() {
128
+ const sources = new Set(this.edges.map((edge) => edge.source));
129
+ const found = [];
130
+ Object.values(this.nodes).forEach((node) => {
131
+ if (!sources.has(node.id)) {
132
+ found.push(node);
133
+ }
134
+ });
135
+ return found[0];
136
+ }
137
+ extend(graph) {
138
+ // Add all nodes from the other graph, taking care to avoid duplicates
139
+ Object.entries(graph.nodes).forEach(([key, value]) => {
140
+ this.nodes[key] = value;
141
+ });
142
+ // Add all edges from the other graph
143
+ this.edges = [...this.edges, ...graph.edges];
144
+ }
145
+ trimFirstNode() {
146
+ const firstNode = this.firstNode();
147
+ if (firstNode) {
148
+ const outgoingEdges = this.edges.filter((edge) => edge.source === firstNode.id);
149
+ if (Object.keys(this.nodes).length === 1 || outgoingEdges.length === 1) {
150
+ this.removeNode(firstNode);
151
+ }
152
+ }
153
+ }
154
+ trimLastNode() {
155
+ const lastNode = this.lastNode();
156
+ if (lastNode) {
157
+ const incomingEdges = this.edges.filter((edge) => edge.target === lastNode.id);
158
+ if (Object.keys(this.nodes).length === 1 || incomingEdges.length === 1) {
159
+ this.removeNode(lastNode);
160
+ }
161
+ }
162
+ }
163
+ }
164
+ exports.Graph = Graph;
@@ -0,0 +1,25 @@
1
+ import type { RunnableInterface, RunnableIOSchema } from "./types.js";
2
+ interface Edge {
3
+ source: string;
4
+ target: string;
5
+ data?: string;
6
+ }
7
+ interface Node {
8
+ id: string;
9
+ data: RunnableIOSchema | RunnableInterface;
10
+ }
11
+ export declare function nodeDataStr(node: Node): string;
12
+ export declare class Graph {
13
+ nodes: Record<string, Node>;
14
+ edges: Edge[];
15
+ toJSON(): Record<string, any>;
16
+ addNode(data: RunnableInterface | RunnableIOSchema, id?: string): Node;
17
+ removeNode(node: Node): void;
18
+ addEdge(source: Node, target: Node, data?: string): Edge;
19
+ firstNode(): Node | undefined;
20
+ lastNode(): Node | undefined;
21
+ extend(graph: Graph): void;
22
+ trimFirstNode(): void;
23
+ trimLastNode(): void;
24
+ }
25
+ export {};
@@ -0,0 +1,159 @@
1
+ import { zodToJsonSchema } from "zod-to-json-schema";
2
+ import { v4 as uuidv4, validate as isUuid } from "uuid";
3
+ import { isRunnableInterface } from "./utils.js";
4
+ const MAX_DATA_DISPLAY_NAME_LENGTH = 42;
5
+ export function nodeDataStr(node) {
6
+ if (!isUuid(node.id)) {
7
+ return node.id;
8
+ }
9
+ else if (isRunnableInterface(node.data)) {
10
+ try {
11
+ let data = node.data.toString();
12
+ if (data.startsWith("<") ||
13
+ data[0] !== data[0].toUpperCase() ||
14
+ data.split("\n").length > 1) {
15
+ data = node.data.getName();
16
+ }
17
+ else if (data.length > MAX_DATA_DISPLAY_NAME_LENGTH) {
18
+ data = `${data.substring(0, MAX_DATA_DISPLAY_NAME_LENGTH)}...`;
19
+ }
20
+ return data.startsWith("Runnable") ? data.slice("Runnable".length) : data;
21
+ }
22
+ catch (error) {
23
+ return node.data.getName();
24
+ }
25
+ }
26
+ else {
27
+ return node.data.name ?? "UnknownSchema";
28
+ }
29
+ }
30
+ function nodeDataJson(node) {
31
+ // if node.data is implements Runnable
32
+ if (isRunnableInterface(node.data)) {
33
+ return {
34
+ type: "runnable",
35
+ data: {
36
+ id: node.data.lc_id,
37
+ name: node.data.getName(),
38
+ },
39
+ };
40
+ }
41
+ else {
42
+ return {
43
+ type: "schema",
44
+ data: { ...zodToJsonSchema(node.data.schema), title: node.data.name },
45
+ };
46
+ }
47
+ }
48
+ export class Graph {
49
+ constructor() {
50
+ Object.defineProperty(this, "nodes", {
51
+ enumerable: true,
52
+ configurable: true,
53
+ writable: true,
54
+ value: {}
55
+ });
56
+ Object.defineProperty(this, "edges", {
57
+ enumerable: true,
58
+ configurable: true,
59
+ writable: true,
60
+ value: []
61
+ });
62
+ }
63
+ // Convert the graph to a JSON-serializable format.
64
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
65
+ toJSON() {
66
+ const stableNodeIds = {};
67
+ Object.values(this.nodes).forEach((node, i) => {
68
+ stableNodeIds[node.id] = isUuid(node.id) ? i : node.id;
69
+ });
70
+ return {
71
+ nodes: Object.values(this.nodes).map((node) => ({
72
+ id: stableNodeIds[node.id],
73
+ ...nodeDataJson(node),
74
+ })),
75
+ edges: this.edges.map((edge) => edge.data
76
+ ? {
77
+ source: stableNodeIds[edge.source],
78
+ target: stableNodeIds[edge.target],
79
+ data: edge.data,
80
+ }
81
+ : {
82
+ source: stableNodeIds[edge.source],
83
+ target: stableNodeIds[edge.target],
84
+ }),
85
+ };
86
+ }
87
+ addNode(data, id) {
88
+ if (id !== undefined && this.nodes[id] !== undefined) {
89
+ throw new Error(`Node with id ${id} already exists`);
90
+ }
91
+ const nodeId = id || uuidv4();
92
+ const node = { id: nodeId, data };
93
+ this.nodes[nodeId] = node;
94
+ return node;
95
+ }
96
+ removeNode(node) {
97
+ // Remove the node from the nodes map
98
+ delete this.nodes[node.id];
99
+ // Filter out edges connected to the node
100
+ this.edges = this.edges.filter((edge) => edge.source !== node.id && edge.target !== node.id);
101
+ }
102
+ addEdge(source, target, data) {
103
+ if (this.nodes[source.id] === undefined) {
104
+ throw new Error(`Source node ${source.id} not in graph`);
105
+ }
106
+ if (this.nodes[target.id] === undefined) {
107
+ throw new Error(`Target node ${target.id} not in graph`);
108
+ }
109
+ const edge = { source: source.id, target: target.id, data };
110
+ this.edges.push(edge);
111
+ return edge;
112
+ }
113
+ firstNode() {
114
+ const targets = new Set(this.edges.map((edge) => edge.target));
115
+ const found = [];
116
+ Object.values(this.nodes).forEach((node) => {
117
+ if (!targets.has(node.id)) {
118
+ found.push(node);
119
+ }
120
+ });
121
+ return found[0];
122
+ }
123
+ lastNode() {
124
+ const sources = new Set(this.edges.map((edge) => edge.source));
125
+ const found = [];
126
+ Object.values(this.nodes).forEach((node) => {
127
+ if (!sources.has(node.id)) {
128
+ found.push(node);
129
+ }
130
+ });
131
+ return found[0];
132
+ }
133
+ extend(graph) {
134
+ // Add all nodes from the other graph, taking care to avoid duplicates
135
+ Object.entries(graph.nodes).forEach(([key, value]) => {
136
+ this.nodes[key] = value;
137
+ });
138
+ // Add all edges from the other graph
139
+ this.edges = [...this.edges, ...graph.edges];
140
+ }
141
+ trimFirstNode() {
142
+ const firstNode = this.firstNode();
143
+ if (firstNode) {
144
+ const outgoingEdges = this.edges.filter((edge) => edge.source === firstNode.id);
145
+ if (Object.keys(this.nodes).length === 1 || outgoingEdges.length === 1) {
146
+ this.removeNode(firstNode);
147
+ }
148
+ }
149
+ }
150
+ trimLastNode() {
151
+ const lastNode = this.lastNode();
152
+ if (lastNode) {
153
+ const incomingEdges = this.edges.filter((edge) => edge.target === lastNode.id);
154
+ if (Object.keys(this.nodes).length === 1 || incomingEdges.length === 1) {
155
+ this.removeNode(lastNode);
156
+ }
157
+ }
158
+ }
159
+ }
@@ -1,4 +1,5 @@
1
- export { type RunnableFunc, type RunnableLike, type RunnableBatchOptions, type RunnableRetryFailedAttemptHandler, Runnable, type RunnableInterface, type RunnableBindingArgs, RunnableBinding, RunnableEach, RunnableRetry, RunnableSequence, RunnableMap, RunnableParallel, RunnableLambda, RunnableWithFallbacks, RunnableAssign, RunnablePick, _coerceToRunnable, } from "./base.js";
1
+ export { type RunnableFunc, type RunnableLike, type RunnableRetryFailedAttemptHandler, Runnable, type RunnableBindingArgs, RunnableBinding, RunnableEach, RunnableRetry, RunnableSequence, RunnableMap, RunnableParallel, RunnableLambda, RunnableWithFallbacks, RunnableAssign, RunnablePick, _coerceToRunnable, } from "./base.js";
2
+ export { type RunnableBatchOptions, type RunnableInterface, type RunnableIOSchema, } from "./types.js";
2
3
  export { type RunnableConfig, getCallbackManagerForConfig, patchConfig, ensureConfig, } from "./config.js";
3
4
  export { RunnablePassthrough } from "./passthrough.js";
4
5
  export { type RouterInput, RouterRunnable } from "./router.js";
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,33 @@
1
+ import type { z } from "zod";
2
+ import type { RunnableConfig } from "./config.js";
3
+ import type { IterableReadableStreamInterface } from "../utils/stream.js";
4
+ import type { SerializableInterface } from "../load/serializable.js";
5
+ export type RunnableBatchOptions = {
6
+ /** @deprecated Pass in via the standard runnable config object instead */
7
+ maxConcurrency?: number;
8
+ returnExceptions?: boolean;
9
+ };
10
+ export type RunnableIOSchema = {
11
+ name?: string;
12
+ schema: z.ZodType;
13
+ };
14
+ /**
15
+ * Base interface implemented by all runnables.
16
+ * Used for cross-compatibility between different versions of LangChain core.
17
+ *
18
+ * Should not change on patch releases.
19
+ */
20
+ export interface RunnableInterface<RunInput = any, RunOutput = any, CallOptions extends RunnableConfig = RunnableConfig> extends SerializableInterface {
21
+ lc_serializable: boolean;
22
+ invoke(input: RunInput, options?: Partial<CallOptions>): Promise<RunOutput>;
23
+ batch(inputs: RunInput[], options?: Partial<CallOptions> | Partial<CallOptions>[], batchOptions?: RunnableBatchOptions & {
24
+ returnExceptions?: false;
25
+ }): Promise<RunOutput[]>;
26
+ batch(inputs: RunInput[], options?: Partial<CallOptions> | Partial<CallOptions>[], batchOptions?: RunnableBatchOptions & {
27
+ returnExceptions: true;
28
+ }): Promise<(RunOutput | Error)[]>;
29
+ batch(inputs: RunInput[], options?: Partial<CallOptions> | Partial<CallOptions>[], batchOptions?: RunnableBatchOptions): Promise<(RunOutput | Error)[]>;
30
+ stream(input: RunInput, options?: Partial<CallOptions>): Promise<IterableReadableStreamInterface<RunOutput>>;
31
+ transform(generator: AsyncGenerator<RunInput>, options: Partial<CallOptions>): AsyncGenerator<RunOutput>;
32
+ getName(suffix?: string): string;
33
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports._RootEventFilter = void 0;
3
+ exports._RootEventFilter = exports.isRunnableInterface = void 0;
4
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5
+ function isRunnableInterface(thing) {
6
+ return thing ? thing.lc_runnable : false;
7
+ }
8
+ exports.isRunnableInterface = isRunnableInterface;
4
9
  /**
5
10
  * Utility to filter the root event in the streamEvents implementation.
6
11
  * This is simply binding the arguments to the namespace to make save on
@@ -1,4 +1,6 @@
1
1
  import { StreamEvent } from "../tracers/log_stream.js";
2
+ import type { RunnableInterface } from "./types.js";
3
+ export declare function isRunnableInterface(thing: any): thing is RunnableInterface;
2
4
  /**
3
5
  * Utility to filter the root event in the streamEvents implementation.
4
6
  * This is simply binding the arguments to the namespace to make save on
@@ -1,3 +1,7 @@
1
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2
+ export function isRunnableInterface(thing) {
3
+ return thing ? thing.lc_runnable : false;
4
+ }
1
5
  /**
2
6
  * Utility to filter the root event in the streamEvents implementation.
3
7
  * This is simply binding the arguments to the namespace to make save on
@@ -120,7 +120,7 @@ function isChatGenerationChunk(x) {
120
120
  */
121
121
  class LogStreamCallbackHandler extends base_js_1.BaseTracer {
122
122
  constructor(fields) {
123
- super(fields);
123
+ super({ _awaitHandler: true, ...fields });
124
124
  Object.defineProperty(this, "autoClose", {
125
125
  enumerable: true,
126
126
  configurable: true,
@@ -115,7 +115,7 @@ function isChatGenerationChunk(x) {
115
115
  */
116
116
  export class LogStreamCallbackHandler extends BaseTracer {
117
117
  constructor(fields) {
118
- super(fields);
118
+ super({ _awaitHandler: true, ...fields });
119
119
  Object.defineProperty(this, "autoClose", {
120
120
  enumerable: true,
121
121
  configurable: true,
@@ -4,7 +4,7 @@ exports.RootListenersTracer = void 0;
4
4
  const base_js_1 = require("./base.cjs");
5
5
  class RootListenersTracer extends base_js_1.BaseTracer {
6
6
  constructor({ config, onStart, onEnd, onError, }) {
7
- super();
7
+ super({ _awaitHandler: true });
8
8
  Object.defineProperty(this, "name", {
9
9
  enumerable: true,
10
10
  configurable: true,
@@ -1,7 +1,7 @@
1
1
  import { BaseTracer } from "./base.js";
2
2
  export class RootListenersTracer extends BaseTracer {
3
3
  constructor({ config, onStart, onEnd, onError, }) {
4
- super();
4
+ super({ _awaitHandler: true });
5
5
  Object.defineProperty(this, "name", {
6
6
  enumerable: true,
7
7
  configurable: true,
@@ -12,7 +12,7 @@ class RunCollectorCallbackHandler extends base_js_1.BaseTracer {
12
12
  * @param exampleId The ID of the example.
13
13
  */
14
14
  constructor({ exampleId } = {}) {
15
- super();
15
+ super({ _awaitHandler: true });
16
16
  /** The name of the callback handler. */
17
17
  Object.defineProperty(this, "name", {
18
18
  enumerable: true,
@@ -9,7 +9,7 @@ export class RunCollectorCallbackHandler extends BaseTracer {
9
9
  * @param exampleId The ID of the example.
10
10
  */
11
11
  constructor({ exampleId } = {}) {
12
- super();
12
+ super({ _awaitHandler: true });
13
13
  /** The name of the callback handler. */
14
14
  Object.defineProperty(this, "name", {
15
15
  enumerable: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/core",
3
- "version": "0.1.44",
3
+ "version": "0.1.45",
4
4
  "description": "Core LangChain.js abstractions and schemas",
5
5
  "type": "module",
6
6
  "engines": {