refactor(delta-channel): drop snapshot_every and saver Overwrite terminator

snapshot_every was a knob for bounding reconstruction cost on deep threads.
Benchmarks (notes/add_messages_replay_problem.md + scratch work on
sr/add-messages-replay-bench) showed the add_messages fast-path
(optimize/add-messages-fast-path) closes the quadratic replay cost for
threads under ~1000 turns, where the crossover to snapshots makes sense.
For deeper threads we'll ship a first-class compaction primitive instead.

Removals:

* DeltaChannel: snapshot_every ctor param, _writes_since_snapshot counter,
  should_snapshot() / snapshot_write() methods, counter threading through
  _apply_write / update / from_checkpoint / copy.
* Pregel loop: post-checkpoint snapshot-injection block and
  SNAPSHOT_TASK_ID import + constant.
* Checkpoint base: _overwrite_types() helper and the ancestor-walk
  short-circuit on user-emitted Overwrite in sync + async
  get_channel_writes.
* InMemory + Postgres savers: same walk-terminator shortcut. The
  pre-delta blob terminator (seed-from-ancestor-blob) stays — it's
  required for migration correctness, not a snapshot optimization.
* Tests for all of the above.

Preserved:

* Channel-level Overwrite semantics in DeltaChannel / BinOpAggregate:
  Overwrite still resets the value at reducer level; same-super-step
  dedup and InvalidUpdateError on multiple Overwrites still enforced.
* Pre-delta migration seeding.
This commit is contained in:
Sydney Runkle
2026-04-23 09:54:12 -04:00
parent d120f127ca
commit 31ef0e942a
9 changed files with 65 additions and 418 deletions
@@ -13,7 +13,6 @@ from langgraph.checkpoint.base import (
BaseCheckpointSaver,
ChannelVersions,
DeltaChannelWrites,
_overwrite_types,
get_checkpoint_id,
)
from langgraph.checkpoint.serde.types import TASKS
@@ -238,19 +237,14 @@ class BasePostgresSaver(BaseCheckpointSaver[str]):
(`AsyncPostgresSaver`); both paths run the queries themselves and
feed the rows here.
Walk is newest → oldest from the target's parent. Stops at the first
terminator:
* a user-emitted `Overwrite` in `checkpoint_writes` — replaces
prior history;
* a non-sentinel blob in `checkpoint_blobs` — a pre-delta snapshot;
bound as `DeltaChannelWrites.seed` so replay starts from it.
Walk is newest → oldest from the target's parent. A non-sentinel
blob in `checkpoint_blobs` (a pre-delta snapshot) terminates the
walk and is bound as `DeltaChannelWrites.seed` so replay starts
from it.
Writes stored at `target_id` itself are pending writes for the next
step and are excluded — the walk begins at the target's parent.
"""
overwrite_types = _overwrite_types()
parent_of: dict[str, str | None] = {}
ver_of: dict[str, str | None] = {}
for r in parents_rows:
@@ -298,15 +292,9 @@ class BasePostgresSaver(BaseCheckpointSaver[str]):
seed = blob_value
found_seed = True
break
terminated = False
for type_tag, write_blob, _task_id, _idx in writes_by_cid.get(cid, []):
val = self.serde.loads_typed((type_tag, write_blob))
collected.append(val)
if isinstance(val, overwrite_types):
terminated = True
break
if terminated:
break
collected.reverse() # oldest → newest
if found_seed: