@langchain/langgraph 1.4.4 → 1.4.6

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.
@@ -2,6 +2,8 @@ const require_constants = require("../constants.cjs");
2
2
  const require_errors = require("../errors.cjs");
3
3
  let _langchain_langgraph_checkpoint = require("@langchain/langgraph-checkpoint");
4
4
  //#region src/channels/base.ts
5
+ /** Matches Postgres `uuid` / Python `uuid.UUID` (128-bit, 8-4-4-4-12 hex). */
6
+ const STRUCTURED_UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
5
7
  /**
6
8
  * Structural check for a {@link DeltaChannel} without importing it (avoids an
7
9
  * import cycle: `delta.ts` imports `base.ts`).
@@ -87,6 +89,18 @@ function emptyChannels(channels, checkpoint) {
87
89
  return newChannels;
88
90
  }
89
91
  /**
92
+ * Synthetic task id for exit-mode DeltaChannel writes.
93
+ *
94
+ * Embeds the superstep in the first UUID group so `ORDER BY task_id, idx`
95
+ * preserves chronological order while remaining a valid RFC UUID (required by
96
+ * Postgres `checkpoint_writes.task_id uuid` columns).
97
+ */
98
+ function exitDeltaTaskId(step, taskId) {
99
+ if (!STRUCTURED_UUID.test(taskId)) throw new TypeError(`Invalid task id for exit delta: ${taskId}`);
100
+ const parts = taskId.toLowerCase().split("-");
101
+ return `${String(step).padStart(8, "0")}-${parts[1]}-${parts[2]}-${parts[3]}-${parts[4]}`;
102
+ }
103
+ /**
90
104
  * Return the set of {@link DeltaChannel} names that should snapshot now.
91
105
  *
92
106
  * A channel snapshots when EITHER its accumulated update count reaches
@@ -180,6 +194,7 @@ exports.channelsFromCheckpoint = channelsFromCheckpoint;
180
194
  exports.createCheckpoint = createCheckpoint;
181
195
  exports.deltaChannelsToSnapshot = deltaChannelsToSnapshot;
182
196
  exports.emptyChannels = emptyChannels;
197
+ exports.exitDeltaTaskId = exitDeltaTaskId;
183
198
  exports.getOnlyChannels = getOnlyChannels;
184
199
  exports.isBaseChannel = isBaseChannel;
185
200
  exports.isDeltaChannel = isDeltaChannel;
@@ -1 +1 @@
1
- {"version":3,"file":"base.cjs","names":["EmptyChannelError","getDeltaMaxSuperstepsSinceSnapshot","DeltaSnapshot"],"sources":["../../src/channels/base.ts"],"sourcesContent":["import {\n ReadonlyCheckpoint,\n uuid6,\n Checkpoint,\n DeltaSnapshot,\n type BaseCheckpointSaver,\n type DeltaChannelHistory,\n} from \"@langchain/langgraph-checkpoint\";\nimport type { RunnableConfig } from \"@langchain/core/runnables\";\nimport { EmptyChannelError } from \"../errors.js\";\nimport { getDeltaMaxSuperstepsSinceSnapshot } from \"../constants.js\";\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 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 * 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`. Pure predicate — no mutation.\n */\nexport function deltaChannelsToSnapshot(\n channels: Record<string, BaseChannel>,\n countersSinceDeltaSnapshot: Record<string, [number, number]>\n): Set<string> {\n const result = new Set<string>();\n const maxSupersteps = getDeltaMaxSuperstepsSinceSnapshot();\n for (const name in channels) {\n if (!Object.prototype.hasOwnProperty.call(channels, name)) continue;\n const ch = channels[name];\n if (!isDeltaChannel(ch) || !ch.isAvailable()) continue;\n const [updates, supersteps] = countersSinceDeltaSnapshot[name] ?? [0, 0];\n if (\n updates >= (ch as DeltaChannelLike).snapshotFrequency ||\n supersteps >= maxSupersteps\n ) {\n result.add(name);\n }\n }\n return result;\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 updatedChannels?: Set<string>;\n getNextVersion?: (current: number | string | undefined) => number | string;\n }\n): Checkpoint {\n const channelsToSnapshot = options?.channelsToSnapshot ?? new Set<string>();\n const { updatedChannels, getNextVersion } = options ?? {};\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 // Snapshot a DeltaChannel: store the materialized value directly. In\n // exit/deferred modes the channel may have reached its snapshot\n // threshold over several supersteps without the LAST superstep\n // writing to it, so its version wouldn't be bumped by applyWrites —\n // bump it here so the saver includes the snapshot blob.\n if (\n getNextVersion !== undefined &&\n (updatedChannels === undefined || !updatedChannels.has(k))\n ) {\n channelVersions[k] = getNextVersion(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: checkpoint.versions_seen,\n };\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.\n */\nexport async function channelsFromCheckpoint<\n Cc extends Record<string, BaseChannel>,\n>(\n specs: Cc,\n checkpoint: ReadonlyCheckpoint,\n options?: { saver?: BaseCheckpointSaver; config?: RunnableConfig }\n): Promise<Cc> {\n const channels = emptyChannels(specs, checkpoint);\n const { saver, config } = options ?? {};\n\n const filteredSpecs = getOnlyChannels(specs);\n const deltaKeys: string[] = [];\n for (const k in filteredSpecs) {\n if (!Object.prototype.hasOwnProperty.call(filteredSpecs, k)) continue;\n if (\n isDeltaChannel(filteredSpecs[k]) &&\n !Object.prototype.hasOwnProperty.call(checkpoint.channel_values, k)\n ) {\n deltaKeys.push(k);\n }\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","getDeltaMaxSuperstepsSinceSnapshot","DeltaSnapshot"],"sources":["../../src/channels/base.ts"],"sourcesContent":["import {\n ReadonlyCheckpoint,\n uuid6,\n Checkpoint,\n DeltaSnapshot,\n type BaseCheckpointSaver,\n type DeltaChannelHistory,\n} from \"@langchain/langgraph-checkpoint\";\nimport type { RunnableConfig } from \"@langchain/core/runnables\";\nimport { EmptyChannelError } from \"../errors.js\";\nimport { getDeltaMaxSuperstepsSinceSnapshot } 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 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).\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 return `${stepPart}-${parts[1]}-${parts[2]}-${parts[3]}-${parts[4]}`;\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`. Pure predicate — no mutation.\n */\nexport function deltaChannelsToSnapshot(\n channels: Record<string, BaseChannel>,\n countersSinceDeltaSnapshot: Record<string, [number, number]>\n): Set<string> {\n const result = new Set<string>();\n const maxSupersteps = getDeltaMaxSuperstepsSinceSnapshot();\n for (const name in channels) {\n if (!Object.prototype.hasOwnProperty.call(channels, name)) continue;\n const ch = channels[name];\n if (!isDeltaChannel(ch) || !ch.isAvailable()) continue;\n const [updates, supersteps] = countersSinceDeltaSnapshot[name] ?? [0, 0];\n if (\n updates >= (ch as DeltaChannelLike).snapshotFrequency ||\n supersteps >= maxSupersteps\n ) {\n result.add(name);\n }\n }\n return result;\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 updatedChannels?: Set<string>;\n getNextVersion?: (current: number | string | undefined) => number | string;\n }\n): Checkpoint {\n const channelsToSnapshot = options?.channelsToSnapshot ?? new Set<string>();\n const { updatedChannels, getNextVersion } = options ?? {};\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 // Snapshot a DeltaChannel: store the materialized value directly. In\n // exit/deferred modes the channel may have reached its snapshot\n // threshold over several supersteps without the LAST superstep\n // writing to it, so its version wouldn't be bumped by applyWrites —\n // bump it here so the saver includes the snapshot blob.\n if (\n getNextVersion !== undefined &&\n (updatedChannels === undefined || !updatedChannels.has(k))\n ) {\n channelVersions[k] = getNextVersion(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: checkpoint.versions_seen,\n };\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.\n */\nexport async function channelsFromCheckpoint<\n Cc extends Record<string, BaseChannel>,\n>(\n specs: Cc,\n checkpoint: ReadonlyCheckpoint,\n options?: { saver?: BaseCheckpointSaver; config?: RunnableConfig }\n): Promise<Cc> {\n const channels = emptyChannels(specs, checkpoint);\n const { saver, config } = options ?? {};\n\n const filteredSpecs = getOnlyChannels(specs);\n const deltaKeys: string[] = [];\n for (const k in filteredSpecs) {\n if (!Object.prototype.hasOwnProperty.call(filteredSpecs, k)) continue;\n if (\n isDeltaChannel(filteredSpecs[k]) &&\n !Object.prototype.hasOwnProperty.call(checkpoint.channel_values, k)\n ) {\n deltaKeys.push(k);\n }\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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"}
@@ -86,6 +86,14 @@ declare abstract class BaseChannel<ValueType = unknown, UpdateType = unknown, Ch
86
86
  equals(other: BaseChannel): boolean;
87
87
  }
