@langchain/langgraph 0.0.34 → 0.1.0-rc.1

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 (86) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +11 -15
  3. package/dist/channels/any_value.cjs +3 -1
  4. package/dist/channels/any_value.d.ts +1 -1
  5. package/dist/channels/any_value.js +3 -1
  6. package/dist/channels/base.cjs +28 -15
  7. package/dist/channels/base.d.ts +14 -4
  8. package/dist/channels/base.js +26 -13
  9. package/dist/channels/binop.cjs +2 -1
  10. package/dist/channels/binop.d.ts +1 -1
  11. package/dist/channels/binop.js +2 -1
  12. package/dist/channels/dynamic_barrier_value.cjs +30 -18
  13. package/dist/channels/dynamic_barrier_value.d.ts +2 -1
  14. package/dist/channels/dynamic_barrier_value.js +30 -18
  15. package/dist/channels/ephemeral_value.cjs +3 -1
  16. package/dist/channels/ephemeral_value.d.ts +1 -1
  17. package/dist/channels/ephemeral_value.js +3 -1
  18. package/dist/channels/last_value.cjs +3 -2
  19. package/dist/channels/last_value.d.ts +1 -1
  20. package/dist/channels/last_value.js +3 -2
  21. package/dist/channels/named_barrier_value.cjs +14 -6
  22. package/dist/channels/named_barrier_value.d.ts +2 -1
  23. package/dist/channels/named_barrier_value.js +15 -7
  24. package/dist/channels/topic.cjs +10 -11
  25. package/dist/channels/topic.d.ts +1 -1
  26. package/dist/channels/topic.js +10 -11
  27. package/dist/checkpoint/sqlite.cjs +14 -170
  28. package/dist/checkpoint/sqlite.d.ts +1 -14
  29. package/dist/checkpoint/sqlite.js +1 -166
  30. package/dist/constants.cjs +17 -1
  31. package/dist/constants.d.ts +7 -0
  32. package/dist/constants.js +16 -0
  33. package/dist/errors.cjs +21 -1
  34. package/dist/errors.d.ts +8 -0
  35. package/dist/errors.js +18 -0
  36. package/dist/graph/graph.cjs +6 -3
  37. package/dist/graph/graph.d.ts +7 -3
  38. package/dist/graph/graph.js +7 -4
  39. package/dist/graph/index.d.ts +1 -1
  40. package/dist/graph/state.cjs +9 -8
  41. package/dist/graph/state.d.ts +1 -1
  42. package/dist/graph/state.js +9 -8
  43. package/dist/prebuilt/react_agent_executor.d.ts +1 -1
  44. package/dist/pregel/algo.cjs +391 -0
  45. package/dist/pregel/algo.d.ts +35 -0
  46. package/dist/pregel/algo.js +381 -0
  47. package/dist/pregel/debug.cjs +155 -9
  48. package/dist/pregel/debug.d.ts +40 -2
  49. package/dist/pregel/debug.js +147 -7
  50. package/dist/pregel/index.cjs +286 -512
  51. package/dist/pregel/index.d.ts +66 -65
  52. package/dist/pregel/index.js +285 -506
  53. package/dist/pregel/io.cjs +2 -2
  54. package/dist/pregel/io.d.ts +5 -4
  55. package/dist/pregel/io.js +2 -2
  56. package/dist/pregel/loop.cjs +432 -0
  57. package/dist/pregel/loop.d.ts +83 -0
  58. package/dist/pregel/loop.js +425 -0
  59. package/dist/pregel/types.d.ts +56 -4
  60. package/dist/pregel/utils.cjs +48 -0
  61. package/dist/pregel/utils.d.ts +10 -0
  62. package/dist/pregel/utils.js +41 -0
  63. package/dist/pregel/write.cjs +3 -1
  64. package/dist/pregel/write.js +3 -1
  65. package/dist/utils.cjs +21 -1
  66. package/dist/utils.d.ts +4 -0
  67. package/dist/utils.js +18 -0
  68. package/dist/web.cjs +6 -7
  69. package/dist/web.d.ts +2 -4
  70. package/dist/web.js +1 -2
  71. package/package.json +6 -12
  72. package/dist/checkpoint/base.cjs +0 -66
  73. package/dist/checkpoint/base.d.ts +0 -73
  74. package/dist/checkpoint/base.js +0 -57
  75. package/dist/checkpoint/id.cjs +0 -8
  76. package/dist/checkpoint/id.d.ts +0 -1
  77. package/dist/checkpoint/id.js +0 -4
  78. package/dist/checkpoint/index.cjs +0 -9
  79. package/dist/checkpoint/index.d.ts +0 -2
  80. package/dist/checkpoint/index.js +0 -2
  81. package/dist/checkpoint/memory.cjs +0 -82
  82. package/dist/checkpoint/memory.d.ts +0 -10
  83. package/dist/checkpoint/memory.js +0 -78
  84. package/dist/serde/base.cjs +0 -8
  85. package/dist/serde/base.d.ts +0 -12
  86. package/dist/serde/base.js +0 -5
