From 5169786ded9c09f53eb1b153d580e0200a2eb659 Mon Sep 17 00:00:00 2001 From: Sydney Runkle Date: Tue, 21 Apr 2026 09:29:58 -0400 Subject: [PATCH] feat(serde): diff type encodes prev_checkpoint_id; loads_typed returns DeltaValue Co-Authored-By: Claude Sonnet 4.6 --- .../langgraph/checkpoint/serde/jsonplus.py | 6 ++-- libs/checkpoint/tests/test_jsonplus.py | 36 ++++++++----------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/libs/checkpoint/langgraph/checkpoint/serde/jsonplus.py b/libs/checkpoint/langgraph/checkpoint/serde/jsonplus.py index 04c2e7f1d..4c8ade0ea 100644 --- a/libs/checkpoint/langgraph/checkpoint/serde/jsonplus.py +++ b/libs/checkpoint/langgraph/checkpoint/serde/jsonplus.py @@ -263,7 +263,7 @@ class JsonPlusSerializer(SerializerProtocol): elif isinstance(obj, bytearray): return "bytearray", obj elif _is_diff_delta(obj): - return "diff", _msgpack_enc({"d": obj.delta, "p": obj.prev_version}) + return "diff", _msgpack_enc({"d": obj.delta, "c": obj.prev_checkpoint_id}) else: try: return "msgpack", _msgpack_enc(obj) @@ -287,9 +287,11 @@ class JsonPlusSerializer(SerializerProtocol): data_, ext_hook=self._unpack_ext_hook, option=ormsgpack.OPT_NON_STR_KEYS ) elif type_ == "diff": - return ormsgpack.unpackb( + from langgraph.checkpoint.base import DeltaValue # lazy import + raw = ormsgpack.unpackb( data_, ext_hook=self._unpack_ext_hook, option=ormsgpack.OPT_NON_STR_KEYS ) + return DeltaValue(delta=raw["d"], prev_checkpoint_id=raw.get("c")) elif self.pickle_fallback and type_ == "pickle": return pickle.loads(data_) else: diff --git a/libs/checkpoint/tests/test_jsonplus.py b/libs/checkpoint/tests/test_jsonplus.py index 2360721cc..7533092df 100644 --- a/libs/checkpoint/tests/test_jsonplus.py +++ b/libs/checkpoint/tests/test_jsonplus.py @@ -999,33 +999,27 @@ def test_msgpack_nested_pydantic_serializes_as_dict( assert result == obj -def test_diff_delta_serde_round_trip() -> None: +def test_delta_value_serde_round_trip() -> None: from langgraph.checkpoint.base import DeltaValue + from langgraph.checkpoint.serde.jsonplus import JsonPlusSerializer serde = JsonPlusSerializer() - prev = "00000000000000000000000000000001.1234567890123456" - delta = DeltaValue( - delta=[HumanMessage(content="hello", id="msg-1")], - prev_version=prev, - ) - type_tag, blob = serde.dumps_typed(delta) + original = DeltaValue(delta=[{"type": "human", "content": "hi"}], prev_checkpoint_id="abc-123") + type_tag, blob = serde.dumps_typed(original) assert type_tag == "diff" - - result = serde.loads_typed(("diff", blob)) - assert isinstance(result, dict) - assert result["p"] == prev - assert len(result["d"]) == 1 - assert result["d"][0].content == "hello" + loaded = serde.loads_typed((type_tag, blob)) + assert isinstance(loaded, DeltaValue) + assert loaded.delta == original.delta + assert loaded.prev_checkpoint_id == "abc-123" -def test_diff_delta_serde_root_blob() -> None: +def test_delta_value_serde_chain_root() -> None: from langgraph.checkpoint.base import DeltaValue + from langgraph.checkpoint.serde.jsonplus import JsonPlusSerializer serde = JsonPlusSerializer() - delta = DeltaValue(delta=[], prev_version=None) - type_tag, blob = serde.dumps_typed(delta) - assert type_tag == "diff" - - result = serde.loads_typed(("diff", blob)) - assert result["p"] is None - assert result["d"] == [] + original = DeltaValue(delta=[], prev_checkpoint_id=None) + type_tag, blob = serde.dumps_typed(original) + loaded = serde.loads_typed((type_tag, blob)) + assert isinstance(loaded, DeltaValue) + assert loaded.prev_checkpoint_id is None