xworkmate-bridge/docs/backend-api-design.md

327 lines
9.5 KiB
Markdown
Raw Normal View History

# 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
```
2026-05-26 11:06:22 +08:00
OpenClaw task submit 也使用 `/acp/rpc`,通过
`routing.explicitExecutionTarget=gateway`
`routing.preferredGatewayProviderId=openclaw` 表达 gateway 目标。
## 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"
}
}
}
```
2026-05-26 11:06:22 +08:00
OpenClaw gateway 任务的 HTTP task submit 入口是:
```text
2026-05-26 11:06:22 +08:00
POST https://xworkmate-bridge.svc.plus/acp/rpc
```
2026-05-26 11:06:22 +08:00
它承载 `session.start` 和 follow-up `session.message`,并由 routing 字段明确声明 OpenClaw gateway 目标。
```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`,继续提交到
2026-05-26 11:06:22 +08:00
`/acp/rpc`。其他 provider 的 `session.message` 也走 `/acp``/acp/rpc`
`session.cancel``session.close` 属于 control-plane 操作,继续走 `/acp``/acp/rpc`
## 7. 清理后的 Public Surface
| Path | 协议 | APP 是否使用 | 设计定位 |
| --- | --- | --- | --- |
| `/acp` | WebSocket | 是,默认 | JSON-RPC 主入口 |
2026-05-26 11:06:22 +08:00
| `/acp/rpc` | HTTP POST | fallback / CI / 调试 / OpenClaw task submit | JSON-RPC 辅助入口 |
| `/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` 的任何引用。
2026-05-26 11:06:22 +08:00
- APP 的 Gateway/OpenClaw `session.start` 与 follow-up `session.message` 使用 `/acp/rpc` 和 routing metadata。
- 禁止把 provider/gateway 专用 URL 保存或解析为全局 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
2026-05-26 11:06:22 +08:00
/artifacts/* -> 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/commit/version/buildDate` |
| WebSocket `/acp` 握手 | `101 Switching Protocols` |
| WebSocket `acp.capabilities` | `ok=true`,返回 `agent/gateway`、`codex/opencode/gemini/hermes`、`openclaw` |
| `POST /acp/rpc acp.capabilities` | `200`,返回同一能力目录 |
2026-05-26 11:06:22 +08:00
| `POST /acp/rpc session.start` with OpenClaw routing | `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` |
2026-05-26 11:06:22 +08:00
OpenClaw task submit 当前使用 `/acp/rpc` 加 routing metadata。APP 的 capabilities、routing、agent、multi-agent、cancel 和 close 也必须继续使用 `/acp``/acp/rpc`