@@ -115,6 +115,9 @@ class Graph {
115
115
  return this.edges;
116
116
  }
117
117
  addNode(key, action) {
118
+ if (key.includes(constants_js_1.CHECKPOINT_NAMESPACE_SEPARATOR)) {
119
+ throw new Error(`"${constants_js_1.CHECKPOINT_NAMESPACE_SEPARATOR}" is a reserved character and is not allowed in node names.`);
120
+ }
118
121
  this.warnIfCompiled(`Adding a node to a graph that has already been compiled. This will not be reflected in the compiled graph.`);
119
122
  if (key in this.nodes) {
120
123
  throw new Error(`Node \`${key}\` already present.`);
@@ -137,7 +140,7 @@ class Graph {
137
140
  }
138
141
  if (!this.supportMultipleEdges &&
139
142
  Array.from(this.edges).some(([start]) => start === startKey)) {
140
- throw new Error(`Already found path for ${startKey}`);
143
+ throw new Error(`Already found path for ${startKey}. For multiple edges, use StateGraph with an annotated state key.`);
141
144
  }
142
145
  this.edges.add([startKey, endKey]);
143
146
  return this;
@@ -190,8 +193,8 @@ class Graph {
190
193
  [exports.START]: new ephemeral_value_js_1.EphemeralValue(),
191
194
  [exports.END]: new ephemeral_value_js_1.EphemeralValue(),
192
195
  },
193
- inputs: exports.START,
194
- outputs: exports.END,
196
+ inputChannels: exports.START,
197
+ outputChannels: exports.END,
195
198
  streamChannels: [],
196
199
  streamMode: "values",
197
200
  });
@@ -1,8 +1,9 @@
1
1
  import { Runnable, RunnableConfig, RunnableLike } from "@langchain/core/runnables";
2
2
  import { Graph as RunnableGraph } from "@langchain/core/runnables/graph";
3
+ import { BaseCheckpointSaver } from "@langchain/langgraph-checkpoint";
3
4
  import { PregelNode } from "../pregel/read.js";
4
- import { Pregel, PregelInterface } from "../pregel/index.js";
5
- import { BaseCheckpointSaver } from "../checkpoint/base.js";
5
+ import { Pregel } from "../pregel/index.js";
6
+ import type { PregelParams } from "../pregel/types.js";
6
7
  import { BaseChannel } from "../channels/base.js";
7
8
  import { All } from "../pregel/types.js";
8
9
  import { Send } from "../constants.js";
@@ -51,10 +52,13 @@ export declare class Graph<N extends string = typeof END, RunInput = any, RunOut
51
52
  validate(interrupt?: string[]): void;
52
53
  }
53
54
  export declare class CompiledGraph<N extends string, RunInput = any, RunOutput = any> extends Pregel<Record<N | typeof START, PregelNode<RunInput, RunOutput>>, Record<N | typeof START | typeof END | string, BaseChannel>> {
55
+ NodeType: N;
56
+ RunInput: RunInput;
57
+ RunOutput: RunOutput;
54
58
  builder: Graph<N, RunInput, RunOutput>;
55
59
  constructor({ builder, ...rest }: {
56
60
  builder: Graph<N, RunInput, RunOutput>;
57
- } & PregelInterface<Record<N | typeof START, PregelNode<RunInput, RunOutput>>, Record<N | typeof START | typeof END | string, BaseChannel>>);
61
+ } & PregelParams<Record<N | typeof START, PregelNode<RunInput, RunOutput>>, Record<N | typeof START | typeof END | string, BaseChannel>>);
58
62
  attachNode(key: N, node: Runnable<RunInput, RunOutput>): void;
59
63
  attachEdge(start: N | typeof START, end: N | typeof END): void;
60
64
  attachBranch(start: N | typeof START, name: string, branch: Branch<RunInput, N>): void;
@@ -6,7 +6,7 @@ import { PregelNode } from "../pregel/read.js";
6
6
  import { Channel, Pregel } from "../pregel/index.js";
7
7
  import { EphemeralValue } from "../channels/ephemeral_value.js";
8
8
  import { ChannelWrite, PASSTHROUGH } from "../pregel/write.js";
9
- import { _isSend, TAG_HIDDEN } from "../constants.js";
9
+ import { _isSend, CHECKPOINT_NAMESPACE_SEPARATOR, TAG_HIDDEN, } from "../constants.js";
10
10
  import { RunnableCallable } from "../utils.js";
11
11
  import { InvalidUpdateError } from "../errors.js";
12
12
  export const START = "__start__";
@@ -111,6 +111,9 @@ export class Graph {
111
111
  return this.edges;
112
112
  }
