@langchain/langgraph 1.5.1 → 1.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/channels/delta.cjs +1 -1
- package/dist/channels/delta.cjs.map +1 -1
- package/dist/channels/delta.js +1 -1
- package/dist/channels/delta.js.map +1 -1
- package/dist/state/values/delta.cjs.map +1 -1
- package/dist/state/values/delta.d.cts +2 -2
- package/dist/state/values/delta.d.ts +2 -2
- package/dist/state/values/delta.js.map +1 -1
- package/package.json +8 -8
package/dist/channels/delta.cjs
CHANGED
|
@@ -50,7 +50,7 @@ var DeltaChannel = class DeltaChannel extends require_base.BaseChannel {
|
|
|
50
50
|
initialValueFactory;
|
|
51
51
|
constructor(reducer, options) {
|
|
52
52
|
super();
|
|
53
|
-
const snapshotFrequency = options?.snapshotFrequency ??
|
|
53
|
+
const snapshotFrequency = options?.snapshotFrequency ?? 100;
|
|
54
54
|
if (!Number.isInteger(snapshotFrequency) || snapshotFrequency <= 0) throw new Error(`snapshotFrequency must be a positive integer, got ${snapshotFrequency}`);
|
|
55
55
|
this.reducer = reducer;
|
|
56
56
|
this.snapshotFrequency = snapshotFrequency;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delta.cjs","names":["BaseChannel","_getOverwriteValue","_isOverwriteValue","InvalidUpdateError","EmptyChannelError"],"sources":["../../src/channels/delta.ts"],"sourcesContent":["import {\n type CheckpointPendingWrite,\n DeltaSnapshot,\n isDeltaSnapshot,\n} 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\n/**\n * A batch reducer for use with {@link DeltaChannel}.\n *\n * Receives the current accumulated value and a batch of writes in one call,\n * returning the new accumulated value:\n * `reducer(state, [write1, write2, ...]) -> newState`.\n *\n * Reducers must be deterministic and batching-invariant (associative across\n * folds): applying two consecutive write batches separately must produce the\n * same state as applying their concatenation once:\n *\n * ```text\n * reducer(reducer(state, xs), ys) === reducer(state, xs.concat(ys))\n * ```\n *\n * This lets LangGraph replay checkpointed writes in larger batches than they\n * were originally produced without changing reconstructed state. If your\n * reducer is not associative, use {@link BinaryOperatorAggregate} instead —\n * `DeltaChannel` is not a drop-in replacement for every reducer.\n */\nexport type DeltaReducer<ValueType, UpdateType = unknown> = (\n state: ValueType,\n writes: UpdateType[]\n) => ValueType;\n\ntype OverwriteOrValue<ValueType, UpdateType> =\n | OverwriteValue<ValueType>\n | UpdateType;\n\nconst isDeltaChannel = (\n value: BaseChannel\n): value is DeltaChannel<unknown, unknown> => {\n return value != null && value.lc_graph_name === \"DeltaChannel\";\n};\n\n/**\n * Reducer channel that stores only a sentinel in checkpoint blobs and\n * reconstructs state by replaying ancestor writes through the reducer.\n *\n * `DeltaChannel` avoids re-serializing the full accumulated value at every\n * step. Instead of writing the value into `channel_values`, the channel is\n * omitted entirely and its state is reconstructed on read by walking the\n * ancestor chain and replaying the per-step writes through the reducer (see\n * {@link BaseCheckpointSaver.getDeltaChannelHistory}).\n *\n * Snapshot cadence is driven by two counters: a per-channel update count and\n * the total supersteps since the last snapshot. A full {@link DeltaSnapshot}\n * blob is written when EITHER the update count reaches `snapshotFrequency` OR\n * the supersteps count reaches the system-wide\n * `DELTA_MAX_SUPERSTEPS_SINCE_SNAPSHOT` bound (default 5000), bounding replay\n * depth even for channels that stop receiving writes.\n *\n * @remarks Beta. The API and on-disk representation may change in future\n * releases. Threads written with `DeltaChannel` today are expected to remain\n * readable, but the surrounding contract (`getDeltaChannelHistory`, the\n * `DeltaSnapshot` blob shape, the `counters_since_delta_snapshot` metadata\n * field) is not yet stable.\n *\n * @example\n * ```typescript\n * import { Annotation } from \"@langchain/langgraph\";\n * import { DeltaChannel, messagesDeltaReducer } from \"@langchain/langgraph\";\n *\n * const State = Annotation.Root({\n * messages: Annotation<BaseMessage[]>({\n * reducer: () => [], // ignored; DeltaChannel is supplied below\n * }),\n * });\n * ```\n */\nexport class DeltaChannel<\n ValueType = unknown,\n UpdateType = unknown,\n> extends BaseChannel<\n ValueType,\n OverwriteOrValue<ValueType, UpdateType>,\n undefined\n> {\n lc_graph_name = \"DeltaChannel\";\n\n /** `undefined` represents the Python `MISSING` sentinel (empty channel). */\n value: ValueType | undefined;\n\n reducer: DeltaReducer<ValueType, UpdateType>;\n\n snapshotFrequency: number;\n\n initialValueFactory: () => ValueType;\n\n constructor(\n reducer: DeltaReducer<ValueType, UpdateType>,\n options?: {\n snapshotFrequency?: number;\n initialValueFactory?: () => ValueType;\n }\n ) {\n super();\n const snapshotFrequency = options?.snapshotFrequency ?? 1000;\n if (!Number.isInteger(snapshotFrequency) || snapshotFrequency <= 0) {\n throw new Error(\n `snapshotFrequency must be a positive integer, got ${snapshotFrequency}`\n );\n }\n this.reducer = reducer;\n this.snapshotFrequency = snapshotFrequency;\n this.initialValueFactory =\n options?.initialValueFactory ?? (() => [] as ValueType);\n this.value = undefined;\n }\n\n public fromCheckpoint(checkpoint?: undefined | DeltaSnapshot | ValueType) {\n const empty = new DeltaChannel<ValueType, UpdateType>(this.reducer, {\n snapshotFrequency: this.snapshotFrequency,\n initialValueFactory: this.initialValueFactory,\n });\n if (checkpoint === undefined) {\n empty.value = this.initialValueFactory();\n } else if (isDeltaSnapshot(checkpoint)) {\n empty.value = checkpoint.value as ValueType;\n } else {\n empty.value = checkpoint as ValueType;\n }\n return empty as this;\n }\n\n /**\n * Apply ancestor writes oldest-to-newest via a single reducer call.\n *\n * If any write is an Overwrite, the last one in the sequence acts as the\n * reset point: its value becomes the new base and only writes after it are\n * passed to the reducer.\n */\n public replayWrites(writes: CheckpointPendingWrite[]): void {\n const values = writes.map((w) => w[2]);\n if (values.length === 0) return;\n let base = this.value as ValueType;\n let start = 0;\n for (let i = 0; i < values.length; i += 1) {\n const [isOverwrite, overwriteValue] = _getOverwriteValue<ValueType>(\n values[i]\n );\n if (isOverwrite) {\n base =\n overwriteValue !== undefined && overwriteValue !== null\n ? overwriteValue\n : this.initialValueFactory();\n start = i + 1;\n }\n }\n const remaining = values.slice(start) as UpdateType[];\n this.value = remaining.length > 0 ? this.reducer(base, remaining) : base;\n }\n\n public update(values: OverwriteOrValue<ValueType, UpdateType>[]): boolean {\n if (values.length === 0) return false;\n\n let overwriteValue: ValueType | undefined;\n let hasOverwrite = false;\n for (const value of values) {\n if (_isOverwriteValue<ValueType>(value)) {\n if (hasOverwrite) {\n throw new InvalidUpdateError(\n \"Can receive only one Overwrite value per step.\"\n );\n }\n hasOverwrite = true;\n [, overwriteValue] = _getOverwriteValue<ValueType>(value);\n }\n }\n\n if (hasOverwrite) {\n // An Overwrite wins the entire super-step: every sibling write (before\n // AND after) is discarded, mirroring `BinaryOperatorAggregate` — hence\n // only one Overwrite per step. The loop force-snapshots channels that saw\n // an Overwrite, so reconstruction seeds from this value without replaying.\n this.value =\n overwriteValue !== undefined && overwriteValue !== null\n ? overwriteValue\n : this.initialValueFactory();\n return true;\n }\n\n const base =\n this.value === undefined ? this.initialValueFactory() : this.value;\n this.value = this.reducer(base, values as UpdateType[]);\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 /**\n * Always returns `undefined` (the Python `MISSING` sentinel). Snapshot\n * decisions live in `createCheckpoint`, which has the channel version and\n * writes a {@link DeltaSnapshot} directly into `channel_values`. For\n * non-snapshot steps the channel does not appear in `channel_values`;\n * reconstruction walks ancestor writes via the saver's\n * `getDeltaChannelHistory`.\n */\n public checkpoint(): undefined {\n return undefined;\n }\n\n isAvailable(): boolean {\n return this.value !== undefined;\n }\n\n equals(other: BaseChannel): boolean {\n if (this === other) return true;\n if (!isDeltaChannel(other)) return false;\n if (this.snapshotFrequency !== other.snapshotFrequency) return false;\n return this.reducer === other.reducer;\n }\n}\n"],"mappings":";;;;;AA0CA,MAAM,kBACJ,UAC4C;AAC5C,QAAO,SAAS,QAAQ,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsClD,IAAa,eAAb,MAAa,qBAGHA,aAAAA,YAIR;CACA,gBAAgB;;CAGhB;CAEA;CAEA;CAEA;CAEA,YACE,SACA,SAIA;AACA,SAAO;EACP,MAAM,oBAAoB,SAAS,qBAAqB;AACxD,MAAI,CAAC,OAAO,UAAU,kBAAkB,IAAI,qBAAqB,EAC/D,OAAM,IAAI,MACR,qDAAqD,oBACtD;AAEH,OAAK,UAAU;AACf,OAAK,oBAAoB;AACzB,OAAK,sBACH,SAAS,8BAA8B,EAAE;AAC3C,OAAK,QAAQ,KAAA;;CAGf,eAAsB,YAAoD;EACxE,MAAM,QAAQ,IAAI,aAAoC,KAAK,SAAS;GAClE,mBAAmB,KAAK;GACxB,qBAAqB,KAAK;GAC3B,CAAC;AACF,MAAI,eAAe,KAAA,EACjB,OAAM,QAAQ,KAAK,qBAAqB;gEACf,WAAW,CACpC,OAAM,QAAQ,WAAW;MAEzB,OAAM,QAAQ;AAEhB,SAAO;;;;;;;;;CAUT,aAAoB,QAAwC;EAC1D,MAAM,SAAS,OAAO,KAAK,MAAM,EAAE,GAAG;AACtC,MAAI,OAAO,WAAW,EAAG;EACzB,IAAI,OAAO,KAAK;EAChB,IAAI,QAAQ;AACZ,OAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK,GAAG;GACzC,MAAM,CAAC,aAAa,kBAAkBC,kBAAAA,mBACpC,OAAO,GACR;AACD,OAAI,aAAa;AACf,WACE,mBAAmB,KAAA,KAAa,mBAAmB,OAC/C,iBACA,KAAK,qBAAqB;AAChC,YAAQ,IAAI;;;EAGhB,MAAM,YAAY,OAAO,MAAM,MAAM;AACrC,OAAK,QAAQ,UAAU,SAAS,IAAI,KAAK,QAAQ,MAAM,UAAU,GAAG;;CAGtE,OAAc,QAA4D;AACxE,MAAI,OAAO,WAAW,EAAG,QAAO;EAEhC,IAAI;EACJ,IAAI,eAAe;AACnB,OAAK,MAAM,SAAS,OAClB,KAAIC,kBAAAA,kBAA6B,MAAM,EAAE;AACvC,OAAI,aACF,OAAM,IAAIC,eAAAA,mBACR,iDACD;AAEH,kBAAe;AACf,MAAG,kBAAkBF,kBAAAA,mBAA8B,MAAM;;AAI7D,MAAI,cAAc;AAKhB,QAAK,QACH,mBAAmB,KAAA,KAAa,mBAAmB,OAC/C,iBACA,KAAK,qBAAqB;AAChC,UAAO;;EAGT,MAAM,OACJ,KAAK,UAAU,KAAA,IAAY,KAAK,qBAAqB,GAAG,KAAK;AAC/D,OAAK,QAAQ,KAAK,QAAQ,MAAM,OAAuB;AACvD,SAAO;;CAGT,MAAwB;AACtB,MAAI,KAAK,UAAU,KAAA,EACjB,OAAM,IAAIG,eAAAA,mBAAmB;AAE/B,SAAO,KAAK;;;;;;;;;;CAWd,aAA+B;CAI/B,cAAuB;AACrB,SAAO,KAAK,UAAU,KAAA;;CAGxB,OAAO,OAA6B;AAClC,MAAI,SAAS,MAAO,QAAO;AAC3B,MAAI,CAAC,eAAe,MAAM,CAAE,QAAO;AACnC,MAAI,KAAK,sBAAsB,MAAM,kBAAmB,QAAO;AAC/D,SAAO,KAAK,YAAY,MAAM"}
|
|
1
|
+
{"version":3,"file":"delta.cjs","names":["BaseChannel","_getOverwriteValue","_isOverwriteValue","InvalidUpdateError","EmptyChannelError"],"sources":["../../src/channels/delta.ts"],"sourcesContent":["import {\n type CheckpointPendingWrite,\n DeltaSnapshot,\n isDeltaSnapshot,\n} 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\n/**\n * A batch reducer for use with {@link DeltaChannel}.\n *\n * Receives the current accumulated value and a batch of writes in one call,\n * returning the new accumulated value:\n * `reducer(state, [write1, write2, ...]) -> newState`.\n *\n * Reducers must be deterministic and batching-invariant (associative across\n * folds): applying two consecutive write batches separately must produce the\n * same state as applying their concatenation once:\n *\n * ```text\n * reducer(reducer(state, xs), ys) === reducer(state, xs.concat(ys))\n * ```\n *\n * This lets LangGraph replay checkpointed writes in larger batches than they\n * were originally produced without changing reconstructed state. If your\n * reducer is not associative, use {@link BinaryOperatorAggregate} instead —\n * `DeltaChannel` is not a drop-in replacement for every reducer.\n */\nexport type DeltaReducer<ValueType, UpdateType = unknown> = (\n state: ValueType,\n writes: UpdateType[]\n) => ValueType;\n\ntype OverwriteOrValue<ValueType, UpdateType> =\n | OverwriteValue<ValueType>\n | UpdateType;\n\nconst isDeltaChannel = (\n value: BaseChannel\n): value is DeltaChannel<unknown, unknown> => {\n return value != null && value.lc_graph_name === \"DeltaChannel\";\n};\n\n/**\n * Reducer channel that stores only a sentinel in checkpoint blobs and\n * reconstructs state by replaying ancestor writes through the reducer.\n *\n * `DeltaChannel` avoids re-serializing the full accumulated value at every\n * step. Instead of writing the value into `channel_values`, the channel is\n * omitted entirely and its state is reconstructed on read by walking the\n * ancestor chain and replaying the per-step writes through the reducer (see\n * {@link BaseCheckpointSaver.getDeltaChannelHistory}).\n *\n * Snapshot cadence is driven by two counters: a per-channel update count and\n * the total supersteps since the last snapshot. A full {@link DeltaSnapshot}\n * blob is written when EITHER the update count reaches `snapshotFrequency` OR\n * the supersteps count reaches the system-wide\n * `DELTA_MAX_SUPERSTEPS_SINCE_SNAPSHOT` bound (default 5000), bounding replay\n * depth even for channels that stop receiving writes.\n *\n * @remarks Beta. The API and on-disk representation may change in future\n * releases. Threads written with `DeltaChannel` today are expected to remain\n * readable, but the surrounding contract (`getDeltaChannelHistory`, the\n * `DeltaSnapshot` blob shape, the `counters_since_delta_snapshot` metadata\n * field) is not yet stable.\n *\n * @example\n * ```typescript\n * import { Annotation } from \"@langchain/langgraph\";\n * import { DeltaChannel, messagesDeltaReducer } from \"@langchain/langgraph\";\n *\n * const State = Annotation.Root({\n * messages: Annotation<BaseMessage[]>({\n * reducer: () => [], // ignored; DeltaChannel is supplied below\n * }),\n * });\n * ```\n */\nexport class DeltaChannel<\n ValueType = unknown,\n UpdateType = unknown,\n> extends BaseChannel<\n ValueType,\n OverwriteOrValue<ValueType, UpdateType>,\n undefined\n> {\n lc_graph_name = \"DeltaChannel\";\n\n /** `undefined` represents the Python `MISSING` sentinel (empty channel). */\n value: ValueType | undefined;\n\n reducer: DeltaReducer<ValueType, UpdateType>;\n\n snapshotFrequency: number;\n\n initialValueFactory: () => ValueType;\n\n constructor(\n reducer: DeltaReducer<ValueType, UpdateType>,\n options?: {\n snapshotFrequency?: number;\n initialValueFactory?: () => ValueType;\n }\n ) {\n super();\n const snapshotFrequency = options?.snapshotFrequency ?? 100;\n if (!Number.isInteger(snapshotFrequency) || snapshotFrequency <= 0) {\n throw new Error(\n `snapshotFrequency must be a positive integer, got ${snapshotFrequency}`\n );\n }\n this.reducer = reducer;\n this.snapshotFrequency = snapshotFrequency;\n this.initialValueFactory =\n options?.initialValueFactory ?? (() => [] as ValueType);\n this.value = undefined;\n }\n\n public fromCheckpoint(checkpoint?: undefined | DeltaSnapshot | ValueType) {\n const empty = new DeltaChannel<ValueType, UpdateType>(this.reducer, {\n snapshotFrequency: this.snapshotFrequency,\n initialValueFactory: this.initialValueFactory,\n });\n if (checkpoint === undefined) {\n empty.value = this.initialValueFactory();\n } else if (isDeltaSnapshot(checkpoint)) {\n empty.value = checkpoint.value as ValueType;\n } else {\n empty.value = checkpoint as ValueType;\n }\n return empty as this;\n }\n\n /**\n * Apply ancestor writes oldest-to-newest via a single reducer call.\n *\n * If any write is an Overwrite, the last one in the sequence acts as the\n * reset point: its value becomes the new base and only writes after it are\n * passed to the reducer.\n */\n public replayWrites(writes: CheckpointPendingWrite[]): void {\n const values = writes.map((w) => w[2]);\n if (values.length === 0) return;\n let base = this.value as ValueType;\n let start = 0;\n for (let i = 0; i < values.length; i += 1) {\n const [isOverwrite, overwriteValue] = _getOverwriteValue<ValueType>(\n values[i]\n );\n if (isOverwrite) {\n base =\n overwriteValue !== undefined && overwriteValue !== null\n ? overwriteValue\n : this.initialValueFactory();\n start = i + 1;\n }\n }\n const remaining = values.slice(start) as UpdateType[];\n this.value = remaining.length > 0 ? this.reducer(base, remaining) : base;\n }\n\n public update(values: OverwriteOrValue<ValueType, UpdateType>[]): boolean {\n if (values.length === 0) return false;\n\n let overwriteValue: ValueType | undefined;\n let hasOverwrite = false;\n for (const value of values) {\n if (_isOverwriteValue<ValueType>(value)) {\n if (hasOverwrite) {\n throw new InvalidUpdateError(\n \"Can receive only one Overwrite value per step.\"\n );\n }\n hasOverwrite = true;\n [, overwriteValue] = _getOverwriteValue<ValueType>(value);\n }\n }\n\n if (hasOverwrite) {\n // An Overwrite wins the entire super-step: every sibling write (before\n // AND after) is discarded, mirroring `BinaryOperatorAggregate` — hence\n // only one Overwrite per step. The loop force-snapshots channels that saw\n // an Overwrite, so reconstruction seeds from this value without replaying.\n this.value =\n overwriteValue !== undefined && overwriteValue !== null\n ? overwriteValue\n : this.initialValueFactory();\n return true;\n }\n\n const base =\n this.value === undefined ? this.initialValueFactory() : this.value;\n this.value = this.reducer(base, values as UpdateType[]);\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 /**\n * Always returns `undefined` (the Python `MISSING` sentinel). Snapshot\n * decisions live in `createCheckpoint`, which has the channel version and\n * writes a {@link DeltaSnapshot} directly into `channel_values`. For\n * non-snapshot steps the channel does not appear in `channel_values`;\n * reconstruction walks ancestor writes via the saver's\n * `getDeltaChannelHistory`.\n */\n public checkpoint(): undefined {\n return undefined;\n }\n\n isAvailable(): boolean {\n return this.value !== undefined;\n }\n\n equals(other: BaseChannel): boolean {\n if (this === other) return true;\n if (!isDeltaChannel(other)) return false;\n if (this.snapshotFrequency !== other.snapshotFrequency) return false;\n return this.reducer === other.reducer;\n }\n}\n"],"mappings":";;;;;AA0CA,MAAM,kBACJ,UAC4C;AAC5C,QAAO,SAAS,QAAQ,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsClD,IAAa,eAAb,MAAa,qBAGHA,aAAAA,YAIR;CACA,gBAAgB;;CAGhB;CAEA;CAEA;CAEA;CAEA,YACE,SACA,SAIA;AACA,SAAO;EACP,MAAM,oBAAoB,SAAS,qBAAqB;AACxD,MAAI,CAAC,OAAO,UAAU,kBAAkB,IAAI,qBAAqB,EAC/D,OAAM,IAAI,MACR,qDAAqD,oBACtD;AAEH,OAAK,UAAU;AACf,OAAK,oBAAoB;AACzB,OAAK,sBACH,SAAS,8BAA8B,EAAE;AAC3C,OAAK,QAAQ,KAAA;;CAGf,eAAsB,YAAoD;EACxE,MAAM,QAAQ,IAAI,aAAoC,KAAK,SAAS;GAClE,mBAAmB,KAAK;GACxB,qBAAqB,KAAK;GAC3B,CAAC;AACF,MAAI,eAAe,KAAA,EACjB,OAAM,QAAQ,KAAK,qBAAqB;gEACf,WAAW,CACpC,OAAM,QAAQ,WAAW;MAEzB,OAAM,QAAQ;AAEhB,SAAO;;;;;;;;;CAUT,aAAoB,QAAwC;EAC1D,MAAM,SAAS,OAAO,KAAK,MAAM,EAAE,GAAG;AACtC,MAAI,OAAO,WAAW,EAAG;EACzB,IAAI,OAAO,KAAK;EAChB,IAAI,QAAQ;AACZ,OAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK,GAAG;GACzC,MAAM,CAAC,aAAa,kBAAkBC,kBAAAA,mBACpC,OAAO,GACR;AACD,OAAI,aAAa;AACf,WACE,mBAAmB,KAAA,KAAa,mBAAmB,OAC/C,iBACA,KAAK,qBAAqB;AAChC,YAAQ,IAAI;;;EAGhB,MAAM,YAAY,OAAO,MAAM,MAAM;AACrC,OAAK,QAAQ,UAAU,SAAS,IAAI,KAAK,QAAQ,MAAM,UAAU,GAAG;;CAGtE,OAAc,QAA4D;AACxE,MAAI,OAAO,WAAW,EAAG,QAAO;EAEhC,IAAI;EACJ,IAAI,eAAe;AACnB,OAAK,MAAM,SAAS,OAClB,KAAIC,kBAAAA,kBAA6B,MAAM,EAAE;AACvC,OAAI,aACF,OAAM,IAAIC,eAAAA,mBACR,iDACD;AAEH,kBAAe;AACf,MAAG,kBAAkBF,kBAAAA,mBAA8B,MAAM;;AAI7D,MAAI,cAAc;AAKhB,QAAK,QACH,mBAAmB,KAAA,KAAa,mBAAmB,OAC/C,iBACA,KAAK,qBAAqB;AAChC,UAAO;;EAGT,MAAM,OACJ,KAAK,UAAU,KAAA,IAAY,KAAK,qBAAqB,GAAG,KAAK;AAC/D,OAAK,QAAQ,KAAK,QAAQ,MAAM,OAAuB;AACvD,SAAO;;CAGT,MAAwB;AACtB,MAAI,KAAK,UAAU,KAAA,EACjB,OAAM,IAAIG,eAAAA,mBAAmB;AAE/B,SAAO,KAAK;;;;;;;;;;CAWd,aAA+B;CAI/B,cAAuB;AACrB,SAAO,KAAK,UAAU,KAAA;;CAGxB,OAAO,OAA6B;AAClC,MAAI,SAAS,MAAO,QAAO;AAC3B,MAAI,CAAC,eAAe,MAAM,CAAE,QAAO;AACnC,MAAI,KAAK,sBAAsB,MAAM,kBAAmB,QAAO;AAC/D,SAAO,KAAK,YAAY,MAAM"}
|
package/dist/channels/delta.js
CHANGED
|
@@ -50,7 +50,7 @@ var DeltaChannel = class DeltaChannel extends BaseChannel {
|
|
|
50
50
|
initialValueFactory;
|
|
51
51
|
constructor(reducer, options) {
|
|
52
52
|
super();
|
|
53
|
-
const snapshotFrequency = options?.snapshotFrequency ??
|
|
53
|
+
const snapshotFrequency = options?.snapshotFrequency ?? 100;
|
|
54
54
|
if (!Number.isInteger(snapshotFrequency) || snapshotFrequency <= 0) throw new Error(`snapshotFrequency must be a positive integer, got ${snapshotFrequency}`);
|
|
55
55
|
this.reducer = reducer;
|
|
56
56
|
this.snapshotFrequency = snapshotFrequency;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delta.js","names":[],"sources":["../../src/channels/delta.ts"],"sourcesContent":["import {\n type CheckpointPendingWrite,\n DeltaSnapshot,\n isDeltaSnapshot,\n} 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\n/**\n * A batch reducer for use with {@link DeltaChannel}.\n *\n * Receives the current accumulated value and a batch of writes in one call,\n * returning the new accumulated value:\n * `reducer(state, [write1, write2, ...]) -> newState`.\n *\n * Reducers must be deterministic and batching-invariant (associative across\n * folds): applying two consecutive write batches separately must produce the\n * same state as applying their concatenation once:\n *\n * ```text\n * reducer(reducer(state, xs), ys) === reducer(state, xs.concat(ys))\n * ```\n *\n * This lets LangGraph replay checkpointed writes in larger batches than they\n * were originally produced without changing reconstructed state. If your\n * reducer is not associative, use {@link BinaryOperatorAggregate} instead —\n * `DeltaChannel` is not a drop-in replacement for every reducer.\n */\nexport type DeltaReducer<ValueType, UpdateType = unknown> = (\n state: ValueType,\n writes: UpdateType[]\n) => ValueType;\n\ntype OverwriteOrValue<ValueType, UpdateType> =\n | OverwriteValue<ValueType>\n | UpdateType;\n\nconst isDeltaChannel = (\n value: BaseChannel\n): value is DeltaChannel<unknown, unknown> => {\n return value != null && value.lc_graph_name === \"DeltaChannel\";\n};\n\n/**\n * Reducer channel that stores only a sentinel in checkpoint blobs and\n * reconstructs state by replaying ancestor writes through the reducer.\n *\n * `DeltaChannel` avoids re-serializing the full accumulated value at every\n * step. Instead of writing the value into `channel_values`, the channel is\n * omitted entirely and its state is reconstructed on read by walking the\n * ancestor chain and replaying the per-step writes through the reducer (see\n * {@link BaseCheckpointSaver.getDeltaChannelHistory}).\n *\n * Snapshot cadence is driven by two counters: a per-channel update count and\n * the total supersteps since the last snapshot. A full {@link DeltaSnapshot}\n * blob is written when EITHER the update count reaches `snapshotFrequency` OR\n * the supersteps count reaches the system-wide\n * `DELTA_MAX_SUPERSTEPS_SINCE_SNAPSHOT` bound (default 5000), bounding replay\n * depth even for channels that stop receiving writes.\n *\n * @remarks Beta. The API and on-disk representation may change in future\n * releases. Threads written with `DeltaChannel` today are expected to remain\n * readable, but the surrounding contract (`getDeltaChannelHistory`, the\n * `DeltaSnapshot` blob shape, the `counters_since_delta_snapshot` metadata\n * field) is not yet stable.\n *\n * @example\n * ```typescript\n * import { Annotation } from \"@langchain/langgraph\";\n * import { DeltaChannel, messagesDeltaReducer } from \"@langchain/langgraph\";\n *\n * const State = Annotation.Root({\n * messages: Annotation<BaseMessage[]>({\n * reducer: () => [], // ignored; DeltaChannel is supplied below\n * }),\n * });\n * ```\n */\nexport class DeltaChannel<\n ValueType = unknown,\n UpdateType = unknown,\n> extends BaseChannel<\n ValueType,\n OverwriteOrValue<ValueType, UpdateType>,\n undefined\n> {\n lc_graph_name = \"DeltaChannel\";\n\n /** `undefined` represents the Python `MISSING` sentinel (empty channel). */\n value: ValueType | undefined;\n\n reducer: DeltaReducer<ValueType, UpdateType>;\n\n snapshotFrequency: number;\n\n initialValueFactory: () => ValueType;\n\n constructor(\n reducer: DeltaReducer<ValueType, UpdateType>,\n options?: {\n snapshotFrequency?: number;\n initialValueFactory?: () => ValueType;\n }\n ) {\n super();\n const snapshotFrequency = options?.snapshotFrequency ??
|
|
1
|
+
{"version":3,"file":"delta.js","names":[],"sources":["../../src/channels/delta.ts"],"sourcesContent":["import {\n type CheckpointPendingWrite,\n DeltaSnapshot,\n isDeltaSnapshot,\n} 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\n/**\n * A batch reducer for use with {@link DeltaChannel}.\n *\n * Receives the current accumulated value and a batch of writes in one call,\n * returning the new accumulated value:\n * `reducer(state, [write1, write2, ...]) -> newState`.\n *\n * Reducers must be deterministic and batching-invariant (associative across\n * folds): applying two consecutive write batches separately must produce the\n * same state as applying their concatenation once:\n *\n * ```text\n * reducer(reducer(state, xs), ys) === reducer(state, xs.concat(ys))\n * ```\n *\n * This lets LangGraph replay checkpointed writes in larger batches than they\n * were originally produced without changing reconstructed state. If your\n * reducer is not associative, use {@link BinaryOperatorAggregate} instead —\n * `DeltaChannel` is not a drop-in replacement for every reducer.\n */\nexport type DeltaReducer<ValueType, UpdateType = unknown> = (\n state: ValueType,\n writes: UpdateType[]\n) => ValueType;\n\ntype OverwriteOrValue<ValueType, UpdateType> =\n | OverwriteValue<ValueType>\n | UpdateType;\n\nconst isDeltaChannel = (\n value: BaseChannel\n): value is DeltaChannel<unknown, unknown> => {\n return value != null && value.lc_graph_name === \"DeltaChannel\";\n};\n\n/**\n * Reducer channel that stores only a sentinel in checkpoint blobs and\n * reconstructs state by replaying ancestor writes through the reducer.\n *\n * `DeltaChannel` avoids re-serializing the full accumulated value at every\n * step. Instead of writing the value into `channel_values`, the channel is\n * omitted entirely and its state is reconstructed on read by walking the\n * ancestor chain and replaying the per-step writes through the reducer (see\n * {@link BaseCheckpointSaver.getDeltaChannelHistory}).\n *\n * Snapshot cadence is driven by two counters: a per-channel update count and\n * the total supersteps since the last snapshot. A full {@link DeltaSnapshot}\n * blob is written when EITHER the update count reaches `snapshotFrequency` OR\n * the supersteps count reaches the system-wide\n * `DELTA_MAX_SUPERSTEPS_SINCE_SNAPSHOT` bound (default 5000), bounding replay\n * depth even for channels that stop receiving writes.\n *\n * @remarks Beta. The API and on-disk representation may change in future\n * releases. Threads written with `DeltaChannel` today are expected to remain\n * readable, but the surrounding contract (`getDeltaChannelHistory`, the\n * `DeltaSnapshot` blob shape, the `counters_since_delta_snapshot` metadata\n * field) is not yet stable.\n *\n * @example\n * ```typescript\n * import { Annotation } from \"@langchain/langgraph\";\n * import { DeltaChannel, messagesDeltaReducer } from \"@langchain/langgraph\";\n *\n * const State = Annotation.Root({\n * messages: Annotation<BaseMessage[]>({\n * reducer: () => [], // ignored; DeltaChannel is supplied below\n * }),\n * });\n * ```\n */\nexport class DeltaChannel<\n ValueType = unknown,\n UpdateType = unknown,\n> extends BaseChannel<\n ValueType,\n OverwriteOrValue<ValueType, UpdateType>,\n undefined\n> {\n lc_graph_name = \"DeltaChannel\";\n\n /** `undefined` represents the Python `MISSING` sentinel (empty channel). */\n value: ValueType | undefined;\n\n reducer: DeltaReducer<ValueType, UpdateType>;\n\n snapshotFrequency: number;\n\n initialValueFactory: () => ValueType;\n\n constructor(\n reducer: DeltaReducer<ValueType, UpdateType>,\n options?: {\n snapshotFrequency?: number;\n initialValueFactory?: () => ValueType;\n }\n ) {\n super();\n const snapshotFrequency = options?.snapshotFrequency ?? 100;\n if (!Number.isInteger(snapshotFrequency) || snapshotFrequency <= 0) {\n throw new Error(\n `snapshotFrequency must be a positive integer, got ${snapshotFrequency}`\n );\n }\n this.reducer = reducer;\n this.snapshotFrequency = snapshotFrequency;\n this.initialValueFactory =\n options?.initialValueFactory ?? (() => [] as ValueType);\n this.value = undefined;\n }\n\n public fromCheckpoint(checkpoint?: undefined | DeltaSnapshot | ValueType) {\n const empty = new DeltaChannel<ValueType, UpdateType>(this.reducer, {\n snapshotFrequency: this.snapshotFrequency,\n initialValueFactory: this.initialValueFactory,\n });\n if (checkpoint === undefined) {\n empty.value = this.initialValueFactory();\n } else if (isDeltaSnapshot(checkpoint)) {\n empty.value = checkpoint.value as ValueType;\n } else {\n empty.value = checkpoint as ValueType;\n }\n return empty as this;\n }\n\n /**\n * Apply ancestor writes oldest-to-newest via a single reducer call.\n *\n * If any write is an Overwrite, the last one in the sequence acts as the\n * reset point: its value becomes the new base and only writes after it are\n * passed to the reducer.\n */\n public replayWrites(writes: CheckpointPendingWrite[]): void {\n const values = writes.map((w) => w[2]);\n if (values.length === 0) return;\n let base = this.value as ValueType;\n let start = 0;\n for (let i = 0; i < values.length; i += 1) {\n const [isOverwrite, overwriteValue] = _getOverwriteValue<ValueType>(\n values[i]\n );\n if (isOverwrite) {\n base =\n overwriteValue !== undefined && overwriteValue !== null\n ? overwriteValue\n : this.initialValueFactory();\n start = i + 1;\n }\n }\n const remaining = values.slice(start) as UpdateType[];\n this.value = remaining.length > 0 ? this.reducer(base, remaining) : base;\n }\n\n public update(values: OverwriteOrValue<ValueType, UpdateType>[]): boolean {\n if (values.length === 0) return false;\n\n let overwriteValue: ValueType | undefined;\n let hasOverwrite = false;\n for (const value of values) {\n if (_isOverwriteValue<ValueType>(value)) {\n if (hasOverwrite) {\n throw new InvalidUpdateError(\n \"Can receive only one Overwrite value per step.\"\n );\n }\n hasOverwrite = true;\n [, overwriteValue] = _getOverwriteValue<ValueType>(value);\n }\n }\n\n if (hasOverwrite) {\n // An Overwrite wins the entire super-step: every sibling write (before\n // AND after) is discarded, mirroring `BinaryOperatorAggregate` — hence\n // only one Overwrite per step. The loop force-snapshots channels that saw\n // an Overwrite, so reconstruction seeds from this value without replaying.\n this.value =\n overwriteValue !== undefined && overwriteValue !== null\n ? overwriteValue\n : this.initialValueFactory();\n return true;\n }\n\n const base =\n this.value === undefined ? this.initialValueFactory() : this.value;\n this.value = this.reducer(base, values as UpdateType[]);\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 /**\n * Always returns `undefined` (the Python `MISSING` sentinel). Snapshot\n * decisions live in `createCheckpoint`, which has the channel version and\n * writes a {@link DeltaSnapshot} directly into `channel_values`. For\n * non-snapshot steps the channel does not appear in `channel_values`;\n * reconstruction walks ancestor writes via the saver's\n * `getDeltaChannelHistory`.\n */\n public checkpoint(): undefined {\n return undefined;\n }\n\n isAvailable(): boolean {\n return this.value !== undefined;\n }\n\n equals(other: BaseChannel): boolean {\n if (this === other) return true;\n if (!isDeltaChannel(other)) return false;\n if (this.snapshotFrequency !== other.snapshotFrequency) return false;\n return this.reducer === other.reducer;\n }\n}\n"],"mappings":";;;;;AA0CA,MAAM,kBACJ,UAC4C;AAC5C,QAAO,SAAS,QAAQ,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsClD,IAAa,eAAb,MAAa,qBAGH,YAIR;CACA,gBAAgB;;CAGhB;CAEA;CAEA;CAEA;CAEA,YACE,SACA,SAIA;AACA,SAAO;EACP,MAAM,oBAAoB,SAAS,qBAAqB;AACxD,MAAI,CAAC,OAAO,UAAU,kBAAkB,IAAI,qBAAqB,EAC/D,OAAM,IAAI,MACR,qDAAqD,oBACtD;AAEH,OAAK,UAAU;AACf,OAAK,oBAAoB;AACzB,OAAK,sBACH,SAAS,8BAA8B,EAAE;AAC3C,OAAK,QAAQ,KAAA;;CAGf,eAAsB,YAAoD;EACxE,MAAM,QAAQ,IAAI,aAAoC,KAAK,SAAS;GAClE,mBAAmB,KAAK;GACxB,qBAAqB,KAAK;GAC3B,CAAC;AACF,MAAI,eAAe,KAAA,EACjB,OAAM,QAAQ,KAAK,qBAAqB;WAC/B,gBAAgB,WAAW,CACpC,OAAM,QAAQ,WAAW;MAEzB,OAAM,QAAQ;AAEhB,SAAO;;;;;;;;;CAUT,aAAoB,QAAwC;EAC1D,MAAM,SAAS,OAAO,KAAK,MAAM,EAAE,GAAG;AACtC,MAAI,OAAO,WAAW,EAAG;EACzB,IAAI,OAAO,KAAK;EAChB,IAAI,QAAQ;AACZ,OAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK,GAAG;GACzC,MAAM,CAAC,aAAa,kBAAkB,mBACpC,OAAO,GACR;AACD,OAAI,aAAa;AACf,WACE,mBAAmB,KAAA,KAAa,mBAAmB,OAC/C,iBACA,KAAK,qBAAqB;AAChC,YAAQ,IAAI;;;EAGhB,MAAM,YAAY,OAAO,MAAM,MAAM;AACrC,OAAK,QAAQ,UAAU,SAAS,IAAI,KAAK,QAAQ,MAAM,UAAU,GAAG;;CAGtE,OAAc,QAA4D;AACxE,MAAI,OAAO,WAAW,EAAG,QAAO;EAEhC,IAAI;EACJ,IAAI,eAAe;AACnB,OAAK,MAAM,SAAS,OAClB,KAAI,kBAA6B,MAAM,EAAE;AACvC,OAAI,aACF,OAAM,IAAI,mBACR,iDACD;AAEH,kBAAe;AACf,MAAG,kBAAkB,mBAA8B,MAAM;;AAI7D,MAAI,cAAc;AAKhB,QAAK,QACH,mBAAmB,KAAA,KAAa,mBAAmB,OAC/C,iBACA,KAAK,qBAAqB;AAChC,UAAO;;EAGT,MAAM,OACJ,KAAK,UAAU,KAAA,IAAY,KAAK,qBAAqB,GAAG,KAAK;AAC/D,OAAK,QAAQ,KAAK,QAAQ,MAAM,OAAuB;AACvD,SAAO;;CAGT,MAAwB;AACtB,MAAI,KAAK,UAAU,KAAA,EACjB,OAAM,IAAI,mBAAmB;AAE/B,SAAO,KAAK;;;;;;;;;;CAWd,aAA+B;CAI/B,cAAuB;AACrB,SAAO,KAAK,UAAU,KAAA;;CAGxB,OAAO,OAA6B;AAClC,MAAI,SAAS,MAAO,QAAO;AAC3B,MAAI,CAAC,eAAe,MAAM,CAAE,QAAO;AACnC,MAAI,KAAK,sBAAsB,MAAM,kBAAmB,QAAO;AAC/D,SAAO,KAAK,YAAY,MAAM"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delta.cjs","names":[],"sources":["../../../src/state/values/delta.ts"],"sourcesContent":["import type { SerializableSchema } from \"../types.js\";\nimport type { DeltaReducer } from \"../../channels/delta.js\";\n\n/**\n * Symbol for runtime identification of DeltaValue instances.\n */\nexport const DELTA_VALUE_SYMBOL: symbol = Symbol.for(\n \"langgraph.state.delta_value\"\n);\n\ninterface DeltaValueInitBase<Value = unknown> {\n /**\n * Batch reducer that combines the current accumulated value with a batch of\n * writes in a single call: `reducer(state, [w1, w2, ...]) -> newState`.\n *\n * Reducers must be deterministic and batching-invariant (associative across\n * folds), because {@link DeltaChannel} replays checkpointed writes in larger\n * batches than they were originally produced:\n * `reducer(reducer(state, xs), ys) === reducer(state, xs.concat(ys))`.\n */\n reducer: DeltaReducer<Value, Value>;\n\n /**\n * How often (in per-channel updates) to persist a full `DeltaSnapshot` blob\n * instead of relying purely on replayed deltas. Defaults to the channel's\n * own default (
|
|
1
|
+
{"version":3,"file":"delta.cjs","names":[],"sources":["../../../src/state/values/delta.ts"],"sourcesContent":["import type { SerializableSchema } from \"../types.js\";\nimport type { DeltaReducer } from \"../../channels/delta.js\";\n\n/**\n * Symbol for runtime identification of DeltaValue instances.\n */\nexport const DELTA_VALUE_SYMBOL: symbol = Symbol.for(\n \"langgraph.state.delta_value\"\n);\n\ninterface DeltaValueInitBase<Value = unknown> {\n /**\n * Batch reducer that combines the current accumulated value with a batch of\n * writes in a single call: `reducer(state, [w1, w2, ...]) -> newState`.\n *\n * Reducers must be deterministic and batching-invariant (associative across\n * folds), because {@link DeltaChannel} replays checkpointed writes in larger\n * batches than they were originally produced:\n * `reducer(reducer(state, xs), ys) === reducer(state, xs.concat(ys))`.\n */\n reducer: DeltaReducer<Value, Value>;\n\n /**\n * How often (in per-channel updates) to persist a full `DeltaSnapshot` blob\n * instead of relying purely on replayed deltas. Defaults to the channel's\n * own default (100) when omitted.\n */\n snapshotFrequency?: number;\n\n /**\n * Optional extra fields merged into the generated JSON Schema (e.g.\n * `langgraph_type`) for documentation, Studio hints, or external tooling.\n */\n jsonSchemaExtra?: Record<string, unknown>;\n}\n\ninterface DeltaValueInitWithSchema<Value = unknown, Input = Value> {\n /**\n * Schema describing the type and validation logic for reducer input values.\n *\n * When provided, the reducer may accept inputs distinct from the stored\n * (output) type. Each write is validated against this schema before reduction.\n */\n inputSchema: SerializableSchema<unknown, Input>;\n\n /**\n * Batch reducer that combines the current accumulated value with a batch of\n * validated writes: `reducer(state, [w1, w2, ...]) -> newState`.\n *\n * Must be deterministic and batching-invariant — see\n * {@link DeltaValueInitBase.reducer}.\n */\n reducer: DeltaReducer<Value, Input>;\n\n /**\n * How often (in per-channel updates) to persist a full `DeltaSnapshot` blob.\n * Defaults to the channel's own default (100) when omitted.\n */\n snapshotFrequency?: number;\n\n /**\n * Optional extra fields merged into the generated JSON Schema (e.g.\n * `langgraph_type`) for documentation, Studio hints, or external tooling.\n */\n jsonSchemaExtra?: Record<string, unknown>;\n}\n\n/**\n * Initialization options for {@link DeltaValue}.\n *\n * Two forms are supported:\n * 1. Provide only a reducer (and optionally `snapshotFrequency` /\n * `jsonSchemaExtra`) — the reducer's inputs are validated using the value\n * schema.\n * 2. Provide an explicit `inputSchema` to distinguish the reducer's input type\n * from the stored/output type.\n *\n * @template Value - The type of value stored and produced after reduction.\n * @template Input - The type of inputs accepted by the reducer.\n */\nexport type DeltaValueInit<Value = unknown, Input = Value> =\n | DeltaValueInitWithSchema<Value, Input>\n | DeltaValueInitBase<Value>;\n\n/**\n * Represents a state field backed by a {@link DeltaChannel}.\n *\n * Unlike {@link ReducedValue} (which stores the full accumulated value in every\n * checkpoint blob via `BinaryOperatorAggregate`), a `DeltaValue` field persists\n * only per-step deltas (plus periodic snapshots) and reconstructs its state on\n * read by replaying ancestor writes through a batch reducer. This avoids\n * re-serializing large accumulators (e.g. long message histories) at every step.\n *\n * @remarks Beta. The on-disk representation backing `DeltaChannel` may change in\n * future releases.\n *\n * @template Value - The type of the value stored in state and produced by reduction.\n * @template Input - The type of updates accepted by the reducer.\n *\n * @example\n * ```ts\n * import { z } from \"zod\";\n * import { StateSchema, DeltaValue } from \"@langchain/langgraph\";\n *\n * const State = new StateSchema({\n * history: new DeltaValue(z.array(z.string()).default(() => []), {\n * inputSchema: z.string(),\n * reducer: (current, writes) => [...current, ...writes],\n * }),\n * });\n * ```\n */\nexport class DeltaValue<Value = unknown, Input = Value> {\n /**\n * Instance marker for runtime identification.\n * @internal\n */\n protected readonly [DELTA_VALUE_SYMBOL] = true as const;\n\n /**\n * The schema that describes the type of value stored in state (after\n * reduction). Its default (if any) seeds the channel's initial value.\n */\n readonly valueSchema: SerializableSchema<unknown, Value>;\n\n /**\n * The schema used to validate reducer inputs. Defaults to `valueSchema` when\n * not specified explicitly.\n */\n readonly inputSchema: SerializableSchema<unknown, Input | Value>;\n\n /**\n * The batch reducer that folds a list of incoming writes into the current\n * accumulated value.\n */\n readonly reducer: DeltaReducer<Value, Input>;\n\n /**\n * Snapshot cadence forwarded to the underlying {@link DeltaChannel}.\n */\n readonly snapshotFrequency?: number;\n\n /**\n * Optional extra fields to merge into the generated JSON Schema.\n */\n readonly jsonSchemaExtra?: Record<string, unknown>;\n\n /**\n * Represents the value stored after all reductions.\n */\n declare ValueType: Value;\n\n /**\n * Represents the type that may be provided as input on each update.\n */\n declare InputType: Input;\n\n /**\n * Constructs a DeltaValue, pairing a value schema with a batch reducer (and an\n * optional distinct input schema).\n *\n * @param valueSchema - The schema describing the stored/output value.\n * @param init - The reducer (required), `inputSchema`, `snapshotFrequency`,\n * and `jsonSchemaExtra` (all optional except the reducer).\n */\n constructor(\n valueSchema: SerializableSchema<unknown, Value>,\n init: DeltaValueInitWithSchema<Value, Input>\n );\n\n constructor(\n valueSchema: SerializableSchema<Input, Value>,\n init: DeltaValueInitBase<Value>\n );\n\n constructor(\n valueSchema: SerializableSchema<unknown, Value>,\n init: DeltaValueInit<Value, Input>\n ) {\n this.reducer = init.reducer as DeltaReducer<Value, Input>;\n this.valueSchema = valueSchema;\n this.inputSchema = \"inputSchema\" in init ? init.inputSchema : valueSchema;\n this.snapshotFrequency = init.snapshotFrequency;\n this.jsonSchemaExtra = init.jsonSchemaExtra;\n }\n\n /**\n * Type guard to check if a value is a DeltaValue instance.\n */\n static isInstance<Value = unknown, Input = Value>(\n value: DeltaValue<Value, Input>\n ): value is DeltaValue<Value, Input>;\n\n static isInstance(value: unknown): value is DeltaValue;\n\n static isInstance<Value = unknown, Input = Value>(\n value: DeltaValue<Value, Input> | unknown\n ): value is DeltaValue<Value, Input> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n DELTA_VALUE_SYMBOL in value &&\n (value as Record<symbol, unknown>)[DELTA_VALUE_SYMBOL] === true\n );\n }\n}\n"],"mappings":";;;;AAMA,MAAa,qBAA6B,OAAO,IAC/C,8BACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwGD,IAAa,aAAb,MAAwD;;;;;CAKtD,CAAoB,sBAAsB;;;;;CAM1C;;;;;CAMA;;;;;CAMA;;;;CAKA;;;;CAKA;CA8BA,YACE,aACA,MACA;AACA,OAAK,UAAU,KAAK;AACpB,OAAK,cAAc;AACnB,OAAK,cAAc,iBAAiB,OAAO,KAAK,cAAc;AAC9D,OAAK,oBAAoB,KAAK;AAC9B,OAAK,kBAAkB,KAAK;;CAY9B,OAAO,WACL,OACmC;AACnC,SACE,OAAO,UAAU,YACjB,UAAU,QACV,sBAAsB,SACrB,MAAkC,wBAAwB"}
|
|
@@ -20,7 +20,7 @@ interface DeltaValueInitBase<Value = unknown> {
|
|
|
20
20
|
/**
|
|
21
21
|
* How often (in per-channel updates) to persist a full `DeltaSnapshot` blob
|
|
22
22
|
* instead of relying purely on replayed deltas. Defaults to the channel's
|
|
23
|
-
* own default (
|
|
23
|
+
* own default (100) when omitted.
|
|
24
24
|
*/
|
|
25
25
|
snapshotFrequency?: number;
|
|
26
26
|
/**
|
|
@@ -47,7 +47,7 @@ interface DeltaValueInitWithSchema<Value = unknown, Input = Value> {
|
|
|
47
47
|
reducer: DeltaReducer<Value, Input>;
|
|
48
48
|
/**
|
|
49
49
|
* How often (in per-channel updates) to persist a full `DeltaSnapshot` blob.
|
|
50
|
-
* Defaults to the channel's own default (
|
|
50
|
+
* Defaults to the channel's own default (100) when omitted.
|
|
51
51
|
*/
|
|
52
52
|
snapshotFrequency?: number;
|
|
53
53
|
/**
|
|
@@ -20,7 +20,7 @@ interface DeltaValueInitBase<Value = unknown> {
|
|
|
20
20
|
/**
|
|
21
21
|
* How often (in per-channel updates) to persist a full `DeltaSnapshot` blob
|
|
22
22
|
* instead of relying purely on replayed deltas. Defaults to the channel's
|
|
23
|
-
* own default (
|
|
23
|
+
* own default (100) when omitted.
|
|
24
24
|
*/
|
|
25
25
|
snapshotFrequency?: number;
|
|
26
26
|
/**
|
|
@@ -47,7 +47,7 @@ interface DeltaValueInitWithSchema<Value = unknown, Input = Value> {
|
|
|
47
47
|
reducer: DeltaReducer<Value, Input>;
|
|
48
48
|
/**
|
|
49
49
|
* How often (in per-channel updates) to persist a full `DeltaSnapshot` blob.
|
|
50
|
-
* Defaults to the channel's own default (
|
|
50
|
+
* Defaults to the channel's own default (100) when omitted.
|
|
51
51
|
*/
|
|
52
52
|
snapshotFrequency?: number;
|
|
53
53
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delta.js","names":[],"sources":["../../../src/state/values/delta.ts"],"sourcesContent":["import type { SerializableSchema } from \"../types.js\";\nimport type { DeltaReducer } from \"../../channels/delta.js\";\n\n/**\n * Symbol for runtime identification of DeltaValue instances.\n */\nexport const DELTA_VALUE_SYMBOL: symbol = Symbol.for(\n \"langgraph.state.delta_value\"\n);\n\ninterface DeltaValueInitBase<Value = unknown> {\n /**\n * Batch reducer that combines the current accumulated value with a batch of\n * writes in a single call: `reducer(state, [w1, w2, ...]) -> newState`.\n *\n * Reducers must be deterministic and batching-invariant (associative across\n * folds), because {@link DeltaChannel} replays checkpointed writes in larger\n * batches than they were originally produced:\n * `reducer(reducer(state, xs), ys) === reducer(state, xs.concat(ys))`.\n */\n reducer: DeltaReducer<Value, Value>;\n\n /**\n * How often (in per-channel updates) to persist a full `DeltaSnapshot` blob\n * instead of relying purely on replayed deltas. Defaults to the channel's\n * own default (
|
|
1
|
+
{"version":3,"file":"delta.js","names":[],"sources":["../../../src/state/values/delta.ts"],"sourcesContent":["import type { SerializableSchema } from \"../types.js\";\nimport type { DeltaReducer } from \"../../channels/delta.js\";\n\n/**\n * Symbol for runtime identification of DeltaValue instances.\n */\nexport const DELTA_VALUE_SYMBOL: symbol = Symbol.for(\n \"langgraph.state.delta_value\"\n);\n\ninterface DeltaValueInitBase<Value = unknown> {\n /**\n * Batch reducer that combines the current accumulated value with a batch of\n * writes in a single call: `reducer(state, [w1, w2, ...]) -> newState`.\n *\n * Reducers must be deterministic and batching-invariant (associative across\n * folds), because {@link DeltaChannel} replays checkpointed writes in larger\n * batches than they were originally produced:\n * `reducer(reducer(state, xs), ys) === reducer(state, xs.concat(ys))`.\n */\n reducer: DeltaReducer<Value, Value>;\n\n /**\n * How often (in per-channel updates) to persist a full `DeltaSnapshot` blob\n * instead of relying purely on replayed deltas. Defaults to the channel's\n * own default (100) when omitted.\n */\n snapshotFrequency?: number;\n\n /**\n * Optional extra fields merged into the generated JSON Schema (e.g.\n * `langgraph_type`) for documentation, Studio hints, or external tooling.\n */\n jsonSchemaExtra?: Record<string, unknown>;\n}\n\ninterface DeltaValueInitWithSchema<Value = unknown, Input = Value> {\n /**\n * Schema describing the type and validation logic for reducer input values.\n *\n * When provided, the reducer may accept inputs distinct from the stored\n * (output) type. Each write is validated against this schema before reduction.\n */\n inputSchema: SerializableSchema<unknown, Input>;\n\n /**\n * Batch reducer that combines the current accumulated value with a batch of\n * validated writes: `reducer(state, [w1, w2, ...]) -> newState`.\n *\n * Must be deterministic and batching-invariant — see\n * {@link DeltaValueInitBase.reducer}.\n */\n reducer: DeltaReducer<Value, Input>;\n\n /**\n * How often (in per-channel updates) to persist a full `DeltaSnapshot` blob.\n * Defaults to the channel's own default (100) when omitted.\n */\n snapshotFrequency?: number;\n\n /**\n * Optional extra fields merged into the generated JSON Schema (e.g.\n * `langgraph_type`) for documentation, Studio hints, or external tooling.\n */\n jsonSchemaExtra?: Record<string, unknown>;\n}\n\n/**\n * Initialization options for {@link DeltaValue}.\n *\n * Two forms are supported:\n * 1. Provide only a reducer (and optionally `snapshotFrequency` /\n * `jsonSchemaExtra`) — the reducer's inputs are validated using the value\n * schema.\n * 2. Provide an explicit `inputSchema` to distinguish the reducer's input type\n * from the stored/output type.\n *\n * @template Value - The type of value stored and produced after reduction.\n * @template Input - The type of inputs accepted by the reducer.\n */\nexport type DeltaValueInit<Value = unknown, Input = Value> =\n | DeltaValueInitWithSchema<Value, Input>\n | DeltaValueInitBase<Value>;\n\n/**\n * Represents a state field backed by a {@link DeltaChannel}.\n *\n * Unlike {@link ReducedValue} (which stores the full accumulated value in every\n * checkpoint blob via `BinaryOperatorAggregate`), a `DeltaValue` field persists\n * only per-step deltas (plus periodic snapshots) and reconstructs its state on\n * read by replaying ancestor writes through a batch reducer. This avoids\n * re-serializing large accumulators (e.g. long message histories) at every step.\n *\n * @remarks Beta. The on-disk representation backing `DeltaChannel` may change in\n * future releases.\n *\n * @template Value - The type of the value stored in state and produced by reduction.\n * @template Input - The type of updates accepted by the reducer.\n *\n * @example\n * ```ts\n * import { z } from \"zod\";\n * import { StateSchema, DeltaValue } from \"@langchain/langgraph\";\n *\n * const State = new StateSchema({\n * history: new DeltaValue(z.array(z.string()).default(() => []), {\n * inputSchema: z.string(),\n * reducer: (current, writes) => [...current, ...writes],\n * }),\n * });\n * ```\n */\nexport class DeltaValue<Value = unknown, Input = Value> {\n /**\n * Instance marker for runtime identification.\n * @internal\n */\n protected readonly [DELTA_VALUE_SYMBOL] = true as const;\n\n /**\n * The schema that describes the type of value stored in state (after\n * reduction). Its default (if any) seeds the channel's initial value.\n */\n readonly valueSchema: SerializableSchema<unknown, Value>;\n\n /**\n * The schema used to validate reducer inputs. Defaults to `valueSchema` when\n * not specified explicitly.\n */\n readonly inputSchema: SerializableSchema<unknown, Input | Value>;\n\n /**\n * The batch reducer that folds a list of incoming writes into the current\n * accumulated value.\n */\n readonly reducer: DeltaReducer<Value, Input>;\n\n /**\n * Snapshot cadence forwarded to the underlying {@link DeltaChannel}.\n */\n readonly snapshotFrequency?: number;\n\n /**\n * Optional extra fields to merge into the generated JSON Schema.\n */\n readonly jsonSchemaExtra?: Record<string, unknown>;\n\n /**\n * Represents the value stored after all reductions.\n */\n declare ValueType: Value;\n\n /**\n * Represents the type that may be provided as input on each update.\n */\n declare InputType: Input;\n\n /**\n * Constructs a DeltaValue, pairing a value schema with a batch reducer (and an\n * optional distinct input schema).\n *\n * @param valueSchema - The schema describing the stored/output value.\n * @param init - The reducer (required), `inputSchema`, `snapshotFrequency`,\n * and `jsonSchemaExtra` (all optional except the reducer).\n */\n constructor(\n valueSchema: SerializableSchema<unknown, Value>,\n init: DeltaValueInitWithSchema<Value, Input>\n );\n\n constructor(\n valueSchema: SerializableSchema<Input, Value>,\n init: DeltaValueInitBase<Value>\n );\n\n constructor(\n valueSchema: SerializableSchema<unknown, Value>,\n init: DeltaValueInit<Value, Input>\n ) {\n this.reducer = init.reducer as DeltaReducer<Value, Input>;\n this.valueSchema = valueSchema;\n this.inputSchema = \"inputSchema\" in init ? init.inputSchema : valueSchema;\n this.snapshotFrequency = init.snapshotFrequency;\n this.jsonSchemaExtra = init.jsonSchemaExtra;\n }\n\n /**\n * Type guard to check if a value is a DeltaValue instance.\n */\n static isInstance<Value = unknown, Input = Value>(\n value: DeltaValue<Value, Input>\n ): value is DeltaValue<Value, Input>;\n\n static isInstance(value: unknown): value is DeltaValue;\n\n static isInstance<Value = unknown, Input = Value>(\n value: DeltaValue<Value, Input> | unknown\n ): value is DeltaValue<Value, Input> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n DELTA_VALUE_SYMBOL in value &&\n (value as Record<symbol, unknown>)[DELTA_VALUE_SYMBOL] === true\n );\n }\n}\n"],"mappings":";;;;AAMA,MAAa,qBAA6B,OAAO,IAC/C,8BACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwGD,IAAa,aAAb,MAAwD;;;;;CAKtD,CAAoB,sBAAsB;;;;;CAM1C;;;;;CAMA;;;;;CAMA;;;;CAKA;;;;CAKA;CA8BA,YACE,aACA,MACA;AACA,OAAK,UAAU,KAAK;AACpB,OAAK,cAAc;AACnB,OAAK,cAAc,iBAAiB,OAAO,KAAK,cAAc;AAC9D,OAAK,oBAAoB,KAAK;AAC9B,OAAK,kBAAkB,KAAK;;CAY9B,OAAO,WACL,OACmC;AACnC,SACE,OAAO,UAAU,YACjB,UAAU,QACV,sBAAsB,SACrB,MAAkC,wBAAwB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@langchain/langgraph",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.3",
|
|
4
4
|
"description": "LangGraph",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
"author": "LangChain",
|
|
17
17
|
"license": "MIT",
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@langchain/protocol": "^0.0.
|
|
19
|
+
"@langchain/protocol": "^0.0.20",
|
|
20
20
|
"@standard-schema/spec": "1.1.0",
|
|
21
|
-
"@langchain/langgraph-checkpoint": "^1.2.
|
|
22
|
-
"@langchain/langgraph-sdk": "~1.12.
|
|
21
|
+
"@langchain/langgraph-checkpoint": "^1.2.1",
|
|
22
|
+
"@langchain/langgraph-sdk": "~1.12.8"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
25
25
|
"@langchain/core": "^1.1.48",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"@testing-library/dom": "^10.4.2",
|
|
36
36
|
"@tsconfig/recommended": "^1.0.3",
|
|
37
37
|
"@types/pg": "^8",
|
|
38
|
-
"@vitest/browser": "^4.1.
|
|
39
|
-
"@vitest/browser-playwright": "^4.1.
|
|
38
|
+
"@vitest/browser": "^4.1.12",
|
|
39
|
+
"@vitest/browser-playwright": "^4.1.12",
|
|
40
40
|
"@xenova/transformers": "^2.17.2",
|
|
41
41
|
"cheerio": "1.0.0-rc.12",
|
|
42
42
|
"dotenv": "^16.3.1",
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
"tsx": "^4.19.3",
|
|
49
49
|
"typescript": "^4.9.5 || ^5.4.5",
|
|
50
50
|
"vite-plugin-node-polyfills": "^0.28.0",
|
|
51
|
-
"vitest": "^4.1.
|
|
52
|
-
"@langchain/langgraph-checkpoint-postgres": "1.1.
|
|
51
|
+
"vitest": "^4.1.12",
|
|
52
|
+
"@langchain/langgraph-checkpoint-postgres": "1.1.2",
|
|
53
53
|
"@langchain/langgraph-checkpoint-sqlite": "1.1.0"
|
|
54
54
|
},
|
|
55
55
|
"publishConfig": {
|