xworkmate-bridge/docs/api-reference.md

687 lines
17 KiB
Markdown

# API Interface Reference
This document organizes the current API surface of `xworkmate-bridge` based on the actual code paths in this repository.
It focuses on:
- the ACP Bridge exposed by `xworkmate-go-core serve`
- the Gemini ACP adapter exposed by `xworkmate-go-core gemini-acp-adapter`
- auxiliary HTTP handlers that exist in code but are not currently mounted by `main.go`
## 1. Runtime Entry Points
The binary currently exposes these runtime modes:
```bash
./build/bin/xworkmate-go-core serve
./build/bin/xworkmate-go-core acp-stdio
./build/bin/xworkmate-go-core gemini-acp-adapter
```
Relevant source:
- [main.go](/Users/shenlan/workspaces/cloud-neutral-toolkit/xworkmate-bridge/main.go)
- [internal/acp/server.go](/Users/shenlan/workspaces/cloud-neutral-toolkit/xworkmate-bridge/internal/acp/server.go)
- [internal/geminiadapter/server.go](/Users/shenlan/workspaces/cloud-neutral-toolkit/xworkmate-bridge/internal/geminiadapter/server.go)
## 2. ACP Bridge HTTP / WebSocket API
Canonical APP-facing public origin:
- `https://xworkmate-bridge.svc.plus`
Canonical APP-facing ACP paths:
- `POST /acp/rpc`
- `GET /acp` for WebSocket ACP
Independent upstream ACP and gateway services may exist behind the bridge, but
they are not the primary APP contract.
### 2.1 Default listen address
`serve` mode reads:
- `ACP_LISTEN_ADDR`, default `127.0.0.1:8787`
### 2.2 Exposed routes
When running `xworkmate-go-core serve`, only these two routes are mounted:
| Path | Protocol | Purpose |
| --- | --- | --- |
| `/acp/rpc` | HTTP POST | JSON-RPC entrypoint |
| `/acp` | WebSocket | ACP over WebSocket |
Any other path returns `404`.
### 2.3 Auth and CORS
Bridge auth is bearer-token based:
- Environment variable: `ACP_AUTH_TOKEN`
- Required header: `Authorization: Bearer <token>`
Origin allowlist comes from:
- `ACP_ALLOWED_ORIGINS`
- default: `https://xworkmate.svc.plus,http://localhost:*,http://127.0.0.1:*`
Behavior summary:
- missing or invalid bearer token: HTTP `401`, JSON-RPC error code `-32001`
- disallowed origin: HTTP `403`, JSON-RPC error code `-32003`
- `OPTIONS /acp/rpc` is supported for CORS preflight
Relevant source:
- [internal/acp/server.go](/Users/shenlan/workspaces/cloud-neutral-toolkit/xworkmate-bridge/internal/acp/server.go)
- [internal/acp/web_contract.go](/Users/shenlan/workspaces/cloud-neutral-toolkit/xworkmate-bridge/internal/acp/web_contract.go)
### 2.4 Content negotiation
For `POST /acp/rpc`:
- normal JSON-RPC response: `Content-Type: application/json`
- if `Accept` contains `text/event-stream`, the server streams notifications as SSE and sends the final JSON-RPC result through SSE as well
### 2.5 JSON-RPC methods exposed by the bridge
The bridge currently handles these methods:
| Method | Description |
| --- | --- |
| `acp.capabilities` | Return current bridge capability summary |
| `session.start` | Start a task session |
| `session.message` | Continue an existing session |
| `session.cancel` | Cancel an active session |
| `session.close` | Close session state |
| `xworkmate.dispatch.resolve` | Resolve provider choice from candidate providers and requirements |
| `xworkmate.routing.resolve` | Resolve execution target / provider / skills from routing metadata |
| `xworkmate.mounts.reconcile` | Reconcile managed MCP configuration and mount-related settings |
| `xworkmate.gateway.connect` | Connect bridge runtime to gateway |
| `xworkmate.gateway.request` | Send a request to the connected gateway runtime |
| `xworkmate.gateway.disconnect` | Disconnect gateway runtime |
Unknown methods return JSON-RPC error code `-32601`.
## 3. Bridge Method Details
### 3.1 `acp.capabilities`
Request:
```json
{
"jsonrpc": "2.0",
"id": "cap-1",
"method": "acp.capabilities"
}
```
Response shape:
```json
{
"jsonrpc": "2.0",
"id": "cap-1",
"result": {
"singleAgent": true,
"multiAgent": true,
"providerCatalog": [
{ "providerId": "codex", "label": "Codex" },
{ "providerId": "opencode", "label": "OpenCode" },
{ "providerId": "gemini", "label": "Gemini" }
],
"gatewayProviders": [
{ "providerId": "openclaw", "label": "OpenClaw" }
],
"capabilities": {
"single_agent": true,
"multi_agent": true,
"providerCatalog": [
{ "providerId": "codex", "label": "Codex" },
{ "providerId": "opencode", "label": "OpenCode" },
{ "providerId": "gemini", "label": "Gemini" }
],
"gatewayProviders": [
{ "providerId": "openclaw", "label": "OpenClaw" }
]
}
}
}
```
Notes:
- `providerCatalog` is bridge-owned and built in at startup
- `gatewayProviders` is the APP-facing gateway provider catalog
- production upstream routing map is fixed to:
- `codex` -> `https://acp-server.svc.plus/codex/acp/rpc`
- `opencode` -> `https://acp-server.svc.plus/opencode/acp/rpc`
- `gemini` -> `https://acp-server.svc.plus/gemini/acp/rpc`
- APP traffic reaches those upstreams through the bridge's canonical public
ACP path, not by depending on upstream URLs directly
- upstream ACP auth prefers bridge-owned service auth and otherwise reuses the
inbound bridge bearer header
- `multiAgent` is controlled by `ACP_MULTI_AGENT_ENABLED`, default `true`
### 3.2 `session.start`
Starts a session and resets any existing state with the same `sessionId`.
Minimum required params:
```json
{
"sessionId": "session-1"
}
```
Typical request:
```json
{
"jsonrpc": "2.0",
"id": "task-1",
"method": "session.start",
"params": {
"sessionId": "session-1",
"threadId": "thread-1",
"taskPrompt": "Reply with exactly pong",
"workingDirectory": "/tmp/demo",
"routing": {
"routingMode": "explicit",
"explicitExecutionTarget": "singleAgent",
"explicitProviderId": "opencode"
}
}
}
```
Rules:
- `sessionId` is required, otherwise `-32602`
- `threadId` defaults to `sessionId`
- work is queued per `threadId`
- for public single-agent multi-turn usage, `routing` should be resent on later turns
### 3.3 `session.message`
Continues an existing session.
Minimum required params:
```json
{
"sessionId": "session-1"
}
```
Typical request:
```json
{
"jsonrpc": "2.0",
"id": "task-2",
"method": "session.message",
"params": {
"sessionId": "session-1",
"threadId": "thread-1",
"taskPrompt": "Continue the previous task",
"workingDirectory": "/tmp/demo",
"routing": {
"routingMode": "explicit",
"explicitExecutionTarget": "singleAgent",
"explicitProviderId": "opencode"
}
}
}
```
### 3.4 `session.cancel`
Request:
```json
{
"jsonrpc": "2.0",
"id": "cancel-1",
"method": "session.cancel",
"params": {
"sessionId": "session-1"
}
}
```
Response:
```json
{
"accepted": true,
"cancelled": true
}
```
Notes:
- `accepted` indicates the request envelope was accepted
- `cancelled` is `true` only when an active session was actually cancelled
- if the session does not exist or is already finished, `cancelled` may be
`false`
### 3.5 `session.close`
Request:
```json
{
"jsonrpc": "2.0",
"id": "close-1",
"method": "session.close",
"params": {
"sessionId": "session-1"
}
}
```
Response:
```json
{
"accepted": true,
"closed": true
}
```
Notes:
- `accepted` indicates the request envelope was accepted
- `closed` is `true` only when an existing session state was actually closed
- if the session does not exist or is already gone, `closed` may be `false`
### 3.6 `xworkmate.dispatch.resolve`
Purpose:
- choose a provider from a list of candidates
- apply preferred provider and capability constraints
- optionally consider node state and node info
Key params:
- `providers`: array of provider definitions
- `preferredProviderId`
- `requiredCapabilities`
- `nodeState`
- `nodeInfo`
Provider item shape:
```json
{
"id": "codex",
"name": "Codex",
"defaultArgs": ["app-server"],
"capabilities": ["singleAgent", "tools"]
}
```
### 3.7 `xworkmate.routing.resolve`
Purpose:
- resolve routing metadata into:
- execution target
- provider
- gateway provider
- model
- selected skills
- install suggestion / unavailable state
Canonical use:
- apps should use this method as the single preflight source for:
- effective execution target
- effective provider selection
- unavailable code / message
- apps should not re-derive provider availability or `auto` resolution from
`acp.capabilities`
Key input fields:
- `taskPrompt`
- `workingDirectory`
- `routing.routingMode`
- `routing.preferredGatewayProviderId`
- `routing.explicitExecutionTarget`
- `routing.explicitProviderId`
- `routing.explicitModel`
- `routing.explicitSkills`
- `routing.allowSkillInstall`
- `routing.installApproval`
- `routing.availableSkills`
- `aiGatewayBaseUrl`
- `aiGatewayApiKey`
Representative response fields:
- `resolvedExecutionTarget`
- `resolvedProviderId`
- `resolvedGatewayProviderId`
- `resolvedModel`
- `resolvedSkills`
- `skillResolutionSource`
- `needsSkillInstall`
- `unavailable`
- `unavailableCode`
- `unavailableMessage`
- `skillInstallRequestId`
- `skillCandidates`
- `memorySources`
APP-facing interpretation:
- if `resolvedExecutionTarget = single-agent`, use `resolvedProviderId`
- if `resolvedExecutionTarget = gateway`, use `resolvedGatewayProviderId`
### 3.7.1 UI / APP consumption model
Recommended APP-side flow:
1. Call `acp.capabilities` at startup or refresh time.
2. Read:
- `providerCatalog` as `singleAgentProviders`
- `gatewayProviders` as `gatewayProviders`
3. Before execution, call `xworkmate.routing.resolve`.
4. Use the resolved fields, not local heuristics, to decide which UI state and
execution branch to use.
5. Send `session.start` or `session.message` through the bridge canonical path.
Suggested APP-side view model:
```json
{
"executionTargets": ["single-agent", "multi-agent", "gateway"],
"singleAgentProviders": ["codex", "opencode", "gemini"],
"gatewayProviders": ["openclaw"]
}
```
Recommended interpretation rules:
- if `resolvedExecutionTarget = single-agent`
- read `resolvedProviderId`
- ignore `resolvedGatewayProviderId`
- if `resolvedExecutionTarget = multi-agent`
- treat the run as bridge-orchestrated multi-agent execution
- do not force a single provider picker as the primary routing control
- if `resolvedExecutionTarget = gateway`
- read `resolvedGatewayProviderId`
- ignore `resolvedProviderId`
UI binding guidance:
- provider picker for single-agent mode should be populated from
`providerCatalog`
- gateway picker should be populated from `gatewayProviders`
- gateway UI should display the bridge-owned `openclaw` provider from
`gatewayProviders`
- disabled or unavailable states should come from `xworkmate.routing.resolve`
response fields such as:
- `unavailable`
- `unavailableCode`
- `unavailableMessage`
Do not:
- infer provider availability from hardcoded lists
- treat `openclaw` as a single-agent provider
- re-derive auto-routing from prompt text on the APP side
- use upstream URLs as the APP-facing contract
### 3.8 `xworkmate.mounts.reconcile`
Purpose:
- reconcile managed MCP server config for supported local tools and homes
Key params:
- `config.autoSync`
- `config.usesAris`
- `config.managedMcpServers`
- `aiGatewayUrl`
- `configuredCodexCliPath`
- `codexHome`
- `opencodeHome`
- `openclawHome`
- `aris`
Managed MCP server item shape:
```json
{
"id": "xworkmate_server",
"command": "xworkmate-mcp",
"args": ["--port", "7777"],
"enabled": true
}
```
### 3.9 Gateway runtime methods
#### `xworkmate.gateway.connect`
Purpose:
- connect a bridge runtime session to the bridge-owned production gateway route
- from the APP perspective this still enters through the canonical bridge ACP
path and bridge JSON-RPC methods, not a direct `openclaw` URL contract
Key params:
- `runtimeId`
- `gatewayProviderId`
- `clientId`
- `locale`
- `userAgent`
- `connectAuthMode`
- `connectAuthFields`
- `connectAuthSources`
- `hasSharedAuth`
- `hasDeviceToken`
- `endpoint.host`
- `endpoint.port`
- `endpoint.tls`
- `packageInfo`
- `deviceInfo`
- `identity`
- `auth`
Response fields:
- `ok`
- `snapshot`
- `auth`
- `returnedDeviceToken`
- `error`
Notes:
- empty or unsupported `gatewayProviderId` values are normalized to
`openclaw`
- for `gatewayProviderId=openclaw`, the bridge overrides runtime endpoint
selection to `wss://openclaw.svc.plus`
- upstream gateway auth uses `Authorization: Bearer $INTERNAL_SERVICE_TOKEN`
- the app does not provide production openclaw endpoint truth
#### `xworkmate.gateway.request`
Purpose:
- send a gateway runtime RPC-like request through an existing runtime connection
Params:
- `runtimeId`
- `method`
- `params`
- `timeoutMs`
Response fields:
- `ok`
- `payload`
- `error`
#### `xworkmate.gateway.disconnect`
Params:
- `runtimeId`
Response:
```json
{
"accepted": true
}
```
## 4. WebSocket Contract
`/acp` accepts the same JSON-RPC method set as `/acp/rpc`.
Differences from HTTP:
- each inbound message is a JSON-RPC request frame
- notifications are written back as WebSocket JSON messages
- result envelopes and error envelopes are also written as WebSocket JSON messages
Observed bridge behavior on the public deployment:
- authenticated plain `GET /acp` without WebSocket upgrade headers returns HTTP
`400 Bad Request`
- authenticated `GET /acp` with valid WebSocket upgrade headers returns HTTP
`101 Switching Protocols`
## 5. Gemini ACP Adapter API
### 5.1 Default listen address
`gemini-acp-adapter` reads:
- `GEMINI_ADAPTER_LISTEN_ADDR`, default `127.0.0.1:8791`
### 5.2 Exposed routes
When running `xworkmate-go-core gemini-acp-adapter`, only these routes are mounted:
| Path | Protocol | Purpose |
| --- | --- | --- |
| `/acp/rpc` | HTTP POST | Adapter JSON-RPC entrypoint |
| `/acp` | WebSocket | Adapter WebSocket JSON-RPC entrypoint |
### 5.3 Auth and CORS
Adapter auth is separate from bridge auth:
- Environment variable: `GEMINI_ADAPTER_AUTH_TOKEN`
- Required header: `Authorization: Bearer <token>`
Allowed origins come from:
- `GEMINI_ADAPTER_ALLOWED_ORIGINS`
- default: `https://xworkmate.svc.plus,http://localhost:*,http://127.0.0.1:*`
### 5.4 Adapter JSON-RPC methods
| Method | Description |
| --- | --- |
| `acp.capabilities` | Synthesized Gemini single-agent capability response |
| `session.start` | Start adapter-local Gemini session |
| `session.message` | Continue adapter-local Gemini session |
| `session.cancel` | Accept cancel request, currently returns `cancelled: false` |
| `session.close` | Close adapter-local session |
| `gemini.initialize` | Return upstream initialize result |
| `gemini.raw` | Forward raw Gemini-facing payload handling |
Unsupported methods return:
```json
{
"success": false,
"error": "unsupported method: <method>"
}
```
### 5.5 Core adapter env vars
- `GEMINI_ADAPTER_LISTEN_ADDR`
- `GEMINI_ADAPTER_BIN`
- `GEMINI_ADAPTER_ARGS`
- `GEMINI_ADAPTER_PROTOCOL_VERSION`
- `GEMINI_ADAPTER_AUTH_TOKEN`
- `GEMINI_ADAPTER_PROVIDER_ID`
- `GEMINI_ADAPTER_PROVIDER_LABEL`
- `GEMINI_ADAPTER_ALLOWED_ORIGINS`
- `GEMINI_ADAPTER_UPSTREAM_METHOD`
- `ACP_GEMINI_BIN`
## 6. Auxiliary HTTP Handlers Present in Code
The repository also contains two plain HTTP handlers:
- [internal/handler/auth_handler.go](/Users/shenlan/workspaces/cloud-neutral-toolkit/xworkmate-bridge/internal/handler/auth_handler.go)
- [internal/handler/token_auth_handler.go](/Users/shenlan/workspaces/cloud-neutral-toolkit/xworkmate-bridge/internal/handler/token_auth_handler.go)
These handlers are currently not mounted by `main.go`, so they are not part of the live binary HTTP routing surface unless another embedding program wires them in.
### 6.1 Username/password auth handler
Request body:
```json
{
"username": "demo",
"password": "secret"
}
```
Behavior:
- invalid JSON -> `400 invalid json`
- auth failure -> `401 <error message>`
- success -> `200 {"status":"ok"}`
### 6.2 Bearer token auth handler
Behavior:
- no service -> `503 service unavailable`
- invalid bearer token -> `401 unauthorized`
- success -> `200 {"ok":true}`
## 7. Public Deployment Notes
Existing project docs already record the current public ingress convention:
- Bridge-facing public ACP HTTP JSON-RPC path: `.../acp/rpc`
- WebSocket ACP path: `.../acp`
Reference docs:
- [docs/acp-public-validation-2026-04-09.md](/Users/shenlan/workspaces/cloud-neutral-toolkit/xworkmate-bridge/docs/acp-public-validation-2026-04-09.md)
- [docs/gemini-acp-adapter.md](/Users/shenlan/workspaces/cloud-neutral-toolkit/xworkmate-bridge/docs/gemini-acp-adapter.md)
- [docs/architecture/acp-forwarding-topology.md](/Users/shenlan/workspaces/cloud-neutral-toolkit/xworkmate-bridge/docs/architecture/acp-forwarding-topology.md)
## 8. Suggested Maintenance Rule
If a new externally callable method is added to:
- [internal/acp/server.go](/Users/shenlan/workspaces/cloud-neutral-toolkit/xworkmate-bridge/internal/acp/server.go)
- [internal/geminiadapter/server.go](/Users/shenlan/workspaces/cloud-neutral-toolkit/xworkmate-bridge/internal/geminiadapter/server.go)
then this document should be updated in the same change.