980fcabc48
CI / push-validation (pull_request) Successful in 28s
CI / lint (pull_request) Successful in 32s
CI / helm (pull_request) Successful in 36s
CI / build (pull_request) Successful in 43s
CI / quality (pull_request) Successful in 55s
CI / typecheck (pull_request) Successful in 1m18s
CI / security (pull_request) Successful in 1m19s
CI / unit_tests (pull_request) Successful in 6m51s
CI / integration_tests (pull_request) Successful in 10m33s
CI / docker (pull_request) Failing after 12m6s
CI / coverage (pull_request) Failing after 12m22s
CI / status-check (pull_request) Failing after 3s
172 lines
4.8 KiB
Markdown
172 lines
4.8 KiB
Markdown
# `cleveragents.a2a` — Agent-to-Agent Protocol
|
|
|
|
The `a2a` package implements the Agent-to-Agent (A2A) protocol boundary.
|
|
In **local mode** the `A2aLocalFacade` maps A2A operation names to direct
|
|
Python method calls on application services — no serialization, no network.
|
|
In **server mode** stub transports raise `A2aNotAvailableError` until the
|
|
concrete HTTP transport is wired in.
|
|
|
|
See [ADR-026](../adr/ADR-026-agent-client-protocol.md) and
|
|
[ADR-047](../adr/ADR-047-acp-standard-adoption.md) for design rationale.
|
|
|
|
---
|
|
|
|
## Core Classes
|
|
|
|
### `A2aLocalFacade`
|
|
|
|
```python
|
|
class A2aLocalFacade:
|
|
async def dispatch(self, request: A2aRequest) -> A2aResponse: ...
|
|
```
|
|
|
|
Routes A2A requests to live application services. Supported operations:
|
|
|
|
| Operation | Description |
|
|
|-----------|-------------|
|
|
| `session.create` | Create a new conversation session |
|
|
| `session.close` | Close an existing session |
|
|
| `plan.create` | Create a new plan |
|
|
| `plan.execute` | Execute a plan |
|
|
| `plan.status` | Query plan status |
|
|
| `plan.diff` | Retrieve plan diff |
|
|
| `plan.apply` | Apply a plan |
|
|
| `registry.list_tools` | List available tools |
|
|
| `registry.list_resources` | List available resources |
|
|
| `event.subscribe` | Subscribe to event stream |
|
|
|
|
```python
|
|
from cleveragents.a2a import A2aLocalFacade, A2aRequest
|
|
|
|
facade = A2aLocalFacade(container)
|
|
response = await facade.dispatch(
|
|
A2aRequest(method="session.create", params={"actor": "openai/gpt-4o"})
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
### `A2aRequest` / `A2aResponse`
|
|
|
|
> **Breaking change (v3.7.0+):** Fields were renamed to comply with the
|
|
> [JSON-RPC 2.0](https://www.jsonrpc.org/specification) wire format.
|
|
> See the [CHANGELOG](../../CHANGELOG.md) for the migration table.
|
|
|
|
```python
|
|
class A2aRequest(BaseModel):
|
|
jsonrpc: Literal["2.0"] = "2.0" # was: a2a_version
|
|
id: str | None = None # was: request_id
|
|
method: str # was: operation
|
|
params: dict[str, Any] = {}
|
|
|
|
class A2aResponse(BaseModel):
|
|
jsonrpc: Literal["2.0"] = "2.0" # was: a2a_version
|
|
id: str | None = None # was: request_id
|
|
result: Any | None = None # was: data (success path)
|
|
error: A2aErrorDetail | None = None
|
|
# result and error are mutually exclusive (enforced by validator)
|
|
```
|
|
|
|
Usage example (updated for JSON-RPC 2.0 field names):
|
|
|
|
```python
|
|
from cleveragents.a2a import A2aLocalFacade, A2aRequest
|
|
|
|
facade = A2aLocalFacade(container)
|
|
response = await facade.dispatch(
|
|
A2aRequest(method="session.create", params={"actor": "openai/gpt-4o"})
|
|
)
|
|
if response.result is not None:
|
|
session_id = response.result["session_id"]
|
|
elif response.error is not None:
|
|
raise RuntimeError(response.error.message)
|
|
```
|
|
|
|
---
|
|
|
|
### `A2aEventQueue`
|
|
|
|
Async event queue for subscribing to plan and session events.
|
|
|
|
```python
|
|
queue = A2aEventQueue()
|
|
async for event in queue.subscribe("plan-42"):
|
|
print(event.type, event.payload)
|
|
```
|
|
|
|
Call `queue.close()` on shutdown to release resources.
|
|
|
|
---
|
|
|
|
### `A2aVersionNegotiator`
|
|
|
|
Negotiates the A2A protocol version between client and server.
|
|
|
|
---
|
|
|
|
## Error Types
|
|
|
|
| Exception | Description |
|
|
|-----------|-------------|
|
|
| `A2aError` | Base A2A exception |
|
|
| `A2aNotAvailableError` | Operation not available in current mode |
|
|
| `A2aOperationNotFoundError` | Unknown operation name |
|
|
| `A2aVersionMismatchError` | Incompatible protocol versions |
|
|
|
|
---
|
|
|
|
## Server Client Stubs
|
|
|
|
`ServerClient`, `RemoteExecutionClient`, and `AuthClient` are protocol
|
|
interfaces for server-mode operation. `StubServerClient`,
|
|
`StubRemoteExecutionClient`, and `StubAuthClient` raise
|
|
`A2aNotAvailableError` for all methods until server mode is fully
|
|
implemented.
|
|
|
|
---
|
|
|
|
## Server Connection
|
|
|
|
```python
|
|
from cleveragents.a2a import ServerConnectionConfig
|
|
|
|
config = ServerConnectionConfig(url="https://my-server.example.com", token="...")
|
|
```
|
|
|
|
Validates URL format and token presence.
|
|
|
|
---
|
|
|
|
## ACP to A2A Rename (v3.6.0)
|
|
|
|
> **Breaking change in v3.6.0.** The `cleveragents.acp` module was renamed to
|
|
> `cleveragents.a2a`. All `Acp*` class names were renamed to `A2a*`. The
|
|
> `AcpRequest` and `AcpResponse` field names were updated to comply with the
|
|
> JSON-RPC 2.0 specification.
|
|
|
|
For the complete migration guide, see
|
|
[`docs/development/acp-to-a2a-migration.md`](../development/acp-to-a2a-migration.md).
|
|
|
|
**Symbol rename summary:**
|
|
|
|
| Old (ACP) | New (A2A) |
|
|
|---|---|
|
|
| `AcpRequest` | `A2aRequest` |
|
|
| `AcpResponse` | `A2aResponse` |
|
|
| `AcpLocalFacade` | `A2aLocalFacade` |
|
|
| `AcpError` | `A2aError` |
|
|
| `AcpEventQueue` | `A2aEventQueue` |
|
|
|
|
**Field rename summary (`A2aRequest` / `A2aResponse`):**
|
|
|
|
| Old Field | New Field |
|
|
|---|---|
|
|
| `a2a_version` | `jsonrpc` |
|
|
| `request_id` | `id` |
|
|
| `operation` | `method` |
|
|
| `payload` | `params` |
|
|
| `data` | `result` |
|
|
| `error_detail` | `error` |
|
|
|
|
See [ADR-047](../adr/ADR-047-acp-standard-adoption.md) for architectural rationale.
|