A2A interoperability profile
A2A interoperability profile for Q integrations.
Q supports A2A 1.0 JSON-RPC, qualified locally with the official Python SDK 1.2.2. The hosted profile is off by default (A2A_SERVER_PROFILE_ENABLED=false). It requires the agent_api tenant feature, migrated PostgreSQL, Temporal workers and an existing Q agent with an authorised workspace. See durable runs, authentication and ADR 0030.
Discover and call
For an agent created through Q's existing agent API:
- Agent base URL:
https://q.example/v1/a2a/agents/{agent_id}. - Authenticated card:
GET {agent-base}/.well-known/agent-card.json. Returns one standard AgentCard; use itssupportedInterfacesentry forJSONRPC, protocol1.0. - RPC:
POST {agent-base}/rpc,Content-Type: application/json,A2A-Version: 1.0andAuthorization: Bearer ….
Credentials always need ai:answer, plus a2a:read for discovery/get/list/subscribe or a2a:delegate for send/cancel. Corresponding wildcard scopes are accepted. Agent workspace and current evidence grants are independently checked; scopes alone do not grant another principal's task. The card does not claim OAuth credential issuance. Provision scoped credentials through Q's existing authentication system.
Executable official-client example: install Q's locked environment (or a2a-sdk==1.2.2 in your own client environment), set Q_A2A_AGENT_URL and Q_API_KEY, then run python examples/a2a/client.py. Supply and retain Q_A2A_MESSAGE_ID to recover an uncertain submission. The example uses synthetic input but calls the configured real agent when run against a live deployment.
Operations and recovery
| Operation | Behaviour |
|---|---|
SendMessage | Text message creates a durable run. configuration.returnImmediately=true returns its current task; the default waits for completion or interruption, subject to the HTTP wait limit. |
SendStreamingMessage | First event is a Task snapshot, then ordered status/artifact updates. A completed artifact precedes its completed status event. |
GetTask | Reads authoritative committed state, optional message history and verified final text artifacts. |
ListTasks | Principal/agent scoped; context/status/time filters; most recent status first; opaque cursor pages, up to 100 tasks. Artifacts are omitted unless requested. |
CancelTask | Persists cancellation and notifies the durable workflow. Terminal tasks return TaskNotCancelableError; recover their state with GetTask. |
SubscribeToTask | Starts with the current authorised snapshot for a non-terminal task, then observes changes. Terminal tasks return UnsupportedOperationError; use GetTask. |
Retain message.messageId before submitting. Its identity is scoped to tenant, principal and agent. Repeating the same message recovers the same run; changing its content under the same ID fails. Q commits the accepted run before dispatch; an uncertain Temporal submission is reconciled with the saved workflow identity. Neither a lost HTTP response nor a disconnected stream authorises a second run. The JSON-RPC request ID correlates a single exchange and is separate from the durable message identity.
Input uses role: "ROLE_USER", messageId and parts: [{"text": "..."}]. Text input is limited to 32,000 characters, 16 parts and a 64 KiB request body. Output is a verified inline Markdown artifact with stable artifactId, checksum and byte count. JSON task and list results are bounded to 1 MiB; artifact-heavy list pages may contain fewer tasks. Binary files, arbitrary file URLs and partial token replay are not part of this profile. Status/artifact updates are observations of committed state; reconnecting recovers a snapshot, not every intermediate transition.
HTTP observation waits use 110-second windows. Expiry or disconnect ends observation, while the durable run continues under its saved one-hour execution deadline. Poll/GetTask or subscribe again. Observer leases have separate global/tenant/principal bounds (defaults 256/16/4) and cannot consume cancellation admission. Source/workspace revocation blocks retained content; cancellation returns only a control receipt and does not disclose revoked artifacts. Artifact verification failure is an error, never empty successful evidence.
Mandatory approval and additional-input states appear as TASK_STATE_INPUT_REQUIRED. Use Q's explicit approval/resume API; sending an A2A message cannot approve a tool, change a workspace or resume that task. This profile accepts new text tasks, not A2A multi-turn conversation continuation. Context IDs are server-assigned. Request tenant routing overrides, message metadata, references and extensions are unsupported. Push configuration and extended-card operations return standard unsupported errors. Missing version means unsupported 0.3; Q accepts 1.0 patch revisions, rejects other major/minor revisions and never silently downgrades.
Outbound agents and migration
/v1/a2a/agents remains Q's tenant-owned registration API. Its management shape is not a standard AgentCard. Register the exact JSON-RPC endpoint, with bearer credentials stored through Q's encrypted origin-bound registry. Q's outbound adapter uses the official SDK and common DNS/address/redirect/time/byte policy, verifies response correlation, and does not retry an uncertain send. Discovered cards remain untrusted metadata and cannot install credentials or registrations.
The Q delegation wrapper POST /v1/a2a/tasks requires taskId as a stable outbound message ID. It targets registered external agents only and now returns standard task/message data inside its existing result wrapper. A network or response ambiguity returns status: "unknown"; it is not evidence of remote failure. Reconcile with the remote task API where a task ID was received. Remote agents define their own message deduplication guarantees: do not automatically replay an ambiguous remote side effect.
The old custom SendMessage/GetTask/ListTasks/CancelTask routes, global card list, /v1/a2a/.well-known/agent.json, local q.* task submission and /v1/a2a/tasks/{id} are retired with HTTP 410. They used non-standard shapes and volatile, non-executing tasks. Migrate to the per-agent card/RPC interface; old process-only task IDs cannot be restored. This is an intentional alpha contract change, recorded in the baseline.
Qualification boundary
The standard wire tests exercise official SDK clients against Q and Q's client against an independently configured official SDK server. PostgreSQL tests cover duplicate submissions, reconstruction, artifacts, pagination, cancellation, ownership, revocation, approvals and ambiguous dispatch. Provider output is synthetic; tests do not certify real provider quality, remote implementations or a deployed Temporal/proxy fleet.
Apply migration 20261009_030000_a2a_status before enablement. It records status timestamps at the database boundary for all lifecycle writers. Rollout additionally requires current dependency auditing, TLS/proxy/SSE timeouts, worker grants, reconciler configuration, identity revocation and representative load checks. Push notifications, other bindings/revisions, task resumption and live interoperability certification are not claimed.