@langchain/langgraph 1.5.0 → 1.5.1

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 (55) hide show
  1. package/dist/channels/base.cjs +10 -3
  2. package/dist/channels/base.cjs.map +1 -1
  3. package/dist/channels/base.d.cts.map +1 -1
  4. package/dist/channels/base.d.ts.map +1 -1
  5. package/dist/channels/base.js +10 -3
  6. package/dist/channels/base.js.map +1 -1
  7. package/dist/channels/binop.cjs +2 -1
  8. package/dist/channels/binop.cjs.map +1 -1
  9. package/dist/channels/binop.d.cts.map +1 -1
  10. package/dist/channels/binop.d.ts.map +1 -1
  11. package/dist/channels/binop.js +2 -1
  12. package/dist/channels/binop.js.map +1 -1
  13. package/dist/errors.cjs +22 -0
  14. package/dist/errors.cjs.map +1 -1
  15. package/dist/errors.d.cts +10 -1
  16. package/dist/errors.d.cts.map +1 -1
  17. package/dist/errors.d.ts +10 -1
  18. package/dist/errors.d.ts.map +1 -1
  19. package/dist/errors.js +21 -1
  20. package/dist/errors.js.map +1 -1
  21. package/dist/graph/messages_reducer.cjs +23 -6
  22. package/dist/graph/messages_reducer.cjs.map +1 -1
  23. package/dist/graph/messages_reducer.d.cts +4 -2
  24. package/dist/graph/messages_reducer.d.cts.map +1 -1
  25. package/dist/graph/messages_reducer.d.ts +4 -2
  26. package/dist/graph/messages_reducer.d.ts.map +1 -1
  27. package/dist/graph/messages_reducer.js +24 -7
  28. package/dist/graph/messages_reducer.js.map +1 -1
  29. package/dist/index.cjs +2 -0
  30. package/dist/index.d.cts +2 -2
  31. package/dist/index.d.ts +2 -2
  32. package/dist/index.js +2 -2
  33. package/dist/interrupt.cjs +9 -1
  34. package/dist/interrupt.cjs.map +1 -1
  35. package/dist/interrupt.d.cts.map +1 -1
  36. package/dist/interrupt.d.ts.map +1 -1
  37. package/dist/interrupt.js +10 -2
  38. package/dist/interrupt.js.map +1 -1
  39. package/dist/pregel/debug.cjs +1 -0
  40. package/dist/pregel/debug.cjs.map +1 -1
  41. package/dist/pregel/debug.js +1 -0
  42. package/dist/pregel/debug.js.map +1 -1
  43. package/dist/pregel/loop.cjs +15 -8
  44. package/dist/pregel/loop.cjs.map +1 -1
  45. package/dist/pregel/loop.js +15 -8
  46. package/dist/pregel/loop.js.map +1 -1
  47. package/dist/pregel/runner.cjs +1 -1
  48. package/dist/pregel/runner.cjs.map +1 -1
  49. package/dist/pregel/runner.js +2 -2
  50. package/dist/pregel/runner.js.map +1 -1
  51. package/dist/web.cjs +2 -0
  52. package/dist/web.d.cts +2 -2
  53. package/dist/web.d.ts +2 -2
  54. package/dist/web.js +2 -2
  55. package/package.json +2 -2
@@ -269,19 +269,25 @@ function isDeltaWritesVersioned(metadata) {
269
269
  return metadata?.[DELTA_WRITES_VERSIONED] === true;
270
270
  }
271
271
  /**
272
- * Delta channels whose value at `checkpoint` the ancestor walk rebuilds.
272
+ * Channels whose value at `checkpoint` the ancestor walk rebuilds.
273
273
  *
274
274
  * A {@link DeltaSnapshot} or a migrated plain value in `channel_values`
275
275
  * resolves directly, so only a channel with nothing stored there needs the
276
276
  * walk. With `versionedOnly`, a channel with no version was never written, so
277
277
  * it is empty without one; a walk for it would find no snapshot to stop at and
278
278
  * read every ancestor, every time the thread is loaded.
279
+ *
280
+ * A `BinaryOperatorAggregate` stores its value at every version, so one with a
281
+ * version and nothing stored was written as a DeltaChannel before its
282
+ * annotation changed, and is rebuilt the same way.
279
283
  */
280
284
  function deltaChannelsToReplay(specs, checkpoint, versionedOnly) {
281
285
  const keys = [];
282
286
  for (const k in specs) {
283
287
  if (!Object.prototype.hasOwnProperty.call(specs, k)) continue;
284
- if (isDeltaChannel(specs[k]) && (!versionedOnly || checkpoint.channel_versions[k] !== void 0) && !Object.prototype.hasOwnProperty.call(checkpoint.channel_values, k)) keys.push(k);
288
+ if (Object.prototype.hasOwnProperty.call(checkpoint.channel_values, k)) continue;
289
+ const versioned = checkpoint.channel_versions[k] !== void 0;
290
+ if (isDeltaChannel(specs[k]) && (versioned || !versionedOnly) || specs[k].lc_graph_name === "BinaryOperatorAggregate" && versioned) keys.push(k);
285
291
  }
286
292
  return keys;
287
293
  }
@@ -315,7 +321,8 @@ async function channelsFromCheckpoint(specs, checkpoint, options) {
315
321
  const history = histories[k];
316
322
  if (history === void 0) continue;
317
323
  const replayCh = filteredSpecs[k].fromCheckpoint(history.seed);
318
- replayCh.replayWrites(history.writes);
324
+ if (isDeltaChannel(replayCh)) replayCh.replayWrites(history.writes);
325
+ else for (const [, , value] of history.writes) replayCh.update([value]);
319
326
  channels[k] = replayCh;
320
327
  }
321
328
  return channels;
