@langchain/langgraph 1.4.18 → 1.4.20

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.
@@ -424,17 +424,62 @@ var Pregel = class extends PartialRunnable {
424
424
  yield* this.getSubgraphs(namespace, recurse);
425
425
  }
426
426
  /**
427
+ * The checkpointer runs and state methods use: none for `checkpointer: false`,
428
+ * else the one a parent lends a subgraph through the config, else this
429
+ * graph's own.
430
+ */
431
+ _resolveCheckpointer(config) {
432
+ if (this.checkpointer === false) return void 0;
433
+ const lent = config?.configurable?.[require_constants.CONFIG_KEY_CHECKPOINTER];
434
+ if (lent !== void 0) return lent;
435
+ if (this.checkpointer === true) throw new Error("checkpointer: true cannot be used for root graphs.");
436
+ return this.checkpointer;
437
+ }
438
+ _stateCheckpointer(config) {
439
+ const checkpointer = this._resolveCheckpointer(config);
440
+ if (typeof checkpointer !== "object" || checkpointer === null) throw new require_errors.GraphValueError("No checkpointer set", { lc_error_code: "MISSING_CHECKPOINTER" });
441
+ return checkpointer;
442
+ }
443
+ /**
444
+ * A `checkpointer: true` subgraph keeps one history per thread, stored
445
+ * under its namespace with the task ids removed.
446
+ */
447
+ _ownCheckpointConfig(config) {
448
+ if (this.checkpointer !== true) return config;
449
+ const ns = config.configurable?.["checkpoint_ns"] ?? "";
450
+ return {
451
+ ...config,
452
+ configurable: {
453
+ ...config.configurable,
454
+ [require_constants.CONFIG_KEY_CHECKPOINT_NS]: ns.split("|").map((part) => part.split(":")[0]).join("|")
455
+ }
456
+ };
457
+ }
458
+ /**
459
+ * The subgraph a state method's namespaced config addresses, and the config
460
+ * to call it with, lending it `checkpointer`. `undefined` when the config is
461
+ * for this graph, comes from inside a running task, or names no declared
462
+ * subgraph (a dynamically created one, such as a tool-call subgraph).
463
+ */
464
+ async _subgraphForNamespace(config, checkpointer) {
465
+ const checkpointNamespace = config.configurable?.checkpoint_ns ?? "";
466
+ if (checkpointNamespace === "" || config.configurable?.["__pregel_read"] !== void 0 || config.configurable?.["__pregel_checkpointer"] !== void 0) return;
467
+ const recastNamespace = require_config.recastCheckpointNamespace(checkpointNamespace);
468
+ for await (const [name, subgraph] of this.getSubgraphsAsync(recastNamespace, true)) if (name === recastNamespace) return [subgraph, require_utils.patchConfigurable(config, { [require_constants.CONFIG_KEY_CHECKPOINTER]: checkpointer })];
469
+ }
470
+ /**
427
471
  * Prepares a state snapshot from saved checkpoint data.
428
472
  * This is an internal method used by getState and getStateHistory.
429
473
  *
430
474
  * @param config - Configuration for preparing the snapshot
431
475
  * @param saved - Optional saved checkpoint data
432
- * @param subgraphCheckpointer - Optional checkpointer for subgraphs
476
+ * @param saver - Checkpointer the caller resolved; a subgraph's own `checkpointer` is unset or `true`
477
+ * @param recurse - Whether to include each subgraph task's state
433
478
  * @param applyPendingWrites - Whether to apply pending writes to tasks and then to channels
434
479
  * @returns A snapshot of the graph state
435
480
  * @internal
436
481
  */
