构建

Wire 协议

Wire 主版本 1 · 9 个协商 Profile

Wire 主版本 1 是一份小型的失败即关闭契约:九个协商 Profile、20 种紧凑 JSON 消息、一个 LF 分隔符、受限字段,并且不携带内部 Agent 或账号标识。

1. Wire 规则

每个逻辑消息都是一个紧凑 JSON 的 UTF-8 对象,末尾恰好一个 LF 字节。完整帧连同 LF 最多 4096 字节。传输层可以拆分帧,但接收方绝不执行部分消息:只有完整对象通过校验后才改变状态。原始解码 API 从行解码器取得已移除分隔符的 JSON。接收方不接受来自不同逻辑消息的交错分片。接收方会在无效 UTF-8、超长输入或断连后清空当前拼帧状态。

九个协商 Profile 都使用同一个信封;可选 Profile 开始传输前必须先通过 Device Info 门控。

名称类型说明
v必填
integer规范的无符号十进制整数 1;小数与指数写法无效。
id
ASCII stringpresent、answer、resolved 必填,error 的 id 可选,status 不带 id。出现时必须是 1–64 个字符,并匹配 [A-Za-z0-9._:-]+。
enums必填
lowercase只能使用区分大小写的小写值。
unknown fields
bounded JSON有效且受限的未知可选字段会被忽略;未知值最多八层嵌套,字段名在帧上限内没有独立长度限制。
invalid input必填
失败即关闭符合规范的解码器会拒绝坏 UTF-8 和任何嵌套层级的重复已知 key,包括等价 JSON 转义;未知类型、缺字段和越界值也会被拒绝。

Device Info 契约

Device Info 是从其 GATT characteristic 读取的紧凑 UTF-8 JSON 值,不使用换行拼帧。下面八个基础字段全部必填:wire 必须包含 1,profiles 必须包含 approval/1。model 与 fw都必须是非空可打印字符串,最多 64 字节 UTF-8。主机忽略未知 capability 字段。状态能力要求 profiles 同时包含status/1,并且 statusSlots >= 1。缺少statusSlots 或值为零,都表示不能发送状态。

名称类型说明
protocol / spec必填
stringnexting-device 与非空规范版本;官方 App 按协商结果应用边界。
wire / profiles必填
arrayswire 包含 1;profiles 包含 approval/1。
model / fw必填
string每项都非空可打印,最多 64 字节 UTF-8。
max_message_bytes必填
integer至少 512;官方实现上限为 4096。
max_summary_bytes必填
integer官方 App 接受由 Device Info 协商出的有界值。
statusSlots
integer?可选 0–8 能力;只有正数与 status/1 同时出现才启用。

2. present

主机下发一个合格审批,并启动相对单调寿命。新的 present 会替换当前请求;主机必须先用 replaced 完成旧请求,再下发新请求。

主机 → 设备present主机下发一个审批
名称类型说明
v必填
integer规范 Wire 主版本 1。
t必填
string精确为 present。
id必填
string当前请求 ID。
sum必填
string0–240 字节 UTF-8。
opt必填
tuple必须按顺序精确为 ["allow","deny"]。
ttl必填
integer从接收时起相对 1–300000 ms。
规范帧json
{"v":1,"t":"present","id":"r1","sum":"Allow git push?","opt":["allow","deny"],"ttl":30000}

设备进入 Pending。带第三个选项、持久授权、多选行为或选项语义不明确的 prompt 必须留在手机上。

3. answer

设备只能回答当前可见请求,随后进入 Waiting Resolution。如果 1000 ms 后仍未完成,可重发完全相同的 answer,直到收到 resolution 或本地 TTL 过期;绝不能改变选择。

设备 → 主机answer设备报告一次实体选择
名称类型说明
v必填
integer规范 Wire 主版本 1。
t必填
string精确为 answer。
id必填
string必须匹配可见请求。
ch必填
enumallow 或 deny。
规范帧json
{"v":1,"t":"answer","id":"r1","ch":"allow"}

主机按请求 ID 去重,锁定第一个硬件选择,并且同一时间最多运行一次权威 action sink 尝试。

4. resolved

无论设备处于 Pending 还是 Waiting Resolution,匹配的 resolved 都会立即清除可见审批 UI 与缓存的重试状态。权威 sink 接受时原因是 answered,寿命结束时是 expired,主机撤回时是 cancelled,更新请求取代旧请求时是 replaced。

主机 → 设备resolved主机完成一个请求
名称类型说明
v必填
integer规范 Wire 主版本 1。
t必填
string精确为 resolved。
id必填
string要完成的请求。
r必填
enumanswered、expired、cancelled 或 replaced。
规范帧json
{"v":1,"t":"resolved","id":"r1","r":"replaced"}

迟到或未知的 resolution 不能清除另一个当前请求。

5. error

Error 只用于诊断,并且遵循失败即关闭。error 的 id 可选;code 必填,可取 bad_message、message_too_large、unsupported_version、 unsupported_profile、unknown_request、not_authorized 或 busy。如果回复会放大流量或泄露授权状态,实现可以静默丢弃畸形或攻击者控制的输入。

主机 ↔ 设备error任一端报告受限的协议错误
名称类型说明
v必填
integer规范 Wire 主版本 1。
t必填
string精确为 error。
id
string?可选的相关请求 ID。
code必填
enum必填的协议错误码。
规范帧json
{"v":1,"t":"error","id":"r1","code":"unknown_request"}

收到 error 不代表被拒绝的消息曾执行过任何部分。

6. status

Status 是易失的全量替换。每个有效帧原子替换全部已跟踪槽;agents: [] 清空所有槽。Agent state 可取 idle、thinking、working、complete、needs_input 或 error。畸形帧保留之前的状态,断连或重启会清除已渲染状态。

主机 → 设备status主机替换全部 Agent 指示状态
名称类型说明
v必填
integer规范 Wire 主版本 1。
t必填
string精确为 status。
agents必填
array0–8 项;空数组清空全部槽。
slot必填
integer帧内唯一的 0–7。
state必填
enum必填的状态枚举。
label
string?可选 1–64 字节 UTF-8,不含控制字符。
规范帧json
{"v":1,"t":"status","agents":[{"slot":0,"state":"thinking","label":"fix login bug"}]}

设备渲染自己支持的最低编号实体槽,并忽略更高槽。status 永远不会创建、回答、过期或完成审批。

交互 Profile

以下已冻结 Profile 共用相同拼帧与失败即关闭规则。Device Info 必须先声明精确 Profile,Host 才会收发对应消息。

名称类型说明
navigation/1
双向nav_present、nav_move、nav_select、nav_resolved
keys/1
双向keymap 与带重放保护的 key_event
rotary/1
双向rotary_map、rotary_event、rotary_press
voice/1
双向voice_event 与 voice_state;只传控制,不传音频或转写
text/1
下行发往已声明屏幕通道的有界纯文本
usage/1
下行usage 与 usage_clear,用于信息展示
config/1
双向原子版本化 config 与 config_result
实体输入示例json
{"v":1,"t":"key_event","slot":3,"event":"press","seq":18}
{"v":1,"t":"rotary_event","slot":0,"delta":1,"seq":19}
{"v":1,"t":"voice_event","event":"start","seq":20}

7. 测试向量

在导出的源码根目录运行可执行 JavaScript 参考测试。它会读取九个 Profile 的共享向量,并覆盖编解码、拼帧、relay 竞争、序号和拒绝案例。

源码根目录sh
node --test reference/js/test/*.test.mjs
请把 protocol/vectors/ 下的全部文件当作规范行为,而不是示意样例。