mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-10-14 20:25:23 +02:00
Changing a field from a `DeltaChannel` to a plain reducer, for example to `Annotated[list, add_messages]`, made threads written under the `DeltaChannel` read that field as empty. The next run saved its writes over the empty value, so continuing an old thread replaced its history. The writes were still stored: the read only rebuilt fields whose current annotation is a `DeltaChannel`. - A `BinaryOperatorAggregate` stores its value at every version, so one with a version and nothing stored was written as a `DeltaChannel`. It's now rebuilt from the same history walk, one `update` per write, since a single call would reject a second `Overwrite` and drop the writes after one. - `BinaryOperatorAggregate.from_checkpoint` unwraps a stored `_DeltaSnapshot`. - The next run saves the full value, so later reads are plain reads, and switching back to a `DeltaChannel` keeps everything. Threads written under a plain reducer never walk. A rebuilt read costs the walk plus one reducer call per write since the last snapshot: with `add_messages` on `InMemorySaver`, 25 ms at 2,048 messages with a snapshot every 50 writes, and 0.3 s at 1,998 or 0.9 s at 4,998 messages with the default 1000. After one run, reads take 6 to 16 ms. `test_delta_channel_to_plain.py` covers every saver; all but the plain-thread test fail on main. JS: langchain-ai/langgraphjs#3017