xworkmate-bridge/docs/backend-api-design.md
2026-05-03 12:14:31 +08:00

332 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# XWorkmate Bridge Backend API Design
Last verified: 2026-05-03
本文档定义 `xworkmate-bridge``xworkmate-app` 提供后端服务时的最佳接口设计。当前设计以线上环境为准,并把 WebSocket 作为默认运行时协议。
## 1. 设计目标
`xworkmate-app` 只连接 `xworkmate-bridge`,不保存也不拼接任何 provider 或 gateway 的内部地址。
APP 侧只需要保存:
```text
BRIDGE_SERVER_URL=https://xworkmate-bridge.svc.plus
BRIDGE_WS_URL=wss://xworkmate-bridge.svc.plus/acp
BRIDGE_HTTP_RPC_URL=https://xworkmate-bridge.svc.plus/acp/rpc
BRIDGE_AUTH_TOKEN=<provided by account/profile sync>
```
APP 所有能力发现、路由决策和任务执行都通过 bridge 的 JSON-RPC contract 完成:
```text
xworkmate-app
-> wss://xworkmate-bridge.svc.plus/acp
-> acp.capabilities
-> xworkmate.routing.resolve
-> session.start / session.message / session.cancel / session.close
-> bridge 内部路由到 codex / opencode / gemini / hermes / openclaw
```
例外OpenClaw task submit 的 HTTP fallback 专用入口是
`POST https://xworkmate-bridge.svc.plus/gateway/openclaw`。它只接受
`session.start` 和同一任务生命周期内的 follow-up `session.message`,不得作为
capabilities、routing、cancel、close 或其他 provider 的通用 ACP base endpoint。
## 2. App-Facing Contract
### 2.1 默认传输
默认传输是 JSON-RPC over WebSocket
```text
wss://xworkmate-bridge.svc.plus/acp
```
WebSocket 握手必须带:
```http
Authorization: Bearer $BRIDGE_AUTH_TOKEN
Origin: https://xworkmate.svc.plus
```
连接建立后,每个消息都是 JSON-RPC 2.0 frame。
### 2.2 HTTP RPC
HTTP JSON-RPC 仅用于 CI、脚本、调试、诊断和兼容 fallback。除 OpenClaw task submit 之外canonical HTTP RPC 是:
```text
POST https://xworkmate-bridge.svc.plus/acp/rpc
```
请求头同样必须带:
```http
Authorization: Bearer $BRIDGE_AUTH_TOKEN
Origin: https://xworkmate.svc.plus
Content-Type: application/json
```
### 2.3 Health
发布和运行验证使用:
```text
GET https://xworkmate-bridge.svc.plus/api/ping
```
该接口用于验证运行中的 bridge 镜像、tag、commit、version 和状态,不参与 APP 任务路由。
## 3. JSON-RPC 方法
APP-facing 稳定方法只有以下几组。
| Method | 用途 |
| --- | --- |
| `acp.capabilities` | 获取 bridge 当前能力目录 |
| `xworkmate.routing.resolve` | 让 bridge 计算路由,不执行任务 |
| `session.start` | 启动一个任务或首轮对话 |
| `session.message` | 同 session 继续追问 |
| `session.cancel` | 取消当前 session |
| `session.close` | 关闭 session 并释放 bridge 内部状态 |
| `xworkmate.gateway.connect` | gateway runtime 控制面连接 |
| `xworkmate.gateway.request` | gateway runtime 控制面请求 |
| `xworkmate.gateway.disconnect` | gateway runtime 控制面断开 |
APP 不应调用 provider-specific URL。Provider 与 gateway 只能来自 `acp.capabilities` 的返回值。
## 4. 能力发现
请求:
```json
{
"jsonrpc": "2.0",
"id": "cap-1",
"method": "acp.capabilities",
"params": {}
}
```
线上验证返回的核心结构:
```json
{
"availableExecutionTargets": ["agent", "gateway"],
"providerCatalog": [
{ "providerId": "codex", "label": "Codex", "targets": ["agent"], "category": "native" },
{ "providerId": "opencode", "label": "OpenCode", "targets": ["agent"], "category": "native" },
{ "providerId": "gemini", "label": "Gemini", "targets": ["agent"], "category": "protocol-adapter" },
{ "providerId": "hermes", "label": "Hermes", "targets": ["agent"], "category": "protocol-adapter" }
],
"gatewayProviders": [
{ "providerId": "openclaw", "label": "OpenClaw", "targets": ["gateway"] }
]
}
```
APP UI 只能用这些字段驱动 provider/gateway 展示:
- `providerCatalog`
- `gatewayProviders`
- `availableExecutionTargets`
不得在 APP 代码里静态保存:
- `codex` URL
- `opencode` URL
- `gemini` URL
- `hermes` URL
- `openclaw` URL
- 本地端口
- systemd unit 名
## 5. 路由决策
单 Agent 显式路由示例:
```json
{
"jsonrpc": "2.0",
"id": "route-agent-1",
"method": "xworkmate.routing.resolve",
"params": {
"taskPrompt": "create a powerpoint deck",
"workingDirectory": "/tmp/work",
"routing": {
"routingMode": "explicit",
"explicitExecutionTarget": "singleAgent",
"explicitProviderId": "codex"
}
}
}
```
Gateway/OpenClaw 显式路由示例:
```json
{
"jsonrpc": "2.0",
"id": "route-gateway-1",
"method": "xworkmate.routing.resolve",
"params": {
"taskPrompt": "run this through OpenClaw",
"workingDirectory": "/tmp/work",
"routing": {
"routingMode": "explicit",
"explicitExecutionTarget": "gateway",
"preferredGatewayProviderId": "openclaw"
}
}
}
```
返回字段:
- `resolvedExecutionTarget`
- `resolvedProviderId`
- `resolvedGatewayProviderId`
- `resolvedModel`
- `resolvedSkills`
- `status`
- `unavailable`
- `unavailableCode`
- `unavailableMessage`
- `skillResolutionSource`
- `needsSkillInstall`
- `skillInstallRequestId`
## 6. 任务执行
单 Agent 任务:
```json
{
"jsonrpc": "2.0",
"id": "task-1",
"method": "session.start",
"params": {
"sessionId": "s1",
"threadId": "t1",
"taskPrompt": "create a powerpoint deck",
"workingDirectory": "/tmp/work",
"routing": {
"routingMode": "explicit",
"explicitExecutionTarget": "singleAgent",
"explicitProviderId": "codex"
}
}
}
```
OpenClaw gateway 任务的 HTTP task submit 专用入口是:
```text
POST https://xworkmate-bridge.svc.plus/gateway/openclaw
```
它只承载 `session.start` 和 follow-up `session.message`。Bridge 会强制注入
`explicitExecutionTarget=gateway``preferredGatewayProviderId=openclaw`,并拒绝
`multiAgent=true`、agent/provider 冲突参数、`acp.capabilities`、`xworkmate.routing.resolve`、`session.cancel` 和 `session.close`
```json
{
"jsonrpc": "2.0",
"id": "gateway-task-1",
"method": "session.start",
"params": {
"sessionId": "s-gateway-1",
"threadId": "t-gateway-1",
"taskPrompt": "run through OpenClaw",
"workingDirectory": "/tmp/work",
"routing": {
"routingMode": "explicit",
"explicitExecutionTarget": "gateway",
"preferredGatewayProviderId": "openclaw"
}
}
}
```
OpenClaw 的 `session.message` 复用同一 `sessionId` / `threadId`,继续提交到
`/gateway/openclaw`。其他 provider 的 `session.message``/acp``/acp/rpc`
`session.cancel``session.close` 属于 control-plane 操作,继续走 `/acp``/acp/rpc`
## 7. 清理后的 Public Surface
| Path | 协议 | APP 是否使用 | 设计定位 |
| --- | --- | --- | --- |
| `/acp` | WebSocket | 是,默认 | JSON-RPC 主入口 |
| `/acp/rpc` | HTTP POST | 仅 fallback / CI / 调试 | JSON-RPC 辅助入口 |
| `/gateway/openclaw` | HTTP POST | 仅 OpenClaw task submit | 只接受 `session.start` / `session.message` |
| `/api/ping` | HTTP GET | 否 | 发布与运行健康检查 |
| `/` | HTTP GET | 否 | 简单运行状态 |
| `/acp-server/*` | 无 APP contract | 否 | 线上 Caddy 显式返回 `404` |
陈旧接口清理规则:
- 删除 APP 侧对 `/acp-server/codex`、`/acp-server/opencode`、`/acp-server/gemini`、`/acp-server/hermes` 的任何引用。
- 只允许 APP 的 Gateway/OpenClaw `session.start` 与 follow-up `session.message` 使用 `/gateway/openclaw`
- 禁止把 `/gateway/openclaw` 保存或解析为全局 ACP base endpoint。
- 不在 APP 侧保存 provider/gateway URL、端口或 service 名。
- 不把 provider 选择逻辑散落在 APP 的 URL 拼接逻辑里。
- 所有 provider/gateway 能力与可用性都来自 `acp.capabilities`
## 8. 线上环境事实
以下为 2026-05-03 通过 `ssh root@xworkmate-bridge.svc.plus` 核对的部署事实。它们用于 bridge 运维和验证,不属于 APP contract。
### Caddy
`/etc/caddy/conf.d/xworkmate-bridge.caddy` 当前只反代:
```text
/api* -> 127.0.0.1:8787
/acp* -> 127.0.0.1:8787
/gateway/openclaw -> 127.0.0.1:8787
/acp-server/* -> 404
/ -> 127.0.0.1:8787
```
Caddy 层要求:
```http
Authorization: Bearer $BRIDGE_AUTH_TOKEN
```
### Systemd / Local Listeners
| Unit / Runtime | Listener | 说明 |
| --- | --- | --- |
| `xworkmate-bridge.service` | `127.0.0.1:8787` | Public bridge origin |
| `acp-codex.service` | `127.0.0.1:9001` | Codex ACP backend |
| `acp-gemini.service` | `127.0.0.1:8791` | Gemini adapter |
| `acp-hermes.service` | `127.0.0.1:3920` | Hermes adapter |
| `acp-opencode.service` | `127.0.0.1:38992` | OpenCode adapter |
| OpenClaw runtime process | `ws://127.0.0.1:18789` | OpenClaw gateway runtime listener |
这些地址只允许 bridge 内部使用。APP 不保存、不展示、不请求这些地址。
验证时 `xworkmate-bridge`、`acp-codex`、`acp-gemini`、`acp-hermes`、`acp-opencode` 均为 `active``openclaw-gateway.service` 返回 `inactive`,但 `ss` 显示 `openclaw` 进程仍监听 `127.0.0.1:18789``[::1]:18789`。因此 APP contract 只记录 `openclaw` 作为 `gatewayProviders` 能力,不把 systemd unit 状态作为 APP 可见状态。
## 9. 线上验证结果
2026-05-03 使用 `Authorization: Bearer $BRIDGE_AUTH_TOKEN``Origin: https://xworkmate.svc.plus` 验证:
| 验证项 | 结果 |
| --- | --- |
| `GET /api/ping` | `200`,返回 `status=image/tag/commit/version` |
| WebSocket `/acp` 握手 | `101 Switching Protocols` |
| WebSocket `acp.capabilities` | `ok=true`,返回 `agent/gateway`、`codex/opencode/gemini/hermes`、`openclaw` |
| `POST /acp/rpc acp.capabilities` | `200`,返回同一能力目录 |
| `POST /gateway/openclaw session.start` | `200`,成功或 structured provider failure不应是 route/auth failure |
| `POST /acp-server/hermes` | `404` |
| `POST /acp-server/codex` | `404` |
| `POST /acp-server/gemini` | `404` |
| `POST /acp-server/opencode` | `404` |
`/gateway/openclaw` 当前是专用 OpenClaw task submit contract不是全局 ACP base endpoint。APP 的
capabilities、routing、agent、multi-agent、cancel 和 close 必须继续使用 `/acp``/acp/rpc`