@langchain/langgraph 0.2.72 → 0.2.74

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.
Files changed (157) hide show
  1. package/dist/channels/any_value.cjs +1 -1
  2. package/dist/channels/any_value.js +1 -1
  3. package/dist/channels/any_value.js.map +1 -1
  4. package/dist/channels/base.cjs +4 -4
  5. package/dist/channels/base.js.map +1 -1
  6. package/dist/channels/binop.cjs +1 -1
  7. package/dist/channels/binop.js +1 -1
  8. package/dist/channels/binop.js.map +1 -1
  9. package/dist/channels/dynamic_barrier_value.cjs +1 -1
  10. package/dist/channels/dynamic_barrier_value.js +1 -1
  11. package/dist/channels/dynamic_barrier_value.js.map +1 -1
  12. package/dist/channels/ephemeral_value.cjs +1 -1
  13. package/dist/channels/ephemeral_value.js +1 -1
  14. package/dist/channels/ephemeral_value.js.map +1 -1
  15. package/dist/channels/last_value.cjs +1 -1
  16. package/dist/channels/last_value.js +1 -1
  17. package/dist/channels/last_value.js.map +1 -1
  18. package/dist/channels/named_barrier_value.cjs +1 -1
  19. package/dist/channels/named_barrier_value.js +1 -1
  20. package/dist/channels/named_barrier_value.js.map +1 -1
  21. package/dist/channels/topic.cjs +1 -1
  22. package/dist/channels/topic.js +1 -1
  23. package/dist/channels/topic.js.map +1 -1
  24. package/dist/constants.cjs +5 -5
  25. package/dist/constants.d.ts +2 -2
  26. package/dist/constants.js.map +1 -1
  27. package/dist/errors.cjs +5 -5
  28. package/dist/errors.d.ts +1 -1
  29. package/dist/errors.js +1 -1
  30. package/dist/errors.js.map +1 -1
  31. package/dist/func/index.cjs +3 -3
  32. package/dist/func/index.js.map +1 -1
  33. package/dist/func/types.cjs +1 -2
  34. package/dist/graph/annotation.cjs +2 -2
  35. package/dist/graph/annotation.js.map +1 -1
  36. package/dist/graph/graph.cjs +46 -40
  37. package/dist/graph/graph.d.ts +10 -2
  38. package/dist/graph/graph.js +46 -40
  39. package/dist/graph/graph.js.map +1 -1
  40. package/dist/graph/index.cjs +2 -1
  41. package/dist/graph/index.d.ts +1 -1
  42. package/dist/graph/index.js +1 -1
  43. package/dist/graph/index.js.map +1 -1
  44. package/dist/graph/message.cjs +43 -5
  45. package/dist/graph/message.d.ts +5 -0
  46. package/dist/graph/message.js +40 -3
  47. package/dist/graph/message.js.map +1 -1
  48. package/dist/graph/message.test.cjs +196 -0
  49. package/dist/graph/message.test.d.ts +1 -0
  50. package/dist/graph/message.test.js +194 -0
  51. package/dist/graph/message.test.js.map +1 -0
  52. package/dist/graph/messages_annotation.cjs +51 -1
  53. package/dist/graph/messages_annotation.d.ts +47 -0
  54. package/dist/graph/messages_annotation.js +50 -0
  55. package/dist/graph/messages_annotation.js.map +1 -1
  56. package/dist/graph/state.cjs +102 -89
  57. package/dist/graph/state.d.ts +16 -3
  58. package/dist/graph/state.js +102 -89
  59. package/dist/graph/state.js.map +1 -1
  60. package/dist/graph/zod/plugin.js.map +1 -1
  61. package/dist/graph/zod/schema.cjs +5 -6
  62. package/dist/graph/zod/schema.js.map +1 -1
  63. package/dist/graph/zod/state.cjs +6 -7
  64. package/dist/graph/zod/state.js.map +1 -1
  65. package/dist/interrupt.cjs +1 -2
  66. package/dist/interrupt.js.map +1 -1
  67. package/dist/managed/base.cjs +3 -3
  68. package/dist/managed/base.js.map +1 -1
  69. package/dist/managed/shared_value.js.map +1 -1
  70. package/dist/prebuilt/agentName.cjs +3 -4
  71. package/dist/prebuilt/agentName.js.map +1 -1
  72. package/dist/prebuilt/agent_executor.cjs +1 -2
  73. package/dist/prebuilt/agent_executor.d.ts +1 -1
  74. package/dist/prebuilt/agent_executor.js.map +1 -1
  75. package/dist/prebuilt/chat_agent_executor.cjs +1 -2
  76. package/dist/prebuilt/chat_agent_executor.js.map +1 -1
  77. package/dist/prebuilt/react_agent_executor.cjs +4 -4
  78. package/dist/prebuilt/react_agent_executor.d.ts +2 -2
  79. package/dist/prebuilt/react_agent_executor.js.map +1 -1
  80. package/dist/prebuilt/tool_executor.js.map +1 -1
  81. package/dist/prebuilt/tool_node.cjs +2 -2
  82. package/dist/prebuilt/tool_node.js.map +1 -1
  83. package/dist/pregel/algo.cjs +8 -7
  84. package/dist/pregel/algo.js +1 -0
  85. package/dist/pregel/algo.js.map +1 -1
  86. package/dist/pregel/call.cjs +3 -4
  87. package/dist/pregel/call.js.map +1 -1
  88. package/dist/pregel/debug.cjs +10 -10
  89. package/dist/pregel/debug.d.ts +3 -3
  90. package/dist/pregel/debug.js.map +1 -1
  91. package/dist/pregel/debug.test.cjs +31 -31
  92. package/dist/pregel/debug.test.js +12 -12
  93. package/dist/pregel/debug.test.js.map +1 -1
  94. package/dist/pregel/index.js.map +1 -1
  95. package/dist/pregel/io.cjs +8 -9
  96. package/dist/pregel/io.js +2 -2
  97. package/dist/pregel/io.js.map +1 -1
  98. package/dist/pregel/io.mapCommand.test.cjs +29 -29
  99. package/dist/pregel/io.mapCommand.test.js +5 -5
  100. package/dist/pregel/io.mapCommand.test.js.map +1 -1
  101. package/dist/pregel/loop.js.map +1 -1
  102. package/dist/pregel/messages.cjs +15 -13
  103. package/dist/pregel/messages.d.ts +1 -1
  104. package/dist/pregel/messages.js +15 -13
  105. package/dist/pregel/messages.js.map +1 -1
  106. package/dist/pregel/messages.test.cjs +105 -105
  107. package/dist/pregel/messages.test.js +31 -31
  108. package/dist/pregel/messages.test.js.map +1 -1
  109. package/dist/pregel/read.js.map +1 -1
  110. package/dist/pregel/read.test.cjs +35 -35
  111. package/dist/pregel/read.test.js +4 -4
  112. package/dist/pregel/read.test.js.map +1 -1
  113. package/dist/pregel/remote.js.map +1 -1
  114. package/dist/pregel/retry.cjs +10 -10
  115. package/dist/pregel/retry.js +8 -8
  116. package/dist/pregel/retry.js.map +1 -1
  117. package/dist/pregel/runner.cjs +91 -118
  118. package/dist/pregel/runner.js +92 -119
  119. package/dist/pregel/runner.js.map +1 -1
  120. package/dist/pregel/runner.test.cjs +14 -14
  121. package/dist/pregel/runner.test.js +4 -4
  122. package/dist/pregel/runner.test.js.map +1 -1
  123. package/dist/pregel/stream.js.map +1 -1
  124. package/dist/pregel/types.cjs +2 -2
  125. package/dist/pregel/types.js.map +1 -1
  126. package/dist/pregel/utils/config.cjs +40 -22
  127. package/dist/pregel/utils/config.d.ts +8 -5
  128. package/dist/pregel/utils/config.js +33 -14
  129. package/dist/pregel/utils/config.js.map +1 -1
  130. package/dist/pregel/utils/config.test.cjs +58 -58
  131. package/dist/pregel/utils/config.test.js +12 -12
  132. package/dist/pregel/utils/config.test.js.map +1 -1
  133. package/dist/pregel/utils/index.cjs +12 -11
  134. package/dist/pregel/utils/index.js +6 -4
  135. package/dist/pregel/utils/index.js.map +1 -1
  136. package/dist/pregel/utils/subgraph.cjs +2 -3
  137. package/dist/pregel/utils/subgraph.js.map +1 -1
  138. package/dist/pregel/utils/subgraph.test.cjs +18 -18
  139. package/dist/pregel/utils/subgraph.test.js +1 -1
  140. package/dist/pregel/utils/subgraph.test.js.map +1 -1
  141. package/dist/pregel/validate.cjs +3 -3
  142. package/dist/pregel/validate.js.map +1 -1
  143. package/dist/pregel/validate.test.cjs +43 -43
  144. package/dist/pregel/validate.test.js +3 -3
  145. package/dist/pregel/validate.test.js.map +1 -1
  146. package/dist/pregel/write.js.map +1 -1
  147. package/dist/pregel/write.test.cjs +30 -30
  148. package/dist/pregel/write.test.js +8 -8
  149. package/dist/pregel/write.test.js.map +1 -1
  150. package/dist/setup/async_local_storage.cjs +1 -2
  151. package/dist/utils.cjs +7 -7
  152. package/dist/utils.js.map +1 -1
  153. package/dist/web.cjs +3 -1
  154. package/dist/web.d.ts +2 -2
  155. package/dist/web.js +2 -2
  156. package/dist/web.js.map +1 -1
  157. package/package.json +11 -11
