docs: add ACP forwarding topology

This commit is contained in:
Haitao Pan 2026-04-10 08:37:03 +08:00
parent 98a076cd65
commit 7f180e0f02
3 changed files with 100 additions and 24 deletions

View File

@ -8,6 +8,7 @@
- ACP stdio bridge entrypoint
- Go helper runtime packages used by the ACP bridge
- Unit tests for bridge routing, RPC contracts, mounts, runtime dispatch, and provider sync
- Architecture notes and public ingress topology docs in [docs/architecture/acp-forwarding-topology.md](/Users/shenlan/workspaces/cloud-neutral-toolkit/xworkmate-bridge/docs/architecture/acp-forwarding-topology.md)
## Compatibility

View File

@ -37,6 +37,12 @@ Missing bearer auth returns a JSON-RPC error envelope with code `-32001`.
## Public Validation Results
The ingress returned `200 OK` on all three public routes after re-apply, and the deployment response confirmed the active upstream mappings:
- `codex` -> `127.0.0.1:9010`
- `opencode` -> `127.0.0.1:3910`
- `gemini` -> `127.0.0.1:8791`
### Codex
Verified `acp.capabilities` over the public ingress:
@ -52,13 +58,14 @@ Verified `acp.capabilities` over the public ingress:
}
```
Verified `session.start` reached the Codex execution layer, but the task failed upstream.
Verified end-to-end task execution over the public ingress.
Observed upstream failure summary:
Observed conversation behavior:
- repeated `wss://api.openai.com/v1/responses` `500 Internal Server Error`
- final `https://api.openai.com/v1/responses` `401 Unauthorized`
- message: `Missing bearer or basic authentication in header`
- `session.start` succeeded and returned `round1`
- `session.message` also succeeded and returned `round2`
- `session.message` must include the same `routing` payload as `session.start`
- omitting `routing` returns `ROUTING_REQUIRED`
### OpenCode
@ -87,6 +94,13 @@ Observed result:
}
```
Observed conversation behavior:
- `session.start` succeeded and returned `round1`
- `session.message` also succeeded and returned `round2`
- `session.message` must include the same `routing` payload as `session.start`
- omitting `routing` returns `ROUTING_REQUIRED`
### Gemini
Verified `acp.capabilities` over the public ingress:
@ -113,6 +127,27 @@ Before the compatibility layer landed, the upstream Gemini ACP returned:
The adapter has now been updated so `session.start` and `session.message` default to adapter-local prompt compatibility instead of forwarding unsupported upstream methods.
Observed conversation behavior after re-apply:
- `session.start` succeeded and returned `round1`
- `session.message` succeeded and returned `round2`
- long conversation validation passed through the public ingress
## Long Conversation Validation
All three public ACP agent entries now pass a two-turn conversation check:
1. `session.start`
2. `session.message`
Verified result summary:
- `codex` long conversation passed
- `opencode` long conversation passed
- `gemini` long conversation passed
This is the current app-integration baseline for `acp-server.svc.plus`.
## App Integration Notes
### Recommended request shape
@ -152,22 +187,7 @@ For single-agent task execution:
### Provider-specific notes
- `opencode` is the currently verified public task path.
- `gemini` now depends on the adapter compatibility layer, not an upstream Gemini ACP conversation method.
- `codex` public routing is healthy, but task execution requires upstream OpenAI auth to be present in the runtime environment.
## Codex Runtime Root Cause
Remote inspection on `jp-xhttp-contabo.svc.plus` showed:
- `codex-app-server` only had `HOME=/root TERM=xterm-256color NODE_NO_WARNINGS=1`
- `/root/.codex` existed, but no auth/config JSON files were present
- `codex --version` was `0.117.0`
That means the deployed Codex runtime was able to start, but it did not have a usable OpenAI auth source.
For future deployments, the systemd units should provide:
- `CODEX_HOME`
- `OPENAI_API_KEY` when API-key auth is used
- optional custom base URL variables when running against a non-default upstream
- `codex`, `opencode`, and `gemini` are all now verified public task paths.
- `gemini` still depends on the adapter compatibility layer, not a native upstream Gemini ACP conversation method.
- For multi-turn flows, apps should preserve and resend `routing` on every `session.message`.
- `codex` and `opencode` currently require explicit `routing` on follow-up turns.

View File

@ -0,0 +1,55 @@
# ACP Forwarding Topology
This document describes how `xworkmate-bridge.svc.plus` forwards requests to the public ACP and gateway endpoints.
## Topology
```mermaid
flowchart TD
U[Client / App] --> B[xworkmate-bridge.svc.plus]
B -->|HTTP POST /acp/rpc| ACPRPC[ACP HTTP RPC handler]
B -->|WebSocket /acp| ACPWS[ACP WebSocket handler]
ACPRPC --> R{Method?}
ACPWS --> R
R -->|acp.capabilities| CAP[Return available provider list]
R -->|session.start / session.message| ENQ[Resolve routing and enqueue turn]
R -->|session.cancel / session.close| LIFE[Session lifecycle control]
R -->|xworkmate.providers.sync| SYNC[Sync external provider catalog]
R -->|xworkmate.gateway.*| GWAPI[Gateway control methods]
R -->|xworkmate.dispatch.resolve| DISPATCH[Dispatch resolution]
R -->|xworkmate.routing.resolve| ROUTE[Routing resolution]
ENQ --> D{Resolved execution target}
D -->|gateway / openclaw| GW[gatewayruntime.Manager]
D -->|singleAgent + codex| C[codex provider]
D -->|singleAgent + opencode| O[opencode provider]
D -->|singleAgent + gemini| G[gemini provider]
GW --> OCLAW[wss://openclaw.svc.plus]
C --> CODR[https://acp-server.svc.plus/codex/acp/rpc]
O --> OPR[https://acp-server.svc.plus/opencode/acp/rpc]
G --> GMR[https://acp-server.svc.plus/gemini/acp/rpc]
SYNC --> CAT[providerCatalog]
CAT --> C
CAT --> O
CAT --> G
```
## Request Flow
The bridge accepts ACP JSON-RPC over `POST /acp/rpc` and ACP WebSocket traffic over `/acp`.
For `session.start` and `session.message`, the server resolves routing metadata, selects either the gateway runtime or a single-agent provider, and then forwards the turn to the resolved endpoint.
For the public single-agent ACP providers, `http` and `https` endpoints are forwarded as JSON-RPC `POST .../acp/rpc` requests, while `ws` and `wss` endpoints are forwarded as WebSocket ACP sessions on `/acp`.
## Current Public Endpoints
- `wss://openclaw.svc.plus`
- `https://acp-server.svc.plus/codex/acp/rpc`
- `https://acp-server.svc.plus/opencode/acp/rpc`
- `https://acp-server.svc.plus/gemini/acp/rpc`