Skip to content

fix: respect A2A Message.role in inbound event conversion#5224

Open
giulio-leone wants to merge 2 commits intogoogle:mainfrom
giulio-leone:fix/a2a-inbound-role-mapping
Open

fix: respect A2A Message.role in inbound event conversion#5224
giulio-leone wants to merge 2 commits intogoogle:mainfrom
giulio-leone:fix/a2a-inbound-role-mapping

Conversation

@giulio-leone
Copy link
Copy Markdown
Contributor

Summary

Fixes #5186.

convert_a2a_message_to_event() hard-coded role='model' on the GenAI Content it produced, ignoring the A2A Message.role field. This caused Role.user messages to be restored as model events.

Additionally, the task-history fallback in convert_a2a_task_to_event() (in event_converter.py) blindly took history[-1] without checking Message.role, so a trailing user message could be misattributed as agent output.

Root Cause

  • event_converter.py: Content(role="model", ...) was hard-coded in two places inside convert_a2a_message_to_event().
  • to_adk_event.py: _create_event() hard-coded role="model" with no way to override.
  • event_converter.py: convert_a2a_task_to_event() fallback path used a2a_task.history[-1] unconditionally.

Changes

File Change
converters/utils.py New a2a_role_to_genai_role() helper (Role.agent"model", Role.user"user")
converters/event_converter.py Use helper in convert_a2a_message_to_event(); filter history fallback to agent-role messages only
converters/to_adk_event.py Add role param to _create_event(); pass mapped role from convert_a2a_message_to_event()
test_event_converter.py Regression tests for role mapping + history fallback
test_to_adk.py Regression tests for role mapping
test_utils.py Unit tests for a2a_role_to_genai_role()

Testing

All 86 converter tests pass (test_event_converter.py, test_to_adk.py, test_utils.py).

@google-cla
Copy link
Copy Markdown

google-cla bot commented Apr 9, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@adk-bot
Copy link
Copy Markdown
Collaborator

adk-bot commented Apr 9, 2026

Response from ADK Triaging Agent

Hello @giulio-leone, thank you for creating this PR!

Before we can review your contribution, could you please sign our Contributor License Agreement (CLA)? You can find more information at https://cla.developers.google.com/.

Additionally, since this PR is a bug fix, could you please provide logs or a screenshot demonstrating that the fix is working as expected? This will help the reviewers to better understand and verify your changes.

Thank you!

@adk-bot adk-bot added the core [Component] This issue is related to the core interface and implementation label Apr 9, 2026
@giulio-leone
Copy link
Copy Markdown
Contributor Author

Added focused regression coverage for the fix:

  • test_event_converter.py: verifies Role.user is restored as user and that task-history fallback ignores trailing user messages
  • test_to_adk.py: verifies inbound event conversion preserves the mapped role
  • test_utils.py: verifies a2a_role_to_genai_role() mappings

Local result: 86 converter tests passed (test_event_converter.py, test_to_adk.py, test_utils.py).

This reproduces the original bug path and confirms that user-role messages are no longer misattributed as model output.

@rohityan
Copy link
Copy Markdown
Collaborator

Hi @giulio-leone , Thank you for your contribution! We appreciate you taking the time to submit this pull request.
Please fix formatting errors by running autoformat.sh

@rohityan rohityan added the request clarification [Status] The maintainer need clarification or more information from the author label Apr 13, 2026
convert_a2a_message_to_event() hard-coded role='model' on the GenAI
Content it produced, ignoring the A2A Message.role field. This caused
Role.user messages to be misattributed as model output.

Additionally, the task-history fallback in convert_a2a_task_to_event()
blindly took history[-1] without checking Message.role, so a trailing
user message could be restored as agent output.

Changes:
- Add a2a_role_to_genai_role() helper in utils.py (Role.agent→'model',
  Role.user→'user').
- event_converter.py: use the helper instead of hard-coded 'model' in
  convert_a2a_message_to_event(); filter history fallback to agent-role
  messages only.
- to_adk_event.py: add role parameter to _create_event(); pass mapped
  role from convert_a2a_message_to_event().
- Regression tests for role restoration and history fallback.
@giulio-leone giulio-leone force-pushed the fix/a2a-inbound-role-mapping branch from d39ec54 to 8cb01e3 Compare April 14, 2026 01:43
@giulio-leone
Copy link
Copy Markdown
Contributor Author

Rebased onto the current main, ran ./autoformat.sh, and kept the final diff scoped to the PR file (src/google/adk/a2a/converters/event_converter.py).

Local revalidation after the rebase:

  • isort --check on the 6 touched converter files
  • pyink --check --diff --config pyproject.toml on the same 6 files
  • PYTHONPATH=$PWD/src python -m pytest tests/unittests/a2a/converters/ → 154 passed

I also rechecked the role-conversion path locally to confirm the behavior is still intact after the formatting-only update: Role.user stays user, Role.agent stays model, and task-history fallback still ignores trailing user messages.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core [Component] This issue is related to the core interface and implementation request clarification [Status] The maintainer need clarification or more information from the author

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A2A inbound message conversion ignores Message.role, always maps to "model"

3 participants