@langchain/langgraph 0.2.27 → 0.2.29

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,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports._isCommand = exports.Command = exports._isSend = exports.Send = exports._isSendInterface = exports.CHECKPOINT_NAMESPACE_END = exports.CHECKPOINT_NAMESPACE_SEPARATOR = exports.RESERVED = exports.NULL_TASK_ID = exports.TASK_NAMESPACE = exports.PULL = exports.PUSH = exports.TASKS = exports.TAG_NOSTREAM = exports.TAG_HIDDEN = exports.RECURSION_LIMIT_DEFAULT = exports.RUNTIME_PLACEHOLDER = exports.RESUME = exports.INTERRUPT = exports.CONFIG_KEY_CHECKPOINT_MAP = exports.CONFIG_KEY_RESUME_VALUE = exports.CONFIG_KEY_STREAM = exports.CONFIG_KEY_TASK_ID = exports.CONFIG_KEY_RESUMING = exports.CONFIG_KEY_CHECKPOINTER = exports.CONFIG_KEY_READ = exports.CONFIG_KEY_SEND = exports.ERROR = exports.INPUT = exports.MISSING = void 0;
3
+ exports._isCommand = exports.Command = exports._isSend = exports.Send = exports._isSendInterface = exports.CHECKPOINT_NAMESPACE_END = exports.CHECKPOINT_NAMESPACE_SEPARATOR = exports.RESERVED = exports.NULL_TASK_ID = exports.TASK_NAMESPACE = exports.PULL = exports.PUSH = exports.TASKS = exports.SELF = exports.TAG_NOSTREAM = exports.TAG_HIDDEN = exports.RECURSION_LIMIT_DEFAULT = exports.RUNTIME_PLACEHOLDER = exports.RESUME = exports.INTERRUPT = exports.CONFIG_KEY_CHECKPOINT_MAP = exports.CONFIG_KEY_RESUME_VALUE = exports.CONFIG_KEY_STREAM = exports.CONFIG_KEY_TASK_ID = exports.CONFIG_KEY_RESUMING = exports.CONFIG_KEY_CHECKPOINTER = exports.CONFIG_KEY_READ = exports.CONFIG_KEY_SEND = exports.ERROR = exports.INPUT = exports.MISSING = void 0;
4
4
  exports.MISSING = Symbol.for("__missing__");
5
5
  exports.INPUT = "__input__";
6
6
  exports.ERROR = "__error__";
@@ -19,6 +19,7 @@ exports.RUNTIME_PLACEHOLDER = "__pregel_runtime_placeholder__";
19
19
  exports.RECURSION_LIMIT_DEFAULT = 25;
20
20
  exports.TAG_HIDDEN = "langsmith:hidden";
21
21
  exports.TAG_NOSTREAM = "langsmith:nostream";
22
+ exports.SELF = "__self__";
22
23
  exports.TASKS = "__pregel_tasks";
23
24
  exports.PUSH = "__pregel_push";
24
25
  exports.PULL = "__pregel_pull";
