@langchain/langgraph 0.2.7 → 0.2.9
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 +12 -2
- package/dist/constants.d.ts +7 -1
- package/dist/constants.js +11 -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 +9 -7
- package/dist/graph/state.d.ts +2 -2
- package/dist/graph/state.js +10 -8
- package/dist/managed/shared_value.cjs +1 -1
- package/dist/managed/shared_value.js +1 -1
- package/dist/pregel/algo.cjs +119 -54
- package/dist/pregel/algo.d.ts +5 -2
- package/dist/pregel/algo.js +117 -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 +295 -123
- package/dist/pregel/index.d.ts +16 -5
- package/dist/pregel/index.js +292 -123
- 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 +256 -111
- package/dist/pregel/loop.d.ts +21 -5
- package/dist/pregel/loop.js +256 -109
- package/dist/pregel/read.cjs +9 -2
- package/dist/pregel/read.d.ts +2 -1
- package/dist/pregel/read.js +9 -2
- package/dist/pregel/retry.d.ts +1 -1
- package/dist/pregel/types.d.ts +5 -2
- package/dist/pregel/utils/config.cjs +72 -0
- package/dist/pregel/utils/config.d.ts +2 -0
- package/dist/pregel/utils/config.js +68 -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.d.ts +2 -1
- package/package.json +1 -1
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";
|
|
@@ -113,12 +128,6 @@ class Pregel extends runnables_1.Runnable {
|
|
|
113
128
|
writable: true,
|
|
114
129
|
value: void 0
|
|
115
130
|
});
|
|
116
|
-
Object.defineProperty(this, "configKeys", {
|
|
117
|
-
enumerable: true,
|
|
118
|
-
configurable: true,
|
|
119
|
-
writable: true,
|
|
120
|
-
value: void 0
|
|
121
|
-
});
|
|
122
131
|
Object.defineProperty(this, "autoValidate", {
|
|
123
132
|
enumerable: true,
|
|
124
133
|
configurable: true,
|
|
@@ -173,6 +182,12 @@ class Pregel extends runnables_1.Runnable {
|
|
|
173
182
|
writable: true,
|
|
174
183
|
value: void 0
|
|
175
184
|
});
|
|
185
|
+
Object.defineProperty(this, "config", {
|
|
186
|
+
enumerable: true,
|
|
187
|
+
configurable: true,
|
|
188
|
+
writable: true,
|
|
189
|
+
value: void 0
|
|
190
|
+
});
|
|
176
191
|
Object.defineProperty(this, "store", {
|
|
177
192
|
enumerable: true,
|
|
178
193
|
configurable: true,
|
|
@@ -189,7 +204,6 @@ class Pregel extends runnables_1.Runnable {
|
|
|
189
204
|
this.streamMode = streamMode ?? this.streamMode;
|
|
190
205
|
this.inputChannels = fields.inputChannels;
|
|
191
206
|
this.outputChannels = fields.outputChannels;
|
|
192
|
-
this.configKeys = fields.configKeys;
|
|
193
207
|
this.streamChannels = fields.streamChannels ?? this.streamChannels;
|
|
194
208
|
this.interruptAfter = fields.interruptAfter;
|
|
195
209
|
this.interruptBefore = fields.interruptBefore;
|
|
@@ -197,11 +211,18 @@ class Pregel extends runnables_1.Runnable {
|
|
|
197
211
|
this.debug = fields.debug ?? this.debug;
|
|
198
212
|
this.checkpointer = fields.checkpointer;
|
|
199
213
|
this.retryPolicy = fields.retryPolicy;
|
|
214
|
+
this.config = fields.config;
|
|
200
215
|
this.store = fields.store;
|
|
201
216
|
if (this.autoValidate) {
|
|
202
217
|
this.validate();
|
|
203
218
|
}
|
|
204
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
|
+
}
|
|
205
226
|
validate() {
|
|
206
227
|
(0, validate_js_1.validateGraph)({
|
|
207
228
|
nodes: this.nodes,
|
|
@@ -233,50 +254,181 @@ class Pregel extends runnables_1.Runnable {
|
|
|
233
254
|
return Object.keys(this.channels);
|
|
234
255
|
}
|
|
235
256
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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
|
+
};
|
|
242
311
|
}
|
|
243
|
-
const saved = await this.checkpointer.getTuple(config);
|
|
244
|
-
const checkpoint = saved ? saved.checkpoint : (0, langgraph_checkpoint_1.emptyCheckpoint)();
|
|
245
|
-
const channels = (0, base_js_1.emptyChannels)(this.channels, checkpoint);
|
|
246
312
|
// Pass `skipManaged: true` as managed values should not be returned in get state calls.
|
|
247
313
|
const { managed } = await this.prepareSpecs(config, { skipManaged: true });
|
|
248
|
-
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
|
|
249
354
|
return {
|
|
250
355
|
values: (0, io_js_1.readChannels)(channels, this.streamChannelsAsIs),
|
|
251
356
|
next: nextTasks.map((task) => task.name),
|
|
252
|
-
tasks: (0, debug_js_1.tasksWithWrites)(nextTasks, saved?.pendingWrites ?? []),
|
|
253
|
-
metadata: saved
|
|
254
|
-
config:
|
|
255
|
-
createdAt: saved
|
|
256
|
-
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,
|
|
257
362
|
};
|
|
258
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
|
+
}
|
|
259
398
|
/**
|
|
260
399
|
* Get the history of the state of the graph.
|
|
261
400
|
*/
|
|
262
401
|
async *getStateHistory(config, options) {
|
|
263
|
-
|
|
264
|
-
|
|
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.`);
|
|
265
423
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
tasks: (0, debug_js_1.tasksWithWrites)(nextTasks, saved.pendingWrites ?? []),
|
|
275
|
-
metadata: saved.metadata,
|
|
276
|
-
config: saved.config,
|
|
277
|
-
createdAt: saved.checkpoint.ts,
|
|
278
|
-
parentConfig: saved.parentConfig,
|
|
279
|
-
};
|
|
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
|
+
});
|
|
280
432
|
}
|
|
281
433
|
}
|
|
282
434
|
/**
|
|
@@ -284,34 +436,59 @@ class Pregel extends runnables_1.Runnable {
|
|
|
284
436
|
* node `as_node`. If `as_node` is not provided, it will be set to the last node
|
|
285
437
|
* that updated the state, if not ambiguous.
|
|
286
438
|
*/
|
|
287
|
-
async updateState(
|
|
288
|
-
|
|
439
|
+
async updateState(inputConfig, values, asNode) {
|
|
440
|
+
const checkpointer = inputConfig.configurable?.[constants_js_1.CONFIG_KEY_CHECKPOINTER] ?? this.checkpointer;
|
|
441
|
+
if (!checkpointer) {
|
|
289
442
|
throw new errors_js_1.GraphValueError("No checkpointer set");
|
|
290
443
|
}
|
|
291
|
-
//
|
|
292
|
-
const
|
|
293
|
-
|
|
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
|
|
294
470
|
? (0, langgraph_checkpoint_1.copyCheckpoint)(saved.checkpoint)
|
|
295
471
|
: (0, langgraph_checkpoint_1.emptyCheckpoint)();
|
|
296
|
-
const checkpointPreviousVersions =
|
|
472
|
+
const checkpointPreviousVersions = {
|
|
473
|
+
...saved?.checkpoint.channel_versions,
|
|
474
|
+
};
|
|
297
475
|
const step = saved?.metadata?.step ?? -1;
|
|
298
476
|
// merge configurable fields with previous checkpoint config
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
...saved?.config.configurable,
|
|
306
|
-
},
|
|
307
|
-
};
|
|
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
|
+
}
|
|
308
483
|
// Find last node that updated the state, if not provided
|
|
309
484
|
if (values == null && asNode === undefined) {
|
|
310
|
-
|
|
485
|
+
const nextConfig = await checkpointer.put(checkpointConfig, (0, base_js_1.createCheckpoint)(checkpoint, undefined, step), {
|
|
311
486
|
source: "update",
|
|
312
487
|
step,
|
|
313
488
|
writes: {},
|
|
489
|
+
parents: saved?.metadata?.parents ?? {},
|
|
314
490
|
}, {});
|
|
491
|
+
return (0, index_js_1.patchCheckpointMap)(nextConfig, saved ? saved.metadata : undefined);
|
|
315
492
|
}
|
|
316
493
|
const nonNullVersion = Object.values(checkpoint.versions_seen)
|
|
317
494
|
.map((seenVersions) => {
|
|
@@ -326,7 +503,6 @@ class Pregel extends runnables_1.Runnable {
|
|
|
326
503
|
}
|
|
327
504
|
}
|
|
328
505
|
else if (asNode === undefined) {
|
|
329
|
-
// TODO: Double check
|
|
330
506
|
const lastSeenByNode = Object.entries(checkpoint.versions_seen)
|
|
331
507
|
.map(([n, seen]) => {
|
|
332
508
|
return Object.values(seen).map((v) => {
|
|
@@ -383,18 +559,21 @@ class Pregel extends runnables_1.Runnable {
|
|
|
383
559
|
task, select_, fresh_),
|
|
384
560
|
},
|
|
385
561
|
}));
|
|
562
|
+
// save task writes
|
|
386
563
|
if (saved !== undefined) {
|
|
387
|
-
await
|
|
564
|
+
await checkpointer.putWrites(checkpointConfig, task.writes, task.id);
|
|
388
565
|
}
|
|
389
566
|
// apply to checkpoint
|
|
390
567
|
// TODO: Why does keyof StrRecord allow number and symbol?
|
|
391
|
-
(0, algo_js_1._applyWrites)(checkpoint, channels, [task],
|
|
392
|
-
const newVersions = (0,
|
|
393
|
-
|
|
568
|
+
(0, algo_js_1._applyWrites)(checkpoint, channels, [task], checkpointer.getNextVersion.bind(this.checkpointer));
|
|
569
|
+
const newVersions = (0, index_js_1.getNewChannelVersions)(checkpointPreviousVersions, checkpoint.channel_versions);
|
|
570
|
+
const nextConfig = await checkpointer.put(checkpointConfig, (0, base_js_1.createCheckpoint)(checkpoint, channels, step + 1), {
|
|
394
571
|
source: "update",
|
|
395
572
|
step: step + 1,
|
|
396
573
|
writes: { [asNode]: values },
|
|
574
|
+
parents: saved?.metadata?.parents ?? {},
|
|
397
575
|
}, newVersions);
|
|
576
|
+
return (0, index_js_1.patchCheckpointMap)(nextConfig, saved ? saved.metadata : undefined);
|
|
398
577
|
}
|
|
399
578
|
_defaults(config) {
|
|
400
579
|
const { debug, streamMode, inputKeys, outputKeys, interruptAfter, interruptBefore, ...rest } = config;
|
|
@@ -422,25 +601,18 @@ class Pregel extends runnables_1.Runnable {
|
|
|
422
601
|
else {
|
|
423
602
|
defaultStreamMode = this.streamMode;
|
|
424
603
|
}
|
|
425
|
-
|
|
426
|
-
if (config.configurable !== undefined
|
|
427
|
-
config.configurable[constants_js_1.CONFIG_KEY_READ] !== undefined) {
|
|
604
|
+
// if being called as a node in another graph, always use values mode
|
|
605
|
+
if (config.configurable?.[constants_js_1.CONFIG_KEY_TASK_ID] !== undefined) {
|
|
428
606
|
defaultStreamMode = ["values"];
|
|
429
607
|
}
|
|
608
|
+
let defaultCheckpointer;
|
|
430
609
|
if (config !== undefined &&
|
|
431
|
-
config.configurable?.[constants_js_1.CONFIG_KEY_CHECKPOINTER] !== undefined
|
|
432
|
-
(defaultInterruptAfter.length > 0 || defaultInterruptBefore.length > 0)) {
|
|
610
|
+
config.configurable?.[constants_js_1.CONFIG_KEY_CHECKPOINTER] !== undefined) {
|
|
433
611
|
defaultCheckpointer = config.configurable[constants_js_1.CONFIG_KEY_CHECKPOINTER];
|
|
434
612
|
}
|
|
435
613
|
else {
|
|
436
614
|
defaultCheckpointer = this.checkpointer;
|
|
437
615
|
}
|
|
438
|
-
if (this.configKeys !== undefined) {
|
|
439
|
-
const newConfigurable = Object.fromEntries(Object.entries(rest.configurable ?? {}).filter(([key]) => {
|
|
440
|
-
return this.configKeys?.includes(key);
|
|
441
|
-
}));
|
|
442
|
-
rest.configurable = newConfigurable;
|
|
443
|
-
}
|
|
444
616
|
return [
|
|
445
617
|
defaultDebug,
|
|
446
618
|
defaultStreamMode,
|
|
@@ -471,7 +643,7 @@ class Pregel extends runnables_1.Runnable {
|
|
|
471
643
|
return super.stream(input, options);
|
|
472
644
|
}
|
|
473
645
|
async prepareSpecs(config, options) {
|
|
474
|
-
const configForManaged = (0,
|
|
646
|
+
const configForManaged = (0, utils_js_1.patchConfigurable)(config, {
|
|
475
647
|
[constants_js_1.CONFIG_KEY_STORE]: this.store,
|
|
476
648
|
});
|
|
477
649
|
const channelSpecs = {};
|
|
@@ -514,7 +686,8 @@ class Pregel extends runnables_1.Runnable {
|
|
|
514
686
|
};
|
|
515
687
|
}
|
|
516
688
|
async *_streamIterator(input, options) {
|
|
517
|
-
const
|
|
689
|
+
const streamSubgraphs = options?.subgraphs;
|
|
690
|
+
const inputConfig = (0, config_js_1.ensureLangGraphConfig)(this.config, options);
|
|
518
691
|
if (inputConfig.recursionLimit === undefined ||
|
|
519
692
|
inputConfig.recursionLimit < 1) {
|
|
520
693
|
throw new Error(`Passed "recursionLimit" must be at least 1.`);
|
|
@@ -524,12 +697,36 @@ class Pregel extends runnables_1.Runnable {
|
|
|
524
697
|
throw new Error(`Checkpointer requires one or more of the following "configurable" keys: "thread_id", "checkpoint_ns", "checkpoint_id"`);
|
|
525
698
|
}
|
|
526
699
|
const callbackManager = await (0, runnables_1.getCallbackManagerForConfig)(inputConfig);
|
|
527
|
-
const runManager = await callbackManager?.handleChainStart(this.toJSON(), (0,
|
|
700
|
+
const runManager = await callbackManager?.handleChainStart(this.toJSON(), (0, index_js_1._coerceToDict)(input, "input"), inputConfig.runId, undefined, undefined, undefined, inputConfig?.runName ?? this.getName());
|
|
528
701
|
delete inputConfig.runId;
|
|
529
702
|
// assign defaults
|
|
530
703
|
const [debug, streamMode, , outputKeys, config, interruptBefore, interruptAfter, checkpointer,] = this._defaults(inputConfig);
|
|
531
704
|
const { channelSpecs, managed } = await this.prepareSpecs(config);
|
|
532
705
|
let loop;
|
|
706
|
+
const stream = new double_ended_queue_1.default();
|
|
707
|
+
function* emitCurrentLoopOutputs() {
|
|
708
|
+
while (loop !== undefined && stream.length > 0) {
|
|
709
|
+
const nextItem = stream.shift();
|
|
710
|
+
if (nextItem === undefined) {
|
|
711
|
+
throw new Error("Data structure error.");
|
|
712
|
+
}
|
|
713
|
+
const [namespace, mode, payload] = nextItem;
|
|
714
|
+
if (streamMode.includes(mode)) {
|
|
715
|
+
if (streamSubgraphs && streamMode.length > 1) {
|
|
716
|
+
yield [namespace, mode, payload];
|
|
717
|
+
}
|
|
718
|
+
else if (streamMode.length > 1) {
|
|
719
|
+
yield [mode, payload];
|
|
720
|
+
}
|
|
721
|
+
else if (streamSubgraphs) {
|
|
722
|
+
yield [namespace, payload];
|
|
723
|
+
}
|
|
724
|
+
else {
|
|
725
|
+
yield payload;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
}
|
|
533
730
|
try {
|
|
534
731
|
loop = await loop_js_1.PregelLoop.initialize({
|
|
535
732
|
input,
|
|
@@ -541,7 +738,14 @@ class Pregel extends runnables_1.Runnable {
|
|
|
541
738
|
outputKeys,
|
|
542
739
|
streamKeys: this.streamChannelsAsIs,
|
|
543
740
|
store: this.store,
|
|
741
|
+
stream: new loop_js_1.StreamProtocol((chunk) => stream.push(chunk), new Set(streamMode)),
|
|
544
742
|
});
|
|
743
|
+
if (options?.subgraphs) {
|
|
744
|
+
loop.config.configurable = {
|
|
745
|
+
...loop.config.configurable,
|
|
746
|
+
[constants_js_1.CONFIG_KEY_STREAM]: loop.stream,
|
|
747
|
+
};
|
|
748
|
+
}
|
|
545
749
|
while (await loop.tick({
|
|
546
750
|
inputKeys: this.inputChannels,
|
|
547
751
|
interruptAfter,
|
|
@@ -551,27 +755,14 @@ class Pregel extends runnables_1.Runnable {
|
|
|
551
755
|
if (debug) {
|
|
552
756
|
(0, debug_js_1.printStepCheckpoint)(loop.checkpointMetadata.step, loop.channels, this.streamChannelsList);
|
|
553
757
|
}
|
|
554
|
-
|
|
555
|
-
const nextItem = loop.stream.shift();
|
|
556
|
-
if (nextItem === undefined) {
|
|
557
|
-
throw new Error("Data structure error.");
|
|
558
|
-
}
|
|
559
|
-
if (streamMode.includes(nextItem[0])) {
|
|
560
|
-
if (streamMode.length === 1) {
|
|
561
|
-
yield nextItem[1];
|
|
562
|
-
}
|
|
563
|
-
else {
|
|
564
|
-
yield nextItem;
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
}
|
|
758
|
+
yield* emitCurrentLoopOutputs();
|
|
568
759
|
if (debug) {
|
|
569
|
-
(0, debug_js_1.printStepTasks)(loop.step, loop.tasks);
|
|
760
|
+
(0, debug_js_1.printStepTasks)(loop.step, Object.values(loop.tasks));
|
|
570
761
|
}
|
|
571
762
|
// execute tasks, and wait for one to fail or all to finish.
|
|
572
763
|
// each task is independent from all other concurrent tasks
|
|
573
764
|
// yield updates/debug output as each task finishes
|
|
574
|
-
const taskStream = (0, retry_js_1.executeTasksWithRetry)(loop.tasks.filter((task) => task.writes.length === 0), {
|
|
765
|
+
const taskStream = (0, retry_js_1.executeTasksWithRetry)(Object.values(loop.tasks).filter((task) => task.writes.length === 0), {
|
|
575
766
|
stepTimeout: this.stepTimeout,
|
|
576
767
|
signal: config.signal,
|
|
577
768
|
retryPolicy: this.retryPolicy,
|
|
@@ -580,7 +771,12 @@ class Pregel extends runnables_1.Runnable {
|
|
|
580
771
|
for await (const { task, error } of taskStream) {
|
|
581
772
|
if (error !== undefined) {
|
|
582
773
|
if ((0, errors_js_1.isGraphInterrupt)(error)) {
|
|
583
|
-
loop.
|
|
774
|
+
if (loop.isNested) {
|
|
775
|
+
throw error;
|
|
776
|
+
}
|
|
777
|
+
if (error.interrupts.length) {
|
|
778
|
+
loop.putWrites(task.id, error.interrupts.map((interrupt) => [constants_js_1.INTERRUPT, interrupt]));
|
|
779
|
+
}
|
|
584
780
|
}
|
|
585
781
|
else {
|
|
586
782
|
loop.putWrites(task.id, [
|
|
@@ -591,42 +787,18 @@ class Pregel extends runnables_1.Runnable {
|
|
|
591
787
|
else {
|
|
592
788
|
loop.putWrites(task.id, task.writes);
|
|
593
789
|
}
|
|
594
|
-
|
|
595
|
-
const nextItem = loop.stream.shift();
|
|
596
|
-
if (nextItem === undefined) {
|
|
597
|
-
throw new Error("Data structure error.");
|
|
598
|
-
}
|
|
599
|
-
if (streamMode.includes(nextItem[0])) {
|
|
600
|
-
if (streamMode.length === 1) {
|
|
601
|
-
yield nextItem[1];
|
|
602
|
-
}
|
|
603
|
-
else {
|
|
604
|
-
yield nextItem;
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
}
|
|
790
|
+
yield* emitCurrentLoopOutputs();
|
|
608
791
|
if (error !== undefined && !(0, errors_js_1.isGraphInterrupt)(error)) {
|
|
609
792
|
throw error;
|
|
610
793
|
}
|
|
611
794
|
}
|
|
612
795
|
if (debug) {
|
|
613
|
-
(0, debug_js_1.printStepWrites)(loop.step, loop.tasks
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
while (loop.stream.length > 0) {
|
|
617
|
-
const nextItem = loop.stream.shift();
|
|
618
|
-
if (nextItem === undefined) {
|
|
619
|
-
throw new Error("Data structure error.");
|
|
620
|
-
}
|
|
621
|
-
if (streamMode.includes(nextItem[0])) {
|
|
622
|
-
if (streamMode.length === 1) {
|
|
623
|
-
yield nextItem[1];
|
|
624
|
-
}
|
|
625
|
-
else {
|
|
626
|
-
yield nextItem;
|
|
627
|
-
}
|
|
796
|
+
(0, debug_js_1.printStepWrites)(loop.step, Object.values(loop.tasks)
|
|
797
|
+
.map((task) => task.writes)
|
|
798
|
+
.flat(), this.streamChannelsList);
|
|
628
799
|
}
|
|
629
800
|
}
|
|
801
|
+
yield* emitCurrentLoopOutputs();
|
|
630
802
|
if (loop.status === "out_of_steps") {
|
|
631
803
|
throw new errors_js_1.GraphRecursionError([
|
|
632
804
|
`Recursion limit of ${config.recursionLimit} reached`,
|
|
@@ -635,7 +807,7 @@ class Pregel extends runnables_1.Runnable {
|
|
|
635
807
|
].join(" "));
|
|
636
808
|
}
|
|
637
809
|
await Promise.all(loop?.checkpointerPromises ?? []);
|
|
638
|
-
await runManager?.handleChainEnd(
|
|
810
|
+
await runManager?.handleChainEnd(loop.output);
|
|
639
811
|
}
|
|
640
812
|
catch (e) {
|
|
641
813
|
await runManager?.handleChainError(e);
|
|
@@ -670,7 +842,7 @@ class Pregel extends runnables_1.Runnable {
|
|
|
670
842
|
async invoke(input, options) {
|
|
671
843
|
const streamMode = options?.streamMode ?? "values";
|
|
672
844
|
const config = {
|
|
673
|
-
...
|
|
845
|
+
...options,
|
|
674
846
|
outputKeys: options?.outputKeys ?? this.outputChannels,
|
|
675
847
|
streamMode,
|
|
676
848
|
};
|