113
113
  addNode(key, action) {
114
+ if (key.includes(CHECKPOINT_NAMESPACE_SEPARATOR)) {
115
+ throw new Error(`"${CHECKPOINT_NAMESPACE_SEPARATOR}" is a reserved character and is not allowed in node names.`);
116
+ }
114
117
  this.warnIfCompiled(`Adding a node to a graph that has already been compiled. This will not be reflected in the compiled graph.`);
115
118
  if (key in this.nodes) {
116
119
  throw new Error(`Node \`${key}\` already present.`);
@@ -133,7 +136,7 @@ export class Graph {
133
136
  }
134
137
  if (!this.supportMultipleEdges &&
135
138
  Array.from(this.edges).some(([start]) => start === startKey)) {
136
- throw new Error(`Already found path for ${startKey}`);
139
+ throw new Error(`Already found path for ${startKey}. For multiple edges, use StateGraph with an annotated state key.`);
137
140
  }
138
141
  this.edges.add([startKey, endKey]);
139
142
  return this;
@@ -186,8 +189,8 @@ export class Graph {
186
189
  [START]: new EphemeralValue(),
187
190
  [END]: new EphemeralValue(),
188
191
  },
189
- inputs: START,
190
- outputs: END,
192
+ inputChannels: START,
193
+ outputChannels: END,
191
194
  streamChannels: [],
192
195
  streamMode: "values",
193
196
  });
@@ -1,4 +1,4 @@
1
1
  export { Annotation, type StateType, type UpdateType } from "./annotation.js";
2
- export { END, START, Graph } from "./graph.js";
2
+ export { END, START, Graph, type CompiledGraph } from "./graph.js";
3
3
  export { type StateGraphArgs, StateGraph, type CompiledStateGraph, } from "./state.js";
4
4
  export { MessageGraph, messagesStateReducer } from "./message.js";
@@ -74,14 +74,14 @@ class StateGraph extends graph_js_1.Graph {
74
74
  throw new Error("END cannot be a start node");
75
75
  }
76
76
  if (!Object.keys(this.nodes).some((node) => node === start)) {
77
- throw new Error(`Need to add_node ${start} first`);
77
+ throw new Error(`Need to addNode ${start} first`);
78
78
  }
79
79
  }
80
80
  if (endKey === graph_js_1.END) {
81
81
  throw new Error("END cannot be an end node");
82
82
  }
83
83
  if (!Object.keys(this.nodes).some((node) => node === endKey)) {
84
- throw new Error(`Need to add_node ${endKey} first`);
84
+ throw new Error(`Need to addNode ${endKey} first`);
85
85
  }
86
86
  this.waitingEdges.add([startKey, endKey]);
87
87
  return this;
@@ -94,7 +94,7 @@ class StateGraph extends graph_js_1.Graph {
94
94
  ]);
95
95
  // prepare output channels
96
96
  const stateKeys = Object.keys(this.channels);
97
- const outputs = stateKeys.length === 1 && stateKeys[0] === ROOT
97
+ const outputChannels = stateKeys.length === 1 && stateKeys[0] === ROOT
98
98
  ? stateKeys[0]
99
99
  : stateKeys;
100
100
  // create empty compiled graph
@@ -109,9 +109,9 @@ class StateGraph extends graph_js_1.Graph {
109
109
  ...this.channels,
110
110
  [graph_js_1.START]: new ephemeral_value_js_1.EphemeralValue(),
111
111
  },
112
- inputs: graph_js_1.START,
113
- outputs,
114
- streamChannels: outputs,
112
+ inputChannels: graph_js_1.START,
113
+ outputChannels,
114
+ streamChannels: outputChannels,
115
115
  streamMode: "updates",
116
116
  });
117
117
  // attach nodes, edges and branches
@@ -155,7 +155,8 @@ class CompiledStateGraph extends graph_js_1.CompiledGraph {
155
155
  return write_js_1.SKIP_WRITE;
156
156
  }
157
157
  else if (typeof input !== "object" || Array.isArray(input)) {
158
- throw new errors_js_1.InvalidUpdateError(`Expected dict, got ${typeof input}`);
158
+ const typeofInput = Array.isArray(input) ? "array" : typeof input;
159
+ throw new errors_js_1.InvalidUpdateError(`Expected object, got ${typeofInput}`);
159
160
  }
160
161
  else {
161
162
  return key in input ? input[key] : write_js_1.SKIP_WRITE;
@@ -252,7 +253,7 @@ class CompiledStateGraph extends graph_js_1.CompiledGraph {
252
253
  return new write_js_1.ChannelWrite(writes, [constants_js_1.TAG_HIDDEN]);
253
254
  },
254
255
  // reader
255
- (config) => read_js_1.ChannelRead.doRead(config, this.outputs, true)));
256
+ (config) => read_js_1.ChannelRead.doRead(config, this.outputChannels, true)));
256
257
  // attach branch subscribers
257
258
  const ends = branch.ends
258
259
  ? Object.values(branch.ends)
