Skip to content

Commit 139c700

Browse files
enjoykumawatharanrk
authored andcommitted
fix: preserve JSON-native types in A2A _serialize_value()
`_serialize_value()` in `from_adk_event.py` was calling `str()` on all non-Pydantic values, which corrupted JSON-native metadata types (`dict`, `list`, `int`, `float`, `bool`) into their Python string representations during A2A event conversion. Before: `{"count": 42}` became `{"count": "42"}` and `{"tags": ["a", "b"]}` became `{"tags": "['a', 'b']"}`. After: JSON-native types (`dict`, `list`, `int`, `float`, `bool`, `str`) are passed through as-is. Only non-JSON-serializable types (e.g. `datetime`) are still stringified. Closes #5183 Co-authored-by: Haran Rajkumar <haranrk@google.com> PiperOrigin-RevId: 934496131
1 parent ee79e71 commit 139c700

2 files changed

Lines changed: 53 additions & 0 deletions

File tree

src/google/adk/a2a/converters/from_adk_event.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,10 @@ def _serialize_value(value: Any) -> Optional[Any]:
259259
logger.warning("Failed to serialize Pydantic model, falling back: %s", e)
260260
return str(value)
261261

262+
# Pass through JSON-native types as-is
263+
if isinstance(value, (dict, list, int, float, bool, str)):
264+
return value
265+
262266
return str(value)
263267

264268

tests/unittests/a2a/converters/test_from_adk.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,3 +130,52 @@ def test_convert_event_to_a2a_events_with_actions(self):
130130
metadata = result[0].status.message.metadata
131131
assert "adk_actions" in metadata
132132
assert metadata["adk_actions"]["artifactDelta"] == {"image": 0}
133+
134+
135+
class TestSerializeValue:
136+
"""Tests for _serialize_value preserving JSON-native types."""
137+
138+
def setup_method(self) -> None:
139+
from google.adk.a2a.converters.from_adk_event import _serialize_value
140+
141+
self.serialize = _serialize_value
142+
143+
def test_dict_preserved(self) -> None:
144+
value = {"key": "val", "nested": {"a": 1}}
145+
result = self.serialize(value)
146+
assert result == value
147+
assert isinstance(result, dict)
148+
149+
def test_list_preserved(self) -> None:
150+
value = [1, "two", {"three": 3}]
151+
result = self.serialize(value)
152+
assert result == value
153+
assert isinstance(result, list)
154+
155+
def test_int_preserved(self) -> None:
156+
result = self.serialize(42)
157+
assert result == 42
158+
assert isinstance(result, int)
159+
160+
def test_float_preserved(self) -> None:
161+
result = self.serialize(3.14)
162+
assert result == 3.14
163+
assert isinstance(result, float)
164+
165+
def test_bool_preserved(self) -> None:
166+
assert self.serialize(True) is True
167+
assert self.serialize(False) is False
168+
169+
def test_string_preserved(self) -> None:
170+
assert self.serialize("hello") == "hello"
171+
172+
def test_none_returns_none(self) -> None:
173+
assert self.serialize(None) is None
174+
175+
def test_non_json_type_stringified(self) -> None:
176+
"""Non-JSON-native types should still be converted to str."""
177+
from datetime import datetime
178+
179+
dt = datetime(2025, 1, 1)
180+
result = self.serialize(dt)
181+
assert isinstance(result, str)

0 commit comments

Comments
 (0)