Skip to content

Commit 1cc0ffc

Browse files
committed
fix: safe encode json events
1 parent 34375ab commit 1cc0ffc

File tree

1 file changed

+50
-2
lines changed

1 file changed

+50
-2
lines changed

python-sdk/ag_ui/encoder/encoder.py

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
"""
22
This module contains the EventEncoder class
33
"""
4-
4+
from typing import Any
5+
import json
56
from ag_ui.core.events import BaseEvent
67

78
AGUI_MEDIA_TYPE = "application/vnd.ag-ui.event+proto"
@@ -25,8 +26,55 @@ def encode(self, event: BaseEvent) -> str:
2526
"""
2627
return self._encode_sse(event)
2728

29+
def make_json_safe(self, value: Any) -> Any:
30+
"""
31+
Recursively convert a value into a JSON-serializable structure.
32+
33+
- Handles Pydantic models via `model_dump`.
34+
- Handles LangChain messages via `to_dict`.
35+
- Recursively walks dicts, lists, and tuples.
36+
- For arbitrary objects, falls back to `__dict__` if available, else `repr()`.
37+
"""
38+
# Pydantic models
39+
if hasattr(value, "model_dump"):
40+
try:
41+
return self.make_json_safe(value.model_dump(by_alias=True, exclude_none=True))
42+
except Exception:
43+
pass
44+
45+
# LangChain-style objects
46+
if hasattr(value, "to_dict"):
47+
try:
48+
return self.make_json_safe(value.to_dict())
49+
except Exception:
50+
pass
51+
52+
# Dict
53+
if isinstance(value, dict):
54+
return {key: self.make_json_safe(sub_value) for key, sub_value in value.items()}
55+
56+
# List / tuple
57+
if isinstance(value, (list, tuple)):
58+
return [self.make_json_safe(sub_value) for sub_value in value]
59+
60+
# Already JSON safe
61+
if isinstance(value, (str, int, float, bool)) or value is None:
62+
return value
63+
64+
# Arbitrary object: try __dict__ first, fallback to repr
65+
if hasattr(value, "__dict__"):
66+
return {
67+
"__type__": type(value).__name__,
68+
**self.make_json_safe(value.__dict__),
69+
}
70+
71+
return repr(value)
72+
2873
def _encode_sse(self, event: BaseEvent) -> str:
2974
"""
3075
Encodes an event into an SSE string.
3176
"""
32-
return f"data: {event.model_dump_json(by_alias=True, exclude_none=True)}\n\n"
77+
event_dict = event.model_dump(by_alias=True, exclude_none=True)
78+
json_ready = self.make_json_safe(event_dict)
79+
json_string = json.dumps(json_ready)
80+
return f"data: {json_string}\n\n"

0 commit comments

Comments
 (0)