# A2A (Agent-to-Agent Protocol) Reference ## Overview CleverAgents adopts the external **Agent-to-Agent (A2A) Protocol** standard ([a2a-protocol.org](https://a2a-protocol.org)) as the sole communication protocol for all client-server interaction. A2A provides the boundary layer between the Presentation and Application layers. **Module:** `cleveragents.a2a` **Protocol:** JSON-RPC 2.0 binding (A2A specification Section 9) **SDK:** `a2a-sdk` package ([a2aproject/a2a-python](https://github.com/a2aproject/a2a-python)) ## Table of Contents - [A2A (Agent-to-Agent Protocol) Reference](#a2a-agent-to-agent-protocol-reference) - [Overview](#overview) - [Table of Contents](#table-of-contents) - [Agent Card](#agent-card) - [Transport Modes](#transport-modes) - [Standard A2A Operations](#standard-a2a-operations) - [Extension Methods](#extension-methods) - [Plan Operations](#plan-operations) - [Registry Operations](#registry-operations) - [Context Operations](#context-operations) - [Sync Operations](#sync-operations) - [Namespace Operations](#namespace-operations) - [Health and Diagnostics](#health-and-diagnostics) - [Streaming Events](#streaming-events) - [Task Lifecycle States](#task-lifecycle-states) - [Example Streaming Event](#example-streaming-event) - [Multi-Turn Interactions](#multi-turn-interactions) - [Local Facade](#local-facade) - [Constructor](#constructor) - [Methods](#methods) - [Service Wiring](#service-wiring) - [Service Keys](#service-keys) - [Error Code Taxonomy](#error-code-taxonomy) - [Example Error Response](#example-error-response) - [Authentication](#authentication) - [Client Architecture](#client-architecture) - [Components](#components) - [Error Hierarchy](#error-hierarchy) --- ## Agent Card A2A uses **Agent Cards** for capability discovery. The CleverAgents Agent Card is served at `/.well-known/agent.json` in server mode: ```json { "name": "CleverAgents", "description": "AI agent orchestration platform", "url": "https://server.example.com", "version": "1.0", "capabilities": { "streaming": true, "pushNotifications": true }, "skills": [ { "id": "plan-lifecycle", "name": "Plan Lifecycle Management" }, { "id": "registry-crud", "name": "Entity Registry Operations" }, { "id": "context-mgmt", "name": "Context Assembly" }, { "id": "entity-sync", "name": "Entity Synchronization" }, { "id": "namespace-mgmt", "name": "Namespace Management" } ], "extensions": [ { "uri": "urn:cleveragents:extensions:v1", "description": "CleverAgents platform operations" } ], "securitySchemes": [ { "type": "http", "scheme": "bearer" } ], "interfaces": [ { "protocol": "jsonrpc", "url": "https://server.example.com/a2a" } ] } ``` An authenticated extended Agent Card with additional detail is available via the `getExtendedAgentCard` operation. --- ## Transport Modes | Mode | Transport | Class / SDK Component | Behaviour | |--------|------------------------|------------------------------------|--------------------------------------------------------| | Local | A2A JSON-RPC over stdio | `A2aLocalFacade` + JSON-RPC stdio | Agent as subprocess; extensions resolved in-process | | Server | A2A JSON-RPC over HTTP | A2A SDK HTTP transport | JSON-RPC 2.0 to CleverAgents server | In local mode the agent runs as a subprocess. JSON-RPC messages flow over stdin/stdout. Extension methods (`_cleveragents/*`) are intercepted by `A2aLocalFacade` and routed to in-process Application-layer services. No network, no authentication. In server mode the client connects via the A2A SDK's HTTP transport. All operations — standard A2A and extensions — flow through the single A2A JSON-RPC 2.0 endpoint on the server. --- ## Standard A2A Operations These operations are defined by the external A2A specification and handle the core agent interaction lifecycle: | Operation | Direction | Purpose | |-----------|-----------|---------| | `message/send` | Client -> Server | Send a message to the agent; returns a Task or direct Message | | `message/stream` | Client -> Server | Send a message with SSE streaming of task updates | | `tasks/get` | Client -> Server | Retrieve current state of a task | | `tasks/list` | Client -> Server | List tasks with optional filtering and pagination | | `tasks/cancel` | Client -> Server | Cancel a running task | | `tasks/subscribe` | Client -> Server | Subscribe to task updates via SSE | | `pushNotificationConfig/create` | Client -> Server | Create push notification webhook | | `pushNotificationConfig/get` | Client -> Server | Get push notification config | | `pushNotificationConfig/list` | Client -> Server | List push notification configs | | `pushNotificationConfig/delete` | Client -> Server | Delete push notification config | | `getExtendedAgentCard` | Client -> Server | Fetch authenticated Agent Card | --- ## Extension Methods Platform operations use `_cleveragents/`-prefixed extension methods (declared in the Agent Card via the A2A extension mechanism): ### Plan Operations | Method | Service Method | Required Params | |--------|----------------|-----------------| | `_cleveragents/plan/use` | `PlanService.create_plan()` | `action_name`, `project_names` | | `_cleveragents/plan/execute` | `PlanLifecycle.execute()` | `plan_id` | | `_cleveragents/plan/apply` | `PlanLifecycle.apply()` | `plan_id` | | `_cleveragents/plan/cancel` | `PlanService.cancel()` | `plan_id` | | `_cleveragents/plan/status` | `PlanService.get_status()` | `plan_id` | | `_cleveragents/plan/tree` | `PlanService.get_tree()` | `plan_id` | | `_cleveragents/plan/explain` | `PlanService.explain_decision()` | `plan_id`, `decision_id` | | `_cleveragents/plan/correct` | `CorrectionFlow.correct()` | `plan_id`, `decision_id`, `correction` | | `_cleveragents/plan/diff` | `PlanService.get_diff()` | `plan_id` | | `_cleveragents/plan/artifacts` | `PlanService.get_artifacts()` | `plan_id` | | `_cleveragents/plan/prompt` | `PlanService.inject_guidance()` | `plan_id`, `message` | | `_cleveragents/plan/rollback` | `PlanLifecycle.rollback()` | `plan_id` | | `_cleveragents/plan/list` | `PlanService.list()` | *(optional filters)* | ### Registry Operations Pattern applies to all entity types (`actor`, `skill`, `tool`, `validation`, `resource`, `resource_type`, `project`, `action`, `automation_profile`, `invariant`, `lsp`): | Method Pattern | Service Method Pattern | Required Params | |----------------|------------------------|-----------------| | `_cleveragents/registry/{entity}/list` | `{Entity}Service.list()` | `namespace` (optional) | | `_cleveragents/registry/{entity}/show` | `{Entity}Service.show()` | `name` | | `_cleveragents/registry/{entity}/add` | `{Entity}Service.add()` | Entity-specific fields | | `_cleveragents/registry/{entity}/update` | `{Entity}Service.update()` | `name`, updated fields | | `_cleveragents/registry/{entity}/remove` | `{Entity}Service.remove()` | `name` | ### Context Operations | Method | Service Method | Required Params | |--------|---------------|-----------------| | `_cleveragents/context/show` | `ContextService.show()` | `project_name` | | `_cleveragents/context/inspect` | `ContextService.inspect()` | `project_name` | | `_cleveragents/context/simulate` | `ContextService.simulate()` | `project_name`, simulation params | | `_cleveragents/context/set` | `ContextService.set()` | `project_name`, context data | ### Sync Operations | Method | Service Method | Required Params | |--------|---------------|-----------------| | `_cleveragents/sync/pull` | `SyncService.pull()` | `namespace` | | `_cleveragents/sync/push` | `SyncService.push()` | `namespace`, `entities` | | `_cleveragents/sync/status` | `SyncService.status()` | `namespace` (optional) | ### Namespace Operations | Method | Service Method | Required Params | |--------|---------------|-----------------| | `_cleveragents/namespace/list` | `NamespaceService.list()` | -- | | `_cleveragents/namespace/show` | `NamespaceService.show()` | `namespace` | | `_cleveragents/namespace/members` | `NamespaceService.members()` | `namespace` | ### Health and Diagnostics | Method | Purpose | |--------|---------| | `_cleveragents/health/check` | Server health check | | `_cleveragents/diagnostics/run` | Run diagnostic suite | --- ## Streaming Events A2A streaming uses SSE via the `message/stream` operation, delivering typed events as the task progresses: | Event Type | Emitted When | |-----------|-------------| | `TaskStatusUpdateEvent` | Task state changes (submitted -> working -> completed, etc.) | | `TaskArtifactUpdateEvent` | Agent produces output (response chunks, plan entries, tool results) | ### Task Lifecycle States | State | Meaning | |-------|---------| | `submitted` | Task created, awaiting processing | | `working` | Agent is actively processing | | `input-required` | Agent needs client input (human-in-the-loop) | | `completed` | Task finished successfully | | `failed` | Task failed with error | | `canceled` | Task was canceled by client | | `rejected` | Task was rejected by agent | ### Example Streaming Event ```json { "jsonrpc": "2.0", "method": "message/stream", "params": { "id": "task_01HXR...", "status": { "state": "working" }, "artifacts": [{ "parts": [{ "text": "I'll start by extracting..." }] }] } } ``` --- ## Multi-Turn Interactions A2A replaces protocol-level callbacks with multi-turn interactions via the Task lifecycle: | Interaction | How It Works | |-------------|--------------| | Human-in-the-loop approval | Task enters `input-required` state; client displays prompt; client responds via `message/send` | | File access (read/write) | `_cleveragents/fs/*` extension methods handled locally by client | | Terminal access | `_cleveragents/terminal/*` extension methods handled locally by client | When a server-hosted agent needs client-side resources, the Task enters `input-required` state. The client handles the request and responds, resuming the task. --- ## Local Facade `A2aLocalFacade` handles extension method dispatch in local mode: ```python from cleveragents.a2a import A2aLocalFacade from cleveragents.a2a.models import A2aRequest facade = A2aLocalFacade(services={ "session_service": my_session_service, "plan_lifecycle_service": my_plan_lifecycle_service, "tool_registry": my_tool_registry, "resource_registry_service": my_resource_registry_service, }) # Extension methods are dispatched to in-process services (synchronous) response = facade.dispatch(A2aRequest( method="_cleveragents/plan/status", params={"plan_id": "01J..."} )) ``` ### Constructor | Parameter | Type | Default | Description | |------------|----------------------------|---------|-------------------------------| | `services` | `dict[str, Any] \| None` | `None` | Named services for routing | ### Methods | Method | Returns | Description | |---------------------------------|-------------------|--------------------------------------| | `dispatch(request: A2aRequest)` | `A2aResponse` | Route extension method to handler | | `register_service` | `None` | Register a named service | | `list_operations()` | `list[str]` | All supported extension method names | --- ## Service Wiring Each A2A extension method is wired to a concrete application service. Services are injected via the `services` dict at construction time or registered later with `register_service()`. ### Service Keys | Key | Type | Wired Methods | |------------------------------|-----------------------------|-------------------------------------| | `session_service` | `SessionWorkflow` | Standard message operations | | `plan_lifecycle_service` | `PlanLifecycleService` | `_cleveragents/plan/*` | | `tool_registry` | `ToolRegistry` | `_cleveragents/registry/tool/*` | | `resource_registry_service` | `ResourceRegistryService` | `_cleveragents/registry/resource/*` | | `sync_service` | `SyncService` | `_cleveragents/sync/*` | | `namespace_service` | `NamespaceService` | `_cleveragents/namespace/*` | | `context_service` | `ContextService` | `_cleveragents/context/*` | --- ## Error Code Taxonomy Domain exceptions are mapped to JSON-RPC 2.0 error codes: | JSON-RPC Code | Domain Exception(s) | Meaning | |-------------------|----------------------------------------|----------------------------------| | `-32700` | -- | Parse error (malformed JSON) | | `-32600` | -- | Invalid request | | `-32601` | `A2aOperationNotFoundError` | Method not found | | `-32602` | `ValidationError` | Invalid params | | `-32603` | Any unhandled `Exception` | Internal error | | `-32001` | `ResourceNotFoundError` | Entity not found | | `-32002` | `AuthenticationError` | Authentication required | | `-32003` | `AuthorizationError` | Authorization forbidden | | `-32004` | `BusinessRuleViolation` | Invalid state | | `-32005` | `DuplicateEntityError` | Already exists | | `-32006` | `BudgetExceededError` | Budget exceeded | | `-32007` | `A2aVersionMismatchError` | Version mismatch | | `-32008` | `PlanError` | Plan lifecycle error | | `-32009` | `ConfigurationError` | Configuration error | ### Example Error Response ```json { "jsonrpc": "2.0", "id": 42, "error": { "code": -32001, "message": "Plan not found", "data": { "plan_id": "01HXRCF1..." } } } ``` --- ## Authentication Authentication uses standard HTTP security schemes declared in the Agent Card: 1. Client discovers Agent Card at `/.well-known/agent.json` 2. Agent Card's `securitySchemes` declares supported auth mechanisms 3. Client authenticates using the declared scheme (e.g., `Authorization: Bearer `) 4. All subsequent requests include authentication credentials Local mode (stdio) bypasses authentication -- the agent subprocess runs with the user's local permissions. --- ## Client Architecture The client uses an `A2aClient` wrapping the A2A Python SDK: ```python from cleveragents.a2a import A2aClient, TransportSelector # TransportSelector picks stdio or HTTP based on configuration transport = TransportSelector().get_transport() client = A2aClient(transport) # Standard A2A operation await client.send_message(message="Add pagination", context_id="ctx_01HXR...") # Extension method result = await client.plan_status(plan_id="01HXRCF1...") ``` ### Components | Component | Role | Notes | |-----------|------|-------| | `A2aLocalFacade` | Extension dispatch in local mode | Routes `_cleveragents/` methods to in-process services | | A2A SDK HTTP transport | Server mode transport | Production HTTP transport with SSE streaming | | A2A SDK JSON-RPC types | Wire format | `SendMessageRequest`, `Task`, `Message`, `Part`, etc. | | `A2aEventQueue` | Local mode event delivery | In-process task update event delivery | | Agent Card | Discovery | Capability advertisement and auth scheme declaration | --- ## Error Hierarchy ``` CleverAgentsError └── A2aError ├── A2aNotAvailableError ├── A2aVersionMismatchError └── A2aOperationNotFoundError ``` | Exception | When Raised | |-----------------------------|----------------------------------------------------| | `A2aNotAvailableError` | Server-mode operation attempted without connection | | `A2aVersionMismatchError` | Unsupported A2A version | | `A2aOperationNotFoundError` | Unknown method dispatched | --- ## ACP to A2A Migration > **v3.6.0 breaking change.** The `cleveragents.acp` module was renamed to > `cleveragents.a2a` and all `Acp*` symbols were renamed to `A2a*`. The > request/response wire format was updated to comply with JSON-RPC 2.0. For a complete migration guide including symbol rename tables, field name changes, operation name mapping, and YAML configuration updates, see [`docs/development/acp-to-a2a-migration.md`](../development/acp-to-a2a-migration.md). ### Quick Reference: Deprecated Legacy Operations The following ACP operation names are accepted by `A2aLocalFacade.dispatch()` in `cleveragents.a2a.facade.A2aLocalFacade` (commit `449c33b7`) for backward compatibility but are **deprecated**: | Deprecated (ACP) | Replacement (A2A) | |---|---| | `session.create` | `_cleveragents/session/create` | | `session.close` | `_cleveragents/session/close` | | `plan.create` | `_cleveragents/plan/use` | | `plan.execute` | `_cleveragents/plan/execute` | | `plan.status` | `_cleveragents/plan/status` | | `plan.diff` | `_cleveragents/plan/diff` | | `plan.apply` | `_cleveragents/plan/apply` | | `registry.list_tools` | `_cleveragents/registry/tool/list` | | `registry.list_resources` | `_cleveragents/registry/resource/list` | | `context.get` | `_cleveragents/context/show` | See [ADR-047](../adr/ADR-047-acp-standard-adoption.md) for the architectural rationale behind this change.