@langchain/langgraph 0.2.8 → 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.
Files changed (45) hide show
  1. package/dist/constants.cjs +12 -2
  2. package/dist/constants.d.ts +7 -1
  3. package/dist/constants.js +11 -1
  4. package/dist/errors.cjs +5 -4
  5. package/dist/errors.d.ts +1 -1
  6. package/dist/errors.js +5 -4
  7. package/dist/graph/graph.cjs +7 -2
  8. package/dist/graph/graph.js +8 -3
  9. package/dist/graph/message.cjs +2 -0
  10. package/dist/graph/message.js +2 -0
  11. package/dist/graph/state.cjs +8 -3
  12. package/dist/graph/state.d.ts +1 -1
  13. package/dist/graph/state.js +9 -4
  14. package/dist/managed/shared_value.cjs +1 -1
  15. package/dist/managed/shared_value.js +1 -1
  16. package/dist/pregel/algo.cjs +119 -54
  17. package/dist/pregel/algo.d.ts +5 -2
  18. package/dist/pregel/algo.js +117 -53
  19. package/dist/pregel/debug.cjs +15 -18
  20. package/dist/pregel/debug.d.ts +3 -2
  21. package/dist/pregel/debug.js +16 -19
  22. package/dist/pregel/index.cjs +295 -110
  23. package/dist/pregel/index.d.ts +16 -4
  24. package/dist/pregel/index.js +292 -110
  25. package/dist/pregel/io.cjs +15 -8
  26. package/dist/pregel/io.d.ts +2 -2
  27. package/dist/pregel/io.js +15 -8
  28. package/dist/pregel/loop.cjs +256 -111
  29. package/dist/pregel/loop.d.ts +21 -5
  30. package/dist/pregel/loop.js +256 -109
  31. package/dist/pregel/read.cjs +9 -2
  32. package/dist/pregel/read.d.ts +2 -1
  33. package/dist/pregel/read.js +9 -2
  34. package/dist/pregel/retry.d.ts +1 -1
  35. package/dist/pregel/types.d.ts +5 -1
  36. package/dist/pregel/utils/config.cjs +72 -0
  37. package/dist/pregel/utils/config.d.ts +2 -0
  38. package/dist/pregel/utils/config.js +68 -0
  39. package/dist/pregel/{utils.cjs → utils/index.cjs} +33 -10
  40. package/dist/pregel/{utils.d.ts → utils/index.d.ts} +4 -7
  41. package/dist/pregel/{utils.js → utils/index.js} +30 -8
  42. package/dist/utils.cjs +5 -3
  43. package/dist/utils.js +5 -3
  44. package/dist/web.d.ts +2 -1
  45. package/package.json +1 -1
