mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-09-05 01:07:48 +02:00
test(langgraph): compare read-back checkpoints in the immutability saver
MemorySaverAssertImmutable recorded the checkpoint object handed to put, then compared it against one read back through get. Those two are not the same shape: channel_values are stored per (channel, version), so a channel a step did not write is refilled from the blob its inherited version still points at. Every channel except DeltaChannel writes its value into channel_values on every checkpoint, so the two agreed by accident. A DeltaChannel stores nothing except at a snapshot, so once one snapshots and a later step does not write it, the saver reports a checkpoint that changed after it was written when nothing was mutated. Reproducible on main with no fork involved: a delta channel with snapshot_frequency=1 written by the first node and left alone by the next two trips the assertion. Existing delta tests miss it only because they all use snapshot_frequency=1000. Record what the saver reads back instead. Comparing read-back against read-back still catches a checkpoint whose stored data really changed.
This commit is contained in:
@@ -86,11 +86,19 @@ class MemorySaverAssertImmutable(InMemorySaver):
|
||||
)
|
||||
== saved
|
||||
), config["configurable"]["checkpoint_ns"]
|
||||
self.storage_for_copies[thread_id][checkpoint_ns][checkpoint["id"]] = (
|
||||
self.serde.dumps_typed(checkpoint)
|
||||
)
|
||||
# call super to write checkpoint
|
||||
return super().put(config, checkpoint, metadata, new_versions)
|
||||
next_config = super().put(config, checkpoint, metadata, new_versions)
|
||||
# Record the checkpoint as the saver reads it back, not the object it
|
||||
# was handed. `channel_values` are stored per (channel, version), so a
|
||||
# channel a step did not write is refilled from the blob its inherited
|
||||
# version still points at. A `DeltaChannel` omits its value except at a
|
||||
# snapshot, which makes the two representations differ for reasons that
|
||||
# are not mutation. Comparing read-back against read-back still catches
|
||||
# a checkpoint whose stored data actually changed.
|
||||
self.storage_for_copies[thread_id][checkpoint_ns][checkpoint["id"]] = (
|
||||
self.serde.dumps_typed(super().get(next_config))
|
||||
)
|
||||
return next_config
|
||||
|
||||
|
||||
class MemorySaverNoPending(InMemorySaver):
|
||||
|
||||
Reference in New Issue
Block a user