@@ -1 +1 @@
1
- {"version":3,"file":"base.cjs","names":["EmptyChannelError","EXIT_DELTA_NULL_TASK_ID","getDeltaMaxSuperstepsSinceSnapshot","DeltaSnapshot","SNAPSHOT_BUMPS"],"sources":["../../src/channels/base.ts"],"sourcesContent":["import {\n ReadonlyCheckpoint,\n uuid6,\n Checkpoint,\n DeltaSnapshot,\n type BaseCheckpointSaver,\n type CheckpointMetadata,\n type DeltaChannelHistory,\n} from \"@langchain/langgraph-checkpoint\";\nimport type { RunnableConfig } from \"@langchain/core/runnables\";\nimport { EmptyChannelError } from \"../errors.js\";\nimport {\n CHECKPOINT_NAMESPACE_END,\n CHECKPOINT_NAMESPACE_SEPARATOR,\n EXIT_DELTA_NULL_TASK_ID,\n getDeltaMaxSuperstepsSinceSnapshot,\n NULL_TASK_ID,\n SNAPSHOT_BUMPS,\n} from \"../constants.js\";\n\n/** Matches Postgres `uuid` / Python `uuid.UUID` (128-bit, 8-4-4-4-12 hex). */\nconst STRUCTURED_UUID =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * Structural check for a {@link DeltaChannel} without importing it (avoids an\n * import cycle: `delta.ts` imports `base.ts`).\n */\nexport function isDeltaChannel(channel: BaseChannel): boolean {\n return channel != null && channel.lc_graph_name === \"DeltaChannel\";\n}\n\nexport function deltaChannelWrites<W extends readonly [PropertyKey, unknown]>(\n channels: Record<string, BaseChannel>,\n writes: ReadonlyArray<W>\n): W[] {\n return writes.filter(([ch]) => isDeltaChannel(channels[String(ch)]));\n}\n\nexport function isBaseChannel(obj: unknown): obj is BaseChannel {\n return obj != null && (obj as BaseChannel).lg_is_channel === true;\n}\n\n/** @internal */\nexport abstract class BaseChannel<\n ValueType = unknown,\n UpdateType = unknown,\n CheckpointType = unknown,\n> {\n ValueType: ValueType;\n\n UpdateType: UpdateType;\n\n /**\n * The name of the channel.\n */\n abstract lc_graph_name: string;\n\n /** @ignore */\n lg_is_channel = true;\n\n /**\n * Return a new identical channel, optionally initialized from a checkpoint.\n * Can be thought of as a \"restoration\" from a checkpoint which is a \"snapshot\" of the channel's state.\n *\n * @param {CheckpointType | undefined} checkpoint\n * @param {CheckpointType | undefined} initialValue\n * @returns {this}\n */\n abstract fromCheckpoint(checkpoint?: CheckpointType): this;\n\n /**\n * Update the channel's value with the given sequence of updates.\n * The order of the updates in the sequence is arbitrary.\n * This method is called by Pregel for all channels at the end of each step.\n * If there are no updates, it is called with an empty sequence.\n *\n * Raises InvalidUpdateError if the sequence of updates is invalid.\n * Returns True if the channel was updated, False otherwise.\n *\n * @throws {InvalidUpdateError} if the sequence of updates is invalid.\n * @param {Array<UpdateType>} values\n * @returns {void}\n */\n abstract update(values: UpdateType[]): boolean;\n\n /**\n * Return the current value of the channel.\n *\n * @throws {EmptyChannelError} if the channel is empty (never updated yet).\n * @returns {ValueType}\n */\n abstract get(): ValueType;\n\n /**\n * Return a string representation of the channel's current state.\n *\n * @throws {EmptyChannelError} if the channel is empty (never updated yet), or doesn't support checkpoints.\n * @returns {CheckpointType | undefined}\n */\n abstract checkpoint(): CheckpointType | undefined;\n\n /**\n * Mark the current value of the channel as consumed. By default, no-op.\n * A channel can use this method to modify its state, preventing the value\n * from being consumed again.\n *\n * Returns True if the channel was updated, False otherwise.\n */\n consume(): boolean {\n return false;\n }\n\n /**\n * Notify the channel that the Pregel run is finishing. By default, no-op.\n * A channel can use this method to modify its state, preventing finish.\n *\n * Returns True if the channel was updated, False otherwise.\n */\n finish(): boolean {\n return false;\n }\n\n /**\n * Return True if the channel is available (not empty), False otherwise.\n * Subclasses should override this method to provide a more efficient\n * implementation than calling get() and catching EmptyChannelError.\n */\n isAvailable(): boolean {\n try {\n this.get();\n return true;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n if (error.name === EmptyChannelError.unminifiable_name) {\n return false;\n }\n throw error;\n }\n }\n\n /**\n * Compare this channel with another channel for equality.\n * Used to determine if two channels with the same key are semantically equivalent.\n * Subclasses should override this method to provide a meaningful comparison.\n *\n * @param {BaseChannel} other - The other channel to compare with.\n * @returns {boolean} True if the channels are equal, false otherwise.\n */\n equals(other: BaseChannel): boolean {\n return this === other;\n }\n}\n\nconst IS_ONLY_BASE_CHANNEL = Symbol.for(\"LG_IS_ONLY_BASE_CHANNEL\");\nexport function getOnlyChannels(\n channels: Record<string, BaseChannel>\n): Record<string, BaseChannel> {\n // @ts-expect-error - we know it's a record of base channels\n if (channels[IS_ONLY_BASE_CHANNEL] === true) return channels;\n\n const newChannels = {} as Record<string, BaseChannel>;\n for (const k in channels) {\n if (!Object.prototype.hasOwnProperty.call(channels, k)) continue;\n const value = channels[k];\n if (isBaseChannel(value)) newChannels[k] = value;\n }\n\n Object.assign(newChannels, { [IS_ONLY_BASE_CHANNEL]: true });\n return newChannels;\n}\n\nexport function emptyChannels<Cc extends Record<string, BaseChannel>>(\n channels: Cc,\n checkpoint: ReadonlyCheckpoint\n): Cc {\n const filteredChannels = getOnlyChannels(channels) as Cc;\n\n const newChannels = {} as Cc;\n for (const k in filteredChannels) {\n if (!Object.prototype.hasOwnProperty.call(filteredChannels, k)) continue;\n const channelValue = checkpoint.channel_values[k];\n newChannels[k] = filteredChannels[k].fromCheckpoint(channelValue);\n }\n Object.assign(newChannels, { [IS_ONLY_BASE_CHANNEL]: true });\n return newChannels;\n}\n\n/**\n * Minimal structural view of a {@link DeltaChannel}, used by helpers in this\n * module that must not import the concrete class (import-cycle avoidance).\n */\ninterface DeltaChannelLike extends BaseChannel {\n snapshotFrequency: number;\n replayWrites(writes: DeltaChannelHistory[\"writes\"]): void;\n}\n\n/**\n * Synthetic task id for exit-mode DeltaChannel writes.\n *\n * Embeds the superstep in the first UUID group so `ORDER BY task_id, idx`\n * preserves chronological order while remaining a valid RFC UUID (required by\n * Postgres `checkpoint_writes.task_id uuid` columns). Never `NULL_TASK_ID`:\n * readers apply writes under it as the anchor checkpoint's own pending writes.\n */\nexport function exitDeltaTaskId(step: number, taskId: string): string {\n if (!STRUCTURED_UUID.test(taskId)) {\n throw new TypeError(`Invalid task id for exit delta: ${taskId}`);\n }\n const parts = taskId.toLowerCase().split(\"-\");\n const stepPart = String(step).padStart(8, \"0\");\n const synthetic = `${stepPart}-${parts[1]}-${parts[2]}-${parts[3]}-${parts[4]}`;\n return synthetic === NULL_TASK_ID ? EXIT_DELTA_NULL_TASK_ID : synthetic;\n}\n\n/**\n * Synthetic task id for exit-mode writes of a superstep after the anchor's\n * own.\n *\n * Sorts after every real task id, in step order, so replay keeps them after\n * the anchor's own superstep whether a saver orders writes by task path\n * (`writesSortKey`) or by task id. Mirrors Python's\n * `exit_delta_late_task_id` exactly, including the two hexadecimal step\n * groups (step is split across them).\n */\nexport function exitDeltaLateTaskId(step: number, taskId: string): string {\n if (!STRUCTURED_UUID.test(taskId)) {\n throw new TypeError(`Invalid task id for exit delta: ${taskId}`);\n }\n const parts = taskId.toLowerCase().split(\"-\");\n const stepHi = (step >> 16).toString(16).padStart(4, \"0\");\n const stepLo = (step & 0xffff).toString(16).padStart(4, \"0\");\n return `ffffffff-${stepHi}-${stepLo}-${parts[3]}-${parts[4]}`;\n}\n\n/**\n * DeltaChannels a branch starting from this checkpoint must snapshot.\n *\n * A checkpoint's pending writes belong to the child that consumed them, and\n * nothing records which child that was. A new branch snapshots every delta\n * channel they touch, so its ancestor walk never replays them (port of\n * Python #8548's `delta_channels_with_pending_writes`).\n */\nexport function deltaChannelsWithPendingWrites(\n channels: Record<string, BaseChannel>,\n pendingWrites: ReadonlyArray<[string, string, unknown]> | undefined\n): Set<string> {\n const result = new Set<string>();\n if (pendingWrites === undefined) return result;\n for (const [, ch] of pendingWrites) {\n const channel = channels[ch];\n if (channel != null && isDeltaChannel(channel)) result.add(ch);\n }\n return result;\n}\n\n/**\n * Return the set of {@link DeltaChannel} names that should snapshot now.\n *\n * A channel snapshots when EITHER its accumulated update count reaches\n * `snapshotFrequency` OR the total supersteps since its last snapshot reaches\n * `DELTA_MAX_SUPERSTEPS_SINCE_SNAPSHOT`. Given `channelVersions`, a channel\n * without a version is skipped: it was never written on this branch, so it\n * has nothing to snapshot. Pass `undefined` on a branch without\n * {@link DELTA_WRITES_VERSIONED}, where such a channel can still hold writes\n * and this snapshot is what bounds its walk. Pure predicate, no mutation.\n */\nexport function deltaChannelsToSnapshot(\n channels: Record<string, BaseChannel>,\n countersSinceDeltaSnapshot: Record<string, [number, number]>,\n channelVersions: Record<string, number | string> | undefined\n): Set<string> {\n const result = new Set<string>();\n for (const name in channels) {\n if (!Object.prototype.hasOwnProperty.call(channels, name)) continue;\n const ch = channels[name];\n if (\n !isDeltaChannel(ch) ||\n !ch.isAvailable() ||\n (channelVersions !== undefined && channelVersions[name] === undefined)\n ) {\n continue;\n }\n if (reachedSnapshotBound(ch, countersSinceDeltaSnapshot[name])) {\n result.add(name);\n }\n }\n return result;\n}\n\n/** Whether a delta channel's counters reached the bound where it snapshots. */\nexport function reachedSnapshotBound(\n channel: BaseChannel,\n counters: [number, number] | undefined\n): boolean {\n const [updates, supersteps] = counters ?? [0, 0];\n return (\n updates >= (channel as DeltaChannelLike).snapshotFrequency ||\n supersteps >= getDeltaMaxSuperstepsSinceSnapshot()\n );\n}\n\nexport function createCheckpoint<ValueType>(\n checkpoint: ReadonlyCheckpoint,\n channels: Record<string, BaseChannel<ValueType>> | undefined,\n step: number,\n options?: {\n id?: string;\n channelsToSnapshot?: Set<string>;\n /** The channel versions of the last checkpoint the saver stored. */\n storedVersions?: Record<string, number | string>;\n getNextVersion?: (current: number | string | undefined) => number | string;\n triggerToNodes?: Record<string, string[]>;\n }\n): Checkpoint {\n const channelsToSnapshot = options?.channelsToSnapshot ?? new Set<string>();\n const { storedVersions, getNextVersion } = options ?? {};\n const bumped: Record<string, [number | string | undefined, number | string]> =\n {};\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let values: Record<string, any>;\n let channelVersions: Record<string, number | string> =\n checkpoint.channel_versions;\n if (channels === undefined) {\n values = checkpoint.channel_values;\n } else {\n values = {};\n channelVersions = { ...checkpoint.channel_versions };\n for (const k in channels) {\n if (!Object.prototype.hasOwnProperty.call(channels, k)) continue;\n const channel = channels[k];\n if (channelsToSnapshot.has(k)) {\n // `put` only stores a blob for a channel whose version moved, so\n // snapshotting a channel that didn't move since the last stored\n // checkpoint needs a bump: exit mode reaching the cadence on a\n // superstep that skipped the channel, and a fork's first checkpoint.\n if (\n getNextVersion !== undefined &&\n storedVersions !== undefined &&\n channelVersions[k] === storedVersions[k]\n ) {\n const old = channelVersions[k];\n channelVersions[k] = getNextVersion(old);\n bumped[k] = [old, channelVersions[k]];\n }\n values[k] = new DeltaSnapshot(channel.get());\n continue;\n }\n if (isDeltaChannel(channel)) {\n // Omitted from channel_values; reconstructed from ancestor writes.\n continue;\n }\n try {\n values[k] = channel.checkpoint();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n if (error.name === EmptyChannelError.unminifiable_name) {\n // no-op\n } else {\n throw error; // Rethrow unexpected errors\n }\n }\n }\n }\n\n return {\n v: 4,\n id: options?.id ?? uuid6(step),\n ts: new Date().toISOString(),\n channel_values: values,\n channel_versions: channelVersions,\n versions_seen: markBumpsSeen(\n checkpoint.versions_seen,\n bumped,\n options?.triggerToNodes\n ),\n };\n}\n\n/**\n * Advance whoever had seen a bumped channel's old version to the new one.\n *\n * A bump that only stores a snapshot is not a write. Left unseen, it would\n * re-fire `interruptBefore` and rerun the channel's subscribers. A channel\n * bumped from no version was never written, so it also goes to the\n * subscribers that never ran: they have no entry, and would start on the bump.\n * For each entry it advances, {@link SNAPSHOT_BUMPS} keeps the new version and\n * the one the node really read, so {@link versionsSeenWithoutBumps} can put\n * the read back.\n */\nfunction markBumpsSeen(\n versionsSeen: ReadonlyCheckpoint[\"versions_seen\"],\n bumped: Record<string, [number | string | undefined, number | string]>,\n triggerToNodes: Record<string, string[]> = {}\n): Checkpoint[\"versions_seen\"] {\n if (Object.keys(bumped).length === 0) return versionsSeen;\n const out = { ...versionsSeen };\n for (const [k, [old]] of Object.entries(bumped)) {\n if (old !== undefined) continue;\n for (const node of triggerToNodes[k] ?? []) out[node] ??= {};\n }\n const marks = { ...versionsSeen[SNAPSHOT_BUMPS] };\n for (const node in out) {\n if (\n !Object.prototype.hasOwnProperty.call(out, node) ||\n node === SNAPSHOT_BUMPS\n ) {\n continue;\n }\n for (const [k, [old, next]] of Object.entries(bumped)) {\n if (out[node][k] !== old) continue;\n const [advanced, read] = bumpKeys(node, k);\n // If an earlier bump set `old`, the real read is already recorded.\n if (old !== undefined && marks[advanced] !== old) marks[read] = old;\n marks[advanced] = next;\n out[node] = { ...out[node], [k]: next };\n }\n }\n if (Object.keys(marks).length > 0) out[SNAPSHOT_BUMPS] = marks;\n return out;\n}\n\n// Node names can't contain either separator, so the keys can't collide.\nconst bumpKeys = (node: string, channel: string): [string, string] => [\n `${node}${CHECKPOINT_NAMESPACE_SEPARATOR}${channel}`,\n `${node}${CHECKPOINT_NAMESPACE_END}${channel}`,\n];\n\n/**\n * `versions_seen` as the nodes read it: an entry a snapshot bump advanced goes\n * back to the version the node really read, or away if it never read one.\n */\nexport function versionsSeenWithoutBumps(\n versionsSeen: ReadonlyCheckpoint[\"versions_seen\"]\n): ReadonlyCheckpoint[\"versions_seen\"] {\n const marks = versionsSeen[SNAPSHOT_BUMPS];\n if (marks === undefined || Object.keys(marks).length === 0) {\n return versionsSeen;\n }\n const out: Checkpoint[\"versions_seen\"] = {};\n for (const node in versionsSeen) {\n if (\n !Object.prototype.hasOwnProperty.call(versionsSeen, node) ||\n node === SNAPSHOT_BUMPS\n ) {\n continue;\n }\n out[node] = {};\n for (const [k, v] of Object.entries(versionsSeen[node])) {\n const [advanced, read] = bumpKeys(node, k);\n if (marks[advanced] !== v) out[node][k] = v;\n else if (read in marks) out[node][k] = marks[read];\n }\n }\n return out;\n}\n\n/**\n * Checkpoint metadata key, `true` when every DeltaChannel write on the\n * checkpoint's branch carries a version. A delta channel with no version there\n * was never written, so it needs no walk. Branches started before this key\n * existed never get it: an older `updateState` stored a delta channel's first\n * write without a version, and only the walk finds such a write.\n */\nexport const DELTA_WRITES_VERSIONED = \"delta_writes_versioned\";\n\nexport function isDeltaWritesVersioned(\n metadata: CheckpointMetadata | undefined\n): boolean {\n return (\n (metadata as Record<string, unknown> | undefined)?.[\n DELTA_WRITES_VERSIONED\n ] === true\n );\n}\n\n/**\n * Delta channels whose value at `checkpoint` the ancestor walk rebuilds.\n *\n * A {@link DeltaSnapshot} or a migrated plain value in `channel_values`\n * resolves directly, so only a channel with nothing stored there needs the\n * walk. With `versionedOnly`, a channel with no version was never written, so\n * it is empty without one; a walk for it would find no snapshot to stop at and\n * read every ancestor, every time the thread is loaded.\n */\nfunction deltaChannelsToReplay(\n specs: Record<string, BaseChannel>,\n checkpoint: ReadonlyCheckpoint,\n versionedOnly: boolean\n): string[] {\n const keys: string[] = [];\n for (const k in specs) {\n if (!Object.prototype.hasOwnProperty.call(specs, k)) continue;\n if (\n isDeltaChannel(specs[k]) &&\n (!versionedOnly || checkpoint.channel_versions[k] !== undefined) &&\n !Object.prototype.hasOwnProperty.call(checkpoint.channel_values, k)\n ) {\n keys.push(k);\n }\n }\n return keys;\n}\n\n/**\n * Hydrate channels from a checkpoint, reconstructing any {@link DeltaChannel}\n * whose value is absent from `channel_values` by replaying ancestor writes.\n *\n * For most channels (and for delta channels with a {@link DeltaSnapshot} or a\n * migrated plain value in `channel_values`), {@link emptyChannels} is\n * sufficient and no saver access is required. When a delta channel is absent\n * from `channel_values`, an ancestor walk via `saver.getDeltaChannelHistory`\n * finds the nearest seed and accumulates the writes between it and the\n * target. All delta channels needing replay are batched into a single saver\n * call. Pass `deltaWritesVersioned` for a checkpoint whose metadata carries\n * {@link DELTA_WRITES_VERSIONED}, so delta channels without a version are\n * left empty instead of walked.\n */\nexport async function channelsFromCheckpoint<\n Cc extends Record<string, BaseChannel>,\n>(\n specs: Cc,\n checkpoint: ReadonlyCheckpoint,\n options?: {\n saver?: BaseCheckpointSaver;\n config?: RunnableConfig;\n deltaWritesVersioned?: boolean;\n }\n): Promise<Cc> {\n const channels = emptyChannels(specs, checkpoint);\n const { saver, config } = options ?? {};\n\n const filteredSpecs = getOnlyChannels(specs);\n const deltaKeys = deltaChannelsToReplay(\n filteredSpecs,\n checkpoint,\n options?.deltaWritesVersioned ?? false\n );\n\n const written = deltaKeys.filter(\n (k) => checkpoint.channel_versions[k] !== undefined\n );\n if ((saver === undefined || config === undefined) && written.length > 0) {\n throw new Error(\n `DeltaChannel ${written.join(\", \")} has history to replay but no checkpointer or config was passed to read it`\n );\n }\n if (deltaKeys.length === 0 || saver === undefined || config === undefined) {\n return channels;\n }\n\n const histories = await saver.getDeltaChannelHistory({\n config,\n channels: deltaKeys,\n });\n for (const k of deltaKeys) {\n const history = histories[k];\n if (history === undefined) continue;\n const replayCh = filteredSpecs[k].fromCheckpoint(\n history.seed\n ) as unknown as DeltaChannelLike;\n replayCh.replayWrites(history.writes);\n (channels as Record<string, BaseChannel>)[k] = replayCh;\n }\n return channels;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"base.cjs","names":["EmptyChannelError","EXIT_DELTA_NULL_TASK_ID","getDeltaMaxSuperstepsSinceSnapshot","DeltaSnapshot","SNAPSHOT_BUMPS"],"sources":["../../src/channels/base.ts"],"sourcesContent":["import {\n ReadonlyCheckpoint,\n uuid6,\n Checkpoint,\n DeltaSnapshot,\n type BaseCheckpointSaver,\n type CheckpointMetadata,\n type DeltaChannelHistory,\n} from \"@langchain/langgraph-checkpoint\";\nimport type { RunnableConfig } from \"@langchain/core/runnables\";\nimport { EmptyChannelError } from \"../errors.js\";\nimport {\n CHECKPOINT_NAMESPACE_END,\n CHECKPOINT_NAMESPACE_SEPARATOR,\n EXIT_DELTA_NULL_TASK_ID,\n getDeltaMaxSuperstepsSinceSnapshot,\n NULL_TASK_ID,\n SNAPSHOT_BUMPS,\n} from \"../constants.js\";\n\n/** Matches Postgres `uuid` / Python `uuid.UUID` (128-bit, 8-4-4-4-12 hex). */\nconst STRUCTURED_UUID =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * Structural check for a {@link DeltaChannel} without importing it (avoids an\n * import cycle: `delta.ts` imports `base.ts`).\n */\nexport function isDeltaChannel(channel: BaseChannel): boolean {\n return channel != null && channel.lc_graph_name === \"DeltaChannel\";\n}\n\nexport function deltaChannelWrites<W extends readonly [PropertyKey, unknown]>(\n channels: Record<string, BaseChannel>,\n writes: ReadonlyArray<W>\n): W[] {\n return writes.filter(([ch]) => isDeltaChannel(channels[String(ch)]));\n}\n\nexport function isBaseChannel(obj: unknown): obj is BaseChannel {\n return obj != null && (obj as BaseChannel).lg_is_channel === true;\n}\n\n/** @internal */\nexport abstract class BaseChannel<\n ValueType = unknown,\n UpdateType = unknown,\n CheckpointType = unknown,\n> {\n ValueType: ValueType;\n\n UpdateType: UpdateType;\n\n /**\n * The name of the channel.\n */\n abstract lc_graph_name: string;\n\n /** @ignore */\n lg_is_channel = true;\n\n /**\n * Return a new identical channel, optionally initialized from a checkpoint.\n * Can be thought of as a \"restoration\" from a checkpoint which is a \"snapshot\" of the channel's state.\n *\n * @param {CheckpointType | undefined} checkpoint\n * @param {CheckpointType | undefined} initialValue\n * @returns {this}\n */\n abstract fromCheckpoint(checkpoint?: CheckpointType): this;\n\n /**\n * Update the channel's value with the given sequence of updates.\n * The order of the updates in the sequence is arbitrary.\n * This method is called by Pregel for all channels at the end of each step.\n * If there are no updates, it is called with an empty sequence.\n *\n * Raises InvalidUpdateError if the sequence of updates is invalid.\n * Returns True if the channel was updated, False otherwise.\n *\n * @throws {InvalidUpdateError} if the sequence of updates is invalid.\n * @param {Array<UpdateType>} values\n * @returns {void}\n */\n abstract update(values: UpdateType[]): boolean;\n\n /**\n * Return the current value of the channel.\n *\n * @throws {EmptyChannelError} if the channel is empty (never updated yet).\n * @returns {ValueType}\n */\n abstract get(): ValueType;\n\n /**\n * Return a string representation of the channel's current state.\n *\n * @throws {EmptyChannelError} if the channel is empty (never updated yet), or doesn't support checkpoints.\n * @returns {CheckpointType | undefined}\n */\n abstract checkpoint(): CheckpointType | undefined;\n\n /**\n * Mark the current value of the channel as consumed. By default, no-op.\n * A channel can use this method to modify its state, preventing the value\n * from being consumed again.\n *\n * Returns True if the channel was updated, False otherwise.\n */\n consume(): boolean {\n return false;\n }\n\n /**\n * Notify the channel that the Pregel run is finishing. By default, no-op.\n * A channel can use this method to modify its state, preventing finish.\n *\n * Returns True if the channel was updated, False otherwise.\n */\n finish(): boolean {\n return false;\n }\n\n /**\n * Return True if the channel is available (not empty), False otherwise.\n * Subclasses should override this method to provide a more efficient\n * implementation than calling get() and catching EmptyChannelError.\n */\n isAvailable(): boolean {\n try {\n this.get();\n return true;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n if (error.name === EmptyChannelError.unminifiable_name) {\n return false;\n }\n throw error;\n }\n }\n\n /**\n * Compare this channel with another channel for equality.\n * Used to determine if two channels with the same key are semantically equivalent.\n * Subclasses should override this method to provide a meaningful comparison.\n *\n * @param {BaseChannel} other - The other channel to compare with.\n * @returns {boolean} True if the channels are equal, false otherwise.\n */\n equals(other: BaseChannel): boolean {\n return this === other;\n }\n}\n\nconst IS_ONLY_BASE_CHANNEL = Symbol.for(\"LG_IS_ONLY_BASE_CHANNEL\");\nexport function getOnlyChannels(\n channels: Record<string, BaseChannel>\n): Record<string, BaseChannel> {\n // @ts-expect-error - we know it's a record of base channels\n if (channels[IS_ONLY_BASE_CHANNEL] === true) return channels;\n\n const newChannels = {} as Record<string, BaseChannel>;\n for (const k in channels) {\n if (!Object.prototype.hasOwnProperty.call(channels, k)) continue;\n const value = channels[k];\n if (isBaseChannel(value)) newChannels[k] = value;\n }\n\n Object.assign(newChannels, { [IS_ONLY_BASE_CHANNEL]: true });\n return newChannels;\n}\n\nexport function emptyChannels<Cc extends Record<string, BaseChannel>>(\n channels: Cc,\n checkpoint: ReadonlyCheckpoint\n): Cc {\n const filteredChannels = getOnlyChannels(channels) as Cc;\n\n const newChannels = {} as Cc;\n for (const k in filteredChannels) {\n if (!Object.prototype.hasOwnProperty.call(filteredChannels, k)) continue;\n const channelValue = checkpoint.channel_values[k];\n newChannels[k] = filteredChannels[k].fromCheckpoint(channelValue);\n }\n Object.assign(newChannels, { [IS_ONLY_BASE_CHANNEL]: true });\n return newChannels;\n}\n\n/**\n * Minimal structural view of a {@link DeltaChannel}, used by helpers in this\n * module that must not import the concrete class (import-cycle avoidance).\n */\ninterface DeltaChannelLike extends BaseChannel {\n snapshotFrequency: number;\n replayWrites(writes: DeltaChannelHistory[\"writes\"]): void;\n}\n\n/**\n * Synthetic task id for exit-mode DeltaChannel writes.\n *\n * Embeds the superstep in the first UUID group so `ORDER BY task_id, idx`\n * preserves chronological order while remaining a valid RFC UUID (required by\n * Postgres `checkpoint_writes.task_id uuid` columns). Never `NULL_TASK_ID`:\n * readers apply writes under it as the anchor checkpoint's own pending writes.\n */\nexport function exitDeltaTaskId(step: number, taskId: string): string {\n if (!STRUCTURED_UUID.test(taskId)) {\n throw new TypeError(`Invalid task id for exit delta: ${taskId}`);\n }\n const parts = taskId.toLowerCase().split(\"-\");\n const stepPart = String(step).padStart(8, \"0\");\n const synthetic = `${stepPart}-${parts[1]}-${parts[2]}-${parts[3]}-${parts[4]}`;\n return synthetic === NULL_TASK_ID ? EXIT_DELTA_NULL_TASK_ID : synthetic;\n}\n\n/**\n * Synthetic task id for exit-mode writes of a superstep after the anchor's\n * own.\n *\n * Sorts after every real task id, in step order, so replay keeps them after\n * the anchor's own superstep whether a saver orders writes by task path\n * (`writesSortKey`) or by task id. Mirrors Python's\n * `exit_delta_late_task_id` exactly, including the two hexadecimal step\n * groups (step is split across them).\n */\nexport function exitDeltaLateTaskId(step: number, taskId: string): string {\n if (!STRUCTURED_UUID.test(taskId)) {\n throw new TypeError(`Invalid task id for exit delta: ${taskId}`);\n }\n const parts = taskId.toLowerCase().split(\"-\");\n const stepHi = (step >> 16).toString(16).padStart(4, \"0\");\n const stepLo = (step & 0xffff).toString(16).padStart(4, \"0\");\n return `ffffffff-${stepHi}-${stepLo}-${parts[3]}-${parts[4]}`;\n}\n\n/**\n * DeltaChannels a branch starting from this checkpoint must snapshot.\n *\n * A checkpoint's pending writes belong to the child that consumed them, and\n * nothing records which child that was. A new branch snapshots every delta\n * channel they touch, so its ancestor walk never replays them (port of\n * Python #8548's `delta_channels_with_pending_writes`).\n */\nexport function deltaChannelsWithPendingWrites(\n channels: Record<string, BaseChannel>,\n pendingWrites: ReadonlyArray<[string, string, unknown]> | undefined\n): Set<string> {\n const result = new Set<string>();\n if (pendingWrites === undefined) return result;\n for (const [, ch] of pendingWrites) {\n const channel = channels[ch];\n if (channel != null && isDeltaChannel(channel)) result.add(ch);\n }\n return result;\n}\n\n/**\n * Return the set of {@link DeltaChannel} names that should snapshot now.\n *\n * A channel snapshots when EITHER its accumulated update count reaches\n * `snapshotFrequency` OR the total supersteps since its last snapshot reaches\n * `DELTA_MAX_SUPERSTEPS_SINCE_SNAPSHOT`. Given `channelVersions`, a channel\n * without a version is skipped: it was never written on this branch, so it\n * has nothing to snapshot. Pass `undefined` on a branch without\n * {@link DELTA_WRITES_VERSIONED}, where such a channel can still hold writes\n * and this snapshot is what bounds its walk. Pure predicate, no mutation.\n */\nexport function deltaChannelsToSnapshot(\n channels: Record<string, BaseChannel>,\n countersSinceDeltaSnapshot: Record<string, [number, number]>,\n channelVersions: Record<string, number | string> | undefined\n): Set<string> {\n const result = new Set<string>();\n for (const name in channels) {\n if (!Object.prototype.hasOwnProperty.call(channels, name)) continue;\n const ch = channels[name];\n if (\n !isDeltaChannel(ch) ||\n !ch.isAvailable() ||\n (channelVersions !== undefined && channelVersions[name] === undefined)\n ) {\n continue;\n }\n if (reachedSnapshotBound(ch, countersSinceDeltaSnapshot[name])) {\n result.add(name);\n }\n }\n return result;\n}\n\n/** Whether a delta channel's counters reached the bound where it snapshots. */\nexport function reachedSnapshotBound(\n channel: BaseChannel,\n counters: [number, number] | undefined\n): boolean {\n const [updates, supersteps] = counters ?? [0, 0];\n return (\n updates >= (channel as DeltaChannelLike).snapshotFrequency ||\n supersteps >= getDeltaMaxSuperstepsSinceSnapshot()\n );\n}\n\nexport function createCheckpoint<ValueType>(\n checkpoint: ReadonlyCheckpoint,\n channels: Record<string, BaseChannel<ValueType>> | undefined,\n step: number,\n options?: {\n id?: string;\n channelsToSnapshot?: Set<string>;\n /** The channel versions of the last checkpoint the saver stored. */\n storedVersions?: Record<string, number | string>;\n getNextVersion?: (current: number | string | undefined) => number | string;\n triggerToNodes?: Record<string, string[]>;\n }\n): Checkpoint {\n const channelsToSnapshot = options?.channelsToSnapshot ?? new Set<string>();\n const { storedVersions, getNextVersion } = options ?? {};\n const bumped: Record<string, [number | string | undefined, number | string]> =\n {};\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let values: Record<string, any>;\n let channelVersions: Record<string, number | string> =\n checkpoint.channel_versions;\n if (channels === undefined) {\n values = checkpoint.channel_values;\n } else {\n values = {};\n channelVersions = { ...checkpoint.channel_versions };\n for (const k in channels) {\n if (!Object.prototype.hasOwnProperty.call(channels, k)) continue;\n const channel = channels[k];\n if (channelsToSnapshot.has(k)) {\n // `put` only stores a blob for a channel whose version moved, so\n // snapshotting a channel that didn't move since the last stored\n // checkpoint needs a bump: exit mode reaching the cadence on a\n // superstep that skipped the channel, and a fork's first checkpoint.\n if (\n getNextVersion !== undefined &&\n storedVersions !== undefined &&\n channelVersions[k] === storedVersions[k]\n ) {\n const old = channelVersions[k];\n channelVersions[k] = getNextVersion(old);\n bumped[k] = [old, channelVersions[k]];\n }\n values[k] = new DeltaSnapshot(channel.get());\n continue;\n }\n if (isDeltaChannel(channel)) {\n // Omitted from channel_values; reconstructed from ancestor writes.\n continue;\n }\n try {\n values[k] = channel.checkpoint();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n if (error.name === EmptyChannelError.unminifiable_name) {\n // no-op\n } else {\n throw error; // Rethrow unexpected errors\n }\n }\n }\n }\n\n return {\n v: 4,\n id: options?.id ?? uuid6(step),\n ts: new Date().toISOString(),\n channel_values: values,\n channel_versions: channelVersions,\n versions_seen: markBumpsSeen(\n checkpoint.versions_seen,\n bumped,\n options?.triggerToNodes\n ),\n };\n}\n\n/**\n * Advance whoever had seen a bumped channel's old version to the new one.\n *\n * A bump that only stores a snapshot is not a write. Left unseen, it would\n * re-fire `interruptBefore` and rerun the channel's subscribers. A channel\n * bumped from no version was never written, so it also goes to the\n * subscribers that never ran: they have no entry, and would start on the bump.\n * For each entry it advances, {@link SNAPSHOT_BUMPS} keeps the new version and\n * the one the node really read, so {@link versionsSeenWithoutBumps} can put\n * the read back.\n */\nfunction markBumpsSeen(\n versionsSeen: ReadonlyCheckpoint[\"versions_seen\"],\n bumped: Record<string, [number | string | undefined, number | string]>,\n triggerToNodes: Record<string, string[]> = {}\n): Checkpoint[\"versions_seen\"] {\n if (Object.keys(bumped).length === 0) return versionsSeen;\n const out = { ...versionsSeen };\n for (const [k, [old]] of Object.entries(bumped)) {\n if (old !== undefined) continue;\n for (const node of triggerToNodes[k] ?? []) out[node] ??= {};\n }\n const marks = { ...versionsSeen[SNAPSHOT_BUMPS] };\n for (const node in out) {\n if (\n !Object.prototype.hasOwnProperty.call(out, node) ||\n node === SNAPSHOT_BUMPS\n ) {\n continue;\n }\n for (const [k, [old, next]] of Object.entries(bumped)) {\n if (out[node][k] !== old) continue;\n const [advanced, read] = bumpKeys(node, k);\n // If an earlier bump set `old`, the real read is already recorded.\n if (old !== undefined && marks[advanced] !== old) marks[read] = old;\n marks[advanced] = next;\n out[node] = { ...out[node], [k]: next };\n }\n }\n if (Object.keys(marks).length > 0) out[SNAPSHOT_BUMPS] = marks;\n return out;\n}\n\n// Node names can't contain either separator, so the keys can't collide.\nconst bumpKeys = (node: string, channel: string): [string, string] => [\n `${node}${CHECKPOINT_NAMESPACE_SEPARATOR}${channel}`,\n `${node}${CHECKPOINT_NAMESPACE_END}${channel}`,\n];\n\n/**\n * `versions_seen` as the nodes read it: an entry a snapshot bump advanced goes\n * back to the version the node really read, or away if it never read one.\n */\nexport function versionsSeenWithoutBumps(\n versionsSeen: ReadonlyCheckpoint[\"versions_seen\"]\n): ReadonlyCheckpoint[\"versions_seen\"] {\n const marks = versionsSeen[SNAPSHOT_BUMPS];\n if (marks === undefined || Object.keys(marks).length === 0) {\n return versionsSeen;\n }\n const out: Checkpoint[\"versions_seen\"] = {};\n for (const node in versionsSeen) {\n if (\n !Object.prototype.hasOwnProperty.call(versionsSeen, node) ||\n node === SNAPSHOT_BUMPS\n ) {\n continue;\n }\n out[node] = {};\n for (const [k, v] of Object.entries(versionsSeen[node])) {\n const [advanced, read] = bumpKeys(node, k);\n if (marks[advanced] !== v) out[node][k] = v;\n else if (read in marks) out[node][k] = marks[read];\n }\n }\n return out;\n}\n\n/**\n * Checkpoint metadata key, `true` when every DeltaChannel write on the\n * checkpoint's branch carries a version. A delta channel with no version there\n * was never written, so it needs no walk. Branches started before this key\n * existed never get it: an older `updateState` stored a delta channel's first\n * write without a version, and only the walk finds such a write.\n */\nexport const DELTA_WRITES_VERSIONED = \"delta_writes_versioned\";\n\nexport function isDeltaWritesVersioned(\n metadata: CheckpointMetadata | undefined\n): boolean {\n return (\n (metadata as Record<string, unknown> | undefined)?.[\n DELTA_WRITES_VERSIONED\n ] === true\n );\n}\n\n/**\n * Channels whose value at `checkpoint` the ancestor walk rebuilds.\n *\n * A {@link DeltaSnapshot} or a migrated plain value in `channel_values`\n * resolves directly, so only a channel with nothing stored there needs the\n * walk. With `versionedOnly`, a channel with no version was never written, so\n * it is empty without one; a walk for it would find no snapshot to stop at and\n * read every ancestor, every time the thread is loaded.\n *\n * A `BinaryOperatorAggregate` stores its value at every version, so one with a\n * version and nothing stored was written as a DeltaChannel before its\n * annotation changed, and is rebuilt the same way.\n */\nfunction deltaChannelsToReplay(\n specs: Record<string, BaseChannel>,\n checkpoint: ReadonlyCheckpoint,\n versionedOnly: boolean\n): string[] {\n const keys: string[] = [];\n for (const k in specs) {\n if (!Object.prototype.hasOwnProperty.call(specs, k)) continue;\n if (Object.prototype.hasOwnProperty.call(checkpoint.channel_values, k)) {\n continue;\n }\n const versioned = checkpoint.channel_versions[k] !== undefined;\n if (\n (isDeltaChannel(specs[k]) && (versioned || !versionedOnly)) ||\n (specs[k].lc_graph_name === \"BinaryOperatorAggregate\" && versioned)\n ) {\n keys.push(k);\n }\n }\n return keys;\n}\n\n/**\n * Hydrate channels from a checkpoint, reconstructing any {@link DeltaChannel}\n * whose value is absent from `channel_values` by replaying ancestor writes.\n *\n * For most channels (and for delta channels with a {@link DeltaSnapshot} or a\n * migrated plain value in `channel_values`), {@link emptyChannels} is\n * sufficient and no saver access is required. When a delta channel is absent\n * from `channel_values`, an ancestor walk via `saver.getDeltaChannelHistory`\n * finds the nearest seed and accumulates the writes between it and the\n * target. All delta channels needing replay are batched into a single saver\n * call. Pass `deltaWritesVersioned` for a checkpoint whose metadata carries\n * {@link DELTA_WRITES_VERSIONED}, so delta channels without a version are\n * left empty instead of walked.\n */\nexport async function channelsFromCheckpoint<\n Cc extends Record<string, BaseChannel>,\n>(\n specs: Cc,\n checkpoint: ReadonlyCheckpoint,\n options?: {\n saver?: BaseCheckpointSaver;\n config?: RunnableConfig;\n deltaWritesVersioned?: boolean;\n }\n): Promise<Cc> {\n const channels = emptyChannels(specs, checkpoint);\n const { saver, config } = options ?? {};\n\n const filteredSpecs = getOnlyChannels(specs);\n const deltaKeys = deltaChannelsToReplay(\n filteredSpecs,\n checkpoint,\n options?.deltaWritesVersioned ?? false\n );\n\n const written = deltaKeys.filter(\n (k) => checkpoint.channel_versions[k] !== undefined\n );\n if ((saver === undefined || config === undefined) && written.length > 0) {\n throw new Error(\n `DeltaChannel ${written.join(\", \")} has history to replay but no checkpointer or config was passed to read it`\n );\n }\n if (deltaKeys.length === 0 || saver === undefined || config === undefined) {\n return channels;\n }\n\n const histories = await saver.getDeltaChannelHistory({\n config,\n channels: deltaKeys,\n });\n for (const k of deltaKeys) {\n const history = histories[k];\n if (history === undefined) continue;\n const replayCh = filteredSpecs[k].fromCheckpoint(history.seed);\n if (isDeltaChannel(replayCh)) {\n (replayCh as DeltaChannelLike).replayWrites(history.writes);\n } else {\n // One update per write: the writes span many supersteps, and a single\n // call would reject a second Overwrite and drop the writes after one.\n for (const [, , value] of history.writes) replayCh.update([value]);\n }\n (channels as Record<string, BaseChannel>)[k] = replayCh;\n }\n return channels;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"base.d.cts","names":[],"sources":["../../src/channels/base.ts"],"mappings":";;;;;;AA4BA;;iBAAgB,cAAA,CAAe,OAAA,EAAS,WAAA;AAgBxC;AAAA,uBAAsB,WAAA;EAKpB,SAAA,EAAW,SAAA;EAEX,UAAA,EAAY,UAAA;EAAA;;;EAAA,SAKH,aAAA;EA4Cc;EAzCvB,aAAA;EA0FyB;;;;;;;;EAAA,SAhFhB,cAAA,CAAe,UAAA,GAAa,cAAA;EAb5B;;;;;;;;;;;;;EAAA,SA4BA,MAAA,CAAO,MAAA,EAAQ,UAAA;EA4CxB;;;;;;EAAA,SApCS,GAAA,CAAA,GAAO,SAAA;EAgFW;;;;;;EAAA,SAxElB,UAAA,CAAA,GAAc,cAAA;EA2EpB;;;;;;;EAlEH,OAAA,CAAA;EAiEA;;;;AA+BF;;EAtFE,MAAA,CAAA;EAsF8B;;AAoBhC;;;EAjGE,WAAA,CAAA;EAiG8D;AAkBhE;;;;;;;EA9FE,MAAA,CAAO,KAAA,EAAO,WAAA;AAAA;AAAA,iBAuBA,aAAA,YAAyB,MAAA,SAAe,WAAA,EAAA,CACtD,QAAA,EAAU,EAAA,EACV,UAAA,EAAY,kBAAA,GACX,EAAA;;;;;;;AA4FH;;iBA9DgB,eAAA,CAAgB,IAAA,UAAc,MAAA;;;;;;;;;;;iBAoB9B,mBAAA,CAAoB,IAAA,UAAc,MAAA;;;;;;;AA6ElD;;iBA3DgB,8BAAA,CACd,QAAA,EAAU,MAAA,SAAe,WAAA,GACzB,aAAA,EAAe,aAAA,0CACd,GAAA;;;;;;;;;;;;iBAqBa,uBAAA,CACd,QAAA,EAAU,MAAA,SAAe,WAAA,GACzB,0BAAA,EAA4B,MAAA,4BAC5B,eAAA,EAAiB,MAAA,wCAChB,GAAA;AAAA,iBA+Ba,gBAAA,WAAA,CACd,UAAA,EAAY,kBAAA,EACZ,QAAA,EAAU,MAAA,SAAe,WAAA,CAAY,SAAA,gBACrC,IAAA,UACA,OAAA;EACE,EAAA;EACA,kBAAA,GAAqB,GAAA,UAHvB;EAKE,cAAA,GAAiB,MAAA;EACjB,cAAA,IAAkB,OAAA;EAClB,cAAA,GAAiB,MAAA;AAAA,IAElB,UAAA;;;;;;;;;;;;;;;iBA4MmB,sBAAA,YACT,MAAA,SAAe,WAAA,EAAA,CAE1B,KAAA,EAAO,EAAA,EACP,UAAA,EAAY,kBAAA,EACZ,OAAA;EACE,KAAA,GAAQ,mBAAA;EACR,MAAA,GAAS,cAAA;EACT,oBAAA;AAAA,IAED,OAAA,CAAQ,EAAA"}
1
+ {"version":3,"file":"base.d.cts","names":[],"sources":["../../src/channels/base.ts"],"mappings":";;;;;;AA4BA;;iBAAgB,cAAA,CAAe,OAAA,EAAS,WAAA;AAgBxC;AAAA,uBAAsB,WAAA;EAKpB,SAAA,EAAW,SAAA;EAEX,UAAA,EAAY,UAAA;EAAA;;;EAAA,SAKH,aAAA;EA4Cc;EAzCvB,aAAA;EA0FyB;;;;;;;;EAAA,SAhFhB,cAAA,CAAe,UAAA,GAAa,cAAA;EAb5B;;;;;;;;;;;;;EAAA,SA4BA,MAAA,CAAO,MAAA,EAAQ,UAAA;EA4CxB;;;;;;EAAA,SApCS,GAAA,CAAA,GAAO,SAAA;EAgFW;;;;;;EAAA,SAxElB,UAAA,CAAA,GAAc,cAAA;EA2EpB;;;;;;;EAlEH,OAAA,CAAA;EAiEA;;;;AA+BF;;EAtFE,MAAA,CAAA;EAsF8B;;AAoBhC;;;EAjGE,WAAA,CAAA;EAiG8D;AAkBhE;;;;;;;EA9FE,MAAA,CAAO,KAAA,EAAO,WAAA;AAAA;AAAA,iBAuBA,aAAA,YAAyB,MAAA,SAAe,WAAA,EAAA,CACtD,QAAA,EAAU,EAAA,EACV,UAAA,EAAY,kBAAA,GACX,EAAA;;;;;;;AA4FH;;iBA9DgB,eAAA,CAAgB,IAAA,UAAc,MAAA;;;;;;;;;;;iBAoB9B,mBAAA,CAAoB,IAAA,UAAc,MAAA;;;;;;;AA6ElD;;iBA3DgB,8BAAA,CACd,QAAA,EAAU,MAAA,SAAe,WAAA,GACzB,aAAA,EAAe,aAAA,0CACd,GAAA;;;;;;;;;;;;iBAqBa,uBAAA,CACd,QAAA,EAAU,MAAA,SAAe,WAAA,GACzB,0BAAA,EAA4B,MAAA,4BAC5B,eAAA,EAAiB,MAAA,wCAChB,GAAA;AAAA,iBA+Ba,gBAAA,WAAA,CACd,UAAA,EAAY,kBAAA,EACZ,QAAA,EAAU,MAAA,SAAe,WAAA,CAAY,SAAA,gBACrC,IAAA,UACA,OAAA;EACE,EAAA;EACA,kBAAA,GAAqB,GAAA,UAHvB;EAKE,cAAA,GAAiB,MAAA;EACjB,cAAA,IAAkB,OAAA;EAClB,cAAA,GAAiB,MAAA;AAAA,IAElB,UAAA;;;;;;;;;;;;;;;iBAmNmB,sBAAA,YACT,MAAA,SAAe,WAAA,EAAA,CAE1B,KAAA,EAAO,EAAA,EACP,UAAA,EAAY,kBAAA,EACZ,OAAA;EACE,KAAA,GAAQ,mBAAA;EACR,MAAA,GAAS,cAAA;EACT,oBAAA;AAAA,IAED,OAAA,CAAQ,EAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"base.d.ts","names":[],"sources":["../../src/channels/base.ts"],"mappings":";;;;;;AA4BA;;iBAAgB,cAAA,CAAe,OAAA,EAAS,WAAA;AAgBxC;AAAA,uBAAsB,WAAA;EAKpB,SAAA,EAAW,SAAA;EAEX,UAAA,EAAY,UAAA;EAAA;;;EAAA,SAKH,aAAA;EA4Cc;EAzCvB,aAAA;EA0FyB;;;;;;;;EAAA,SAhFhB,cAAA,CAAe,UAAA,GAAa,cAAA;EAb5B;;;;;;;;;;;;;EAAA,SA4BA,MAAA,CAAO,MAAA,EAAQ,UAAA;EA4CxB;;;;;;EAAA,SApCS,GAAA,CAAA,GAAO,SAAA;EAgFW;;;;;;EAAA,SAxElB,UAAA,CAAA,GAAc,cAAA;EA2EpB;;;;;;;EAlEH,OAAA,CAAA;EAiEA;;;;AA+BF;;EAtFE,MAAA,CAAA;EAsF8B;;AAoBhC;;;EAjGE,WAAA,CAAA;EAiG8D;AAkBhE;;;;;;;EA9FE,MAAA,CAAO,KAAA,EAAO,WAAA;AAAA;AAAA,iBAuBA,aAAA,YAAyB,MAAA,SAAe,WAAA,EAAA,CACtD,QAAA,EAAU,EAAA,EACV,UAAA,EAAY,kBAAA,GACX,EAAA;;;;;;;AA4FH;;iBA9DgB,eAAA,CAAgB,IAAA,UAAc,MAAA;;;;;;;;;;;iBAoB9B,mBAAA,CAAoB,IAAA,UAAc,MAAA;;;;;;;AA6ElD;;iBA3DgB,8BAAA,CACd,QAAA,EAAU,MAAA,SAAe,WAAA,GACzB,aAAA,EAAe,aAAA,0CACd,GAAA;;;;;;;;;;;;iBAqBa,uBAAA,CACd,QAAA,EAAU,MAAA,SAAe,WAAA,GACzB,0BAAA,EAA4B,MAAA,4BAC5B,eAAA,EAAiB,MAAA,wCAChB,GAAA;AAAA,iBA+Ba,gBAAA,WAAA,CACd,UAAA,EAAY,kBAAA,EACZ,QAAA,EAAU,MAAA,SAAe,WAAA,CAAY,SAAA,gBACrC,IAAA,UACA,OAAA;EACE,EAAA;EACA,kBAAA,GAAqB,GAAA,UAHvB;EAKE,cAAA,GAAiB,MAAA;EACjB,cAAA,IAAkB,OAAA;EAClB,cAAA,GAAiB,MAAA;AAAA,IAElB,UAAA;;;;;;;;;;;;;;;iBA4MmB,sBAAA,YACT,MAAA,SAAe,WAAA,EAAA,CAE1B,KAAA,EAAO,EAAA,EACP,UAAA,EAAY,kBAAA,EACZ,OAAA;EACE,KAAA,GAAQ,mBAAA;EACR,MAAA,GAAS,cAAA;EACT,oBAAA;AAAA,IAED,OAAA,CAAQ,EAAA"}
1
+ {"version":3,"file":"base.d.ts","names":[],"sources":["../../src/channels/base.ts"],"mappings":";;;;;;AA4BA;;iBAAgB,cAAA,CAAe,OAAA,EAAS,WAAA;AAgBxC;AAAA,uBAAsB,WAAA;EAKpB,SAAA,EAAW,SAAA;EAEX,UAAA,EAAY,UAAA;EAAA;;;EAAA,SAKH,aAAA;EA4Cc;EAzCvB,aAAA;EA0FyB;;;;;;;;EAAA,SAhFhB,cAAA,CAAe,UAAA,GAAa,cAAA;EAb5B;;;;;;;;;;;;;EAAA,SA4BA,MAAA,CAAO,MAAA,EAAQ,UAAA;EA4CxB;;;;;;EAAA,SApCS,GAAA,CAAA,GAAO,SAAA;EAgFW;;;;;;EAAA,SAxElB,UAAA,CAAA,GAAc,cAAA;EA2EpB;;;;;;;EAlEH,OAAA,CAAA;EAiEA;;;;AA+BF;;EAtFE,MAAA,CAAA;EAsF8B;;AAoBhC;;;EAjGE,WAAA,CAAA;EAiG8D;AAkBhE;;;;;;;EA9FE,MAAA,CAAO,KAAA,EAAO,WAAA;AAAA;AAAA,iBAuBA,aAAA,YAAyB,MAAA,SAAe,WAAA,EAAA,CACtD,QAAA,EAAU,EAAA,EACV,UAAA,EAAY,kBAAA,GACX,EAAA;;;;;;;AA4FH;;iBA9DgB,eAAA,CAAgB,IAAA,UAAc,MAAA;;;;;;;;;;;iBAoB9B,mBAAA,CAAoB,IAAA,UAAc,MAAA;;;;;;;AA6ElD;;iBA3DgB,8BAAA,CACd,QAAA,EAAU,MAAA,SAAe,WAAA,GACzB,aAAA,EAAe,aAAA,0CACd,GAAA;;;;;;;;;;;;iBAqBa,uBAAA,CACd,QAAA,EAAU,MAAA,SAAe,WAAA,GACzB,0BAAA,EAA4B,MAAA,4BAC5B,eAAA,EAAiB,MAAA,wCAChB,GAAA;AAAA,iBA+Ba,gBAAA,WAAA,CACd,UAAA,EAAY,kBAAA,EACZ,QAAA,EAAU,MAAA,SAAe,WAAA,CAAY,SAAA,gBACrC,IAAA,UACA,OAAA;EACE,EAAA;EACA,kBAAA,GAAqB,GAAA,UAHvB;EAKE,cAAA,GAAiB,MAAA;EACjB,cAAA,IAAkB,OAAA;EAClB,cAAA,GAAiB,MAAA;AAAA,IAElB,UAAA;;;;;;;;;;;;;;;iBAmNmB,sBAAA,YACT,MAAA,SAAe,WAAA,EAAA,CAE1B,KAAA,EAAO,EAAA,EACP,UAAA,EAAY,kBAAA,EACZ,OAAA;EACE,KAAA,GAAQ,mBAAA;EACR,MAAA,GAAS,cAAA;EACT,oBAAA;AAAA,IAED,OAAA,CAAQ,EAAA"}
@@ -269,19 +269,25 @@ function isDeltaWritesVersioned(metadata) {
269
269
  return metadata?.[DELTA_WRITES_VERSIONED] === true;
270
270
  }
271
271
  /**
272
- * Delta channels whose value at `checkpoint` the ancestor walk rebuilds.
272
+ * Channels whose value at `checkpoint` the ancestor walk rebuilds.
273
273
  *
274
274
  * A {@link DeltaSnapshot} or a migrated plain value in `channel_values`
275
275
  * resolves directly, so only a channel with nothing stored there needs the
276
276
  * walk. With `versionedOnly`, a channel with no version was never written, so
277
277
  * it is empty without one; a walk for it would find no snapshot to stop at and
278
278
  * read every ancestor, every time the thread is loaded.
279
+ *
280
+ * A `BinaryOperatorAggregate` stores its value at every version, so one with a
281
+ * version and nothing stored was written as a DeltaChannel before its
282
+ * annotation changed, and is rebuilt the same way.
279
283
  */
280
284
  function deltaChannelsToReplay(specs, checkpoint, versionedOnly) {
281
285
  const keys = [];
282
286
  for (const k in specs) {
283
287
  if (!Object.prototype.hasOwnProperty.call(specs, k)) continue;
284
- if (isDeltaChannel(specs[k]) && (!versionedOnly || checkpoint.channel_versions[k] !== void 0) && !Object.prototype.hasOwnProperty.call(checkpoint.channel_values, k)) keys.push(k);
288
+ if (Object.prototype.hasOwnProperty.call(checkpoint.channel_values, k)) continue;
289
+ const versioned = checkpoint.channel_versions[k] !== void 0;
290
+ if (isDeltaChannel(specs[k]) && (versioned || !versionedOnly) || specs[k].lc_graph_name === "BinaryOperatorAggregate" && versioned) keys.push(k);
285
291
  }
286
292
  return keys;
287
293
  }
@@ -315,7 +321,8 @@ async function channelsFromCheckpoint(specs, checkpoint, options) {
315
321
  const history = histories[k];
316
322
  if (history === void 0) continue;
317
323
  const replayCh = filteredSpecs[k].fromCheckpoint(history.seed);
318
- replayCh.replayWrites(history.writes);
324
+ if (isDeltaChannel(replayCh)) replayCh.replayWrites(history.writes);
325
+ else for (const [, , value] of history.writes) replayCh.update([value]);
319
326
  channels[k] = replayCh;
320
327
  }
321
328
  return channels;
@@ -1 +1 @@
1
- {"version":3,"file":"base.js","names":[],"sources":["../../src/channels/base.ts"],"sourcesContent":["import {\n ReadonlyCheckpoint,\n uuid6,\n Checkpoint,\n DeltaSnapshot,\n type BaseCheckpointSaver,\n type CheckpointMetadata,\n type DeltaChannelHistory,\n} from \"@langchain/langgraph-checkpoint\";\nimport type { RunnableConfig } from \"@langchain/core/runnables\";\nimport { EmptyChannelError } from \"../errors.js\";\nimport {\n CHECKPOINT_NAMESPACE_END,\n CHECKPOINT_NAMESPACE_SEPARATOR,\n EXIT_DELTA_NULL_TASK_ID,\n getDeltaMaxSuperstepsSinceSnapshot,\n NULL_TASK_ID,\n SNAPSHOT_BUMPS,\n} from \"../constants.js\";\n\n/** Matches Postgres `uuid` / Python `uuid.UUID` (128-bit, 8-4-4-4-12 hex). */\nconst STRUCTURED_UUID =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * Structural check for a {@link DeltaChannel} without importing it (avoids an\n * import cycle: `delta.ts` imports `base.ts`).\n */\nexport function isDeltaChannel(channel: BaseChannel): boolean {\n return channel != null && channel.lc_graph_name === \"DeltaChannel\";\n}\n\nexport function deltaChannelWrites<W extends readonly [PropertyKey, unknown]>(\n channels: Record<string, BaseChannel>,\n writes: ReadonlyArray<W>\n): W[] {\n return writes.filter(([ch]) => isDeltaChannel(channels[String(ch)]));\n}\n\nexport function isBaseChannel(obj: unknown): obj is BaseChannel {\n return obj != null && (obj as BaseChannel).lg_is_channel === true;\n}\n\n/** @internal */\nexport abstract class BaseChannel<\n ValueType = unknown,\n UpdateType = unknown,\n CheckpointType = unknown,\n> {\n ValueType: ValueType;\n\n UpdateType: UpdateType;\n\n /**\n * The name of the channel.\n */\n abstract lc_graph_name: string;\n\n /** @ignore */\n lg_is_channel = true;\n\n /**\n * Return a new identical channel, optionally initialized from a checkpoint.\n * Can be thought of as a \"restoration\" from a checkpoint which is a \"snapshot\" of the channel's state.\n *\n * @param {CheckpointType | undefined} checkpoint\n * @param {CheckpointType | undefined} initialValue\n * @returns {this}\n */\n abstract fromCheckpoint(checkpoint?: CheckpointType): this;\n\n /**\n * Update the channel's value with the given sequence of updates.\n * The order of the updates in the sequence is arbitrary.\n * This method is called by Pregel for all channels at the end of each step.\n * If there are no updates, it is called with an empty sequence.\n *\n * Raises InvalidUpdateError if the sequence of updates is invalid.\n * Returns True if the channel was updated, False otherwise.\n *\n * @throws {InvalidUpdateError} if the sequence of updates is invalid.\n * @param {Array<UpdateType>} values\n * @returns {void}\n */\n abstract update(values: UpdateType[]): boolean;\n\n /**\n * Return the current value of the channel.\n *\n * @throws {EmptyChannelError} if the channel is empty (never updated yet).\n * @returns {ValueType}\n */\n abstract get(): ValueType;\n\n /**\n * Return a string representation of the channel's current state.\n *\n * @throws {EmptyChannelError} if the channel is empty (never updated yet), or doesn't support checkpoints.\n * @returns {CheckpointType | undefined}\n */\n abstract checkpoint(): CheckpointType | undefined;\n\n /**\n * Mark the current value of the channel as consumed. By default, no-op.\n * A channel can use this method to modify its state, preventing the value\n * from being consumed again.\n *\n * Returns True if the channel was updated, False otherwise.\n */\n consume(): boolean {\n return false;\n }\n\n /**\n * Notify the channel that the Pregel run is finishing. By default, no-op.\n * A channel can use this method to modify its state, preventing finish.\n *\n * Returns True if the channel was updated, False otherwise.\n */\n finish(): boolean {\n return false;\n }\n\n /**\n * Return True if the channel is available (not empty), False otherwise.\n * Subclasses should override this method to provide a more efficient\n * implementation than calling get() and catching EmptyChannelError.\n */\n isAvailable(): boolean {\n try {\n this.get();\n return true;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n if (error.name === EmptyChannelError.unminifiable_name) {\n return false;\n }\n throw error;\n }\n }\n\n /**\n * Compare this channel with another channel for equality.\n * Used to determine if two channels with the same key are semantically equivalent.\n * Subclasses should override this method to provide a meaningful comparison.\n *\n * @param {BaseChannel} other - The other channel to compare with.\n * @returns {boolean} True if the channels are equal, false otherwise.\n */\n equals(other: BaseChannel): boolean {\n return this === other;\n }\n}\n\nconst IS_ONLY_BASE_CHANNEL = Symbol.for(\"LG_IS_ONLY_BASE_CHANNEL\");\nexport function getOnlyChannels(\n channels: Record<string, BaseChannel>\n): Record<string, BaseChannel> {\n // @ts-expect-error - we know it's a record of base channels\n if (channels[IS_ONLY_BASE_CHANNEL] === true) return channels;\n\n const newChannels = {} as Record<string, BaseChannel>;\n for (const k in channels) {\n if (!Object.prototype.hasOwnProperty.call(channels, k)) continue;\n const value = channels[k];\n if (isBaseChannel(value)) newChannels[k] = value;\n }\n\n Object.assign(newChannels, { [IS_ONLY_BASE_CHANNEL]: true });\n return newChannels;\n}\n\nexport function emptyChannels<Cc extends Record<string, BaseChannel>>(\n channels: Cc,\n checkpoint: ReadonlyCheckpoint\n): Cc {\n const filteredChannels = getOnlyChannels(channels) as Cc;\n\n const newChannels = {} as Cc;\n for (const k in filteredChannels) {\n if (!Object.prototype.hasOwnProperty.call(filteredChannels, k)) continue;\n const channelValue = checkpoint.channel_values[k];\n newChannels[k] = filteredChannels[k].fromCheckpoint(channelValue);\n }\n Object.assign(newChannels, { [IS_ONLY_BASE_CHANNEL]: true });\n return newChannels;\n}\n\n/**\n * Minimal structural view of a {@link DeltaChannel}, used by helpers in this\n * module that must not import the concrete class (import-cycle avoidance).\n */\ninterface DeltaChannelLike extends BaseChannel {\n snapshotFrequency: number;\n replayWrites(writes: DeltaChannelHistory[\"writes\"]): void;\n}\n\n/**\n * Synthetic task id for exit-mode DeltaChannel writes.\n *\n * Embeds the superstep in the first UUID group so `ORDER BY task_id, idx`\n * preserves chronological order while remaining a valid RFC UUID (required by\n * Postgres `checkpoint_writes.task_id uuid` columns). Never `NULL_TASK_ID`:\n * readers apply writes under it as the anchor checkpoint's own pending writes.\n */\nexport function exitDeltaTaskId(step: number, taskId: string): string {\n if (!STRUCTURED_UUID.test(taskId)) {\n throw new TypeError(`Invalid task id for exit delta: ${taskId}`);\n }\n const parts = taskId.toLowerCase().split(\"-\");\n const stepPart = String(step).padStart(8, \"0\");\n const synthetic = `${stepPart}-${parts[1]}-${parts[2]}-${parts[3]}-${parts[4]}`;\n return synthetic === NULL_TASK_ID ? EXIT_DELTA_NULL_TASK_ID : synthetic;\n}\n\n/**\n * Synthetic task id for exit-mode writes of a superstep after the anchor's\n * own.\n *\n * Sorts after every real task id, in step order, so replay keeps them after\n * the anchor's own superstep whether a saver orders writes by task path\n * (`writesSortKey`) or by task id. Mirrors Python's\n * `exit_delta_late_task_id` exactly, including the two hexadecimal step\n * groups (step is split across them).\n */\nexport function exitDeltaLateTaskId(step: number, taskId: string): string {\n if (!STRUCTURED_UUID.test(taskId)) {\n throw new TypeError(`Invalid task id for exit delta: ${taskId}`);\n }\n const parts = taskId.toLowerCase().split(\"-\");\n const stepHi = (step >> 16).toString(16).padStart(4, \"0\");\n const stepLo = (step & 0xffff).toString(16).padStart(4, \"0\");\n return `ffffffff-${stepHi}-${stepLo}-${parts[3]}-${parts[4]}`;\n}\n\n/**\n * DeltaChannels a branch starting from this checkpoint must snapshot.\n *\n * A checkpoint's pending writes belong to the child that consumed them, and\n * nothing records which child that was. A new branch snapshots every delta\n * channel they touch, so its ancestor walk never replays them (port of\n * Python #8548's `delta_channels_with_pending_writes`).\n */\nexport function deltaChannelsWithPendingWrites(\n channels: Record<string, BaseChannel>,\n pendingWrites: ReadonlyArray<[string, string, unknown]> | undefined\n): Set<string> {\n const result = new Set<string>();\n if (pendingWrites === undefined) return result;\n for (const [, ch] of pendingWrites) {\n const channel = channels[ch];\n if (channel != null && isDeltaChannel(channel)) result.add(ch);\n }\n return result;\n}\n\n/**\n * Return the set of {@link DeltaChannel} names that should snapshot now.\n *\n * A channel snapshots when EITHER its accumulated update count reaches\n * `snapshotFrequency` OR the total supersteps since its last snapshot reaches\n * `DELTA_MAX_SUPERSTEPS_SINCE_SNAPSHOT`. Given `channelVersions`, a channel\n * without a version is skipped: it was never written on this branch, so it\n * has nothing to snapshot. Pass `undefined` on a branch without\n * {@link DELTA_WRITES_VERSIONED}, where such a channel can still hold writes\n * and this snapshot is what bounds its walk. Pure predicate, no mutation.\n */\nexport function deltaChannelsToSnapshot(\n channels: Record<string, BaseChannel>,\n countersSinceDeltaSnapshot: Record<string, [number, number]>,\n channelVersions: Record<string, number | string> | undefined\n): Set<string> {\n const result = new Set<string>();\n for (const name in channels) {\n if (!Object.prototype.hasOwnProperty.call(channels, name)) continue;\n const ch = channels[name];\n if (\n !isDeltaChannel(ch) ||\n !ch.isAvailable() ||\n (channelVersions !== undefined && channelVersions[name] === undefined)\n ) {\n continue;\n }\n if (reachedSnapshotBound(ch, countersSinceDeltaSnapshot[name])) {\n result.add(name);\n }\n }\n return result;\n}\n\n/** Whether a delta channel's counters reached the bound where it snapshots. */\nexport function reachedSnapshotBound(\n channel: BaseChannel,\n counters: [number, number] | undefined\n): boolean {\n const [updates, supersteps] = counters ?? [0, 0];\n return (\n updates >= (channel as DeltaChannelLike).snapshotFrequency ||\n supersteps >= getDeltaMaxSuperstepsSinceSnapshot()\n );\n}\n\nexport function createCheckpoint<ValueType>(\n checkpoint: ReadonlyCheckpoint,\n channels: Record<string, BaseChannel<ValueType>> | undefined,\n step: number,\n options?: {\n id?: string;\n channelsToSnapshot?: Set<string>;\n /** The channel versions of the last checkpoint the saver stored. */\n storedVersions?: Record<string, number | string>;\n getNextVersion?: (current: number | string | undefined) => number | string;\n triggerToNodes?: Record<string, string[]>;\n }\n): Checkpoint {\n const channelsToSnapshot = options?.channelsToSnapshot ?? new Set<string>();\n const { storedVersions, getNextVersion } = options ?? {};\n const bumped: Record<string, [number | string | undefined, number | string]> =\n {};\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let values: Record<string, any>;\n let channelVersions: Record<string, number | string> =\n checkpoint.channel_versions;\n if (channels === undefined) {\n values = checkpoint.channel_values;\n } else {\n values = {};\n channelVersions = { ...checkpoint.channel_versions };\n for (const k in channels) {\n if (!Object.prototype.hasOwnProperty.call(channels, k)) continue;\n const channel = channels[k];\n if (channelsToSnapshot.has(k)) {\n // `put` only stores a blob for a channel whose version moved, so\n // snapshotting a channel that didn't move since the last stored\n // checkpoint needs a bump: exit mode reaching the cadence on a\n // superstep that skipped the channel, and a fork's first checkpoint.\n if (\n getNextVersion !== undefined &&\n storedVersions !== undefined &&\n channelVersions[k] === storedVersions[k]\n ) {\n const old = channelVersions[k];\n channelVersions[k] = getNextVersion(old);\n bumped[k] = [old, channelVersions[k]];\n }\n values[k] = new DeltaSnapshot(channel.get());\n continue;\n }\n if (isDeltaChannel(channel)) {\n // Omitted from channel_values; reconstructed from ancestor writes.\n continue;\n }\n try {\n values[k] = channel.checkpoint();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n if (error.name === EmptyChannelError.unminifiable_name) {\n // no-op\n } else {\n throw error; // Rethrow unexpected errors\n }\n }\n }\n }\n\n return {\n v: 4,\n id: options?.id ?? uuid6(step),\n ts: new Date().toISOString(),\n channel_values: values,\n channel_versions: channelVersions,\n versions_seen: markBumpsSeen(\n checkpoint.versions_seen,\n bumped,\n options?.triggerToNodes\n ),\n };\n}\n\n/**\n * Advance whoever had seen a bumped channel's old version to the new one.\n *\n * A bump that only stores a snapshot is not a write. Left unseen, it would\n * re-fire `interruptBefore` and rerun the channel's subscribers. A channel\n * bumped from no version was never written, so it also goes to the\n * subscribers that never ran: they have no entry, and would start on the bump.\n * For each entry it advances, {@link SNAPSHOT_BUMPS} keeps the new version and\n * the one the node really read, so {@link versionsSeenWithoutBumps} can put\n * the read back.\n */\nfunction markBumpsSeen(\n versionsSeen: ReadonlyCheckpoint[\"versions_seen\"],\n bumped: Record<string, [number | string | undefined, number | string]>,\n triggerToNodes: Record<string, string[]> = {}\n): Checkpoint[\"versions_seen\"] {\n if (Object.keys(bumped).length === 0) return versionsSeen;\n const out = { ...versionsSeen };\n for (const [k, [old]] of Object.entries(bumped)) {\n if (old !== undefined) continue;\n for (const node of triggerToNodes[k] ?? []) out[node] ??= {};\n }\n const marks = { ...versionsSeen[SNAPSHOT_BUMPS] };\n for (const node in out) {\n if (\n !Object.prototype.hasOwnProperty.call(out, node) ||\n node === SNAPSHOT_BUMPS\n ) {\n continue;\n }\n for (const [k, [old, next]] of Object.entries(bumped)) {\n if (out[node][k] !== old) continue;\n const [advanced, read] = bumpKeys(node, k);\n // If an earlier bump set `old`, the real read is already recorded.\n if (old !== undefined && marks[advanced] !== old) marks[read] = old;\n marks[advanced] = next;\n out[node] = { ...out[node], [k]: next };\n }\n }\n if (Object.keys(marks).length > 0) out[SNAPSHOT_BUMPS] = marks;\n return out;\n}\n\n// Node names can't contain either separator, so the keys can't collide.\nconst bumpKeys = (node: string, channel: string): [string, string] => [\n `${node}${CHECKPOINT_NAMESPACE_SEPARATOR}${channel}`,\n `${node}${CHECKPOINT_NAMESPACE_END}${channel}`,\n];\n\n/**\n * `versions_seen` as the nodes read it: an entry a snapshot bump advanced goes\n * back to the version the node really read, or away if it never read one.\n */\nexport function versionsSeenWithoutBumps(\n versionsSeen: ReadonlyCheckpoint[\"versions_seen\"]\n): ReadonlyCheckpoint[\"versions_seen\"] {\n const marks = versionsSeen[SNAPSHOT_BUMPS];\n if (marks === undefined || Object.keys(marks).length === 0) {\n return versionsSeen;\n }\n const out: Checkpoint[\"versions_seen\"] = {};\n for (const node in versionsSeen) {\n if (\n !Object.prototype.hasOwnProperty.call(versionsSeen, node) ||\n node === SNAPSHOT_BUMPS\n ) {\n continue;\n }\n out[node] = {};\n for (const [k, v] of Object.entries(versionsSeen[node])) {\n const [advanced, read] = bumpKeys(node, k);\n if (marks[advanced] !== v) out[node][k] = v;\n else if (read in marks) out[node][k] = marks[read];\n }\n }\n return out;\n}\n\n/**\n * Checkpoint metadata key, `true` when every DeltaChannel write on the\n * checkpoint's branch carries a version. A delta channel with no version there\n * was never written, so it needs no walk. Branches started before this key\n * existed never get it: an older `updateState` stored a delta channel's first\n * write without a version, and only the walk finds such a write.\n */\nexport const DELTA_WRITES_VERSIONED = \"delta_writes_versioned\";\n\nexport function isDeltaWritesVersioned(\n metadata: CheckpointMetadata | undefined\n): boolean {\n return (\n (metadata as Record<string, unknown> | undefined)?.[\n DELTA_WRITES_VERSIONED\n ] === true\n );\n}\n\n/**\n * Delta channels whose value at `checkpoint` the ancestor walk rebuilds.\n *\n * A {@link DeltaSnapshot} or a migrated plain value in `channel_values`\n * resolves directly, so only a channel with nothing stored there needs the\n * walk. With `versionedOnly`, a channel with no version was never written, so\n * it is empty without one; a walk for it would find no snapshot to stop at and\n * read every ancestor, every time the thread is loaded.\n */\nfunction deltaChannelsToReplay(\n specs: Record<string, BaseChannel>,\n checkpoint: ReadonlyCheckpoint,\n versionedOnly: boolean\n): string[] {\n const keys: string[] = [];\n for (const k in specs) {\n if (!Object.prototype.hasOwnProperty.call(specs, k)) continue;\n if (\n isDeltaChannel(specs[k]) &&\n (!versionedOnly || checkpoint.channel_versions[k] !== undefined) &&\n !Object.prototype.hasOwnProperty.call(checkpoint.channel_values, k)\n ) {\n keys.push(k);\n }\n }\n return keys;\n}\n\n/**\n * Hydrate channels from a checkpoint, reconstructing any {@link DeltaChannel}\n * whose value is absent from `channel_values` by replaying ancestor writes.\n *\n * For most channels (and for delta channels with a {@link DeltaSnapshot} or a\n * migrated plain value in `channel_values`), {@link emptyChannels} is\n * sufficient and no saver access is required. When a delta channel is absent\n * from `channel_values`, an ancestor walk via `saver.getDeltaChannelHistory`\n * finds the nearest seed and accumulates the writes between it and the\n * target. All delta channels needing replay are batched into a single saver\n * call. Pass `deltaWritesVersioned` for a checkpoint whose metadata carries\n * {@link DELTA_WRITES_VERSIONED}, so delta channels without a version are\n * left empty instead of walked.\n */\nexport async function channelsFromCheckpoint<\n Cc extends Record<string, BaseChannel>,\n>(\n specs: Cc,\n checkpoint: ReadonlyCheckpoint,\n options?: {\n saver?: BaseCheckpointSaver;\n config?: RunnableConfig;\n deltaWritesVersioned?: boolean;\n }\n): Promise<Cc> {\n const channels = emptyChannels(specs, checkpoint);\n const { saver, config } = options ?? {};\n\n const filteredSpecs = getOnlyChannels(specs);\n const deltaKeys = deltaChannelsToReplay(\n filteredSpecs,\n checkpoint,\n options?.deltaWritesVersioned ?? false\n );\n\n const written = deltaKeys.filter(\n (k) => checkpoint.channel_versions[k] !== undefined\n );\n if ((saver === undefined || config === undefined) && written.length > 0) {\n throw new Error(\n `DeltaChannel ${written.join(\", \")} has history to replay but no checkpointer or config was passed to read it`\n );\n }\n if (deltaKeys.length === 0 || saver === undefined || config === undefined) {\n return channels;\n }\n\n const histories = await saver.getDeltaChannelHistory({\n config,\n channels: deltaKeys,\n });\n for (const k of deltaKeys) {\n const history = histories[k];\n if (history === undefined) continue;\n const replayCh = filteredSpecs[k].fromCheckpoint(\n history.seed\n ) as unknown as DeltaChannelLike;\n replayCh.replayWrites(history.writes);\n (channels as Record<string, BaseChannel>)[k] = replayCh;\n }\n return channels;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"base.js","names":[],"sources":["../../src/channels/base.ts"],"sourcesContent":["import {\n ReadonlyCheckpoint,\n uuid6,\n Checkpoint,\n DeltaSnapshot,\n type BaseCheckpointSaver,\n type CheckpointMetadata,\n type DeltaChannelHistory,\n} from \"@langchain/langgraph-checkpoint\";\nimport type { RunnableConfig } from \"@langchain/core/runnables\";\nimport { EmptyChannelError } from \"../errors.js\";\nimport {\n CHECKPOINT_NAMESPACE_END,\n CHECKPOINT_NAMESPACE_SEPARATOR,\n EXIT_DELTA_NULL_TASK_ID,\n getDeltaMaxSuperstepsSinceSnapshot,\n NULL_TASK_ID,\n SNAPSHOT_BUMPS,\n} from \"../constants.js\";\n\n/** Matches Postgres `uuid` / Python `uuid.UUID` (128-bit, 8-4-4-4-12 hex). */\nconst STRUCTURED_UUID =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * Structural check for a {@link DeltaChannel} without importing it (avoids an\n * import cycle: `delta.ts` imports `base.ts`).\n */\nexport function isDeltaChannel(channel: BaseChannel): boolean {\n return channel != null && channel.lc_graph_name === \"DeltaChannel\";\n}\n\nexport function deltaChannelWrites<W extends readonly [PropertyKey, unknown]>(\n channels: Record<string, BaseChannel>,\n writes: ReadonlyArray<W>\n): W[] {\n return writes.filter(([ch]) => isDeltaChannel(channels[String(ch)]));\n}\n\nexport function isBaseChannel(obj: unknown): obj is BaseChannel {\n return obj != null && (obj as BaseChannel).lg_is_channel === true;\n}\n\n/** @internal */\nexport abstract class BaseChannel<\n ValueType = unknown,\n UpdateType = unknown,\n CheckpointType = unknown,\n> {\n ValueType: ValueType;\n\n UpdateType: UpdateType;\n\n /**\n * The name of the channel.\n */\n abstract lc_graph_name: string;\n\n /** @ignore */\n lg_is_channel = true;\n\n /**\n * Return a new identical channel, optionally initialized from a checkpoint.\n * Can be thought of as a \"restoration\" from a checkpoint which is a \"snapshot\" of the channel's state.\n *\n * @param {CheckpointType | undefined} checkpoint\n * @param {CheckpointType | undefined} initialValue\n * @returns {this}\n */\n abstract fromCheckpoint(checkpoint?: CheckpointType): this;\n\n /**\n * Update the channel's value with the given sequence of updates.\n * The order of the updates in the sequence is arbitrary.\n * This method is called by Pregel for all channels at the end of each step.\n * If there are no updates, it is called with an empty sequence.\n *\n * Raises InvalidUpdateError if the sequence of updates is invalid.\n * Returns True if the channel was updated, False otherwise.\n *\n * @throws {InvalidUpdateError} if the sequence of updates is invalid.\n * @param {Array<UpdateType>} values\n * @returns {void}\n */\n abstract update(values: UpdateType[]): boolean;\n\n /**\n * Return the current value of the channel.\n *\n * @throws {EmptyChannelError} if the channel is empty (never updated yet).\n * @returns {ValueType}\n */\n abstract get(): ValueType;\n\n /**\n * Return a string representation of the channel's current state.\n *\n * @throws {EmptyChannelError} if the channel is empty (never updated yet), or doesn't support checkpoints.\n * @returns {CheckpointType | undefined}\n */\n abstract checkpoint(): CheckpointType | undefined;\n\n /**\n * Mark the current value of the channel as consumed. By default, no-op.\n * A channel can use this method to modify its state, preventing the value\n * from being consumed again.\n *\n * Returns True if the channel was updated, False otherwise.\n */\n consume(): boolean {\n return false;\n }\n\n /**\n * Notify the channel that the Pregel run is finishing. By default, no-op.\n * A channel can use this method to modify its state, preventing finish.\n *\n * Returns True if the channel was updated, False otherwise.\n */\n finish(): boolean {\n return false;\n }\n\n /**\n * Return True if the channel is available (not empty), False otherwise.\n * Subclasses should override this method to provide a more efficient\n * implementation than calling get() and catching EmptyChannelError.\n */\n isAvailable(): boolean {\n try {\n this.get();\n return true;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n if (error.name === EmptyChannelError.unminifiable_name) {\n return false;\n }\n throw error;\n }\n }\n\n /**\n * Compare this channel with another channel for equality.\n * Used to determine if two channels with the same key are semantically equivalent.\n * Subclasses should override this method to provide a meaningful comparison.\n *\n * @param {BaseChannel} other - The other channel to compare with.\n * @returns {boolean} True if the channels are equal, false otherwise.\n */\n equals(other: BaseChannel): boolean {\n return this === other;\n }\n}\n\nconst IS_ONLY_BASE_CHANNEL = Symbol.for(\"LG_IS_ONLY_BASE_CHANNEL\");\nexport function getOnlyChannels(\n channels: Record<string, BaseChannel>\n): Record<string, BaseChannel> {\n // @ts-expect-error - we know it's a record of base channels\n if (channels[IS_ONLY_BASE_CHANNEL] === true) return channels;\n\n const newChannels = {} as Record<string, BaseChannel>;\n for (const k in channels) {\n if (!Object.prototype.hasOwnProperty.call(channels, k)) continue;\n const value = channels[k];\n if (isBaseChannel(value)) newChannels[k] = value;\n }\n\n Object.assign(newChannels, { [IS_ONLY_BASE_CHANNEL]: true });\n return newChannels;\n}\n\nexport function emptyChannels<Cc extends Record<string, BaseChannel>>(\n channels: Cc,\n checkpoint: ReadonlyCheckpoint\n): Cc {\n const filteredChannels = getOnlyChannels(channels) as Cc;\n\n const newChannels = {} as Cc;\n for (const k in filteredChannels) {\n if (!Object.prototype.hasOwnProperty.call(filteredChannels, k)) continue;\n const channelValue = checkpoint.channel_values[k];\n newChannels[k] = filteredChannels[k].fromCheckpoint(channelValue);\n }\n Object.assign(newChannels, { [IS_ONLY_BASE_CHANNEL]: true });\n return newChannels;\n}\n\n/**\n * Minimal structural view of a {@link DeltaChannel}, used by helpers in this\n * module that must not import the concrete class (import-cycle avoidance).\n */\ninterface DeltaChannelLike extends BaseChannel {\n snapshotFrequency: number;\n replayWrites(writes: DeltaChannelHistory[\"writes\"]): void;\n}\n\n/**\n * Synthetic task id for exit-mode DeltaChannel writes.\n *\n * Embeds the superstep in the first UUID group so `ORDER BY task_id, idx`\n * preserves chronological order while remaining a valid RFC UUID (required by\n * Postgres `checkpoint_writes.task_id uuid` columns). Never `NULL_TASK_ID`:\n * readers apply writes under it as the anchor checkpoint's own pending writes.\n */\nexport function exitDeltaTaskId(step: number, taskId: string): string {\n if (!STRUCTURED_UUID.test(taskId)) {\n throw new TypeError(`Invalid task id for exit delta: ${taskId}`);\n }\n const parts = taskId.toLowerCase().split(\"-\");\n const stepPart = String(step).padStart(8, \"0\");\n const synthetic = `${stepPart}-${parts[1]}-${parts[2]}-${parts[3]}-${parts[4]}`;\n return synthetic === NULL_TASK_ID ? EXIT_DELTA_NULL_TASK_ID : synthetic;\n}\n\n/**\n * Synthetic task id for exit-mode writes of a superstep after the anchor's\n * own.\n *\n * Sorts after every real task id, in step order, so replay keeps them after\n * the anchor's own superstep whether a saver orders writes by task path\n * (`writesSortKey`) or by task id. Mirrors Python's\n * `exit_delta_late_task_id` exactly, including the two hexadecimal step\n * groups (step is split across them).\n */\nexport function exitDeltaLateTaskId(step: number, taskId: string): string {\n if (!STRUCTURED_UUID.test(taskId)) {\n throw new TypeError(`Invalid task id for exit delta: ${taskId}`);\n }\n const parts = taskId.toLowerCase().split(\"-\");\n const stepHi = (step >> 16).toString(16).padStart(4, \"0\");\n const stepLo = (step & 0xffff).toString(16).padStart(4, \"0\");\n return `ffffffff-${stepHi}-${stepLo}-${parts[3]}-${parts[4]}`;\n}\n\n/**\n * DeltaChannels a branch starting from this checkpoint must snapshot.\n *\n * A checkpoint's pending writes belong to the child that consumed them, and\n * nothing records which child that was. A new branch snapshots every delta\n * channel they touch, so its ancestor walk never replays them (port of\n * Python #8548's `delta_channels_with_pending_writes`).\n */\nexport function deltaChannelsWithPendingWrites(\n channels: Record<string, BaseChannel>,\n pendingWrites: ReadonlyArray<[string, string, unknown]> | undefined\n): Set<string> {\n const result = new Set<string>();\n if (pendingWrites === undefined) return result;\n for (const [, ch] of pendingWrites) {\n const channel = channels[ch];\n if (channel != null && isDeltaChannel(channel)) result.add(ch);\n }\n return result;\n}\n\n/**\n * Return the set of {@link DeltaChannel} names that should snapshot now.\n *\n * A channel snapshots when EITHER its accumulated update count reaches\n * `snapshotFrequency` OR the total supersteps since its last snapshot reaches\n * `DELTA_MAX_SUPERSTEPS_SINCE_SNAPSHOT`. Given `channelVersions`, a channel\n * without a version is skipped: it was never written on this branch, so it\n * has nothing to snapshot. Pass `undefined` on a branch without\n * {@link DELTA_WRITES_VERSIONED}, where such a channel can still hold writes\n * and this snapshot is what bounds its walk. Pure predicate, no mutation.\n */\nexport function deltaChannelsToSnapshot(\n channels: Record<string, BaseChannel>,\n countersSinceDeltaSnapshot: Record<string, [number, number]>,\n channelVersions: Record<string, number | string> | undefined\n): Set<string> {\n const result = new Set<string>();\n for (const name in channels) {\n if (!Object.prototype.hasOwnProperty.call(channels, name)) continue;\n const ch = channels[name];\n if (\n !isDeltaChannel(ch) ||\n !ch.isAvailable() ||\n (channelVersions !== undefined && channelVersions[name] === undefined)\n ) {\n continue;\n }\n if (reachedSnapshotBound(ch, countersSinceDeltaSnapshot[name])) {\n result.add(name);\n }\n }\n return result;\n}\n\n/** Whether a delta channel's counters reached the bound where it snapshots. */\nexport function reachedSnapshotBound(\n channel: BaseChannel,\n counters: [number, number] | undefined\n): boolean {\n const [updates, supersteps] = counters ?? [0, 0];\n return (\n updates >= (channel as DeltaChannelLike).snapshotFrequency ||\n supersteps >= getDeltaMaxSuperstepsSinceSnapshot()\n );\n}\n\nexport function createCheckpoint<ValueType>(\n checkpoint: ReadonlyCheckpoint,\n channels: Record<string, BaseChannel<ValueType>> | undefined,\n step: number,\n options?: {\n id?: string;\n channelsToSnapshot?: Set<string>;\n /** The channel versions of the last checkpoint the saver stored. */\n storedVersions?: Record<string, number | string>;\n getNextVersion?: (current: number | string | undefined) => number | string;\n triggerToNodes?: Record<string, string[]>;\n }\n): Checkpoint {\n const channelsToSnapshot = options?.channelsToSnapshot ?? new Set<string>();\n const { storedVersions, getNextVersion } = options ?? {};\n const bumped: Record<string, [number | string | undefined, number | string]> =\n {};\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let values: Record<string, any>;\n let channelVersions: Record<string, number | string> =\n checkpoint.channel_versions;\n if (channels === undefined) {\n values = checkpoint.channel_values;\n } else {\n values = {};\n channelVersions = { ...checkpoint.channel_versions };\n for (const k in channels) {\n if (!Object.prototype.hasOwnProperty.call(channels, k)) continue;\n const channel = channels[k];\n if (channelsToSnapshot.has(k)) {\n // `put` only stores a blob for a channel whose version moved, so\n // snapshotting a channel that didn't move since the last stored\n // checkpoint needs a bump: exit mode reaching the cadence on a\n // superstep that skipped the channel, and a fork's first checkpoint.\n if (\n getNextVersion !== undefined &&\n storedVersions !== undefined &&\n channelVersions[k] === storedVersions[k]\n ) {\n const old = channelVersions[k];\n channelVersions[k] = getNextVersion(old);\n bumped[k] = [old, channelVersions[k]];\n }\n values[k] = new DeltaSnapshot(channel.get());\n continue;\n }\n if (isDeltaChannel(channel)) {\n // Omitted from channel_values; reconstructed from ancestor writes.\n continue;\n }\n try {\n values[k] = channel.checkpoint();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n if (error.name === EmptyChannelError.unminifiable_name) {\n // no-op\n } else {\n throw error; // Rethrow unexpected errors\n }\n }\n }\n }\n\n return {\n v: 4,\n id: options?.id ?? uuid6(step),\n ts: new Date().toISOString(),\n channel_values: values,\n channel_versions: channelVersions,\n versions_seen: markBumpsSeen(\n checkpoint.versions_seen,\n bumped,\n options?.triggerToNodes\n ),\n };\n}\n\n/**\n * Advance whoever had seen a bumped channel's old version to the new one.\n *\n * A bump that only stores a snapshot is not a write. Left unseen, it would\n * re-fire `interruptBefore` and rerun the channel's subscribers. A channel\n * bumped from no version was never written, so it also goes to the\n * subscribers that never ran: they have no entry, and would start on the bump.\n * For each entry it advances, {@link SNAPSHOT_BUMPS} keeps the new version and\n * the one the node really read, so {@link versionsSeenWithoutBumps} can put\n * the read back.\n */\nfunction markBumpsSeen(\n versionsSeen: ReadonlyCheckpoint[\"versions_seen\"],\n bumped: Record<string, [number | string | undefined, number | string]>,\n triggerToNodes: Record<string, string[]> = {}\n): Checkpoint[\"versions_seen\"] {\n if (Object.keys(bumped).length === 0) return versionsSeen;\n const out = { ...versionsSeen };\n for (const [k, [old]] of Object.entries(bumped)) {\n if (old !== undefined) continue;\n for (const node of triggerToNodes[k] ?? []) out[node] ??= {};\n }\n const marks = { ...versionsSeen[SNAPSHOT_BUMPS] };\n for (const node in out) {\n if (\n !Object.prototype.hasOwnProperty.call(out, node) ||\n node === SNAPSHOT_BUMPS\n ) {\n continue;\n }\n for (const [k, [old, next]] of Object.entries(bumped)) {\n if (out[node][k] !== old) continue;\n const [advanced, read] = bumpKeys(node, k);\n // If an earlier bump set `old`, the real read is already recorded.\n if (old !== undefined && marks[advanced] !== old) marks[read] = old;\n marks[advanced] = next;\n out[node] = { ...out[node], [k]: next };\n }\n }\n if (Object.keys(marks).length > 0) out[SNAPSHOT_BUMPS] = marks;\n return out;\n}\n\n// Node names can't contain either separator, so the keys can't collide.\nconst bumpKeys = (node: string, channel: string): [string, string] => [\n `${node}${CHECKPOINT_NAMESPACE_SEPARATOR}${channel}`,\n `${node}${CHECKPOINT_NAMESPACE_END}${channel}`,\n];\n\n/**\n * `versions_seen` as the nodes read it: an entry a snapshot bump advanced goes\n * back to the version the node really read, or away if it never read one.\n */\nexport function versionsSeenWithoutBumps(\n versionsSeen: ReadonlyCheckpoint[\"versions_seen\"]\n): ReadonlyCheckpoint[\"versions_seen\"] {\n const marks = versionsSeen[SNAPSHOT_BUMPS];\n if (marks === undefined || Object.keys(marks).length === 0) {\n return versionsSeen;\n }\n const out: Checkpoint[\"versions_seen\"] = {};\n for (const node in versionsSeen) {\n if (\n !Object.prototype.hasOwnProperty.call(versionsSeen, node) ||\n node === SNAPSHOT_BUMPS\n ) {\n continue;\n }\n out[node] = {};\n for (const [k, v] of Object.entries(versionsSeen[node])) {\n const [advanced, read] = bumpKeys(node, k);\n if (marks[advanced] !== v) out[node][k] = v;\n else if (read in marks) out[node][k] = marks[read];\n }\n }\n return out;\n}\n\n/**\n * Checkpoint metadata key, `true` when every DeltaChannel write on the\n * checkpoint's branch carries a version. A delta channel with no version there\n * was never written, so it needs no walk. Branches started before this key\n * existed never get it: an older `updateState` stored a delta channel's first\n * write without a version, and only the walk finds such a write.\n */\nexport const DELTA_WRITES_VERSIONED = \"delta_writes_versioned\";\n\nexport function isDeltaWritesVersioned(\n metadata: CheckpointMetadata | undefined\n): boolean {\n return (\n (metadata as Record<string, unknown> | undefined)?.[\n DELTA_WRITES_VERSIONED\n ] === true\n );\n}\n\n/**\n * Channels whose value at `checkpoint` the ancestor walk rebuilds.\n *\n * A {@link DeltaSnapshot} or a migrated plain value in `channel_values`\n * resolves directly, so only a channel with nothing stored there needs the\n * walk. With `versionedOnly`, a channel with no version was never written, so\n * it is empty without one; a walk for it would find no snapshot to stop at and\n * read every ancestor, every time the thread is loaded.\n *\n * A `BinaryOperatorAggregate` stores its value at every version, so one with a\n * version and nothing stored was written as a DeltaChannel before its\n * annotation changed, and is rebuilt the same way.\n */\nfunction deltaChannelsToReplay(\n specs: Record<string, BaseChannel>,\n checkpoint: ReadonlyCheckpoint,\n versionedOnly: boolean\n): string[] {\n const keys: string[] = [];\n for (const k in specs) {\n if (!Object.prototype.hasOwnProperty.call(specs, k)) continue;\n if (Object.prototype.hasOwnProperty.call(checkpoint.channel_values, k)) {\n continue;\n }\n const versioned = checkpoint.channel_versions[k] !== undefined;\n if (\n (isDeltaChannel(specs[k]) && (versioned || !versionedOnly)) ||\n (specs[k].lc_graph_name === \"BinaryOperatorAggregate\" && versioned)\n ) {\n keys.push(k);\n }\n }\n return keys;\n}\n\n/**\n * Hydrate channels from a checkpoint, reconstructing any {@link DeltaChannel}\n * whose value is absent from `channel_values` by replaying ancestor writes.\n *\n * For most channels (and for delta channels with a {@link DeltaSnapshot} or a\n * migrated plain value in `channel_values`), {@link emptyChannels} is\n * sufficient and no saver access is required. When a delta channel is absent\n * from `channel_values`, an ancestor walk via `saver.getDeltaChannelHistory`\n * finds the nearest seed and accumulates the writes between it and the\n * target. All delta channels needing replay are batched into a single saver\n * call. Pass `deltaWritesVersioned` for a checkpoint whose metadata carries\n * {@link DELTA_WRITES_VERSIONED}, so delta channels without a version are\n * left empty instead of walked.\n */\nexport async function channelsFromCheckpoint<\n Cc extends Record<string, BaseChannel>,\n>(\n specs: Cc,\n checkpoint: ReadonlyCheckpoint,\n options?: {\n saver?: BaseCheckpointSaver;\n config?: RunnableConfig;\n deltaWritesVersioned?: boolean;\n }\n): Promise<Cc> {\n const channels = emptyChannels(specs, checkpoint);\n const { saver, config } = options ?? {};\n\n const filteredSpecs = getOnlyChannels(specs);\n const deltaKeys = deltaChannelsToReplay(\n filteredSpecs,\n checkpoint,\n options?.deltaWritesVersioned ?? false\n );\n\n const written = deltaKeys.filter(\n (k) => checkpoint.channel_versions[k] !== undefined\n );\n if ((saver === undefined || config === undefined) && written.length > 0) {\n throw new Error(\n `DeltaChannel ${written.join(\", \")} has history to replay but no checkpointer or config was passed to read it`\n );\n }\n if (deltaKeys.length === 0 || saver === undefined || config === undefined) {\n return channels;\n }\n\n const histories = await saver.getDeltaChannelHistory({\n config,\n channels: deltaKeys,\n });\n for (const k of deltaKeys) {\n const history = histories[k];\n if (history === undefined) continue;\n const replayCh = filteredSpecs[k].fromCheckpoint(history.seed);\n if (isDeltaChannel(replayCh)) {\n (replayCh as DeltaChannelLike).replayWrites(history.writes);\n } else {\n // One update per write: the writes span many supersteps, and a single\n // call would reject a second Overwrite and drop the writes after one.\n for (const [, , value] of history.writes) replayCh.update([value]);\n }\n (channels as Record<string, BaseChannel>)[k] = replayCh;\n }\n return channels;\n}\n"],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  const require_constants = require("../constants.cjs");
2
2
  const require_errors = require("../errors.cjs");
3
3
  const require_base = require("./base.cjs");
4
+ let _langchain_langgraph_checkpoint = require("@langchain/langgraph-checkpoint");
4
5
  //#region src/channels/binop.ts
5
6
  const isBinaryOperatorAggregate = (value) => {
6
7
  return value != null && value.lc_graph_name === "BinaryOperatorAggregate";
@@ -21,7 +22,7 @@ var BinaryOperatorAggregate = class BinaryOperatorAggregate extends require_base
21
22
  }
22
23
  fromCheckpoint(checkpoint) {
23
24
  const empty = new BinaryOperatorAggregate(this.operator, this.initialValueFactory);
24
- if (typeof checkpoint !== "undefined") empty.value = checkpoint;
25
+ if (typeof checkpoint !== "undefined") empty.value = (0, _langchain_langgraph_checkpoint.isDeltaSnapshot)(checkpoint) ? checkpoint.value : checkpoint;
25
26
  return empty;
26
27
  }
27
28
  update(values) {
@@ -1 +1 @@
1
- {"version":3,"file":"binop.cjs","names":["BaseChannel","_getOverwriteValue","_isOverwriteValue","InvalidUpdateError","EmptyChannelError"],"sources":["../../src/channels/binop.ts"],"sourcesContent":["import {\n _getOverwriteValue,\n _isOverwriteValue,\n type OverwriteValue,\n} from \"../constants.js\";\nimport { EmptyChannelError, InvalidUpdateError } from \"../errors.js\";\nimport { BaseChannel } from \"./base.js\";\n\ntype OverwriteOrValue<ValueType, UpdateType> =\n | OverwriteValue<ValueType>\n | UpdateType;\n\nexport type BinaryOperator<ValueType, UpdateType> = (\n a: ValueType,\n b: UpdateType\n) => ValueType;\n\nconst isBinaryOperatorAggregate = (\n value: BaseChannel\n): value is BinaryOperatorAggregate<unknown, unknown> => {\n return value != null && value.lc_graph_name === \"BinaryOperatorAggregate\";\n};\n\n/**\n * Stores the result of applying a binary operator to the current value and each new value.\n */\nexport class BinaryOperatorAggregate<\n ValueType,\n UpdateType = ValueType,\n> extends BaseChannel<\n ValueType,\n OverwriteOrValue<ValueType, UpdateType>,\n ValueType\n> {\n lc_graph_name = \"BinaryOperatorAggregate\";\n\n value: ValueType | undefined;\n\n operator: BinaryOperator<ValueType, UpdateType>;\n\n initialValueFactory?: () => ValueType;\n\n constructor(\n operator: BinaryOperator<ValueType, UpdateType>,\n initialValueFactory?: () => ValueType\n ) {\n super();\n\n this.operator = operator;\n this.initialValueFactory = initialValueFactory;\n this.value = initialValueFactory?.();\n }\n\n public fromCheckpoint(checkpoint?: ValueType) {\n const empty = new BinaryOperatorAggregate(\n this.operator,\n this.initialValueFactory\n );\n if (typeof checkpoint !== \"undefined\") {\n empty.value = checkpoint;\n }\n return empty as this;\n }\n\n public update(values: OverwriteOrValue<ValueType, UpdateType>[]): boolean {\n let newValues = values;\n if (!newValues.length) return false;\n\n if (this.value === undefined) {\n const first = newValues[0];\n const [isOverwrite, overwriteVal] = _getOverwriteValue<ValueType>(first);\n if (isOverwrite) {\n this.value = overwriteVal;\n } else {\n this.value = first as ValueType;\n }\n newValues = newValues.slice(1);\n }\n\n let seenOverwrite = false;\n for (const incoming of newValues) {\n if (_isOverwriteValue<ValueType>(incoming)) {\n if (seenOverwrite) {\n throw new InvalidUpdateError(\n \"Can receive only one Overwrite value per step.\"\n );\n }\n const [, val] = _getOverwriteValue<ValueType>(incoming);\n this.value = val;\n seenOverwrite = true;\n continue;\n } else if (!seenOverwrite && this.value !== undefined) {\n this.value = this.operator(this.value, incoming);\n }\n }\n return true;\n }\n\n public get(): ValueType {\n if (this.value === undefined) {\n throw new EmptyChannelError();\n }\n return this.value;\n }\n\n public checkpoint(): ValueType {\n if (this.value === undefined) {\n throw new EmptyChannelError();\n }\n return this.value;\n }\n\n isAvailable(): boolean {\n return this.value !== undefined;\n }\n\n /**\n * Compare this channel with another channel for equality.\n * Two BinaryOperatorAggregate channels are equal if they have the same operator function.\n * This follows the Python implementation which compares operator references.\n */\n equals(other: BaseChannel): boolean {\n if (this === other) return true;\n if (!isBinaryOperatorAggregate(other)) return false;\n return this.operator === other.operator;\n }\n}\n"],"mappings":";;;;AAiBA,MAAM,6BACJ,UACuD;AACvD,QAAO,SAAS,QAAQ,MAAM,kBAAkB;;;;;AAMlD,IAAa,0BAAb,MAAa,gCAGHA,aAAAA,YAIR;CACA,gBAAgB;CAEhB;CAEA;CAEA;CAEA,YACE,UACA,qBACA;AACA,SAAO;AAEP,OAAK,WAAW;AAChB,OAAK,sBAAsB;AAC3B,OAAK,QAAQ,uBAAuB;;CAGtC,eAAsB,YAAwB;EAC5C,MAAM,QAAQ,IAAI,wBAChB,KAAK,UACL,KAAK,oBACN;AACD,MAAI,OAAO,eAAe,YACxB,OAAM,QAAQ;AAEhB,SAAO;;CAGT,OAAc,QAA4D;EACxE,IAAI,YAAY;AAChB,MAAI,CAAC,UAAU,OAAQ,QAAO;AAE9B,MAAI,KAAK,UAAU,KAAA,GAAW;GAC5B,MAAM,QAAQ,UAAU;GACxB,MAAM,CAAC,aAAa,gBAAgBC,kBAAAA,mBAA8B,MAAM;AACxE,OAAI,YACF,MAAK,QAAQ;OAEb,MAAK,QAAQ;AAEf,eAAY,UAAU,MAAM,EAAE;;EAGhC,IAAI,gBAAgB;AACpB,OAAK,MAAM,YAAY,UACrB,KAAIC,kBAAAA,kBAA6B,SAAS,EAAE;AAC1C,OAAI,cACF,OAAM,IAAIC,eAAAA,mBACR,iDACD;GAEH,MAAM,GAAG,OAAOF,kBAAAA,mBAA8B,SAAS;AACvD,QAAK,QAAQ;AACb,mBAAgB;AAChB;aACS,CAAC,iBAAiB,KAAK,UAAU,KAAA,EAC1C,MAAK,QAAQ,KAAK,SAAS,KAAK,OAAO,SAAS;AAGpD,SAAO;;CAGT,MAAwB;AACtB,MAAI,KAAK,UAAU,KAAA,EACjB,OAAM,IAAIG,eAAAA,mBAAmB;AAE/B,SAAO,KAAK;;CAGd,aAA+B;AAC7B,MAAI,KAAK,UAAU,KAAA,EACjB,OAAM,IAAIA,eAAAA,mBAAmB;AAE/B,SAAO,KAAK;;CAGd,cAAuB;AACrB,SAAO,KAAK,UAAU,KAAA;;;;;;;CAQxB,OAAO,OAA6B;AAClC,MAAI,SAAS,MAAO,QAAO;AAC3B,MAAI,CAAC,0BAA0B,MAAM,CAAE,QAAO;AAC9C,SAAO,KAAK,aAAa,MAAM"}
1
+ {"version":3,"file":"binop.cjs","names":["BaseChannel","_getOverwriteValue","_isOverwriteValue","InvalidUpdateError","EmptyChannelError"],"sources":["../../src/channels/binop.ts"],"sourcesContent":["import { isDeltaSnapshot } from \"@langchain/langgraph-checkpoint\";\nimport {\n _getOverwriteValue,\n _isOverwriteValue,\n type OverwriteValue,\n} from \"../constants.js\";\nimport { EmptyChannelError, InvalidUpdateError } from \"../errors.js\";\nimport { BaseChannel } from \"./base.js\";\n\ntype OverwriteOrValue<ValueType, UpdateType> =\n | OverwriteValue<ValueType>\n | UpdateType;\n\nexport type BinaryOperator<ValueType, UpdateType> = (\n a: ValueType,\n b: UpdateType\n) => ValueType;\n\nconst isBinaryOperatorAggregate = (\n value: BaseChannel\n): value is BinaryOperatorAggregate<unknown, unknown> => {\n return value != null && value.lc_graph_name === \"BinaryOperatorAggregate\";\n};\n\n/**\n * Stores the result of applying a binary operator to the current value and each new value.\n */\nexport class BinaryOperatorAggregate<\n ValueType,\n UpdateType = ValueType,\n> extends BaseChannel<\n ValueType,\n OverwriteOrValue<ValueType, UpdateType>,\n ValueType\n> {\n lc_graph_name = \"BinaryOperatorAggregate\";\n\n value: ValueType | undefined;\n\n operator: BinaryOperator<ValueType, UpdateType>;\n\n initialValueFactory?: () => ValueType;\n\n constructor(\n operator: BinaryOperator<ValueType, UpdateType>,\n initialValueFactory?: () => ValueType\n ) {\n super();\n\n this.operator = operator;\n this.initialValueFactory = initialValueFactory;\n this.value = initialValueFactory?.();\n }\n\n public fromCheckpoint(checkpoint?: ValueType) {\n const empty = new BinaryOperatorAggregate(\n this.operator,\n this.initialValueFactory\n );\n if (typeof checkpoint !== \"undefined\") {\n // A thread written while this field was a DeltaChannel stores snapshots.\n empty.value = isDeltaSnapshot(checkpoint)\n ? (checkpoint.value as ValueType)\n : checkpoint;\n }\n return empty as this;\n }\n\n public update(values: OverwriteOrValue<ValueType, UpdateType>[]): boolean {\n let newValues = values;\n if (!newValues.length) return false;\n\n if (this.value === undefined) {\n const first = newValues[0];\n const [isOverwrite, overwriteVal] = _getOverwriteValue<ValueType>(first);\n if (isOverwrite) {\n this.value = overwriteVal;\n } else {\n this.value = first as ValueType;\n }\n newValues = newValues.slice(1);\n }\n\n let seenOverwrite = false;\n for (const incoming of newValues) {\n if (_isOverwriteValue<ValueType>(incoming)) {\n if (seenOverwrite) {\n throw new InvalidUpdateError(\n \"Can receive only one Overwrite value per step.\"\n );\n }\n const [, val] = _getOverwriteValue<ValueType>(incoming);\n this.value = val;\n seenOverwrite = true;\n continue;\n } else if (!seenOverwrite && this.value !== undefined) {\n this.value = this.operator(this.value, incoming);\n }\n }\n return true;\n }\n\n public get(): ValueType {\n if (this.value === undefined) {\n throw new EmptyChannelError();\n }\n return this.value;\n }\n\n public checkpoint(): ValueType {\n if (this.value === undefined) {\n throw new EmptyChannelError();\n }\n return this.value;\n }\n\n isAvailable(): boolean {\n return this.value !== undefined;\n }\n\n /**\n * Compare this channel with another channel for equality.\n * Two BinaryOperatorAggregate channels are equal if they have the same operator function.\n * This follows the Python implementation which compares operator references.\n */\n equals(other: BaseChannel): boolean {\n if (this === other) return true;\n if (!isBinaryOperatorAggregate(other)) return false;\n return this.operator === other.operator;\n }\n}\n"],"mappings":";;;;;AAkBA,MAAM,6BACJ,UACuD;AACvD,QAAO,SAAS,QAAQ,MAAM,kBAAkB;;;;;AAMlD,IAAa,0BAAb,MAAa,gCAGHA,aAAAA,YAIR;CACA,gBAAgB;CAEhB;CAEA;CAEA;CAEA,YACE,UACA,qBACA;AACA,SAAO;AAEP,OAAK,WAAW;AAChB,OAAK,sBAAsB;AAC3B,OAAK,QAAQ,uBAAuB;;CAGtC,eAAsB,YAAwB;EAC5C,MAAM,QAAQ,IAAI,wBAChB,KAAK,UACL,KAAK,oBACN;AACD,MAAI,OAAO,eAAe,YAExB,OAAM,SAAA,GAAA,gCAAA,iBAAwB,WAAW,GACpC,WAAW,QACZ;AAEN,SAAO;;CAGT,OAAc,QAA4D;EACxE,IAAI,YAAY;AAChB,MAAI,CAAC,UAAU,OAAQ,QAAO;AAE9B,MAAI,KAAK,UAAU,KAAA,GAAW;GAC5B,MAAM,QAAQ,UAAU;GACxB,MAAM,CAAC,aAAa,gBAAgBC,kBAAAA,mBAA8B,MAAM;AACxE,OAAI,YACF,MAAK,QAAQ;OAEb,MAAK,QAAQ;AAEf,eAAY,UAAU,MAAM,EAAE;;EAGhC,IAAI,gBAAgB;AACpB,OAAK,MAAM,YAAY,UACrB,KAAIC,kBAAAA,kBAA6B,SAAS,EAAE;AAC1C,OAAI,cACF,OAAM,IAAIC,eAAAA,mBACR,iDACD;GAEH,MAAM,GAAG,OAAOF,kBAAAA,mBAA8B,SAAS;AACvD,QAAK,QAAQ;AACb,mBAAgB;AAChB;aACS,CAAC,iBAAiB,KAAK,UAAU,KAAA,EAC1C,MAAK,QAAQ,KAAK,SAAS,KAAK,OAAO,SAAS;AAGpD,SAAO;;CAGT,MAAwB;AACtB,MAAI,KAAK,UAAU,KAAA,EACjB,OAAM,IAAIG,eAAAA,mBAAmB;AAE/B,SAAO,KAAK;;CAGd,aAA+B;AAC7B,MAAI,KAAK,UAAU,KAAA,EACjB,OAAM,IAAIA,eAAAA,mBAAmB;AAE/B,SAAO,KAAK;;CAGd,cAAuB;AACrB,SAAO,KAAK,UAAU,KAAA;;;;;;;CAQxB,OAAO,OAA6B;AAClC,MAAI,SAAS,MAAO,QAAO;AAC3B,MAAI,CAAC,0BAA0B,MAAM,CAAE,QAAO;AAC9C,SAAO,KAAK,aAAa,MAAM"}
@@ -1 +1 @@
1
- {"version":3,"file":"binop.d.cts","names":[],"sources":["../../src/channels/binop.ts"],"mappings":";;;;KAQK,gBAAA,0BACD,cAAA,CAAe,SAAA,IACf,UAAA;AAAA,KAEQ,cAAA,2BACV,CAAA,EAAG,SAAA,EACH,CAAA,EAAG,UAAA,KACA,SAAA;AATmC;;;AAAA,cAoB3B,uBAAA,yBAEE,SAAA,UACL,WAAA,CACR,SAAA,EACA,gBAAA,CAAiB,SAAA,EAAW,UAAA,GAC5B,SAAA;EAEA,aAAA;EAEA,KAAA,EAAO,SAAA;EAEP,QAAA,EAAU,cAAA,CAAe,SAAA,EAAW,UAAA;EAEpC,mBAAA,SAA4B,SAAA;EAE5B,WAAA,CACE,QAAA,EAAU,cAAA,CAAe,SAAA,EAAW,UAAA,GACpC,mBAAA,SAA4B,SAAA;EASvB,cAAA,CAAe,UAAA,GAAa,SAAA;EAW5B,MAAA,CAAO,MAAA,EAAQ,gBAAA,CAAiB,SAAA,EAAW,UAAA;EAkC3C,GAAA,CAAA,GAAO,SAAA;EAOP,UAAA,CAAA,GAAc,SAAA;EAOrB,WAAA,CAAA;EAtGY;AAEd;;;;EA6GE,MAAA,CAAO,KAAA,EAAO,WAAA;AAAA"}
1
+ {"version":3,"file":"binop.d.cts","names":[],"sources":["../../src/channels/binop.ts"],"mappings":";;;;KASK,gBAAA,0BACD,cAAA,CAAe,SAAA,IACf,UAAA;AAAA,KAEQ,cAAA,2BACV,CAAA,EAAG,SAAA,EACH,CAAA,EAAG,UAAA,KACA,SAAA;AATmC;;;AAAA,cAoB3B,uBAAA,yBAEE,SAAA,UACL,WAAA,CACR,SAAA,EACA,gBAAA,CAAiB,SAAA,EAAW,UAAA,GAC5B,SAAA;EAEA,aAAA;EAEA,KAAA,EAAO,SAAA;EAEP,QAAA,EAAU,cAAA,CAAe,SAAA,EAAW,UAAA;EAEpC,mBAAA,SAA4B,SAAA;EAE5B,WAAA,CACE,QAAA,EAAU,cAAA,CAAe,SAAA,EAAW,UAAA,GACpC,mBAAA,SAA4B,SAAA;EASvB,cAAA,CAAe,UAAA,GAAa,SAAA;EAc5B,MAAA,CAAO,MAAA,EAAQ,gBAAA,CAAiB,SAAA,EAAW,UAAA;EAkC3C,GAAA,CAAA,GAAO,SAAA;EAOP,UAAA,CAAA,GAAc,SAAA;EAOrB,WAAA,CAAA;EAzGY;AAEd;;;;EAgHE,MAAA,CAAO,KAAA,EAAO,WAAA;AAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"binop.d.ts","names":[],"sources":["../../src/channels/binop.ts"],"mappings":";;;;KAQK,gBAAA,0BACD,cAAA,CAAe,SAAA,IACf,UAAA;AAAA,KAEQ,cAAA,2BACV,CAAA,EAAG,SAAA,EACH,CAAA,EAAG,UAAA,KACA,SAAA;AATmC;;;AAAA,cAoB3B,uBAAA,yBAEE,SAAA,UACL,WAAA,CACR,SAAA,EACA,gBAAA,CAAiB,SAAA,EAAW,UAAA,GAC5B,SAAA;EAEA,aAAA;EAEA,KAAA,EAAO,SAAA;EAEP,QAAA,EAAU,cAAA,CAAe,SAAA,EAAW,UAAA;EAEpC,mBAAA,SAA4B,SAAA;EAE5B,WAAA,CACE,QAAA,EAAU,cAAA,CAAe,SAAA,EAAW,UAAA,GACpC,mBAAA,SAA4B,SAAA;EASvB,cAAA,CAAe,UAAA,GAAa,SAAA;EAW5B,MAAA,CAAO,MAAA,EAAQ,gBAAA,CAAiB,SAAA,EAAW,UAAA;EAkC3C,GAAA,CAAA,GAAO,SAAA;EAOP,UAAA,CAAA,GAAc,SAAA;EAOrB,WAAA,CAAA;EAtGY;AAEd;;;;EA6GE,MAAA,CAAO,KAAA,EAAO,WAAA;AAAA"}
1
+ {"version":3,"file":"binop.d.ts","names":[],"sources":["../../src/channels/binop.ts"],"mappings":";;;;KASK,gBAAA,0BACD,cAAA,CAAe,SAAA,IACf,UAAA;AAAA,KAEQ,cAAA,2BACV,CAAA,EAAG,SAAA,EACH,CAAA,EAAG,UAAA,KACA,SAAA;AATmC;;;AAAA,cAoB3B,uBAAA,yBAEE,SAAA,UACL,WAAA,CACR,SAAA,EACA,gBAAA,CAAiB,SAAA,EAAW,UAAA,GAC5B,SAAA;EAEA,aAAA;EAEA,KAAA,EAAO,SAAA;EAEP,QAAA,EAAU,cAAA,CAAe,SAAA,EAAW,UAAA;EAEpC,mBAAA,SAA4B,SAAA;EAE5B,WAAA,CACE,QAAA,EAAU,cAAA,CAAe,SAAA,EAAW,UAAA,GACpC,mBAAA,SAA4B,SAAA;EASvB,cAAA,CAAe,UAAA,GAAa,SAAA;EAc5B,MAAA,CAAO,MAAA,EAAQ,gBAAA,CAAiB,SAAA,EAAW,UAAA;EAkC3C,GAAA,CAAA,GAAO,SAAA;EAOP,UAAA,CAAA,GAAc,SAAA;EAOrB,WAAA,CAAA;EAzGY;AAEd;;;;EAgHE,MAAA,CAAO,KAAA,EAAO,WAAA;AAAA"}
@@ -1,6 +1,7 @@
1
1
  import { _getOverwriteValue, _isOverwriteValue } from "../constants.js";
2
2
  import { EmptyChannelError, InvalidUpdateError } from "../errors.js";
3
3
  import { BaseChannel } from "./base.js";
4
+ import { isDeltaSnapshot } from "@langchain/langgraph-checkpoint";
4
5
  //#region src/channels/binop.ts
5
6
  const isBinaryOperatorAggregate = (value) => {
6
7
  return value != null && value.lc_graph_name === "BinaryOperatorAggregate";
@@ -21,7 +22,7 @@ var BinaryOperatorAggregate = class BinaryOperatorAggregate extends BaseChannel
21
22
  }
22
23
  fromCheckpoint(checkpoint) {
23
24
  const empty = new BinaryOperatorAggregate(this.operator, this.initialValueFactory);
24
- if (typeof checkpoint !== "undefined") empty.value = checkpoint;
25
+ if (typeof checkpoint !== "undefined") empty.value = isDeltaSnapshot(checkpoint) ? checkpoint.value : checkpoint;
25
26
  return empty;
26
27
  }
27
28
  update(values) {
@@ -1 +1 @@
1
- {"version":3,"file":"binop.js","names":[],"sources":["../../src/channels/binop.ts"],"sourcesContent":["import {\n _getOverwriteValue,\n _isOverwriteValue,\n type OverwriteValue,\n} from \"../constants.js\";\nimport { EmptyChannelError, InvalidUpdateError } from \"../errors.js\";\nimport { BaseChannel } from \"./base.js\";\n\ntype OverwriteOrValue<ValueType, UpdateType> =\n | OverwriteValue<ValueType>\n | UpdateType;\n\nexport type BinaryOperator<ValueType, UpdateType> = (\n a: ValueType,\n b: UpdateType\n) => ValueType;\n\nconst isBinaryOperatorAggregate = (\n value: BaseChannel\n): value is BinaryOperatorAggregate<unknown, unknown> => {\n return value != null && value.lc_graph_name === \"BinaryOperatorAggregate\";\n};\n\n/**\n * Stores the result of applying a binary operator to the current value and each new value.\n */\nexport class BinaryOperatorAggregate<\n ValueType,\n UpdateType = ValueType,\n> extends BaseChannel<\n ValueType,\n OverwriteOrValue<ValueType, UpdateType>,\n ValueType\n> {\n lc_graph_name = \"BinaryOperatorAggregate\";\n\n value: ValueType | undefined;\n\n operator: BinaryOperator<ValueType, UpdateType>;\n\n initialValueFactory?: () => ValueType;\n\n constructor(\n operator: BinaryOperator<ValueType, UpdateType>,\n initialValueFactory?: () => ValueType\n ) {\n super();\n\n this.operator = operator;\n this.initialValueFactory = initialValueFactory;\n this.value = initialValueFactory?.();\n }\n\n public fromCheckpoint(checkpoint?: ValueType) {\n const empty = new BinaryOperatorAggregate(\n this.operator,\n this.initialValueFactory\n );\n if (typeof checkpoint !== \"undefined\") {\n empty.value = checkpoint;\n }\n return empty as this;\n }\n\n public update(values: OverwriteOrValue<ValueType, UpdateType>[]): boolean {\n let newValues = values;\n if (!newValues.length) return false;\n\n if (this.value === undefined) {\n const first = newValues[0];\n const [isOverwrite, overwriteVal] = _getOverwriteValue<ValueType>(first);\n if (isOverwrite) {\n this.value = overwriteVal;\n } else {\n this.value = first as ValueType;\n }\n newValues = newValues.slice(1);\n }\n\n let seenOverwrite = false;\n for (const incoming of newValues) {\n if (_isOverwriteValue<ValueType>(incoming)) {\n if (seenOverwrite) {\n throw new InvalidUpdateError(\n \"Can receive only one Overwrite value per step.\"\n );\n }\n const [, val] = _getOverwriteValue<ValueType>(incoming);\n this.value = val;\n seenOverwrite = true;\n continue;\n } else if (!seenOverwrite && this.value !== undefined) {\n this.value = this.operator(this.value, incoming);\n }\n }\n return true;\n }\n\n public get(): ValueType {\n if (this.value === undefined) {\n throw new EmptyChannelError();\n }\n return this.value;\n }\n\n public checkpoint(): ValueType {\n if (this.value === undefined) {\n throw new EmptyChannelError();\n }\n return this.value;\n }\n\n isAvailable(): boolean {\n return this.value !== undefined;\n }\n\n /**\n * Compare this channel with another channel for equality.\n * Two BinaryOperatorAggregate channels are equal if they have the same operator function.\n * This follows the Python implementation which compares operator references.\n */\n equals(other: BaseChannel): boolean {\n if (this === other) return true;\n if (!isBinaryOperatorAggregate(other)) return false;\n return this.operator === other.operator;\n }\n}\n"],"mappings":";;;;AAiBA,MAAM,6BACJ,UACuD;AACvD,QAAO,SAAS,QAAQ,MAAM,kBAAkB;;;;;AAMlD,IAAa,0BAAb,MAAa,gCAGH,YAIR;CACA,gBAAgB;CAEhB;CAEA;CAEA;CAEA,YACE,UACA,qBACA;AACA,SAAO;AAEP,OAAK,WAAW;AAChB,OAAK,sBAAsB;AAC3B,OAAK,QAAQ,uBAAuB;;CAGtC,eAAsB,YAAwB;EAC5C,MAAM,QAAQ,IAAI,wBAChB,KAAK,UACL,KAAK,oBACN;AACD,MAAI,OAAO,eAAe,YACxB,OAAM,QAAQ;AAEhB,SAAO;;CAGT,OAAc,QAA4D;EACxE,IAAI,YAAY;AAChB,MAAI,CAAC,UAAU,OAAQ,QAAO;AAE9B,MAAI,KAAK,UAAU,KAAA,GAAW;GAC5B,MAAM,QAAQ,UAAU;GACxB,MAAM,CAAC,aAAa,gBAAgB,mBAA8B,MAAM;AACxE,OAAI,YACF,MAAK,QAAQ;OAEb,MAAK,QAAQ;AAEf,eAAY,UAAU,MAAM,EAAE;;EAGhC,IAAI,gBAAgB;AACpB,OAAK,MAAM,YAAY,UACrB,KAAI,kBAA6B,SAAS,EAAE;AAC1C,OAAI,cACF,OAAM,IAAI,mBACR,iDACD;GAEH,MAAM,GAAG,OAAO,mBAA8B,SAAS;AACvD,QAAK,QAAQ;AACb,mBAAgB;AAChB;aACS,CAAC,iBAAiB,KAAK,UAAU,KAAA,EAC1C,MAAK,QAAQ,KAAK,SAAS,KAAK,OAAO,SAAS;AAGpD,SAAO;;CAGT,MAAwB;AACtB,MAAI,KAAK,UAAU,KAAA,EACjB,OAAM,IAAI,mBAAmB;AAE/B,SAAO,KAAK;;CAGd,aAA+B;AAC7B,MAAI,KAAK,UAAU,KAAA,EACjB,OAAM,IAAI,mBAAmB;AAE/B,SAAO,KAAK;;CAGd,cAAuB;AACrB,SAAO,KAAK,UAAU,KAAA;;;;;;;CAQxB,OAAO,OAA6B;AAClC,MAAI,SAAS,MAAO,QAAO;AAC3B,MAAI,CAAC,0BAA0B,MAAM,CAAE,QAAO;AAC9C,SAAO,KAAK,aAAa,MAAM"}
1
+ {"version":3,"file":"binop.js","names":[],"sources":["../../src/channels/binop.ts"],"sourcesContent":["import { isDeltaSnapshot } from \"@langchain/langgraph-checkpoint\";\nimport {\n _getOverwriteValue,\n _isOverwriteValue,\n type OverwriteValue,\n} from \"../constants.js\";\nimport { EmptyChannelError, InvalidUpdateError } from \"../errors.js\";\nimport { BaseChannel } from \"./base.js\";\n\ntype OverwriteOrValue<ValueType, UpdateType> =\n | OverwriteValue<ValueType>\n | UpdateType;\n\nexport type BinaryOperator<ValueType, UpdateType> = (\n a: ValueType,\n b: UpdateType\n) => ValueType;\n\nconst isBinaryOperatorAggregate = (\n value: BaseChannel\n): value is BinaryOperatorAggregate<unknown, unknown> => {\n return value != null && value.lc_graph_name === \"BinaryOperatorAggregate\";\n};\n\n/**\n * Stores the result of applying a binary operator to the current value and each new value.\n */\nexport class BinaryOperatorAggregate<\n ValueType,\n UpdateType = ValueType,\n> extends BaseChannel<\n ValueType,\n OverwriteOrValue<ValueType, UpdateType>,\n ValueType\n> {\n lc_graph_name = \"BinaryOperatorAggregate\";\n\n value: ValueType | undefined;\n\n operator: BinaryOperator<ValueType, UpdateType>;\n\n initialValueFactory?: () => ValueType;\n\n constructor(\n operator: BinaryOperator<ValueType, UpdateType>,\n initialValueFactory?: () => ValueType\n ) {\n super();\n\n this.operator = operator;\n this.initialValueFactory = initialValueFactory;\n this.value = initialValueFactory?.();\n }\n\n public fromCheckpoint(checkpoint?: ValueType) {\n const empty = new BinaryOperatorAggregate(\n this.operator,\n this.initialValueFactory\n );\n if (typeof checkpoint !== \"undefined\") {\n // A thread written while this field was a DeltaChannel stores snapshots.\n empty.value = isDeltaSnapshot(checkpoint)\n ? (checkpoint.value as ValueType)\n : checkpoint;\n }\n return empty as this;\n }\n\n public update(values: OverwriteOrValue<ValueType, UpdateType>[]): boolean {\n let newValues = values;\n if (!newValues.length) return false;\n\n if (this.value === undefined) {\n const first = newValues[0];\n const [isOverwrite, overwriteVal] = _getOverwriteValue<ValueType>(first);\n if (isOverwrite) {\n this.value = overwriteVal;\n } else {\n this.value = first as ValueType;\n }\n newValues = newValues.slice(1);\n }\n\n let seenOverwrite = false;\n for (const incoming of newValues) {\n if (_isOverwriteValue<ValueType>(incoming)) {\n if (seenOverwrite) {\n throw new InvalidUpdateError(\n \"Can receive only one Overwrite value per step.\"\n );\n }\n const [, val] = _getOverwriteValue<ValueType>(incoming);\n this.value = val;\n seenOverwrite = true;\n continue;\n } else if (!seenOverwrite && this.value !== undefined) {\n this.value = this.operator(this.value, incoming);\n }\n }\n return true;\n }\n\n public get(): ValueType {\n if (this.value === undefined) {\n throw new EmptyChannelError();\n }\n return this.value;\n }\n\n public checkpoint(): ValueType {\n if (this.value === undefined) {\n throw new EmptyChannelError();\n }\n return this.value;\n }\n\n isAvailable(): boolean {\n return this.value !== undefined;\n }\n\n /**\n * Compare this channel with another channel for equality.\n * Two BinaryOperatorAggregate channels are equal if they have the same operator function.\n * This follows the Python implementation which compares operator references.\n */\n equals(other: BaseChannel): boolean {\n if (this === other) return true;\n if (!isBinaryOperatorAggregate(other)) return false;\n return this.operator === other.operator;\n }\n}\n"],"mappings":";;;;;AAkBA,MAAM,6BACJ,UACuD;AACvD,QAAO,SAAS,QAAQ,MAAM,kBAAkB;;;;;AAMlD,IAAa,0BAAb,MAAa,gCAGH,YAIR;CACA,gBAAgB;CAEhB;CAEA;CAEA;CAEA,YACE,UACA,qBACA;AACA,SAAO;AAEP,OAAK,WAAW;AAChB,OAAK,sBAAsB;AAC3B,OAAK,QAAQ,uBAAuB;;CAGtC,eAAsB,YAAwB;EAC5C,MAAM,QAAQ,IAAI,wBAChB,KAAK,UACL,KAAK,oBACN;AACD,MAAI,OAAO,eAAe,YAExB,OAAM,QAAQ,gBAAgB,WAAW,GACpC,WAAW,QACZ;AAEN,SAAO;;CAGT,OAAc,QAA4D;EACxE,IAAI,YAAY;AAChB,MAAI,CAAC,UAAU,OAAQ,QAAO;AAE9B,MAAI,KAAK,UAAU,KAAA,GAAW;GAC5B,MAAM,QAAQ,UAAU;GACxB,MAAM,CAAC,aAAa,gBAAgB,mBAA8B,MAAM;AACxE,OAAI,YACF,MAAK,QAAQ;OAEb,MAAK,QAAQ;AAEf,eAAY,UAAU,MAAM,EAAE;;EAGhC,IAAI,gBAAgB;AACpB,OAAK,MAAM,YAAY,UACrB,KAAI,kBAA6B,SAAS,EAAE;AAC1C,OAAI,cACF,OAAM,IAAI,mBACR,iDACD;GAEH,MAAM,GAAG,OAAO,mBAA8B,SAAS;AACvD,QAAK,QAAQ;AACb,mBAAgB;AAChB;aACS,CAAC,iBAAiB,KAAK,UAAU,KAAA,EAC1C,MAAK,QAAQ,KAAK,SAAS,KAAK,OAAO,SAAS;AAGpD,SAAO;;CAGT,MAAwB;AACtB,MAAI,KAAK,UAAU,KAAA,EACjB,OAAM,IAAI,mBAAmB;AAE/B,SAAO,KAAK;;CAGd,aAA+B;AAC7B,MAAI,KAAK,UAAU,KAAA,EACjB,OAAM,IAAI,mBAAmB;AAE/B,SAAO,KAAK;;CAGd,cAAuB;AACrB,SAAO,KAAK,UAAU,KAAA;;;;;;;CAQxB,OAAO,OAA6B;AAClC,MAAI,SAAS,MAAO,QAAO;AAC3B,MAAI,CAAC,0BAA0B,MAAM,CAAE,QAAO;AAC9C,SAAO,KAAK,aAAa,MAAM"}
package/dist/errors.cjs CHANGED
@@ -132,6 +132,26 @@ function isParentCommand(e) {
132
132
  function isGraphBubbleUp(e) {
133
133
  return e !== void 0 && e.is_bubble_up === true;
134
134
  }
135
+ const INVALID_RESUME = Symbol.for("langgraph.invalid_resume");
136
+ /** @internal */
137
+ function _markInvalidResume(error) {
138
+ if (typeof error === "object" && error !== null) Object.defineProperty(error, INVALID_RESUME, { value: true });
139
+ }
140
+ /**
141
+ * Whether `error` was thrown because a resume value didn't match the interrupt's
142
+ * `responseSchema`, directly or as the `cause` of a wrapping error (such as one
143
+ * from agent middleware). The resume fails once the step's other tasks finish,
144
+ * and the interrupt can be answered again.
145
+ */
146
+ function isInvalidResume(error) {
147
+ let current = error;
148
+ for (let depth = 0; depth < 10; depth += 1) {
149
+ if (typeof current !== "object" || current === null) return false;
150
+ if (current[INVALID_RESUME] === true) return true;
151
+ current = current.cause;
152
+ }
153
+ return false;
154
+ }
135
155
  function isGraphInterrupt(e) {
136
156
  return e !== void 0 && [GraphInterrupt.unminifiable_name, NodeInterrupt.unminifiable_name].includes(e.name);
137
157
  }
@@ -315,10 +335,12 @@ exports.ParentCommand = ParentCommand;
315
335
  exports.RemoteException = RemoteException;
316
336
  exports.StateGraphInputError = StateGraphInputError;
317
337
  exports.UnreachableNodeError = UnreachableNodeError;
338
+ exports._markInvalidResume = _markInvalidResume;
318
339
  exports.getSubgraphsSeenSet = getSubgraphsSeenSet;
319
340
  exports.isGraphBubbleUp = isGraphBubbleUp;
320
341
  exports.isGraphDrained = isGraphDrained;
321
342
  exports.isGraphInterrupt = isGraphInterrupt;
343
+ exports.isInvalidResume = isInvalidResume;
322
344
  exports.isNodeError = isNodeError;
323
345
  exports.isNodeTimeoutError = isNodeTimeoutError;
324
346
  exports.isParentCommand = isParentCommand;
@@ -1 +1 @@
1
- {"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["import { Command, Interrupt } from \"./constants.js\";\n\n// When editing, make sure to update the index found here:\n// https://langchain-ai.github.io/langgraphjs/troubleshooting/errors/\nexport type BaseLangGraphErrorFields = {\n lc_error_code?:\n | \"GRAPH_RECURSION_LIMIT\"\n | \"INVALID_CONCURRENT_GRAPH_UPDATE\"\n | \"INVALID_GRAPH_NODE_RETURN_VALUE\"\n | \"MISSING_CHECKPOINTER\"\n | \"MULTIPLE_SUBGRAPHS\"\n | \"UNREACHABLE_NODE\";\n};\n\n// TODO: Merge with base LangChain error class when we drop support for core@0.2.0\n/** @category Errors */\nexport class BaseLangGraphError extends Error {\n lc_error_code?: string;\n\n constructor(message?: string, fields?: BaseLangGraphErrorFields) {\n let finalMessage = message ?? \"\";\n if (fields?.lc_error_code) {\n finalMessage = `${finalMessage}\\n\\nTroubleshooting URL: https://docs.langchain.com/oss/javascript/langgraph/${fields.lc_error_code}/\\n`;\n }\n super(finalMessage);\n this.lc_error_code = fields?.lc_error_code;\n }\n}\n\nexport class GraphBubbleUp extends BaseLangGraphError {\n get is_bubble_up() {\n return true;\n }\n}\n\nexport class GraphRecursionError extends BaseLangGraphError {\n constructor(message?: string, fields?: BaseLangGraphErrorFields) {\n super(message, fields);\n this.name = \"GraphRecursionError\";\n }\n\n static get unminifiable_name() {\n return \"GraphRecursionError\";\n }\n}\n\nexport class GraphValueError extends BaseLangGraphError {\n constructor(message?: string, fields?: BaseLangGraphErrorFields) {\n super(message, fields);\n this.name = \"GraphValueError\";\n }\n\n static get unminifiable_name() {\n return \"GraphValueError\";\n }\n}\n\n/**\n * Raised when a graph run exits early due to a drain request.\n *\n * This indicates the graph stopped cooperatively at a superstep boundary\n * because {@link RunControl#requestDrain} was called (e.g., in response to\n * SIGTERM). The checkpoint is saved and the run can be resumed later.\n */\nexport class GraphDrained extends GraphBubbleUp {\n reason: string;\n\n constructor(reason: string = \"shutdown\", fields?: BaseLangGraphErrorFields) {\n super(`Graph drained: ${reason}`, fields);\n this.name = \"GraphDrained\";\n this.reason = reason;\n }\n\n static get unminifiable_name() {\n return \"GraphDrained\";\n }\n}\n\nexport function isGraphDrained(e?: unknown): e is GraphDrained {\n return (\n e !== undefined && (e as Error).name === GraphDrained.unminifiable_name\n );\n}\n\nexport class GraphInterrupt extends GraphBubbleUp {\n interrupts: Interrupt[];\n\n constructor(interrupts?: Interrupt[], fields?: BaseLangGraphErrorFields) {\n super(JSON.stringify(interrupts, null, 2), fields);\n this.name = \"GraphInterrupt\";\n this.interrupts = interrupts ?? [];\n }\n\n static get unminifiable_name() {\n return \"GraphInterrupt\";\n }\n}\n\n/** Raised by a node to interrupt execution. */\nexport class NodeInterrupt extends GraphInterrupt {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n constructor(message: any, fields?: BaseLangGraphErrorFields) {\n super([{ value: message }], fields);\n this.name = \"NodeInterrupt\";\n }\n\n static get unminifiable_name() {\n return \"NodeInterrupt\";\n }\n}\n\n/**\n * Failure context passed to a node-level error handler.\n *\n * A node-level error handler is registered via\n * `StateGraph.addNode(name, fn, { errorHandler })`. The handler runs ONLY after\n * the failing node's {@link RetryPolicy} is exhausted, so retry and handling\n * stay decoupled. The handler receives the failed node's name and the thrown\n * error via a `NodeError` instance, can return a state update, and can route to\n * a recovery branch via `new Command({ goto })` (saga / compensation flows).\n *\n * @example\n * ```ts\n * import { NodeError } from \"@langchain/langgraph\";\n *\n * function handler(state: State, error: NodeError) {\n * return new Command({\n * update: { status: `recovered from ${error.node}: ${error.error.message}` },\n * goto: \"finalize\",\n * });\n * }\n * ```\n */\nexport class NodeError {\n /** Name of the node whose execution failed. */\n node: string;\n\n /** Error thrown by the failed node. */\n error: Error;\n\n constructor(node: string, error: Error) {\n this.node = node;\n this.error = error;\n }\n\n static get unminifiable_name() {\n return \"NodeError\";\n }\n}\n\n/**\n * Type guard that checks whether a value is a {@link NodeError}.\n */\nexport function isNodeError(e?: unknown): e is NodeError {\n return (\n e != null &&\n typeof e === \"object\" &&\n e.constructor != null &&\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (e.constructor as any).unminifiable_name === NodeError.unminifiable_name\n );\n}\n\nexport class ParentCommand extends GraphBubbleUp {\n command: Command;\n\n constructor(command: Command) {\n super();\n this.name = \"ParentCommand\";\n this.command = command;\n }\n\n static get unminifiable_name() {\n return \"ParentCommand\";\n }\n}\n\nexport function isParentCommand(e?: unknown): e is ParentCommand {\n return (\n e !== undefined &&\n (e as ParentCommand).name === ParentCommand.unminifiable_name\n );\n}\n\nexport function isGraphBubbleUp(e?: unknown): e is GraphBubbleUp {\n return e !== undefined && (e as GraphBubbleUp).is_bubble_up === true;\n}\n\nexport function isGraphInterrupt(e?: unknown): e is GraphInterrupt {\n return (\n e !== undefined &&\n [\n GraphInterrupt.unminifiable_name,\n NodeInterrupt.unminifiable_name,\n ].includes((e as Error).name)\n );\n}\n\n/**\n * Raised when a node invocation exceeds one of its configured timeouts.\n *\n * Does **not** extend {@link GraphBubbleUp} (so it flows through the normal node\n * error path) and is intentionally treated as retryable by the default retry\n * policy — its message/name do not match the default `retryOn` blocklist, so a\n * configured {@link RetryPolicy} will retry it (see langchain-ai/langgraph#7659).\n *\n * Both {@link NodeTimeoutError.runTimeout} and {@link NodeTimeoutError.idleTimeout}\n * reflect the configured policy at the time of the failure (each `undefined` if\n * not configured). {@link NodeTimeoutError.kind} and {@link NodeTimeoutError.timeout}\n * identify which one fired.\n *\n * @category Errors\n */\nexport class NodeTimeoutError extends BaseLangGraphError {\n /** Name of the node/task that timed out. */\n node: string;\n\n /** Which timeout fired: a hard `\"run\"` cap or a progress-resetting `\"idle\"` cap. */\n kind: \"run\" | \"idle\";\n\n /** The value (ms) of the timeout that fired (`runTimeout` or `idleTimeout`). */\n timeout: number;\n\n /** Elapsed time (ms) since the attempt started, at the moment the timeout fired. */\n elapsed: number;\n\n /** Configured run timeout (ms), if any. */\n runTimeout?: number;\n\n /** Configured idle timeout (ms), if any. */\n idleTimeout?: number;\n\n constructor(\n fields: {\n node: string;\n elapsed: number;\n kind: \"run\" | \"idle\";\n runTimeout?: number;\n idleTimeout?: number;\n },\n errorFields?: BaseLangGraphErrorFields\n ) {\n const { node, elapsed, kind, runTimeout, idleTimeout } = fields;\n let message: string;\n let timeout: number;\n if (kind === \"idle\") {\n if (idleTimeout === undefined) {\n throw new Error(\"idleTimeout is required when kind='idle'\");\n }\n timeout = idleTimeout;\n message =\n `Node \"${node}\" exceeded its idle timeout of ${idleTimeout}ms ` +\n `without making progress (elapsed: ${elapsed}ms).`;\n } else {\n if (runTimeout === undefined) {\n throw new Error(\"runTimeout is required when kind='run'\");\n }\n timeout = runTimeout;\n message =\n `Node \"${node}\" exceeded its run timeout of ${runTimeout}ms ` +\n `(elapsed: ${elapsed}ms).`;\n }\n super(message, errorFields);\n this.name = \"NodeTimeoutError\";\n this.node = node;\n this.kind = kind;\n this.timeout = timeout;\n this.elapsed = elapsed;\n this.runTimeout = runTimeout;\n this.idleTimeout = idleTimeout;\n }\n\n static get unminifiable_name() {\n return \"NodeTimeoutError\";\n }\n}\n\nexport function isNodeTimeoutError(e?: unknown): e is NodeTimeoutError {\n return (\n e !== undefined &&\n (e as NodeTimeoutError).name === NodeTimeoutError.unminifiable_name\n );\n}\n\nexport class EmptyInputError extends BaseLangGraphError {\n constructor(message?: string, fields?: BaseLangGraphErrorFields) {\n super(message, fields);\n this.name = \"EmptyInputError\";\n }\n\n static get unminifiable_name() {\n return \"EmptyInputError\";\n }\n}\n\nexport class EmptyChannelError extends BaseLangGraphError {\n constructor(message?: string, fields?: BaseLangGraphErrorFields) {\n // Skip expensive stack trace capture — used for control flow on channel reads.\n const prevLimit = Error.stackTraceLimit;\n Error.stackTraceLimit = 0;\n super(message, fields);\n Error.stackTraceLimit = prevLimit;\n this.name = \"EmptyChannelError\";\n }\n\n static get unminifiable_name() {\n return \"EmptyChannelError\";\n }\n}\n\nexport class InvalidUpdateError extends BaseLangGraphError {\n constructor(message?: string, fields?: BaseLangGraphErrorFields) {\n super(message, fields);\n this.name = \"InvalidUpdateError\";\n }\n\n static get unminifiable_name() {\n return \"InvalidUpdateError\";\n }\n}\n\n/**\n * @deprecated This exception type is no longer thrown.\n */\nexport class MultipleSubgraphsError extends BaseLangGraphError {\n constructor(message?: string, fields?: BaseLangGraphErrorFields) {\n super(message, fields);\n this.name = \"MultipleSubgraphError\";\n }\n\n static get unminifiable_name() {\n return \"MultipleSubgraphError\";\n }\n}\n\nexport class UnreachableNodeError extends BaseLangGraphError {\n constructor(message?: string, fields?: BaseLangGraphErrorFields) {\n super(message, fields);\n this.name = \"UnreachableNodeError\";\n }\n\n static get unminifiable_name() {\n return \"UnreachableNodeError\";\n }\n}\n\n/**\n * Exception raised when an error occurs in the remote graph.\n */\nexport class RemoteException extends BaseLangGraphError {\n constructor(message?: string, fields?: BaseLangGraphErrorFields) {\n super(message, fields);\n this.name = \"RemoteException\";\n }\n\n static get unminifiable_name() {\n return \"RemoteException\";\n }\n}\n\n/**\n * Error thrown when invalid input is provided to a StateGraph.\n *\n * This typically means that the input to the StateGraph constructor or builder\n * did not match the required types. A valid input should be a\n * StateDefinition, an Annotation.Root, or a Zod schema.\n *\n * @example\n * // Example of incorrect usage:\n * try {\n * new StateGraph({ foo: \"bar\" }); // Not a valid input\n * } catch (err) {\n * if (err instanceof StateGraphInputError) {\n * console.error(err.message);\n * }\n * }\n */\nexport class StateGraphInputError extends BaseLangGraphError {\n /**\n * Create a new StateGraphInputError.\n * @param message - Optional custom error message.\n * @param fields - Optional additional error fields.\n */\n constructor(message?: string, fields?: BaseLangGraphErrorFields) {\n super(message, fields);\n this.name = \"StateGraphInputError\";\n this.message =\n \"Invalid StateGraph input. Make sure to pass a valid StateDefinition, Annotation.Root, or Zod schema.\";\n }\n\n /**\n * The unminifiable (static, human-readable) error name for this error class.\n */\n static get unminifiable_name() {\n return \"StateGraphInputError\";\n }\n}\n\n/**\n * Used for subgraph detection.\n */\nexport const getSubgraphsSeenSet = () => {\n if (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (globalThis as any)[Symbol.for(\"LG_CHECKPOINT_SEEN_NS_SET\")] === undefined\n ) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (globalThis as any)[Symbol.for(\"LG_CHECKPOINT_SEEN_NS_SET\")] = new Set();\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (globalThis as any)[Symbol.for(\"LG_CHECKPOINT_SEEN_NS_SET\")];\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["import { Command, Interrupt } from \"./constants.js\";\n\n// When editing, make sure to update the index found here:\n// https://langchain-ai.github.io/langgraphjs/troubleshooting/errors/\nexport type BaseLangGraphErrorFields = {\n lc_error_code?:\n | \"GRAPH_RECURSION_LIMIT\"\n | \"INVALID_CONCURRENT_GRAPH_UPDATE\"\n | \"INVALID_GRAPH_NODE_RETURN_VALUE\"\n | \"MISSING_CHECKPOINTER\"\n | \"MULTIPLE_SUBGRAPHS\"\n | \"UNREACHABLE_NODE\";\n};\n\n// TODO: Merge with base LangChain error class when we drop support for core@0.2.0\n/** @category Errors */\nexport class BaseLangGraphError extends Error {\n lc_error_code?: string;\n\n constructor(message?: string, fields?: BaseLangGraphErrorFields) {\n let finalMessage = message ?? \"\";\n if (fields?.lc_error_code) {\n finalMessage = `${finalMessage}\\n\\nTroubleshooting URL: https://docs.langchain.com/oss/javascript/langgraph/${fields.lc_error_code}/\\n`;\n }\n super(finalMessage);\n this.lc_error_code = fields?.lc_error_code;\n }\n}\n\nexport class GraphBubbleUp extends BaseLangGraphError {\n get is_bubble_up() {\n return true;\n }\n}\n\nexport class GraphRecursionError extends BaseLangGraphError {\n constructor(message?: string, fields?: BaseLangGraphErrorFields) {\n super(message, fields);\n this.name = \"GraphRecursionError\";\n }\n\n static get unminifiable_name() {\n return \"GraphRecursionError\";\n }\n}\n\nexport class GraphValueError extends BaseLangGraphError {\n constructor(message?: string, fields?: BaseLangGraphErrorFields) {\n super(message, fields);\n this.name = \"GraphValueError\";\n }\n\n static get unminifiable_name() {\n return \"GraphValueError\";\n }\n}\n\n/**\n * Raised when a graph run exits early due to a drain request.\n *\n * This indicates the graph stopped cooperatively at a superstep boundary\n * because {@link RunControl#requestDrain} was called (e.g., in response to\n * SIGTERM). The checkpoint is saved and the run can be resumed later.\n */\nexport class GraphDrained extends GraphBubbleUp {\n reason: string;\n\n constructor(reason: string = \"shutdown\", fields?: BaseLangGraphErrorFields) {\n super(`Graph drained: ${reason}`, fields);\n this.name = \"GraphDrained\";\n this.reason = reason;\n }\n\n static get unminifiable_name() {\n return \"GraphDrained\";\n }\n}\n\nexport function isGraphDrained(e?: unknown): e is GraphDrained {\n return (\n e !== undefined && (e as Error).name === GraphDrained.unminifiable_name\n );\n}\n\nexport class GraphInterrupt extends GraphBubbleUp {\n interrupts: Interrupt[];\n\n constructor(interrupts?: Interrupt[], fields?: BaseLangGraphErrorFields) {\n super(JSON.stringify(interrupts, null, 2), fields);\n this.name = \"GraphInterrupt\";\n this.interrupts = interrupts ?? [];\n }\n\n static get unminifiable_name() {\n return \"GraphInterrupt\";\n }\n}\n\n/** Raised by a node to interrupt execution. */\nexport class NodeInterrupt extends GraphInterrupt {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n constructor(message: any, fields?: BaseLangGraphErrorFields) {\n super([{ value: message }], fields);\n this.name = \"NodeInterrupt\";\n }\n\n static get unminifiable_name() {\n return \"NodeInterrupt\";\n }\n}\n\n/**\n * Failure context passed to a node-level error handler.\n *\n * A node-level error handler is registered via\n * `StateGraph.addNode(name, fn, { errorHandler })`. The handler runs ONLY after\n * the failing node's {@link RetryPolicy} is exhausted, so retry and handling\n * stay decoupled. The handler receives the failed node's name and the thrown\n * error via a `NodeError` instance, can return a state update, and can route to\n * a recovery branch via `new Command({ goto })` (saga / compensation flows).\n *\n * @example\n * ```ts\n * import { NodeError } from \"@langchain/langgraph\";\n *\n * function handler(state: State, error: NodeError) {\n * return new Command({\n * update: { status: `recovered from ${error.node}: ${error.error.message}` },\n * goto: \"finalize\",\n * });\n * }\n * ```\n */\nexport class NodeError {\n /** Name of the node whose execution failed. */\n node: string;\n\n /** Error thrown by the failed node. */\n error: Error;\n\n constructor(node: string, error: Error) {\n this.node = node;\n this.error = error;\n }\n\n static get unminifiable_name() {\n return \"NodeError\";\n }\n}\n\n/**\n * Type guard that checks whether a value is a {@link NodeError}.\n */\nexport function isNodeError(e?: unknown): e is NodeError {\n return (\n e != null &&\n typeof e === \"object\" &&\n e.constructor != null &&\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (e.constructor as any).unminifiable_name === NodeError.unminifiable_name\n );\n}\n\nexport class ParentCommand extends GraphBubbleUp {\n command: Command;\n\n constructor(command: Command) {\n super();\n this.name = \"ParentCommand\";\n this.command = command;\n }\n\n static get unminifiable_name() {\n return \"ParentCommand\";\n }\n}\n\nexport function isParentCommand(e?: unknown): e is ParentCommand {\n return (\n e !== undefined &&\n (e as ParentCommand).name === ParentCommand.unminifiable_name\n );\n}\n\nexport function isGraphBubbleUp(e?: unknown): e is GraphBubbleUp {\n return e !== undefined && (e as GraphBubbleUp).is_bubble_up === true;\n}\n\n// Set by `interrupt()` on the error from a resume value that fails its\n// `responseSchema`. `Symbol.for`, so another copy of this package recognizes it.\nconst INVALID_RESUME = Symbol.for(\"langgraph.invalid_resume\");\n\n/** @internal */\nexport function _markInvalidResume(error: unknown): void {\n if (typeof error === \"object\" && error !== null) {\n Object.defineProperty(error, INVALID_RESUME, { value: true });\n }\n}\n\n/**\n * Whether `error` was thrown because a resume value didn't match the interrupt's\n * `responseSchema`, directly or as the `cause` of a wrapping error (such as one\n * from agent middleware). The resume fails once the step's other tasks finish,\n * and the interrupt can be answered again.\n */\nexport function isInvalidResume(error: unknown): boolean {\n let current = error;\n // Bounded, in case a `cause` chain loops.\n for (let depth = 0; depth < 10; depth += 1) {\n if (typeof current !== \"object\" || current === null) return false;\n if ((current as Record<symbol, unknown>)[INVALID_RESUME] === true) {\n return true;\n }\n current = (current as { cause?: unknown }).cause;\n }\n return false;\n}\n\nexport function isGraphInterrupt(e?: unknown): e is GraphInterrupt {\n return (\n e !== undefined &&\n [\n GraphInterrupt.unminifiable_name,\n NodeInterrupt.unminifiable_name,\n ].includes((e as Error).name)\n );\n}\n\n/**\n * Raised when a node invocation exceeds one of its configured timeouts.\n *\n * Does **not** extend {@link GraphBubbleUp} (so it flows through the normal node\n * error path) and is intentionally treated as retryable by the default retry\n * policy — its message/name do not match the default `retryOn` blocklist, so a\n * configured {@link RetryPolicy} will retry it (see langchain-ai/langgraph#7659).\n *\n * Both {@link NodeTimeoutError.runTimeout} and {@link NodeTimeoutError.idleTimeout}\n * reflect the configured policy at the time of the failure (each `undefined` if\n * not configured). {@link NodeTimeoutError.kind} and {@link NodeTimeoutError.timeout}\n * identify which one fired.\n *\n * @category Errors\n */\nexport class NodeTimeoutError extends BaseLangGraphError {\n /** Name of the node/task that timed out. */\n node: string;\n\n /** Which timeout fired: a hard `\"run\"` cap or a progress-resetting `\"idle\"` cap. */\n kind: \"run\" | \"idle\";\n\n /** The value (ms) of the timeout that fired (`runTimeout` or `idleTimeout`). */\n timeout: number;\n\n /** Elapsed time (ms) since the attempt started, at the moment the timeout fired. */\n elapsed: number;\n\n /** Configured run timeout (ms), if any. */\n runTimeout?: number;\n\n /** Configured idle timeout (ms), if any. */\n idleTimeout?: number;\n\n constructor(\n fields: {\n node: string;\n elapsed: number;\n kind: \"run\" | \"idle\";\n runTimeout?: number;\n idleTimeout?: number;\n },\n errorFields?: BaseLangGraphErrorFields\n ) {\n const { node, elapsed, kind, runTimeout, idleTimeout } = fields;\n let message: string;\n let timeout: number;\n if (kind === \"idle\") {\n if (idleTimeout === undefined) {\n throw new Error(\"idleTimeout is required when kind='idle'\");\n }\n timeout = idleTimeout;\n message =\n `Node \"${node}\" exceeded its idle timeout of ${idleTimeout}ms ` +\n `without making progress (elapsed: ${elapsed}ms).`;\n } else {\n if (runTimeout === undefined) {\n throw new Error(\"runTimeout is required when kind='run'\");\n }\n timeout = runTimeout;\n message =\n `Node \"${node}\" exceeded its run timeout of ${runTimeout}ms ` +\n `(elapsed: ${elapsed}ms).`;\n }\n super(message, errorFields);\n this.name = \"NodeTimeoutError\";\n this.node = node;\n this.kind = kind;\n this.timeout = timeout;\n this.elapsed = elapsed;\n this.runTimeout = runTimeout;\n this.idleTimeout = idleTimeout;\n }\n\n static get unminifiable_name() {\n return \"NodeTimeoutError\";\n }\n}\n\nexport function isNodeTimeoutError(e?: unknown): e is NodeTimeoutError {\n return (\n e !== undefined &&\n (e as NodeTimeoutError).name === NodeTimeoutError.unminifiable_name\n );\n}\n\nexport class EmptyInputError extends BaseLangGraphError {\n constructor(message?: string, fields?: BaseLangGraphErrorFields) {\n super(message, fields);\n this.name = \"EmptyInputError\";\n }\n\n static get unminifiable_name() {\n return \"EmptyInputError\";\n }\n}\n\nexport class EmptyChannelError extends BaseLangGraphError {\n constructor(message?: string, fields?: BaseLangGraphErrorFields) {\n // Skip expensive stack trace capture — used for control flow on channel reads.\n const prevLimit = Error.stackTraceLimit;\n Error.stackTraceLimit = 0;\n super(message, fields);\n Error.stackTraceLimit = prevLimit;\n this.name = \"EmptyChannelError\";\n }\n\n static get unminifiable_name() {\n return \"EmptyChannelError\";\n }\n}\n\nexport class InvalidUpdateError extends BaseLangGraphError {\n constructor(message?: string, fields?: BaseLangGraphErrorFields) {\n super(message, fields);\n this.name = \"InvalidUpdateError\";\n }\n\n static get unminifiable_name() {\n return \"InvalidUpdateError\";\n }\n}\n\n/**\n * @deprecated This exception type is no longer thrown.\n */\nexport class MultipleSubgraphsError extends BaseLangGraphError {\n constructor(message?: string, fields?: BaseLangGraphErrorFields) {\n super(message, fields);\n this.name = \"MultipleSubgraphError\";\n }\n\n static get unminifiable_name() {\n return \"MultipleSubgraphError\";\n }\n}\n\nexport class UnreachableNodeError extends BaseLangGraphError {\n constructor(message?: string, fields?: BaseLangGraphErrorFields) {\n super(message, fields);\n this.name = \"UnreachableNodeError\";\n }\n\n static get unminifiable_name() {\n return \"UnreachableNodeError\";\n }\n}\n\n/**\n * Exception raised when an error occurs in the remote graph.\n */\nexport class RemoteException extends BaseLangGraphError {\n constructor(message?: string, fields?: BaseLangGraphErrorFields) {\n super(message, fields);\n this.name = \"RemoteException\";\n }\n\n static get unminifiable_name() {\n return \"RemoteException\";\n }\n}\n\n/**\n * Error thrown when invalid input is provided to a StateGraph.\n *\n * This typically means that the input to the StateGraph constructor or builder\n * did not match the required types. A valid input should be a\n * StateDefinition, an Annotation.Root, or a Zod schema.\n *\n * @example\n * // Example of incorrect usage:\n * try {\n * new StateGraph({ foo: \"bar\" }); // Not a valid input\n * } catch (err) {\n * if (err instanceof StateGraphInputError) {\n * console.error(err.message);\n * }\n * }\n */\nexport class StateGraphInputError extends BaseLangGraphError {\n /**\n * Create a new StateGraphInputError.\n * @param message - Optional custom error message.\n * @param fields - Optional additional error fields.\n */\n constructor(message?: string, fields?: BaseLangGraphErrorFields) {\n super(message, fields);\n this.name = \"StateGraphInputError\";\n this.message =\n \"Invalid StateGraph input. Make sure to pass a valid StateDefinition, Annotation.Root, or Zod schema.\";\n }\n\n /**\n * The unminifiable (static, human-readable) error name for this error class.\n */\n static get unminifiable_name() {\n return \"StateGraphInputError\";\n }\n}\n\n/**\n * Used for subgraph detection.\n */\nexport const getSubgraphsSeenSet = () => {\n if (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (globalThis as any)[Symbol.for(\"LG_CHECKPOINT_SEEN_NS_SET\")] === undefined\n ) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (globalThis as any)[Symbol.for(\"LG_CHECKPOINT_SEEN_NS_SET\")] = new Set();\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (globalThis as any)[Symbol.for(\"LG_CHECKPOINT_SEEN_NS_SET\")];\n};\n"],"mappings":"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"}