@@ -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 utils_js_1 = require("./utils.cjs");
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 utils_js_2 = require("../utils.cjs");
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
- * Get the current state of the graph.
231
- */
232
- async getState(config) {
233
- if (!this.checkpointer) {
234
- throw new errors_js_1.GraphValueError("No checkpointer set");
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 nextTasks = (0, algo_js_1._prepareNextTasks)(checkpoint, this.nodes, channels, managed, saved !== undefined ? saved.config : config, false, { step: saved ? (saved.metadata?.step ?? -1) + 1 : -1 });
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?.metadata,
247
- config: saved ? saved.config : config,
248
- createdAt: saved?.checkpoint.ts,
249
- parentConfig: saved?.parentConfig,
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
- if (!this.checkpointer) {
257
- throw new errors_js_1.GraphValueError("No checkpointer set");
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
- // Pass `skipManaged: true` as managed values should not be returned in get state calls.
260
- const { managed } = await this.prepareSpecs(config, { skipManaged: true });
261
- for await (const saved of this.checkpointer.list(config, options)) {
262
- const channels = (0, base_js_1.emptyChannels)(this.channels, saved.checkpoint);
263
- const nextTasks = (0, algo_js_1._prepareNextTasks)(saved.checkpoint, this.nodes, channels, managed, saved.config, false, { step: -1 });
264
- yield {
265
- values: (0, io_js_1.readChannels)(channels, this.streamChannelsAsIs),
266
- next: nextTasks.map((task) => task.name),
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(config, values, asNode) {
281
- if (!this.checkpointer) {
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
- // Get the latest checkpoint
285
- const saved = await this.checkpointer.getTuple(config);
286
- const checkpoint = saved
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 = saved?.checkpoint.channel_versions ?? {};
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
- const checkpointConfig = {
293
- ...config,
294
- configurable: {
295
- ...config.configurable,
296
- // TODO: add proper support for updating nested subgraph state
297
- checkpoint_ns: "",
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
- return await this.checkpointer.put(checkpointConfig, (0, base_js_1.createCheckpoint)(checkpoint, undefined, step), {
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) => {
@@ -376,18 +559,21 @@ class Pregel extends runnables_1.Runnable {
376
559
  task, select_, fresh_),
377
560
  },
378
561
  }));
562
+ // save task writes
379
563
  if (saved !== undefined) {
380
- await this.checkpointer.putWrites(checkpointConfig, task.writes, task.id);
564
+ await checkpointer.putWrites(checkpointConfig, task.writes, task.id);
381
565
  }
382
566
  // apply to checkpoint
383
567
  // TODO: Why does keyof StrRecord allow number and symbol?
384
- (0, algo_js_1._applyWrites)(checkpoint, channels, [task], this.checkpointer.getNextVersion.bind(this.checkpointer));
385
- const newVersions = (0, utils_js_1.getNewChannelVersions)(checkpointPreviousVersions, checkpoint.channel_versions);
386
- return await this.checkpointer.put(checkpointConfig, (0, base_js_1.createCheckpoint)(checkpoint, channels, step + 1), {
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), {
387
571
  source: "update",
388
572
  step: step + 1,
389
573
  writes: { [asNode]: values },
574
+ parents: saved?.metadata?.parents ?? {},
390
575
  }, newVersions);
576
+ return (0, index_js_1.patchCheckpointMap)(nextConfig, saved ? saved.metadata : undefined);
391
577
  }
392
578
  _defaults(config) {
393
579
  const { debug, streamMode, inputKeys, outputKeys, interruptAfter, interruptBefore, ...rest } = config;
@@ -415,14 +601,13 @@ class Pregel extends runnables_1.Runnable {
415
601
  else {
416
602
  defaultStreamMode = this.streamMode;
417
603
  }
418
- let defaultCheckpointer;
419
- if (config.configurable !== undefined &&
420
- 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) {
421
606
  defaultStreamMode = ["values"];
422
607
  }
608
+ let defaultCheckpointer;
423
609
  if (config !== undefined &&
424
- config.configurable?.[constants_js_1.CONFIG_KEY_CHECKPOINTER] !== undefined &&
425
- (defaultInterruptAfter.length > 0 || defaultInterruptBefore.length > 0)) {
610
+ config.configurable?.[constants_js_1.CONFIG_KEY_CHECKPOINTER] !== undefined) {
426
611
  defaultCheckpointer = config.configurable[constants_js_1.CONFIG_KEY_CHECKPOINTER];
427
612
  }
428
613
  else {
@@ -458,7 +643,7 @@ class Pregel extends runnables_1.Runnable {
458
643
  return super.stream(input, options);
459
644
  }
460
645
  async prepareSpecs(config, options) {
461
- const configForManaged = (0, utils_js_2.patchConfigurable)(config, {
646
+ const configForManaged = (0, utils_js_1.patchConfigurable)(config, {
462
647
  [constants_js_1.CONFIG_KEY_STORE]: this.store,
463
648
  });
464
649
  const channelSpecs = {};
@@ -501,7 +686,8 @@ class Pregel extends runnables_1.Runnable {
501
686
  };
502
687
  }
503
688
  async *_streamIterator(input, options) {
504
- const inputConfig = (0, runnables_1.ensureConfig)(options);
689
+ const streamSubgraphs = options?.subgraphs;
690
+ const inputConfig = (0, config_js_1.ensureLangGraphConfig)(this.config, options);
505
691
  if (inputConfig.recursionLimit === undefined ||
506
692
  inputConfig.recursionLimit < 1) {
507
693
  throw new Error(`Passed "recursionLimit" must be at least 1.`);
@@ -511,12 +697,36 @@ class Pregel extends runnables_1.Runnable {
511
697
  throw new Error(`Checkpointer requires one or more of the following "configurable" keys: "thread_id", "checkpoint_ns", "checkpoint_id"`);
512
698
  }
513
699
  const callbackManager = await (0, runnables_1.getCallbackManagerForConfig)(inputConfig);
514
- const runManager = await callbackManager?.handleChainStart(this.toJSON(), (0, utils_js_1._coerceToDict)(input, "input"), inputConfig.runId, undefined, undefined, undefined, inputConfig?.runName ?? this.getName());
700
+ const runManager = await callbackManager?.handleChainStart(this.toJSON(), (0, index_js_1._coerceToDict)(input, "input"), inputConfig.runId, undefined, undefined, undefined, inputConfig?.runName ?? this.getName());
515
701
  delete inputConfig.runId;
516
702
  // assign defaults
517
703
  const [debug, streamMode, , outputKeys, config, interruptBefore, interruptAfter, checkpointer,] = this._defaults(inputConfig);
518
704
  const { channelSpecs, managed } = await this.prepareSpecs(config);
519
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
+ }
520
730
  try {
521
731
  loop = await loop_js_1.PregelLoop.initialize({
522
732
  input,
@@ -528,7 +738,14 @@ class Pregel extends runnables_1.Runnable {
528
738
  outputKeys,
529
739
  streamKeys: this.streamChannelsAsIs,
530
740
  store: this.store,
741
+ stream: new loop_js_1.StreamProtocol((chunk) => stream.push(chunk), new Set(streamMode)),
531
742
  });
743
+ if (options?.subgraphs) {
744
+ loop.config.configurable = {
745
+ ...loop.config.configurable,
746
+ [constants_js_1.CONFIG_KEY_STREAM]: loop.stream,
747
+ };
748
+ }
532
749
  while (await loop.tick({
533
750
  inputKeys: this.inputChannels,
534
751
  interruptAfter,
@@ -538,27 +755,14 @@ class Pregel extends runnables_1.Runnable {
538
755
  if (debug) {
539
756
  (0, debug_js_1.printStepCheckpoint)(loop.checkpointMetadata.step, loop.channels, this.streamChannelsList);
540
757
  }
541
- while (loop.stream.length > 0) {
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
- }
758
+ yield* emitCurrentLoopOutputs();
555
759
  if (debug) {
556
- (0, debug_js_1.printStepTasks)(loop.step, loop.tasks);
760
+ (0, debug_js_1.printStepTasks)(loop.step, Object.values(loop.tasks));
557
761
  }
558
762
  // execute tasks, and wait for one to fail or all to finish.
559
763
  // each task is independent from all other concurrent tasks
560
764
  // yield updates/debug output as each task finishes
561
- 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), {
562
766
  stepTimeout: this.stepTimeout,
563
767
  signal: config.signal,
564
768
  retryPolicy: this.retryPolicy,
@@ -567,7 +771,12 @@ class Pregel extends runnables_1.Runnable {
567
771
  for await (const { task, error } of taskStream) {
568
772
  if (error !== undefined) {
569
773
  if ((0, errors_js_1.isGraphInterrupt)(error)) {
570
- loop.putWrites(task.id, error.interrupts.map((interrupt) => [constants_js_1.INTERRUPT, interrupt]));
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
+ }
571
780
  }
572
781
  else {
573
782
  loop.putWrites(task.id, [
@@ -578,42 +787,18 @@ class Pregel extends runnables_1.Runnable {
578
787
  else {
579
788
  loop.putWrites(task.id, task.writes);
580
789
  }
581
- while (loop.stream.length > 0) {
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
- }
790
+ yield* emitCurrentLoopOutputs();
595
791
  if (error !== undefined && !(0, errors_js_1.isGraphInterrupt)(error)) {
596
792
  throw error;
597
793
  }
598
794
  }
599
795
  if (debug) {
600
- (0, debug_js_1.printStepWrites)(loop.step, loop.tasks.map((task) => task.writes).flat(), this.streamChannelsList);
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
- }
796
+ (0, debug_js_1.printStepWrites)(loop.step, Object.values(loop.tasks)
797
+ .map((task) => task.writes)
798
+ .flat(), this.streamChannelsList);
615
799
  }
616
800
  }
801
+ yield* emitCurrentLoopOutputs();
617
802
  if (loop.status === "out_of_steps") {
618
803
  throw new errors_js_1.GraphRecursionError([
619
804
  `Recursion limit of ${config.recursionLimit} reached`,
@@ -622,7 +807,7 @@ class Pregel extends runnables_1.Runnable {
622
807
  ].join(" "));
623
808
  }
624
809
  await Promise.all(loop?.checkpointerPromises ?? []);
625
- await runManager?.handleChainEnd((0, io_js_1.readChannels)(loop.channels, outputKeys));
810
+ await runManager?.handleChainEnd(loop.output);
626
811
  }
627
812
  catch (e) {
628
813
  await runManager?.handleChainError(e);
@@ -657,7 +842,7 @@ class Pregel extends runnables_1.Runnable {
657
842
  async invoke(input, options) {
658
843
  const streamMode = options?.streamMode ?? "values";
659
844
  const config = {
660
- ...(0, runnables_1.ensureConfig)(options),
845
+ ...options,
661
846
  outputKeys: options?.outputKeys ?? this.outputChannels,
662
847
  streamMode,
663
848
  };
@@ -1,12 +1,12 @@
1
1
  import { Runnable, RunnableConfig, RunnableFunc } from "@langchain/core/runnables";
2
2
  import { IterableReadableStream } from "@langchain/core/utils/stream";
3
- import { All, BaseCheckpointSaver, CheckpointListOptions } from "@langchain/langgraph-checkpoint";
3
+ import { All, BaseCheckpointSaver, CheckpointListOptions, CheckpointTuple } from "@langchain/langgraph-checkpoint";
4
4
  import { BaseChannel } from "../channels/base.js";
5
5
  import { PregelNode } from "./read.js";
6
6
  import { ChannelWrite } from "./write.js";
7
7
  import { PregelInterface, PregelParams, StateSnapshot, StreamMode } from "./types.js";
8
8
  import { StrRecord } from "./algo.js";
9
- import { RetryPolicy } from "./utils.js";
9
+ import { RetryPolicy } from "./utils/index.js";
10
10
  import { BaseStore } from "../store/base.js";
11
11
  import { ManagedValueMapping, type ManagedValueSpec } from "../managed/base.js";
12
12
  type WriteValue = Runnable | RunnableFunc<unknown, unknown> | unknown;
@@ -35,6 +35,8 @@ export interface PregelOptions<Nn extends StrRecord<string, PregelNode>, Cc exte
35
35
  interruptAfter?: All | Array<keyof Nn>;
36
36
  /** Enable debug mode for the graph run. */
37
37
  debug?: boolean;
38
+ /** Whether to stream subgraphs. */
39
+ subgraphs?: boolean;
38
40
  }
39
41
  export type PregelInputType = any;
40
42
  export type PregelOutputType = any;
@@ -54,15 +56,25 @@ export declare class Pregel<Nn extends StrRecord<string, PregelNode>, Cc extends
54
56
  debug: boolean;
55
57
  checkpointer?: BaseCheckpointSaver;
56
58
  retryPolicy?: RetryPolicy;
59
+ config?: RunnableConfig;
57
60
  store?: BaseStore;
58
61
  constructor(fields: PregelParams<Nn, Cc>);
62
+ withConfig(config: RunnableConfig): typeof this;
59
63
  validate(): this;
60
64
  get streamChannelsList(): Array<keyof Cc>;
61
65
  get streamChannelsAsIs(): keyof Cc | Array<keyof Cc>;
66
+ getSubgraphs(namespace?: string, recurse?: boolean): Generator<[string, Pregel<any, any>]>;
67
+ protected _prepareStateSnapshot({ config, saved, subgraphCheckpointer, }: {
68
+ config: RunnableConfig;
69
+ saved?: CheckpointTuple;
70
+ subgraphCheckpointer?: BaseCheckpointSaver;
71
+ }): Promise<StateSnapshot>;
62
72
  /**
63
73
  * Get the current state of the graph.
64
74
  */
65
- getState(config: RunnableConfig): Promise<StateSnapshot>;
75
+ getState(config: RunnableConfig, options?: {
76
+ subgraphs?: boolean;
77
+ }): Promise<StateSnapshot>;
66
78
  /**
67
79
  * Get the history of the state of the graph.
68
80
  */
@@ -72,7 +84,7 @@ export declare class Pregel<Nn extends StrRecord<string, PregelNode>, Cc extends
72
84
  * node `as_node`. If `as_node` is not provided, it will be set to the last node
73
85
  * that updated the state, if not ambiguous.
74
86
  */
75
- updateState(config: RunnableConfig, values: Record<string, unknown> | unknown, asNode?: keyof Nn): Promise<RunnableConfig>;
87
+ updateState(inputConfig: RunnableConfig, values: Record<string, unknown> | unknown, asNode?: keyof Nn | string): Promise<RunnableConfig>;
76
88
  _defaults(config: PregelOptions<Nn, Cc>): [
77
89
  boolean,
78
90
  StreamMode[],