Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -307,8 +307,9 @@ class MyState: ...

def _encode(value: Any) -> Any:
"""Recursively encode a value for JSON storage."""
# JSON-native types pass through
if isinstance(value, _JSON_NATIVE_TYPES):
# JSON-native types pass through only for exact types so scalar subclasses
# (such as IntEnum, StrEnum, or custom scalar subclasses) preserve their type.
if type(value) in _JSON_NATIVE_TYPES:
return value

# Recursively encode dict values (keys become strings). Only plain dicts
Expand Down
41 changes: 41 additions & 0 deletions python/packages/core/tests/workflow/test_checkpoint_encode.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from collections import Counter, OrderedDict, defaultdict
from dataclasses import dataclass
from datetime import datetime, timezone
from enum import IntEnum
from typing import Any, cast

from agent_framework._workflows._checkpoint_encoding import (
Expand All @@ -14,6 +15,19 @@
)


class StatusEnum(IntEnum):
PENDING = 1
ACTIVE = 2


class CustomInt(int):
pass


class CustomStr(str):
pass


@dataclass
class SimpleDataclass:
"""A simple dataclass for testing encoding."""
Expand Down Expand Up @@ -87,6 +101,33 @@ def test_encode_none() -> None:
assert encode_checkpoint_value(None) is None


def test_encode_scalar_subclasses_preserves_type_fidelity() -> None:
"""Test that scalar subclasses like IntEnum are pickled rather than flattened to raw primitives."""
status = StatusEnum.ACTIVE
encoded = encode_checkpoint_value(status)
assert isinstance(encoded, dict)
assert _PICKLE_MARKER in encoded
decoded = decode_checkpoint_value(encoded)
assert decoded == StatusEnum.ACTIVE
assert type(decoded) is StatusEnum

custom_int = CustomInt(42)
encoded_int = encode_checkpoint_value(custom_int)
assert isinstance(encoded_int, dict)
assert _PICKLE_MARKER in encoded_int
decoded_int = decode_checkpoint_value(encoded_int)
assert decoded_int == 42
assert type(decoded_int) is CustomInt

custom_str = CustomStr("custom")
encoded_str = encode_checkpoint_value(custom_str)
assert isinstance(encoded_str, dict)
assert _PICKLE_MARKER in encoded_str
decoded_str = decode_checkpoint_value(encoded_str)
assert decoded_str == "custom"
assert type(decoded_str) is CustomStr


# --- Tests for collection encoding ---


Expand Down
Loading