@@ -1,6 +1,8 @@
1
1
  /* __LC_ALLOW_ENTRYPOINT_SIDE_EFFECTS__ */
2
+ import { z } from "zod";
2
3
  import { Annotation } from "./annotation.js";
3
4
  import { messagesStateReducer } from "./message.js";
5
+ import { withLangGraph } from "./zod/state.js";
4
6
  /**
5
7
  * Prebuilt state annotation that combines returned messages.
6
8
  * Can handle standard messages and special modifiers like {@link RemoveMessage}
@@ -42,4 +44,52 @@ export const MessagesAnnotation = Annotation.Root({
42
44
  default: () => [],
43
45
  }),
44
46
  });
47
+ /**
48
+ * Prebuilt state object that uses Zod to combine returned messages.
49
+ * This utility is synonymous with the `MessagesAnnotation` annotation,
50
+ * but uses Zod as the way to express messages state.
51
+ *
52
+ * You can use import and use this prebuilt schema like this:
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * import { MessagesZodState, StateGraph } from "@langchain/langgraph";
57
+ *
58
+ * const graph = new StateGraph(MessagesZodState)
59
+ * .addNode(...)
60
+ * ...
61
+ * ```
62
+ *
63
+ * Which is equivalent to initializing the schema object manually like this:
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * import { z } from "zod";
68
+ * import type { BaseMessage, BaseMessageLike } from "@langchain/core/messages";
69
+ * import { StateGraph, messagesStateReducer } from "@langchain/langgraph";
70
+ * import "@langchain/langgraph/zod";
71
+ *
72
+ * const AgentState = z.object({
73
+ * messages: z
74
+ * .custom<BaseMessage[]>()
75
+ * .default(() => [])
76
+ * .langgraph.reducer(
77
+ * messagesStateReducer,
78
+ * z.custom<BaseMessageLike | BaseMessageLike[]>()
79
+ * ),
80
+ * });
81
+ * const graph = new StateGraph(AgentState)
82
+ * .addNode(...)
83
+ * ...
84
+ * ```
85
+ */
86
+ export const MessagesZodState = z.object({
87
+ messages: withLangGraph(z.custom(), {
88
+ reducer: {
89
+ schema: z.custom(),
90
+ fn: messagesStateReducer,
91
+ },
92
+ default: () => [],
93
+ }),
94
+ });
45
95
  //# sourceMappingURL=messages_annotation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"messages_annotation.js","sourceRoot":"","sources":["../../src/graph/messages_annotation.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAG1C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAY,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAE9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,UAAU,CAAC,IAAI,CAAC;IAChD,QAAQ,EAAE,UAAU,CAA0B;QAC5C,OAAO,EAAE,oBAAoB;QAC7B,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE;KAClB,CAAC;CACH,CAAC,CAAC"}
