@langchain/langgraph
Version:
135 lines (134 loc) • 5.41 kB
JavaScript
const require_constants = require("../constants.cjs");
const require_errors = require("../errors.cjs");
const require_base = require("./base.cjs");
let _langchain_langgraph_checkpoint = require("@langchain/langgraph-checkpoint");
//#region src/channels/delta.ts
const isDeltaChannel = (value) => {
return value != null && value.lc_graph_name === "DeltaChannel";
};
/**
* Reducer channel that stores only a sentinel in checkpoint blobs and
* reconstructs state by replaying ancestor writes through the reducer.
*
* `DeltaChannel` avoids re-serializing the full accumulated value at every
* step. Instead of writing the value into `channel_values`, the channel is
* omitted entirely and its state is reconstructed on read by walking the
* ancestor chain and replaying the per-step writes through the reducer (see
* {@link BaseCheckpointSaver.getDeltaChannelHistory}).
*
* Snapshot cadence is driven by two counters: a per-channel update count and
* the total supersteps since the last snapshot. A full {@link DeltaSnapshot}
* blob is written when EITHER the update count reaches `snapshotFrequency` OR
* the supersteps count reaches the system-wide
* `DELTA_MAX_SUPERSTEPS_SINCE_SNAPSHOT` bound (default 5000), bounding replay
* depth even for channels that stop receiving writes.
*
* @remarks Beta. The API and on-disk representation may change in future
* releases. Threads written with `DeltaChannel` today are expected to remain
* readable, but the surrounding contract (`getDeltaChannelHistory`, the
* `DeltaSnapshot` blob shape, the `counters_since_delta_snapshot` metadata
* field) is not yet stable.
*
* @example
* ```typescript
* import { Annotation } from "@langchain/langgraph";
* import { DeltaChannel, messagesDeltaReducer } from "@langchain/langgraph";
*
* const State = Annotation.Root({
* messages: Annotation<BaseMessage[]>({
* reducer: () => [], // ignored; DeltaChannel is supplied below
* }),
* });
* ```
*/
var DeltaChannel = class DeltaChannel extends require_base.BaseChannel {
lc_graph_name = "DeltaChannel";
/** `undefined` represents the Python `MISSING` sentinel (empty channel). */
value;
reducer;
snapshotFrequency;
initialValueFactory;
constructor(reducer, options) {
super();
const snapshotFrequency = options?.snapshotFrequency ?? 1e3;
if (!Number.isInteger(snapshotFrequency) || snapshotFrequency <= 0) throw new Error(`snapshotFrequency must be a positive integer, got ${snapshotFrequency}`);
this.reducer = reducer;
this.snapshotFrequency = snapshotFrequency;
this.initialValueFactory = options?.initialValueFactory ?? (() => []);
this.value = void 0;
}
fromCheckpoint(checkpoint) {
const empty = new DeltaChannel(this.reducer, {
snapshotFrequency: this.snapshotFrequency,
initialValueFactory: this.initialValueFactory
});
if (checkpoint === void 0) empty.value = this.initialValueFactory();
else if ((0, _langchain_langgraph_checkpoint.isDeltaSnapshot)(checkpoint)) empty.value = checkpoint.value;
else empty.value = checkpoint;
return empty;
}
/**
* Apply ancestor writes oldest-to-newest via a single reducer call.
*
* If any write is an Overwrite, the last one in the sequence acts as the
* reset point: its value becomes the new base and only writes after it are
* passed to the reducer.
*/
replayWrites(writes) {
const values = writes.map((w) => w[2]);
if (values.length === 0) return;
let base = this.value;
let start = 0;
for (let i = 0; i < values.length; i += 1) {
const [isOverwrite, overwriteValue] = require_constants._getOverwriteValue(values[i]);
if (isOverwrite) {
base = overwriteValue !== void 0 && overwriteValue !== null ? overwriteValue : this.initialValueFactory();
start = i + 1;
}
}
const remaining = values.slice(start);
this.value = remaining.length > 0 ? this.reducer(base, remaining) : base;
}
update(values) {
if (values.length === 0) return false;
let overwriteValue;
let hasOverwrite = false;
for (const value of values) if (require_constants._isOverwriteValue(value)) {
if (hasOverwrite) throw new require_errors.InvalidUpdateError("Can receive only one Overwrite value per step.");
hasOverwrite = true;
[, overwriteValue] = require_constants._getOverwriteValue(value);
}
if (hasOverwrite) {
this.value = overwriteValue !== void 0 && overwriteValue !== null ? overwriteValue : this.initialValueFactory();
return true;
}
const base = this.value === void 0 ? this.initialValueFactory() : this.value;
this.value = this.reducer(base, values);
return true;
}
get() {
if (this.value === void 0) throw new require_errors.EmptyChannelError();
return this.value;
}
/**
* Always returns `undefined` (the Python `MISSING` sentinel). Snapshot
* decisions live in `createCheckpoint`, which has the channel version and
* writes a {@link DeltaSnapshot} directly into `channel_values`. For
* non-snapshot steps the channel does not appear in `channel_values`;
* reconstruction walks ancestor writes via the saver's
* `getDeltaChannelHistory`.
*/
checkpoint() {}
isAvailable() {
return this.value !== void 0;
}
equals(other) {
if (this === other) return true;
if (!isDeltaChannel(other)) return false;
if (this.snapshotFrequency !== other.snapshotFrequency) return false;
return this.reducer === other.reducer;
}
};
//#endregion
exports.DeltaChannel = DeltaChannel;
//# sourceMappingURL=delta.cjs.map