@@ -117,9 +118,12 @@ class Send {
117
118
  exports.Send = Send;
118
119
  function _isSend(x) {
119
120
  const operation = x;
120
- return operation.lg_name === "Send";
121
+ return operation !== undefined && operation.lg_name === "Send";
121
122
  }
122
123
  exports._isSend = _isSend;
124
+ /**
125
+ * One or more commands to update the graph's state and send messages to nodes.
126
+ */
123
127
  class Command {
124
128
  constructor(args) {
125
129
  Object.defineProperty(this, "lg_name", {
@@ -134,10 +138,40 @@ class Command {
134
138
  writable: true,
135
139
  value: void 0
136
140
  });
141
+ Object.defineProperty(this, "graph", {
142
+ enumerable: true,
143
+ configurable: true,
144
+ writable: true,
145
+ value: void 0
146
+ });
147
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
148
+ Object.defineProperty(this, "update", {
149
+ enumerable: true,
150
+ configurable: true,
151
+ writable: true,
152
+ value: void 0
153
+ });
154
+ Object.defineProperty(this, "goto", {
155
+ enumerable: true,
156
+ configurable: true,
157
+ writable: true,
158
+ value: []
159
+ });
137
160
  this.resume = args.resume;
161
+ this.graph = args.graph;
162
+ this.update = args.update;
163
+ if (args.goto) {
164
+ this.goto = Array.isArray(args.goto) ? args.goto : [args.goto];
165
+ }
138
166
  }
139
167
  }
140
168
  exports.Command = Command;
169
+ Object.defineProperty(Command, "PARENT", {
170
+ enumerable: true,
171
+ configurable: true,
172
+ writable: true,
173
+ value: "__parent__"
174
+ });
141
175
  function _isCommand(x) {
142
176
  return typeof x === "object" && !!x && x.lg_name === "Command";
143
177
  }
@@ -15,6 +15,7 @@ export declare const RUNTIME_PLACEHOLDER = "__pregel_runtime_placeholder__";
15
15
  export declare const RECURSION_LIMIT_DEFAULT = 25;
16
16
  export declare const TAG_HIDDEN = "langsmith:hidden";
17
17
  export declare const TAG_NOSTREAM = "langsmith:nostream";
18
+ export declare const SELF = "__self__";
18
19
  export declare const TASKS = "__pregel_tasks";
19
20
  export declare const PUSH = "__pregel_push";
20
21
  export declare const PULL = "__pregel_pull";
@@ -87,11 +88,40 @@ export type Interrupt = {
87
88
  resumable?: boolean;
88
89
  ns?: string[];
89
90
  };
91
+ export type CommandParams<R> = {
92
+ /**
93
+ * Value to resume execution with. To be used together with {@link interrupt}.
94
+ */
95
+ resume?: R;
96
+ /**
97
+ * Graph to send the command to. Supported values are:
98
+ * - None: the current graph (default)
99
+ * - GraphCommand.PARENT: closest parent graph
100
+ */
101
+ graph?: string;
102
+ /**
103
+ * Update to apply to the graph's state.
104
+ */
105
+ update?: Record<string, any>;
106
+ /**
107
+ * Can be one of the following:
108
+ * - name of the node to navigate to next (any node that belongs to the specified `graph`)
109
+ * - sequence of node names to navigate to next
110
+ * - `Send` object (to execute a node with the input provided)
111
+ * - sequence of `Send` objects
112
+ */
113
+ goto?: string | Send | (string | Send)[];
114
+ };
115
+ /**
116
+ * One or more commands to update the graph's state and send messages to nodes.
117
+ */
90
118
  export declare class Command<R = unknown> {
91
119
  lg_name: string;
92
- resume: R;
93
- constructor(args: {
94
- resume: R;
95
- });
120
+ resume?: R;
121
+ graph?: string;
122
+ update?: Record<string, any>;
123
+ goto: string | Send | (string | Send)[];
124
+ static PARENT: string;
125
+ constructor(args: CommandParams<R>);
96
126
  }
97
127
  export declare function _isCommand(x: unknown): x is Command;
package/dist/constants.js CHANGED
@@ -16,6 +16,7 @@ export const RUNTIME_PLACEHOLDER = "__pregel_runtime_placeholder__";
16
16
  export const RECURSION_LIMIT_DEFAULT = 25;
17
17
  export const TAG_HIDDEN = "langsmith:hidden";
18
18
  export const TAG_NOSTREAM = "langsmith:nostream";
19
+ export const SELF = "__self__";
19
20
  export const TASKS = "__pregel_tasks";
20
21
  export const PUSH = "__pregel_push";
21
22
  export const PULL = "__pregel_pull";
@@ -112,8 +113,11 @@ export class Send {
112
113
  }
113
114
  export function _isSend(x) {
114
115
  const operation = x;
115
- return operation.lg_name === "Send";
116
+ return operation !== undefined && operation.lg_name === "Send";
116
117
  }
118
+ /**
119
+ * One or more commands to update the graph's state and send messages to nodes.
120
+ */
117
121
  export class Command {
118
122
  constructor(args) {
119
123
  Object.defineProperty(this, "lg_name", {
@@ -128,9 +132,39 @@ export class Command {
128
132
  writable: true,
129
133
  value: void 0
130
134
  });
135
+ Object.defineProperty(this, "graph", {
136
+ enumerable: true,
137
+ configurable: true,
138
+ writable: true,
139
+ value: void 0
140
+ });
141
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
142
+ Object.defineProperty(this, "update", {
143
+ enumerable: true,
144
+ configurable: true,
145
+ writable: true,
146
+ value: void 0
147
+ });
148
+ Object.defineProperty(this, "goto", {
149
+ enumerable: true,
150
+ configurable: true,
151
+ writable: true,
152
+ value: []
153
+ });
131
154
  this.resume = args.resume;
155
+ this.graph = args.graph;
156
+ this.update = args.update;
157
+ if (args.goto) {
158
+ this.goto = Array.isArray(args.goto) ? args.goto : [args.goto];
159
+ }
132
160
  }
133
161
  }
162
+ Object.defineProperty(Command, "PARENT", {
163
+ enumerable: true,
164
+ configurable: true,
165
+ writable: true,
166
+ value: "__parent__"
167
+ });
134
168
  export function _isCommand(x) {
135
169
  return typeof x === "object" && !!x && x.lg_name === "Command";
136
170
  }
package/dist/errors.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getSubgraphsSeenSet = exports.RemoteException = exports.MultipleSubgraphsError = exports.InvalidUpdateError = exports.EmptyChannelError = exports.EmptyInputError = exports.isGraphInterrupt = exports.isGraphBubbleUp = exports.NodeInterrupt = exports.GraphInterrupt = exports.GraphValueError = exports.GraphRecursionError = exports.GraphBubbleUp = exports.BaseLangGraphError = void 0;
3
+ exports.getSubgraphsSeenSet = exports.RemoteException = exports.MultipleSubgraphsError = exports.InvalidUpdateError = exports.EmptyChannelError = exports.EmptyInputError = exports.isGraphInterrupt = exports.isGraphBubbleUp = exports.isParentCommand = exports.ParentCommand = exports.NodeInterrupt = exports.GraphInterrupt = exports.GraphValueError = exports.GraphRecursionError = exports.GraphBubbleUp = exports.BaseLangGraphError = void 0;
4
4
  // TODO: Merge with base LangChain error class when we drop support for core@0.2.0
5
5
  class BaseLangGraphError extends Error {
6
6
  constructor(message, fields) {
@@ -79,6 +79,28 @@ class NodeInterrupt extends GraphInterrupt {
79
79
  }
80
80
  }
81
81
  exports.NodeInterrupt = NodeInterrupt;
82
+ class ParentCommand extends GraphBubbleUp {
83
+ constructor(command) {
84
+ super();
85
+ Object.defineProperty(this, "command", {
86
+ enumerable: true,
87
+ configurable: true,
88
+ writable: true,
89
+ value: void 0
90
+ });
91
+ this.name = "ParentCommand";
92
+ this.command = command;
93
+ }
94
+ static get unminifiable_name() {
95
+ return "ParentCommand";
96
+ }
97
+ }
98
+ exports.ParentCommand = ParentCommand;
99
+ function isParentCommand(e) {
100
+ return (e !== undefined &&
101
+ e.name === ParentCommand.unminifiable_name);
102
+ }
103
+ exports.isParentCommand = isParentCommand;
82
104
  function isGraphBubbleUp(e) {
83
105
  return e !== undefined && e.is_bubble_up === true;
84
106
  }
package/dist/errors.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Interrupt } from "./constants.js";
1
+ import { Command, Interrupt } from "./constants.js";
2
2
  export type BaseLangGraphErrorFields = {
3
3
  lc_error_code?: string;
4
4
  };
@@ -27,6 +27,12 @@ export declare class NodeInterrupt extends GraphInterrupt {
27
27
  constructor(message: any, fields?: BaseLangGraphErrorFields);
28
28
  static get unminifiable_name(): string;
29
29
  }
30
+ export declare class ParentCommand extends GraphBubbleUp {
31
+ command: Command;
32
+ constructor(command: Command);
33
+ static get unminifiable_name(): string;
34
+ }
35
+ export declare function isParentCommand(e?: Error): e is ParentCommand;
30
36
  export declare function isGraphBubbleUp(e?: Error): e is GraphBubbleUp;
31
37
  export declare function isGraphInterrupt(e?: GraphInterrupt | Error): e is GraphInterrupt;
32
38
  export declare class EmptyInputError extends BaseLangGraphError {
package/dist/errors.js CHANGED
@@ -70,6 +70,26 @@ export class NodeInterrupt extends GraphInterrupt {
70
70
  return "NodeInterrupt";
71
71
  }
72
72
  }
73
+ export class ParentCommand extends GraphBubbleUp {
74
+ constructor(command) {
75
+ super();
76
+ Object.defineProperty(this, "command", {
77
+ enumerable: true,
78
+ configurable: true,
79
+ writable: true,
80
+ value: void 0
81
+ });
82
+ this.name = "ParentCommand";
83
+ this.command = command;
84
+ }
85
+ static get unminifiable_name() {
86
+ return "ParentCommand";
87
+ }
88
+ }
89
+ export function isParentCommand(e) {
90
+ return (e !== undefined &&
91
+ e.name === ParentCommand.unminifiable_name);
92
+ }
73
93
  export function isGraphBubbleUp(e) {
74
94
  return e !== undefined && e.is_bubble_up === true;
75
95
  }
@@ -32,7 +32,14 @@ class Branch {
32
32
  writable: true,
33
33
  value: void 0
34
34
  });
35
- this.condition = options.path;
35
+ if (runnables_1.Runnable.isRunnable(options.path)) {
36
+ this.condition = options.path;
37
+ }
38
+ else {
39
+ this.condition = (0, runnables_1._coerceToRunnable)(options.path).withConfig({
40
+ runName: `Branch`,
41
+ });
42
+ }
36
43
  this.ends = Array.isArray(options.pathMap)
37
44
  ? options.pathMap.reduce((acc, n) => {
38
45
  acc[n] = n;
@@ -40,7 +47,7 @@ class Branch {
40
47
  }, {})
41
48
  : options.pathMap;
42
49
  }
43
- compile(writer, reader) {
50
+ run(writer, reader) {
44
51
  return write_js_1.ChannelWrite.registerWriter(new utils_js_1.RunnableCallable({
45
52
  trace: false,
46
53
  func: async (input, config) => {
@@ -59,8 +66,10 @@ class Branch {
59
66
  },
60
67
  }));
61
68
  }
62
- async _route(input, config, writer, reader) {
63
- let result = await this.condition(reader ? reader(config) : input, config);
69
+ async _route(input, config, writer, reader
70
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
71
+ ) {
72
+ let result = await this.condition.invoke(reader ? reader(config) : input, config);
64
73
  if (!Array.isArray(result)) {
65
74
  result = [result];
66
75
  }
@@ -77,7 +86,8 @@ class Branch {
77
86
  if (destinations.filter(constants_js_1._isSend).some((packet) => packet.node === exports.END)) {
78
87
  throw new errors_js_1.InvalidUpdateError("Cannot send a packet to the END node");
79
88
  }
80
- return writer(destinations);
89
+ const writeResult = await writer(destinations, config);
90
+ return writeResult ?? input;
81
91
  }
82
92
  }
83
93
  exports.Branch = Branch;
@@ -149,6 +159,7 @@ class Graph {
149
159
  runnable,
150
160
  metadata: options?.metadata,
151
161
  subgraphs: (0, subgraph_js_1.isPregelLike)(runnable) ? [runnable] : options?.subgraphs,
162
+ ends: options?.ends,
152
163
  };
153
164
  return this;
154
165
  }
@@ -168,10 +179,26 @@ class Graph {
168
179
  return this;
169
180
  }
170
181
  addConditionalEdges(source, path, pathMap) {
171
- const options = typeof source === "object" ? source : { source, path: path, pathMap };
182
+ const options = typeof source === "object"
183
+ ? source
184
+ : {
185
+ source,
186
+ path: path,
187
+ pathMap,
188
+ };
172
189
  this.warnIfCompiled("Adding an edge to a graph that has already been compiled. This will not be reflected in the compiled graph.");
190
+ if (!runnables_1.Runnable.isRunnable(options.path)) {
191
+ const pathDisplayValues = Array.isArray(options.pathMap)
192
+ ? options.pathMap.join(",")
193
+ : Object.keys(options.pathMap ?? {}).join(",");
194
+ options.path = (0, runnables_1._coerceToRunnable)(options.path).withConfig({
195
+ runName: `Branch<${options.source}${pathDisplayValues !== "" ? `,${pathDisplayValues}` : ""}>`.slice(0, 63),
196
+ });
197
+ }
173
198
  // find a name for condition
174
- const name = options.path.name || "condition";
199
+ const name = options.path.getName() === "RunnableLambda"
200
+ ? "condition"
201
+ : options.path.getName();
175
202
  // validate condition
176
203
  if (this.branches[options.source] && this.branches[options.source][name]) {
177
204
  throw new Error(`Condition \`${name}\` already present for node \`${source}\``);
@@ -264,6 +291,11 @@ class Graph {
264
291
  }
265
292
  }
266
293
  }
294
+ for (const node of Object.values(this.nodes)) {
295
+ for (const target of node.ends ?? []) {
296
+ allTargets.add(target);
297
+ }
298
+ }
267
299
  // validate targets
268
300
  for (const node of Object.keys(this.nodes)) {
269
301
  if (!allTargets.has(node)) {
@@ -305,6 +337,7 @@ class CompiledGraph extends index_js_1.Pregel {
305
337
  triggers: [],
306
338
  metadata: node.metadata,
307
339
  subgraphs: node.subgraphs,
340
+ ends: node.ends,
308
341
  })
309
342
  .pipe(node.runnable)
310
343
  .pipe(new write_js_1.ChannelWrite([{ channel: key, value: write_js_1.PASSTHROUGH }], [constants_js_1.TAG_HIDDEN]));
@@ -328,7 +361,7 @@ class CompiledGraph extends index_js_1.Pregel {
328
361
  this.nodes[exports.START] = index_js_1.Channel.subscribeTo(exports.START, { tags: [constants_js_1.TAG_HIDDEN] });
329
362
  }
330
363
  // attach branch writer
331
- this.nodes[start].pipe(branch.compile((dests) => {
364
+ this.nodes[start].pipe(branch.run((dests) => {
332
365
  const writes = dests.map((dest) => {
333
366
  if ((0, constants_js_1._isSend)(dest)) {
334
367
  return dest;
@@ -500,6 +533,13 @@ class CompiledGraph extends index_js_1.Pregel {
500
533
  }
501
534
  }
502
535
  }
536
+ for (const [key, node] of Object.entries(this.builder.nodes)) {
537
+ if (node.ends !== undefined) {
538
+ for (const end of node.ends) {
539
+ addEdge(_escapeMermaidKeywords(key), _escapeMermaidKeywords(end), undefined, true);
540
+ }
541
+ }
542
+ }
503
543
  return graph;
504
544
  }
505
545
  /**
@@ -15,24 +15,27 @@ export declare const START = "__start__";
15
15
  export declare const END = "__end__";
16
16
  export interface BranchOptions<IO, N extends string, CallOptions extends LangGraphRunnableConfig = LangGraphRunnableConfig> {
17
17
  source: N;
18
- path: Branch<IO, N, CallOptions>["condition"];
18
+ path: RunnableLike<IO, BranchPathReturnValue, CallOptions>;
19
19
  pathMap?: Record<string, N | typeof END> | (N | typeof END)[];
20
20
  }
21
+ export type BranchPathReturnValue = string | Send | (string | Send)[] | Promise<string | Send | (string | Send)[]>;
21
22
  export declare class Branch<IO, N extends string, CallOptions extends LangGraphRunnableConfig = LangGraphRunnableConfig> {
22
- condition: (input: IO, config: CallOptions) => string | Send | (string | Send)[] | Promise<string | Send | (string | Send)[]>;
23
+ condition: Runnable<IO, BranchPathReturnValue, CallOptions>;
23
24
  ends?: Record<string, N | typeof END>;
24
25
  constructor(options: Omit<BranchOptions<IO, N, CallOptions>, "source">);
25
- compile(writer: (dests: (string | Send)[]) => Runnable | undefined, reader?: (config: CallOptions) => IO): RunnableCallable<unknown, unknown>;
26
- _route(input: IO, config: CallOptions, writer: (dests: (string | Send)[]) => Runnable | undefined, reader?: (config: CallOptions) => IO): Promise<Runnable | undefined>;
26
+ run(writer: (dests: (string | Send)[], config: LangGraphRunnableConfig) => Runnable | void | Promise<void>, reader?: (config: CallOptions) => IO): RunnableCallable<unknown, unknown>;
27
+ _route(input: IO, config: CallOptions, writer: (dests: (string | Send)[], config: LangGraphRunnableConfig) => Runnable | void | Promise<void>, reader?: (config: CallOptions) => IO): Promise<Runnable | any>;
27
28
  }
28
29
  export type NodeSpec<RunInput, RunOutput> = {
29
30
  runnable: Runnable<RunInput, RunOutput>;
30
31
  metadata?: Record<string, unknown>;
31
32
  subgraphs?: Pregel<any, any>[];
33
+ ends?: string[];
32
34
  };
33
35
  export type AddNodeOptions = {
34
36
  metadata?: Record<string, unknown>;
35
37
  subgraphs?: Pregel<any, any>[];
38
+ ends?: string[];
36
39
  };
37
40
  export declare class Graph<N extends string = typeof END, RunInput = any, RunOutput = any, NodeSpecType extends NodeSpec<RunInput, RunOutput> = NodeSpec<RunInput, RunOutput>, C extends StateDefinition = StateDefinition> {
38
41
  nodes: Record<N, NodeSpecType>;
@@ -46,7 +49,7 @@ export declare class Graph<N extends string = typeof END, RunInput = any, RunOut
46
49
  addNode<K extends string, NodeInput = RunInput>(key: K, action: RunnableLike<NodeInput, RunOutput extends object ? RunOutput & Record<string, any> : RunOutput, LangGraphRunnableConfig<StateType<C>>>, options?: AddNodeOptions): Graph<N | K, RunInput, RunOutput>;
47
50
  addEdge(startKey: N | typeof START, endKey: N | typeof END): this;
48
51
  addConditionalEdges(source: BranchOptions<RunInput, N, LangGraphRunnableConfig<StateType<C>>>): this;
49
- addConditionalEdges(source: N, path: Branch<RunInput, N, LangGraphRunnableConfig<StateType<C>>>["condition"], pathMap?: BranchOptions<RunInput, N, LangGraphRunnableConfig<StateType<C>>>["pathMap"]): this;
52
+ addConditionalEdges(source: N, path: RunnableLike<RunInput, BranchPathReturnValue, LangGraphRunnableConfig<StateType<C>>>, pathMap?: BranchOptions<RunInput, N, LangGraphRunnableConfig<StateType<C>>>["pathMap"]): this;
50
53
  /**
51
54
  * @deprecated use `addEdge(START, key)` instead
52
55
  */
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable @typescript-eslint/no-use-before-define */
2
- import { _coerceToRunnable, } from "@langchain/core/runnables";
2
+ import { _coerceToRunnable, Runnable, } from "@langchain/core/runnables";
3
3
  import { Graph as DrawableGraph, } from "@langchain/core/runnables/graph";
4
4
  import { z } from "zod";
5
5
  import { validate as isUuid } from "uuid";
@@ -29,7 +29,14 @@ export class Branch {
29
29
  writable: true,
30
30
  value: void 0
31
31
  });
32
- this.condition = options.path;
32
+ if (Runnable.isRunnable(options.path)) {
33
+ this.condition = options.path;
34
+ }
35
+ else {
36
+ this.condition = _coerceToRunnable(options.path).withConfig({
37
+ runName: `Branch`,
38
+ });
39
+ }
33
40
  this.ends = Array.isArray(options.pathMap)
34
41
  ? options.pathMap.reduce((acc, n) => {
35
42
  acc[n] = n;
@@ -37,7 +44,7 @@ export class Branch {
37
44
  }, {})
38
45
  : options.pathMap;
39
46
  }
40
- compile(writer, reader) {
47
+ run(writer, reader) {
41
48
  return ChannelWrite.registerWriter(new RunnableCallable({
42
49
  trace: false,
43
50
  func: async (input, config) => {
@@ -56,8 +63,10 @@ export class Branch {
56
63
  },
57
64
  }));
58
65
  }
59
- async _route(input, config, writer, reader) {
60
- let result = await this.condition(reader ? reader(config) : input, config);
66
+ async _route(input, config, writer, reader
67
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
68
+ ) {
69
+ let result = await this.condition.invoke(reader ? reader(config) : input, config);
61
70
  if (!Array.isArray(result)) {
62
71
  result = [result];
63
72
  }
@@ -74,7 +83,8 @@ export class Branch {
74
83
  if (destinations.filter(_isSend).some((packet) => packet.node === END)) {
75
84
  throw new InvalidUpdateError("Cannot send a packet to the END node");
76
85
  }
77
- return writer(destinations);
86
+ const writeResult = await writer(destinations, config);
87
+ return writeResult ?? input;
78
88
  }
79
89
  }
80
90
  export class Graph {
@@ -145,6 +155,7 @@ export class Graph {
145
155
  runnable,
146
156
  metadata: options?.metadata,
147
157
  subgraphs: isPregelLike(runnable) ? [runnable] : options?.subgraphs,
158
+ ends: options?.ends,
148
159
  };
149
160
  return this;
150
161
  }
@@ -164,10 +175,26 @@ export class Graph {
164
175
  return this;
165
176
  }
166
177
  addConditionalEdges(source, path, pathMap) {
167
- const options = typeof source === "object" ? source : { source, path: path, pathMap };
178
+ const options = typeof source === "object"
179
+ ? source
180
+ : {
181
+ source,
182
+ path: path,
183
+ pathMap,
184
+ };
168
185
  this.warnIfCompiled("Adding an edge to a graph that has already been compiled. This will not be reflected in the compiled graph.");
186
+ if (!Runnable.isRunnable(options.path)) {
187
+ const pathDisplayValues = Array.isArray(options.pathMap)
188
+ ? options.pathMap.join(",")
189
+ : Object.keys(options.pathMap ?? {}).join(",");
190
+ options.path = _coerceToRunnable(options.path).withConfig({
191
+ runName: `Branch<${options.source}${pathDisplayValues !== "" ? `,${pathDisplayValues}` : ""}>`.slice(0, 63),
192
+ });
193
+ }
169
194
  // find a name for condition
170
- const name = options.path.name || "condition";
195
+ const name = options.path.getName() === "RunnableLambda"
196
+ ? "condition"
197
+ : options.path.getName();
171
198
  // validate condition
172
199
  if (this.branches[options.source] && this.branches[options.source][name]) {
173
200
  throw new Error(`Condition \`${name}\` already present for node \`${source}\``);
@@ -260,6 +287,11 @@ export class Graph {
260
287
  }
261
288
  }
262
289
  }
290
+ for (const node of Object.values(this.nodes)) {
291
+ for (const target of node.ends ?? []) {
292
+ allTargets.add(target);
293
+ }
294
+ }
263
295
  // validate targets
264
296
  for (const node of Object.keys(this.nodes)) {
265
297
  if (!allTargets.has(node)) {
@@ -300,6 +332,7 @@ export class CompiledGraph extends Pregel {
300
332
  triggers: [],
301
333
  metadata: node.metadata,
302
334
  subgraphs: node.subgraphs,
335
+ ends: node.ends,
303
336
  })
304
337
  .pipe(node.runnable)
305
338
  .pipe(new ChannelWrite([{ channel: key, value: PASSTHROUGH }], [TAG_HIDDEN]));
@@ -323,7 +356,7 @@ export class CompiledGraph extends Pregel {
323
356
  this.nodes[START] = Channel.subscribeTo(START, { tags: [TAG_HIDDEN] });
324
357
  }
325
358
  // attach branch writer
326
- this.nodes[start].pipe(branch.compile((dests) => {
359
+ this.nodes[start].pipe(branch.run((dests) => {
327
360
  const writes = dests.map((dest) => {
328
361
  if (_isSend(dest)) {
329
362
  return dest;
@@ -495,6 +528,13 @@ export class CompiledGraph extends Pregel {
495
528
  }
496
529
  }
497
530
  }
531
+ for (const [key, node] of Object.entries(this.builder.nodes)) {
532
+ if (node.ends !== undefined) {
533
+ for (const end of node.ends) {
534
+ addEdge(_escapeMermaidKeywords(key), _escapeMermaidKeywords(end), undefined, true);
535
+ }
536
+ }
537
+ }
498
538
  return graph;
499
539
  }
500
540
  /**