Skip to main content
This page describes how Aion Server adapts A2A requests to Google ADK and maps ADK events back into A2A Messages, Tasks, and streaming events. This page uses the v1 canonical JSON-RPC method names. Aion ingress may continue to accept legacy slash-style aliases for compatibility.

1. Inbound Messages

1.1 Agent Invocation

Both SendMessage and SendStreamingMessage use the same execution path: the agent’s run_async() is always driven as an async event stream.
  • SendMessage (blocking=true) — collects all events and returns the final Task.
  • SendMessage (blocking=false) — returns after the first event, continues processing in background with status="working".
  • SendStreamingMessage — yields events as they arrive and streams them to the client via SSE.
Both methods use the same SendMessageRequest payload; only the response mode differs.

1.2 Part Type Mapping

Inbound A2A message parts are transformed into ADK Content as follows:
A2A PartADK Representation
Part(text=...)types.Part(text=...)
Part(raw=...)types.Part(inline_data=types.Blob(mime_type=..., data=...))
Part(url=...)types.Part(file_data=types.FileData(mime_type=..., file_uri=...))
Part(data=...)types.Part(text=json.dumps(data))
MIME type resolution order for file parts: explicit mime_type attribute → guess from filename → fallback to application/octet-stream. If the message contains no usable parts, the plain text input from the request is used as a fallback.

1.3 Accessing Inbound Context — ctx.a2a_inbox

When an inbound A2A Message arrives, Aion Server makes it available through ctx.a2a_inbox on the invocation context:
from google.adk.agents import BaseAgent


class MyAgent(BaseAgent):
    async def _run_async_impl(self, ctx):
        inbox = ctx.a2a_inbox
        task = inbox.task
        message = inbox.message
        metadata = inbox.metadata
a2a_inbox contains:
FieldTypeDescription
taskTaskThe current A2A Task
messageMessageThe full inbound A2A Message, including non-text parts
metadatadictSendMessageRequest-level metadata (distribution/network, trace info)

2. Outbound Messages

Valid responses to an A2A SendMessage call are a Message or a Task. Aion Server constructs the response using the following precedence:

(1) a2a_outbox (authoritative)

Set a2a_outbox in event.actions.state_delta to provide an explicit A2A response. It must be an A2AOutbox instance wrapping either a Message or a Task:
from a2a.types import Message, Task, Part, Role
from aion.shared.types import A2AOutbox
from google.adk.agents import BaseAgent
from google.adk.events import Event, EventActions


class MyAgent(BaseAgent):
    async def _run_async_impl(self, ctx):
        # Option 1: outbox as Message
        yield Event(
            author=self.name,
            actions=EventActions(state_delta={
                "a2a_outbox": A2AOutbox(message=Message(
                    role=Role.ROLE_AGENT,
                    parts=[Part(text="Done!")],
                ))
            })
        )

        # Option 2: outbox as Task (patch)
        yield Event(
            author=self.name,
            actions=EventActions(state_delta={
                "a2a_outbox": A2AOutbox(task=Task(
                    history=[...],
                    artifacts=[...],
                    metadata={"my_key": "my_value"},
                ))
            })
        )
Server-owned fields are enforced:
  • task_id and context_id are set to current values managed by Aion Server.
  • Canonical routing and identity metadata (e.g. aion:network, sender IDs) is server-controlled.
Behavior:
  • If a2a_outbox.message is set → append to current Task history.
  • If a2a_outbox.task is set → treat as a patch to the server’s Task: server merges or extends history and artifacts; provided metadata merges shallowly; server-controlled keys take precedence.

(2) Fallback: accumulated delta text

If no a2a_outbox is set and the stream ended while still in partial mode (no closing non-partial event followed), Aion Server emits the accumulated delta text as the final response message. This fallback only applies when the last event was partial and no non-partial event closed the stream.
If you need to return a comprehensive A2A response (e.g., data parts, rich metadata, multiple artifacts), use a2a_outbox rather than relying on the streaming fallback.

3. Summary

  • Read ctx.a2a_inbox to access the inbound A2A Task, Message, and metadata.
  • Optionally set a2a_outbox in event.actions.state_delta as an A2AOutbox instance for full-fidelity A2A responses.
  • Yield partial events for real-time text streaming.