88
88
  declare function emptyChannels<Cc extends Record<string, BaseChannel>>(channels: Cc, checkpoint: ReadonlyCheckpoint): Cc;
89
+ /**
90
+ * Synthetic task id for exit-mode DeltaChannel writes.
91
+ *
92
+ * Embeds the superstep in the first UUID group so `ORDER BY task_id, idx`
93
+ * preserves chronological order while remaining a valid RFC UUID (required by
94
+ * Postgres `checkpoint_writes.task_id uuid` columns).
95
+ */
96
+ declare function exitDeltaTaskId(step: number, taskId: string): string;
89
97
  /**
90
98
  * Return the set of {@link DeltaChannel} names that should snapshot now.
91
99
  *
@@ -117,5 +125,5 @@ declare function channelsFromCheckpoint<Cc extends Record<string, BaseChannel>>(
117
125
  config?: RunnableConfig;
118
126
  }): Promise<Cc>;
119
127
  //#endregion
120
- export { BaseChannel, channelsFromCheckpoint, createCheckpoint, deltaChannelsToSnapshot, emptyChannels, isDeltaChannel };
128
+ export { BaseChannel, channelsFromCheckpoint, createCheckpoint, deltaChannelsToSnapshot, emptyChannels, exitDeltaTaskId, isDeltaChannel };
121
129
  //# sourceMappingURL=base.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"base.d.cts","names":[],"sources":["../../src/channels/base.ts"],"mappings":";;;;;;AAgBA;;iBAAgB,cAAA,CAAe,OAAA,EAAS,WAAA;;uBASlB,WAAA;EAKpB,SAAA,EAAW,SAAA;EAEX,UAAA,EAAY,UAAA;EAFD;;;EAAA,SAOF,aAAA;EAoCO;EAjChB,aAAA;EA0Fc;;;;;;;;EAAA,SAhFL,cAAA,CAAe,UAAA,GAAa,cAAA;EAlBzB;;;;;;;;;;;;;EAAA,SAiCH,MAAA,CAAO,MAAA,EAAQ,UAAA;EAmCxB;;;;;;EAAA,SA3BS,GAAA,CAAA,GAAO,SAAA;EAgFF;;;;;;EAAA,SAxEL,UAAA,CAAA,GAAc,cAAA;EA2EtB;;;;;;;EAlED,OAAA,CAAA;EAiEY;;;;;AA8Bd;EArFE,MAAA,CAAA;;;;;;EASA,WAAA,CAAA;EA+EI;;;;;;;;EA1DJ,MAAA,CAAO,KAAA,EAAO,WAAA;AAAA;AAAA,iBAuBA,aAAA,YAAyB,MAAA,SAAe,WAAA,EAAA,CACtD,QAAA,EAAU,EAAA,EACV,UAAA,EAAY,kBAAA,GACX,EAAA;;;;;;;;iBA6Ba,uBAAA,CACd,QAAA,EAAU,MAAA,SAAe,WAAA,GACzB,0BAAA,EAA4B,MAAA,6BAC3B,GAAA;AAAA,iBAkBa,gBAAA,WAAA,CACd,UAAA,EAAY,kBAAA,EACZ,QAAA,EAAU,MAAA,SAAe,WAAA,CAAY,SAAA,gBACrC,IAAA,UACA,OAAA;EACE,EAAA;EACA,kBAAA,GAAqB,GAAA;EACrB,eAAA,GAAkB,GAAA;EAClB,cAAA,IAAkB,OAAA;AAAA,IAEnB,UAAA;;;;;;;;;;;;;iBAqEmB,sBAAA,YACT,MAAA,SAAe,WAAA,EAAA,CAE1B,KAAA,EAAO,EAAA,EACP,UAAA,EAAY,kBAAA,EACZ,OAAA;EAAY,KAAA,GAAQ,mBAAA;EAAqB,MAAA,GAAS,cAAA;AAAA,IACjD,OAAA,CAAQ,EAAA"}
1
+ {"version":3,"file":"base.d.cts","names":[],"sources":["../../src/channels/base.ts"],"mappings":";;;;;;AAoBA;;iBAAgB,cAAA,CAAe,OAAA,EAAS,WAAA;;uBASlB,WAAA;EAKpB,SAAA,EAAW,SAAA;EAEX,UAAA,EAAY,UAAA;EAFD;;;EAAA,SAOF,aAAA;EAoCO;EAjChB,aAAA;EA0Fc;;;;;;;;EAAA,SAhFL,cAAA,CAAe,UAAA,GAAa,cAAA;EAlBzB;;;;;;;;;;;;;EAAA,SAiCH,MAAA,CAAO,MAAA,EAAQ,UAAA;EAmCxB;;;;;;EAAA,SA3BS,GAAA,CAAA,GAAO,SAAA;EAgFF;;;;;;EAAA,SAxEL,UAAA,CAAA,GAAc,cAAA;EA2EtB;;;;;;;EAlED,OAAA,CAAA;EAiEY;;;;;AA8Bd;EArFE,MAAA,CAAA;;;;AAqGF;;EA5FE,WAAA,CAAA;EA6FyB;;;;;;;;EAxEzB,MAAA,CAAO,KAAA,EAAO,WAAA;AAAA;AAAA,iBAuBA,aAAA,YAAyB,MAAA,SAAe,WAAA,EAAA,CACtD,QAAA,EAAU,EAAA,EACV,UAAA,EAAY,kBAAA,GACX,EAAA;;;AAkEH;;;;;iBArCgB,eAAA,CAAgB,IAAA,UAAc,MAAA;;;;;;;;iBAgB9B,uBAAA,CACd,QAAA,EAAU,MAAA,SAAe,WAAA,GACzB,0BAAA,EAA4B,MAAA,6BAC3B,GAAA;AAAA,iBAkBa,gBAAA,WAAA,CACd,UAAA,EAAY,kBAAA,EACZ,QAAA,EAAU,MAAA,SAAe,WAAA,CAAY,SAAA,gBACrC,IAAA,UACA,OAAA;EACE,EAAA;EACA,kBAAA,GAAqB,GAAA;EACrB,eAAA,GAAkB,GAAA;EAClB,cAAA,IAAkB,OAAA;AAAA,IAEnB,UAAA;;;;;;;;;;;;AAqEH;iBAAsB,sBAAA,YACT,MAAA,SAAe,WAAA,EAAA,CAE1B,KAAA,EAAO,EAAA,EACP,UAAA,EAAY,kBAAA,EACZ,OAAA;EAAY,KAAA,GAAQ,mBAAA;EAAqB,MAAA,GAAS,cAAA;AAAA,IACjD,OAAA,CAAQ,EAAA"}
@@ -86,6 +86,14 @@ declare abstract class BaseChannel<ValueType = unknown, UpdateType = unknown, Ch
86
86
  equals(other: BaseChannel): boolean;
87
87
  }
88
88
  declare function emptyChannels<Cc extends Record<string, BaseChannel>>(channels: Cc, checkpoint: ReadonlyCheckpoint): Cc;
89
+ /**
90
+ * Synthetic task id for exit-mode DeltaChannel writes.
91
+ *
92
+ * Embeds the superstep in the first UUID group so `ORDER BY task_id, idx`
93
+ * preserves chronological order while remaining a valid RFC UUID (required by
94
+ * Postgres `checkpoint_writes.task_id uuid` columns).
95
+ */
96
+ declare function exitDeltaTaskId(step: number, taskId: string): string;
89
97
  /**
90
98
  * Return the set of {@link DeltaChannel} names that should snapshot now.
91
99
  *
@@ -117,5 +125,5 @@ declare function channelsFromCheckpoint<Cc extends Record<string, BaseChannel>>(
117
125
  config?: RunnableConfig;
118
126
  }): Promise<Cc>;
119
127
  //#endregion
120
- export { BaseChannel, channelsFromCheckpoint, createCheckpoint, deltaChannelsToSnapshot, emptyChannels, isDeltaChannel };
128
+ export { BaseChannel, channelsFromCheckpoint, createCheckpoint, deltaChannelsToSnapshot, emptyChannels, exitDeltaTaskId, isDeltaChannel };
121
129
  //# sourceMappingURL=base.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"base.d.ts","names":[],"sources":["../../src/channels/base.ts"],"mappings":";;;;;;AAgBA;;iBAAgB,cAAA,CAAe,OAAA,EAAS,WAAA;;uBASlB,WAAA;EAKpB,SAAA,EAAW,SAAA;EAEX,UAAA,EAAY,UAAA;EAFD;;;EAAA,SAOF,aAAA;EAoCO;EAjChB,aAAA;EA0Fc;;;;;;;;EAAA,SAhFL,cAAA,CAAe,UAAA,GAAa,cAAA;EAlBzB;;;;;;;;;;;;;EAAA,SAiCH,MAAA,CAAO,MAAA,EAAQ,UAAA;EAmCxB;;;;;;EAAA,SA3BS,GAAA,CAAA,GAAO,SAAA;EAgFF;;;;;;EAAA,SAxEL,UAAA,CAAA,GAAc,cAAA;EA2EtB;;;;;;;EAlED,OAAA,CAAA;EAiEY;;;;;AA8Bd;EArFE,MAAA,CAAA;;;;;;EASA,WAAA,CAAA;EA+EI;;;;;;;;EA1DJ,MAAA,CAAO,KAAA,EAAO,WAAA;AAAA;AAAA,iBAuBA,aAAA,YAAyB,MAAA,SAAe,WAAA,EAAA,CACtD,QAAA,EAAU,EAAA,EACV,UAAA,EAAY,kBAAA,GACX,EAAA;;;;;;;;iBA6Ba,uBAAA,CACd,QAAA,EAAU,MAAA,SAAe,WAAA,GACzB,0BAAA,EAA4B,MAAA,6BAC3B,GAAA;AAAA,iBAkBa,gBAAA,WAAA,CACd,UAAA,EAAY,kBAAA,EACZ,QAAA,EAAU,MAAA,SAAe,WAAA,CAAY,SAAA,gBACrC,IAAA,UACA,OAAA;EACE,EAAA;EACA,kBAAA,GAAqB,GAAA;EACrB,eAAA,GAAkB,GAAA;EAClB,cAAA,IAAkB,OAAA;AAAA,IAEnB,UAAA;;;;;;;;;;;;;iBAqEmB,sBAAA,YACT,MAAA,SAAe,WAAA,EAAA,CAE1B,KAAA,EAAO,EAAA,EACP,UAAA,EAAY,kBAAA,EACZ,OAAA;EAAY,KAAA,GAAQ,mBAAA;EAAqB,MAAA,GAAS,cAAA;AAAA,IACjD,OAAA,CAAQ,EAAA"}
1
+ {"version":3,"file":"base.d.ts","names":[],"sources":["../../src/channels/base.ts"],"mappings":";;;;;;AAoBA;;iBAAgB,cAAA,CAAe,OAAA,EAAS,WAAA;;uBASlB,WAAA;EAKpB,SAAA,EAAW,SAAA;EAEX,UAAA,EAAY,UAAA;EAFD;;;EAAA,SAOF,aAAA;EAoCO;EAjChB,aAAA;EA0Fc;;;;;;;;EAAA,SAhFL,cAAA,CAAe,UAAA,GAAa,cAAA;EAlBzB;;;;;;;;;;;;;EAAA,SAiCH,MAAA,CAAO,MAAA,EAAQ,UAAA;EAmCxB;;;;;;EAAA,SA3BS,GAAA,CAAA,GAAO,SAAA;EAgFF;;;;;;EAAA,SAxEL,UAAA,CAAA,GAAc,cAAA;EA2EtB;;;;;;;EAlED,OAAA,CAAA;EAiEY;;;;;AA8Bd;EArFE,MAAA,CAAA;;;;AAqGF;;EA5FE,WAAA,CAAA;EA6FyB;;;;;;;;EAxEzB,MAAA,CAAO,KAAA,EAAO,WAAA;AAAA;AAAA,iBAuBA,aAAA,YAAyB,MAAA,SAAe,WAAA,EAAA,CACtD,QAAA,EAAU,EAAA,EACV,UAAA,EAAY,kBAAA,GACX,EAAA;;;AAkEH;;;;;iBArCgB,eAAA,CAAgB,IAAA,UAAc,MAAA;;;;;;;;iBAgB9B,uBAAA,CACd,QAAA,EAAU,MAAA,SAAe,WAAA,GACzB,0BAAA,EAA4B,MAAA,6BAC3B,GAAA;AAAA,iBAkBa,gBAAA,WAAA,CACd,UAAA,EAAY,kBAAA,EACZ,QAAA,EAAU,MAAA,SAAe,WAAA,CAAY,SAAA,gBACrC,IAAA,UACA,OAAA;EACE,EAAA;EACA,kBAAA,GAAqB,GAAA;EACrB,eAAA,GAAkB,GAAA;EAClB,cAAA,IAAkB,OAAA;AAAA,IAEnB,UAAA;;;;;;;;;;;;AAqEH;iBAAsB,sBAAA,YACT,MAAA,SAAe,WAAA,EAAA,CAE1B,KAAA,EAAO,EAAA,EACP,UAAA,EAAY,kBAAA,EACZ,OAAA;EAAY,KAAA,GAAQ,mBAAA;EAAqB,MAAA,GAAS,cAAA;AAAA,IACjD,OAAA,CAAQ,EAAA"}
@@ -2,6 +2,8 @@ import { getDeltaMaxSuperstepsSinceSnapshot } from "../constants.js";
2
2
  import { EmptyChannelError } from "../errors.js";
3
3
  import { DeltaSnapshot, uuid6 } from "@langchain/langgraph-checkpoint";
4
4
  //#region src/channels/base.ts
5
+ /** Matches Postgres `uuid` / Python `uuid.UUID` (128-bit, 8-4-4-4-12 hex). */
6
+ const STRUCTURED_UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
5
7
  /**
6
8
  * Structural check for a {@link DeltaChannel} without importing it (avoids an
7
9
  * import cycle: `delta.ts` imports `base.ts`).
@@ -87,6 +89,18 @@ function emptyChannels(channels, checkpoint) {
87
89
  return newChannels;
88
90
  }
89
91
  /**
92
+ * Synthetic task id for exit-mode DeltaChannel writes.
93
+ *
94
+ * Embeds the superstep in the first UUID group so `ORDER BY task_id, idx`
95
+ * preserves chronological order while remaining a valid RFC UUID (required by
96
+ * Postgres `checkpoint_writes.task_id uuid` columns).
97
+ */
98
+ function exitDeltaTaskId(step, taskId) {
99
+ if (!STRUCTURED_UUID.test(taskId)) throw new TypeError(`Invalid task id for exit delta: ${taskId}`);
100
+ const parts = taskId.toLowerCase().split("-");
101
+ return `${String(step).padStart(8, "0")}-${parts[1]}-${parts[2]}-${parts[3]}-${parts[4]}`;
102
+ }
103
+ /**
90
104
  * Return the set of {@link DeltaChannel} names that should snapshot now.
91
105
  *
92
106
  * A channel snapshots when EITHER its accumulated update count reaches
@@ -175,6 +189,6 @@ async function channelsFromCheckpoint(specs, checkpoint, options) {
175
189
  return channels;
176
190
  }
177
191
  //#endregion
178
- export { BaseChannel, channelsFromCheckpoint, createCheckpoint, deltaChannelsToSnapshot, emptyChannels, getOnlyChannels, isBaseChannel, isDeltaChannel };
192
+ export { BaseChannel, channelsFromCheckpoint, createCheckpoint, deltaChannelsToSnapshot, emptyChannels, exitDeltaTaskId, getOnlyChannels, isBaseChannel, isDeltaChannel };
179
193
 
180
194
  //# sourceMappingURL=base.js.map
@@ -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 DeltaChannelHistory,\n} from \"@langchain/langgraph-checkpoint\";\nimport type { RunnableConfig } from \"@langchain/core/runnables\";\nimport { EmptyChannelError } from \"../errors.js\";\nimport { getDeltaMaxSuperstepsSinceSnapshot } from \"../constants.js\";\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 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 * 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`. Pure predicate — no mutation.\n */\nexport function deltaChannelsToSnapshot(\n channels: Record<string, BaseChannel>,\n countersSinceDeltaSnapshot: Record<string, [number, number]>\n): Set<string> {\n const result = new Set<string>();\n const maxSupersteps = getDeltaMaxSuperstepsSinceSnapshot();\n for (const name in channels) {\n if (!Object.prototype.hasOwnProperty.call(channels, name)) continue;\n const ch = channels[name];\n if (!isDeltaChannel(ch) || !ch.isAvailable()) continue;\n const [updates, supersteps] = countersSinceDeltaSnapshot[name] ?? [0, 0];\n if (\n updates >= (ch as DeltaChannelLike).snapshotFrequency ||\n supersteps >= maxSupersteps\n ) {\n result.add(name);\n }\n }\n return result;\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 updatedChannels?: Set<string>;\n getNextVersion?: (current: number | string | undefined) => number | string;\n }\n): Checkpoint {\n const channelsToSnapshot = options?.channelsToSnapshot ?? new Set<string>();\n const { updatedChannels, getNextVersion } = options ?? {};\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 // Snapshot a DeltaChannel: store the materialized value directly. In\n // exit/deferred modes the channel may have reached its snapshot\n // threshold over several supersteps without the LAST superstep\n // writing to it, so its version wouldn't be bumped by applyWrites —\n // bump it here so the saver includes the snapshot blob.\n if (\n getNextVersion !== undefined &&\n (updatedChannels === undefined || !updatedChannels.has(k))\n ) {\n channelVersions[k] = getNextVersion(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: checkpoint.versions_seen,\n };\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.\n */\nexport async function channelsFromCheckpoint<\n Cc extends Record<string, BaseChannel>,\n>(\n specs: Cc,\n checkpoint: ReadonlyCheckpoint,\n options?: { saver?: BaseCheckpointSaver; config?: RunnableConfig }\n): Promise<Cc> {\n const channels = emptyChannels(specs, checkpoint);\n const { saver, config } = options ?? {};\n\n const filteredSpecs = getOnlyChannels(specs);\n const deltaKeys: string[] = [];\n for (const k in filteredSpecs) {\n if (!Object.prototype.hasOwnProperty.call(filteredSpecs, k)) continue;\n if (\n isDeltaChannel(filteredSpecs[k]) &&\n !Object.prototype.hasOwnProperty.call(checkpoint.channel_values, k)\n ) {\n deltaKeys.push(k);\n }\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 DeltaChannelHistory,\n} from \"@langchain/langgraph-checkpoint\";\nimport type { RunnableConfig } from \"@langchain/core/runnables\";\nimport { EmptyChannelError } from \"../errors.js\";\nimport { getDeltaMaxSuperstepsSinceSnapshot } 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 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).\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 return `${stepPart}-${parts[1]}-${parts[2]}-${parts[3]}-${parts[4]}`;\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`. Pure predicate — no mutation.\n */\nexport function deltaChannelsToSnapshot(\n channels: Record<string, BaseChannel>,\n countersSinceDeltaSnapshot: Record<string, [number, number]>\n): Set<string> {\n const result = new Set<string>();\n const maxSupersteps = getDeltaMaxSuperstepsSinceSnapshot();\n for (const name in channels) {\n if (!Object.prototype.hasOwnProperty.call(channels, name)) continue;\n const ch = channels[name];\n if (!isDeltaChannel(ch) || !ch.isAvailable()) continue;\n const [updates, supersteps] = countersSinceDeltaSnapshot[name] ?? [0, 0];\n if (\n updates >= (ch as DeltaChannelLike).snapshotFrequency ||\n supersteps >= maxSupersteps\n ) {\n result.add(name);\n }\n }\n return result;\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 updatedChannels?: Set<string>;\n getNextVersion?: (current: number | string | undefined) => number | string;\n }\n): Checkpoint {\n const channelsToSnapshot = options?.channelsToSnapshot ?? new Set<string>();\n const { updatedChannels, getNextVersion } = options ?? {};\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 // Snapshot a DeltaChannel: store the materialized value directly. In\n // exit/deferred modes the channel may have reached its snapshot\n // threshold over several supersteps without the LAST superstep\n // writing to it, so its version wouldn't be bumped by applyWrites —\n // bump it here so the saver includes the snapshot blob.\n if (\n getNextVersion !== undefined &&\n (updatedChannels === undefined || !updatedChannels.has(k))\n ) {\n channelVersions[k] = getNextVersion(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: checkpoint.versions_seen,\n };\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.\n */\nexport async function channelsFromCheckpoint<\n Cc extends Record<string, BaseChannel>,\n>(\n specs: Cc,\n checkpoint: ReadonlyCheckpoint,\n options?: { saver?: BaseCheckpointSaver; config?: RunnableConfig }\n): Promise<Cc> {\n const channels = emptyChannels(specs, checkpoint);\n const { saver, config } = options ?? {};\n\n const filteredSpecs = getOnlyChannels(specs);\n const deltaKeys: string[] = [];\n for (const k in filteredSpecs) {\n if (!Object.prototype.hasOwnProperty.call(filteredSpecs, k)) continue;\n if (\n isDeltaChannel(filteredSpecs[k]) &&\n !Object.prototype.hasOwnProperty.call(checkpoint.channel_values, k)\n ) {\n deltaKeys.push(k);\n }\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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"}
@@ -25,4 +25,5 @@ exports.channelsFromCheckpoint = require_base.channelsFromCheckpoint;
25
25
  exports.createCheckpoint = require_base.createCheckpoint;
26
26
  exports.deltaChannelsToSnapshot = require_base.deltaChannelsToSnapshot;
27
27
  exports.empty = require_base.emptyChannels;
28
+ exports.exitDeltaTaskId = require_base.exitDeltaTaskId;
28
29
  exports.isDeltaChannel = require_base.isDeltaChannel;
@@ -1,4 +1,4 @@
1
- import { BaseChannel, channelsFromCheckpoint, createCheckpoint, deltaChannelsToSnapshot, emptyChannels, isDeltaChannel } from "./base.cjs";
1
+ import { BaseChannel, channelsFromCheckpoint, createCheckpoint, deltaChannelsToSnapshot, emptyChannels, exitDeltaTaskId, isDeltaChannel } from "./base.cjs";
2
2
  import { DeltaChannel, DeltaReducer } from "./delta.cjs";
3
3
  import { BinaryOperator, BinaryOperatorAggregate } from "./binop.cjs";
4
4
  import { AnyValue } from "./any_value.cjs";
@@ -8,4 +8,4 @@ import { EphemeralValue } from "./ephemeral_value.cjs";
8
8
  import { NamedBarrierValue, NamedBarrierValueAfterFinish } from "./named_barrier_value.cjs";
9
9
  import { Topic } from "./topic.cjs";
10
10
  import { UntrackedValueChannel } from "./untracked_value.cjs";
11
- export { AnyValue, BaseChannel, type BinaryOperator, BinaryOperatorAggregate, DeltaChannel, type DeltaReducer, DynamicBarrierValue, EphemeralValue, LastValue, LastValueAfterFinish, NamedBarrierValue, NamedBarrierValueAfterFinish, Topic, UntrackedValueChannel, type WaitForNames, channelsFromCheckpoint, createCheckpoint, deltaChannelsToSnapshot, emptyChannels as empty, isDeltaChannel };
11
+ export { AnyValue, BaseChannel, type BinaryOperator, BinaryOperatorAggregate, DeltaChannel, type DeltaReducer, DynamicBarrierValue, EphemeralValue, LastValue, LastValueAfterFinish, NamedBarrierValue, NamedBarrierValueAfterFinish, Topic, UntrackedValueChannel, type WaitForNames, channelsFromCheckpoint, createCheckpoint, deltaChannelsToSnapshot, emptyChannels as empty, exitDeltaTaskId, isDeltaChannel };
@@ -1,4 +1,4 @@
1
- import { BaseChannel, channelsFromCheckpoint, createCheckpoint, deltaChannelsToSnapshot, emptyChannels, isDeltaChannel } from "./base.js";
1
+ import { BaseChannel, channelsFromCheckpoint, createCheckpoint, deltaChannelsToSnapshot, emptyChannels, exitDeltaTaskId, isDeltaChannel } from "./base.js";
2
2
  import { DeltaChannel, DeltaReducer } from "./delta.js";
3
3
  import { BinaryOperator, BinaryOperatorAggregate } from "./binop.js";
4
4
  import { AnyValue } from "./any_value.js";
@@ -8,4 +8,4 @@ import { EphemeralValue } from "./ephemeral_value.js";
8
8
  import { NamedBarrierValue, NamedBarrierValueAfterFinish } from "./named_barrier_value.js";
9
9
  import { Topic } from "./topic.js";
10
10
  import { UntrackedValueChannel } from "./untracked_value.js";
11
- export { AnyValue, BaseChannel, type BinaryOperator, BinaryOperatorAggregate, DeltaChannel, type DeltaReducer, DynamicBarrierValue, EphemeralValue, LastValue, LastValueAfterFinish, NamedBarrierValue, NamedBarrierValueAfterFinish, Topic, UntrackedValueChannel, type WaitForNames, channelsFromCheckpoint, createCheckpoint, deltaChannelsToSnapshot, emptyChannels as empty, isDeltaChannel };
11
+ export { AnyValue, BaseChannel, type BinaryOperator, BinaryOperatorAggregate, DeltaChannel, type DeltaReducer, DynamicBarrierValue, EphemeralValue, LastValue, LastValueAfterFinish, NamedBarrierValue, NamedBarrierValueAfterFinish, Topic, UntrackedValueChannel, type WaitForNames, channelsFromCheckpoint, createCheckpoint, deltaChannelsToSnapshot, emptyChannels as empty, exitDeltaTaskId, isDeltaChannel };
@@ -1,4 +1,4 @@
1
- import { BaseChannel, channelsFromCheckpoint, createCheckpoint, deltaChannelsToSnapshot, emptyChannels, isDeltaChannel } from "./base.js";
1
+ import { BaseChannel, channelsFromCheckpoint, createCheckpoint, deltaChannelsToSnapshot, emptyChannels, exitDeltaTaskId, isDeltaChannel } from "./base.js";
2
2
  import { BinaryOperatorAggregate } from "./binop.js";
3
3
  import { LastValue, LastValueAfterFinish } from "./last_value.js";
4
4
  import { Topic } from "./topic.js";
@@ -8,4 +8,4 @@ import { DeltaChannel } from "./delta.js";
8
8
  import { AnyValue } from "./any_value.js";
9
9
  import { DynamicBarrierValue } from "./dynamic_barrier_value.js";
10
10
  import { UntrackedValueChannel } from "./untracked_value.js";
11
- export { AnyValue, BaseChannel, BinaryOperatorAggregate, DeltaChannel, DynamicBarrierValue, EphemeralValue, LastValue, LastValueAfterFinish, NamedBarrierValue, NamedBarrierValueAfterFinish, Topic, UntrackedValueChannel, channelsFromCheckpoint, createCheckpoint, deltaChannelsToSnapshot, emptyChannels as empty, isDeltaChannel };
11
+ export { AnyValue, BaseChannel, BinaryOperatorAggregate, DeltaChannel, DynamicBarrierValue, EphemeralValue, LastValue, LastValueAfterFinish, NamedBarrierValue, NamedBarrierValueAfterFinish, Topic, UntrackedValueChannel, channelsFromCheckpoint, createCheckpoint, deltaChannelsToSnapshot, emptyChannels as empty, exitDeltaTaskId, isDeltaChannel };
@@ -908,7 +908,7 @@ var PregelLoop = class PregelLoop {
908
908
  group.push([ch, v]);
909
909
  }
910
910
  for (const { key, step, tid } of order) {
911
- const synthTid = `${String(step).padStart(8, "0")}-${tid}`;
911
+ const synthTid = require_base.exitDeltaTaskId(step, tid);
912
912
  this._trackCheckpointerPromise(this.checkpointer.putWrites(anchorWriteConfig, grouped.get(key), synthTid));
913
913
  }
914
914
  }