169 lines
5.3 KiB
Markdown
169 lines
5.3 KiB
Markdown
# DSHWatch 通信协议细化(v0.1)
|
||
|
||
> 本文件是 docs/DESIGN.md §4 的细化,定义三段链路的字段级协议,便于后续按此写代码。仍属"对齐粒度"文档。
|
||
|
||
---
|
||
|
||
## 0. 概述
|
||
|
||
三跳:
|
||
|
||
1. 手表(DSHWatch) <-> 手机(DSHWatchPhone):BLE / @system.interconnect / Wearable MessageApi。
|
||
2. 手机 <-> 服务器(DSHWatch_Server):WebSocket。
|
||
3. 服务器 <-> DSH 插件(dsh-watch-bridge):WebSocket。
|
||
|
||
手机在 1 和 2 之间做双向网关翻译。手表看到的永远是"整理过的短文本",不直接透传原始大 JSON。
|
||
|
||
---
|
||
|
||
## 1. 手表 <-> 手机(BLE / interconnect)
|
||
|
||
### 1.1 物理通道
|
||
|
||
- 手表:@system.interconnect 的 connect.send({ data: obj })。
|
||
- 手机:小米穿戴 SDK MessageApi.sendMessage(nodeId, byte[])。
|
||
- 大数据(文本 > 约 1KB):按 base64 分片。官方 demo 用 header/data/end 三段;本项目沿用:
|
||
|
||
开始帧:{ "type":"header", "totalChunks": N, "id":"..." }
|
||
数据帧:{ "type":"data", "id":"...", "index": i, "chunk":"base64..." }
|
||
结束帧:{ "type":"end", "id":"..." }
|
||
|
||
### 1.2 消息信封
|
||
|
||
{
|
||
"to": "phone" | "watch",
|
||
"type": "hello" | "status" | "event" | "command" | "text" | "cancel" | "settings" | "ack" | "heartbeat",
|
||
"seq": 123,
|
||
"ts": 1760000000000,
|
||
"payload": { ... }
|
||
}
|
||
|
||
### 1.3 type 与 payload
|
||
|
||
- hello:{ "role":"watch|phone", "version":"0.1" }
|
||
- status:{ "online":bool, "harnessOnline":bool, "running":bool, "sessionId":"...", "sessionTitle":"...", "model":"...", "server":"..." }
|
||
- event:{ "kind":"session/event|session/projection", "sessionId":"...", "summary":"...", "seq":123 }
|
||
- command:{ "kind":"prompt|quick|select_session", "sessionId":"...", "content":"...", "quick":"..." }
|
||
- text:{ "sessionId":"...", "text":"..." }
|
||
- cancel:{ "sessionId":"..." }
|
||
- settings:{ "serverUrl":"...", "userId":"...", "token":"..." }
|
||
- ack:{ "ok":bool, "error":{ "code":"...", "message":"..." } }
|
||
- heartbeat:{}
|
||
|
||
### 1.4 顺序与可靠性
|
||
|
||
- seq 手表端单调递增。
|
||
- 手机端收到后原样回 ack(ok)。
|
||
- 分片用 id 关联;缺失分片则丢弃该条并 ack 失败。
|
||
|
||
---
|
||
|
||
## 2. 手机 <-> 服务器(WebSocket)
|
||
|
||
连接地址:ws(s)://host:port/ws(或 /)。
|
||
|
||
### 2.1 握手
|
||
|
||
手机发送:
|
||
|
||
{ "type":"hello", "role":"client", "userId":"...", "token":"..." }
|
||
|
||
服务器回:
|
||
|
||
{ "type":"hello", "role":"client", "online":true, "harness":true, "status":{...} }
|
||
|
||
### 2.2 请求/响应
|
||
|
||
手机 -> 服务器:
|
||
|
||
{ "type":"request", "requestId":"uuid", "method":"session.prompt", "timeoutMs":30000, "params":{...} }
|
||
|
||
服务器 -> 手机(转发给 Harness 后回):
|
||
|
||
{ "type":"response", "requestId":"uuid", "ok":true, "result":{...} }
|
||
{ "type":"response", "requestId":"uuid", "ok":false, "error":{ "code":"...", "message":"..." } }
|
||
|
||
### 2.3 推送(服务器 -> 手机)
|
||
|
||
{ "type":"harness", "online":true }
|
||
{ "type":"status", "status":{...} }
|
||
{ "type":"event", "event":{ "type":"session/event", "sessionId":"...", "event":{...} } }
|
||
{ "type":"notice", "code":"...", "message":"..." }
|
||
|
||
### 2.4 method 白名单(插件透传)
|
||
|
||
- harness.status / harness.prompt
|
||
- session.list/create/history/prompt/cancel/rename/fork/models/selectModel/attachment
|
||
- goal.create/edit/pause/resume/complete/clear
|
||
- subagent.list/history/prompt/interrupt
|
||
- workspace.list/create/rename/delete/insertBefore/insertSessionBefore/archiveSession
|
||
- host.describe/pickDirectory/listDirectory/createDirectory/openPath
|
||
- skill.list
|
||
- agentPreset.list/select/read/copy/openDocument/remove
|
||
- llm.providers/models/discoverModels
|
||
- settings.describe/openDocument/update/replace/mutate
|
||
- credentials.describe/set/unset
|
||
|
||
---
|
||
|
||
## 3. 服务器 <-> DSH 插件(WebSocket)
|
||
|
||
### 3.1 握手
|
||
|
||
插件 -> 服务器:
|
||
|
||
{ "type":"hello", "role":"dsh", "userId":"...", "token":"..." }
|
||
|
||
服务器回:
|
||
|
||
{ "type":"hello", "role":"dsh", "online":true, "status":{ "userId":"..." } }
|
||
|
||
### 3.2 转发
|
||
|
||
服务器 -> 插件(来自手机):
|
||
|
||
{ "type":"request", "requestId":"uuid", "method":"...", "params":{...} }
|
||
|
||
插件 -> 服务器:
|
||
|
||
{ "type":"response", "requestId":"uuid", "ok":true, "result":{...} }
|
||
{ "type":"response", "requestId":"uuid", "ok":false, "error":{...} }
|
||
|
||
### 3.3 推送
|
||
|
||
插件 -> 服务器:
|
||
|
||
{ "type":"status", "status":{...} }
|
||
{ "type":"event", "event":{...} }
|
||
{ "type":"ping" } # 心跳
|
||
|
||
### 3.4 状态快照形态
|
||
|
||
{
|
||
"online": true,
|
||
"ts": 1760000000000,
|
||
"version": "0.0.1",
|
||
"cwd": "D:/...",
|
||
"provider": "deepseek",
|
||
"model": "deepseek-chat",
|
||
"attachedSessions": 2,
|
||
"activeSessionId": "session-xxx",
|
||
"running": false,
|
||
"sessions": [ { "sessionId":"...", "updatedAt":123, "running":false, "blank":false, "agentPreset":"..." } ]
|
||
}
|
||
|
||
---
|
||
|
||
## 4. 错误码约定
|
||
|
||
auth-error / missing-userId / bad-request / harness-offline / harness-timeout / invoke-error / duplicate-requestId / invalid-JSON / unknown-path
|
||
|
||
---
|
||
|
||
## 5. 备注
|
||
|
||
- 服务器不落盘,纯内存转发。
|
||
- token 建议走 wss,且在服务端用环境变量或本地 config.json,不入 git。
|
||
- 客户端重连:指数退避(1s,2s,4s,8s,上限 30s)。
|
||
- 事件流可能很大,手表端只渲染 kind=session/event 且是 text 的摘要;其余在手机端可看原始。
|