diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bfab0255..c427b892e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Changed `wf10_batch.robot` to be less likely to create files, and `plan_generation_graph.robot` to give more test answers. ## [Unreleased] +- **docs(a2a): ACP to A2A migration guide** (#10230): Added migration guide documenting how to upgrade from the ACP module to the A2A module introduced in v3.6.0, including symbol renames, field renames, operation-name mappings, and YAML configuration updates. - **Plan Prompt JSON Timing Field** (#9353): `agents plan prompt --format json` now includes `timing.started` as an ISO 8601 UTC timestamp in the JSON envelope, matching the spec (§CLI Commands — `agents plan prompt`). Extended diff --git a/docs/api/a2a.md b/docs/api/a2a.md index 8e1ca9211..9cb9e1040 100644 --- a/docs/api/a2a.md +++ b/docs/api/a2a.md @@ -134,3 +134,38 @@ 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. diff --git a/docs/development/acp-to-a2a-migration.md b/docs/development/acp-to-a2a-migration.md new file mode 100644 index 000000000..30022bec3 --- /dev/null +++ b/docs/development/acp-to-a2a-migration.md @@ -0,0 +1,264 @@ +# ACP to A2A Module Rename and Symbol Standardization + +> **Introduced in:** v3.6.0 +> **Architectural decision:** [ADR-047 - A2A Standard Adoption](../adr/ADR-047-acp-standard-adoption.md) +> **Module path:** `cleveragents.a2a` (commit `449c33b7`) + +--- + +## Overview + +In v3.6.0 the internal **ACP (Agent Client Protocol)** module was renamed to +**A2A (Agent-to-Agent Protocol)** and all public symbols were standardized to +align with the external [A2A open standard](https://a2a-protocol.org) (Linux +Foundation, Apache 2.0). + +This was not merely a rename - it was an architectural shift from a bespoke +JSON envelope protocol to the industry-standard A2A wire format built on +**JSON-RPC 2.0**. The change eliminates the proprietary ACP envelope, replaces +custom REST routing with JSON-RPC 2.0 method dispatch, and introduces +**Agent Card** discovery (`/.well-known/agent.json`). + +--- + +## What Changed + +### 1. Module Path + +| Before (ACP) | After (A2A) | +|---|---| +| `cleveragents.acp` | `cleveragents.a2a` | +| `from cleveragents.acp import ...` | `from cleveragents.a2a import ...` | + +### 2. Class and Symbol Names + +All public symbols were renamed from `Acp*` to `A2a*`: + +| Old Symbol (ACP) | New Symbol (A2A) | Notes | +|---|---|---| +| `AcpRequest` | `A2aRequest` | Wire format changed - see section 3 | +| `AcpResponse` | `A2aResponse` | Wire format changed - see section 3 | +| `AcpError` | `A2aError` | Base exception | +| `AcpNotAvailableError` | `A2aNotAvailableError` | Server-mode guard | +| `AcpOperationNotFoundError` | `A2aOperationNotFoundError` | Unknown method | +| `AcpVersionMismatchError` | `A2aVersionMismatchError` | Protocol version guard | +| `AcpLocalFacade` | `A2aLocalFacade` | Local-mode dispatcher | +| `AcpHttpTransport` | `A2aHttpTransport` | Server-mode transport stub | +| `AcpEventQueue` | `A2aEventQueue` | In-process event delivery | +| `AcpVersionNegotiator` | `A2aVersionNegotiator` | Version negotiation | +| `AcpVersion` | `A2aVersion` | Version constants | +| `AcpEvent` | `A2aEvent` | SSE event envelope | +| `AcpErrorDetail` | `A2aErrorDetail` | JSON-RPC error object | + +### 3. Request and Response Field Names + +`A2aRequest` and `A2aResponse` now use **JSON-RPC 2.0** field names instead of +the proprietary ACP envelope fields. These models are defined in +`cleveragents.a2a.models` (commit `449c33b7`): + +| Old Field (ACP) | New Field (A2A / JSON-RPC 2.0) | Type | +|---|---|---| +| `a2a_version` | `jsonrpc` (always `"2.0"`) | `str` | +| `request_id` | `id` | `str` | +| `operation` | `method` | `str` | +| `payload` | `params` | `dict[str, Any]` | +| `data` (success path) | `result` | `dict[str, Any] or None` | +| `error_detail` | `error` | `A2aErrorDetail or None` | + +**Before (ACP):** +```python +from cleveragents.acp import AcpRequest, AcpLocalFacade + +request = AcpRequest( + a2a_version="1.0", + request_id="req-001", + operation="plan.status", + payload={"plan_id": "01HXRCF1..."}, +) +response = facade.dispatch(request) +if response.data: + print(response.data["phase"]) +``` + +**After (A2A):** +```python +from cleveragents.a2a import A2aRequest, A2aLocalFacade + +request = A2aRequest( + jsonrpc="2.0", + id="req-001", + method="_cleveragents/plan/status", + params={"plan_id": "01HXRCF1..."}, +) +response = facade.dispatch(request) +if response.result: + print(response.result["phase"]) +``` + +### 4. Operation Names + +The ACP proprietary operation names were replaced with the A2A standard +`_cleveragents/` extension method namespace. The legacy names are still +accepted by `A2aLocalFacade.dispatch()` in `cleveragents.a2a.facade` +(commit `449c33b7`) for backward compatibility but are **deprecated** and +will be removed in a future major version. + +| Old Operation (ACP / deprecated) | New Operation (A2A) | +|---|---| +| `session.create` | `_cleveragents/session/create` (via `message/send`) | +| `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` | +| `event.subscribe` | (event delivery via SSE `message/stream`) | + +The full list of supported A2A extension methods is documented in +[`docs/reference/a2a.md`](../reference/a2a.md#extension-methods). + +### 5. YAML and Configuration Files + +If you have YAML configuration files, actor definitions, or skill files that +reference the old ACP module path or operation names, update them as follows: + +**Actor YAML - protocol binding:** +```yaml +# Before (ACP) +protocol: + type: acp + version: "1.0" + +# After (A2A) +protocol: + type: a2a + version: "2.0" +``` + +**Skill YAML - operation references:** +```yaml +# Before (ACP) +operations: + - operation: plan.create + - operation: plan.execute + +# After (A2A) +operations: + - method: _cleveragents/plan/use + - method: _cleveragents/plan/execute +``` + +**Server connection config:** +```yaml +# Before (ACP) +server: + protocol: acp + endpoint: https://my-server.example.com/acp + +# After (A2A) +server: + protocol: a2a + endpoint: https://my-server.example.com/a2a +``` + +--- + +## Migration Steps + +Follow these steps when upgrading from a codebase that used the ACP module: + +### Step 1 - Update imports + +Replace all `cleveragents.acp` imports with `cleveragents.a2a`: + +```bash +# Find all files that import from the old ACP module +grep -r "from cleveragents.acp" src/ tests/ +grep -r "import cleveragents.acp" src/ tests/ +``` + +Then update each import: +```python +# Before +from cleveragents.acp import AcpLocalFacade, AcpRequest, AcpResponse + +# After +from cleveragents.a2a import A2aLocalFacade, A2aRequest, A2aResponse +``` + +### Step 2 - Rename symbol references + +Use your editor's find-and-replace to rename all `Acp*` symbols to `A2a*` +(see the complete symbol table in section 2 above). + +### Step 3 - Update request field names + +Update all `AcpRequest` and `AcpResponse` constructor calls and field accesses +to use the new JSON-RPC 2.0 field names (see section 3 above). + +### Step 4 - Update operation names + +Replace deprecated ACP operation strings with the new `_cleveragents/` +extension method names (see section 4 above). The legacy names still work but +emit deprecation warnings. + +### Step 5 - Update YAML files + +Search for any YAML files that reference `acp` in protocol type fields or +operation names and update them (see section 5 above). + +### Step 6 - Verify + +Run the full test suite to confirm no regressions: + +```bash +nox -s unit_tests +nox -s integration_tests +``` + +--- + +## Backward Compatibility + +The `A2aLocalFacade.dispatch()` method in `cleveragents.a2a.facade.A2aLocalFacade` +(commit `449c33b7`) continues to accept the legacy ACP operation names +(`session.create`, `plan.create`, etc.) via the `_LEGACY_OPERATIONS` list. +This backward compatibility shim will be removed in the next major version. + +The `A2aVersion` class in `cleveragents.a2a.models.A2aVersion` (commit +`449c33b7`) retains the `CURRENT` and `SUPPORTED` constants for backward +compatibility, though the wire format now uses the `jsonrpc` field rather than +a proprietary `a2a_version` field. + +--- + +## Architectural Rationale + +The rename was driven by the adoption of the external A2A open standard +([a2a-protocol.org](https://a2a-protocol.org)), which supersedes the bespoke +ACP protocol. Key reasons for the change: + +- **Ecosystem alignment**: A2A is governed by the Linux Foundation with 22k+ + GitHub stars and SDKs in Python, Go, JavaScript, Java, and .NET. +- **Agent Card discovery**: The standard introduces `/.well-known/agent.json` + for dynamic capability advertisement. +- **JSON-RPC 2.0**: Replaces the proprietary envelope with a mature, widely- + tooled standard. +- **Extensibility**: The `_cleveragents/` extension namespace cleanly separates + platform-specific operations from standard agent interactions. + +See [ADR-047](../adr/ADR-047-acp-standard-adoption.md) for the full +architectural rationale and decision record. + +--- + +## Related Documentation + +- [A2A Reference](../reference/a2a.md) - complete API reference for the `cleveragents.a2a` module +- [A2A API](../api/a2a.md) - class-level API documentation +- [ADR-026 - Agent-to-Agent Protocol](../adr/ADR-026-agent-client-protocol.md) - protocol boundary design +- [ADR-047 - A2A Standard Adoption](../adr/ADR-047-acp-standard-adoption.md) - rationale for adopting the external standard +- [ADR-048 - Server Application Architecture](../adr/ADR-048-server-application-architecture.md) - server implementation using A2A diff --git a/docs/reference/a2a.md b/docs/reference/a2a.md index 23ff95a0e..a0d9ab41d 100644 --- a/docs/reference/a2a.md +++ b/docs/reference/a2a.md @@ -88,8 +88,8 @@ via the `getExtendedAgentCard` operation. ## Transport Modes -| Mode | Transport | Class / SDK Component | Behaviour | -|--------|------------------------|------------------------------------|--------------------------------------------------------------------| +| 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 | @@ -165,7 +165,7 @@ Pattern applies to all entity types (`actor`, `skill`, `tool`, `validation`, ### 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 | @@ -174,7 +174,7 @@ Pattern applies to all entity types (`actor`, `skill`, `tool`, `validation`, ### 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) | @@ -182,7 +182,7 @@ Pattern applies to all entity types (`actor`, `skill`, `tool`, `validation`, ### Namespace Operations | Method | Service Method | Required Params | -|--------|----------------|-----------------| +|--------|---------------|-----------------| | `_cleveragents/namespace/list` | `NamespaceService.list()` | -- | | `_cleveragents/namespace/show` | `NamespaceService.show()` | `namespace` | | `_cleveragents/namespace/members` | `NamespaceService.members()` | `namespace` | @@ -198,20 +198,13 @@ Pattern applies to all entity types (`actor`, `skill`, `tool`, `validation`, ## Streaming Events -A2A streaming uses SSE via the `message/stream` operation (client → server -request), delivering typed events as the task progresses. The SSE data -payloads are JSON-RPC 2.0 **notifications** (no `id` field): +A2A streaming uses SSE via the `message/stream` operation, delivering typed +events as the task progresses: -| Event Type | JSON-RPC Method | Emitted When | -|------------|-----------------|--------------| -| `TaskStatusUpdateEvent` | `task/statusUpdate` | Task state changes (submitted -> working -> completed, etc.) | -| `TaskArtifactUpdateEvent` | `task/artifactUpdate` | Agent produces output (response chunks, plan entries, tool results) | - -> **Note:** `message/stream` is the **request** method (client → server) that -> initiates streaming. The SSE data payloads use `task/statusUpdate` or -> `task/artifactUpdate` as the notification method name — not `message/stream`. -> Non-spec fields (`event_id`, `event_type`, `timestamp`) are carried in SSE -> envelope headers (`event:` and `id:` lines), not in the data payload. +| 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 @@ -227,30 +220,16 @@ payloads are JSON-RPC 2.0 **notifications** (no `id` field): ### Example Streaming Event -SSE data payload for a task status update (JSON-RPC 2.0 notification): - ```json { "jsonrpc": "2.0", - "method": "task/statusUpdate", + "method": "message/stream", "params": { - "taskId": "task_01HXR...", - "status": { "state": "working" } - } -} -``` - -SSE data payload for an artifact update: - -```json -{ - "jsonrpc": "2.0", - "method": "task/artifactUpdate", - "params": { - "taskId": "task_01HXR...", - "artifact": { + "id": "task_01HXR...", + "status": { "state": "working" }, + "artifacts": [{ "parts": [{ "text": "I'll start by extracting..." }] - } + }] } } ``` @@ -298,9 +277,9 @@ response = facade.dispatch(A2aRequest( ### Constructor -| Parameter | Type | Default | Description | -|------------|----------------------------------|---------|--------------------------------| -| `services` | `dict[str, Any] \| None` | `None` | Named services for routing | +| Parameter | Type | Default | Description | +|------------|----------------------------|---------|-------------------------------| +| `services` | `dict[str, Any] \| None` | `None` | Named services for routing | ### Methods @@ -320,15 +299,15 @@ 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/*` | +| 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/*` | --- @@ -423,8 +402,42 @@ CleverAgentsError └── A2aOperationNotFoundError ``` -| Exception | When Raised | -|------------------------------|--------------------------------------------------------------------| -| `A2aNotAvailableError` | Server-mode operation attempted without connection | -| `A2aVersionMismatchError` | Unsupported A2A version | -| `A2aOperationNotFoundError` | Unknown method dispatched | +| 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. diff --git a/mkdocs.yml b/mkdocs.yml index fc4864bad..107028bcf 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -52,6 +52,7 @@ nav: - Automation Tracking: development/automation-tracking.md - Custom Sandbox Strategy: development/custom_sandbox_strategy.md - Documentation Writer: development/docs-writer.md + - ACP to A2A Migration: development/acp-to-a2a-migration.md - Implementation Timeline: timeline.md - Advanced Concepts (v3.6.0): - Overview & Context Strategies: advanced-concepts/index.md