# `03.sdk_and_coreapp` 第 1 次设计评审记录 > 评审日期:2026-08-05 > 评审编号:01 > 评审基线:[APP架构设计.md](../../设计/APP架构设计.md) > 评审对象:[03.sdk_and_coreapp.md](03.sdk_and_coreapp.md) > 评审方式:独立子 agent 只读评审;本文件记录评审意见,不代表已采纳或已实现。 > **后续决议(2026-08-05):** `MiniAppManifest.kind` 收敛为 `system | bundled`。Task Dashboard > 与 Whiteboard 均为非系统级 `bundled` MiniApp,必须采用与一般 MiniApp 相同的受限 Surface / > Bridge 模型;“参考”仅描述它们在本迭代验证 SDK 的目的。下文的 `bundled-reference` 为评审时的 > 历史术语,已由此决议取代。 > **后续决议(2026-08-05):** `notice / choice / confirm / input` 始终是 Interact 的人与 Agent > 会话交互,不属于 MiniApp SDK,也不用于 MiniApp 内部业务逻辑。当前 bundled MiniApp 位于前台时, > Interact / Shell 可在其上方显示同一会话的交互层;请求与答案仍只属于 Interact、当前会话和 Agent。 > **后续决议(2026-08-05):** 每个启动的 App instance 在主 IM 中创建或恢复一个 App 子会话;其中 > 只保留人与 Agent 围绕该 App 的提问、回答和简洁结果。App 的内部按钮、表单、画布编辑等业务操作 > 不进入子会话。后台化不结束子会话;真正结束时保留折叠历史;新的 instance 创建新的子会话。 > **后续决议(2026-08-05):** 已结束的 App 子会话可以在主 IM 中只读展开。用户选择“继续处理”时, > Runtime 创建新的 App instance 和新的子会话;新会话可引用旧会话或 App 数据,但不能续写旧记录或 > 复活旧问题。 > **后续决议(2026-08-05,已更新):** App 子会话只在 `AppLifecycleManager.close` 使对应 instance > 停止或失败时结束;前后台切换、暂停和 Agent Tool 完成都不结束子会话。关闭时,Runtime 向 Agent > 可靠发送 App 已关闭事件;尚未回答的 Interact 交互不自动取消,Agent 可 remote dismiss,或让其继续 > 在主 IM 中等待用户回答/超时。子会话保留为主 IM 历史。 > **后续决议(2026-08-05):** MVP 中一个 LineUp Runtime 只连接一个 Agent。每条标准交互和 > App 子会话仍保存当前 `agent_uid` 作为 `agent_id`,但本迭代不实现多个 Agent 的连接、切换、 > 会话列表、outbox 或路由。 ## 问题清单(Outline) > **状态标记:** ✅ 已解决并回填设计; 🟡 待产品/架构决策; 🔵 待在契约中细化; ⚪ 待实施编排或文档整理; — 不再适用。 > > 本清单是当前有效视图;后文保留评审时的原始问题、分析和建议作为依据。每次确认一个决策或完成 > 回填时,应先更新此处状态,再更新对应正文和验收项。 | 状态 | 编号 | 问题 | 当前结论 / 下一步 | |---|---|---|---| | ✅ | B1 | Task Dashboard 的信任级别与 UI 容器 | 已确认:Task Dashboard、Whiteboard 均为非系统级 `kind = bundled` MiniApp,必须运行于受限 Surface / Bridge,不能使用可信 Host DOM。 | | ✅ | I1 | `bundled-reference` / `bundled-development` 命名歧义 | 已确认:Manifest 枚举为 `system \| bundled`;“参考”仅描述当前迭代的工作目的。 | | ✅ | I2 | 标准交互由谁显示、答案如何回传 | 已确认:Interact / Shell 显示人与 Agent 的交互;bundled MiniApp 前台时可被该交互层覆盖。结果由 Runtime 可靠回传 Agent,不交给 MiniApp。 | | ✅ | I3 | 标准交互与 Agent Tool Call 的关系 | 已确认:标准交互仅由 Agent Tool 调起并创建交互记录;MiniApp 不存在 `sdk.ui.request`,不会自行创建 Agent Tool Call。 | | ✅ | I4 | 标准交互结果的返回通道 | 已确认:用户答案先回 Runtime,再可靠回传 Agent;不经 MiniApp Inbox、Tool 订阅或 MiniApp SDK 返回。 | | ✅ | I5 | Request/Result schema、状态机、幂等与错误码 | 已确认第一版:`notice` 非阻塞;`confirm` 二选一且默认取消;`choice` 只支持 2~6 项单选;`input` 只支持一个文本输入;首次有效回答终结交互;默认 15 分钟超时,可在 1 分钟~24 小时内调整。 | | ✅ | I6 | 敏感输入的持久化、恢复、审计和日志边界 | 已确认:未提交草稿仅存在当前运行期间,重启即清空;已提交的人与 Agent 答案保留在所属主 IM 或 App 子会话中,随父 IM 会话处理;二者均不写日志、Telemetry 或普通审计明文。 | | ✅ | I7 | App 子会话与主 IM 的关系 | 已确认:每个 App instance 创建/恢复一个子会话;后台保留,真正结束后在主 IM 中折叠存档,新 instance 独立。仅记录人与 Agent 围绕 App 的交互,不记录 App 内部业务操作。 | | ✅ | I8 | 已结束 App 子会话的查看与继续处理 | 已确认:旧子会话可只读展开;继续旧工作创建新 instance / 新子会话,可引用旧上下文,但不追加旧记录或复活旧问题。 | | ✅ | I9 | App 子会话何时结束 | 已确认:仅 `AppLifecycleManager.close` 导致 instance stopped/failed 时结束;前后台切换、暂停、Agent Tool 完成不结束。关闭时 Runtime 向 Agent 发送 App 已关闭事件,但不自动取消未回答的 Interact 交互。 | | ✅ | I10 | MVP 的 Agent 身份范围 | 已确认:Runtime 仅连接一个 Agent;交互和 App 子会话保存该 `agent_id`,但不实现多 Agent 连接、切换或路由。 | | — | S1 | `parent_call_id` 的关联校验与父 Tool 终止后的处置 | 不再适用:MiniApp 不再发起标准交互;标准交互直接绑定 Agent call 与 conversation。 | | ✅ | S2 | 交互层显示与恢复规则 | 已确认:原 App 前台时显示交互层;切换到其他 App/IM 时收起并在子会话标记“等待你的回答”;用户可在 IM 或回到原 App 后回答;关闭 App 只移除覆盖层并通知 Agent,不自动取消交互。 | | ✅ | S3 | Interact 呈现与 Agent Tool 回传的分层 | 已确认:Interact / Shell 只显示并把用户动作/答案交给 Runtime;Runtime 根据已保存的交互上下文校验、持久化和可靠回传 Agent;不经过 MiniApp。 | | ✅ | S4 | 阶段编号重复 | 已确认:Task Dashboard / Whiteboard 的端到端参考实现属于 `03.sdk_and_coreapp`;移除重复的 `03.reference-miniapps`,后续应用分发阶段保持为 `04.app-delivery-registry`。 | | ✅ | S5 | 实施步骤顺序 | 已确认:先完成通用 Tool 闭环,再完成 Runtime 独占的 Agent interaction service 和 Interact 回传契约,之后才适配 Interact、实现两个 bundled 参考 MiniApp,最后端到端验收。 | ## 1. 总体结论 这份文件保留了首次评审时提出的问题和建议,方便追溯讨论过程;其中涉及 `sdk.ui`、MiniApp 发起 标准交互、owner 注入等早期设想,均已被本文件顶部的“后续决议”和问题清单中的最终结论取代,不能作为 实施依据。 当前已经收敛的核心结论是: - 产品层级是 **LineUp App → LineUp Runtime → MiniApps**,Runtime 不是与 MiniApp 平级的产品 App。 - `notice / choice / confirm / input` 是 Interact 中人与 Agent 对话的一部分,不是 MiniApp SDK,也不能由 bundled MiniApp 发起、读取、提交或取消。 - Interact / Shell 只呈现和收集用户答案;Runtime 保存交互归属、校验首次有效回答、写入可靠 outbox,并 向当前唯一 Agent 回传结果。 - Task Dashboard 与 Whiteboard 都是 `kind = bundled`;它们使用一般 MiniApp 的受限 Surface、Bridge、 生命周期和 SDK,只保留自身的业务 UI。 - 保留 `lineup.v1.tool.call(choice | confirm | input)` 的 Agent 交互兼容入口;不在本迭代迁移 `chat → interact` 命名。 - 本迭代不建设 AppServer Catalog、下载、安装、更新、市场、远程 Bundle、真实媒体/文件能力或多 Agent Runtime 连接。 本轮评审问题均已得到设计结论,后续进入实现时应以 [03.sdk_and_coreapp.md](03.sdk_and_coreapp.md) 和 [APP架构设计.md](../../设计/APP架构设计.md) 为准。 ## 2. 阻塞问题 ### B1. Task Dashboard 的可信 DOM / Host adapter 权限突破了当前信任模型 **架构基线**在 [APP架构设计.md](../../设计/APP架构设计.md) 的 MiniApp 信任模型中明确: - `Interact / System MiniApp` 可使用可信内建 DOM 组件; - Installed MiniApp 必须经隔离 iframe / Surface Bridge 运行。 而 [03.sdk_and_coreapp.md](03.sdk_and_coreapp.md) 同时写了: ```text Task Dashboard 可由受信 Host adapter 挂载;Whiteboard 必须走受限 Surface ``` 并将 Task Dashboard 定义为: ```text kind = bundled-reference ``` 且说明它可使用“随 LineUp 发布的受信 Host adapter”。 **问题:** 当前权威架构没有明确授权 `bundled-reference` 获得与 System MiniApp 相同的可信 DOM 容器。若 Host adapter 可执行或挂载 Task Dashboard 的 UI,而未经过受限 Surface,隔离边界、SDK 受限视图和“禁止访问 Host DOM”就无法以同一安全模型证明。 **需要冻结的决策(二选一):** 1. **保守方案,且最符合当前权威基线:** Task Dashboard 和 Whiteboard 都是非 System MiniApp,必须经隔离 Surface / Bridge 运行。Host adapter 仅作为 Runtime/Shell 的不可见装配层,不向 MiniApp 提供可直接操作的可信 Host DOM。 2. **若产品确实需要 Task Dashboard 使用可信原生 DOM:** 将其升级为 `kind = system`,并在架构主文档新增或明确“bundled trusted system MiniApp”信任层、发布来源、可用 DOM 权限和审计边界;不能继续称其为普通 `bundled-reference`。 **建议验收:** - 若维持 `bundled-reference`,Task Dashboard 无法获得 Host 根 DOM、Tauri invoke 或未授权 Host adapter。 - 若改为 `system`,仍要验证其特权只限 Runtime SDK,不能取得 Transport、Store 或 Agent 访问权。 ## 3. 重要问题 ### I1. `bundled-development` 与 `bundled-reference` 的术语、Manifest 枚举未建立映射 迭代文档把“内置”解释为 `bundled-development`,但冻结的 `MiniAppManifest.kind` 只有: ```ts kind: "system" | "bundled-reference"; ``` 架构主文档也使用了“参考 MiniApp 在此阶段可以是 `bundled-development`”的表述。 这两个词可以共存,但必须明确它们不是互相竞争的 `kind` 枚举值。 **建议补充最小映射表:** | 概念 | 建议语义 | |---|---| | `bundled-development` | 本迭代的交付/加载方式:随开发 Host 预置,不下载、不安装、不经服务端 Catalog。 | | `kind = bundled-reference` | Manifest 身份:参考 MiniApp,决定 SDK / Surface 信任策略。 | | `kind = system` | 随产品发布、代码可信的系统 MiniApp,例如 Interact。 | 并明确:`bundled-development` **不是** `MiniAppManifest.kind` 的第三个取值。 ### I2. `sdk.ui` 缺少 Renderer 如何安全提交用户结果给 Runtime 的闭环契约 当前公开 API 只有: ```ts request(...) get(...) subscribe(...) cancel(...) ``` 但未定义: - Runtime 如何把被 Policy 选中、可呈现的 interaction record 交给 renderer; - renderer 如何提交 `submitted`、`result` 或 `cancelled`; - Runtime 如何校验 `interaction_id`、owner、renderer binding、状态迁移、一次性提交和结果 schema; - 在 opaque-origin iframe / Surface Bridge 内,呈现和回传采用何种受限消息协议; - renderer 与 owner 是同一 MiniApp 时,是否通过 `sdk.ui` 提交,还是只能通过 Runtime/Shell 私有 Renderer API 提交。 **建议冻结 Runtime 私有 Renderer Contract / 最小 Bridge Contract:** ```text Runtime 分配 interaction_id + renderer_binding + presentation container/surface → renderer 仅接收 presentation-safe request projection → renderer 向 Runtime-owned endpoint 提交 action/result → Runtime 校验: - 被分配的 renderer / container - interaction_id - owner binding - 当前状态与一次性提交 - result schema - expiry → Runtime 持久化状态迁移,并向 owner-scoped ui 订阅发出更新 ``` 隔离 Surface 至少还要限定消息白名单、`surface_id` / `instance_id` 绑定和 nonce 或等效关联方式;不得只凭 origin 信任。 ### I3. 标准交互与 `RuntimeToolCallRecord` 的关系不清晰 当前文档同时规定: - MiniApp 可调用 `sdk.ui.request(...)`; - owner 的 source 可为 `agent_tool | miniapp_tool | runtime_policy`; - 所有标准交互“必须映射为 Runtime 统一的 `interactive` Tool Call / `StandardInteractionRecord`”。 因此会产生问题:Task Dashboard 在没有 Agent Tool Call、例如用户点击“关闭未完成任务”时调用 `sdk.ui.request(confirm)`,Runtime 是否必须凭空创建 Agent-facing `RuntimeToolCallRecord`? **建议明确拆成三条路径:** | 来源 | Runtime 记录 | 与 Agent Tool 的关系 | |---|---|---| | Agent / legacy `lineup.v1.tool.call(choice/confirm/input)` | `RuntimeToolCallRecord` + `StandardInteractionRecord` | 交互终态受控驱动该 Tool 的后续处理。 | | MiniApp `sdk.ui.request(...)` | owner-bound `StandardInteractionRecord` | 不自动创建新的 Agent Tool;若提供合法 `parent_call_id`,只建立关联。父 Tool 的完成由 owner 经 `sdk.tools.*` 决定。 | | Runtime Policy 自发提示 | `runtime_policy` owner 的 interaction record | 需明确其是否绑定某一 Capability / lifecycle request。 | 没有 parent Tool 的交互只改变 MiniApp 本地工作流,不应制造 Inventory、Agent 回传或 outbox 语义。 ### I4. 结果投递位置与公开 API 不一致 流程写“结果仅投递回 owner MiniApp 的 Tool/Inbox”,但 SDK 已公开 `sdk.ui.get/subscribe`。 否则实现可能分叉成: 1. 结果通过 `sdk.ui.subscribe` 的 record update 返回; 2. 结果作为 Inbox 消息; 3. 结果通过 parent Tool 的 SDK Tool event 返回。 **建议冻结为:** ```text sdk.ui.get / sdk.ui.subscribe = owner 获取标准交互状态与结果的唯一 UI-domain 通道 sdk.inbox = Agent / Runtime 入站消息;不复用为 interaction result transport sdk.tools.complete / fail / cancel = owner 根据 UI result 自行决定是否推进关联 parent Tool ``` 还需定义:订阅是否立即回放 owner 当前 pending records、终态保留/清理策略、断线重连后的重放及去重语义。 ### I5. Schema、状态机、幂等规则不足以支持安全验收 已有四类 request 及基础状态,但还需要明确: - `StandardInteractionResult` 与 `InteractionReceipt` 的类型; - `choice.actions[].id` 的唯一性、最大数量、空数组是否允许,以及 single/multi/button 的选择基数; - `input.fields[].id` 的唯一性、字段数上限、必填、数值解析、空字符串、长度和范围的适用规则; - `notice` 的“只读”与 `acknowledged` 的精确定义:是否需要用户确认、是否自动完成、是否可超时; - `request`、`submit`、`cancel`、超时、恢复之间的合法状态迁移; - 并发提交、重放、重复取消、跨 Surface 重放的确定性返回; - 交互专用稳定拒绝码。 建议至少增加: ```text interaction_not_found interaction_owner_mismatch interaction_state_invalid interaction_expired interaction_result_invalid interaction_renderer_mismatch parent_call_invalid ``` ### I6. 持久化、审计与敏感输入的日志最小化约束尚未衔接 `input` 可以含用户自由文本;标准交互要求持久化、恢复和审计,但架构文档又要求日志不得包含身份、会话、消息正文、Tool 参数、token 或 artifact 内容。 **建议明确:** - 恢复所需的受保护 operational state、审计最小元数据、日志/Telemetry 三者的分层; - `input` 草稿和结果的保留期、终态清理策略,以及是否加密; - 审计仅记录 interaction ID、kind、受保护 owner 标识、状态迁移和错误码; - title、prompt、字段值和 action label 不进入日志、指标、错误详情或普通审计明文; - 验收增加日志负向断言。 ## 4. 建议完善项 ### S1. 扩大 `parent_call_id` 校验条件 除“属于当前实例且状态允许关联”外,Runtime 至少应校验: ```text 同 app_scope 同 instance_id 同 conversation_id 父 Tool 非终态 不存在跨 owner 关联 ``` 还要定义父 Tool 被取消或超时时关联 interaction 的处理:自动取消、保留为独立操作,或交由 Policy 决定。否则恢复后容易遗留孤儿卡片。 ### S2. 将 presentation policy 写成可判定矩阵 至少应覆盖: | owner 状态 / 容器 | 建议行为 | |---|---| | Agent IM / Interact 有效 | Interact IM timeline/card。 | | owner 前台且存在合法 renderer | owner 容器或已绑定 Surface 的标准 modal/sheet/card。 | | owner 后台或 suspended | 保持 pending;通知/唤醒仅经 Policy,不得抢占焦点。 | | Surface 已关闭或失效 | 不向旧 Surface 投递;恢复、降级或安全失败。 | | renderer 不可用 | 保持 pending 或返回稳定拒绝码;不能把 payload 注入 Host DOM。 | | 系统能力确认 | 走 Capability Gateway,禁止降级为普通 `confirm`。 | ### S3. Interact 呈现与 Agent Tool 回传的分层 **已确认(2026-08-05):** 用户在 Interact 中回答时,Interact 只负责显示问题、收集用户动作并把 答案交给 Runtime。它不是 Agent 的消息发送端,也不负责判断答案属于哪个 Agent、哪个会话或哪个 App 子会话。 ```text Interact / Shell 显示问题 → 用户作答 → Interact 向 Runtime 提交「interaction_id + 用户动作/答案」 → Runtime 从已保存的交互记录取得 agent_id、conversation、App 子会话和 Agent Tool 归属 → Runtime 核对 Interact 实例、展示位置、状态、期限、答案格式和首次提交 → Runtime 持久化会话记录与终态,并写入可靠 outbox → Runtime 向当前唯一 Agent 回传一次结果 ``` 提交端不能传递或覆盖 `agent_id`、`conversation_id`、`call_id`、`app_session_id` 等归属信息;这些 只能由 Runtime 创建交互时保存。重复点击、刷新后的旧页面、无效展示位置、过期或已结束问题的提交都 必须被拒绝,且不能改变已经保存的结果或再次通知 Agent。Task Dashboard、Whiteboard 等 bundled MiniApp 始终不参与这条链路,也读不到问题或答案。 ### S4. 统一阶段编号 **已确认(2026-08-05):** Task Dashboard 与 Whiteboard 是 `03.sdk_and_coreapp` 中用来验证 SDK 的 bundled 参考 MiniApp,本阶段就完成其端到端路径。因此删除重复的 `03.reference-miniapps`;后续阶段 保持为 `04.app-delivery-registry`,不需要整体重编号。 ### S5. 在实施步骤中拆出标准交互服务和 renderer/Bridge 契约 **已确认(2026-08-05):** 实施顺序已调整为: 1. 冻结契约与测试样本; 2. 实现 Runtime 通用 Tool 闭环; 3. 实现 Runtime 独占的 Agent interaction service,以及 Runtime ↔ Interact 的最小呈现/提交契约; 4. 再适配 Interact IM 和 App 子会话; 5. 最后通过 Task Dashboard、Whiteboard 验证一般 bundled MiniApp 路径,并进行端到端验收。 这样标准交互不会先被做成 Chat 专用或 MiniApp SDK 能力;Interact 只是第一个使用 Runtime 私有交互 契约的系统级呈现者,两个 bundled MiniApp 则只验证各自的 Tool、Surface 和业务 UI 边界。 ## 5. 建议新增的最小验收场景 1. A 实例提交属于 B 实例、不同 conversation 或已终态 Tool 的 `parent_call_id` 时,Runtime 拒绝且不创建 record。 2. A 创建 interaction 后,B 无法 `get`、订阅、取消、提交,或通过伪造 `interaction_id` 获得任何 payload/result。 3. 同一 interaction 的两次 renderer submit 只有一次成功;第二次得到稳定终态错误且不改变已持久化结果。 4. 旧 `lineup.v1.tool.call(choice|confirm|input)` 创建关联 Tool Call 和 owner 为 Interact IM context 的 interaction;用户结果先由 Runtime 落库,再由 Interact 以 owner 身份完成 Tool。 5. Task Dashboard 无 parent Tool 的 `sdk.ui.request(confirm)` 不创建 Agent-facing Tool Call、不写 Agent outbox;带合法 parent Tool 时仅关联,不自动完成该 Tool。 6. Task Dashboard 前台时,标准 modal/sheet/card 在其合法容器显示,焦点栈与 Interact background 状态不被改写。 7. Whiteboard 在 Surface reload、关闭、旧 iframe 重放提交时,`surface_id` 与 renderer binding 都被验证,旧 iframe 消息被拒绝。 8. 非法 input、重复/未知 choice action、过期 interaction、跨 owner cancel 都被拒绝且不写错误结果。 9. 标准交互输入值、提示正文、选择标签不出现在日志、Telemetry 或 Audit 明文中;重启恢复仅保留设计允许的最小数据。 10. 若维持 `bundled-reference`,Task Dashboard 不能直接挂载可信 Host DOM;若改为 `system`,必须有对应的 manifest/source-trust 回归用例。 ## 6. 建议的阅读和决策顺序 明天继续时,建议按以下顺序决策和回填: 1. 先决定 **B1:Task Dashboard 的信任级别与 UI 容器**; 2. 冻结 **I2:Renderer → Runtime 的提交/Bridge 契约**; 3. 冻结 **I3/I4:StandardInteractionRecord 与 Tool Call 的关系,以及 UI result 的唯一返回通道**; 4. 细化 **I5/I6:schema、状态机、幂等、错误码、持久化与日志最小化**; 5. 把 S1~S5 与第 5 节的验收场景回填入 [03.sdk_and_coreapp.md](03.sdk_and_coreapp.md) 和必要的 [APP架构设计.md](../../设计/APP架构设计.md)。 在上述收敛前,不建议开始 `standard-interaction-service` 或参考 MiniApp 的实现,以免重新形成 Chat / Interact 专用旁路。