437
- async _prepareStateSnapshot({ config, saved, subgraphCheckpointer, applyPendingWrites = false }) {
482
+ async _prepareStateSnapshot({ config, saved, saver, recurse = false, applyPendingWrites = false }) {
438
483
  if (saved === void 0) return {
439
484
  values: {},
440
485
  next: [],
@@ -442,8 +487,9 @@ var Pregel = class extends PartialRunnable {
442
487
  tasks: []
443
488
  };
444
489
  const channels = await require_base.channelsFromCheckpoint(this.channels, saved.checkpoint, {
445
- saver: typeof this.checkpointer === "object" ? this.checkpointer : void 0,
446
- config: saved.config ?? config
490
+ saver,
491
+ config: saved.config ?? config,
492
+ deltaWritesVersioned: require_base.isDeltaWritesVersioned(saved.metadata)
447
493
  });
448
494
  if (saved.pendingWrites?.length) {
449
495
  const nullWrites = saved.pendingWrites.filter(([taskId, _]) => taskId === require_constants.NULL_TASK_ID).map(([_, channel, value]) => [String(channel), value]);
@@ -462,10 +508,10 @@ var Pregel = class extends PartialRunnable {
462
508
  const taskStates = {};
463
509
  for (const task of nextTasks) {
464
510
  const matchingSubgraph = subgraphs.find(([name]) => name === task.name);
465
- if (!matchingSubgraph) continue;
511
+ if (!matchingSubgraph || matchingSubgraph[1].checkpointer === false) continue;
466
512
  let taskNs = `${String(task.name)}:${task.id}`;
467
513
  if (parentNamespace) taskNs = `${parentNamespace}|${taskNs}`;
468
- if (subgraphCheckpointer === void 0) {
514
+ if (!recurse) {
469
515
  const config = { configurable: {
470
516
  thread_id: saved.config.configurable?.thread_id,
471
517
  checkpoint_ns: taskNs
@@ -473,7 +519,7 @@ var Pregel = class extends PartialRunnable {
473
519
  taskStates[task.id] = config;
474
520
  } else {
475
521
  const subgraphConfig = { configurable: {
476
- [require_constants.CONFIG_KEY_CHECKPOINTER]: subgraphCheckpointer,
522
+ [require_constants.CONFIG_KEY_CHECKPOINTER]: saver,
477
523
  thread_id: saved.config.configurable?.thread_id,
478
524
  checkpoint_ns: taskNs
479
525
  } };
@@ -521,19 +567,20 @@ var Pregel = class extends PartialRunnable {
521
567
  * @throws {GraphValueError} If no checkpointer is configured
522
568
  */
523
569
  async getState(config, options) {
524
- const checkpointer = config.configurable?.["__pregel_checkpointer"] ?? this.checkpointer;
525
- if (!checkpointer) throw new require_errors.GraphValueError("No checkpointer set", { lc_error_code: "MISSING_CHECKPOINTER" });
526
- const checkpointNamespace = config.configurable?.checkpoint_ns ?? "";
527
- if (checkpointNamespace !== "" && config.configurable?.["__pregel_read"] === void 0 && config.configurable?.["__pregel_checkpointer"] === void 0) {
528
- const recastNamespace = require_config.recastCheckpointNamespace(checkpointNamespace);
529
- for await (const [name, subgraph] of this.getSubgraphsAsync(recastNamespace, true)) if (name === recastNamespace) return await subgraph.getState(require_utils.patchConfigurable(config, { [require_constants.CONFIG_KEY_CHECKPOINTER]: checkpointer }), { subgraphs: options?.subgraphs });
570
+ const checkpointer = this._stateCheckpointer(config);
571
+ const subgraph = await this._subgraphForNamespace(config, checkpointer);
572
+ if (subgraph !== void 0) {
573
+ const [pregel, subgraphConfig] = subgraph;
574
+ return await pregel.getState(subgraphConfig, { subgraphs: options?.subgraphs });
530
575
  }
531
- const mergedConfig = (0, _langchain_core_runnables.mergeConfigs)(this.config, config);
532
- const saved = await checkpointer.getTuple(config);
576
+ const ownConfig = this._ownCheckpointConfig(config);
577
+ const mergedConfig = (0, _langchain_core_runnables.mergeConfigs)(this.config, ownConfig);
578
+ const saved = await checkpointer.getTuple(ownConfig);
533
579
  return await this._prepareStateSnapshot({
534
580
  config: mergedConfig,
535
581
  saved,
536
- subgraphCheckpointer: options?.subgraphs ? checkpointer : void 0,
582
+ saver: checkpointer,
583
+ recurse: options?.subgraphs,
537
584
  applyPendingWrites: !config.configurable?.checkpoint_id
538
585
  });
539
586
  }
@@ -551,20 +598,18 @@ var Pregel = class extends PartialRunnable {
551
598
  * @throws {Error} If no checkpointer is configured
552
599
  */
553
600
  async *getStateHistory(config, options) {
554
- const checkpointer = config.configurable?.["__pregel_checkpointer"] ?? this.checkpointer;
555
- if (!checkpointer) throw new require_errors.GraphValueError("No checkpointer set", { lc_error_code: "MISSING_CHECKPOINTER" });
556
- const checkpointNamespace = config.configurable?.checkpoint_ns ?? "";
557
- if (checkpointNamespace !== "" && config.configurable?.["__pregel_checkpointer"] === void 0) {
558
- const recastNamespace = require_config.recastCheckpointNamespace(checkpointNamespace);
559
- for await (const [name, pregel] of this.getSubgraphsAsync(recastNamespace, true)) if (name === recastNamespace) {
560
- yield* pregel.getStateHistory(require_utils.patchConfigurable(config, { [require_constants.CONFIG_KEY_CHECKPOINTER]: checkpointer }), options);
561
- return;
562
- }
601
+ const checkpointer = this._stateCheckpointer(config);
602
+ const subgraph = await this._subgraphForNamespace(config, checkpointer);
603
+ if (subgraph !== void 0) {
604
+ const [pregel, subgraphConfig] = subgraph;
605
+ yield* pregel.getStateHistory(subgraphConfig, options);
606
+ return;
563
607
  }
564
- const mergedConfig = (0, _langchain_core_runnables.mergeConfigs)(this.config, config, { configurable: { checkpoint_ns: checkpointNamespace } });
608
+ const mergedConfig = this._ownCheckpointConfig((0, _langchain_core_runnables.mergeConfigs)(this.config, config, { configurable: { checkpoint_ns: config.configurable?.checkpoint_ns ?? "" } }));
565
609
  for await (const checkpointTuple of checkpointer.list(mergedConfig, options)) yield this._prepareStateSnapshot({
566
610
  config: checkpointTuple.config,
567
- saved: checkpointTuple
611
+ saved: checkpointTuple,
612
+ saver: checkpointer
568
613
  });
569
614
  }
570
615
  /**
@@ -584,18 +629,18 @@ var Pregel = class extends PartialRunnable {
584
629
  * @throws {InvalidUpdateError} If the update cannot be attributed to a node or an update can be only applied in sequence.
585
630
  */
586
631
  async bulkUpdateState(startConfig, supersteps) {
587
- const checkpointer = startConfig.configurable?.["__pregel_checkpointer"] ?? this.checkpointer;
588
- if (!checkpointer) throw new require_errors.GraphValueError("No checkpointer set", { lc_error_code: "MISSING_CHECKPOINTER" });
632
+ const checkpointer = this._stateCheckpointer(startConfig);
589
633
  if (supersteps.length === 0) throw new Error("No supersteps provided");
590
634
  if (supersteps.some((s) => s.updates.length === 0)) throw new Error("No updates provided");
591
- const checkpointNamespace = startConfig.configurable?.checkpoint_ns ?? "";
592
- if (checkpointNamespace !== "" && startConfig.configurable?.["__pregel_checkpointer"] === void 0) {
593
- const recastNamespace = require_config.recastCheckpointNamespace(checkpointNamespace);
594
- for await (const [, pregel] of this.getSubgraphsAsync(recastNamespace, true)) return await pregel.bulkUpdateState(require_utils.patchConfigurable(startConfig, { [require_constants.CONFIG_KEY_CHECKPOINTER]: checkpointer }), supersteps);
595
- throw new Error(`Subgraph "${recastNamespace}" not found`);
635
+ const subgraph = await this._subgraphForNamespace(startConfig, checkpointer);
636
+ if (subgraph !== void 0) {
637
+ const [pregel, subgraphConfig] = subgraph;
638
+ return await pregel.bulkUpdateState(subgraphConfig, supersteps);
596
639
  }
640
+ const checkpointNamespace = startConfig.configurable?.checkpoint_ns ?? "";
641
+ if (checkpointNamespace !== "" && startConfig.configurable?.["__pregel_read"] === void 0 && startConfig.configurable?.["__pregel_checkpointer"] === void 0) throw new Error(`Subgraph "${require_config.recastCheckpointNamespace(checkpointNamespace)}" not found`);
597
642
  const updateSuperStep = async (inputConfig, updates) => {
598
- const config = this.config ? (0, _langchain_core_runnables.mergeConfigs)(this.config, inputConfig) : inputConfig;
643
+ const config = this._ownCheckpointConfig(this.config ? (0, _langchain_core_runnables.mergeConfigs)(this.config, inputConfig) : inputConfig);
599
644
  const saved = await checkpointer.getTuple(config);
600
645
  const checkpoint = saved !== void 0 ? (0, _langchain_langgraph_checkpoint.copyCheckpoint)(saved.checkpoint) : (0, _langchain_langgraph_checkpoint.emptyCheckpoint)();
601
646
  const checkpointPreviousVersions = { ...saved?.checkpoint.channel_versions };
@@ -609,18 +654,22 @@ var Pregel = class extends PartialRunnable {
609
654
  ...checkpointMetadata
610
655
  };
611
656
  }
657
+ const deltaWritesVersioned = Object.values(this.channels).some(require_base.isDeltaChannel) && (saved === void 0 || require_base.isDeltaWritesVersioned(saved.metadata));
658
+ const versionedMetadata = deltaWritesVersioned ? { [require_base.DELTA_WRITES_VERSIONED]: true } : {};
612
659
  const { values, asNode } = updates[0];
613
660
  if (values == null && asNode === void 0) {
614
661
  if (updates.length > 1) throw new require_errors.InvalidUpdateError(`Cannot create empty checkpoint with multiple updates`);
615
662
  return require_index.patchCheckpointMap(await checkpointer.put(checkpointConfig, require_base.createCheckpoint(checkpoint, void 0, step), {
616
663
  source: "update",
617
664
  step: step + 1,
618
- parents: saved?.metadata?.parents ?? {}
665
+ parents: saved?.metadata?.parents ?? {},
666
+ ...versionedMetadata
619
667
  }, {}), saved ? saved.metadata : void 0);
620
668
  }
621
669
  const channels = await require_base.channelsFromCheckpoint(this.channels, checkpoint, {
622
670
  saver: checkpointer,
623
- config: saved?.config ?? checkpointConfig
671
+ config: saved?.config ?? checkpointConfig,
672
+ deltaWritesVersioned
624
673
  });
625
674
  if (values === null && asNode === "__end__") {
626
675
  if (updates.length > 1) throw new require_errors.InvalidUpdateError(`Cannot apply multiple updates when clearing state`);
@@ -647,11 +696,13 @@ var Pregel = class extends PartialRunnable {
647
696
  }
648
697
  require_algo._applyWrites(checkpoint, channels, Object.values(nextTasks), checkpointer.getNextVersion.bind(checkpointer), this.triggerToNodes);
649
698
  }
699
+ const { [require_base.DELTA_WRITES_VERSIONED]: _carried, ...endMetadata } = checkpointMetadata;
650
700
  return require_index.patchCheckpointMap(await checkpointer.put(checkpointConfig, require_base.createCheckpoint(checkpoint, channels, step), {
651
- ...checkpointMetadata,
701
+ ...endMetadata,
652
702
  source: "update",
653
703
  step: step + 1,
654
- parents: saved?.metadata?.parents ?? {}
704
+ parents: saved?.metadata?.parents ?? {},
705
+ ...versionedMetadata
655
706
  }, require_index.getNewChannelVersions(checkpointPreviousVersions, checkpoint.channel_versions)), saved ? saved.metadata : void 0);
656
707
  }
657
708
  if (asNode === "__copy__") {
@@ -666,7 +717,8 @@ var Pregel = class extends PartialRunnable {
666
717
  const nextConfig = await checkpointer.put(saved.parentConfig ?? require_utils.patchConfigurable(saved.config, { checkpoint_id: void 0 }), nextCheckpoint, {
667
718
  source: "fork",
668
719
  step: step + 1,
669
- parents: saved.metadata?.parents ?? {}
720
+ parents: saved.metadata?.parents ?? {},
721
+ ...versionedMetadata
670
722
  }, {});
671
723
  if (isCopyWithUpdates(values)) {
672
724
  const nextTasks = require_algo._prepareNextTasks(nextCheckpoint, saved.pendingWrites, this.nodes, channels, nextConfig, false, { step: step + 2 });
@@ -699,12 +751,13 @@ var Pregel = class extends PartialRunnable {
699
751
  name: require_constants.INPUT,
700
752
  writes: inputWrites,
701
753
  triggers: []
702
- }], checkpointer.getNextVersion.bind(this.checkpointer), this.triggerToNodes);
754
+ }], checkpointer.getNextVersion.bind(checkpointer), this.triggerToNodes);
703
755
  const nextStep = saved?.metadata?.step != null ? saved.metadata.step + 1 : -1;
704
756
  const nextConfig = await checkpointer.put(checkpointConfig, require_base.createCheckpoint(checkpoint, channels, nextStep), {
705
757
  source: "input",
706
758
  step: nextStep,
707
- parents: saved?.metadata?.parents ?? {}
759
+ parents: saved?.metadata?.parents ?? {},
760
+ ...versionedMetadata
708
761
  }, require_index.getNewChannelVersions(checkpointPreviousVersions, checkpoint.channel_versions));
709
762
  await checkpointer.putWrites(nextConfig, inputWrites, (0, _langchain_langgraph_checkpoint.uuid5)(require_constants.INPUT, checkpoint.id));
710
763
  return require_index.patchCheckpointMap(nextConfig, saved ? saved.metadata : void 0);
@@ -716,11 +769,11 @@ var Pregel = class extends PartialRunnable {
716
769
  step: (saved.metadata?.step ?? -1) + 1
717
770
  });
718
771
  const nullWrites = (saved.pendingWrites ?? []).filter((w) => w[0] === require_constants.NULL_TASK_ID).map((w) => w.slice(1));
719
- if (nullWrites.length > 0) require_algo._applyWrites(saved.checkpoint, channels, [{
772
+ if (nullWrites.length > 0) require_algo._applyWrites(checkpoint, channels, [{
720
773
  name: require_constants.INPUT,
721
774
  writes: nullWrites,
722
775
  triggers: []
723
- }], void 0, this.triggerToNodes);
776
+ }], checkpointer.getNextVersion.bind(checkpointer), this.triggerToNodes);
724
777
  for (const [tid, k, v] of saved.pendingWrites) {
725
778
  if ([
726
779
  "__error__",
@@ -732,7 +785,7 @@ var Pregel = class extends PartialRunnable {
732
785
  const tasks = Object.values(nextTasks).filter((task) => {
733
786
  return task.writes.length > 0;
734
787
  });
735
- if (tasks.length > 0) require_algo._applyWrites(checkpoint, channels, tasks, void 0, this.triggerToNodes);
788
+ if (tasks.length > 0) require_algo._applyWrites(checkpoint, channels, tasks, checkpointer.getNextVersion.bind(checkpointer), this.triggerToNodes);
736
789
  }
737
790
  const nonNullVersion = Object.values(checkpoint.versions_seen).map((seenVersions) => {
738
791
  return Object.values(seenVersions);
@@ -769,7 +822,7 @@ var Pregel = class extends PartialRunnable {
769
822
  });
770
823
  }
771
824
  const tasks = [];
772
- for (const { asNode, values, taskId } of validUpdates) {
825
+ for (const [i, { asNode, values, taskId }] of validUpdates.entries()) {
773
826
  if (this.nodes[asNode] === void 0) throw new require_errors.InvalidUpdateError(`Node "${asNode.toString()}" does not exist`);
774
827
  const writers = this.nodes[asNode].getWriters();
775
828
  if (!writers.length) throw new require_errors.InvalidUpdateError(`No writers found for node "${asNode.toString()}"`);
@@ -779,7 +832,7 @@ var Pregel = class extends PartialRunnable {
779
832
  proc: writers.length > 1 ? _langchain_core_runnables.RunnableSequence.from(writers, { omitSequenceTags: true }) : writers[0],
780
833
  writes: [],
781
834
  triggers: [require_constants.INTERRUPT],
782
- id: taskId ?? (0, _langchain_langgraph_checkpoint.uuid5)("__interrupt__", checkpoint.id),
835
+ id: taskId ?? (0, _langchain_langgraph_checkpoint.uuid5)(i === 0 ? "__interrupt__" : `__interrupt__:${i}`, checkpoint.id),
783
836
  writers: []
784
837
  });
785
838
  }
@@ -797,12 +850,17 @@ var Pregel = class extends PartialRunnable {
797
850
  const channelWrites = task.writes.filter((w) => w[0] !== require_constants.PUSH);
798
851
  if (saved !== void 0 && channelWrites.length > 0) await checkpointer.putWrites(checkpointConfig, channelWrites, task.id);
799
852
  }
800
- require_algo._applyWrites(checkpoint, channels, tasks, checkpointer.getNextVersion.bind(this.checkpointer), this.triggerToNodes);
853
+ require_algo._applyWrites(checkpoint, channels, tasks, checkpointer.getNextVersion.bind(checkpointer), this.triggerToNodes);
854
+ const channelsToSnapshot = /* @__PURE__ */ new Set();
855
+ if (saved === void 0) {
856
+ for (const [k, ch] of Object.entries(channels)) if (require_base.isDeltaChannel(ch) && checkpoint.channel_versions[k] !== void 0) channelsToSnapshot.add(k);
857
+ }
801
858
  const newVersions = require_index.getNewChannelVersions(checkpointPreviousVersions, checkpoint.channel_versions);
802
- const nextConfig = await checkpointer.put(checkpointConfig, require_base.createCheckpoint(checkpoint, channels, step + 1), {
859
+ const nextConfig = await checkpointer.put(checkpointConfig, require_base.createCheckpoint(checkpoint, channels, step + 1, { channelsToSnapshot }), {
803
860
  source: "update",
804
861
  step: step + 1,
805
- parents: saved?.metadata?.parents ?? {}
862
+ parents: saved?.metadata?.parents ?? {},
863
+ ...versionedMetadata
806
864
  }, newVersions);
807
865
  for (const task of tasks) {
808
866
  const pushWrites = task.writes.filter((w) => w[0] === require_constants.PUSH);
@@ -877,11 +935,7 @@ var Pregel = class extends PartialRunnable {
877
935
  else defaultStreamMode = this.streamMode;
878
936
  streamModeSingle = true;
879
937
  }
880
- let defaultCheckpointer;
881
- if (this.checkpointer === false) defaultCheckpointer = void 0;
882
- else if (config !== void 0 && config.configurable?.["__pregel_checkpointer"] !== void 0) defaultCheckpointer = config.configurable[require_constants.CONFIG_KEY_CHECKPOINTER];
883
- else if (this.checkpointer === true) throw new Error("checkpointer: true cannot be used for root graphs.");
884
- else defaultCheckpointer = this.checkpointer;
938
+ const defaultCheckpointer = this._resolveCheckpointer(config);
885
939
  const defaultStore = config.store ?? this.store;
886
940
  const defaultCache = config.cache ?? this.cache;
887
941
  if (config.durability != null && config.checkpointDuring != null) throw new Error("Cannot use both `durability` and `checkpointDuring` at the same time.");
@@ -1021,11 +1075,7 @@ var Pregel = class extends PartialRunnable {
1021
1075
  if (typeof config.context !== "undefined") config.context = await this._validateContext(config.context);
1022
1076
  else config.configurable = await this._validateContext(config.configurable);
1023
1077
  const stream = new require_stream.IterableReadableWritableStream({ modes: new Set(streamMode) });
1024
- if (this.checkpointer === true) {
1025
- config.configurable ??= {};
1026
- const ns = config.configurable["checkpoint_ns"] ?? "";
1027
- config.configurable[require_constants.CONFIG_KEY_CHECKPOINT_NS] = ns.split("|").map((part) => part.split(":")[0]).join("|");
1028
- }
1078
+ config.configurable = this._ownCheckpointConfig(config).configurable;
1029
1079
  if (streamMode.includes("messages")) {
1030
1080
  const messageStreamer = isV3 ? new require_messages_v2.StreamProtocolMessagesHandler((chunk) => stream.push(chunk)) : new require_messages.StreamMessagesHandler((chunk) => stream.push(chunk));
1031
1081
  const { callbacks } = config;