@langchain/langgraph 0.2.8 → 0.2.10-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/dist/constants.cjs +11 -2
- package/dist/constants.d.ts +6 -1
- package/dist/constants.js +10 -1
- package/dist/errors.cjs +5 -4
- package/dist/errors.d.ts +1 -1
- package/dist/errors.js +5 -4
- package/dist/graph/graph.cjs +7 -2
- package/dist/graph/graph.js +8 -3
- package/dist/graph/message.cjs +2 -0
- package/dist/graph/message.js +2 -0
- package/dist/graph/state.cjs +8 -3
- package/dist/graph/state.d.ts +2 -3
- package/dist/graph/state.js +9 -4
- package/dist/managed/shared_value.cjs +12 -10
- package/dist/managed/shared_value.d.ts +6 -5
- package/dist/managed/shared_value.js +12 -10
- package/dist/pregel/algo.cjs +124 -54
- package/dist/pregel/algo.d.ts +13 -3
- package/dist/pregel/algo.js +122 -53
- package/dist/pregel/debug.cjs +15 -18
- package/dist/pregel/debug.d.ts +3 -2
- package/dist/pregel/debug.js +16 -19
- package/dist/pregel/index.cjs +307 -116
- package/dist/pregel/index.d.ts +21 -6
- package/dist/pregel/index.js +305 -117
- package/dist/pregel/io.cjs +15 -8
- package/dist/pregel/io.d.ts +2 -2
- package/dist/pregel/io.js +15 -8
- package/dist/pregel/loop.cjs +258 -113
- package/dist/pregel/loop.d.ts +24 -9
- package/dist/pregel/loop.js +258 -111
- package/dist/pregel/read.cjs +9 -2
- package/dist/pregel/read.d.ts +3 -2
- package/dist/pregel/read.js +9 -2
- package/dist/pregel/retry.d.ts +1 -1
- package/dist/pregel/runnable_types.cjs +2 -0
- package/dist/pregel/runnable_types.d.ts +5 -0
- package/dist/pregel/runnable_types.js +1 -0
- package/dist/pregel/types.d.ts +8 -4
- package/dist/pregel/utils/config.cjs +73 -0
- package/dist/pregel/utils/config.d.ts +3 -0
- package/dist/pregel/utils/config.js +69 -0
- package/dist/pregel/{utils.cjs → utils/index.cjs} +33 -10
- package/dist/pregel/{utils.d.ts → utils/index.d.ts} +4 -7
- package/dist/pregel/{utils.js → utils/index.js} +30 -8
- package/dist/utils.cjs +5 -3
- package/dist/utils.js +5 -3
- package/dist/web.cjs +4 -2
- package/dist/web.d.ts +4 -3
- package/dist/web.js +1 -2
- package/package.json +1 -1
- package/dist/store/base.cjs +0 -12
- package/dist/store/base.d.ts +0 -7
- package/dist/store/base.js +0 -8
- package/dist/store/batch.cjs +0 -126
- package/dist/store/batch.d.ts +0 -55
- package/dist/store/batch.js +0 -122
- package/dist/store/index.cjs +0 -19
- package/dist/store/index.d.ts +0 -3
- package/dist/store/index.js +0 -3
- package/dist/store/memory.cjs +0 -43
- package/dist/store/memory.d.ts +0 -6
- package/dist/store/memory.js +0 -39
package/dist/pregel/index.cjs
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.Pregel = exports.Channel = void 0;
|
|
4
7
|
/* eslint-disable no-param-reassign */
|
|
5
8
|
const runnables_1 = require("@langchain/core/runnables");
|
|
6
9
|
const langgraph_checkpoint_1 = require("@langchain/langgraph-checkpoint");
|
|
10
|
+
const double_ended_queue_1 = __importDefault(require("double-ended-queue"));
|
|
7
11
|
const base_js_1 = require("../channels/base.cjs");
|
|
8
12
|
const read_js_1 = require("./read.cjs");
|
|
9
13
|
const validate_js_1 = require("./validate.cjs");
|
|
@@ -13,11 +17,12 @@ const write_js_1 = require("./write.cjs");
|
|
|
13
17
|
const constants_js_1 = require("../constants.cjs");
|
|
14
18
|
const errors_js_1 = require("../errors.cjs");
|
|
15
19
|
const algo_js_1 = require("./algo.cjs");
|
|
16
|
-
const
|
|
20
|
+
const index_js_1 = require("./utils/index.cjs");
|
|
17
21
|
const loop_js_1 = require("./loop.cjs");
|
|
18
22
|
const retry_js_1 = require("./retry.cjs");
|
|
19
23
|
const base_js_2 = require("../managed/base.cjs");
|
|
20
|
-
const
|
|
24
|
+
const utils_js_1 = require("../utils.cjs");
|
|
25
|
+
const config_js_1 = require("./utils/config.cjs");
|
|
21
26
|
function isString(value) {
|
|
22
27
|
return typeof value === "string";
|
|
23
28
|
}
|
|
@@ -76,6 +81,16 @@ class Channel {
|
|
|
76
81
|
}
|
|
77
82
|
}
|
|
78
83
|
exports.Channel = Channel;
|
|
84
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
85
|
+
function isPregel(x) {
|
|
86
|
+
return ("inputChannels" in x &&
|
|
87
|
+
x.inputChannels !== undefined &&
|
|
88
|
+
"outputChannels" &&
|
|
89
|
+
x.outputChannels !== undefined);
|
|
90
|
+
}
|
|
91
|
+
function isRunnableSequence(x) {
|
|
92
|
+
return "steps" in x && Array.isArray(x.steps);
|
|
93
|
+
}
|
|
79
94
|
class Pregel extends runnables_1.Runnable {
|
|
80
95
|
static lc_name() {
|
|
81
96
|
return "LangGraph";
|
|
@@ -167,6 +182,12 @@ class Pregel extends runnables_1.Runnable {
|
|
|
167
182
|
writable: true,
|
|
168
183
|
value: void 0
|
|
169
184
|
});
|
|
185
|
+
Object.defineProperty(this, "config", {
|
|
186
|
+
enumerable: true,
|
|
187
|
+
configurable: true,
|
|
188
|
+
writable: true,
|
|
189
|
+
value: void 0
|
|
190
|
+
});
|
|
170
191
|
Object.defineProperty(this, "store", {
|
|
171
192
|
enumerable: true,
|
|
172
193
|
configurable: true,
|
|
@@ -190,11 +211,18 @@ class Pregel extends runnables_1.Runnable {
|
|
|
190
211
|
this.debug = fields.debug ?? this.debug;
|
|
191
212
|
this.checkpointer = fields.checkpointer;
|
|
192
213
|
this.retryPolicy = fields.retryPolicy;
|
|
214
|
+
this.config = fields.config;
|
|
193
215
|
this.store = fields.store;
|
|
194
216
|
if (this.autoValidate) {
|
|
195
217
|
this.validate();
|
|
196
218
|
}
|
|
197
219
|
}
|
|
220
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
221
|
+
// @ts-ignore Remove ignore when we remove support for 0.2 versions of core
|
|
222
|
+
withConfig(config) {
|
|
223
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
224
|
+
return new this.constructor({ ...this, config });
|
|
225
|
+
}
|
|
198
226
|
validate() {
|
|
199
227
|
(0, validate_js_1.validateGraph)({
|
|
200
228
|
nodes: this.nodes,
|
|
@@ -226,50 +254,181 @@ class Pregel extends runnables_1.Runnable {
|
|
|
226
254
|
return Object.keys(this.channels);
|
|
227
255
|
}
|
|
228
256
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
257
|
+
*getSubgraphs(namespace, recurse
|
|
258
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
259
|
+
) {
|
|
260
|
+
for (const [name, node] of Object.entries(this.nodes)) {
|
|
261
|
+
// filter by prefix
|
|
262
|
+
if (namespace !== undefined) {
|
|
263
|
+
if (!namespace.startsWith(name)) {
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
// find the subgraph if any
|
|
268
|
+
let graph;
|
|
269
|
+
const candidates = [node.bound];
|
|
270
|
+
for (const candidate of candidates) {
|
|
271
|
+
if (isPregel(candidate)) {
|
|
272
|
+
graph = candidate;
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
else if (isRunnableSequence(candidate)) {
|
|
276
|
+
candidates.push(...candidate.steps);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
// if found, yield recursively
|
|
280
|
+
if (graph !== undefined) {
|
|
281
|
+
if (name === namespace) {
|
|
282
|
+
yield [name, graph];
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
if (namespace === undefined) {
|
|
286
|
+
yield [name, graph];
|
|
287
|
+
}
|
|
288
|
+
if (recurse) {
|
|
289
|
+
let newNamespace = namespace;
|
|
290
|
+
if (namespace !== undefined) {
|
|
291
|
+
newNamespace = namespace.slice(name.length + 1);
|
|
292
|
+
}
|
|
293
|
+
for (const [subgraphName, subgraph] of graph.getSubgraphs(newNamespace, recurse)) {
|
|
294
|
+
yield [
|
|
295
|
+
`${name}${constants_js_1.CHECKPOINT_NAMESPACE_SEPARATOR}${subgraphName}`,
|
|
296
|
+
subgraph,
|
|
297
|
+
];
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
async _prepareStateSnapshot({ config, saved, subgraphCheckpointer, }) {
|
|
304
|
+
if (saved === undefined) {
|
|
305
|
+
return {
|
|
306
|
+
values: {},
|
|
307
|
+
next: [],
|
|
308
|
+
config,
|
|
309
|
+
tasks: [],
|
|
310
|
+
};
|
|
235
311
|
}
|
|
236
|
-
const saved = await this.checkpointer.getTuple(config);
|
|
237
|
-
const checkpoint = saved ? saved.checkpoint : (0, langgraph_checkpoint_1.emptyCheckpoint)();
|
|
238
|
-
const channels = (0, base_js_1.emptyChannels)(this.channels, checkpoint);
|
|
239
312
|
// Pass `skipManaged: true` as managed values should not be returned in get state calls.
|
|
240
313
|
const { managed } = await this.prepareSpecs(config, { skipManaged: true });
|
|
241
|
-
const
|
|
314
|
+
const channels = (0, base_js_1.emptyChannels)(this.channels, saved.checkpoint);
|
|
315
|
+
const nextTasks = Object.values((0, algo_js_1._prepareNextTasks)(saved.checkpoint, this.nodes, channels, managed, saved.config, false, { step: (saved.metadata?.step ?? -1) + 1 }));
|
|
316
|
+
const subgraphs = await (0, utils_js_1.gatherIterator)(this.getSubgraphs());
|
|
317
|
+
const parentNamespace = saved.config.configurable?.checkpoint_ns ?? "";
|
|
318
|
+
const taskStates = {};
|
|
319
|
+
for (const task of nextTasks) {
|
|
320
|
+
const matchingSubgraph = subgraphs.find(([name]) => name === task.name);
|
|
321
|
+
if (!matchingSubgraph) {
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
// assemble checkpoint_ns for this task
|
|
325
|
+
let taskNs = `${task.name}${constants_js_1.CHECKPOINT_NAMESPACE_END}${task.id}`;
|
|
326
|
+
if (parentNamespace) {
|
|
327
|
+
taskNs = `${parentNamespace}${constants_js_1.CHECKPOINT_NAMESPACE_SEPARATOR}${taskNs}`;
|
|
328
|
+
}
|
|
329
|
+
if (subgraphCheckpointer === undefined) {
|
|
330
|
+
// set config as signal that subgraph checkpoints exist
|
|
331
|
+
const config = {
|
|
332
|
+
configurable: {
|
|
333
|
+
thread_id: saved.config.configurable?.thread_id,
|
|
334
|
+
checkpoint_ns: taskNs,
|
|
335
|
+
},
|
|
336
|
+
};
|
|
337
|
+
taskStates[task.id] = config;
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
// get the state of the subgraph
|
|
341
|
+
const config = {
|
|
342
|
+
configurable: {
|
|
343
|
+
[constants_js_1.CONFIG_KEY_CHECKPOINTER]: subgraphCheckpointer,
|
|
344
|
+
thread_id: saved.config.configurable?.thread_id,
|
|
345
|
+
checkpoint_ns: taskNs,
|
|
346
|
+
},
|
|
347
|
+
};
|
|
348
|
+
taskStates[task.id] = await matchingSubgraph[1].getState(config, {
|
|
349
|
+
subgraphs: true,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
// assemble the state snapshot
|
|
242
354
|
return {
|
|
243
355
|
values: (0, io_js_1.readChannels)(channels, this.streamChannelsAsIs),
|
|
244
356
|
next: nextTasks.map((task) => task.name),
|
|
245
|
-
tasks: (0, debug_js_1.tasksWithWrites)(nextTasks, saved?.pendingWrites ?? []),
|
|
246
|
-
metadata: saved
|
|
247
|
-
config:
|
|
248
|
-
createdAt: saved
|
|
249
|
-
parentConfig: saved
|
|
357
|
+
tasks: (0, debug_js_1.tasksWithWrites)(nextTasks, saved?.pendingWrites ?? [], taskStates),
|
|
358
|
+
metadata: saved.metadata,
|
|
359
|
+
config: (0, index_js_1.patchCheckpointMap)(saved.config, saved.metadata),
|
|
360
|
+
createdAt: saved.checkpoint.ts,
|
|
361
|
+
parentConfig: saved.parentConfig,
|
|
250
362
|
};
|
|
251
363
|
}
|
|
364
|
+
/**
|
|
365
|
+
* Get the current state of the graph.
|
|
366
|
+
*/
|
|
367
|
+
async getState(config, options) {
|
|
368
|
+
const checkpointer = config.configurable?.[constants_js_1.CONFIG_KEY_CHECKPOINTER] ?? this.checkpointer;
|
|
369
|
+
if (!checkpointer) {
|
|
370
|
+
throw new errors_js_1.GraphValueError("No checkpointer set");
|
|
371
|
+
}
|
|
372
|
+
const checkpointNamespace = config.configurable?.checkpoint_ns ?? "";
|
|
373
|
+
if (checkpointNamespace !== "" &&
|
|
374
|
+
config.configurable?.[constants_js_1.CONFIG_KEY_CHECKPOINTER] === undefined) {
|
|
375
|
+
// remove task_ids from checkpoint_ns
|
|
376
|
+
const recastCheckpointNamespace = checkpointNamespace
|
|
377
|
+
.split(constants_js_1.CHECKPOINT_NAMESPACE_SEPARATOR)
|
|
378
|
+
.map((part) => part.split(constants_js_1.CHECKPOINT_NAMESPACE_END)[0])
|
|
379
|
+
.join(constants_js_1.CHECKPOINT_NAMESPACE_SEPARATOR);
|
|
380
|
+
for (const [name, subgraph] of this.getSubgraphs(recastCheckpointNamespace, true)) {
|
|
381
|
+
if (name === recastCheckpointNamespace) {
|
|
382
|
+
return await subgraph.getState((0, utils_js_1.patchConfigurable)(config, {
|
|
383
|
+
[constants_js_1.CONFIG_KEY_CHECKPOINTER]: checkpointer,
|
|
384
|
+
}), { subgraphs: options?.subgraphs });
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
throw new Error(`Subgraph with namespace "${recastCheckpointNamespace}" not found.`);
|
|
388
|
+
}
|
|
389
|
+
const mergedConfig = (0, runnables_1.mergeConfigs)(this.config, config);
|
|
390
|
+
const saved = await checkpointer.getTuple(config);
|
|
391
|
+
const snapshot = await this._prepareStateSnapshot({
|
|
392
|
+
config: mergedConfig,
|
|
393
|
+
saved,
|
|
394
|
+
subgraphCheckpointer: options?.subgraphs ? checkpointer : undefined,
|
|
395
|
+
});
|
|
396
|
+
return snapshot;
|
|
397
|
+
}
|
|
252
398
|
/**
|
|
253
399
|
* Get the history of the state of the graph.
|
|
254
400
|
*/
|
|
255
401
|
async *getStateHistory(config, options) {
|
|
256
|
-
|
|
257
|
-
|
|
402
|
+
const checkpointer = config.configurable?.[constants_js_1.CONFIG_KEY_CHECKPOINTER] ?? this.checkpointer;
|
|
403
|
+
if (!checkpointer) {
|
|
404
|
+
throw new Error("No checkpointer set");
|
|
405
|
+
}
|
|
406
|
+
const checkpointNamespace = config.configurable?.checkpoint_ns ?? "";
|
|
407
|
+
if (checkpointNamespace !== "" &&
|
|
408
|
+
config.configurable?.[constants_js_1.CONFIG_KEY_CHECKPOINTER] === undefined) {
|
|
409
|
+
const recastCheckpointNamespace = checkpointNamespace
|
|
410
|
+
.split(constants_js_1.CHECKPOINT_NAMESPACE_SEPARATOR)
|
|
411
|
+
.map((part) => part.split(constants_js_1.CHECKPOINT_NAMESPACE_END)[0])
|
|
412
|
+
.join(constants_js_1.CHECKPOINT_NAMESPACE_SEPARATOR);
|
|
413
|
+
// find the subgraph with the matching name
|
|
414
|
+
for (const [name, pregel] of this.getSubgraphs(recastCheckpointNamespace, true)) {
|
|
415
|
+
if (name === recastCheckpointNamespace) {
|
|
416
|
+
yield* pregel.getStateHistory((0, utils_js_1.patchConfigurable)(config, {
|
|
417
|
+
[constants_js_1.CONFIG_KEY_CHECKPOINTER]: checkpointer,
|
|
418
|
+
}), options);
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
throw new Error(`Subgraph with namespace "${recastCheckpointNamespace}" not found.`);
|
|
258
423
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
tasks: (0, debug_js_1.tasksWithWrites)(nextTasks, saved.pendingWrites ?? []),
|
|
268
|
-
metadata: saved.metadata,
|
|
269
|
-
config: saved.config,
|
|
270
|
-
createdAt: saved.checkpoint.ts,
|
|
271
|
-
parentConfig: saved.parentConfig,
|
|
272
|
-
};
|
|
424
|
+
const mergedConfig = (0, runnables_1.mergeConfigs)(this.config, config, {
|
|
425
|
+
configurable: { checkpoint_ns: checkpointNamespace },
|
|
426
|
+
});
|
|
427
|
+
for await (const checkpointTuple of checkpointer.list(mergedConfig, options)) {
|
|
428
|
+
yield this._prepareStateSnapshot({
|
|
429
|
+
config: checkpointTuple.config,
|
|
430
|
+
saved: checkpointTuple,
|
|
431
|
+
});
|
|
273
432
|
}
|
|
274
433
|
}
|
|
275
434
|
/**
|
|
@@ -277,34 +436,59 @@ class Pregel extends runnables_1.Runnable {
|
|
|
277
436
|
* node `as_node`. If `as_node` is not provided, it will be set to the last node
|
|
278
437
|
* that updated the state, if not ambiguous.
|
|
279
438
|
*/
|
|
280
|
-
async updateState(
|
|
281
|
-
|
|
439
|
+
async updateState(inputConfig, values, asNode) {
|
|
440
|
+
const checkpointer = inputConfig.configurable?.[constants_js_1.CONFIG_KEY_CHECKPOINTER] ?? this.checkpointer;
|
|
441
|
+
if (!checkpointer) {
|
|
282
442
|
throw new errors_js_1.GraphValueError("No checkpointer set");
|
|
283
443
|
}
|
|
284
|
-
//
|
|
285
|
-
const
|
|
286
|
-
|
|
444
|
+
// delegate to subgraph
|
|
445
|
+
const checkpointNamespace = inputConfig.configurable?.checkpoint_ns ?? "";
|
|
446
|
+
if (checkpointNamespace !== "" &&
|
|
447
|
+
inputConfig.configurable?.[constants_js_1.CONFIG_KEY_CHECKPOINTER] === undefined) {
|
|
448
|
+
// remove task_ids from checkpoint_ns
|
|
449
|
+
const recastCheckpointNamespace = checkpointNamespace
|
|
450
|
+
.split(constants_js_1.CHECKPOINT_NAMESPACE_SEPARATOR)
|
|
451
|
+
.map((part) => {
|
|
452
|
+
return part.split(constants_js_1.CHECKPOINT_NAMESPACE_END)[0];
|
|
453
|
+
})
|
|
454
|
+
.join(constants_js_1.CHECKPOINT_NAMESPACE_SEPARATOR);
|
|
455
|
+
// find the subgraph with the matching name
|
|
456
|
+
// eslint-disable-next-line no-unreachable-loop
|
|
457
|
+
for (const [, pregel] of this.getSubgraphs(recastCheckpointNamespace, true)) {
|
|
458
|
+
return await pregel.updateState((0, utils_js_1.patchConfigurable)(inputConfig, {
|
|
459
|
+
[constants_js_1.CONFIG_KEY_CHECKPOINTER]: checkpointer,
|
|
460
|
+
}), values, asNode);
|
|
461
|
+
}
|
|
462
|
+
throw new Error(`Subgraph "${recastCheckpointNamespace}" not found`);
|
|
463
|
+
}
|
|
464
|
+
// get last checkpoint
|
|
465
|
+
const config = this.config
|
|
466
|
+
? (0, runnables_1.mergeConfigs)(this.config, inputConfig)
|
|
467
|
+
: inputConfig;
|
|
468
|
+
const saved = await checkpointer.getTuple(config);
|
|
469
|
+
const checkpoint = saved !== undefined
|
|
287
470
|
? (0, langgraph_checkpoint_1.copyCheckpoint)(saved.checkpoint)
|
|
288
471
|
: (0, langgraph_checkpoint_1.emptyCheckpoint)();
|
|
289
|
-
const checkpointPreviousVersions =
|
|
472
|
+
const checkpointPreviousVersions = {
|
|
473
|
+
...saved?.checkpoint.channel_versions,
|
|
474
|
+
};
|
|
290
475
|
const step = saved?.metadata?.step ?? -1;
|
|
291
476
|
// merge configurable fields with previous checkpoint config
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
...saved?.config.configurable,
|
|
299
|
-
},
|
|
300
|
-
};
|
|
477
|
+
let checkpointConfig = (0, utils_js_1.patchConfigurable)(config, {
|
|
478
|
+
checkpoint_ns: config.configurable?.checkpoint_ns ?? "",
|
|
479
|
+
});
|
|
480
|
+
if (saved) {
|
|
481
|
+
checkpointConfig = (0, utils_js_1.patchConfigurable)(config, saved.config.configurable);
|
|
482
|
+
}
|
|
301
483
|
// Find last node that updated the state, if not provided
|
|
302
484
|
if (values == null && asNode === undefined) {
|
|
303
|
-
|
|
485
|
+
const nextConfig = await checkpointer.put(checkpointConfig, (0, base_js_1.createCheckpoint)(checkpoint, undefined, step), {
|
|
304
486
|
source: "update",
|
|
305
487
|
step,
|
|
306
488
|
writes: {},
|
|
489
|
+
parents: saved?.metadata?.parents ?? {},
|
|
307
490
|
}, {});
|
|
491
|
+
return (0, index_js_1.patchCheckpointMap)(nextConfig, saved ? saved.metadata : undefined);
|
|
308
492
|
}
|
|
309
493
|
const nonNullVersion = Object.values(checkpoint.versions_seen)
|
|
310
494
|
.map((seenVersions) => {
|
|
@@ -319,7 +503,6 @@ class Pregel extends runnables_1.Runnable {
|
|
|
319
503
|
}
|
|
320
504
|
}
|
|
321
505
|
else if (asNode === undefined) {
|
|
322
|
-
// TODO: Double check
|
|
323
506
|
const lastSeenByNode = Object.entries(checkpoint.versions_seen)
|
|
324
507
|
.map(([n, seen]) => {
|
|
325
508
|
return Object.values(seen).map((v) => {
|
|
@@ -367,7 +550,10 @@ class Pregel extends runnables_1.Runnable {
|
|
|
367
550
|
id: (0, langgraph_checkpoint_1.uuid5)(constants_js_1.INTERRUPT, checkpoint.id),
|
|
368
551
|
};
|
|
369
552
|
// execute task
|
|
370
|
-
await task.proc.invoke(task.input, (0, runnables_1.patchConfig)(
|
|
553
|
+
await task.proc.invoke(task.input, (0, runnables_1.patchConfig)({
|
|
554
|
+
...config,
|
|
555
|
+
store: config?.store ?? this.store,
|
|
556
|
+
}, {
|
|
371
557
|
runName: config.runName ?? `${this.getName()}UpdateState`,
|
|
372
558
|
configurable: {
|
|
373
559
|
[constants_js_1.CONFIG_KEY_SEND]: (items) => task.writes.push(...items),
|
|
@@ -376,18 +562,21 @@ class Pregel extends runnables_1.Runnable {
|
|
|
376
562
|
task, select_, fresh_),
|
|
377
563
|
},
|
|
378
564
|
}));
|
|
565
|
+
// save task writes
|
|
379
566
|
if (saved !== undefined) {
|
|
380
|
-
await
|
|
567
|
+
await checkpointer.putWrites(checkpointConfig, task.writes, task.id);
|
|
381
568
|
}
|
|
382
569
|
// apply to checkpoint
|
|
383
570
|
// TODO: Why does keyof StrRecord allow number and symbol?
|
|
384
|
-
(0, algo_js_1._applyWrites)(checkpoint, channels, [task],
|
|
385
|
-
const newVersions = (0,
|
|
386
|
-
|
|
571
|
+
(0, algo_js_1._applyWrites)(checkpoint, channels, [task], checkpointer.getNextVersion.bind(this.checkpointer));
|
|
572
|
+
const newVersions = (0, index_js_1.getNewChannelVersions)(checkpointPreviousVersions, checkpoint.channel_versions);
|
|
573
|
+
const nextConfig = await checkpointer.put(checkpointConfig, (0, base_js_1.createCheckpoint)(checkpoint, channels, step + 1), {
|
|
387
574
|
source: "update",
|
|
388
575
|
step: step + 1,
|
|
389
576
|
writes: { [asNode]: values },
|
|
577
|
+
parents: saved?.metadata?.parents ?? {},
|
|
390
578
|
}, newVersions);
|
|
579
|
+
return (0, index_js_1.patchCheckpointMap)(nextConfig, saved ? saved.metadata : undefined);
|
|
391
580
|
}
|
|
392
581
|
_defaults(config) {
|
|
393
582
|
const { debug, streamMode, inputKeys, outputKeys, interruptAfter, interruptBefore, ...rest } = config;
|
|
@@ -415,19 +604,19 @@ class Pregel extends runnables_1.Runnable {
|
|
|
415
604
|
else {
|
|
416
605
|
defaultStreamMode = this.streamMode;
|
|
417
606
|
}
|
|
418
|
-
|
|
419
|
-
if (config.configurable !== undefined
|
|
420
|
-
config.configurable[constants_js_1.CONFIG_KEY_READ] !== undefined) {
|
|
607
|
+
// if being called as a node in another graph, always use values mode
|
|
608
|
+
if (config.configurable?.[constants_js_1.CONFIG_KEY_TASK_ID] !== undefined) {
|
|
421
609
|
defaultStreamMode = ["values"];
|
|
422
610
|
}
|
|
611
|
+
let defaultCheckpointer;
|
|
423
612
|
if (config !== undefined &&
|
|
424
|
-
config.configurable?.[constants_js_1.CONFIG_KEY_CHECKPOINTER] !== undefined
|
|
425
|
-
(defaultInterruptAfter.length > 0 || defaultInterruptBefore.length > 0)) {
|
|
613
|
+
config.configurable?.[constants_js_1.CONFIG_KEY_CHECKPOINTER] !== undefined) {
|
|
426
614
|
defaultCheckpointer = config.configurable[constants_js_1.CONFIG_KEY_CHECKPOINTER];
|
|
427
615
|
}
|
|
428
616
|
else {
|
|
429
617
|
defaultCheckpointer = this.checkpointer;
|
|
430
618
|
}
|
|
619
|
+
const defaultStore = config.store ?? this.store;
|
|
431
620
|
return [
|
|
432
621
|
defaultDebug,
|
|
433
622
|
defaultStreamMode,
|
|
@@ -437,6 +626,7 @@ class Pregel extends runnables_1.Runnable {
|
|
|
437
626
|
defaultInterruptBefore,
|
|
438
627
|
defaultInterruptAfter,
|
|
439
628
|
defaultCheckpointer,
|
|
629
|
+
defaultStore,
|
|
440
630
|
];
|
|
441
631
|
}
|
|
442
632
|
/**
|
|
@@ -458,9 +648,10 @@ class Pregel extends runnables_1.Runnable {
|
|
|
458
648
|
return super.stream(input, options);
|
|
459
649
|
}
|
|
460
650
|
async prepareSpecs(config, options) {
|
|
461
|
-
const configForManaged =
|
|
462
|
-
|
|
463
|
-
|
|
651
|
+
const configForManaged = {
|
|
652
|
+
...config,
|
|
653
|
+
store: this.store,
|
|
654
|
+
};
|
|
464
655
|
const channelSpecs = {};
|
|
465
656
|
const managedSpecs = {};
|
|
466
657
|
for (const [name, spec] of Object.entries(this.channels)) {
|
|
@@ -501,7 +692,8 @@ class Pregel extends runnables_1.Runnable {
|
|
|
501
692
|
};
|
|
502
693
|
}
|
|
503
694
|
async *_streamIterator(input, options) {
|
|
504
|
-
const
|
|
695
|
+
const streamSubgraphs = options?.subgraphs;
|
|
696
|
+
const inputConfig = (0, config_js_1.ensureLangGraphConfig)(this.config, options);
|
|
505
697
|
if (inputConfig.recursionLimit === undefined ||
|
|
506
698
|
inputConfig.recursionLimit < 1) {
|
|
507
699
|
throw new Error(`Passed "recursionLimit" must be at least 1.`);
|
|
@@ -511,12 +703,36 @@ class Pregel extends runnables_1.Runnable {
|
|
|
511
703
|
throw new Error(`Checkpointer requires one or more of the following "configurable" keys: "thread_id", "checkpoint_ns", "checkpoint_id"`);
|
|
512
704
|
}
|
|
513
705
|
const callbackManager = await (0, runnables_1.getCallbackManagerForConfig)(inputConfig);
|
|
514
|
-
const runManager = await callbackManager?.handleChainStart(this.toJSON(), (0,
|
|
706
|
+
const runManager = await callbackManager?.handleChainStart(this.toJSON(), (0, index_js_1._coerceToDict)(input, "input"), inputConfig.runId, undefined, undefined, undefined, inputConfig?.runName ?? this.getName());
|
|
515
707
|
delete inputConfig.runId;
|
|
516
708
|
// assign defaults
|
|
517
|
-
const [debug, streamMode, , outputKeys, config, interruptBefore, interruptAfter, checkpointer,] = this._defaults(inputConfig);
|
|
709
|
+
const [debug, streamMode, , outputKeys, config, interruptBefore, interruptAfter, checkpointer, store,] = this._defaults(inputConfig);
|
|
518
710
|
const { channelSpecs, managed } = await this.prepareSpecs(config);
|
|
519
711
|
let loop;
|
|
712
|
+
const stream = new double_ended_queue_1.default();
|
|
713
|
+
function* emitCurrentLoopOutputs() {
|
|
714
|
+
while (loop !== undefined && stream.length > 0) {
|
|
715
|
+
const nextItem = stream.shift();
|
|
716
|
+
if (nextItem === undefined) {
|
|
717
|
+
throw new Error("Data structure error.");
|
|
718
|
+
}
|
|
719
|
+
const [namespace, mode, payload] = nextItem;
|
|
720
|
+
if (streamMode.includes(mode)) {
|
|
721
|
+
if (streamSubgraphs && streamMode.length > 1) {
|
|
722
|
+
yield [namespace, mode, payload];
|
|
723
|
+
}
|
|
724
|
+
else if (streamMode.length > 1) {
|
|
725
|
+
yield [mode, payload];
|
|
726
|
+
}
|
|
727
|
+
else if (streamSubgraphs) {
|
|
728
|
+
yield [namespace, payload];
|
|
729
|
+
}
|
|
730
|
+
else {
|
|
731
|
+
yield payload;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
}
|
|
520
736
|
try {
|
|
521
737
|
loop = await loop_js_1.PregelLoop.initialize({
|
|
522
738
|
input,
|
|
@@ -527,8 +743,15 @@ class Pregel extends runnables_1.Runnable {
|
|
|
527
743
|
managed,
|
|
528
744
|
outputKeys,
|
|
529
745
|
streamKeys: this.streamChannelsAsIs,
|
|
530
|
-
store
|
|
746
|
+
store,
|
|
747
|
+
stream: new loop_js_1.StreamProtocol((chunk) => stream.push(chunk), new Set(streamMode)),
|
|
531
748
|
});
|
|
749
|
+
if (options?.subgraphs) {
|
|
750
|
+
loop.config.configurable = {
|
|
751
|
+
...loop.config.configurable,
|
|
752
|
+
[constants_js_1.CONFIG_KEY_STREAM]: loop.stream,
|
|
753
|
+
};
|
|
754
|
+
}
|
|
532
755
|
while (await loop.tick({
|
|
533
756
|
inputKeys: this.inputChannels,
|
|
534
757
|
interruptAfter,
|
|
@@ -538,27 +761,14 @@ class Pregel extends runnables_1.Runnable {
|
|
|
538
761
|
if (debug) {
|
|
539
762
|
(0, debug_js_1.printStepCheckpoint)(loop.checkpointMetadata.step, loop.channels, this.streamChannelsList);
|
|
540
763
|
}
|
|
541
|
-
|
|
542
|
-
const nextItem = loop.stream.shift();
|
|
543
|
-
if (nextItem === undefined) {
|
|
544
|
-
throw new Error("Data structure error.");
|
|
545
|
-
}
|
|
546
|
-
if (streamMode.includes(nextItem[0])) {
|
|
547
|
-
if (streamMode.length === 1) {
|
|
548
|
-
yield nextItem[1];
|
|
549
|
-
}
|
|
550
|
-
else {
|
|
551
|
-
yield nextItem;
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
}
|
|
764
|
+
yield* emitCurrentLoopOutputs();
|
|
555
765
|
if (debug) {
|
|
556
|
-
(0, debug_js_1.printStepTasks)(loop.step, loop.tasks);
|
|
766
|
+
(0, debug_js_1.printStepTasks)(loop.step, Object.values(loop.tasks));
|
|
557
767
|
}
|
|
558
768
|
// execute tasks, and wait for one to fail or all to finish.
|
|
559
769
|
// each task is independent from all other concurrent tasks
|
|
560
770
|
// yield updates/debug output as each task finishes
|
|
561
|
-
const taskStream = (0, retry_js_1.executeTasksWithRetry)(loop.tasks.filter((task) => task.writes.length === 0), {
|
|
771
|
+
const taskStream = (0, retry_js_1.executeTasksWithRetry)(Object.values(loop.tasks).filter((task) => task.writes.length === 0), {
|
|
562
772
|
stepTimeout: this.stepTimeout,
|
|
563
773
|
signal: config.signal,
|
|
564
774
|
retryPolicy: this.retryPolicy,
|
|
@@ -567,7 +777,12 @@ class Pregel extends runnables_1.Runnable {
|
|
|
567
777
|
for await (const { task, error } of taskStream) {
|
|
568
778
|
if (error !== undefined) {
|
|
569
779
|
if ((0, errors_js_1.isGraphInterrupt)(error)) {
|
|
570
|
-
loop.
|
|
780
|
+
if (loop.isNested) {
|
|
781
|
+
throw error;
|
|
782
|
+
}
|
|
783
|
+
if (error.interrupts.length) {
|
|
784
|
+
loop.putWrites(task.id, error.interrupts.map((interrupt) => [constants_js_1.INTERRUPT, interrupt]));
|
|
785
|
+
}
|
|
571
786
|
}
|
|
572
787
|
else {
|
|
573
788
|
loop.putWrites(task.id, [
|
|
@@ -578,42 +793,18 @@ class Pregel extends runnables_1.Runnable {
|
|
|
578
793
|
else {
|
|
579
794
|
loop.putWrites(task.id, task.writes);
|
|
580
795
|
}
|
|
581
|
-
|
|
582
|
-
const nextItem = loop.stream.shift();
|
|
583
|
-
if (nextItem === undefined) {
|
|
584
|
-
throw new Error("Data structure error.");
|
|
585
|
-
}
|
|
586
|
-
if (streamMode.includes(nextItem[0])) {
|
|
587
|
-
if (streamMode.length === 1) {
|
|
588
|
-
yield nextItem[1];
|
|
589
|
-
}
|
|
590
|
-
else {
|
|
591
|
-
yield nextItem;
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
}
|
|
796
|
+
yield* emitCurrentLoopOutputs();
|
|
595
797
|
if (error !== undefined && !(0, errors_js_1.isGraphInterrupt)(error)) {
|
|
596
798
|
throw error;
|
|
597
799
|
}
|
|
598
800
|
}
|
|
599
801
|
if (debug) {
|
|
600
|
-
(0, debug_js_1.printStepWrites)(loop.step, loop.tasks
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
while (loop.stream.length > 0) {
|
|
604
|
-
const nextItem = loop.stream.shift();
|
|
605
|
-
if (nextItem === undefined) {
|
|
606
|
-
throw new Error("Data structure error.");
|
|
607
|
-
}
|
|
608
|
-
if (streamMode.includes(nextItem[0])) {
|
|
609
|
-
if (streamMode.length === 1) {
|
|
610
|
-
yield nextItem[1];
|
|
611
|
-
}
|
|
612
|
-
else {
|
|
613
|
-
yield nextItem;
|
|
614
|
-
}
|
|
802
|
+
(0, debug_js_1.printStepWrites)(loop.step, Object.values(loop.tasks)
|
|
803
|
+
.map((task) => task.writes)
|
|
804
|
+
.flat(), this.streamChannelsList);
|
|
615
805
|
}
|
|
616
806
|
}
|
|
807
|
+
yield* emitCurrentLoopOutputs();
|
|
617
808
|
if (loop.status === "out_of_steps") {
|
|
618
809
|
throw new errors_js_1.GraphRecursionError([
|
|
619
810
|
`Recursion limit of ${config.recursionLimit} reached`,
|
|
@@ -622,7 +813,7 @@ class Pregel extends runnables_1.Runnable {
|
|
|
622
813
|
].join(" "));
|
|
623
814
|
}
|
|
624
815
|
await Promise.all(loop?.checkpointerPromises ?? []);
|
|
625
|
-
await runManager?.handleChainEnd(
|
|
816
|
+
await runManager?.handleChainEnd(loop.output);
|
|
626
817
|
}
|
|
627
818
|
catch (e) {
|
|
628
819
|
await runManager?.handleChainError(e);
|
|
@@ -631,7 +822,7 @@ class Pregel extends runnables_1.Runnable {
|
|
|
631
822
|
finally {
|
|
632
823
|
// Call `.stop()` again incase it was not called in the loop, e.g due to an error.
|
|
633
824
|
if (loop) {
|
|
634
|
-
loop.store?.stop();
|
|
825
|
+
await loop.store?.stop();
|
|
635
826
|
}
|
|
636
827
|
await Promise.all([
|
|
637
828
|
loop?.checkpointerPromises ?? [],
|
|
@@ -657,7 +848,7 @@ class Pregel extends runnables_1.Runnable {
|
|
|
657
848
|
async invoke(input, options) {
|
|
658
849
|
const streamMode = options?.streamMode ?? "values";
|
|
659
850
|
const config = {
|
|
660
|
-
...
|
|
851
|
+
...options,
|
|
661
852
|
outputKeys: options?.outputKeys ?? this.outputChannels,
|
|
662
853
|
streamMode,
|
|
663
854
|
};
|