make, README and docs: build and install from source
- Makefile: make / run / install / uninstall / deps / test / serve / setup /
hands / relay-run / server / dist / clean (macOS and Linux).
- README.md and docs/: install (all platforms, data locations, troubleshooting),
multi-device (brain, hands, screens, pairing, what the offline messages mean),
architecture (layers, data, security, sync, keys, hands, picture helper),
protocol (relay and AnyBot endpoints, WebSocket frames, sync ops), release
(packaging, Gitea Actions, Linux and Mac runners).
- install.sh --deps-only, bundle.sh KEEP_APP=1 (used by make deps / install).
- FEATURES.md: the multi-device part is done.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uirha3oEtWeHh58zA7ErHa
2026-11-04 14:16:45 +00:00
|
|
|
|
# 介面與長連線格式
|
|
|
|
|
|
|
|
|
|
|
|
給要改帳號伺服器或寫其他用戶端的人。所有回覆都是 JSON;錯誤是 `{"error": "白話的說明"}` 加上對應的 HTTP 狀態碼。
|
|
|
|
|
|
|
|
|
|
|
|
## 身分
|
|
|
|
|
|
|
|
|
|
|
|
| 誰 | 怎麼證明 | 從哪來 |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| 人(手機) | `Authorization: Bearer <session>` | `POST /relay/login` |
|
|
|
|
|
|
| 一台 AnyBot(主機) | `Authorization: Bearer <host token>` | `POST /relay/hosts`(登入後)或 `POST /relay/pair/claim`(配對碼) |
|
|
|
|
|
|
|
|
|
|
|
|
伺服器只存密碼和金鑰的雜湊值。
|
|
|
|
|
|
|
|
|
|
|
|
## 帳號伺服器(relay)
|
|
|
|
|
|
|
|
|
|
|
|
### 帳號
|
|
|
|
|
|
|
|
|
|
|
|
| 方法 | 路徑 | 說明 |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| POST | `/relay/signup` | `{user, password, invite}`。第一個帳號不用邀請碼,之後要 `ANYBOT_RELAY_INVITE` |
|
|
|
|
|
|
| POST | `/relay/login` | `{user, password, device}` → `{token}`。錯 8 次停 5 分鐘 |
|
|
|
|
|
|
| POST | `/relay/logout` | 登出這個 session |
|
|
|
|
|
|
| GET | `/relay/me` | 帳號、可用的 AnyBot(含 `online`、`uses`、`hands`)、登入過的裝置、有沒有備份 |
|
|
|
|
|
|
|
|
|
|
|
|
### 主機
|
|
|
|
|
|
|
|
|
|
|
|
| 方法 | 路徑 | 說明 |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| POST | `/relay/hosts` | (人)`{name}` → `{id, token}`。同名的主機會換新金鑰 |
|
|
|
|
|
|
| POST | `/relay/hosts/<id>/remove` | (人)移除主機 |
|
|
|
|
|
|
| GET | `/relay/host/ws` | (主機)長連線,見下面 |
|
|
|
|
|
|
| GET | `/relay/host/next` | (主機)舊式長輪詢:有要求就回 job,25 秒沒有回 204 |
|
|
|
|
|
|
| POST | `/relay/host/reply/<job id>` | (主機)回答舊式 job |
|
|
|
|
|
|
| GET | `/relay/host/peers` | (主機)帳號裡的其他主機 |
|
|
|
|
|
|
| GET/POST | `/relay/host/members` | (主機)團隊成員和角色(admin、member) |
|
|
|
|
|
|
| POST | `/relay/host/notify` | (主機)推播通知到帳號的手機 |
|
|
|
|
|
|
| POST | `/relay/host/sites/<name>` | (主機)發布 Bot 做的網頁,公開在 `/s/<name>/` |
|
|
|
|
|
|
| PUT/GET | `/relay/backup` | 加密備份(伺服器打不開) |
|
|
|
|
|
|
|
|
|
|
|
|
### 配對碼
|
|
|
|
|
|
|
|
|
|
|
|
| 方法 | 路徑 | 說明 |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| POST | `/relay/pair` | (人或主機)`{for: 大腦的主機 id}` → `{code, expires_in: 600}` |
|
|
|
|
|
|
| POST | `/relay/pair/claim` | (不用登入)`{code, name}` → `{id, token, user, for, for_name}`。只能用一次;同一個位址錯 8 次停 5 分鐘 |
|
|
|
|
|
|
|
|
|
|
|
|
### 轉送
|
|
|
|
|
|
|
|
|
|
|
|
| 路徑 | 誰 | 轉成 |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| `/h/<host>/api/...` | 手機 | 那台 AnyBot 的 `/api/...`,角色是 owner/admin/member |
|
|
|
|
|
|
| `/relay/hosts/<host>/api/sync[/...]` | 同帳號的主機 | 大腦的 `/api/sync...`,角色 `mirror` |
|
|
|
|
|
|
| `/relay/hosts/<host>/api/device/run` | 同帳號的主機 | 手腳的 `/api/device/run`,角色 `device` |
|
|
|
|
|
|
|
|
|
|
|
|
轉送時伺服器附上 `user`、`role` 和 `from`(問的那台主機 id)。對方不在線時立刻回 503「目前離線」;收到了但 35 秒內沒回答,回 504。
|
|
|
|
|
|
|
Remove what nothing uses and keep one copy of what was written several times
Unused (found by taking away the dead-code allowances; nothing else used them, tests aside):
computer::specs, quiet_button, the never-made Poke::Spin, ten icons and their SVGs, the
theme's chrome/bubble_agent colours, ImportRow.line, voice's multipart/transcribe/speak
wrappers, and the old keychain writers vault::save/remove/index_add with their live test
(the vault store replaced them; reading old keychain entries for the import stays).
One copy each: percent-encoding (httpd::url_encode, was four), tool arguments (tools::args_of,
was three), the WebSocket handshake (httpd::accept_websocket, was three), the read pacing
(wire::Pace, was two: relay and app), docker with input and a time limit (dk_with_input, was
two). Docs: FEATURES §看畫面 (VNC), protocol (v* frames, /screen, tickets), architecture.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 15:21:47 +00:00
|
|
|
|
看 Bot 的電腦(VNC,一條串流,不是一問一答):
|
|
|
|
|
|
|
|
|
|
|
|
| 路徑 | 誰 | 說明 |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| `GET /screen`、`GET /novnc.js` | 任何人 | 看畫面的網頁和 noVNC 1.6.0(MPL-2.0) |
|
|
|
|
|
|
| `POST /relay/screen-ticket` `{host}` | 同帳號的主機(host token) | → `{ticket}`:10 分鐘內有效,讓這台的 App 開瀏覽器看那台的電腦 |
|
|
|
|
|
|
| WebSocket `/relay/vnc/<host>?t=` 或 `?ticket=` | 擁有者、管理員 | 二進位訊息是 VNC;文字訊息是要打進去的字。伺服器把它接到那台 AnyBot 的長連線(下面的 `v*`) |
|
|
|
|
|
|
|
make, README and docs: build and install from source
- Makefile: make / run / install / uninstall / deps / test / serve / setup /
hands / relay-run / server / dist / clean (macOS and Linux).
- README.md and docs/: install (all platforms, data locations, troubleshooting),
multi-device (brain, hands, screens, pairing, what the offline messages mean),
architecture (layers, data, security, sync, keys, hands, picture helper),
protocol (relay and AnyBot endpoints, WebSocket frames, sync ops), release
(packaging, Gitea Actions, Linux and Mac runners).
- install.sh --deps-only, bundle.sh KEEP_APP=1 (used by make deps / install).
- FEATURES.md: the multi-device part is done.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uirha3oEtWeHh58zA7ErHa
2026-11-04 14:16:45 +00:00
|
|
|
|
## AnyBot 提供的介面(`remote::handle`)
|
|
|
|
|
|
|
|
|
|
|
|
只有經過帳號伺服器(或同一個網路、用手機密碼登入)才到得了。
|
|
|
|
|
|
|
|
|
|
|
|
| 方法 | 路徑 | 角色 | 說明 |
|
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
| GET | `/api/state?since=` | 手機 | Bot 清單、誰在工作、等核准的事(有變化才回,最多等 20 秒) |
|
|
|
|
|
|
| GET | `/api/bots/<id>?since=` | 手機 | 一個 Bot 的訊息 |
|
|
|
|
|
|
| POST | `/api/bots/<id>/<動作>` | 手機 | `send`、`stop`、`answer`、`read`、`new`、`upload`… |
|
Remove what nothing uses and keep one copy of what was written several times
Unused (found by taking away the dead-code allowances; nothing else used them, tests aside):
computer::specs, quiet_button, the never-made Poke::Spin, ten icons and their SVGs, the
theme's chrome/bubble_agent colours, ImportRow.line, voice's multipart/transcribe/speak
wrappers, and the old keychain writers vault::save/remove/index_add with their live test
(the vault store replaced them; reading old keychain entries for the import stays).
One copy each: percent-encoding (httpd::url_encode, was four), tool arguments (tools::args_of,
was three), the WebSocket handshake (httpd::accept_websocket, was three), the read pacing
(wire::Pace, was two: relay and app), docker with input and a time limit (dk_with_input, was
two). Docs: FEATURES §看畫面 (VNC), protocol (v* frames, /screen, tickets), architecture.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 15:21:47 +00:00
|
|
|
|
| GET/POST | `/api/screen/mac` | 手機 | 看這台 Mac 的畫面、點擊打字(開了「從手機操作」才可以) |
|
|
|
|
|
|
| GET | `/screen`、`/novnc.js` | 任何人 | 看 Bot 的電腦的網頁(noVNC);本身沒有資料 |
|
|
|
|
|
|
| WebSocket | `/api/vnc?t=` | 手機(同一個網路) | VNC,直接到這台的 Bot 的電腦(見 vnc.rs) |
|
|
|
|
|
|
| GET | `/api/sync/screen` | mirror | Bot 的電腦的小縮圖(JPEG,寬 320) |
|
|
|
|
|
|
| POST | `/api/sync/screen` | mirror | `{kind: "hold", on}`(接管時 Bot 等你)、`{kind: "wake"}` |
|
make, README and docs: build and install from source
- Makefile: make / run / install / uninstall / deps / test / serve / setup /
hands / relay-run / server / dist / clean (macOS and Linux).
- README.md and docs/: install (all platforms, data locations, troubleshooting),
multi-device (brain, hands, screens, pairing, what the offline messages mean),
architecture (layers, data, security, sync, keys, hands, picture helper),
protocol (relay and AnyBot endpoints, WebSocket frames, sync ops), release
(packaging, Gitea Actions, Linux and Mac runners).
- install.sh --deps-only, bundle.sh KEEP_APP=1 (used by make deps / install).
- FEATURES.md: the multi-device part is done.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uirha3oEtWeHh58zA7ErHa
2026-11-04 14:16:45 +00:00
|
|
|
|
| POST | `/api/device/run` | device | `{tool, args, who}` → `{text, ok, image}`:在這台跑一個工具 |
|
|
|
|
|
|
| GET | `/api/sync?since=&client=` | mirror | 大腦的變化(見 architecture.md) |
|
|
|
|
|
|
| POST | `/api/sync/edit` | mirror | `{ops, client, seq}` → `{ok, applied}` |
|
|
|
|
|
|
| POST | `/api/sync/act` | mirror | `{bot, action, …}`:send、stop、answer、read、new、regenerate、reply、restore |
|
|
|
|
|
|
| POST | `/api/sync/upload/<bot>?name=` | mirror | 原始檔案內容 → `{path}` |
|
|
|
|
|
|
| GET | `/api/sync/file?path=` | mirror | 大腦上的附件(只限 `attachments/` 裡的檔案) |
|
|
|
|
|
|
| POST | `/api/sync/models` | mirror | `{provider}` → `{models}`:用大腦的金鑰取得模型清單 |
|
|
|
|
|
|
|
|
|
|
|
|
## 長連線的格式(`src/wire.rs`)
|
|
|
|
|
|
|
|
|
|
|
|
WebSocket 的二進位訊息,每則是:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
[4 位元組,表頭長度,big-endian] [表頭 JSON] [內容的原始位元組]
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
內容不做 base64。`z: true` 表示內容用 deflate 壓過;`z_ok: true` 表示問的人看得懂壓過的回答。
|
|
|
|
|
|
|
|
|
|
|
|
| t | 方向 | 表頭欄位 | 意思 |
|
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
| `hello` | AnyBot → 伺服器 | `brain`、`hands` | 這台在看哪個大腦、是不是手腳(手機和設定畫面用) |
|
|
|
|
|
|
| `job` | 伺服器 → AnyBot | `id, method, path, query, user, role, from, z, z_ok` | 給這台的要求 |
|
|
|
|
|
|
| `reply` | AnyBot → 伺服器 | `id, status, ctype, headers, z` | 回答 job |
|
|
|
|
|
|
| `call` | AnyBot → 伺服器 | `id, to, method, path, query, z` | 要問帳號裡的另一台(只能是 `/api/sync…` 或 `/api/device/run`) |
|
Remove what nothing uses and keep one copy of what was written several times
Unused (found by taking away the dead-code allowances; nothing else used them, tests aside):
computer::specs, quiet_button, the never-made Poke::Spin, ten icons and their SVGs, the
theme's chrome/bubble_agent colours, ImportRow.line, voice's multipart/transcribe/speak
wrappers, and the old keychain writers vault::save/remove/index_add with their live test
(the vault store replaced them; reading old keychain entries for the import stays).
One copy each: percent-encoding (httpd::url_encode, was four), tool arguments (tools::args_of,
was three), the WebSocket handshake (httpd::accept_websocket, was three), the read pacing
(wire::Pace, was two: relay and app), docker with input and a time limit (dk_with_input, was
two). Docs: FEATURES §看畫面 (VNC), protocol (v* frames, /screen, tickets), architecture.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 15:21:47 +00:00
|
|
|
|
| `ret` | 伺服器 → AnyBot | `id, status, ctype, z, headers` | call 的回答 |
|
|
|
|
|
|
| `vopen` | 伺服器 → AnyBot | `sid` | 有人要看這台的 Bot 的電腦:接上它的 VNC(AnyBot 先回 VNC 的開頭) |
|
|
|
|
|
|
| `vdata` | 雙向 | `sid` | VNC 的位元組(內容) |
|
|
|
|
|
|
| `vtext` | 伺服器 → AnyBot | `sid` | 看的人打的字(UTF-8),貼進 Bot 的電腦 |
|
|
|
|
|
|
| `vclose` | 雙向 | `sid`(AnyBot 送的有 `why`) | 結束這條 |
|
make, README and docs: build and install from source
- Makefile: make / run / install / uninstall / deps / test / serve / setup /
hands / relay-run / server / dist / clean (macOS and Linux).
- README.md and docs/: install (all platforms, data locations, troubleshooting),
multi-device (brain, hands, screens, pairing, what the offline messages mean),
architecture (layers, data, security, sync, keys, hands, picture helper),
protocol (relay and AnyBot endpoints, WebSocket frames, sync ops), release
(packaging, Gitea Actions, Linux and Mac runners).
- install.sh --deps-only, bundle.sh KEEP_APP=1 (used by make deps / install).
- FEATURES.md: the multi-device part is done.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uirha3oEtWeHh58zA7ErHa
2026-11-04 14:16:45 +00:00
|
|
|
|
|
Remove what nothing uses and keep one copy of what was written several times
Unused (found by taking away the dead-code allowances; nothing else used them, tests aside):
computer::specs, quiet_button, the never-made Poke::Spin, ten icons and their SVGs, the
theme's chrome/bubble_agent colours, ImportRow.line, voice's multipart/transcribe/speak
wrappers, and the old keychain writers vault::save/remove/index_add with their live test
(the vault store replaced them; reading old keychain entries for the import stays).
One copy each: percent-encoding (httpd::url_encode, was four), tool arguments (tools::args_of,
was three), the WebSocket handshake (httpd::accept_websocket, was three), the read pacing
(wire::Pace, was two: relay and app), docker with input and a time limit (dk_with_input, was
two). Docs: FEATURES §看畫面 (VNC), protocol (v* frames, /screen, tickets), architecture.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 15:21:47 +00:00
|
|
|
|
兩邊的迴圈有東西在跑時每 2 毫秒、安靜時每 40 毫秒看一次有沒有要讀的(`wire::Pace`),之後立刻送出排隊的訊息。心跳用 WebSocket 的 ping/pong。連線斷掉時,伺服器把還在等的 job 都回 503「斷線了」,AnyBot 把還在等的 call 都回「和帳號伺服器的連線斷了」。
|
make, README and docs: build and install from source
- Makefile: make / run / install / uninstall / deps / test / serve / setup /
hands / relay-run / server / dist / clean (macOS and Linux).
- README.md and docs/: install (all platforms, data locations, troubleshooting),
multi-device (brain, hands, screens, pairing, what the offline messages mean),
architecture (layers, data, security, sync, keys, hands, picture helper),
protocol (relay and AnyBot endpoints, WebSocket frames, sync ops), release
(packaging, Gitea Actions, Linux and Mac runners).
- install.sh --deps-only, bundle.sh KEEP_APP=1 (used by make deps / install).
- FEATURES.md: the multi-device part is done.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uirha3oEtWeHh58zA7ErHa
2026-11-04 14:16:45 +00:00
|
|
|
|
|
|
|
|
|
|
## 同步的改動(`/api/sync/edit` 的 ops)
|
|
|
|
|
|
|
|
|
|
|
|
| op | 欄位 | 說明 |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| `set` | `key, value` | 換掉一個設定(`next_*` 計數只會變大) |
|
|
|
|
|
|
| `patch` | `key, patch` | 清單或對照表逐項修改 |
|
|
|
|
|
|
| `merge` | `key, value` | 搬移時補上大腦沒有的(providers、skills、mcp_servers) |
|
|
|
|
|
|
| `bot_add` | `bot` | 新增 Bot(id 撞到會換) |
|
|
|
|
|
|
| `bot_del` | `id` | 刪除(主要 Bot 不能刪) |
|
|
|
|
|
|
| `bot_set` | `id, key, value` | 改 Bot 的一個欄位 |
|
|
|
|
|
|
| `bot_patch` | `id, key, patch` | 逐項修改 Bot 的清單欄位(例行任務保留大腦記錄的執行時間) |
|
|
|
|
|
|
| `bot_read` | `id` | 標為已讀 |
|
|
|
|
|
|
| `bot_order` | `ids` | Bot 的順序 |
|
|
|
|
|
|
|
|
|
|
|
|
`patch` 的格式:
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{"value": …} 換掉整個值
|
|
|
|
|
|
{"map": {"put": {"鍵": 值}, "del": ["鍵"]}} 對照表
|
|
|
|
|
|
{"list": {"put": [項目], "del": [鍵], "order": [鍵]}} 清單;鍵是項目的 id,沒有就用 name,純值就是值本身
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
清單裡的項目沒有 id 或名字、或鍵重複時,送整個值。
|