@@ -1,7 +1,7 @@
1
1
  import { Runnable, RunnableConfig, RunnableLike } from "@langchain/core/runnables";
2
+ import { BaseCheckpointSaver } from "@langchain/langgraph-checkpoint";
2
3
  import { BaseChannel } from "../channels/base.js";
3
4
  import { END, CompiledGraph, Graph, START, Branch } from "./graph.js";
4
- import { BaseCheckpointSaver } from "../checkpoint/base.js";
5
5
  import { All } from "../pregel/types.js";
6
6
  import { AnnotationRoot, SingleReducer, StateDefinition, StateType, UpdateType } from "./annotation.js";
7
7
  export type ChannelReducers<Channels extends object> = {
@@ -71,14 +71,14 @@ export class StateGraph extends Graph {
71
71
  throw new Error("END cannot be a start node");
72
72
  }
73
73
  if (!Object.keys(this.nodes).some((node) => node === start)) {
74
- throw new Error(`Need to add_node ${start} first`);
74
+ throw new Error(`Need to addNode ${start} first`);
75
75
  }
76
76
  }
77
77
  if (endKey === END) {
78
78
  throw new Error("END cannot be an end node");
79
79
  }
80
80
  if (!Object.keys(this.nodes).some((node) => node === endKey)) {
81
- throw new Error(`Need to add_node ${endKey} first`);
81
+ throw new Error(`Need to addNode ${endKey} first`);
82
82
  }
83
83
  this.waitingEdges.add([startKey, endKey]);
84
84
  return this;
@@ -91,7 +91,7 @@ export class StateGraph extends Graph {
91
91
  ]);
92
92
  // prepare output channels
93
93
  const stateKeys = Object.keys(this.channels);
94
- const outputs = stateKeys.length === 1 && stateKeys[0] === ROOT
94
+ const outputChannels = stateKeys.length === 1 && stateKeys[0] === ROOT
95
95
  ? stateKeys[0]
96
96
  : stateKeys;
97
97
  // create empty compiled graph
@@ -106,9 +106,9 @@ export class StateGraph extends Graph {
106
106
  ...this.channels,
107
107
  [START]: new EphemeralValue(),
108
108
  },
109
- inputs: START,
110
- outputs,
111
- streamChannels: outputs,
109
+ inputChannels: START,
110
+ outputChannels,
111
+ streamChannels: outputChannels,
112
112
  streamMode: "updates",
113
113
  });
114
114
  // attach nodes, edges and branches
@@ -151,7 +151,8 @@ export class CompiledStateGraph extends CompiledGraph {
151
151
  return SKIP_WRITE;
152
152
  }
153
153
  else if (typeof input !== "object" || Array.isArray(input)) {
154
- throw new InvalidUpdateError(`Expected dict, got ${typeof input}`);
154
+ const typeofInput = Array.isArray(input) ? "array" : typeof input;
155
+ throw new InvalidUpdateError(`Expected object, got ${typeofInput}`);
155
156
  }
156
157
  else {
157
158
  return key in input ? input[key] : SKIP_WRITE;
@@ -248,7 +249,7 @@ export class CompiledStateGraph extends CompiledGraph {
248
249
  return new ChannelWrite(writes, [TAG_HIDDEN]);
249
250
  },
250
251
  // reader
251
- (config) => ChannelRead.doRead(config, this.outputs, true)));
252
+ (config) => ChannelRead.doRead(config, this.outputChannels, true)));
252
253
  // attach branch subscribers
253
254
  const ends = branch.ends
254
255
  ? Object.values(branch.ends)
@@ -2,7 +2,7 @@ import { BaseChatModel } from "@langchain/core/language_models/chat_models";
2
2
  import { BaseMessage, SystemMessage } from "@langchain/core/messages";
3
3
  import { Runnable, RunnableToolLike } from "@langchain/core/runnables";
4
4
  import { StructuredToolInterface } from "@langchain/core/tools";
5
- import { BaseCheckpointSaver } from "../checkpoint/base.js";
5
+ import { BaseCheckpointSaver } from "@langchain/langgraph-checkpoint";
6
6
  import { START } from "../graph/index.js";
7
7
  import { MessagesState } from "../graph/message.js";
8
8
  import { CompiledStateGraph } from "../graph/state.js";
