@langchain/langgraph 0.0.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 (84) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +588 -0
  3. package/dist/channels/base.cjs +58 -0
  4. package/dist/channels/base.d.ts +46 -0
  5. package/dist/channels/base.js +50 -0
  6. package/dist/channels/binop.cjs +70 -0
  7. package/dist/channels/binop.d.ts +16 -0
  8. package/dist/channels/binop.js +66 -0
  9. package/dist/channels/index.cjs +9 -0
  10. package/dist/channels/index.d.ts +1 -0
  11. package/dist/channels/index.js +1 -0
  12. package/dist/channels/last_value.cjs +53 -0
  13. package/dist/channels/last_value.d.ts +12 -0
  14. package/dist/channels/last_value.js +49 -0
  15. package/dist/channels/topic.cjs +90 -0
  16. package/dist/channels/topic.d.ts +19 -0
  17. package/dist/channels/topic.js +86 -0
  18. package/dist/checkpoint/base.cjs +32 -0
  19. package/dist/checkpoint/base.d.ts +47 -0
  20. package/dist/checkpoint/base.js +27 -0
  21. package/dist/checkpoint/index.cjs +8 -0
  22. package/dist/checkpoint/index.d.ts +2 -0
  23. package/dist/checkpoint/index.js +2 -0
  24. package/dist/checkpoint/memory.cjs +35 -0
  25. package/dist/checkpoint/memory.d.ts +8 -0
  26. package/dist/checkpoint/memory.js +31 -0
  27. package/dist/constants.cjs +5 -0
  28. package/dist/constants.d.ts +2 -0
  29. package/dist/constants.js +2 -0
  30. package/dist/graph/graph.cjs +175 -0
  31. package/dist/graph/graph.d.ts +30 -0
  32. package/dist/graph/graph.js +171 -0
  33. package/dist/graph/index.cjs +9 -0
  34. package/dist/graph/index.d.ts +2 -0
  35. package/dist/graph/index.js +2 -0
  36. package/dist/graph/state.cjs +108 -0
  37. package/dist/graph/state.d.ts +17 -0
  38. package/dist/graph/state.js +104 -0
  39. package/dist/index.cjs +8 -0
  40. package/dist/index.d.ts +1 -0
  41. package/dist/index.js +1 -0
  42. package/dist/prebuilt/agent_executor.cjs +96 -0
  43. package/dist/prebuilt/agent_executor.d.ts +12 -0
  44. package/dist/prebuilt/agent_executor.js +92 -0
  45. package/dist/prebuilt/chat_agent_executor.cjs +130 -0
  46. package/dist/prebuilt/chat_agent_executor.d.ts +6 -0
  47. package/dist/prebuilt/chat_agent_executor.js +126 -0
  48. package/dist/prebuilt/index.cjs +9 -0
  49. package/dist/prebuilt/index.d.ts +3 -0
  50. package/dist/prebuilt/index.js +3 -0
  51. package/dist/prebuilt/tool_executor.cjs +63 -0
  52. package/dist/prebuilt/tool_executor.d.ts +27 -0
  53. package/dist/prebuilt/tool_executor.js +59 -0
  54. package/dist/pregel/debug.cjs +46 -0
  55. package/dist/pregel/debug.d.ts +4 -0
  56. package/dist/pregel/debug.js +41 -0
  57. package/dist/pregel/index.cjs +475 -0
  58. package/dist/pregel/index.d.ts +75 -0
  59. package/dist/pregel/index.js +469 -0
  60. package/dist/pregel/io.cjs +57 -0
  61. package/dist/pregel/io.d.ts +9 -0
  62. package/dist/pregel/io.js +52 -0
  63. package/dist/pregel/read.cjs +217 -0
  64. package/dist/pregel/read.d.ts +43 -0
  65. package/dist/pregel/read.js +211 -0
  66. package/dist/pregel/reserved.cjs +7 -0
  67. package/dist/pregel/reserved.d.ts +3 -0
  68. package/dist/pregel/reserved.js +4 -0
  69. package/dist/pregel/validate.cjs +90 -0
  70. package/dist/pregel/validate.d.ts +15 -0
  71. package/dist/pregel/validate.js +85 -0
  72. package/dist/pregel/write.cjs +54 -0
  73. package/dist/pregel/write.d.ts +13 -0
  74. package/dist/pregel/write.js +50 -0
  75. package/index.cjs +1 -0
  76. package/index.d.ts +1 -0
  77. package/index.js +1 -0
  78. package/package.json +100 -0
  79. package/prebuilt.cjs +1 -0
  80. package/prebuilt.d.ts +1 -0
  81. package/prebuilt.js +1 -0
  82. package/pregel.cjs +1 -0
  83. package/pregel.d.ts +1 -0
  84. package/pregel.js +1 -0
