@langchain/langgraph 0.0.34 → 0.1.0-rc.0
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.
- package/README.md +11 -15
- package/dist/channels/any_value.cjs +3 -1
- package/dist/channels/any_value.d.ts +1 -1
- package/dist/channels/any_value.js +3 -1
- package/dist/channels/base.cjs +8 -0
- package/dist/channels/base.d.ts +12 -1
- package/dist/channels/base.js +8 -0
- package/dist/channels/binop.cjs +2 -1
- package/dist/channels/binop.d.ts +1 -1
- package/dist/channels/binop.js +2 -1
- package/dist/channels/dynamic_barrier_value.cjs +30 -18
- package/dist/channels/dynamic_barrier_value.d.ts +2 -1
- package/dist/channels/dynamic_barrier_value.js +30 -18
- package/dist/channels/ephemeral_value.cjs +3 -1
- package/dist/channels/ephemeral_value.d.ts +1 -1
- package/dist/channels/ephemeral_value.js +3 -1
- package/dist/channels/last_value.cjs +3 -2
- package/dist/channels/last_value.d.ts +1 -1
- package/dist/channels/last_value.js +3 -2
- package/dist/channels/named_barrier_value.cjs +14 -6
- package/dist/channels/named_barrier_value.d.ts +2 -1
- package/dist/channels/named_barrier_value.js +15 -7
- package/dist/channels/topic.cjs +10 -11
- package/dist/channels/topic.d.ts +1 -1
- package/dist/channels/topic.js +10 -11
- package/dist/checkpoint/base.cjs +9 -0
- package/dist/checkpoint/base.d.ts +23 -18
- package/dist/checkpoint/base.js +9 -0
- package/dist/checkpoint/id.cjs +13 -1
- package/dist/checkpoint/id.d.ts +1 -0
- package/dist/checkpoint/id.js +12 -1
- package/dist/checkpoint/index.d.ts +2 -1
- package/dist/checkpoint/memory.cjs +152 -39
- package/dist/checkpoint/memory.d.ts +6 -3
- package/dist/checkpoint/memory.js +152 -39
- package/dist/checkpoint/serde/types.cjs +2 -0
- package/dist/checkpoint/serde/types.d.ts +40 -0
- package/dist/checkpoint/serde/types.js +1 -0
- package/dist/checkpoint/sqlite.cjs +127 -98
- package/dist/checkpoint/sqlite.d.ts +5 -3
- package/dist/checkpoint/sqlite.js +127 -98
- package/dist/checkpoint/types.cjs +2 -0
- package/dist/checkpoint/types.d.ts +28 -0
- package/dist/checkpoint/types.js +1 -0
- package/dist/constants.cjs +17 -1
- package/dist/constants.d.ts +7 -0
- package/dist/constants.js +16 -0
- package/dist/errors.cjs +21 -1
- package/dist/errors.d.ts +8 -0
- package/dist/errors.js +18 -0
- package/dist/graph/graph.cjs +6 -3
- package/dist/graph/graph.d.ts +6 -2
- package/dist/graph/graph.js +7 -4
- package/dist/graph/index.d.ts +1 -1
- package/dist/graph/state.cjs +7 -7
- package/dist/graph/state.js +7 -7
- package/dist/pregel/algo.cjs +384 -0
- package/dist/pregel/algo.d.ts +32 -0
- package/dist/pregel/algo.js +374 -0
- package/dist/pregel/debug.cjs +158 -9
- package/dist/pregel/debug.d.ts +39 -2
- package/dist/pregel/debug.js +151 -7
- package/dist/pregel/index.cjs +217 -509
- package/dist/pregel/index.d.ts +29 -66
- package/dist/pregel/index.js +219 -506
- package/dist/pregel/io.cjs +2 -2
- package/dist/pregel/io.d.ts +5 -4
- package/dist/pregel/io.js +2 -2
- package/dist/pregel/loop.cjs +428 -0
- package/dist/pregel/loop.d.ts +84 -0
- package/dist/pregel/loop.js +421 -0
- package/dist/pregel/types.d.ts +53 -4
- package/dist/pregel/utils.cjs +33 -0
- package/dist/pregel/utils.d.ts +3 -0
- package/dist/pregel/utils.js +28 -0
- package/dist/pregel/write.cjs +3 -1
- package/dist/pregel/write.js +3 -1
- package/dist/utils.cjs +21 -1
- package/dist/utils.d.ts +4 -0
- package/dist/utils.js +18 -0
- package/dist/web.d.ts +3 -2
- package/package.json +4 -2
package/dist/pregel/index.cjs
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.Pregel = exports.Channel = void 0;
|
|
4
4
|
/* eslint-disable no-param-reassign */
|
|
5
5
|
const runnables_1 = require("@langchain/core/runnables");
|
|
6
|
-
const stream_1 = require("@langchain/core/utils/stream");
|
|
7
6
|
const base_js_1 = require("../channels/base.cjs");
|
|
8
7
|
const base_js_2 = require("../checkpoint/base.cjs");
|
|
9
8
|
const read_js_1 = require("./read.cjs");
|
|
10
9
|
const validate_js_1 = require("./validate.cjs");
|
|
11
10
|
const io_js_1 = require("./io.cjs");
|
|
11
|
+
const debug_js_1 = require("./debug.cjs");
|
|
12
12
|
const write_js_1 = require("./write.cjs");
|
|
13
13
|
const constants_js_1 = require("../constants.cjs");
|
|
14
14
|
const errors_js_1 = require("../errors.cjs");
|
|
15
|
-
const
|
|
15
|
+
const algo_js_1 = require("./algo.cjs");
|
|
16
|
+
const id_js_1 = require("../checkpoint/id.cjs");
|
|
17
|
+
const utils_js_1 = require("../utils.cjs");
|
|
18
|
+
const utils_js_2 = require("./utils.cjs");
|
|
19
|
+
const loop_js_1 = require("./loop.cjs");
|
|
16
20
|
function isString(value) {
|
|
17
21
|
return typeof value === "string";
|
|
18
22
|
}
|
|
@@ -96,13 +100,13 @@ class Pregel extends runnables_1.Runnable {
|
|
|
96
100
|
writable: true,
|
|
97
101
|
value: void 0
|
|
98
102
|
});
|
|
99
|
-
Object.defineProperty(this, "
|
|
103
|
+
Object.defineProperty(this, "inputChannels", {
|
|
100
104
|
enumerable: true,
|
|
101
105
|
configurable: true,
|
|
102
106
|
writable: true,
|
|
103
107
|
value: void 0
|
|
104
108
|
});
|
|
105
|
-
Object.defineProperty(this, "
|
|
109
|
+
Object.defineProperty(this, "outputChannels", {
|
|
106
110
|
enumerable: true,
|
|
107
111
|
configurable: true,
|
|
108
112
|
writable: true,
|
|
@@ -118,7 +122,7 @@ class Pregel extends runnables_1.Runnable {
|
|
|
118
122
|
enumerable: true,
|
|
119
123
|
configurable: true,
|
|
120
124
|
writable: true,
|
|
121
|
-
value: "values"
|
|
125
|
+
value: ["values"]
|
|
122
126
|
});
|
|
123
127
|
Object.defineProperty(this, "streamChannels", {
|
|
124
128
|
enumerable: true,
|
|
@@ -156,20 +160,22 @@ class Pregel extends runnables_1.Runnable {
|
|
|
156
160
|
writable: true,
|
|
157
161
|
value: void 0
|
|
158
162
|
});
|
|
163
|
+
let { streamMode } = fields;
|
|
164
|
+
if (streamMode != null && !Array.isArray(streamMode)) {
|
|
165
|
+
streamMode = [streamMode];
|
|
166
|
+
}
|
|
159
167
|
this.nodes = fields.nodes;
|
|
160
168
|
this.channels = fields.channels;
|
|
161
169
|
this.autoValidate = fields.autoValidate ?? this.autoValidate;
|
|
162
|
-
this.streamMode =
|
|
163
|
-
this.
|
|
170
|
+
this.streamMode = streamMode ?? this.streamMode;
|
|
171
|
+
this.inputChannels = fields.inputChannels;
|
|
172
|
+
this.outputChannels = fields.outputChannels;
|
|
164
173
|
this.streamChannels = fields.streamChannels ?? this.streamChannels;
|
|
165
174
|
this.interruptAfter = fields.interruptAfter;
|
|
166
175
|
this.interruptBefore = fields.interruptBefore;
|
|
167
|
-
this.inputs = fields.inputs;
|
|
168
176
|
this.stepTimeout = fields.stepTimeout ?? this.stepTimeout;
|
|
169
177
|
this.debug = fields.debug ?? this.debug;
|
|
170
178
|
this.checkpointer = fields.checkpointer;
|
|
171
|
-
// Bind the method to the instance
|
|
172
|
-
this._transform = this._transform.bind(this);
|
|
173
179
|
if (this.autoValidate) {
|
|
174
180
|
this.validate();
|
|
175
181
|
}
|
|
@@ -178,8 +184,8 @@ class Pregel extends runnables_1.Runnable {
|
|
|
178
184
|
(0, validate_js_1.validateGraph)({
|
|
179
185
|
nodes: this.nodes,
|
|
180
186
|
channels: this.channels,
|
|
181
|
-
outputChannels: this.
|
|
182
|
-
inputChannels: this.
|
|
187
|
+
outputChannels: this.outputChannels,
|
|
188
|
+
inputChannels: this.inputChannels,
|
|
183
189
|
streamChannels: this.streamChannels,
|
|
184
190
|
interruptAfterNodes: this.interruptAfter,
|
|
185
191
|
interruptBeforeNodes: this.interruptBefore,
|
|
@@ -212,8 +218,7 @@ class Pregel extends runnables_1.Runnable {
|
|
|
212
218
|
const saved = await this.checkpointer.getTuple(config);
|
|
213
219
|
const checkpoint = saved ? saved.checkpoint : (0, base_js_2.emptyCheckpoint)();
|
|
214
220
|
const channels = (0, base_js_1.emptyChannels)(this.channels, checkpoint);
|
|
215
|
-
|
|
216
|
-
const [_, nextTasks] = _prepareNextTasks(checkpoint, this.nodes, channels, false, { step: -1 });
|
|
221
|
+
const [, nextTasks] = (0, algo_js_1._prepareNextTasks)(checkpoint, this.nodes, channels, saved !== undefined ? saved.config : config, false, { step: -1 });
|
|
217
222
|
return {
|
|
218
223
|
values: (0, io_js_1.readChannels)(channels, this.streamChannelsAsIs),
|
|
219
224
|
next: nextTasks.map((task) => task.name),
|
|
@@ -223,14 +228,13 @@ class Pregel extends runnables_1.Runnable {
|
|
|
223
228
|
parentConfig: saved?.parentConfig,
|
|
224
229
|
};
|
|
225
230
|
}
|
|
226
|
-
async *getStateHistory(config,
|
|
231
|
+
async *getStateHistory(config, options) {
|
|
227
232
|
if (!this.checkpointer) {
|
|
228
233
|
throw new errors_js_1.GraphValueError("No checkpointer set");
|
|
229
234
|
}
|
|
230
|
-
for await (const saved of this.checkpointer.list(config,
|
|
235
|
+
for await (const saved of this.checkpointer.list(config, options)) {
|
|
231
236
|
const channels = (0, base_js_1.emptyChannels)(this.channels, saved.checkpoint);
|
|
232
|
-
|
|
233
|
-
const [_, nextTasks] = _prepareNextTasks(saved.checkpoint, this.nodes, channels, false, { step: -1 });
|
|
237
|
+
const [, nextTasks] = (0, algo_js_1._prepareNextTasks)(saved.checkpoint, this.nodes, channels, saved.config, false, { step: -1 });
|
|
234
238
|
yield {
|
|
235
239
|
values: (0, io_js_1.readChannels)(channels, this.streamChannelsAsIs),
|
|
236
240
|
next: nextTasks.map((task) => task.name),
|
|
@@ -250,38 +254,75 @@ class Pregel extends runnables_1.Runnable {
|
|
|
250
254
|
const checkpoint = saved
|
|
251
255
|
? (0, base_js_2.copyCheckpoint)(saved.checkpoint)
|
|
252
256
|
: (0, base_js_2.emptyCheckpoint)();
|
|
253
|
-
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
257
|
+
const checkpointPreviousVersions = saved?.checkpoint.channel_versions ?? {};
|
|
258
|
+
const step = saved?.metadata?.step ?? -1;
|
|
259
|
+
// merge configurable fields with previous checkpoint config
|
|
260
|
+
const checkpointConfig = {
|
|
261
|
+
...config,
|
|
262
|
+
configurable: {
|
|
263
|
+
...config.configurable,
|
|
264
|
+
// TODO: add proper support for updating nested subgraph state
|
|
265
|
+
checkpoint_ns: "",
|
|
266
|
+
...saved?.config.configurable,
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
// Find last node that updated the state, if not provided
|
|
270
|
+
if (values === undefined && asNode === undefined) {
|
|
271
|
+
return await this.checkpointer.put(checkpointConfig, (0, base_js_1.createCheckpoint)(checkpoint, {}, step), {
|
|
272
|
+
source: "update",
|
|
273
|
+
step,
|
|
274
|
+
writes: {},
|
|
275
|
+
}, {});
|
|
276
|
+
}
|
|
277
|
+
const nonNullVersion = Object.values(checkpoint.versions_seen)
|
|
278
|
+
.map((seenVersions) => {
|
|
279
|
+
return Object.values(seenVersions);
|
|
280
|
+
})
|
|
281
|
+
.flat()
|
|
282
|
+
.find((v) => !!v);
|
|
283
|
+
if (asNode === undefined && !nonNullVersion) {
|
|
284
|
+
if (typeof this.inputChannels === "string" &&
|
|
285
|
+
this.nodes[this.inputChannels] !== undefined) {
|
|
286
|
+
asNode = this.inputChannels;
|
|
267
287
|
}
|
|
268
288
|
}
|
|
269
|
-
else if (
|
|
270
|
-
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
289
|
+
else if (asNode === undefined) {
|
|
290
|
+
// TODO: Double check
|
|
291
|
+
const lastSeenByNode = Object.entries(checkpoint.versions_seen)
|
|
292
|
+
.map(([n, seen]) => {
|
|
293
|
+
return Object.values(seen).map((v) => {
|
|
294
|
+
return [v, n];
|
|
295
|
+
});
|
|
296
|
+
})
|
|
297
|
+
.flat()
|
|
298
|
+
.sort(([aNumber], [bNumber]) => {
|
|
299
|
+
return aNumber - bNumber;
|
|
300
|
+
});
|
|
301
|
+
// if two nodes updated the state at the same time, it's ambiguous
|
|
302
|
+
if (lastSeenByNode) {
|
|
303
|
+
if (lastSeenByNode.length === 1) {
|
|
304
|
+
// eslint-disable-next-line prefer-destructuring
|
|
305
|
+
asNode = lastSeenByNode[0][1];
|
|
306
|
+
}
|
|
307
|
+
else if (lastSeenByNode[lastSeenByNode.length - 1][0] !==
|
|
308
|
+
lastSeenByNode[lastSeenByNode.length - 2][0]) {
|
|
309
|
+
// eslint-disable-next-line prefer-destructuring
|
|
310
|
+
asNode = lastSeenByNode[lastSeenByNode.length - 1][1];
|
|
311
|
+
}
|
|
274
312
|
}
|
|
275
313
|
}
|
|
276
|
-
if (
|
|
277
|
-
throw new errors_js_1.InvalidUpdateError(
|
|
314
|
+
if (asNode === undefined) {
|
|
315
|
+
throw new errors_js_1.InvalidUpdateError(`Ambiguous update, specify "asNode"`);
|
|
316
|
+
}
|
|
317
|
+
if (this.nodes[asNode] === undefined) {
|
|
318
|
+
throw new errors_js_1.InvalidUpdateError(`Node "${asNode.toString()}" does not exist`);
|
|
278
319
|
}
|
|
279
320
|
// update channels
|
|
280
321
|
const channels = (0, base_js_1.emptyChannels)(this.channels, checkpoint);
|
|
281
|
-
//
|
|
322
|
+
// run all writers of the chosen node
|
|
282
323
|
const writers = this.nodes[asNode].getWriters();
|
|
283
324
|
if (!writers.length) {
|
|
284
|
-
throw new errors_js_1.InvalidUpdateError(`No writers found for node ${asNode}`);
|
|
325
|
+
throw new errors_js_1.InvalidUpdateError(`No writers found for node "${asNode.toString()}"`);
|
|
285
326
|
}
|
|
286
327
|
const task = {
|
|
287
328
|
name: asNode,
|
|
@@ -290,24 +331,29 @@ class Pregel extends runnables_1.Runnable {
|
|
|
290
331
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
291
332
|
writers.length > 1 ? runnables_1.RunnableSequence.from(writers) : writers[0],
|
|
292
333
|
writes: [],
|
|
334
|
+
triggers: [constants_js_1.INTERRUPT],
|
|
293
335
|
config: undefined,
|
|
336
|
+
id: (0, id_js_1.uuid5)(constants_js_1.INTERRUPT, checkpoint.id),
|
|
294
337
|
};
|
|
295
338
|
// execute task
|
|
296
339
|
await task.proc.invoke(task.input, (0, runnables_1.patchConfig)(config, {
|
|
297
340
|
runName: `${this.name}UpdateState`,
|
|
298
341
|
configurable: {
|
|
299
342
|
[constants_js_1.CONFIG_KEY_SEND]: (items) => task.writes.push(...items),
|
|
300
|
-
[constants_js_1.CONFIG_KEY_READ]: _localRead.bind(undefined, checkpoint, channels,
|
|
343
|
+
[constants_js_1.CONFIG_KEY_READ]: algo_js_1._localRead.bind(undefined, checkpoint, channels,
|
|
344
|
+
// TODO: Why does keyof StrRecord allow number and symbol?
|
|
345
|
+
task),
|
|
301
346
|
},
|
|
302
347
|
}));
|
|
303
348
|
// apply to checkpoint and save
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
349
|
+
// TODO: Why does keyof StrRecord allow number and symbol?
|
|
350
|
+
(0, algo_js_1._applyWrites)(checkpoint, channels, [task], this.checkpointer.getNextVersion.bind(this.checkpointer));
|
|
351
|
+
const newVersions = (0, utils_js_2.getNewChannelVersions)(checkpointPreviousVersions, checkpoint.channel_versions);
|
|
352
|
+
return await this.checkpointer.put(checkpointConfig, (0, base_js_1.createCheckpoint)(checkpoint, channels, step + 1), {
|
|
307
353
|
source: "update",
|
|
308
|
-
step,
|
|
354
|
+
step: step + 1,
|
|
309
355
|
writes: { [asNode]: values },
|
|
310
|
-
});
|
|
356
|
+
}, newVersions);
|
|
311
357
|
}
|
|
312
358
|
_defaults(config) {
|
|
313
359
|
const { debug, streamMode, inputKeys, outputKeys, interruptAfter, interruptBefore, ...rest } = config;
|
|
@@ -321,7 +367,7 @@ class Pregel extends runnables_1.Runnable {
|
|
|
321
367
|
}
|
|
322
368
|
let defaultInputKeys = inputKeys;
|
|
323
369
|
if (defaultInputKeys === undefined) {
|
|
324
|
-
defaultInputKeys = this.
|
|
370
|
+
defaultInputKeys = this.inputChannels;
|
|
325
371
|
}
|
|
326
372
|
else {
|
|
327
373
|
(0, validate_js_1.validateKeys)(defaultInputKeys, this.channels);
|
|
@@ -330,14 +376,23 @@ class Pregel extends runnables_1.Runnable {
|
|
|
330
376
|
const defaultInterruptAfter = interruptAfter ?? this.interruptAfter ?? [];
|
|
331
377
|
let defaultStreamMode;
|
|
332
378
|
if (streamMode !== undefined) {
|
|
333
|
-
defaultStreamMode = streamMode;
|
|
379
|
+
defaultStreamMode = Array.isArray(streamMode) ? streamMode : [streamMode];
|
|
334
380
|
}
|
|
335
381
|
else {
|
|
336
382
|
defaultStreamMode = this.streamMode;
|
|
337
383
|
}
|
|
384
|
+
let defaultCheckpointer;
|
|
338
385
|
if (config.configurable !== undefined &&
|
|
339
386
|
config.configurable[constants_js_1.CONFIG_KEY_READ] !== undefined) {
|
|
340
|
-
defaultStreamMode = "values";
|
|
387
|
+
defaultStreamMode = ["values"];
|
|
388
|
+
}
|
|
389
|
+
if (config !== undefined &&
|
|
390
|
+
config.configurable?.[constants_js_1.CONFIG_KEY_CHECKPOINTER] !== undefined &&
|
|
391
|
+
(defaultInterruptAfter.length > 0 || defaultInterruptBefore.length > 0)) {
|
|
392
|
+
defaultCheckpointer = config.configurable[constants_js_1.CONFIG_KEY_CHECKPOINTER];
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
defaultCheckpointer = this.checkpointer;
|
|
341
396
|
}
|
|
342
397
|
return [
|
|
343
398
|
defaultDebug,
|
|
@@ -347,489 +402,142 @@ class Pregel extends runnables_1.Runnable {
|
|
|
347
402
|
rest,
|
|
348
403
|
defaultInterruptBefore,
|
|
349
404
|
defaultInterruptAfter,
|
|
405
|
+
defaultCheckpointer,
|
|
350
406
|
];
|
|
351
407
|
}
|
|
352
|
-
async *
|
|
353
|
-
const
|
|
408
|
+
async *_streamIterator(input, options) {
|
|
409
|
+
const inputConfig = (0, runnables_1.ensureConfig)(options);
|
|
410
|
+
if (inputConfig.recursionLimit === undefined ||
|
|
411
|
+
inputConfig.recursionLimit < 1) {
|
|
412
|
+
throw new Error(`Passed "recursionLimit" must be at least 1.`);
|
|
413
|
+
}
|
|
414
|
+
if (this.checkpointer !== undefined &&
|
|
415
|
+
inputConfig.configurable === undefined) {
|
|
416
|
+
throw new Error(`Checkpointer requires one or more of the following "configurable" keys: "thread_id", "checkpoint_ns", "checkpoint_id"`);
|
|
417
|
+
}
|
|
418
|
+
const callbackManager = await (0, runnables_1.getCallbackManagerForConfig)(inputConfig);
|
|
419
|
+
const runManager = await callbackManager?.handleChainStart(this.toJSON(), (0, utils_js_2._coerceToDict)(input, "input"), inputConfig.runId, undefined, undefined, undefined, inputConfig?.runName ?? this.getName());
|
|
420
|
+
delete inputConfig.runId;
|
|
421
|
+
// assign defaults
|
|
422
|
+
const [debug, streamMode, , outputKeys, config, interruptBefore, interruptAfter, checkpointer,] = this._defaults(inputConfig);
|
|
423
|
+
let loop;
|
|
424
|
+
let backgroundError;
|
|
425
|
+
const onBackgroundError = (e) => {
|
|
426
|
+
backgroundError = e;
|
|
427
|
+
};
|
|
354
428
|
try {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
let start = (saved?.metadata?.step ?? -2) + 1;
|
|
372
|
-
// create channels from checkpoint
|
|
373
|
-
const channels = (0, base_js_1.emptyChannels)(this.channels, checkpoint);
|
|
374
|
-
// map inputs to channel updates
|
|
375
|
-
const inputPendingWrites = [];
|
|
376
|
-
for await (const c of input) {
|
|
377
|
-
for (const value of (0, io_js_1.mapInput)(inputKeys, c)) {
|
|
378
|
-
inputPendingWrites.push(value);
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
if (inputPendingWrites.length) {
|
|
382
|
-
// discard any unfinished tasks from previous checkpoint
|
|
383
|
-
const discarded = _prepareNextTasks(checkpoint, processes, channels, true, { step: -1 });
|
|
384
|
-
checkpoint = discarded[0]; // eslint-disable-line prefer-destructuring
|
|
385
|
-
// apply input writes
|
|
386
|
-
_applyWrites(checkpoint, channels, inputPendingWrites);
|
|
387
|
-
// save input checkpoint
|
|
388
|
-
if (this.checkpointer) {
|
|
389
|
-
checkpoint = (0, base_js_1.createCheckpoint)(checkpoint, channels, start);
|
|
390
|
-
bg.push(this.checkpointer.put(checkpointConfig, checkpoint, {
|
|
391
|
-
source: "input",
|
|
392
|
-
step: start,
|
|
393
|
-
writes: Object.fromEntries(inputPendingWrites),
|
|
394
|
-
}));
|
|
395
|
-
checkpointConfig = {
|
|
396
|
-
configurable: {
|
|
397
|
-
...checkpointConfig.configurable,
|
|
398
|
-
checkpoint_id: checkpoint.id,
|
|
399
|
-
},
|
|
400
|
-
};
|
|
429
|
+
loop = await loop_js_1.PregelLoop.initialize({
|
|
430
|
+
input,
|
|
431
|
+
config,
|
|
432
|
+
checkpointer,
|
|
433
|
+
graph: this,
|
|
434
|
+
onBackgroundError,
|
|
435
|
+
});
|
|
436
|
+
while (backgroundError === undefined &&
|
|
437
|
+
(await loop.tick({
|
|
438
|
+
outputKeys,
|
|
439
|
+
interruptAfter,
|
|
440
|
+
interruptBefore,
|
|
441
|
+
manager: runManager,
|
|
442
|
+
}))) {
|
|
443
|
+
if (debug) {
|
|
444
|
+
(0, debug_js_1.printStepCheckpoint)(loop.checkpointMetadata.step, loop.channels, this.streamChannelsList);
|
|
401
445
|
}
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
446
|
+
while (loop.stream.length > 0) {
|
|
447
|
+
const nextItem = loop.stream.shift();
|
|
448
|
+
if (nextItem === undefined) {
|
|
449
|
+
throw new Error("Data structure error.");
|
|
450
|
+
}
|
|
451
|
+
if (streamMode.includes(nextItem[0])) {
|
|
452
|
+
if (streamMode.length === 1) {
|
|
453
|
+
yield nextItem[1];
|
|
454
|
+
}
|
|
455
|
+
else {
|
|
456
|
+
yield nextItem;
|
|
457
|
+
}
|
|
411
458
|
}
|
|
412
|
-
checkpoint.versions_seen[constants_js_1.INTERRUPT][k] = version;
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
// Similarly to Bulk Synchronous Parallel / Pregel model
|
|
416
|
-
// computation proceeds in steps, while there are channel updates
|
|
417
|
-
// channel updates from step N are only visible in step N+1
|
|
418
|
-
// channels are guaranteed to be immutable for the duration of the step,
|
|
419
|
-
// with channel updates applied only at the transition between steps
|
|
420
|
-
const stop = start + (config.recursionLimit ?? DEFAULT_LOOP_LIMIT);
|
|
421
|
-
for (let step = start; step < stop + 1; step += 1) {
|
|
422
|
-
const [nextCheckpoint, nextTasks] = _prepareNextTasks(checkpoint, processes, channels, true, { step });
|
|
423
|
-
// if no more tasks, we're done
|
|
424
|
-
if (nextTasks.length === 0 && step === start) {
|
|
425
|
-
throw new errors_js_1.GraphValueError(`No tasks to run in graph.`);
|
|
426
|
-
}
|
|
427
|
-
else if (nextTasks.length === 0) {
|
|
428
|
-
break;
|
|
429
|
-
}
|
|
430
|
-
else if (step === stop) {
|
|
431
|
-
throw new errors_js_1.GraphRecursionError(`Recursion limit of ${config.recursionLimit} reached without hitting a stop condition. You can increase the limit by setting the "recursionLimit" config key.`);
|
|
432
|
-
}
|
|
433
|
-
// before execution, check if we should interrupt
|
|
434
|
-
if (_shouldInterrupt(checkpoint, interruptBefore, this.streamChannelsList, nextTasks)) {
|
|
435
|
-
break;
|
|
436
|
-
}
|
|
437
|
-
else {
|
|
438
|
-
checkpoint = nextCheckpoint;
|
|
439
459
|
}
|
|
440
460
|
if (debug) {
|
|
441
|
-
|
|
461
|
+
(0, debug_js_1.printStepTasks)(loop.step, loop.tasks);
|
|
442
462
|
}
|
|
443
|
-
const tasksWithConfig = nextTasks.map(
|
|
444
|
-
// eslint-disable-next-line no-loop-func
|
|
445
|
-
(task, i) => [
|
|
446
|
-
task.proc,
|
|
447
|
-
task.input,
|
|
448
|
-
(0, runnables_1.patchConfig)((0, runnables_1.mergeConfigs)(restConfig, processes[task.name].config, {
|
|
449
|
-
metadata: {
|
|
450
|
-
langgraph_step: step,
|
|
451
|
-
langgraph_node: task.name,
|
|
452
|
-
langgraph_triggers: [constants_js_1.TASKS],
|
|
453
|
-
langgraph_task_idx: i,
|
|
454
|
-
},
|
|
455
|
-
}), {
|
|
456
|
-
callbacks: runManager?.getChild(`graph:step:${step}`),
|
|
457
|
-
runName: task.name,
|
|
458
|
-
configurable: {
|
|
459
|
-
...config.configurable,
|
|
460
|
-
[constants_js_1.CONFIG_KEY_SEND]: (items) => task.writes.push(...items),
|
|
461
|
-
[constants_js_1.CONFIG_KEY_READ]: _localRead.bind(undefined, checkpoint, channels, task.writes),
|
|
462
|
-
},
|
|
463
|
-
}),
|
|
464
|
-
]);
|
|
465
463
|
// execute tasks, and wait for one to fail or all to finish.
|
|
466
464
|
// each task is independent from all other concurrent tasks
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
// apply writes to channels
|
|
475
|
-
_applyWrites(checkpoint, channels, pendingWrites);
|
|
476
|
-
// yield current value and checkpoint view
|
|
477
|
-
if (streamMode === "values") {
|
|
478
|
-
yield* (0, io_js_1.mapOutputValues)(outputKeys, pendingWrites, channels);
|
|
465
|
+
// yield updates/debug output as each task finishes
|
|
466
|
+
const tasks = loop.tasks.map((pregelTask) => () => {
|
|
467
|
+
return pregelTask.proc.invoke(pregelTask.input, pregelTask.config);
|
|
468
|
+
});
|
|
469
|
+
await (0, algo_js_1.executeTasks)(tasks, this.stepTimeout, config.signal);
|
|
470
|
+
for (const task of loop.tasks) {
|
|
471
|
+
loop.putWrites(task.id, task.writes);
|
|
479
472
|
}
|
|
480
|
-
|
|
473
|
+
if (streamMode.includes("updates")) {
|
|
481
474
|
// TODO: Refactor
|
|
482
|
-
for await (const task of
|
|
483
|
-
yield* (0, io_js_1.mapOutputUpdates)(outputKeys, [task]);
|
|
475
|
+
for await (const task of loop.tasks) {
|
|
476
|
+
yield* (0, utils_js_1.prefixGenerator)((0, io_js_1.mapOutputUpdates)(outputKeys, [task]), streamMode.length > 1 ? "updates" : undefined);
|
|
484
477
|
}
|
|
485
478
|
}
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
checkpoint = (0, base_js_1.createCheckpoint)(checkpoint, channels, step);
|
|
489
|
-
bg.push(this.checkpointer.put(checkpointConfig, checkpoint, {
|
|
490
|
-
source: "loop",
|
|
491
|
-
step,
|
|
492
|
-
writes: (0, io_js_1.single)(this.streamMode === "values"
|
|
493
|
-
? (0, io_js_1.mapOutputValues)(outputKeys, pendingWrites, channels)
|
|
494
|
-
: (0, io_js_1.mapOutputUpdates)(outputKeys, nextTasks)),
|
|
495
|
-
}));
|
|
496
|
-
checkpointConfig = {
|
|
497
|
-
configurable: {
|
|
498
|
-
...checkpointConfig.configurable,
|
|
499
|
-
checkpoint_id: checkpoint.id,
|
|
500
|
-
},
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
if (_shouldInterrupt(checkpoint, interruptAfter, this.streamChannelsList, nextTasks)) {
|
|
504
|
-
break;
|
|
479
|
+
if (streamMode.includes("debug")) {
|
|
480
|
+
yield* (0, utils_js_1.prefixGenerator)((0, debug_js_1.mapDebugTaskResults)(loop.step, loop.tasks, this.streamChannelsList), streamMode.length > 1 ? "debug" : undefined);
|
|
505
481
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
finally {
|
|
509
|
-
await Promise.all(bg);
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
async invoke(input, options) {
|
|
513
|
-
const config = (0, runnables_1.ensureConfig)(options);
|
|
514
|
-
if (!config?.outputKeys) {
|
|
515
|
-
config.outputKeys = this.outputs;
|
|
516
|
-
}
|
|
517
|
-
if (!config?.streamMode) {
|
|
518
|
-
config.streamMode = "values";
|
|
519
|
-
}
|
|
520
|
-
let latest;
|
|
521
|
-
for await (const chunk of await this.stream(input, config)) {
|
|
522
|
-
latest = chunk;
|
|
523
|
-
}
|
|
524
|
-
if (!latest) {
|
|
525
|
-
return undefined;
|
|
526
|
-
}
|
|
527
|
-
return latest;
|
|
528
|
-
}
|
|
529
|
-
async stream(input, config) {
|
|
530
|
-
const inputIterator = (async function* () {
|
|
531
|
-
yield input;
|
|
532
|
-
})();
|
|
533
|
-
return stream_1.IterableReadableStream.fromAsyncGenerator(this.transform(inputIterator, config));
|
|
534
|
-
}
|
|
535
|
-
async *transform(generator, config) {
|
|
536
|
-
for await (const chunk of this._transformStreamWithConfig(generator, this._transform, config)) {
|
|
537
|
-
yield chunk;
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
exports.Pregel = Pregel;
|
|
542
|
-
async function executeTasks(tasks, stepTimeout, signal) {
|
|
543
|
-
if (stepTimeout && signal) {
|
|
544
|
-
if ("any" in AbortSignal) {
|
|
545
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
546
|
-
signal = AbortSignal.any([
|
|
547
|
-
signal,
|
|
548
|
-
AbortSignal.timeout(stepTimeout),
|
|
549
|
-
]);
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
else if (stepTimeout) {
|
|
553
|
-
signal = AbortSignal.timeout(stepTimeout);
|
|
554
|
-
}
|
|
555
|
-
// Abort if signal is aborted
|
|
556
|
-
signal?.throwIfAborted();
|
|
557
|
-
// Start all tasks
|
|
558
|
-
const started = tasks.map((task) => task());
|
|
559
|
-
// Wait for all tasks to settle
|
|
560
|
-
// If any tasks fail, or signal is aborted, the promise will reject
|
|
561
|
-
await Promise.all(signal
|
|
562
|
-
? [
|
|
563
|
-
...started,
|
|
564
|
-
new Promise((_resolve, reject) => {
|
|
565
|
-
signal?.addEventListener("abort", () => reject(new Error("Abort")));
|
|
566
|
-
}),
|
|
567
|
-
]
|
|
568
|
-
: started);
|
|
569
|
-
}
|
|
570
|
-
function _shouldInterrupt(checkpoint, interruptNodes, snapshotChannels, tasks) {
|
|
571
|
-
const anySnapshotChannelUpdated = snapshotChannels.some((chan) => (0, base_js_2.getChannelVersion)(checkpoint, chan) >
|
|
572
|
-
(0, base_js_2.getVersionSeen)(checkpoint, constants_js_1.INTERRUPT, chan));
|
|
573
|
-
const anyTaskNodeInInterruptNodes = tasks.some((task) => interruptNodes === "*"
|
|
574
|
-
? !task.config?.tags?.includes(constants_js_1.TAG_HIDDEN)
|
|
575
|
-
: interruptNodes.includes(task.name));
|
|
576
|
-
return anySnapshotChannelUpdated && anyTaskNodeInInterruptNodes;
|
|
577
|
-
}
|
|
578
|
-
exports._shouldInterrupt = _shouldInterrupt;
|
|
579
|
-
function _localRead(checkpoint, channels, writes, select, fresh = false) {
|
|
580
|
-
if (fresh) {
|
|
581
|
-
const newCheckpoint = (0, base_js_1.createCheckpoint)(checkpoint, channels, -1);
|
|
582
|
-
// create a new copy of channels
|
|
583
|
-
const newChannels = (0, base_js_1.emptyChannels)(channels, newCheckpoint);
|
|
584
|
-
// Note: _applyWrites contains side effects
|
|
585
|
-
_applyWrites((0, base_js_2.copyCheckpoint)(newCheckpoint), newChannels, writes);
|
|
586
|
-
return (0, io_js_1.readChannels)(newChannels, select);
|
|
587
|
-
}
|
|
588
|
-
else {
|
|
589
|
-
return (0, io_js_1.readChannels)(channels, select);
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
exports._localRead = _localRead;
|
|
593
|
-
function _localWrite(
|
|
594
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
595
|
-
commit, processes, channels,
|
|
596
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
597
|
-
writes) {
|
|
598
|
-
for (const [chan, value] of writes) {
|
|
599
|
-
if (chan === constants_js_1.TASKS) {
|
|
600
|
-
if (!(0, constants_js_1._isSend)(value)) {
|
|
601
|
-
throw new errors_js_1.InvalidUpdateError(`Invalid packet type, expected SendProtocol, got ${JSON.stringify(value)}`);
|
|
602
|
-
}
|
|
603
|
-
if (!(value.node in processes)) {
|
|
604
|
-
throw new errors_js_1.InvalidUpdateError(`Invalid node name ${value.node} in packet`);
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
else if (!(chan in channels)) {
|
|
608
|
-
console.warn(`Skipping write for channel '${chan}' which has no readers`);
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
commit(writes);
|
|
612
|
-
}
|
|
613
|
-
exports._localWrite = _localWrite;
|
|
614
|
-
function _applyWrites(checkpoint, channels, pendingWrites) {
|
|
615
|
-
if (checkpoint.pending_sends) {
|
|
616
|
-
checkpoint.pending_sends = [];
|
|
617
|
-
}
|
|
618
|
-
const pendingWritesByChannel = {};
|
|
619
|
-
// Group writes by channel
|
|
620
|
-
for (const [chan, val] of pendingWrites) {
|
|
621
|
-
if (chan === constants_js_1.TASKS) {
|
|
622
|
-
checkpoint.pending_sends.push({
|
|
623
|
-
node: val.node,
|
|
624
|
-
args: val.args,
|
|
625
|
-
});
|
|
626
|
-
}
|
|
627
|
-
else {
|
|
628
|
-
if (chan in pendingWritesByChannel) {
|
|
629
|
-
pendingWritesByChannel[chan].push(val);
|
|
630
|
-
}
|
|
631
|
-
else {
|
|
632
|
-
pendingWritesByChannel[chan] = [val];
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
// find the highest version of all channels
|
|
637
|
-
let maxVersion = 0;
|
|
638
|
-
if (Object.keys(checkpoint.channel_versions).length > 0) {
|
|
639
|
-
maxVersion = Math.max(...Object.values(checkpoint.channel_versions));
|
|
640
|
-
}
|
|
641
|
-
const updatedChannels = new Set();
|
|
642
|
-
// Apply writes to channels
|
|
643
|
-
for (const [chan, vals] of Object.entries(pendingWritesByChannel)) {
|
|
644
|
-
if (chan in channels) {
|
|
645
|
-
// side effect: update channels
|
|
646
|
-
try {
|
|
647
|
-
channels[chan].update(vals);
|
|
648
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
649
|
-
}
|
|
650
|
-
catch (e) {
|
|
651
|
-
if (e.name === errors_js_1.InvalidUpdateError.unminifiable_name) {
|
|
652
|
-
throw new errors_js_1.InvalidUpdateError(`Invalid update for channel ${chan}. Values: ${vals}\n\nError: ${e.message}`);
|
|
482
|
+
if (debug) {
|
|
483
|
+
(0, debug_js_1.printStepWrites)(loop.step, loop.tasks.map((task) => task.writes).flat(), this.streamChannelsList);
|
|
653
484
|
}
|
|
654
485
|
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
updatedChannels.add(chan);
|
|
658
|
-
}
|
|
659
|
-
else {
|
|
660
|
-
console.warn(`Skipping write for channel ${chan} which has no readers`);
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
// Channels that weren't updated in this step are notified of a new step
|
|
664
|
-
for (const chan in channels) {
|
|
665
|
-
if (!updatedChannels.has(chan)) {
|
|
666
|
-
// side effect: update channels
|
|
667
|
-
channels[chan].update([]);
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
exports._applyWrites = _applyWrites;
|
|
672
|
-
function _prepareNextTasks(checkpoint, processes, channels, forExecution, extra) {
|
|
673
|
-
const newCheckpoint = (0, base_js_2.copyCheckpoint)(checkpoint);
|
|
674
|
-
const tasks = [];
|
|
675
|
-
const taskDescriptions = [];
|
|
676
|
-
for (const packet of checkpoint.pending_sends) {
|
|
677
|
-
if (!(0, constants_js_1._isSendInterface)(packet)) {
|
|
678
|
-
console.warn(`Ignoring invalid packet ${JSON.stringify(packet)} in pending sends.`);
|
|
679
|
-
continue;
|
|
680
|
-
}
|
|
681
|
-
if (!(packet.node in processes)) {
|
|
682
|
-
console.warn(`Ignoring unknown node name ${packet.node} in pending sends.`);
|
|
683
|
-
continue;
|
|
684
|
-
}
|
|
685
|
-
if (forExecution) {
|
|
686
|
-
const proc = processes[packet.node];
|
|
687
|
-
const node = proc.getNode();
|
|
688
|
-
if (node !== undefined) {
|
|
689
|
-
const triggers = [constants_js_1.TASKS];
|
|
690
|
-
const metadata = {
|
|
691
|
-
langgraph_step: extra.step,
|
|
692
|
-
langgraph_node: packet.node,
|
|
693
|
-
langgraph_triggers: triggers,
|
|
694
|
-
langgraph_task_idx: tasks.length,
|
|
695
|
-
};
|
|
696
|
-
const writes = [];
|
|
697
|
-
tasks.push({
|
|
698
|
-
name: packet.node,
|
|
699
|
-
input: packet.args,
|
|
700
|
-
proc: node,
|
|
701
|
-
writes,
|
|
702
|
-
config: (0, runnables_1.patchConfig)((0, runnables_1.mergeConfigs)(proc.config, processes[packet.node].config, {
|
|
703
|
-
metadata,
|
|
704
|
-
}), {
|
|
705
|
-
runName: packet.node,
|
|
706
|
-
// callbacks:
|
|
707
|
-
configurable: {
|
|
708
|
-
[constants_js_1.CONFIG_KEY_SEND]: _localWrite.bind(undefined, (items) => writes.push(...items), processes, channels),
|
|
709
|
-
[constants_js_1.CONFIG_KEY_READ]: _localRead.bind(undefined, checkpoint, channels, writes),
|
|
710
|
-
},
|
|
711
|
-
}),
|
|
712
|
-
});
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
else {
|
|
716
|
-
taskDescriptions.push({
|
|
717
|
-
name: packet.node,
|
|
718
|
-
input: packet.args,
|
|
719
|
-
});
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
// Check if any processes should be run in next step
|
|
723
|
-
// If so, prepare the values to be passed to them
|
|
724
|
-
for (const [name, proc] of Object.entries(processes)) {
|
|
725
|
-
const hasUpdatedChannels = proc.triggers
|
|
726
|
-
.filter((chan) => {
|
|
727
|
-
try {
|
|
728
|
-
(0, io_js_1.readChannel)(channels, chan, false);
|
|
729
|
-
return true;
|
|
486
|
+
if (backgroundError !== undefined) {
|
|
487
|
+
throw backgroundError;
|
|
730
488
|
}
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
.some((chan) => (0, base_js_2.getChannelVersion)(newCheckpoint, chan) >
|
|
736
|
-
(0, base_js_2.getVersionSeen)(newCheckpoint, name, chan));
|
|
737
|
-
// If any of the channels read by this process were updated
|
|
738
|
-
if (hasUpdatedChannels) {
|
|
739
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
740
|
-
let val;
|
|
741
|
-
// If all trigger channels subscribed by this process are not empty
|
|
742
|
-
// then invoke the process with the values of all non-empty channels
|
|
743
|
-
if (Array.isArray(proc.channels)) {
|
|
744
|
-
let emptyChannels = 0;
|
|
745
|
-
for (const chan of proc.channels) {
|
|
746
|
-
try {
|
|
747
|
-
val = (0, io_js_1.readChannel)(channels, chan, false);
|
|
748
|
-
break;
|
|
749
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
750
|
-
}
|
|
751
|
-
catch (e) {
|
|
752
|
-
if (e.name === errors_js_1.EmptyChannelError.unminifiable_name) {
|
|
753
|
-
emptyChannels += 1;
|
|
754
|
-
continue;
|
|
755
|
-
}
|
|
756
|
-
else {
|
|
757
|
-
throw e;
|
|
758
|
-
}
|
|
759
|
-
}
|
|
489
|
+
while (loop.stream.length > 0) {
|
|
490
|
+
const nextItem = loop.stream.shift();
|
|
491
|
+
if (nextItem === undefined) {
|
|
492
|
+
throw new Error("Data structure error.");
|
|
760
493
|
}
|
|
761
|
-
if (
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
}
|
|
765
|
-
else if (typeof proc.channels === "object") {
|
|
766
|
-
val = {};
|
|
767
|
-
try {
|
|
768
|
-
for (const [k, chan] of Object.entries(proc.channels)) {
|
|
769
|
-
val[k] = (0, io_js_1.readChannel)(channels, chan, !proc.triggers.includes(chan));
|
|
770
|
-
}
|
|
771
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
772
|
-
}
|
|
773
|
-
catch (e) {
|
|
774
|
-
if (e.name === errors_js_1.EmptyChannelError.unminifiable_name) {
|
|
775
|
-
continue;
|
|
494
|
+
if (streamMode.includes(nextItem[0])) {
|
|
495
|
+
if (streamMode.length === 1) {
|
|
496
|
+
yield nextItem[1];
|
|
776
497
|
}
|
|
777
498
|
else {
|
|
778
|
-
|
|
499
|
+
yield nextItem;
|
|
779
500
|
}
|
|
780
501
|
}
|
|
781
502
|
}
|
|
782
|
-
|
|
783
|
-
throw new
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
}
|
|
789
|
-
if (forExecution) {
|
|
790
|
-
// Update seen versions
|
|
791
|
-
if (!newCheckpoint.versions_seen[name]) {
|
|
792
|
-
newCheckpoint.versions_seen[name] = {};
|
|
793
|
-
}
|
|
794
|
-
proc.triggers.forEach((chan) => {
|
|
795
|
-
const version = newCheckpoint.channel_versions[chan];
|
|
796
|
-
if (version !== undefined) {
|
|
797
|
-
// side effect: updates newCheckpoint
|
|
798
|
-
newCheckpoint.versions_seen[name][chan] = version;
|
|
799
|
-
}
|
|
800
|
-
});
|
|
801
|
-
const node = proc.getNode();
|
|
802
|
-
if (node !== undefined) {
|
|
803
|
-
const metadata = {
|
|
804
|
-
langgraph_step: extra.step,
|
|
805
|
-
langgraph_node: name,
|
|
806
|
-
langgraph_triggers: proc.triggers,
|
|
807
|
-
langgraph_task_idx: tasks.length,
|
|
808
|
-
};
|
|
809
|
-
const writes = [];
|
|
810
|
-
tasks.push({
|
|
811
|
-
name,
|
|
812
|
-
input: val,
|
|
813
|
-
proc: node,
|
|
814
|
-
writes,
|
|
815
|
-
config: (0, runnables_1.patchConfig)((0, runnables_1.mergeConfigs)(proc.config, { metadata }), {
|
|
816
|
-
runName: name,
|
|
817
|
-
configurable: {
|
|
818
|
-
[constants_js_1.CONFIG_KEY_SEND]: _localWrite.bind(undefined, (items) => writes.push(...items), processes, channels),
|
|
819
|
-
[constants_js_1.CONFIG_KEY_READ]: _localRead.bind(undefined, checkpoint, channels, writes),
|
|
820
|
-
},
|
|
821
|
-
}),
|
|
822
|
-
});
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
else {
|
|
826
|
-
taskDescriptions.push({
|
|
827
|
-
name,
|
|
828
|
-
input: val,
|
|
829
|
-
});
|
|
503
|
+
if (loop.status === "out_of_steps") {
|
|
504
|
+
throw new errors_js_1.GraphRecursionError([
|
|
505
|
+
`Recursion limit of ${config.recursionLimit} reached`,
|
|
506
|
+
"without hitting a stop condition. You can increase the",
|
|
507
|
+
`limit by setting the "recursionLimit" config key.`,
|
|
508
|
+
].join(" "));
|
|
830
509
|
}
|
|
510
|
+
await runManager?.handleChainEnd((0, io_js_1.readChannels)(loop.channels, outputKeys));
|
|
511
|
+
}
|
|
512
|
+
catch (e) {
|
|
513
|
+
await runManager?.handleChainError(e);
|
|
514
|
+
throw e;
|
|
515
|
+
}
|
|
516
|
+
finally {
|
|
517
|
+
await loop?.backgroundTasksPromise;
|
|
831
518
|
}
|
|
832
519
|
}
|
|
833
|
-
|
|
520
|
+
/**
|
|
521
|
+
* Run the graph with a single input and config.
|
|
522
|
+
* @param input
|
|
523
|
+
* @param options
|
|
524
|
+
*/
|
|
525
|
+
async invoke(input, options) {
|
|
526
|
+
const streamMode = options?.streamMode ?? "values";
|
|
527
|
+
const config = {
|
|
528
|
+
...(0, runnables_1.ensureConfig)(options),
|
|
529
|
+
outputKeys: options?.outputKeys ?? this.outputChannels,
|
|
530
|
+
streamMode,
|
|
531
|
+
};
|
|
532
|
+
const chunks = [];
|
|
533
|
+
const stream = await this.stream(input, config);
|
|
534
|
+
for await (const chunk of stream) {
|
|
535
|
+
chunks.push(chunk);
|
|
536
|
+
}
|
|
537
|
+
if (streamMode === "values") {
|
|
538
|
+
return chunks[chunks.length - 1];
|
|
539
|
+
}
|
|
540
|
+
return chunks;
|
|
541
|
+
}
|
|
834
542
|
}
|
|
835
|
-
exports.
|
|
543
|
+
exports.Pregel = Pregel;
|