Skip to content

Python: add agent-framework-hosting-a2a channel#6306

Open
eavanvalkenburg wants to merge 1 commit into
microsoft:feature/python-hostingfrom
eavanvalkenburg:feat/hosting-channel-a2a
Open

Python: add agent-framework-hosting-a2a channel#6306
eavanvalkenburg wants to merge 1 commit into
microsoft:feature/python-hostingfrom
eavanvalkenburg:feat/hosting-channel-a2a

Conversation

@eavanvalkenburg
Copy link
Copy Markdown
Member

Motivation and Context

Part of the hosting channels work tracked in #6265.

The host can already expose its target (an agent or workflow) over several channels (Activity protocol, Telegram, Discord, Teams, Responses). This adds a channel that exposes the same target as a peer agent over the Agent-to-Agent (A2A) protocol, so A2A clients can discover and call the hosted agent/workflow.

Description

Adds the agent-framework-hosting-a2a package providing A2AChannel:

  • Serves an A2A agent card (default derived from the host target's name/description) plus JSON-RPC routes on the host's ASGI app.
  • Handles requests with a host-routed HostAgentExecutor that drives the host pipeline (ChannelContext.run / run_stream) rather than wrapping the target directly, so sessions, cross-channel linking, and run/response hooks all apply.
  • Maps the A2A context id to a ChannelSession isolation key and the caller to a ChannelIdentity. Non-streaming runs publish reply messages as task status updates; streaming runs publish incremental task artifacts.

Includes unit tests, a README, and workspace registration in the root pyproject.toml/uv.lock.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • All unit tests pass, and I have added new tests where possible
  • Is this a breaking change? If yes, add "[BREAKING]" prefix to the title of the PR.

@moonbox3 moonbox3 added documentation Improvements or additions to documentation python labels Jun 3, 2026
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated Code Review

Reviewers: 3 | Confidence: 83%

✓ Correctness

The _exact_path_route utility properly handles the Starlette trailing-slash redirect issue for mounted root routes. The Telegram _is_echo_payload function correctly identifies mirrored user turns for silent notification delivery, and _send already accepts **extra kwargs. The Discord _commands type change from set to tuple is a valid fix (set is not a Sequence). The delete_webhook_on_shutdown flag and the channel route refactoring (contributing Route('/') and relying on the host mount path) are consistent and well-tested. One minor documentation inconsistency remains in the ResponsesChannel class docstring.

✓ Security Reliability

The A2A channel implementation is well-structured and follows existing patterns. Two security concerns: (1) the A2A executor sends raw exception messages to clients, risking information disclosure of internal details; (2) the new push method in the Activity Protocol channel makes authenticated HTTP requests to a URL extracted from identity attributes without validating it against the channel's existing service-URL allow-list, creating a defense-in-depth gap.

✓ Test Coverage

The new hosting-a2a package has good coverage of the happy paths (non-streaming execute, streaming execute, content conversion, agent card construction, route contribution). However, several meaningful behavioral branches in HostAgentExecutor lack tests: the cancel method, the error/failure path in execute, and the non-streaming path when deliver_response returns False. The activity protocol channel changes have excellent test coverage including edge cases for commands, push, identity, and the non-edit-channel buffer path.


Automated review by eavanvalkenburg's agents

logger.exception("A2AChannel encountered an error during execution.")
await updater.update_status(
state=TaskState.TASK_STATE_FAILED,
message=updater.new_agent_message([Part(text=str(exc))]),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security: str(exc) is sent directly to the A2A client. If an unexpected internal exception occurs (database error, file-system error, credential failure, etc.), the raw message may leak sensitive details like file paths, hostnames, or connection strings. The exception is already logged on line 147 via logger.exception. Consider returning a generic message to the client instead.

Suggested change
message=updater.new_agent_message([Part(text=str(exc))]),
message=updater.new_agent_message([Part(text="Internal error during execution")]),



if __name__ == "__main__":
pytest.main([__file__, "-v"])
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing test coverage for HostAgentExecutor.cancel() (line 113 of _executor.py). This public method validates context_id and publishes a TASK_STATE_CANCELED event — consider adding a test similar to test_execute_requires_context_id that also verifies the cancel event is emitted.

Also missing: a test for the execute error/failure path. When self._ctx.run(request) raises an exception, the executor catches it and sets TASK_STATE_FAILED with the error message (lines 143–148 of _executor.py). A test with a _FakeContext whose run raises would verify this important behavior.

assert request.channel == "a2a"
assert request.input == "hello"
assert request.session is not None
assert request.session.isolation_key == "conv-1"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The non-streaming _run path has an early return when deliver_response returns False (line 161 of _executor.py), meaning no working-state messages are published to A2A. This branch is untested — _FakeContext always uses deliver=True. Consider adding a test with _FakeContext(deliver=False, reply="ignored") and asserting that no TASK_STATE_WORKING status events appear in the queue.

Add a hosting channel that exposes the host target (agent or workflow)
as a peer agent over the Agent-to-Agent (A2A) protocol (JSON-RPC plus a
served agent card). Requests are handled by a host-routed
HostAgentExecutor that drives the host pipeline (ChannelContext.run/
run_stream) instead of wrapping the target directly, so sessions,
linking, and run/response hooks apply. Maps the A2A conversation/context
id to a ChannelSession isolation key and the caller to a ChannelIdentity;
streaming emits incremental task artifacts.

Includes tests, README, and workspace registration.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@eavanvalkenburg eavanvalkenburg force-pushed the feat/hosting-channel-a2a branch from e1820a4 to b79c359 Compare June 3, 2026 14:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants