Skip to content

Commit ec8a49e

Browse files
committed
fix: map A2A Message.role to correct GenAI content role
convert_a2a_message_to_event() hard-coded role="model" for all resulting ADK events regardless of the original A2A Message.role. User messages (Role.user) were incorrectly restored as model events. Add _a2a_role_to_content_role() helper that maps A2A Role.user to "user" and Role.agent to "model", and pass the mapped role through _create_event() via a new content_role parameter. Fixes #5186
1 parent b0715d7 commit ec8a49e

2 files changed

Lines changed: 57 additions & 1 deletion

File tree

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
from a2a.types import Message
2626
from a2a.types import Part as A2APart
27+
from a2a.types import Role as A2ARole
2728
from a2a.types import Task
2829
from a2a.types import TaskArtifactUpdateEvent
2930
from a2a.types import TaskState
@@ -177,6 +178,7 @@ def _create_event(
177178
actions: Optional[EventActions] = None,
178179
long_running_function_ids: Optional[set[str]] = None,
179180
partial: bool = False,
181+
content_role: str = "model",
180182
) -> Optional[Event]:
181183
"""Creates an ADK event from parts and metadata."""
182184
event_actions = actions or EventActions()
@@ -199,7 +201,7 @@ def _create_event(
199201
),
200202
content=(
201203
genai_types.Content(
202-
role="model",
204+
role=content_role,
203205
parts=output_parts,
204206
)
205207
if output_parts
@@ -211,6 +213,13 @@ def _create_event(
211213
return event
212214

213215

216+
def _a2a_role_to_content_role(role: Optional[A2ARole]) -> str:
217+
"""Maps an A2A Role to the corresponding GenAI content role."""
218+
if role == A2ARole.user:
219+
return "user"
220+
return "model"
221+
222+
214223
def _parse_adk_metadata_value(value: Any) -> Any:
215224
"""Parses ADK metadata values serialized through A2A."""
216225
if not isinstance(value, str):
@@ -375,11 +384,15 @@ def convert_a2a_message_to_event(
375384
output_parts, _ = _convert_a2a_parts_to_adk_parts(
376385
a2a_message.parts, part_converter
377386
)
387+
content_role = _a2a_role_to_content_role(
388+
getattr(a2a_message, "role", None)
389+
)
378390
return _create_event(
379391
output_parts,
380392
invocation_context,
381393
author,
382394
_extract_event_actions(a2a_message.metadata),
395+
content_role=content_role,
383396
)
384397

385398
except Exception as e:

tests/unittests/a2a/converters/test_to_adk.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from a2a.types import Artifact
2020
from a2a.types import Message
2121
from a2a.types import Part as A2APart
22+
from a2a.types import Role as A2ARole
2223
from a2a.types import Task
2324
from a2a.types import TaskArtifactUpdateEvent
2425
from a2a.types import TaskState
@@ -418,3 +419,45 @@ def test_convert_a2a_artifact_update_to_event_none(self):
418419
"""Test convert_a2a_artifact_update_to_event with None."""
419420
with pytest.raises(ValueError, match="A2A artifact update cannot be None"):
420421
convert_a2a_artifact_update_to_event(None)
422+
423+
def test_convert_a2a_message_to_event_user_role(self):
424+
"""Test that A2A user role maps to GenAI content role 'user'."""
425+
a2a_part = Mock(spec=A2APart)
426+
a2a_part.root = Mock(spec=TextPart)
427+
a2a_part.root.metadata = {}
428+
message = Message(
429+
message_id="msg-1", role=A2ARole.user, parts=[a2a_part]
430+
)
431+
432+
mock_genai_part = genai_types.Part.from_text(text="hello from user")
433+
mock_part_converter = Mock(return_value=[mock_genai_part])
434+
435+
event = convert_a2a_message_to_event(
436+
message,
437+
author="user",
438+
invocation_context=self.mock_context,
439+
part_converter=mock_part_converter,
440+
)
441+
442+
assert event.content.role == "user"
443+
444+
def test_convert_a2a_message_to_event_agent_role(self):
445+
"""Test that A2A agent role maps to GenAI content role 'model'."""
446+
a2a_part = Mock(spec=A2APart)
447+
a2a_part.root = Mock(spec=TextPart)
448+
a2a_part.root.metadata = {}
449+
message = Message(
450+
message_id="msg-1", role=A2ARole.agent, parts=[a2a_part]
451+
)
452+
453+
mock_genai_part = genai_types.Part.from_text(text="hello from agent")
454+
mock_part_converter = Mock(return_value=[mock_genai_part])
455+
456+
event = convert_a2a_message_to_event(
457+
message,
458+
author="test-agent",
459+
invocation_context=self.mock_context,
460+
part_converter=mock_part_converter,
461+
)
462+
463+
assert event.content.role == "model"

0 commit comments

Comments
 (0)