diff --git a/src/google/adk/a2a/converters/to_adk_event.py b/src/google/adk/a2a/converters/to_adk_event.py index 26ae95e1b4..78a7969eaa 100644 --- a/src/google/adk/a2a/converters/to_adk_event.py +++ b/src/google/adk/a2a/converters/to_adk_event.py @@ -24,6 +24,7 @@ from a2a.types import Message from a2a.types import Part as A2APart +from a2a.types import Role as A2ARole from a2a.types import Task from a2a.types import TaskArtifactUpdateEvent from a2a.types import TaskState @@ -177,6 +178,7 @@ def _create_event( actions: Optional[EventActions] = None, long_running_function_ids: Optional[set[str]] = None, partial: bool = False, + content_role: str = "model", ) -> Optional[Event]: """Creates an ADK event from parts and metadata.""" event_actions = actions or EventActions() @@ -199,7 +201,7 @@ def _create_event( ), content=( genai_types.Content( - role="model", + role=content_role, parts=output_parts, ) if output_parts @@ -211,6 +213,13 @@ def _create_event( return event +def _a2a_role_to_content_role(role: Optional[A2ARole]) -> str: + """Maps an A2A Role to the corresponding GenAI content role.""" + if role == A2ARole.user: + return "user" + return "model" + + def _parse_adk_metadata_value(value: Any) -> Any: """Parses ADK metadata values serialized through A2A.""" if not isinstance(value, str): @@ -375,11 +384,13 @@ def convert_a2a_message_to_event( output_parts, _ = _convert_a2a_parts_to_adk_parts( a2a_message.parts, part_converter ) + content_role = _a2a_role_to_content_role(getattr(a2a_message, "role", None)) return _create_event( output_parts, invocation_context, author, _extract_event_actions(a2a_message.metadata), + content_role=content_role, ) except Exception as e: diff --git a/tests/unittests/a2a/converters/test_to_adk.py b/tests/unittests/a2a/converters/test_to_adk.py index 12eaf2a75a..16f9fe84ec 100644 --- a/tests/unittests/a2a/converters/test_to_adk.py +++ b/tests/unittests/a2a/converters/test_to_adk.py @@ -19,6 +19,7 @@ from a2a.types import Artifact from a2a.types import Message from a2a.types import Part as A2APart +from a2a.types import Role as A2ARole from a2a.types import Task from a2a.types import TaskArtifactUpdateEvent from a2a.types import TaskState @@ -418,3 +419,41 @@ def test_convert_a2a_artifact_update_to_event_none(self): """Test convert_a2a_artifact_update_to_event with None.""" with pytest.raises(ValueError, match="A2A artifact update cannot be None"): convert_a2a_artifact_update_to_event(None) + + def test_convert_a2a_message_to_event_user_role(self) -> None: + """Test that A2A user role maps to GenAI content role 'user'.""" + a2a_part = Mock(spec=A2APart) + a2a_part.root = Mock(spec=TextPart) + a2a_part.root.metadata = {} + message = Message(message_id="msg-1", role=A2ARole.user, parts=[a2a_part]) + + mock_genai_part = genai_types.Part.from_text(text="hello from user") + mock_part_converter = Mock(return_value=[mock_genai_part]) + + event = convert_a2a_message_to_event( + message, + author="user", + invocation_context=self.mock_context, + part_converter=mock_part_converter, + ) + + assert event.content.role == "user" + + def test_convert_a2a_message_to_event_agent_role(self) -> None: + """Test that A2A agent role maps to GenAI content role 'model'.""" + a2a_part = Mock(spec=A2APart) + a2a_part.root = Mock(spec=TextPart) + a2a_part.root.metadata = {} + message = Message(message_id="msg-1", role=A2ARole.agent, parts=[a2a_part]) + + mock_genai_part = genai_types.Part.from_text(text="hello from agent") + mock_part_converter = Mock(return_value=[mock_genai_part]) + + event = convert_a2a_message_to_event( + message, + author="test-agent", + invocation_context=self.mock_context, + part_converter=mock_part_converter, + ) + + assert event.content.role == "model"