327 lines
9.6 KiB
Markdown
327 lines
9.6 KiB
Markdown
# 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 也使用 `/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"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
OpenClaw gateway 任务的 HTTP task submit 入口是:
|
||
|
||
```text
|
||
POST https://xworkmate-bridge.svc.plus/acp/rpc
|
||
```
|
||
|
||
它承载 `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`,继续提交到
|
||
`/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 主入口 |
|
||
| `/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` 的任何引用。
|
||
- 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-06-06 通过 `ssh ubuntu@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
|
||
/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 | 说明 |
|
||
| --- | --- | --- |
|
||
| `~/.config/systemd/user/xworkmate-bridge.service` | `127.0.0.1:8787` | Public bridge origin, runs as `ubuntu`, binary at `/home/ubuntu/.local/bin/xworkmate-go-core` |
|
||
| `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 不保存、不展示、不请求这些地址。
|
||
|
||
验证时 `systemctl --user status xworkmate-bridge.service` 为 `active`,系统级 `/etc/systemd/system/xworkmate-bridge.service` 为 `disabled/inactive`。`acp-codex`、`acp-gemini`、`acp-hermes`、`acp-opencode` 仍由现有本机 service 提供。APP contract 只记录 provider/gateway 能力,不把 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`,返回同一能力目录 |
|
||
| `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` |
|
||
|
||
OpenClaw task submit 当前使用 `/acp/rpc` 加 routing metadata。APP 的 capabilities、routing、agent、multi-agent、cancel 和 close 也必须继续使用 `/acp` 或 `/acp/rpc`。
|