Skip to content

Commit 1d9c102

Browse files
fix: properly serialize DictState in state manager (#18)
1 parent 58c0d92 commit 1d9c102

File tree

4 files changed

+17
-6
lines changed

4 files changed

+17
-6
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ dev = [
1212

1313
[project]
1414
name = "llama-index-workflows"
15-
version = "1.0.0"
15+
version = "1.0.1"
1616
description = "An event-driven, async-first, step-based way to control the execution flow of AI applications like Agents."
1717
readme = "README.md"
1818
license = "MIT"

src/workflows/context/state_store.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,10 @@ def to_dict(self, serializer: "BaseSerializer") -> dict[str, Any]:
109109
For DictState, uses the BaseSerializer for individual items since they can be arbitrary types.
110110
For other Pydantic models, leverages Pydantic's serialization but uses BaseSerializer for complex types.
111111
"""
112-
state_dict = self._state.model_dump()
113-
114112
# Special handling for DictState - serialize each item in _data
115113
if isinstance(self._state, DictState):
116114
serialized_data = {}
117-
for key, value in state_dict.get("_data", {}).items():
115+
for key, value in self._state.items():
118116
try:
119117
serialized_data[key] = serializer.serialize(value)
120118
except Exception as e:

tests/test_state_manager.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ def __init__(self, name: str):
1717
self.name = name
1818

1919

20+
class PydanticObject(BaseModel):
21+
name: str
22+
23+
2024
class MyState(BaseModel):
2125
model_config = ConfigDict(
2226
arbitrary_types_allowed=True,
@@ -25,6 +29,7 @@ class MyState(BaseModel):
2529
)
2630

2731
my_obj: MyRandomObject
32+
pydantic_obj: PydanticObject
2833
name: str
2934
age: int
3035

@@ -53,6 +58,7 @@ def custom_state_manager() -> InMemoryStateStore[MyState]:
5358
return InMemoryStateStore(
5459
MyState(
5560
my_obj=MyRandomObject("llama-index"),
61+
pydantic_obj=PydanticObject(name="llama-index"),
5662
name="John",
5763
age=30,
5864
)
@@ -113,7 +119,10 @@ async def test_custom_state_manager(
113119
custom_state_manager: InMemoryStateStore[MyState],
114120
) -> None:
115121
assert (await custom_state_manager.get_state()).model_dump(mode="json") == MyState(
116-
my_obj=MyRandomObject("llama-index"), name="John", age=30
122+
my_obj=MyRandomObject("llama-index"),
123+
pydantic_obj=PydanticObject(name="llama-index"),
124+
name="John",
125+
age=30,
117126
).model_dump(mode="json")
118127

119128
await custom_state_manager.set("name", "Jane")
@@ -127,6 +136,7 @@ async def test_custom_state_manager(
127136
assert full_state.name == "Jane"
128137
assert full_state.age == 25
129138
assert full_state.my_obj.name == "llama-index"
139+
assert full_state.pydantic_obj.name == "llama-index"
130140

131141
# Ensure pydantic is providing type safety
132142
with pytest.raises(ValidationError):
@@ -155,3 +165,6 @@ async def test_state_manager_custom_serialization(
155165
assert await new_state_manager.get("age") == 25
156166

157167
assert (await new_state_manager.get("my_obj")).name == "llama-index"
168+
169+
state = await new_state_manager.get_state()
170+
assert state.pydantic_obj.name == "llama-index"

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)