From 7ef9c0908ffdbdb956b7078f66641fd723f76e12 Mon Sep 17 00:00:00 2001 From: Yizuki_Ame Date: Tue, 7 Apr 2026 02:57:50 +0800 Subject: [PATCH] Fix A2A metadata round-trip serialization Signed-off-by: Yizuki_Ame --- .../adk/a2a/converters/from_adk_event.py | 9 ++++ .../a2a/converters/test_event_round_trip.py | 42 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/google/adk/a2a/converters/from_adk_event.py b/src/google/adk/a2a/converters/from_adk_event.py index 05bf16d167..36f916a6af 100644 --- a/src/google/adk/a2a/converters/from_adk_event.py +++ b/src/google/adk/a2a/converters/from_adk_event.py @@ -17,6 +17,7 @@ from collections.abc import Callable from datetime import datetime from datetime import timezone +import json import logging from typing import Any from typing import Dict @@ -249,6 +250,14 @@ def _serialize_value(value: Any) -> Optional[Any]: logger.warning("Failed to serialize Pydantic model, falling back: %s", e) return str(value) + if isinstance(value, (dict, list, str, bool, int, float)): + return value + + try: + return json.loads(json.dumps(value)) + except (TypeError, ValueError): + pass + return str(value) diff --git a/tests/unittests/a2a/converters/test_event_round_trip.py b/tests/unittests/a2a/converters/test_event_round_trip.py index 00036f6af7..2c50015bfc 100644 --- a/tests/unittests/a2a/converters/test_event_round_trip.py +++ b/tests/unittests/a2a/converters/test_event_round_trip.py @@ -23,8 +23,10 @@ from a2a.types import TaskStatusUpdateEvent from google.adk.a2a.converters.from_adk_event import convert_event_to_a2a_events from google.adk.a2a.converters.from_adk_event import create_error_status_event +from google.adk.a2a.converters.to_adk_event import _parse_adk_metadata_value from google.adk.a2a.converters.to_adk_event import convert_a2a_artifact_update_to_event from google.adk.a2a.converters.to_adk_event import convert_a2a_status_update_to_event +from google.adk.a2a.converters.utils import _get_adk_metadata_key from google.adk.agents.invocation_context import InvocationContext from google.adk.events.event import Event from google.genai import types as genai_types @@ -206,3 +208,43 @@ def test_round_trip_function_response_event(): assert restored_event.content.parts[0].function_response.response == { "result": "success" } + + +def test_round_trip_custom_metadata_preserves_structured_values(): + original_custom_metadata = { + "flag": True, + "count": 42, + "nested": {"key": "val"}, + "tags": ["a", "b"], + } + original_event = Event( + invocation_id="test_invocation", + author="test_agent", + branch="main", + content=genai_types.Content( + role="model", + parts=[genai_types.Part.from_text(text="Hello world!")], + ), + custom_metadata=original_custom_metadata, + ) + agents_artifacts: Dict[str, str] = {} + + a2a_events = convert_event_to_a2a_events( + event=original_event, + agents_artifacts=agents_artifacts, + task_id="task1", + context_id="context1", + ) + + assert len(a2a_events) == 1 + a2a_event = a2a_events[0] + assert isinstance(a2a_event, TaskArtifactUpdateEvent) + + serialized_metadata = a2a_event.artifact.metadata[ + _get_adk_metadata_key("custom_metadata") + ] + + assert not isinstance(serialized_metadata, str) + assert ( + _parse_adk_metadata_value(serialized_metadata) == original_custom_metadata + )