@@ -0,0 +1,27 @@
1
+ import { RunnableBinding, RunnableConfig } from "@langchain/core/runnables";
2
+ import { Tool } from "@langchain/core/tools";
3
+ export interface ToolExecutorArgs {
4
+ tools: Array<Tool>;
5
+ /**
6
+ * @default {INVALID_TOOL_MSG_TEMPLATE}
7
+ */
8
+ invalidToolMsgTemplate?: string;
9
+ }
10
+ /**
11
+ * Interface for invoking a tool
12
+ */
13
+ export interface ToolInvocationInterface {
14
+ tool: string;
15
+ toolInput: string;
16
+ }
17
+ type ToolExecutorInputType = any;
18
+ type ToolExecutorOutputType = any;
19
+ export declare class ToolExecutor extends RunnableBinding<ToolExecutorInputType, ToolExecutorOutputType> {
20
+ lc_graph_name: string;
21
+ tools: Array<Tool>;
22
+ toolMap: Record<string, Tool>;
23
+ invalidToolMsgTemplate: string;
24
+ constructor(fields: ToolExecutorArgs);
25
+ _execute(toolInvocation: ToolInvocationInterface, _config?: RunnableConfig): Promise<string>;
26
+ }
27
+ export {};
@@ -0,0 +1,59 @@
1
+ import { RunnableBinding, RunnableLambda, } from "@langchain/core/runnables";
2
+ const INVALID_TOOL_MSG_TEMPLATE = `{requestedToolName} is not a valid tool, try one of [availableToolNamesString].`;
3
+ export class ToolExecutor extends RunnableBinding {
4
+ constructor(fields) {
5
+ const fieldsWithDefaults = {
6
+ invalidToolMsgTemplate: INVALID_TOOL_MSG_TEMPLATE,
7
+ ...fields,
8
+ };
9
+ const bound = new RunnableLambda({
10
+ func: async (input, options) => this._execute(input, options?.config),
11
+ });
12
+ super({
13
+ bound,
14
+ config: {},
15
+ });
16
+ Object.defineProperty(this, "lc_graph_name", {
17
+ enumerable: true,
18
+ configurable: true,
19
+ writable: true,
20
+ value: "ToolExecutor"
21
+ });
22
+ Object.defineProperty(this, "tools", {
23
+ enumerable: true,
24
+ configurable: true,
25
+ writable: true,
26
+ value: void 0
27
+ });
28
+ Object.defineProperty(this, "toolMap", {
29
+ enumerable: true,
30
+ configurable: true,
31
+ writable: true,
32
+ value: void 0
33
+ });
34
+ Object.defineProperty(this, "invalidToolMsgTemplate", {
35
+ enumerable: true,
36
+ configurable: true,
37
+ writable: true,
38
+ value: void 0
39
+ });
40
+ this.tools = fieldsWithDefaults.tools;
41
+ this.invalidToolMsgTemplate = fieldsWithDefaults.invalidToolMsgTemplate;
42
+ this.toolMap = this.tools.reduce((acc, tool) => {
43
+ acc[tool.name] = tool;
44
+ return acc;
45
+ }, {});
46
+ }
47
+ async _execute(toolInvocation, _config) {
48
+ if (!(toolInvocation.tool in this.toolMap)) {
49
+ return this.invalidToolMsgTemplate
50
+ .replace("{requestedToolName}", toolInvocation.tool)
51
+ .replace("{availableToolNamesString}", Object.keys(this.toolMap).join(", "));
52
+ }
53
+ else {
54
+ const tool = this.toolMap[toolInvocation.tool];
55
+ const output = await tool.invoke(toolInvocation.toolInput);
56
+ return output;
57
+ }
58
+ }
59
+ }
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.printCheckpoint = exports.printStepStart = void 0;
4
+ const base_js_1 = require("../channels/base.cjs");
5
+ const COLORS_MAP = {
6
+ blue: {
7
+ start: "\x1b[34m",
8
+ end: "\x1b[0m",
9
+ },
10
+ };
11
+ /**
12
+ * Wrap some text in a color for printing to the console.
13
+ */
14
+ const wrap = (color, text) => `${color.start}${text}${color.end}`;
15
+ function printStepStart(step,
16
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
+ nextTasks) {
18
+ const nTasks = nextTasks.length;
19
+ console.log(`${wrap(COLORS_MAP.blue, "[pregel/step]")}`, `Starting step ${step} with ${nTasks} task${nTasks === 1 ? "" : "s"}. Next tasks:\n`, `\n${nextTasks
20
+ .map(([_, val, name]) => `- ${name}(${JSON.stringify(val, null, 2)})`)
21
+ .join("\n")}`);
22
+ }
23
+ exports.printStepStart = printStepStart;
24
+ function printCheckpoint(step, channels) {
25
+ console.log(`${wrap(COLORS_MAP.blue, "[pregel/checkpoint]")}`, `Finishing step ${step}. Channel values:\n`, `\n${JSON.stringify(Object.fromEntries(_readChannels(channels)), null, 2)}`);
26
+ }
27
+ exports.printCheckpoint = printCheckpoint;
28
+ function* _readChannels(channels
29
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
30
+ ) {
31
+ for (const [name, channel] of Object.entries(channels)) {
32
+ try {
33
+ yield [name, channel.get()];
34
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
35
+ }
36
+ catch (error) {
37
+ if (error.name === base_js_1.EmptyChannelError.name) {
38
+ // Skip the channel if it's empty
39
+ continue;
40
+ }
41
+ else {
42
+ throw error; // Re-throw the error if it's not an EmptyChannelError
43
+ }
44
+ }
45
+ }
46
+ }
@@ -0,0 +1,4 @@
1
+ import { Runnable } from "@langchain/core/runnables";
2
+ import { BaseChannel } from "../channels/base.js";
3
+ export declare function printStepStart(step: number, nextTasks: Array<[Runnable, any, string]>): void;
4
+ export declare function printCheckpoint<Value>(step: number, channels: Record<string, BaseChannel<Value>>): void;
@@ -0,0 +1,41 @@
1
+ import { EmptyChannelError } from "../channels/base.js";
2
+ const COLORS_MAP = {
3
+ blue: {
4
+ start: "\x1b[34m",
5
+ end: "\x1b[0m",
6
+ },
7
+ };
8
+ /**
9
+ * Wrap some text in a color for printing to the console.
10
+ */
11
+ const wrap = (color, text) => `${color.start}${text}${color.end}`;
12
+ export function printStepStart(step,
13
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
+ nextTasks) {
15
+ const nTasks = nextTasks.length;
16
+ console.log(`${wrap(COLORS_MAP.blue, "[pregel/step]")}`, `Starting step ${step} with ${nTasks} task${nTasks === 1 ? "" : "s"}. Next tasks:\n`, `\n${nextTasks
17
+ .map(([_, val, name]) => `- ${name}(${JSON.stringify(val, null, 2)})`)
18
+ .join("\n")}`);
19
+ }
20
+ export function printCheckpoint(step, channels) {
21
+ console.log(`${wrap(COLORS_MAP.blue, "[pregel/checkpoint]")}`, `Finishing step ${step}. Channel values:\n`, `\n${JSON.stringify(Object.fromEntries(_readChannels(channels)), null, 2)}`);
22
+ }
23
+ function* _readChannels(channels
24
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
25
+ ) {
26
+ for (const [name, channel] of Object.entries(channels)) {
27
+ try {
28
+ yield [name, channel.get()];
29
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
30
+ }
31
+ catch (error) {
32
+ if (error.name === EmptyChannelError.name) {
33
+ // Skip the channel if it's empty
34
+ continue;
35
+ }
36
+ else {
37
+ throw error; // Re-throw the error if it's not an EmptyChannelError
38
+ }
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,475 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Pregel = exports.Channel = exports.GraphRecursionError = void 0;
4
+ /* eslint-disable no-param-reassign */
5
+ const runnables_1 = require("@langchain/core/runnables");
6
+ const stream_1 = require("@langchain/core/utils/stream");
7
+ const base_js_1 = require("../channels/base.cjs");
8
+ const base_js_2 = require("../checkpoint/base.cjs");
9
+ const read_js_1 = require("./read.cjs");
10
+ const validate_js_1 = require("./validate.cjs");
11
+ const reserved_js_1 = require("./reserved.cjs");
12
+ const io_js_1 = require("./io.cjs");
13
+ const write_js_1 = require("./write.cjs");
14
+ const constants_js_1 = require("../constants.cjs");
15
+ const DEFAULT_RECURSION_LIMIT = 25;
16
+ class GraphRecursionError extends Error {
17
+ constructor(message) {
18
+ super(message);
19
+ this.name = "GraphRecursionError";
20
+ }
21
+ }
22
+ exports.GraphRecursionError = GraphRecursionError;
23
+ function _coerceWriteValue(value) {
24
+ if (!runnables_1.Runnable.isRunnable(value) && typeof value !== "function") {
25
+ return (0, runnables_1._coerceToRunnable)(() => value);
26
+ }
27
+ return (0, runnables_1._coerceToRunnable)(value);
28
+ }
29
+ function isString(value) {
30
+ return typeof value === "string";
31
+ }
32
+ class Channel {
33
+ static subscribeTo(channels, options) {
34
+ const { key, when, tags } = options ?? {};
35
+ if (Array.isArray(channels) && key !== undefined) {
36
+ throw new Error("Can't specify a key when subscribing to multiple channels");
37
+ }
38
+ let channelMappingOrString;
39
+ if (isString(channels)) {
40
+ if (key) {
41
+ channelMappingOrString = { [key]: channels };
42
+ }
43
+ else {
44
+ channelMappingOrString = channels;
45
+ }
46
+ }
47
+ else {
48
+ channelMappingOrString = Object.fromEntries(channels.map((chan) => [chan, chan]));
49
+ }
50
+ const triggers = Array.isArray(channels) ? channels : [channels];
51
+ return new read_js_1.ChannelInvoke({
52
+ channels: channelMappingOrString,
53
+ triggers,
54
+ when,
55
+ tags,
56
+ });
57
+ }
58
+ static subscribeToEach(inbox, key) {
59
+ return new read_js_1.ChannelBatch({
60
+ channel: inbox,
61
+ key,
62
+ });
63
+ }
64
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
65
+ static writeTo(...args) {
66
+ // const channelPairs: Array<[string, WriteValue<RunInput, RunOutput>]> =
67
+ // channels.map((c) => [c, undefined]);
68
+ // return new ChannelWrite<RunInput, RunOutput>(channelPairs);
69
+ const channelPairs = [];
70
+ if (args.length === 1 && typeof args[0] === "object") {
71
+ // Handle the case where named arguments are passed as an object
72
+ const additionalArgs = args[0];
73
+ Object.entries(additionalArgs).forEach(([key, value]) => {
74
+ channelPairs.push([key, _coerceWriteValue(value)]);
75
+ });
76
+ }
77
+ else {
78
+ args.forEach((channel) => {
79
+ if (typeof channel === "string") {
80
+ channelPairs.push([channel, undefined]);
81
+ }
82
+ else if (typeof channel === "object") {
83
+ Object.entries(channel).forEach(([key, value]) => {
84
+ channelPairs.push([key, _coerceWriteValue(value)]);
85
+ });
86
+ }
87
+ });
88
+ }
89
+ return new write_js_1.ChannelWrite(channelPairs);
90
+ }
91
+ }
92
+ exports.Channel = Channel;
93
+ class Pregel extends runnables_1.Runnable {
94
+ constructor(fields) {
95
+ super();
96
+ // Because Pregel extends `Runnable`.
97
+ Object.defineProperty(this, "lc_namespace", {
98
+ enumerable: true,
99
+ configurable: true,
100
+ writable: true,
101
+ value: ["langgraph", "pregel"]
102
+ });
103
+ Object.defineProperty(this, "channels", {
104
+ enumerable: true,
105
+ configurable: true,
106
+ writable: true,
107
+ value: {}
108
+ });
109
+ Object.defineProperty(this, "output", {
110
+ enumerable: true,
111
+ configurable: true,
112
+ writable: true,
113
+ value: "output"
114
+ });
115
+ Object.defineProperty(this, "input", {
116
+ enumerable: true,
117
+ configurable: true,
118
+ writable: true,
119
+ value: "input"
120
+ });
121
+ Object.defineProperty(this, "hidden", {
122
+ enumerable: true,
123
+ configurable: true,
124
+ writable: true,
125
+ value: []
126
+ });
127
+ Object.defineProperty(this, "debug", {
128
+ enumerable: true,
129
+ configurable: true,
130
+ writable: true,
131
+ value: false
132
+ });
133
+ Object.defineProperty(this, "nodes", {
134
+ enumerable: true,
135
+ configurable: true,
136
+ writable: true,
137
+ value: void 0
138
+ });
139
+ Object.defineProperty(this, "checkpointer", {
140
+ enumerable: true,
141
+ configurable: true,
142
+ writable: true,
143
+ value: void 0
144
+ });
145
+ Object.defineProperty(this, "stepTimeout", {
146
+ enumerable: true,
147
+ configurable: true,
148
+ writable: true,
149
+ value: void 0
150
+ });
151
+ Object.defineProperty(this, "interrupt", {
152
+ enumerable: true,
153
+ configurable: true,
154
+ writable: true,
155
+ value: []
156
+ });
157
+ this.channels = fields.channels ?? this.channels;
158
+ this.output = fields.output ?? this.output;
159
+ this.input = fields.input ?? this.input;
160
+ this.hidden = fields.hidden ?? this.hidden;
161
+ this.debug = fields.debug ?? this.debug;
162
+ this.nodes = fields.nodes;
163
+ this.checkpointer = fields.checkpointer;
164
+ this.stepTimeout = fields.stepTimeout;
165
+ this.interrupt = fields.interrupt ?? this.interrupt;
166
+ // Bind the method to the instance
167
+ this._transform = this._transform.bind(this);
168
+ (0, validate_js_1.validateGraph)({
169
+ nodes: this.nodes,
170
+ channels: this.channels,
171
+ output: this.output,
172
+ input: this.input,
173
+ hidden: this.hidden,
174
+ interrupt: this.interrupt,
175
+ });
176
+ }
177
+ async *_transform(input, runManager, config = {}) {
178
+ // assign defaults
179
+ let outputKeys = [];
180
+ if (Array.isArray(config.outputKeys) ||
181
+ typeof config.outputKeys === "string") {
182
+ outputKeys = config.outputKeys;
183
+ }
184
+ else {
185
+ for (const chan in this.channels) {
186
+ if (!this.hidden.includes(chan)) {
187
+ outputKeys.push(chan);
188
+ }
189
+ }
190
+ }
191
+ // copy nodes to ignore mutations during execution
192
+ const processes = { ...this.nodes };
193
+ // get checkpoint, or create an empty one
194
+ let checkpoint;
195
+ if (this.checkpointer) {
196
+ checkpoint = this.checkpointer.get(config);
197
+ }
198
+ checkpoint = checkpoint ?? (0, base_js_2.emptyCheckpoint)();
199
+ // create channels from checkpoint
200
+ const channels = (0, base_js_1.emptyChannels)(this.channels, checkpoint);
201
+ // map inputs to channel updates
202
+ const thisInput = this.input;
203
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
204
+ const inputPendingWrites = [];
205
+ for await (const c of input) {
206
+ for (const value of (0, io_js_1.mapInput)(thisInput, c)) {
207
+ inputPendingWrites.push(value);
208
+ }
209
+ }
210
+ _applyWrites(checkpoint, channels, inputPendingWrites, config, 0);
211
+ const read = (chan) => _readChannel(channels, chan);
212
+ // Similarly to Bulk Synchronous Parallel / Pregel model
213
+ // computation proceeds in steps, while there are channel updates
214
+ // channel updates from step N are only visible in step N+1
215
+ // channels are guaranteed to be immutable for the duration of the step,
216
+ // with channel updates applied only at the transition between steps
217
+ const recursionLimit = config.recursionLimit ?? DEFAULT_RECURSION_LIMIT;
218
+ for (let step = 0; step < recursionLimit + 1; step += 1) {
219
+ const nextTasks = _prepareNextTasks(checkpoint, processes, channels);
220
+ // if no more tasks, we're done
221
+ if (nextTasks.length === 0) {
222
+ break;
223
+ }
224
+ else if (step === config.recursionLimit) {
225
+ throw new GraphRecursionError(`Recursion limit of ${config.recursionLimit} reached without hitting a stop condition. You can increase the limit by setting the "recursionLimit" config key.`);
226
+ }
227
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
228
+ const pendingWrites = [];
229
+ const tasksWithConfig = nextTasks.map(([proc, input, name]) => [
230
+ proc,
231
+ input,
232
+ (0, runnables_1.patchConfig)(config, {
233
+ callbacks: runManager?.getChild(`graph:step:${step}`),
234
+ runName: name,
235
+ configurable: {
236
+ ...config.configurable,
237
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
238
+ [constants_js_1.CONFIG_KEY_SEND]: (items) => pendingWrites.push(...items),
239
+ [constants_js_1.CONFIG_KEY_READ]: read,
240
+ },
241
+ }),
242
+ ]);
243
+ // execute tasks, and wait for one to fail or all to finish.
244
+ // each task is independent from all other concurrent tasks
245
+ const tasks = tasksWithConfig.map(([proc, input, updatedConfig]) => () => proc.invoke(input, updatedConfig));
246
+ await executeTasks(tasks, this.stepTimeout);
247
+ // apply writes to channels
248
+ _applyWrites(checkpoint, channels, pendingWrites, config, step + 1);
249
+ // yield current value and checkpoint view
250
+ const stepOutput = (0, io_js_1.mapOutput)(outputKeys, pendingWrites, channels);
251
+ if (stepOutput) {
252
+ yield stepOutput;
253
+ if (typeof outputKeys !== "string") {
254
+ _applyWritesFromView(checkpoint, channels, stepOutput);
255
+ }
256
+ }
257
+ // save end of step checkpoint
258
+ if (this.checkpointer &&
259
+ this.checkpointer.at === base_js_2.CheckpointAt.END_OF_STEP) {
260
+ checkpoint = await (0, base_js_1.createCheckpoint)(checkpoint, channels);
261
+ this.checkpointer.put(config, checkpoint);
262
+ }
263
+ // interrupt if any channel written to is in interrupt list
264
+ if (pendingWrites.some(([chan]) => this.interrupt?.some((i) => i === chan))) {
265
+ break;
266
+ }
267
+ }
268
+ // save end of run checkpoint
269
+ if (this.checkpointer && this.checkpointer.at === base_js_2.CheckpointAt.END_OF_RUN) {
270
+ checkpoint = await (0, base_js_1.createCheckpoint)(checkpoint, channels);
271
+ this.checkpointer.put(config, checkpoint);
272
+ }
273
+ }
274
+ async invoke(input, config) {
275
+ if (!config?.outputKeys) {
276
+ if (!config) {
277
+ config = {};
278
+ }
279
+ config.outputKeys = this.output;
280
+ }
281
+ let latest;
282
+ for await (const chunk of await this.stream(input, config)) {
283
+ latest = chunk;
284
+ }
285
+ if (!latest) {
286
+ return undefined;
287
+ }
288
+ return latest;
289
+ }
290
+ async stream(input, config) {
291
+ const inputIterator = (async function* () {
292
+ yield input;
293
+ })();
294
+ return stream_1.IterableReadableStream.fromAsyncGenerator(this.transform(inputIterator, config));
295
+ }
296
+ async *transform(generator, config) {
297
+ for await (const chunk of this._transformStreamWithConfig(generator, this._transform, config)) {
298
+ yield chunk;
299
+ }
300
+ }
301
+ }
302
+ exports.Pregel = Pregel;
303
+ function timeout(ms) {
304
+ return new Promise((reject) => {
305
+ setTimeout(reject, ms);
306
+ });
307
+ }
308
+ async function executeTasks(tasks, stepTimeout) {
309
+ // Wrap each task in a Promise that respects the step timeout
310
+ const wrappedTasks = tasks.map((task) => stepTimeout
311
+ ? Promise.race([
312
+ task(),
313
+ stepTimeout ? timeout(stepTimeout) : Promise.resolve(),
314
+ ])
315
+ : task());
316
+ // Wait for all tasks to settle
317
+ const results = await Promise.allSettled(wrappedTasks);
318
+ // Process the results
319
+ for (const result of results) {
320
+ if (result.status === "rejected") {
321
+ // If any task failed, cancel all pending tasks and throw the error
322
+ throw result.reason;
323
+ }
324
+ }
325
+ }
326
+ function _readChannel(channels, chan) {
327
+ try {
328
+ return channels[chan].get();
329
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
330
+ }
331
+ catch (e) {
332
+ if (e.name === base_js_1.EmptyChannelError.name) {
333
+ return null;
334
+ }
335
+ throw e;
336
+ }
337
+ }
338
+ function _applyWrites(checkpoint, channels,
339
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
340
+ pendingWrites, config, forStep) {
341
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
342
+ const pendingWritesByChannel = {};
343
+ // Group writes by channel
344
+ for (const [chan, val] of pendingWrites) {
345
+ for (const c in reserved_js_1.ReservedChannels) {
346
+ if (chan === c) {
347
+ throw new Error(`Can't write to reserved channel ${chan}`);
348
+ }
349
+ }
350
+ if (chan in pendingWritesByChannel) {
351
+ pendingWritesByChannel[chan].push(val);
352
+ }
353
+ else {
354
+ pendingWritesByChannel[chan] = [val];
355
+ }
356
+ }
357
+ // Update reserved channels
358
+ pendingWritesByChannel[reserved_js_1.ReservedChannels.isLastStep] = [
359
+ forStep + 1 === config.recursionLimit,
360
+ ];
361
+ const updatedChannels = new Set();
362
+ // Apply writes to channels
363
+ for (const chan in pendingWritesByChannel) {
364
+ if (chan in pendingWritesByChannel) {
365
+ const vals = pendingWritesByChannel[chan];
366
+ if (chan in channels) {
367
+ channels[chan].update(vals);
368
+ if (checkpoint.channelVersions[chan] === undefined) {
369
+ checkpoint.channelVersions[chan] = 1;
370
+ }
371
+ else {
372
+ checkpoint.channelVersions[chan] += 1;
373
+ }
374
+ updatedChannels.add(chan);
375
+ }
376
+ else {
377
+ console.warn(`Skipping write for channel ${chan} which has no readers`);
378
+ }
379
+ }
380
+ }
381
+ // Channels that weren't updated in this step are notified of a new step
382
+ for (const chan in channels) {
383
+ if (!updatedChannels.has(chan)) {
384
+ channels[chan].update([]);
385
+ }
386
+ }
387
+ }
388
+ function _applyWritesFromView(checkpoint, channels, values) {
389
+ for (const [chan, val] of Object.entries(values)) {
390
+ if (val === _readChannel(channels, chan)) {
391
+ continue;
392
+ }
393
+ if (channels[chan].lc_graph_name === "LastValue") {
394
+ throw new Error(`Can't modify channel ${chan} with LastValue`);
395
+ }
396
+ checkpoint.channelVersions[chan] += 1;
397
+ channels[chan].update([values[chan]]);
398
+ }
399
+ }
400
+ function _prepareNextTasks(checkpoint, processes, channels) {
401
+ const tasks = [];
402
+ // Check if any processes should be run in next step
403
+ // If so, prepare the values to be passed to them
404
+ for (const name in processes) {
405
+ if (Object.prototype.hasOwnProperty.call(processes, name)) {
406
+ const proc = processes[name];
407
+ let seen = checkpoint.versionsSeen[name];
408
+ if (!seen) {
409
+ checkpoint.versionsSeen[name] = {};
410
+ seen = checkpoint.versionsSeen[name];
411
+ }
412
+ if ("triggers" in proc) {
413
+ // If any of the channels read by this process were updated
414
+ if (proc.triggers.some((chan) => checkpoint.channelVersions[chan] > (seen[chan] ?? 0))) {
415
+ // If all channels subscribed by this process have been initialized
416
+ try {
417
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
418
+ let val = {};
419
+ if (typeof proc.channels === "string") {
420
+ val[proc.channels] = _readChannel(channels, proc.channels);
421
+ }
422
+ else {
423
+ for (const [k, chan] of Object.entries(proc.channels)) {
424
+ val[k] = _readChannel(channels, chan);
425
+ }
426
+ }
427
+ // Processes that subscribe to a single keyless channel get
428
+ // the value directly, instead of a dict
429
+ if (typeof proc.channels === "string") {
430
+ val = val[proc.channels];
431
+ }
432
+ else if (Object.keys(proc.channels).length === 1 &&
433
+ proc.channels[Object.keys(proc.channels)[0]] === undefined) {
434
+ val = val[Object.keys(proc.channels)[0]];
435
+ }
436
+ // Update seen versions
437
+ proc.triggers.forEach((chan) => {
438
+ const version = checkpoint.channelVersions[chan];
439
+ if (version !== undefined) {
440
+ seen[chan] = version;
441
+ }
442
+ });
443
+ // skip if condition is not met
444
+ if (proc.when === undefined || proc.when(val)) {
445
+ tasks.push([proc, val, name]);
446
+ }
447
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
448
+ }
449
+ catch (error) {
450
+ if (error.name === base_js_1.EmptyChannelError.name) {
451
+ continue;
452
+ }
453
+ else {
454
+ throw error;
455
+ }
456
+ }
457
+ }
458
+ }
459
+ else if ("channel" in proc) {
460
+ // If the channel read by this process was updated
461
+ if (checkpoint.channelVersions[proc.channel] > (seen[proc.channel] ?? 0)) {
462
+ // Here we don't catch EmptyChannelError because the channel
463
+ // must be initialized if the previous `if` condition is true
464
+ let val = channels[proc.channel].get();
465
+ if (proc.key !== undefined) {
466
+ val = [{ [proc.key]: val }];
467
+ }
468
+ tasks.push([proc, val, name]);
469
+ seen[proc.channel] = checkpoint.channelVersions[proc.channel];
470
+ }
471
+ }
472
+ }
473
+ }
474
+ return tasks;
475
+ }