# `03.sdk_and_coreapp` 第 2 次设计评审记录 > 评审编号:02 > 评审日期:2026-08-05 > 评审对象:[03.sdk_and_coreapp.md](03.sdk_and_coreapp.md)、[01.design_review.md](01.design_review.md) > 评审方式:独立子 agent 只读复核 > 结论:核心方向已收敛;没有 P0 阻塞问题。以下 P1 项需在开始编码前逐项确认并回填主定义文档。 ## 问题清单(Outline) > **状态标记:** ✅ 已确认并回填设计; 🟡 待产品/架构决策; 🔵 待在契约中细化; ⚪ 文档或实施编排建议; — 不适用或无此问题。 > > 本清单是本次评审的当前有效视图。后文保留每个问题的背景和建议;在问题被确认前,建议不是实施依据。 > 确认后应先更新本清单,再回填 [03.sdk_and_coreapp.md](03.sdk_and_coreapp.md) 的契约、实施步骤和验收项。 | 状态 | 编号 | 问题 | 当前结论 / 下一步 | |---|---|---|---| | — | P0 | 阻塞级架构冲突 | 本次未发现需要推倒既有模型的 P0 问题。 | | ✅ | P1-1 | Task Dashboard 示例中 Tool 完成后关闭 App | 已回填:Tool 完成只回传 Agent;App 保留、后台或关闭由用户动作、`requestClose` 或 Lifecycle Policy 决定,只有真正 `AppLifecycleManager.close` 才结束 App 与子会话。 | | ✅ | P1-2 | `interactive` Tool 的专用路由 | 已回填:`interactive` 是 Runtime 自己处理的 Agent 交互分支,不创建/复用业务 MiniApp instance,不调整业务 App 焦点,也不进入任何 MiniApp SDK Tool Inbox;Runtime 私有契约交给 Interact / Shell 呈现。 | | — | P1-3 | 展示位置切换后的提交资格 | 不再适用:展示位置不是交互 owner 或提交权限。切换 App 前后台、关闭 App 或改在 IM 显示不改变同一 `interaction_id` 的归属;Runtime 只接受首次有效回答,之后才拒绝重复/重放。 | | ✅ | P1-4 | Tool 与交互的取消、超时和并发提交 | 已回填:用户回答、Agent dismiss、到期和 Runtime 失败竞争同一唯一终态;Runtime 第一个原子状态写入获胜,Tool 跟随同一结果,且只写一条 outbox。interactive Tool 仅使用交互 `expires_at`,不维护独立超时。 | | ✅ | P1-5 | `notice` 的 Tool 完成时点与结果 | 已回填:notice 必须保留为 Interact / IM 的只读卡片,可选同时 Toast 数秒;Runtime 持久化卡片并安排呈现后,立即以 `{ outcome: "accepted" }` 完成并回传,不表示用户已阅读。 | | — | P2-1 | 将普通标准交互统一当作敏感秘密输入 | 不再适用:`notice / choice / confirm / input` 按普通 IM 会话内容与日志基线处理;本迭代不为它们另设秘密输入契约或专门负向扫描。未提交草稿仍只在运行期存在,重启清空。 | | ⚪ | P4-1 | 首次评审中的历史提案可读性 | **遗留问题:** 不阻塞本迭代;建议在下一次文档整理或新评审时,进一步突出其中 `sdk.ui`、owner、`parent_call_id` 等旧提案仅供追溯、不可实施。 | | ⚪ | P4-2 | `password-input` 秘密输入原语 | **遗留问题:** 当前不阻塞 `03`;真正出现密码、卡密、私钥或临时 token 的 Agent 交互需求时,单独定义该原语及其不显示明文、不进入普通 IM 正文/日志/Telemetry/审计、可靠传递与清理等安全契约。 | ## 通过项 - 标准交互已经清楚限定为 Interact 中的人与 Agent 会话交互,而非 MiniApp SDK;公开 SDK 不包含 `sdk.ui`。 - Task Dashboard、Whiteboard 已收敛为 `kind = bundled`,必须走受限 Surface / Bridge,不能取得可信 Host DOM、Tauri、Transport、Store、Agent 或其他 MiniApp 数据。 - 用户答案经 Interact 交给 Runtime;Runtime 保存交互归属、校验、持久化并可靠回传当前唯一 Agent,bundled MiniApp 不参与。 - App 子会话正确区分了人与 Agent 的记录和 MiniApp 内部业务操作;前后台、关闭、历史只读和“继续处理”的总体规则一致。 - MVP 单 Agent 边界明确,没有提前引入多 Agent 连接、切换或路由。 ## P0:阻塞问题 无。 ## P1:开始编码前需要确认的事项 ### P1-1:Tool 完成不应自动关闭 Task Dashboard **已解决(2026-08-05):** 主定义文档已经确认“Agent Tool 完成不自动关闭 App,也不结束 App 子会话”。Task Dashboard 示例与验收现已统一为该规则。 当前规则: ```text Tool 完成 → Runtime 持久化并回传 Agent → App 是否保持前台、进入后台或关闭,取决于用户动作、MiniApp requestClose 或 Lifecycle Policy → 只有真正执行 AppLifecycleManager.close,才结束 App 与 App 子会话 ``` 验收已要求:Tool 成功回传后 Dashboard 可继续使用;只有真正关闭才结束子会话。 ### P1-2:interactive Tool 必须不进入 MiniApp SDK Tool Inbox **已解决(2026-08-05):** 通用 Tool 路由、实施步骤和验收已明确拆开 `interactive` 与一般 Tool。 `notice / choice / confirm / input` 不会投递到 App Orchestrator、业务 MiniApp instance、SDK Tool Inbox 或 `sdk.tools.subscribe`。 当前规则: ```text handling = interactive → 不投递任何 MiniApp SDK Tool Inbox → Runtime Agent interaction service 创建 StandardInteractionRecord → Runtime 私有契约交给 Interact / Shell 呈现 → Interact 提交 interaction_id + 用户动作/答案 → Runtime 校验、持久化、outbox 回传 Agent handling = direct / launch / foreground / operation → 才进入 App Orchestrator、SDK Tool Inbox、MiniApp tools.* 路径 ``` 验收已要求:Agent 发起的四类标准交互不得出现在任何 MiniApp Inbox 或 `sdk.tools.subscribe`。 ### P1-3:切换展示位置后,旧页面必须失去提交资格 **不再适用(2026-08-05):** 该问题错误地把 App 上方覆盖层或 IM 卡片当成了交互的 owner。标准交互 始终属于 Interact / 主 IM;`app_session_id` 只保留与哪段 App 工作相关的上下文,不形成 UI 父子关系。 切换 App 前后台、关闭 App 或改变展示位置不改变同一个 `interaction_id` 的归属,也不需要用 `presentation_id` / `presentation_revision` 废止旧页面的回答资格。只要用户仍处于有效 LineUp / Interact 会话且交互尚未终态,Runtime 可接受该交互的首次有效回答;以后到达的重复、重放或迟到提交 因交互已经终态而被拒绝。Shell 可以避免用户看到重复视觉卡片,但这是体验策略,不是结果正确性的依据。 验收应覆盖:交互从 Whiteboard 覆盖层改在 IM 中显示、Whiteboard 关闭后交互仍 pending 时,任一有效 Interact 页面提交的第一份答案只产生一次持久化结果和一次 Agent 回传;后续提交不改变结果。 ### P1-4:Tool 与交互的取消、超时和并发提交需要收敛规则 **已解决(2026-08-05):** Runtime 是标准交互的唯一终态裁决者。用户回答、Agent dismiss、到期和 Runtime 失败都竞争同一条交互的唯一结果。 当前规则: ```text Runtime 对仍为 pending / presented 的 interaction 执行原子状态写入 → 第一个成功写入的动作获胜 → 用户回答:持久化答案,Tool 得到 answered → Agent dismiss:交互与 Tool 得到 cancelled → expires_at 到期:交互与 Tool 得到 expired → Runtime 失败:交互与 Tool 得到 failed → 同一事务或等价原子动作中只创建一条 Tool 结果 outbox 任何后到的回答、dismiss、取消或超时处理 → interaction_already_final → 不覆盖结果,不创建第二条 outbox ``` MVP 中 interactive Tool 没有另一套独立 timeout;其期限就是交互 `expires_at`。Agent 主动停止等待必须走 `dismiss`,不走独立的通用 Tool 取消路径。 ### P1-5:`notice` 的完成时点和 Tool 结果需要固定 **已解决(2026-08-05):** `notice` 是 Interact / IM 中持久保留的只读卡片;Toast 只是同一条 notice 记录的可选短暂提醒,不是没有历史的独立消息。 ```text Runtime 校验并持久化 notice 卡片 → 交给 Interact 呈现 → 当前前台界面可同时 Toast 数秒 → Runtime 立即以 { outcome: "accepted" } 完成并回传一次 Tool 结果 ``` `accepted` 只表示 Runtime 已接受、保存并安排呈现,不表示用户已看见或阅读。Toast 自动消失、用户忽略 Toast 或收起 notice 卡片,均不产生新的 Agent 结果;持久化或安排呈现前 Runtime 失败时,结果为 `failed`。 ## P2:本迭代验收前必须处理(本次无未决项) ### P2-1:将普通标准交互统一当作敏感秘密输入 **不再适用(2026-08-05):** 此问题把所有标准交互一概当成秘密输入,边界过重且不符合产品语义。 `notice`、`choice`、`confirm` 与普通 `input` 是人与 Agent 的正常 IM 会话内容:已提交的内容按普通 IM 会话历史、保留与日志基线处理,不在 SDK v1 中额外定义为密码或秘密。全局日志基线仍然有效,不能因此 随意打印会话正文、Tool 参数或 token。 未提交的 `input` 草稿仍只能存在于当前运行期;重启后清空,不自动提交、发送或进入 outbox。这是恢复 和正确性要求,不代表普通 `input` 已升级为秘密输入能力。 ## P4:遗留问题(不阻塞当前迭代) ### P4-1:首次评审中的历史提案可读性 **延期原因:** 顶部 Outline 和总体结论已经说明早期 `sdk.ui`、owner、`parent_call_id` 等提案不再是 实施依据;这不影响当前 SDK、Runtime 或验收实现。 建议在下一次文档整理或新的设计评审时,将原始评审正文加上“仅供追溯,禁止作为实现、测试或验收依据” 的更醒目标识,或移至附录。当前有效结论始终以主定义文档和评审记录顶部的 Outline 为准。 ### P4-2:`password-input` 秘密输入原语 **延期原因:** 当前 `03` 要完成的是 `notice / choice / confirm / input` 的 SDK v1 与会话交互闭环; 目前没有真实的密码、卡密、私钥或临时 token 输入场景。把秘密输入仅做成普通 `input` 的掩码样式,不能 解决内容怎样保留、传递、重试和清理的问题,因此不在本迭代仓促实现。 **重新评估条件:** Agent 确实需要向用户收集密码、卡密、私钥、临时 token 或同类秘密时,启动单独设计。 届时 `password-input` 应作为与 `input` 并列的 Agent 交互原语,由 Runtime 按 `kind` 强制执行安全契约, 而不是允许 Agent 用普通 `input` 自行约定保护方式。至少要明确:界面不显示明文;主 IM 只保留“已提交 敏感信息”等替代记录;内容不进入普通日志、Telemetry 或审计;可靠 outbox 的暂存、加密(如需要)、 Agent 接收后的清理、重启、失败、重试与一次性传递规则。