mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-10-16 21:25:35 +02:00
`update_state` saves `counters_since_delta_snapshot` on the checkpoint it creates, except on three paths: `update_state(None, as_node=END)`, `as_node="__input__"` and `as_node="__copy__"`. Those save their checkpoint without it, so the next checkpoint restarts every delta channel's counters from zero: ``` before update_state(None, END): [6, 9] after it: (none) after the next run: [2, 3] (with this change: [6, 10], then [8, 13]) ``` The counters decide when a channel snapshots, so after any of these updates the next snapshot comes later than `snapshot_frequency` and reads walk further back. A thread driven only by these updates never snapshots, so its walk keeps growing. The field's docstring says it is absent only on threads that don't use delta channels. ## Fix `END` and `__input__` build their checkpoint with `create_checkpoint_plan_for_update_state_api`, the plan an update as a node already uses, which now takes the checkpoint's `source`. The counters advance by one superstep (`END` counts the channels its absorbed writes touched as updated), and a channel that reaches its bound snapshots right there. `__copy__` saves a checkpoint with the same values on the same parent, so it keeps the copied checkpoint's counters. ## Tests `test_delta_channel_supersteps_bound.py`, sync and async: - each of the three paths saves the base's counters advanced by one superstep (or unchanged for `__copy__`). - `END` and `__input__` snapshot a channel that reaches its supersteps bound. All 10 fail on main.