# Host 组件流:已实现协议与恢复边界 `streaming.enabled: true` 会在真实 Harness Tool registry 中注册四个工具。实现位于 `host/ui-stream.ts`,调用的共享验证与补丁函数位于 `shared/stream.ts`。它是组件级增量输出:每个已完成的工具调用发布一个带完整快照的 checkpoint,不是逐 token JSON compiler。 ## 1. 工具及游标 | 工具 | 参数 | 结果 | | --- | --- | --- | | intelligent_ui_open | `{document}` | 新 generation,`seq:1`、`revision:0`、`type:"snapshot"` | | intelligent_ui_patch | `{sourceCallId,generation,baseRevision,mutation}` | 一次 add/update/remove,seq 和 revision 各加 1 | | intelligent_ui_complete | `{sourceCallId,generation,baseRevision}` | 完成快照,seq 加 1,revision 保持 | | intelligent_ui_cancel | `{sourceCallId,generation,baseRevision}` | 取消快照,保留最后合法文档,seq 加 1 | `sourceCallId` 来自最初 open 的实际 native Tool call ID,PTC 中则是实际 subcall ID。后续 patch/complete 工具自己的 call ID 不替换这个来源。Host 为同 Session、同 UI 文档 ID 的后续 open 分配递增 generation。模型必须读取 open 工具的简短文本回执并使用其中的真实游标,不能臆造来源 ID。 工具输出的 canonical value 和 `presentationMeta` 都是共享 Schema 校验后的 checkpoint。回执文本包含 `sourceCallId`、`uiId`、`generation`、`revision`、`seq`、`type`,因为仅存在于 presentation metadata 中的内容不会自动变成模型可见文本。 完整 checkpoint 的关键字段为: ```json { "protocol": "dsh.intelligent-ui.stream", "version": "1.0", "sourceCallId": "实际open调用ID", "uiId": "document_id", "generation": 1, "seq": 2, "baseRevision": 0, "revision": 1, "type": "update", "snapshot": { "说明": "此处为完整、通过验证的UI文档,并非可直接运行的示例" } } ``` 上面仅展示字段关系。可以实际提交的起始文档和 mutation 数组见 `examples/stream-initial.json`、`examples/stream-mutations.json`;运行时游标必须取自工具回执。 ## 2. 原子补丁与稳定性 每次 patch 都先构建候选文档,再进行完整 Schema、ID、绑定、表达式、资源和一致性校验。候选失败时,已有文档与持久化游标不变。所有 Host 更新通过单个串行队列提交;`baseRevision` 必须与当前持久化修订完全相等。 同 generation 的文档 ID、版本、模式、state 定义、derived 定义、action 定义、Select 值域和 root 身份保持不变;已经存在的组件 ID 不能更换组件类型。props 更新是完整替换该节点的 props,不是任意 JSON 路径赋值。允许的 mutation 只有 add、update、remove;没有脚本、DOM、网络或命令补丁。 每个 generation 记录所有已接受工具 call ID 的摘要,最多 256 个。紧邻的同调用、同内容重传返回既有结果;相同调用 ID 配不同内容,或重用更早已提交的 call ID,都会拒绝。这个去重由插件实现,不能假设官方 ToolRuntime 会按 call ID 去重。 客户端以 `(sourceCallId, uiId, generation)` 作为 UI owner,在修订增加时保留同一状态管理实例。共享 helper 保持未修改分支的引用,组件 ID 作为 React key。用户输入保留;新生成的初始值不会覆盖当前 state。stream 未 complete 时,外部 invoke 动作被禁用;Host reserve 也独立拒绝未完成 stream,避免半成品界面获得外部操作权限。 ## 3. 两层持久化 第一层是普通 Session tool result:每个成功 checkpoint 都随 `presentationMeta` 进入官方 native `tool/result` 或 `tool/ptc-dispatch`,历史回放直接重建 UI。没有新增非官方 Session 事件,也没有手工写假的 turn 或工具结果。 第二层是 Host 的游标账本:官方 StorageDomain `intelligent_ui_streams`,版本 1,`layout: "single"`,记录当前完整 checkpoint、generation epoch、已接受帧数、累计字节和 call/seq 指纹。这使 Host 能在继续输出前验证客户端无法指定的真实状态。 一个私有记录比公共 frame 多出指纹和 Host 字段,校验按层拆开:先验证外层和 state 层是严格 plain-own-data descriptors;分别验证最多 64 KiB 的 Host 元数据以及按原公共预算验证的 checkpoint;重组后再验证 Schema 和总记录预算。没有通过扩大模型文档预算来容纳 Host 记录。 已完成界面不依赖这份 Host 运行内存:Session 中每个 frame 自带完整 snapshot。Host 账本负责下一次更新的权威游标和去重,并不替代 Session 的会话归属。 ## 4. 中断、缺帧和重启 客户端在乱序、重复或缺帧时按 generation、seq、baseRevision、revision 检查一致性。合法的后续完整 checkpoint 可以恢复缺帧;同序号不同内容会拒绝。单 generation 的 actions、state 等冻结规则在恢复时仍被检查。已存在组件不会为了每个 frame 整体重新挂载。 显式 `intelligent_ui_cancel` 持久化最后合法部分快照。共享协议还识别 `error` 并可显示错误状态;当前 Host 没有单独注册生成 error 帧的工具,也不会伪造一次工具调用来补写自动 cancel 事件。如果连接或 Agent 流在终结帧之前中断,当前界面保留最近有效快照与未完成状态,外部 invoke 仍禁用。单凭 turn/end 自动区分正常完成、截断和取消的提示尚未实现,不能把这种部分输出当成完成结果。 Host 进程或 stream 服务重启后,旧 epoch 的 patch/complete 被拒绝。用户可要求 Agent 以最后快照重新 open 新 generation。已完成和部分快照仍可按会话历史查看;恢复不会自动调用工具,也不会重放旧补丁。 ## 5. 明确的资源预算 - 文档最大 256 KiB,部署可进一步调低 `maxDocumentBytes`。 - 公共 checkpoint 最大为文档上限加 4 KiB envelope。 - 单 mutation 最大 64 KiB。 - 每 generation 最多 256 帧,累计最多 16 MiB;Host 配置可降低帧数。 - 保留至少一个终结 checkpoint 的预算,不能因为普通 patch 耗尽全部容量而无法 complete/cancel。 - 默认保存最多 256 个 generation;达到配置容量后拒绝新的 open,不静默覆盖旧 generation。 该 Host 账本采用单所有者、全量 JSON domain,适合当前有界实现,未证明多 Host 并发扩容能力。长期运行的归档、压缩和集群数据库适配属于后续运维设计;不能删除尚需用于去重的记录后宣称具备永久防重放保证。 ## 6. 验证范围 `tests/host-stream.test.ts` 使用真实 Cordis、AgentLoop、ToolRuntime、StorageDomain/JSON backend,覆盖 open/patch/complete、模型可见游标、失败原子性、不同 Agent Session、普通工具 guard、相邻和非相邻调用去重、取消预算、低部署上限、重启 epoch、卸载,以及真正 Agent turn 内的 native Session 结果。 独立 `tests/p3-boundaries.test.ts` 再验证官方 ToolRuntime 不做 call-ID 去重、旧 call ID 的拒绝,以及精确 262,144 字节文档的 open、磁盘存储、卸载和重载。客户端和真实网页的状态保留、失序恢复、PTC/native 回放及模型表现见整体 [VALIDATION.md](VALIDATION.md)。