sandbox-agent/research/acp/spec.md
2026-02-11 07:57:02 -08:00

366 lines
15 KiB
Markdown

# V1 Spec: ACP Over HTTP
## 0) Delete/Remove First
Before implementing v1, remove in-house protocol files and remove v1 API behavior as documented in:
- `research/acp/00-delete-first.md`
- `research/acp/v1-schema-to-acp-mapping.md` (endpoint/event-by-event conversion target)
This is mandatory to prevent dual-protocol drift.
## 1) Goals
- v1 is intentionally breaking and ACP-native.
- Internal runtime uses ACP end-to-end (no custom universal event schema).
- Existing agent managers are replaced with ACP agent process runtimes.
- v1 API is completely removed; all `/v1/*` requests return explicit removed errors.
- OpenCode <-> ACP support is preserved as a product requirement, but implemented in a separate step after ACP core is stable.
## 2) Non-goals for first v1 cut
- No guarantee of v1 endpoint compatibility.
- No v1 compatibility layer in the initial v1 release.
- No OpenCode compatibility during ACP core bring-up (`/opencode/*` is disabled until the dedicated bridge step).
- No in-house universal event format.
## 3) Protocol baseline
Use ACP v1 schema from:
- `~/misc/acp-docs/schema/schema.json`
- `~/misc/acp-docs/schema/meta.json`
- `research/acp/v1-schema-to-acp-mapping.md` (required for preserving v1 feature coverage during migration)
Supported agent methods (minimum):
- `initialize`, `authenticate` (if needed), `session/new`, `session/prompt`, `session/cancel`
Supported client methods (minimum):
- `session/request_permission`
Included unstable ACP methods for v1 profile:
- `session/list`
- `session/fork`
- `session/resume`
- `session/set_model`
- `$/cancel_request`
Phase-1 optional methods (still optional per agent process capability):
- `fs/read_text_file`, `fs/write_text_file`
- `terminal/*`
- `session/load`, `session/set_mode`, `session/set_config_option`
Sandbox Agent ACP extension methods currently implemented:
- `_sandboxagent/session/detach`
- `_sandboxagent/session/list_models`
- `_sandboxagent/session/set_metadata`
- `_sandboxagent/session/request_question` (agent -> client request pattern)
- `_sandboxagent/session/terminate`
- `_sandboxagent/session/ended` (runtime -> client notification)
## 4) Transport: ACP over HTTP (repo-specific draft)
ACP streamable HTTP is draft upstream, so this spec defines a concrete transport that stays close to current ACP transport guidance and JSON-RPC semantics.
### 4.1 Endpoints
- `POST /v1/rpc`
- `GET /v1/rpc` (SSE stream, `Accept: text/event-stream`)
- `DELETE /v1/rpc` (explicit connection close)
### 4.2 Connection model
- Each ACP HTTP connection maps to a logical client connection id (`X-ACP-Connection-Id`).
- Agent processes are shared per `AgentId` (one backend process per agent type on a server), not per HTTP connection.
- Session inventory is server-global in memory across connections; `session/list` returns this aggregated inventory.
- Connection identity is `X-ACP-Connection-Id` header.
- First `initialize` request may omit `X-ACP-Connection-Id` and must include `params._meta["sandboxagent.dev"].agent`.
- Server ensures backend exists for that agent, creates connection, returns `X-ACP-Connection-Id` in response headers.
- All subsequent `POST /v1/rpc` and `GET /v1/rpc` requests must include `X-ACP-Connection-Id`.
- `DELETE /v1/rpc` with `X-ACP-Connection-Id` detaches/closes only the transport connection and releases connection-scoped resources.
- `DELETE /v1/rpc` does not terminate the session or agent process. Session termination is explicit via `_sandboxagent/session/terminate`.
### 4.3 Message routing
- Client -> agent requests/notifications: sent as JSON-RPC payloads to `POST /v1/rpc`.
- Agent -> client notifications/requests: delivered on `GET /v1/rpc` SSE stream as JSON-RPC envelopes.
- Client replies to agent-initiated requests by POSTing JSON-RPC responses to `POST /v1/rpc`.
### 4.4 SSE framing
- `event: message`
- `id: <monotonic-sequence>`
- `data: <single JSON-RPC object>`
Keepalive:
- SSE comment heartbeat every 15s.
Resume:
- `Last-Event-ID` accepted for best-effort replay from in-memory ring buffer.
### 4.5 HTTP status and errors
- JSON-RPC request success: HTTP 200 with JSON-RPC response object.
- JSON-RPC notification accepted: HTTP 202, empty body.
- Invalid envelope: HTTP 400 with `application/problem+json`.
- Unknown connection: HTTP 404 with `application/problem+json`.
- Server timeout waiting on agent process response: HTTP 504 with `application/problem+json`.
- Successful `DELETE /v1/rpc`: HTTP 204.
- Repeated `DELETE /v1/rpc` on an already-closed connection: HTTP 204 (idempotent close).
- All `/v1/*` endpoints: HTTP 410 with `application/problem+json` and message `v1 API removed; use /v1`.
Note: ACP method-level failures still return JSON-RPC error objects inside 200 responses.
### 4.6 Ordering and concurrency
- Per-connection outbound SSE order is preserved.
- JSON-RPC `id` is opaque and passed through unchanged.
- Multiple in-flight requests are allowed.
### 4.7 Security
- Reuse existing bearer token auth middleware.
- Validate bearer auth at request time for `/v1/*` routes when configured.
- ACP runtime connection ids are in-memory server ids and are not additionally principal-scoped inside runtime.
- Do not expose agent process stderr on stdout channel.
### 4.8 Field research alignment (2026-02-10)
Based on current ACP community implementations/discussion:
- Streamable HTTP and WebSocket are both being piloted.
- Streamable HTTP implementations are converging on MCP-like request patterns while keeping ACP JSON-RPC payloads.
- WebSocket implementations report simpler handling for bidirectional/server-initiated ACP traffic.
Decision for this repo:
- v1 public transport remains Streamable HTTP (`POST`/`GET` SSE over `/v1/rpc`) as the canonical contract.
- WebSocket transport is not part of initial v1 surface; consider later only if HTTP profile proves insufficient operationally.
Reference:
- `research/acp/acp-over-http-findings.md`
## 5) Agent process runtime and install model
## 5.1 Runtime
Replace custom per-agent protocol parsers with one ACP agent process process contract:
- Spawn ACP agent process binary (stdio JSON-RPC).
- Bridge stdio <-> internal ACP client dispatcher.
- No agent-specific JSON parsing in server core.
## 5.2 Installers
Current auto-installer installs native CLIs. v1 installer must install:
- native agent binary (if needed by agent process)
- ACP agent process binary required for that agent
Add a manifest-driven mapping (new file to create in implementation phase):
- `claude`: agent process `claude-code-acp`
- `codex`: agent process `codex-acp`
- `opencode`: native ACP mode (agent process optional)
- `amp`: pending decision (official agent process required or unsupported in v1 initial release)
## 5.3 ACP Registry install instructions
Yes, this must be handled.
V1 installer/docs must include install instructions sourced from ACP registry metadata where available, with explicit fallback for non-registry agent processes.
Requirements:
- Maintain a local agent process manifest with:
- registry slug (if present)
- agent process package/repo source
- native agent dependency
- supported platform matrix
- install verification command
- Prefer ACP registry source of truth when agent process is published there.
- If agent process is not in registry, use pinned fallback source and mark as `non_registry`.
- Support `SANDBOX_AGENT_ACP_REGISTRY_URL` override for controlled/test environments.
- Generate user-facing install instructions from this manifest (do not hand-maintain per-agent docs).
- Expose install provenance in API/CLI (`registry` vs `fallback`).
Output surfaces:
- `GET /v1/agents`: include agent process install source + verification status.
- `POST /v1/agents/{agent}/install`: return concrete installed artifacts and source provenance.
## 5.4 Install commands and lazy agent process install
This must match current ergonomics where installs can be explicit or automatic.
Explicit install interfaces:
- API: `POST /v1/agents/{agent}/install`
- CLI (v1 surface): `sandbox-agent api v1 agents install <agent> [--reinstall] [--agent-version <v>] [--agent process-version <v>]`
Lazy install behavior (default on):
- Trigger point: first ACP bootstrap request (`initialize`) on `/v1/rpc` with `params._meta["sandboxagent.dev"].agent`.
- If required binaries are missing, server installs:
- ACP agent process
- native agent binary if agent process requires it
- Then server starts the agent process process and continues normal ACP handshake.
Operational requirements:
- Per-agent install lock to prevent duplicate concurrent downloads.
- Idempotent install response when artifacts already exist.
- Clear provenance in result (`registry` vs `fallback`) plus concrete artifact versions.
- Config switch to disable lazy install (`require_preinstall=true`) for controlled environments.
## 6) Public v1 API shape
Expose ACP directly, not custom session endpoints.
- `POST /v1/rpc`: transport write path
- `GET /v1/rpc`: transport read path (SSE)
Non-ACP endpoints retained in v1:
- `GET /v1/health`
- `GET /v1/agents` (capabilities + install status)
- `POST /v1/agents/{agent}/install`
- `GET /v1/sessions`
- `GET /v1/sessions/{id}`
- `GET /v1/fs/file`
- `PUT /v1/fs/file`
- `POST /v1/fs/upload-batch`
- `GET /ui/` (Inspector UI shell)
Agent discovery note:
- Do not add standalone `/v1/agents/{agent}/models` or `/v1/agents/{agent}/modes` endpoints.
- Expose optional `models`/`modes` properties on agent response payloads when the agent is installed.
Legacy endpoints retained only as removals:
- `ALL /v1/*` return HTTP 410 with a stable "v1 removed" error body.
- `/opencode/*` is commented out/disabled until Phase 7 and is expected to be broken during ACP core bring-up.
Everything related to prompting/sessions/permissions/tools happens through ACP JSON-RPC messages.
## 6.3 Filesystem Boundary (Intentional)
Sandbox Agent keeps a separate host-owned filesystem API from ACP native filesystem methods.
Rationale:
- ACP `fs/*` methods are agent-protocol capabilities and can vary by agent implementation.
- Sandbox Agent filesystem HTTP endpoints are host/runtime capabilities and should behave consistently across all agents.
- Large binary transfers (raw file read/write and tar upload) need streaming-friendly HTTP behavior; ACP JSON-RPC envelopes are not suitable for super-large binary payload transport.
- `GET /v1/fs/file` specifically benefits from HTTP response streaming for large reads.
For this reason, `GET /v1/fs/file`, `PUT /v1/fs/file`, and `POST /v1/fs/upload-batch` remain dedicated HTTP endpoints even as other static control APIs migrate to ACP extensions.
Parallel ACP compatibility is still supported:
- Keep ACP extension variants in parallel for these operations.
- ACP and HTTP variants should call into the same underlying filesystem service logic so behavior remains consistent.
- ACP variants are not intended for very large file transfer; SDK defaults should prefer HTTP for these methods.
## 6.1 TypeScript SDK integration (mandatory)
Use the existing ACP TypeScript SDK (`@agentclientprotocol/sdk`) inside our SDK implementation.
Rules:
- Do not build a second in-house ACP protocol implementation in `sdks/typescript`.
- Wrap and embed ACP SDK primitives (`ClientSideConnection`/transport handling) in our SDK surface.
- Implement our own ACP-over-HTTP transport agent process for the SDK because the official ACP client SDK does not currently provide our required Streamable HTTP client behavior out of the box.
- Keep our SDK focused on:
- auth/token handling
- endpoint/bootstrap convenience
- spawn/embedded server ergonomics
- product-specific helper APIs
- ACP message framing, JSON-RPC lifecycle, and protocol object modeling should come from upstream ACP SDK.
## 6.2 Inspector (mandatory)
The inspector must be ACP-native in v1.
- Replace v1 session/event calls in inspector with ACP-over-HTTP connection flow (`initialize`, `session/new`, `session/prompt`, streamed `session/update`).
- Add inspector support for rendering raw ACP envelopes and decoded session updates.
- Keep inspector route at `/ui/`; remove dependency on v1 REST session endpoints.
- Inspector end-to-end verification is mandatory via `agent-browser` automation (not only unit/integration tests).
## 7) Data model changes (breaking)
Removed from public contract:
- `UniversalEvent`
- `UniversalItem`
- custom `permission.reply` and `question.reply` REST endpoints
- v1 `sessions/*` REST resources
Added:
- raw ACP JSON-RPC envelopes over HTTP
- explicit connection identity (`X-ACP-Connection-Id`)
## 8) Test contract for v1
Consolidated must-have suites (duplicates collapsed):
- ACP protocol conformance (JSON-RPC + ACP schema/semantics)
- Transport contract (`/v1/rpc` POST/SSE routing, ordering, replay, errors)
- End-to-end agent process matrix (includes core turn flow, cancel, HITL, streaming)
- Installer suite (explicit + lazy install, registry/fallback provenance)
- Security/auth isolation
- TypeScript SDK end-to-end (embedded + server mode, embedding `@agentclientprotocol/sdk`)
- v1 removal contract suite (`/v1/*` => HTTP 410 + stable error payload)
- Inspector ACP suite executed with `agent-browser` (ACP session flow + streaming render correctness)
- OpenCode <-> ACP bridge suite (dedicated later phase)
No synthetic protocol fixtures. Use real agent processes in integration tests.
Minimum required `agent-browser` inspector coverage:
1. Open `/ui/`, spawn an agent/session, send one message, and verify a response is rendered.
Current automation entrypoint:
- `frontend/packages/inspector/tests/agent-browser.e2e.sh`
- `server/packages/sandbox-agent/tests/v1_agent_process_matrix.rs` (deterministic agent process matrix smoke + JSON-RPC conformance checks)
## 9) Open questions to resolve before implementation lock
- Amp agent process availability and support level for v1 launch.
- Whether additional non-binary filesystem endpoints remain HTTP or migrate to ACP extensions after initial cut.
## 10) Deferred Dedicated Step: OpenCode <-> ACP
- During ACP core implementation, `/opencode/*` is commented out/disabled.
- After ACP core is stable, complete the dedicated OpenCode <-> ACP bridge step and re-enable `/opencode/*`.
- Mark the step complete only after dedicated integration tests pass.
## 11) Companion Docs
- `research/acp/v1-schema-to-acp-mapping.md` (normative 1:1 endpoint/event mapping)
- `research/acp/migration-steps.md` (execution order and rollout steps)
- `research/acp/todo.md` (phase checklist and validation tracker)
- `research/acp/acp-over-http-findings.md` (community transport findings and decision context)
- `research/acp/friction.md` (ongoing issue/decision log)
- `docs/quickstart.mdx`, `docs/cli.mdx`, `docs/sdks/typescript.mdx` (external migration and rollout guidance)
## 12) Documentation Updates (mandatory)
When implementing this spec, update docs in the same change set:
- API reference/openapi docs for v1 and `/v1/*` removal semantics
- `docs/cli.mdx` for v1 ACP and removed v1 commands
- `docs/inspector.mdx` for ACP-based inspector behavior
- SDK docs (`docs/sdks/typescript.mdx`) for ACP-over-HTTP transport usage
- Any OpenCode compatibility docs that reference `/opencode/*`