diff --git a/README.md b/README.md index e294bfa..498e877 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ This repository exposes one bridge entrypoint and forwards to four verified publ Example provider sync config: [example/config.yaml](/Users/shenlan/workspaces/cloud-neutral-toolkit/xworkmate-bridge/example/config.yaml) +API reference: [docs/api-reference.md](/Users/shenlan/workspaces/cloud-neutral-toolkit/xworkmate-bridge/docs/api-reference.md) + ## Compatibility For compatibility with `xworkmate-app`, the built helper binary name remains `xworkmate-go-core`. diff --git a/docs/api-reference.md b/docs/api-reference.md new file mode 100644 index 0000000..28bb6d5 --- /dev/null +++ b/docs/api-reference.md @@ -0,0 +1,605 @@ +# 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 + +### 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 ` + +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.providers.sync` | Sync external single-agent provider catalog into the bridge | +| `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, + "providers": ["codex", "gemini", "opencode"], + "capabilities": { + "single_agent": true, + "multi_agent": true, + "providers": ["codex", "gemini", "opencode"] + } + } +} +``` + +Notes: + +- `providers` is the union of: + - synced external providers from `xworkmate.providers.sync` + - locally detected ACP providers from `shared.DetectACPProviders()` +- `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 +} +``` + +### 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 +} +``` + +### 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 + - endpoint target + - provider + - model + - selected skills + - install suggestion / unavailable state + +Key input fields: + +- `taskPrompt` +- `workingDirectory` +- `routing.routingMode` +- `routing.preferredGatewayTarget` +- `routing.explicitExecutionTarget` +- `routing.explicitProviderId` +- `routing.explicitModel` +- `routing.explicitSkills` +- `routing.allowSkillInstall` +- `routing.installApproval` +- `routing.availableSkills` +- `aiGatewayBaseUrl` +- `aiGatewayApiKey` + +Representative response fields: + +- `resolvedExecutionTarget` +- `resolvedEndpointTarget` +- `resolvedProviderId` +- `resolvedModel` +- `resolvedSkills` +- `skillResolutionSource` +- `needsSkillInstall` +- `unavailable` +- `unavailableCode` +- `unavailableMessage` +- `skillInstallRequestId` +- `skillCandidates` +- `memorySources` + +### 3.8 `xworkmate.providers.sync` + +Purpose: + +- register external ACP single-agent providers into the bridge + +Request example: + +```json +{ + "jsonrpc": "2.0", + "id": "sync-1", + "method": "xworkmate.providers.sync", + "params": { + "providers": [ + { + "providerId": "opencode", + "label": "OpenCode", + "endpoint": "https://acp-server.svc.plus/opencode/acp/rpc", + "authorizationHeader": "Bearer ${OPENCODE_AUTH_TOKEN}", + "enabled": true + } + ] + } +} +``` + +Provider fields: + +- `providerId` +- `label` +- `endpoint` +- `authorizationHeader` +- `enabled` + +Response shape: + +```json +{ + "ok": true, + "providers": [ + { + "providerId": "opencode", + "label": "OpenCode", + "endpoint": "https://acp-server.svc.plus/opencode/acp/rpc", + "enabled": true + } + ] +} +``` + +### 3.9 `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.10 Gateway runtime methods + +#### `xworkmate.gateway.connect` + +Purpose: + +- connect a bridge runtime session to the gateway runtime + +Key params: + +- `runtimeId` +- `mode` +- `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` + +#### `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 + +## 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 ` + +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: " +} +``` + +### 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 ` +- 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.