@@ -0,0 +1,391 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports._prepareNextTasks = exports._applyWrites = exports._localWrite = exports._localRead = exports.shouldInterrupt = exports.executeTasks = exports.increment = void 0;
4
+ /* eslint-disable no-param-reassign */
5
+ const runnables_1 = require("@langchain/core/runnables");
6
+ const langgraph_checkpoint_1 = require("@langchain/langgraph-checkpoint");
7
+ const base_js_1 = require("../channels/base.cjs");
8
+ const io_js_1 = require("./io.cjs");
9
+ const constants_js_1 = require("../constants.cjs");
10
+ const errors_js_1 = require("../errors.cjs");
11
+ const utils_js_1 = require("./utils.cjs");
12
+ const increment = (current) => {
13
+ return current !== undefined ? current + 1 : 1;
14
+ };
15
+ exports.increment = increment;
16
+ async function* executeTasks(tasks, stepTimeout, signal
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
+ ) {
19
+ if (stepTimeout && signal) {
20
+ if ("any" in AbortSignal) {
21
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
+ signal = AbortSignal.any([
23
+ signal,
24
+ AbortSignal.timeout(stepTimeout),
25
+ ]);
26
+ }
27
+ }
28
+ else if (stepTimeout) {
29
+ signal = AbortSignal.timeout(stepTimeout);
30
+ }
31
+ // Abort if signal is aborted
32
+ signal?.throwIfAborted();
33
+ // Start all tasks
34
+ const executingTasks = Object.fromEntries(Object.entries(tasks).map(([taskId, task]) => {
35
+ return [taskId, task()];
36
+ }));
37
+ let listener;
38
+ const signalPromise = new Promise((_resolve, reject) => {
39
+ listener = () => reject(new Error("Abort"));
40
+ signal?.addEventListener("abort", listener);
41
+ }).finally(() => signal?.removeEventListener("abort", listener));
42
+ while (Object.keys(executingTasks).length > 0) {
43
+ const { task, error } = await Promise.race([
44
+ ...Object.values(executingTasks),
45
+ signalPromise,
46
+ ]);
47
+ if (error !== undefined) {
48
+ // TODO: don't stop others if exception is interrupt
49
+ throw error;
50
+ }
51
+ yield task;
52
+ delete executingTasks[task.id];
53
+ }
54
+ }
55
+ exports.executeTasks = executeTasks;
56
+ function shouldInterrupt(checkpoint, interruptNodes, tasks) {
57
+ const versionValues = Object.values(checkpoint.channel_versions);
58
+ const versionType = versionValues.length > 0 ? typeof versionValues[0] : undefined;
59
+ let nullVersion;
60
+ if (versionType === "number") {
61
+ nullVersion = 0;
62
+ }
63
+ else if (versionType === "string") {
64
+ nullVersion = "";
65
+ }
66
+ const seen = checkpoint.versions_seen[constants_js_1.INTERRUPT] ?? {};
67
+ const anyChannelUpdated = Object.entries(checkpoint.channel_versions).some(([chan, version]) => {
68
+ return version > (seen[chan] ?? nullVersion);
69
+ });
70
+ const anyTriggeredNodeInInterruptNodes = tasks.some((task) => interruptNodes === "*"
71
+ ? !task.config?.tags?.includes(constants_js_1.TAG_HIDDEN)
72
+ : interruptNodes.includes(task.name));
73
+ return anyChannelUpdated && anyTriggeredNodeInInterruptNodes;
74
+ }
75
+ exports.shouldInterrupt = shouldInterrupt;
76
+ function _localRead(checkpoint, channels, task, select, fresh = false) {
77
+ if (fresh) {
78
+ const newCheckpoint = (0, base_js_1.createCheckpoint)(checkpoint, channels, -1);
79
+ // create a new copy of channels
80
+ const newChannels = (0, base_js_1.emptyChannels)(channels, newCheckpoint);
81
+ // Note: _applyWrites contains side effects
82
+ _applyWrites((0, langgraph_checkpoint_1.copyCheckpoint)(newCheckpoint), newChannels, [task]);
83
+ return (0, io_js_1.readChannels)(newChannels, select);
84
+ }
85
+ else {
86
+ return (0, io_js_1.readChannels)(channels, select);
87
+ }
88
+ }
89
+ exports._localRead = _localRead;
90
+ function _localWrite(
91
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
92
+ commit, processes, channels,
93
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
94
+ writes) {
95
+ for (const [chan, value] of writes) {
96
+ if (chan === constants_js_1.TASKS) {
97
+ if (!(0, constants_js_1._isSend)(value)) {
98
+ throw new errors_js_1.InvalidUpdateError(`Invalid packet type, expected SendProtocol, got ${JSON.stringify(value)}`);
99
+ }
100
+ if (!(value.node in processes)) {
101
+ throw new errors_js_1.InvalidUpdateError(`Invalid node name ${value.node} in packet`);
102
+ }
103
+ }
104
+ else if (!(chan in channels)) {
105
+ console.warn(`Skipping write for channel '${chan}' which has no readers`);
106
+ }
107
+ }
108
+ commit(writes);
109
+ }
110
+ exports._localWrite = _localWrite;
111
+ function _applyWrites(checkpoint, channels, tasks,
112
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
113
+ getNextVersion) {
114
+ // Update seen versions
115
+ for (const task of tasks) {
116
+ if (checkpoint.versions_seen[task.name] === undefined) {
117
+ checkpoint.versions_seen[task.name] = {};
118
+ }
119
+ for (const chan of task.triggers) {
120
+ if (chan in checkpoint.channel_versions) {
121
+ checkpoint.versions_seen[task.name][chan] =
122
+ checkpoint.channel_versions[chan];
123
+ }
124
+ }
125
+ }
126
+ // Find the highest version of all channels
127
+ let maxVersion;
128
+ if (Object.keys(checkpoint.channel_versions).length > 0) {
129
+ maxVersion = Math.max(...Object.values(checkpoint.channel_versions));
130
+ }
131
+ // Consume all channels that were read
132
+ const channelsToConsume = new Set(tasks
133
+ .flatMap((task) => task.triggers)
134
+ .filter((chan) => !constants_js_1.RESERVED.includes(chan)));
135
+ for (const chan of channelsToConsume) {
136
+ if (channels[chan].consume()) {
137
+ if (getNextVersion !== undefined) {
138
+ checkpoint.channel_versions[chan] = getNextVersion(maxVersion, channels[chan]);
139
+ }
140
+ }
141
+ }
142
+ // Clear pending sends
143
+ if (checkpoint.pending_sends) {
144
+ checkpoint.pending_sends = [];
145
+ }
146
+ // Group writes by channel
147
+ const pendingWriteValuesByChannel = {};
148
+ for (const task of tasks) {
149
+ for (const [chan, val] of task.writes) {
150
+ if (chan === constants_js_1.TASKS) {
151
+ checkpoint.pending_sends.push({
152
+ node: val.node,
153
+ args: val.args,
154
+ });
155
+ }
156
+ else {
157
+ if (chan in pendingWriteValuesByChannel) {
158
+ pendingWriteValuesByChannel[chan].push(val);
159
+ }
160
+ else {
161
+ pendingWriteValuesByChannel[chan] = [val];
162
+ }
163
+ }
164
+ }
165
+ }
166
+ // find the highest version of all channels
167
+ maxVersion = undefined;
168
+ if (Object.keys(checkpoint.channel_versions).length > 0) {
169
+ maxVersion = Math.max(...Object.values(checkpoint.channel_versions));
170
+ }
171
+ const updatedChannels = new Set();
172
+ // Apply writes to channels
173
+ for (const [chan, vals] of Object.entries(pendingWriteValuesByChannel)) {
174
+ if (chan in channels) {
175
+ let updated;
176
+ try {
177
+ updated = channels[chan].update(vals);
178
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
179
+ }
180
+ catch (e) {
181
+ if (e.name === errors_js_1.InvalidUpdateError.unminifiable_name) {
182
+ throw new errors_js_1.InvalidUpdateError(`Invalid update for channel ${chan} with values ${JSON.stringify(vals)}`);
183
+ }
184
+ else {
185
+ throw e;
186
+ }
187
+ }
188
+ if (updated && getNextVersion !== undefined) {
189
+ checkpoint.channel_versions[chan] = getNextVersion(maxVersion, channels[chan]);
190
+ }
191
+ updatedChannels.add(chan);
192
+ }
193
+ }
194
+ // Channels that weren't updated in this step are notified of a new step
195
+ for (const chan of Object.keys(channels)) {
196
+ if (!updatedChannels.has(chan)) {
197
+ const updated = channels[chan].update([]);
198
+ if (updated && getNextVersion !== undefined) {
199
+ checkpoint.channel_versions[chan] = getNextVersion(maxVersion, channels[chan]);
200
+ }
201
+ }
202
+ }
203
+ }
204
+ exports._applyWrites = _applyWrites;
205
+ function _prepareNextTasks(checkpoint, processes, channels, config, forExecution, extra) {
206
+ const parentNamespace = config.configurable?.checkpoint_ns ?? "";
207
+ const tasks = [];
208
+ const taskDescriptions = [];
209
+ const { step, isResuming = false, checkpointer, manager } = extra;
210
+ for (const packet of checkpoint.pending_sends) {
211
+ if (!(0, constants_js_1._isSendInterface)(packet)) {
212
+ console.warn(`Ignoring invalid packet ${JSON.stringify(packet)} in pending sends.`);
213
+ continue;
214
+ }
215
+ if (!(packet.node in processes)) {
216
+ console.warn(`Ignoring unknown node name ${packet.node} in pending sends.`);
217
+ continue;
218
+ }
219
+ const triggers = [constants_js_1.TASKS];
220
+ const metadata = (0, utils_js_1._getIdMetadata)({
221
+ langgraph_step: step,
222
+ langgraph_node: packet.node,
223
+ langgraph_triggers: triggers,
224
+ langgraph_task_idx: forExecution ? tasks.length : taskDescriptions.length,
225
+ });
226
+ const checkpointNamespace = parentNamespace === ""
227
+ ? packet.node
228
+ : `${parentNamespace}${constants_js_1.CHECKPOINT_NAMESPACE_SEPARATOR}${packet.node}`;
229
+ const taskId = (0, langgraph_checkpoint_1.uuid5)(JSON.stringify([checkpointNamespace, metadata]), checkpoint.id);
230
+ if (forExecution) {
231
+ const proc = processes[packet.node];
232
+ const node = proc.getNode();
233
+ if (node !== undefined) {
234
+ const writes = [];
235
+ tasks.push({
236
+ name: packet.node,
237
+ input: packet.args,
238
+ proc: node,
239
+ writes,
240
+ triggers,
241
+ config: (0, runnables_1.patchConfig)((0, runnables_1.mergeConfigs)(config, processes[packet.node].config, {
242
+ metadata,
243
+ }), {
244
+ runName: packet.node,
245
+ callbacks: manager?.getChild(`graph:step:${step}`),
246
+ configurable: {
247
+ [constants_js_1.CONFIG_KEY_SEND]: _localWrite.bind(undefined, (items) => writes.push(...items), processes, channels),
248
+ [constants_js_1.CONFIG_KEY_READ]: _localRead.bind(undefined, checkpoint, channels, {
249
+ name: packet.node,
250
+ writes: writes,
251
+ triggers,
252
+ }),
253
+ },
254
+ }),
255
+ id: taskId,
256
+ });
257
+ }
258
+ }
259
+ else {
260
+ taskDescriptions.push({ id: taskId, name: packet.node });
261
+ }
262
+ }
263
+ // Check if any processes should be run in next step
264
+ // If so, prepare the values to be passed to them
265
+ const nullVersion = (0, utils_js_1.getNullChannelVersion)(checkpoint.channel_versions);
266
+ if (nullVersion === undefined) {
267
+ return forExecution ? tasks : taskDescriptions;
268
+ }
269
+ for (const [name, proc] of Object.entries(processes)) {
270
+ const seen = checkpoint.versions_seen[name] ?? {};
271
+ const triggers = proc.triggers
272
+ .filter((chan) => {
273
+ const result = (0, io_js_1.readChannel)(channels, chan, false, true);
274
+ const isEmptyChannelError =
275
+ // eslint-disable-next-line no-instanceof/no-instanceof
276
+ result instanceof Error &&
277
+ result.name === errors_js_1.EmptyChannelError.unminifiable_name;
278
+ return (!isEmptyChannelError &&
279
+ (checkpoint.channel_versions[chan] ?? nullVersion) >
280
+ (seen[chan] ?? nullVersion));
281
+ })
282
+ .sort();
283
+ // If any of the channels read by this process were updated
284
+ if (triggers.length > 0) {
285
+ const val = _procInput(proc, channels, forExecution);
286
+ if (val === undefined) {
287
+ continue;
288
+ }
289
+ const metadata = (0, utils_js_1._getIdMetadata)({
290
+ langgraph_step: step,
291
+ langgraph_node: name,
292
+ langgraph_triggers: triggers,
293
+ langgraph_task_idx: forExecution
294
+ ? tasks.length
295
+ : taskDescriptions.length,
296
+ });
297
+ const checkpointNamespace = parentNamespace === ""
298
+ ? name
299
+ : `${parentNamespace}${constants_js_1.CHECKPOINT_NAMESPACE_SEPARATOR}${name}`;
300
+ const taskId = (0, langgraph_checkpoint_1.uuid5)(JSON.stringify([checkpointNamespace, metadata]), checkpoint.id);
301
+ if (forExecution) {
302
+ const node = proc.getNode();
303
+ if (node !== undefined) {
304
+ const writes = [];
305
+ tasks.push({
306
+ name,
307
+ input: val,
308
+ proc: node,
309
+ writes,
310
+ triggers,
311
+ config: (0, runnables_1.patchConfig)((0, runnables_1.mergeConfigs)(config, proc.config, { metadata }), {
312
+ runName: name,
313
+ callbacks: manager?.getChild(`graph:step:${step}`),
314
+ configurable: {
315
+ [constants_js_1.CONFIG_KEY_SEND]: _localWrite.bind(undefined, (items) => writes.push(...items), processes, channels),
316
+ [constants_js_1.CONFIG_KEY_READ]: _localRead.bind(undefined, checkpoint, channels, {
317
+ name,
318
+ writes: writes,
319
+ triggers,
320
+ }),
321
+ [constants_js_1.CONFIG_KEY_CHECKPOINTER]: checkpointer,
322
+ [constants_js_1.CONFIG_KEY_RESUMING]: isResuming,
323
+ checkpoint_id: checkpoint.id,
324
+ checkpoint_ns: checkpointNamespace,
325
+ },
326
+ }),
327
+ id: taskId,
328
+ });
329
+ }
330
+ }
331
+ else {
332
+ taskDescriptions.push({ id: taskId, name });
333
+ }
334
+ }
335
+ }
336
+ return forExecution ? tasks : taskDescriptions;
337
+ }
338
+ exports._prepareNextTasks = _prepareNextTasks;
339
+ function _procInput(proc, channels, forExecution) {
340
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
341
+ let val;
342
+ // If all trigger channels subscribed by this process are not empty
343
+ // then invoke the process with the values of all non-empty channels
344
+ if (Array.isArray(proc.channels)) {
345
+ let successfulRead = false;
346
+ for (const chan of proc.channels) {
347
+ try {
348
+ val = (0, io_js_1.readChannel)(channels, chan, false);
349
+ successfulRead = true;
350
+ break;
351
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
352
+ }
353
+ catch (e) {
354
+ if (e.name === errors_js_1.EmptyChannelError.unminifiable_name) {
355
+ continue;
356
+ }
357
+ else {
358
+ throw e;
359
+ }
360
+ }
361
+ }
362
+ if (!successfulRead) {
363
+ return;
364
+ }
365
+ }
366
+ else if (typeof proc.channels === "object") {
367
+ val = {};
368
+ try {
369
+ for (const [k, chan] of Object.entries(proc.channels)) {
370
+ val[k] = (0, io_js_1.readChannel)(channels, chan, !proc.triggers.includes(chan));
371
+ }
372
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
373
+ }
374
+ catch (e) {
375
+ if (e.name === errors_js_1.EmptyChannelError.unminifiable_name) {
376
+ return;
377
+ }
378
+ else {
379
+ throw e;
380
+ }
381
+ }
382
+ }
383
+ else {
384
+ throw new Error(`Invalid channels type, expected list or dict, got ${proc.channels}`);
385
+ }
386
+ // If the process has a mapper, apply it to the value
387
+ if (forExecution && proc.mapper !== undefined) {
388
+ val = proc.mapper(val);
389
+ }
390
+ return val;
391
+ }
@@ -0,0 +1,35 @@
1
+ import { RunnableConfig } from "@langchain/core/runnables";
2
+ import { CallbackManagerForChainRun } from "@langchain/core/callbacks/manager";
3
+ import { BaseCheckpointSaver, Checkpoint, ReadonlyCheckpoint, type PendingWrite } from "@langchain/langgraph-checkpoint";
4
+ import { BaseChannel } from "../channels/base.js";
5
+ import { PregelNode } from "./read.js";
6
+ import { All, PregelExecutableTask, PregelTaskDescription } from "./types.js";
7
+ /**
8
+ * Construct a type with a set of properties K of type T
9
+ */
10
+ export type StrRecord<K extends string, T> = {
11
+ [P in K]: T;
12
+ };
13
+ export type WritesProtocol<C = string> = {
14
+ name: string;
15
+ writes: PendingWrite<C>[];
16
+ triggers: string[];
17
+ };
18
+ export declare const increment: (current?: number) => number;
19
+ export declare function executeTasks(tasks: Record<string, () => Promise<{
20
+ task: PregelExecutableTask<any, any>;
21
+ result: any;
22
+ error: Error;
23
+ }>>, stepTimeout?: number, signal?: AbortSignal): AsyncGenerator<PregelExecutableTask<any, any>>;
24
+ export declare function shouldInterrupt<N extends PropertyKey, C extends PropertyKey>(checkpoint: Checkpoint, interruptNodes: All | N[], tasks: PregelExecutableTask<N, C>[]): boolean;
25
+ export declare function _localRead<Cc extends StrRecord<string, BaseChannel>>(checkpoint: ReadonlyCheckpoint, channels: Cc, task: WritesProtocol<keyof Cc>, select: Array<keyof Cc> | keyof Cc, fresh?: boolean): Record<string, unknown> | unknown;
26
+ export declare function _localWrite(commit: (writes: [string, any][]) => void, processes: Record<string, PregelNode>, channels: Record<string, BaseChannel>, writes: [string, any][]): void;
27
+ export declare function _applyWrites<Cc extends Record<string, BaseChannel>>(checkpoint: Checkpoint, channels: Cc, tasks: WritesProtocol<keyof Cc>[], getNextVersion?: (version: any, channel: BaseChannel) => any): void;
28
+ export type NextTaskExtraFields = {
29
+ step: number;
30
+ isResuming?: boolean;
31
+ checkpointer?: BaseCheckpointSaver;
32
+ manager?: CallbackManagerForChainRun;
33
+ };
34
+ export declare function _prepareNextTasks<Nn extends StrRecord<string, PregelNode>, Cc extends StrRecord<string, BaseChannel>>(checkpoint: ReadonlyCheckpoint, processes: Nn, channels: Cc, config: RunnableConfig, forExecution: false, extra: NextTaskExtraFields): PregelTaskDescription[];
35
+ export declare function _prepareNextTasks<Nn extends StrRecord<string, PregelNode>, Cc extends StrRecord<string, BaseChannel>>(checkpoint: ReadonlyCheckpoint, processes: Nn, channels: Cc, config: RunnableConfig, forExecution: true, extra: NextTaskExtraFields): PregelExecutableTask<keyof Nn, keyof Cc>[];