Files

5.3 KiB
Raw Permalink Blame History

DSHWatch 通信协议细化(v0.1)

本文件是 docs/DESIGN.md §4 的细化,定义三段链路的字段级协议,便于后续按此写代码。仍属"对齐粒度"文档。


0. 概述

三跳:

  1. 手表(DSHWatch) <-> 手机(DSHWatchPhone):BLE / @system.interconnect / Wearable MessageApi。
  2. 手机 <-> 服务器(DSHWatch_Server):WebSocket。
  3. 服务器 <-> DSH 插件(dsh-watch):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 的摘要;其余在手机端可看原始。