From 667a8a1a4cf3bb2e95ad2a00139558cab25d53fd Mon Sep 17 00:00:00 2001 From: danieldutu Date: Fri, 23 Oct 2026 22:18:42 +0300 Subject: [PATCH] fix(a2a): keep metadata-only messages in convert_a2a_message_to_event A2A message with parts=[] and adk_custom_metadata came back as None (1 of 1 repro runs on f08f9d67). The peer's custom_metadata, usage_metadata, error_code, grounding_metadata and citation_metadata were lost. _create_event (to_adk_event.py:215-220) returns None when there are no parts and no actions. convert_a2a_message_to_event extracted the metadata fields but never told _create_event that they count as content. The message converter now passes allow_empty_event=True when any extracted metadata field is set. The event keeps content=None. The task and status update converters are unchanged: test_contentless_progress_does_not_emit_a_final_response requires metadata-only progress to stay dropped on those paths. Evidence: the new test fails on main (1 failed, 97 passed) and passes with the change (98 passed). tests/unittests/a2a: 949 passed, 57 skipped. Fixes #5185 --- src/google/adk/a2a/converters/to_adk_event.py | 1 + tests/unittests/a2a/converters/test_to_adk.py | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/google/adk/a2a/converters/to_adk_event.py b/src/google/adk/a2a/converters/to_adk_event.py index 46cf2b46eec..9b5a3f8f684 100644 --- a/src/google/adk/a2a/converters/to_adk_event.py +++ b/src/google/adk/a2a/converters/to_adk_event.py @@ -661,6 +661,7 @@ def convert_a2a_message_to_event( _extract_event_actions(a2a_message.metadata), long_running_function_ids, content_role=content_role, + allow_empty_event=any(metadata_fields.values()), **metadata_fields, ) diff --git a/tests/unittests/a2a/converters/test_to_adk.py b/tests/unittests/a2a/converters/test_to_adk.py index 85ddafb6831..541d52063d5 100644 --- a/tests/unittests/a2a/converters/test_to_adk.py +++ b/tests/unittests/a2a/converters/test_to_adk.py @@ -191,6 +191,26 @@ def test_convert_a2a_message_to_event_returns_action_only_event(self): assert event.actions.escalate is True assert event.content is None + def test_convert_a2a_message_to_event_returns_metadata_only_event(self): + """Test A2A message conversion keeps events with only custom metadata.""" + message = Message( + message_id="msg-1", + role=_compat.ROLE_AGENT, + parts=[], + metadata={_get_adk_metadata_key("custom_metadata"): {"flag": True}}, + ) + + event = convert_a2a_message_to_event( + message, + author="test-author", + invocation_context=self.mock_context, + part_converter=Mock(), + ) + + assert event is not None + assert event.custom_metadata == {"flag": True} + assert event.content is None + def test_convert_a2a_task_to_event_success(self): """Test successful conversion of A2A task to Event.""" a2a_part = _make_a2a_part_for_test({})