1
+ {"version":3,"file":"messages_annotation.js","sourceRoot":"","sources":["../../src/graph/messages_annotation.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAG1C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAY,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,UAAU,CAAC,IAAI,CAAC;IAChD,QAAQ,EAAE,UAAU,CAA0B;QAC5C,OAAO,EAAE,oBAAoB;QAC7B,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE;KAClB,CAAC;CACH,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,MAAM,EAAiB,EAAE;QACjD,OAAO,EAAE;YACP,MAAM,EAAE,CAAC,CAAC,MAAM,EAAY;YAC5B,EAAE,EAAE,oBAAoB;SACzB;QACD,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE;KAClB,CAAC;CACH,CAAC,CAAC"}
@@ -246,54 +246,76 @@ class StateGraph extends graph_js_1.Graph {
246
246
  }
247
247
  }
248
248
  }
249
- addNode(key, action, options) {
250
- if (key in this.channels) {
251
- throw new Error(`${key} is already being used as a state attribute (a.k.a. a channel), cannot also be used as a node name.`);
252
- }
253
- for (const reservedChar of [
254
- constants_js_1.CHECKPOINT_NAMESPACE_SEPARATOR,
255
- constants_js_1.CHECKPOINT_NAMESPACE_END,
256
- ]) {
257
- if (key.includes(reservedChar)) {
258
- throw new Error(`"${reservedChar}" is a reserved character and is not allowed in node names.`);
249
+ addNode(...args) {
250
+ function isMultipleNodes(args) {
251
+ return args.length >= 1 && typeof args[0] !== "string";
252
+ }
253
+ const nodes = (isMultipleNodes(args) // eslint-disable-line no-nested-ternary
254
+ ? Array.isArray(args[0])
255
+ ? args[0]
256
+ : Object.entries(args[0])
257
+ : [[args[0], args[1], args[2]]]);
258
+ if (nodes.length === 0) {
259
+ throw new Error("No nodes provided in `addNode`");
260
+ }
261
+ for (const [key, action, options] of nodes) {
262
+ if (key in this.channels) {
263
+ throw new Error(`${key} is already being used as a state attribute (a.k.a. a channel), cannot also be used as a node name.`);
259
264
  }
265
+ for (const reservedChar of [
266
+ constants_js_1.CHECKPOINT_NAMESPACE_SEPARATOR,
267
+ constants_js_1.CHECKPOINT_NAMESPACE_END,
268
+ ]) {
269
+ if (key.includes(reservedChar)) {
270
+ throw new Error(`"${reservedChar}" is a reserved character and is not allowed in node names.`);
271
+ }
272
+ }
273
+ this.warnIfCompiled(`Adding a node to a graph that has already been compiled. This will not be reflected in the compiled graph.`);
274
+ if (key in this.nodes) {
275
+ throw new Error(`Node \`${key}\` already present.`);
276
+ }
277
+ if (key === constants_js_1.END || key === constants_js_1.START) {
278
+ throw new Error(`Node \`${key}\` is reserved.`);
279
+ }
280
+ let inputSpec = this._schemaDefinition;
281
+ if (options?.input !== undefined) {
282
+ if ((0, state_js_1.isAnyZodObject)(options.input)) {
283
+ inputSpec = (0, state_js_1.getChannelsFromZod)(options.input);
284
+ }
285
+ else if (options.input.spec !== undefined) {
286
+ inputSpec = options.input.spec;
287
+ }
288
+ }
289
+ if (inputSpec !== undefined) {
290
+ this._addSchema(inputSpec);
291
+ }
292
+ let runnable;
293
+ if (runnables_1.Runnable.isRunnable(action)) {
294
+ runnable = action;
295
+ }
296
+ else if (typeof action === "function") {
297
+ runnable = new utils_js_1.RunnableCallable({
298
+ func: action,
299
+ name: key,
300
+ trace: false,
301
+ });
302
+ }
303
+ else {
304
+ runnable = (0, runnables_1._coerceToRunnable)(action);
305
+ }
306
+ const nodeSpec = {
307
+ runnable: runnable,
308
+ retryPolicy: options?.retryPolicy,
309
+ metadata: options?.metadata,
310
+ input: inputSpec ?? this._schemaDefinition,
311
+ subgraphs: (0, subgraph_js_1.isPregelLike)(runnable)
312
+ ? // eslint-disable-next-line @typescript-eslint/no-explicit-any
313
+ [runnable]
314
+ : options?.subgraphs,
315
+ ends: options?.ends,
316
+ };
317
+ this.nodes[key] = nodeSpec;
260
318
  }
261
- this.warnIfCompiled(`Adding a node to a graph that has already been compiled. This will not be reflected in the compiled graph.`);
262
- if (key in this.nodes) {
263
- throw new Error(`Node \`${key}\` already present.`);
264
- }
265
- if (key === constants_js_1.END || key === constants_js_1.START) {
266
- throw new Error(`Node \`${key}\` is reserved.`);
267
- }
268
- if (options?.input !== undefined) {
269
- this._addSchema(options.input.spec);
270
- }
271
- let runnable;
272
- if (runnables_1.Runnable.isRunnable(action)) {
273
- runnable = action;
274
- }
275
- else if (typeof action === "function") {
276
- runnable = new utils_js_1.RunnableCallable({
277
- func: action,
278
- name: key,
279
- trace: false,
280
- });
281
- }
282
- else {
283
- runnable = (0, runnables_1._coerceToRunnable)(action);
284
- }
285
- const nodeSpec = {
286
- runnable: runnable,
287
- retryPolicy: options?.retryPolicy,
288
- metadata: options?.metadata,
289
- input: options?.input?.spec ?? this._schemaDefinition,
290
- subgraphs: (0, subgraph_js_1.isPregelLike)(runnable)
291
- ? // eslint-disable-next-line @typescript-eslint/no-explicit-any
292
- [runnable]
293
- : options?.subgraphs,
294
- ends: options?.ends,
295
- };
296
- this.nodes[key] = nodeSpec;
297
319
  return this;
298
320
  }
299
321
  addEdge(startKey, endKey) {
@@ -321,6 +343,27 @@ class StateGraph extends graph_js_1.Graph {
321
343
  this.waitingEdges.add([startKey, endKey]);
322
344
  return this;
323
345
  }
346
+ addSequence(nodes) {
347
+ const parsedNodes = Array.isArray(nodes)
348
+ ? nodes
349
+ : Object.entries(nodes);
350
+ if (parsedNodes.length === 0) {
351
+ throw new Error("Sequence requires at least one node.");
352
+ }
353
+ let previousNode;
354
+ for (const [key, action, options] of parsedNodes) {
355
+ if (key in this.nodes) {
356
+ throw new Error(`Node names must be unique: node with the name "${key}" already exists.`);
357
+ }
358
+ const validKey = key;
359
+ this.addNode(validKey, action, options);
360
+ if (previousNode != null) {
361
+ this.addEdge(previousNode, validKey);
362
+ }
363
+ previousNode = validKey;
364
+ }
365
+ return this;
366
+ }
324
367
  compile({ checkpointer, store, interruptBefore, interruptAfter, name, } = {}) {
325
368
  // validate the graph
326
369
  this.validate([
@@ -507,15 +550,14 @@ class CompiledStateGraph extends graph_js_1.CompiledGraph {
507
550
  const inputDefinition = node?.input ?? this.builder._schemaDefinition;
508
551
  const inputValues = Object.fromEntries(Object.keys(this.builder._schemaDefinitions.get(inputDefinition)).map((k) => [k, k]));
509
552
  const isSingleInput = Object.keys(inputValues).length === 1 && ROOT in inputValues;
510
- this.channels[key] = new ephemeral_value_js_1.EphemeralValue(false);
553
+ const branchChannel = `branch:to:${key}`;
554
+ this.channels[branchChannel] = new ephemeral_value_js_1.EphemeralValue(false);
511
555
  this.nodes[key] = new read_js_1.PregelNode({
512
- triggers: [],
556
+ triggers: [branchChannel],
513
557
  // read state keys
514
558
  channels: isSingleInput ? Object.keys(inputValues) : inputValues,
515
- // publish to this channel and state keys
516
- writers: [
517
- new write_js_1.ChannelWrite(stateWriteEntries.concat({ channel: key, value: key }), [constants_js_1.TAG_HIDDEN]),
518
- ],
559
+ // publish to state keys
560
+ writers: [new write_js_1.ChannelWrite(stateWriteEntries, [constants_js_1.TAG_HIDDEN])],
519
561
  mapper: isSingleInput
520
562
  ? undefined
521
563
  : // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -531,10 +573,12 @@ class CompiledStateGraph extends graph_js_1.CompiledGraph {
531
573
  }
532
574
  }
533
575
  attachEdge(start, end) {
534
- if (end === constants_js_1.END) {
576
+ if (end === constants_js_1.END)
535
577
  return;
578
+ if (typeof start === "string") {
579
+ this.nodes[start].writers.push(new write_js_1.ChannelWrite([{ channel: `branch:to:${end}`, value: null }], [constants_js_1.TAG_HIDDEN]));
536
580
  }
537
- if (Array.isArray(start)) {
581
+ else if (Array.isArray(start)) {
538
582
  const channelName = `join:${start.join("+")}:${end}`;
539
583
  // register channel
540
584
  this.channels[channelName] =
@@ -546,34 +590,16 @@ class CompiledStateGraph extends graph_js_1.CompiledGraph {
546
590
  this.nodes[s].writers.push(new write_js_1.ChannelWrite([{ channel: channelName, value: s }], [constants_js_1.TAG_HIDDEN]));
547
591
  }
548
592
  }
549
- else if (start === constants_js_1.START) {
550
- const channelName = `${constants_js_1.START}:${end}`;
551
- // register channel
552
- this.channels[channelName] =
553
- new ephemeral_value_js_1.EphemeralValue();
554
- // subscribe to channel
555
- this.nodes[end].triggers.push(channelName);
556
- // publish to channel
557
- this.nodes[constants_js_1.START].writers.push(new write_js_1.ChannelWrite([{ channel: channelName, value: constants_js_1.START }], [constants_js_1.TAG_HIDDEN]));
558
- }
559
- else {
560
- this.nodes[end].triggers.push(start);
561
- }
562
593
  }
563
- attachBranch(start, name, branch, options = { withReader: true }) {
594
+ attachBranch(start, _, branch, options = { withReader: true }) {
564
595
  const branchWriter = async (packets, config) => {
565
596
  const filteredPackets = packets.filter((p) => p !== constants_js_1.END);
566
- if (!filteredPackets.length) {
597
+ if (!filteredPackets.length)
567
598
  return;
568
- }
569
599
  const writes = filteredPackets.map((p) => {
570
- if ((0, constants_js_1._isSend)(p)) {
600
+ if ((0, constants_js_1._isSend)(p))
571
601
  return p;
572
- }
573
- return {
574
- channel: `branch:${start}:${name}:${p}`,
575
- value: start,
576
- };
602
+ return { channel: `branch:to:${p}`, value: start };
577
603
  });
578
604
  await write_js_1.ChannelWrite.doWrite({ ...config, tags: (config.tags ?? []).concat([constants_js_1.TAG_HIDDEN]) }, writes);
579
605
  };
@@ -583,19 +609,6 @@ class CompiledStateGraph extends graph_js_1.CompiledGraph {
583
609
  options.withReader
584
610
  ? (config) => read_js_1.ChannelRead.doRead(config, this.streamChannels ?? this.outputChannels, true)
585
611
  : undefined));
586
- // attach branch subscribers
587
- const ends = branch.ends
588
- ? Object.values(branch.ends)
589
- : Object.keys(this.builder.nodes);
590
- for (const end of ends) {
591
- if (end === constants_js_1.END) {
592
- continue;
593
- }
594
- const channelName = `branch:${start}:${name}:${end}`;
595
- this.channels[channelName] =
596
- new ephemeral_value_js_1.EphemeralValue(false);
597
- this.nodes[end].triggers.push(channelName);
598
- }
599
612
  }
600
613
  async _validateInput(input) {
601
614
  const inputSchema = this.builder._inputRuntimeDefinition;
@@ -24,7 +24,7 @@ export type StateGraphNodeSpec<RunInput, RunOutput> = NodeSpec<RunInput, RunOutp
24
24
  };
25
25
  export type StateGraphAddNodeOptions = {
26
26
  retryPolicy?: RetryPolicy;
27
- input?: AnnotationRoot<any>;
27
+ input?: AnnotationRoot<any> | AnyZodObject;
28
28
  } & AddNodeOptions;
29
29
  export type StateGraphArgsWithStateSchema<SD extends StateDefinition, I extends StateDefinition, O extends StateDefinition> = {
30
30
  stateSchema: AnnotationRoot<SD>;
@@ -42,6 +42,8 @@ type ZodStateGraphArgsWithStateSchema<SD extends AnyZodObject, I extends SDZod,
42
42
  };
43
43
  type SDZod = StateDefinition | AnyZodObject;
44
44
  type ToStateDefinition<T> = T extends AnyZodObject ? ZodToStateDefinition<T> : T extends StateDefinition ? T : never;
45
+ type NodeAction<S, U, C extends SDZod> = RunnableLike<S, U extends object ? U & Record<string, any> : U, // eslint-disable-line @typescript-eslint/no-explicit-any
46
+ LangGraphRunnableConfig<StateType<ToStateDefinition<C>>>>;
45
47
  /**
46
48
  * A graph whose nodes communicate by reading and writing to a shared state.
47
49
  * Each node takes a defined `State` as input and returns a `Partial<State>`.
@@ -133,8 +135,19 @@ export declare class StateGraph<SD extends SDZod | unknown, S = SD extends SDZod
133
135
  constructor(fields: SD extends AnyZodObject ? SD | ZodStateGraphArgsWithStateSchema<SD, I, O> : never, configSchema?: C | AnnotationRoot<ToStateDefinition<C>>);
134
136
  get allEdges(): Set<[string, string]>;
135
137
  _addSchema(stateDefinition: SDZod): void;
136
- addNode<K extends string, NodeInput = S>(key: K, action: RunnableLike<NodeInput, U extends object ? U & Record<string, any> : U, LangGraphRunnableConfig<StateType<ToStateDefinition<C>>>>, options?: StateGraphAddNodeOptions): StateGraph<SD, S, U, N | K, I, O, C>;
138
+ addNode<K extends string>(nodes: Record<K, NodeAction<S, U, C>> | [
139
+ key: K,
140
+ action: NodeAction<S, U, C>,
141
+ options?: StateGraphAddNodeOptions
142
+ ][]): StateGraph<SD, S, U, N | K, I, O, C>;
143
+ addNode<K extends string, NodeInput = S>(key: K, action: NodeAction<NodeInput, U, C>, options?: StateGraphAddNodeOptions): StateGraph<SD, S, U, N | K, I, O, C>;
137
144
  addEdge(startKey: typeof START | N | N[], endKey: N | typeof END): this;
145
+ addSequence<K extends string>(nodes: [
146
+ key: K,
147
+ action: NodeAction<S, U, C>,
148
+ options?: StateGraphAddNodeOptions
149
+ ][]): StateGraph<SD, S, U, N | K, I, O, C>;
150
+ addSequence<K extends string>(nodes: Record<K, NodeAction<S, U, C>>): StateGraph<SD, S, U, N | K, I, O, C>;
138
151
  compile({ checkpointer, store, interruptBefore, interruptAfter, name, }?: {
139
152
  checkpointer?: BaseCheckpointSaver | false;
140
153
  store?: BaseStore;
@@ -153,7 +166,7 @@ export declare class CompiledStateGraph<S, U, N extends string = typeof START, I
153
166
  attachNode(key: typeof START, node?: never): void;
154
167
  attachNode(key: N, node: StateGraphNodeSpec<S, U>): void;
155
168
  attachEdge(start: N | N[] | "__start__", end: N | "__end__"): void;
156
- attachBranch(start: N | typeof START, name: string, branch: Branch<S, N>, options?: {
169
+ attachBranch(start: N | typeof START, _: string, branch: Branch<S, N>, options?: {
157
170
  withReader?: boolean;
158
171
  }): void;
159
172
  protected _validateInput(input: UpdateType<ToStateDefinition<I>>): Promise<UpdateType<ToStateDefinition<I>>>;
@@ -243,54 +243,76 @@ export class StateGraph extends Graph {
243
243
  }
244
244
  }
245
245
  }
246
- addNode(key, action, options) {
247
- if (key in this.channels) {
248
- throw new Error(`${key} is already being used as a state attribute (a.k.a. a channel), cannot also be used as a node name.`);
249
- }
250
- for (const reservedChar of [
251
- CHECKPOINT_NAMESPACE_SEPARATOR,
252
- CHECKPOINT_NAMESPACE_END,
253
- ]) {
254
- if (key.includes(reservedChar)) {
255
- throw new Error(`"${reservedChar}" is a reserved character and is not allowed in node names.`);
246
+ addNode(...args) {
247
+ function isMultipleNodes(args) {
248
+ return args.length >= 1 && typeof args[0] !== "string";
249
+ }
250
+ const nodes = (isMultipleNodes(args) // eslint-disable-line no-nested-ternary
251
+ ? Array.isArray(args[0])
252
+ ? args[0]
253
+ : Object.entries(args[0])
254
+ : [[args[0], args[1], args[2]]]);
255
+ if (nodes.length === 0) {
256
+ throw new Error("No nodes provided in `addNode`");
257
+ }
258
+ for (const [key, action, options] of nodes) {
259
+ if (key in this.channels) {
260
+ throw new Error(`${key} is already being used as a state attribute (a.k.a. a channel), cannot also be used as a node name.`);
256
261
  }
262
+ for (const reservedChar of [
263
+ CHECKPOINT_NAMESPACE_SEPARATOR,
264
+ CHECKPOINT_NAMESPACE_END,
265
+ ]) {
266
+ if (key.includes(reservedChar)) {
267
+ throw new Error(`"${reservedChar}" is a reserved character and is not allowed in node names.`);
268
+ }
269
+ }
270
+ this.warnIfCompiled(`Adding a node to a graph that has already been compiled. This will not be reflected in the compiled graph.`);
271
+ if (key in this.nodes) {
272
+ throw new Error(`Node \`${key}\` already present.`);
273
+ }
274
+ if (key === END || key === START) {
275
+ throw new Error(`Node \`${key}\` is reserved.`);
276
+ }
277
+ let inputSpec = this._schemaDefinition;
278
+ if (options?.input !== undefined) {
279
+ if (isAnyZodObject(options.input)) {
280
+ inputSpec = getChannelsFromZod(options.input);
281
+ }
282
+ else if (options.input.spec !== undefined) {
283
+ inputSpec = options.input.spec;
284
+ }
285
+ }
286
+ if (inputSpec !== undefined) {
287
+ this._addSchema(inputSpec);
288
+ }
289
+ let runnable;
290
+ if (Runnable.isRunnable(action)) {
291
+ runnable = action;
292
+ }
293
+ else if (typeof action === "function") {
294
+ runnable = new RunnableCallable({
295
+ func: action,
296
+ name: key,
297
+ trace: false,
298
+ });
299
+ }
300
+ else {
301
+ runnable = _coerceToRunnable(action);
302
+ }
303
+ const nodeSpec = {
304
+ runnable: runnable,
305
+ retryPolicy: options?.retryPolicy,
306
+ metadata: options?.metadata,
307
+ input: inputSpec ?? this._schemaDefinition,
308
+ subgraphs: isPregelLike(runnable)
309
+ ? // eslint-disable-next-line @typescript-eslint/no-explicit-any
310
+ [runnable]
311
+ : options?.subgraphs,
312
+ ends: options?.ends,
313
+ };
314
+ this.nodes[key] = nodeSpec;
257
315
  }
258
- this.warnIfCompiled(`Adding a node to a graph that has already been compiled. This will not be reflected in the compiled graph.`);
259
- if (key in this.nodes) {
260
- throw new Error(`Node \`${key}\` already present.`);
261
- }
262
- if (key === END || key === START) {
263
- throw new Error(`Node \`${key}\` is reserved.`);
264
- }
265
- if (options?.input !== undefined) {
266
- this._addSchema(options.input.spec);
267
- }
268
- let runnable;
269
- if (Runnable.isRunnable(action)) {
270
- runnable = action;
271
- }
272
- else if (typeof action === "function") {
273
- runnable = new RunnableCallable({
274
- func: action,
275
- name: key,
276
- trace: false,
277
- });
278
- }
279
- else {
280
- runnable = _coerceToRunnable(action);
281
- }
282
- const nodeSpec = {
283
- runnable: runnable,
284
- retryPolicy: options?.retryPolicy,
285
- metadata: options?.metadata,
286
- input: options?.input?.spec ?? this._schemaDefinition,
287
- subgraphs: isPregelLike(runnable)
288
- ? // eslint-disable-next-line @typescript-eslint/no-explicit-any
289
- [runnable]
290
- : options?.subgraphs,
291
- ends: options?.ends,
292
- };
293
- this.nodes[key] = nodeSpec;
294
316
  return this;
295
317
  }
296
318
  addEdge(startKey, endKey) {
@@ -318,6 +340,27 @@ export class StateGraph extends Graph {
318
340
  this.waitingEdges.add([startKey, endKey]);
319
341
  return this;
320
342
  }
343
+ addSequence(nodes) {
344
+ const parsedNodes = Array.isArray(nodes)
345
+ ? nodes
346
+ : Object.entries(nodes);
347
+ if (parsedNodes.length === 0) {
348
+ throw new Error("Sequence requires at least one node.");
349
+ }
350
+ let previousNode;
351
+ for (const [key, action, options] of parsedNodes) {
352
+ if (key in this.nodes) {
353
+ throw new Error(`Node names must be unique: node with the name "${key}" already exists.`);
354
+ }
355
+ const validKey = key;
356
+ this.addNode(validKey, action, options);
357
+ if (previousNode != null) {
358
+ this.addEdge(previousNode, validKey);
359
+ }
360
+ previousNode = validKey;
361
+ }
362
+ return this;
363
+ }
321
364
  compile({ checkpointer, store, interruptBefore, interruptAfter, name, } = {}) {
322
365
  // validate the graph
323
366
  this.validate([
@@ -503,15 +546,14 @@ export class CompiledStateGraph extends CompiledGraph {
503
546
  const inputDefinition = node?.input ?? this.builder._schemaDefinition;
504
547
  const inputValues = Object.fromEntries(Object.keys(this.builder._schemaDefinitions.get(inputDefinition)).map((k) => [k, k]));
505
548
  const isSingleInput = Object.keys(inputValues).length === 1 && ROOT in inputValues;
506
- this.channels[key] = new EphemeralValue(false);
549
+ const branchChannel = `branch:to:${key}`;
550
+ this.channels[branchChannel] = new EphemeralValue(false);
507
551
  this.nodes[key] = new PregelNode({
508
- triggers: [],
552
+ triggers: [branchChannel],
509
553
  // read state keys
510
554
  channels: isSingleInput ? Object.keys(inputValues) : inputValues,
511
- // publish to this channel and state keys
512
- writers: [
513
- new ChannelWrite(stateWriteEntries.concat({ channel: key, value: key }), [TAG_HIDDEN]),
514
- ],
555
+ // publish to state keys
556
+ writers: [new ChannelWrite(stateWriteEntries, [TAG_HIDDEN])],
515
557
  mapper: isSingleInput
516
558
  ? undefined
517
559
  : // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -527,10 +569,12 @@ export class CompiledStateGraph extends CompiledGraph {
527
569
  }
528
570
  }
529
571
  attachEdge(start, end) {
530
- if (end === END) {
572
+ if (end === END)
531
573
  return;
574
+ if (typeof start === "string") {
575
+ this.nodes[start].writers.push(new ChannelWrite([{ channel: `branch:to:${end}`, value: null }], [TAG_HIDDEN]));
532
576
  }
533
- if (Array.isArray(start)) {
577
+ else if (Array.isArray(start)) {
534
578
  const channelName = `join:${start.join("+")}:${end}`;
535
579
  // register channel
536
580
  this.channels[channelName] =
@@ -542,34 +586,16 @@ export class CompiledStateGraph extends CompiledGraph {
542
586
  this.nodes[s].writers.push(new ChannelWrite([{ channel: channelName, value: s }], [TAG_HIDDEN]));
543
587
  }
544
588
  }
545
- else if (start === START) {
546
- const channelName = `${START}:${end}`;
547
- // register channel
548
- this.channels[channelName] =
549
- new EphemeralValue();
550
- // subscribe to channel
551
- this.nodes[end].triggers.push(channelName);
552
- // publish to channel
553
- this.nodes[START].writers.push(new ChannelWrite([{ channel: channelName, value: START }], [TAG_HIDDEN]));
554
- }
555
- else {
556
- this.nodes[end].triggers.push(start);
557
- }
558
589
  }
559
- attachBranch(start, name, branch, options = { withReader: true }) {
590
+ attachBranch(start, _, branch, options = { withReader: true }) {
560
591
  const branchWriter = async (packets, config) => {
561
592
  const filteredPackets = packets.filter((p) => p !== END);
562
- if (!filteredPackets.length) {
593
+ if (!filteredPackets.length)
563
594
  return;
564
- }
565
595
  const writes = filteredPackets.map((p) => {
566
- if (_isSend(p)) {
596
+ if (_isSend(p))
567
597
  return p;
568
- }
569
- return {
570
- channel: `branch:${start}:${name}:${p}`,
571
- value: start,
572
- };
598
+ return { channel: `branch:to:${p}`, value: start };
573
599
  });
574
600
  await ChannelWrite.doWrite({ ...config, tags: (config.tags ?? []).concat([TAG_HIDDEN]) }, writes);
575
601
  };
@@ -579,19 +605,6 @@ export class CompiledStateGraph extends CompiledGraph {
579
605
  options.withReader
580
606
  ? (config) => ChannelRead.doRead(config, this.streamChannels ?? this.outputChannels, true)
581
607
  : undefined));
582
- // attach branch subscribers
583
- const ends = branch.ends
584
- ? Object.values(branch.ends)
585
- : Object.keys(this.builder.nodes);
586
- for (const end of ends) {
587
- if (end === END) {
588
- continue;
589
- }
590
- const channelName = `branch:${start}:${name}:${end}`;
591
- this.channels[channelName] =
592
- new EphemeralValue(false);
593
- this.nodes[end].triggers.push(channelName);
594
- }
595
608
  }
596
609
  async _validateInput(input) {
597
610
  const inputSchema = this.builder._inputRuntimeDefinition;