You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
a2a: donkey.serve() — an A2A listener in one line, wrapping the official a2a-sdk #224
The Omni Gateway / Agent Fabric roadmap includes an A2A Bridge item — turning
Microsoft Copilot agents into A2A-compatible assets. That surfaces a gap in how
A2A is scoped across this issue and BG §2.9, and it is worth settling before
this one is implemented rather than after.
BG §2.9 and this issue cover the SDK as an A2A server: serve(), expose,
and the local dev loop. Nothing in the build guide covers the SDK as an A2A client — consuming a remote A2A agent as a tool inside your own graph.
If the platform is about to make a population of Copilot agents reachable over
A2A, the consumption side becomes the more commonly exercised direction. A
developer's likely first question is not "how do I publish my agent" but "how do
I call the one the platform just published", and the answer today is that they
write their own A2A client and lose every governance property the skeleton
provides — no correlation ID propagation, no attribution headers, no typed
refusals, no budget observation.
That is the inverse of what this issue builds, and it reuses the same card
generation and the same a2a-sdk dependency — so it is a sibling, not a rewrite.
What I am asking for, not asserting
I have not filed an issue for this and have not changed this issue's
scope. Three possible resolutions, and the call belongs to whoever owns A2A here:
It is in scope and needs its own issue plus a BG §2.9 amendment.
It is deliberately out of scope, in which case the reason belongs in the build
guide so it is a recorded decision rather than an omission.
Whichever it is, the hard rule on this issue still governs: wrap the official a2a-sdk, never reimplement the protocol. That applies identically to a client.
Raised while triaging the platform roadmap against the backlog; no code touched.
changed the title [-]a2a: fabric.serve() — an A2A listener in one line, wrapping the official a2a-sdk[/-][+]a2a: donkey.serve() — an A2A listener in one line, wrapping the official a2a-sdk[/+]on Sep 11, 2026
Packaging note: #744 removes the a2a extra from 0.1.x because no code uses it yet. When this lands, add it back in the same change (a2a = ["a2a-sdk>=…"], plus a2a in [all]) so pip install "donkey-kit[a2a]", which website/content/tool-access/a2a.mdx already tells users to run, works again.
Verified against the installed a2a-sdk (§0.3). The class names below were read from a2a-sdk 1.2.3. A throwaway spike served a card and completed a task for a raw JSON-RPC SendMessage with no SDK on the caller side, on 1.0.3, 1.1.0, 1.2.0 and 1.2.3. 1.0.0 fails to import without grpc; 1.0.1–1.0.2 lack a2a.helpers.new_text_part. Floor: a2a-sdk[http-server]>=1.0.3.
Wrapped, never reimplemented: AgentExecutor, DefaultRequestHandler, InMemoryTaskStore, TaskUpdater, create_agent_card_routes, create_jsonrpc_routes, a2a.types.AgentCard, served by uvicorn on Starlette.
Surface
@donkey.agent(name="support-triage", skills=["triage", "draft-reply"])asyncdefhandle(task: A2ATask) ->A2AResult|str: ...
donkey.serve(handle) # blocks; 127.0.0.1:8000app=donkey_kit.a2a.build_app(handle) # the same server as an ASGI app, for tests or your own server
A2ATask / A2AResult: frozen dataclasses (ADR 0001) in donkey_kit.a2a, exported top-level. task.input is the text parts joined; task.data holds the data parts; task.message is the native a2aMessage for anything else.
Return str → text artifact, A2AResult(text=, data=) → text and/or data artifacts. Sync handlers run in a worker thread.
The card comes only from the @donkey.agent record (AgentSpec): name, docstring, skills. An unmarked handler raises TypeError that says to add the marker.
host="127.0.0.1" by default; url= sets the card's interface URL when a gateway fronts the agent; version= the card version.
New [a2a] extra (a2a-sdk[http-server]>=1.0.3, uvicorn>=0.30), added to [all] as noted above. The dependency_allowlist.toml entry and the verified-apis.md floor row ship in the same PR.
New top-level package donkey_kit/a2a/, placed beside integrations in the layers contract (integrations | a2a), which takes an ADR (0014). import donkey_kit never loads a2a-sdk; a missing extra raises the curated pip install "donkey-kit[a2a]" ImportError.
CI: the test matrix installs [a2a]; the constraint locks are regenerated with scripts/compile_constraints.py.
Docs
website/content/a2a.mdx gains a "Why not call the a2a-sdk directly?" table (raw a2a-sdk vs donkey.serve()), with each row marked as shipping now or as #225 (inbound correlation/spans, typed refusals). serve moves off "planned".
Out of scope, as the issue says: governed inbound (#225), expose (#226), dev (#227). The A2A client side raised above is already planned as AgentHandle.as_tool() (website/content/tool-access/a2a.mdx).
Activity
amirkhan-ak-sf commentedon Sep 9, 2026
Scope question raised by the platform roadmap
The Omni Gateway / Agent Fabric roadmap includes an A2A Bridge item — turning
Microsoft Copilot agents into A2A-compatible assets. That surfaces a gap in how
A2A is scoped across this issue and
BG §2.9, and it is worth settling beforethis one is implemented rather than after.
BG §2.9and this issue cover the SDK as an A2A server:serve(),expose,and the local dev loop. Nothing in the build guide covers the SDK as an A2A
client — consuming a remote A2A agent as a tool inside your own graph.
If the platform is about to make a population of Copilot agents reachable over
A2A, the consumption side becomes the more commonly exercised direction. A
developer's likely first question is not "how do I publish my agent" but "how do
I call the one the platform just published", and the answer today is that they
write their own A2A client and lose every governance property the skeleton
provides — no correlation ID propagation, no attribution headers, no typed
refusals, no budget observation.
Concretely, the missing shape is something like:
That is the inverse of what this issue builds, and it reuses the same card
generation and the same
a2a-sdkdependency — so it is a sibling, not a rewrite.What I am asking for, not asserting
I have not filed an issue for this and have not changed this issue's
scope. Three possible resolutions, and the call belongs to whoever owns A2A here:
BG §2.9amendment.guide so it is a recorded decision rather than an omission.
Whichever it is, the hard rule on this issue still governs: wrap the official
a2a-sdk, never reimplement the protocol. That applies identically to a client.Raised while triaging the platform roadmap against the backlog; no code touched.
[-]a2a: fabric.serve() — an A2A listener in one line, wrapping the official a2a-sdk[/-][+]a2a: donkey.serve() — an A2A listener in one line, wrapping the official a2a-sdk[/+]tbolis-at-mulesoft commentedon Oct 3, 2026
Packaging note: #744 removes the
a2aextra from 0.1.x because no code uses it yet. When this lands, add it back in the same change (a2a = ["a2a-sdk>=…"], plusa2ain[all]) sopip install "donkey-kit[a2a]", whichwebsite/content/tool-access/a2a.mdxalready tells users to run, works again.tbolis-at-mulesoft commentedon Oct 24, 2026
Implementation plan
Verified against the installed
a2a-sdk(§0.3). The class names below were read froma2a-sdk1.2.3. A throwaway spike served a card and completed a task for a raw JSON-RPCSendMessagewith no SDK on the caller side, on 1.0.3, 1.1.0, 1.2.0 and 1.2.3. 1.0.0 fails to import withoutgrpc; 1.0.1–1.0.2 lacka2a.helpers.new_text_part. Floor:a2a-sdk[http-server]>=1.0.3.Wrapped, never reimplemented:
AgentExecutor,DefaultRequestHandler,InMemoryTaskStore,TaskUpdater,create_agent_card_routes,create_jsonrpc_routes,a2a.types.AgentCard, served byuvicornon Starlette.Surface
A2ATask/A2AResult: frozen dataclasses (ADR 0001) indonkey_kit.a2a, exported top-level.task.inputis the text parts joined;task.dataholds the data parts;task.messageis the nativea2aMessagefor anything else.str→ text artifact,A2AResult(text=, data=)→ text and/or data artifacts. Sync handlers run in a worker thread.@donkey.agentrecord (AgentSpec): name, docstring, skills. An unmarked handler raisesTypeErrorthat says to add the marker.host="127.0.0.1"by default;url=sets the card's interface URL when a gateway fronts the agent;version=the card version.Packaging & architecture
[a2a]extra (a2a-sdk[http-server]>=1.0.3,uvicorn>=0.30), added to[all]as noted above. Thedependency_allowlist.tomlentry and theverified-apis.mdfloor row ship in the same PR.donkey_kit/a2a/, placed besideintegrationsin the layers contract (integrations | a2a), which takes an ADR (0014).import donkey_kitnever loadsa2a-sdk; a missing extra raises the curatedpip install "donkey-kit[a2a]"ImportError.testmatrix installs[a2a]; the constraint locks are regenerated withscripts/compile_constraints.py.Docs
website/content/a2a.mdxgains a "Why not call the a2a-sdk directly?" table (raw a2a-sdk vsdonkey.serve()), with each row marked as shipping now or as #225 (inbound correlation/spans, typed refusals).servemoves off "planned".Out of scope, as the issue says: governed inbound (#225),
expose(#226),dev(#227). The A2A client side raised above is already planned asAgentHandle.as_tool()(website/content/tool-access/a2a.mdx).