# 桌面精灵交互协议 0.1 草案 日期:2026-11-12。本文定义拟实现的行为,当前 App 不因此自动具备这些接口。MUST/必须表示符合本草案的要求,SHOULD/应表示允许说明原因后偏离的建议,MAY/可表示可选能力。所有示例标识符均为拟议协议值,不证明现有角色已经支持对应动作。 ## 1. 范围与分层 协议定义桌面精灵的能力发现、动作、提示、进度和用户交互。调用方可为普通 App、脚本或 Agent。精灵运行时负责呈现与回传,调用方负责业务决策和继续执行。 核心数据模型和语义必须独立于传输。首个参考实现计划使用 JSON-RPC 2.0,经本机 Unix Domain Socket 传输;CLI 是该服务的客户端,MCP 为可选适配。宿主内部可直接调用同一个调度器,不必经过 Socket,但必须通过同样的参数校验、权限、队列、生命周期与结果模型。内部来源身份由宿主赋予,外部不得伪造。 外部请求只允许使用已声明的数据能力,不包含可执行代码、Shell 命令、宿主闭包、任意回调 URL、文件读取或系统权限绕过。核心协议不包含截图、剪贴板读取或任意文件操作。 ## 2. 发现与描述 服务必须提供以下逻辑方法;最终机器可读描述应与实现由同一注册表生成,不能手工维护两套动作清单。 | 方法 | 用途 | | --- | --- | | `runtime.describe` | 实现名称/版本、协议版本、运行实例 ID、限制、授权状态、结果保留期 | | `characters.list` | 可用角色、当前角色、各角色支持的能力 ID;数量由数组推导 | | `capabilities.list` | 当前授权可用的能力描述、catalogRevision、分页信息(如有) | | `capabilities.describe` | 查询单个能力的完整契约 | | `styles.list` | 实际可用样式及适用能力,不承诺所有能力支持所有样式 | | `requests.create` | 校验并创建调用 | | `requests.get` | 查询一个请求及其当前结果 | | `requests.wait` | 有界等待状态变化,等待超时不取消请求 | | `requests.cancel` | 取消本接入方的请求 | | `requests.update` | 仅按能力声明更新仍未终结的请求 | 发现可以要求配对后的 `discover` 权限。每个能力必须声明:稳定 ID、版本、说明、适用角色、类别、输入 schema、业务结果 schema、所需权限、可更新字段、完成条件、取消行为、交互类型、排队/打断策略及资源限制。空参数、无业务输出也必须明确表达,不能靠省略猜测。 类别为 `animation`、`notice`、`progress`、`interaction`。交互类型为 `none`、`choice`、`text`;可选扩展必须使用命名空间。动画无业务输出仍具有“完成/取消/失败”的请求状态。样式影响外观,tone 表达 information/success/warning/error 的语义,两者不得互相覆盖。 示意描述: ```json { "id": "interaction.choose", "version": "0.1.0", "kind": "interaction", "interaction": "choice", "completion": "user_response", "requiredScopes": ["interact"], "cancelable": true, "inputSchema": { "type": "object", "properties": { "title": {"type": "string", "minLength": 1, "maxLength": 160}, "options": { "type": "array", "minItems": 2, "maxItems": 5, "items": { "type": "object", "properties": { "id": {"type": "string", "minLength": 1, "maxLength": 64}, "label": {"type": "string", "minLength": 1, "maxLength": 24} }, "required": ["id", "label"], "additionalProperties": false } } }, "required": ["title", "options"], "additionalProperties": false }, "outputSchema": { "type": "object", "properties": {"selectedId": {"type": "string"}}, "required": ["selectedId"], "additionalProperties": false } } ``` 此为精简示例;正式描述还须补全上列所有字段。选项 ID 在单次请求内必须唯一,返回 ID 必须属于该请求选项。返回稳定 ID,不用可翻译的显示文案作为业务标识。JSON Schema 负责结构校验,选项唯一、引用关系和状态转换等还需语义校验。 角色可将通用语义能力映射为自己的表现,例如庆祝;角色独有能力通过 `vendor.<反向域名>.<名称>` 扩展。未知能力/样式必须明确拒绝;只有调用方显式允许时才能采用已声明的替代表现,并在结果中记录 resolvedCapability、resolvedStyle 和降级原因。不能把视觉差异伪装成相同行为保障。 ## 3. 调用、结果与状态 创建参数包含 capability、params、character(省略使用用户当前选择)、style(可选)、timeoutMs、idempotencyKey(可选)。客户端可附带自己的 taskId,不能以此获取其他客户端的请求。权限身份必须来自认证,不能由参数中的 source/clientId 决定。 服务在权限、参数、角色支持和容量检查通过后创建 requestId。返回 accepted/queued 不等于已显示、动画完成或用户回答;错误请求不产生成功记录。创建响应和查询响应使用相同请求快照模型:requestId、runtimeInstanceId、capability、状态、revision、创建/截止时间、实际解析结果、终结原因以及可选业务 result。 状态转换: ```text queued → running → completed → awaiting_user → completed queued/running/awaiting_user → cancelled | expired | failed ``` 服务可在创建时直接返回 running。终态不可反转。关闭交互视图必须得到明确取消结果,不得选择默认答案;只有经过用户实际选择才能完成 choice 请求。展示开始时间必须在实际出现时记录。普通提示 completed 表示已按契约完成展示,不等于用户阅读;动画 completed 表示运行时的执行契约结束,不证明用户看到了每帧。 用户回复以 result 返回;取消/超时没有虚构业务答案。交互超时从接受时起算,包含排队时间;timeoutMs 不得被无限更新延长。展示时长从实际展示计时,可根据能力说明在悬停/焦点时暂停,但绝对请求截止时间继续有效。 `requests.wait` 接受 afterRevision 和有界 waitMs;返回最新快照或 unchanged,不得因长等待读取而创建新交互。CLI 可以循环等待,但服务不得承诺自动恢复已结束的 Agent。多个回复/取消竞争时仅一次原子状态转换获胜,后续查询返回同一个终态。 更新必须携带 expectedRevision;冲突返回 REVISION_CONFLICT。进度更新保留同一 requestId,不反复新建气泡。交互已展示后首版不允许更换问题和选项,以免用户点击对应了另一个含义。 ## 4. 重试、隔离、调度和保留 幂等键以认证客户端为作用域:保留期内同键同规范化参数必须返回原 requestId;同键不同参数返回 IDEMPOTENCY_CONFLICT。幂等记录至少与请求结果保留一样久。网络/进程中断后的未知结果必须先查询,不能无条件重复弹窗。 每个客户端只能查看、更新、等待、取消自己的请求;不能枚举其他客户端的交互内容。来源标签从配对记录显示,外部请求不能自称宿主内部或系统提示。 调度器必须有限容量,公布每客户端及总量限制。满额时拒绝并返回 QUEUE_FULL 或 RATE_LIMITED。已接受的请求不能静默丢弃;被淘汰的普通提示必须进入 cancelled 并记录 queue_evicted。交互请求不得被短时提示合并或淘汰;到期或明确取消才能结束。优先级不能绕过系统授权,也不能让任一来源永久占用显示位。 合并只能发生在同一身份、同一能力和显式合并键内;请求 ID 到规范结果的映射必须保持可查询。首版可不提供合并能力。用户隐藏精灵或暂停外部交互后,不得自行唤出;新请求拒绝 RUNTIME_UNAVAILABLE,已接受请求按声明策略取消并给出原因。 首个本地 profile:终态元数据、业务结果及幂等记录保留至少24小时后删除;接入页面须在配对前明确这一内容保留行为,正文不得另写普通日志。数量达到公布上限时拒绝新请求,不提前静默驱逐有效结果。状态持久化失败不得确认已接受或已提交用户回答。App 重启时对未终结请求记为 failed/runtime_restarted,不自动重放;Key 撤销则立即取消其未终结请求并清除其敏感业务结果。卸载、用户主动清除或存储损坏可能使记录不可恢复,查询必须明确说明,不能返回假成功。 ## 5. 本地身份和授权 接入默认关闭。用户主动配对后,运行时本机生成不可预测的高熵 Key,每个接入方单独创建并可撤销。推荐至少256位随机值;服务端只保存验证材料,客户端凭据保存在钥匙串或权限受限的凭据文件。授权范围包括 discover、animate、notify、interact;请求查询/更新/取消始终受所有权限制。配对流程、接口方法及撤销处理须在实现前形成单独认证 profile。 Key 不放进 Skill、源码、普通日志、命令行参数或调用示例。CLI 通过 credential profile 引用本机凭据,从权限受限的本地文件/钥匙串读取。初次配对必须由用户在 App 明确确认接入方及权限,不能由自报名称自动批准。 Unix Domain Socket 放在当前用户私有目录,目录0700、Socket0600;认证消息限长、设超时,不记录凭据。仅凭同用户 Socket 权限不能区分所有本机进程,Key 也不是对已被控制的当前用户账户的安全隔离保障。 首版不监听 TCP、不接受任意跨站调用、不提供远程服务。后续 HTTP profile 若增加,须单独定义绑定范围、认证和 Origin 检查。核心 Key 不授予文件读取、系统权限、Shell 或业务执行能力。 本协议不要求外部云服务或模型;第三方 Agent 可能把请求和回复发送到其云服务,“本地接口”不等于接入方也离线。用户交互内容只回给其所属客户端,不广播给所有订阅者。 ## 6. CLI 参考形态(计划,当前不可执行) ```sh companion runtime describe --json companion characters list --json companion capabilities list --json companion capabilities describe interaction.choose --json companion styles list --json companion requests create --file request.json --credential-profile my-agent --json companion requests get REQUEST_ID --credential-profile my-agent --json companion requests wait REQUEST_ID --credential-profile my-agent --json companion requests cancel REQUEST_ID --credential-profile my-agent --json ``` create 的 JSON 文件只含协议参数,无 Key。实际命令名尚未定案。统一 stdout 输出单个 JSON 值,诊断写 stderr;机器模式不输出动画、颜色或进度文字。UTF-8,禁止 NaN/Infinity;内容按普通文本展示,不自动解释 HTML、脚本或链接动作。所有读取默认使用已配对 profile,未指定且无法唯一选择时明确失败,不自动选权限最大的凭据。 CLI 退出码计划:0=所请求操作成功;2=参数错误;3=认证/权限错误;4=不可连接;5=请求失败;6=请求取消/过期;7=本次等待超时但请求仍在继续。create 成功仅证明接受;wait 输出必须带状态。所有非零结果提供稳定错误码、可读说明和 retryable,不能仅靠本地化文本判断。 至少定义 INVALID_PARAMS、UNSUPPORTED_CAPABILITY、UNSUPPORTED_STYLE、UNAUTHENTICATED、FORBIDDEN、NOT_FOUND、RESULT_EXPIRED、QUEUE_FULL、RATE_LIMITED、RUNTIME_UNAVAILABLE、REVISION_CONFLICT、IDEMPOTENCY_CONFLICT、INTERNAL_ERROR。不存在和无权查看的请求统一 NOT_FOUND;超过可辨识保留期的自有请求才可报告 RESULT_EXPIRED。 ## 7. 版本与一致性 区分协议版本、能力版本、实现版本和 catalogRevision。首版客户端明确协商支持的协议版本,无共同版本拒绝,不猜测兼容。发现后角色/能力有变化时,创建操作重新校验;不能使用过时发现结果强行动作。 稳定版主版本内只做向后兼容增加;破坏性变更发布新主版本。0.x 草案之间允许修订,但仍须显式版本匹配,不能静默更改参数含义。供应商扩展不得重定义核心方法、状态或权限。 发布一致性材料必须覆盖:描述与真实能力一致、非法参数、角色差异、可访问性/减少动态、隐藏状态、重复创建、并发更新、所有权隔离、容量、撤销、点击竞争、超时、断线和重启。有限检查只证明指定版本/条件下符合,不能保证所有环境无故障。 参考实现的宿主内部入口与外部 CLI 使用同一能力注册表和调度器。允许宿主在渲染边界保留本地闭包,但开放结果必须使用稳定选项 ID;外部调用不能访问宿主私有对象。将内部触发接入统一协议时,保持声音开关、精灵显示、用户数据和各业务原有授权边界。 ## 8. 基础资料 本文复用现有描述与传输思路;下列资料不意味着本草案已通过任何组织认证。 - [JSON-RPC 2.0](https://www.jsonrpc.org/specification):基础请求/响应;本草案另定义精灵请求状态,RPC 响应不代表异步操作完成。 - [OpenRPC](https://spec.open-rpc.org/):描述方法、参数、结果及发现;可用于导出协议方法目录,动态角色能力仍由 capabilities 方法给出。 - [JSON Schema](https://json-schema.org/):参数与输出结构;正式 schema 尚待交付。