Compare commits

..

7 Commits

24 changed files with 3316 additions and 142 deletions
+11 -7
View File
@@ -54,7 +54,7 @@ Chat Core App
- 登录、同步、发送、本地回显、Markdown、Agent 状态和刷新恢复保持回归通过; - 登录、同步、发送、本地回显、Markdown、Agent 状态和刷新恢复保持回归通过;
- 当前 Tauri/Web 回归为 23 个测试文件、99 个测试,`npm run build` 通过。 - 当前 Tauri/Web 回归为 23 个测试文件、99 个测试,`npm run build` 通过。
完整边界、MiniApp SDK 路线和发布安全约束见 [APP架构设计.md](APP架构设计.md)。 完整边界、MiniApp SDK 路线和发布安全约束见 [APP架构设计.md](设计/APP架构设计.md)。
## 开发与验证 ## 开发与验证
@@ -92,22 +92,26 @@ npm run desktop:dev
## 文档入口 ## 文档入口
- [APP架构设计.md](APP架构设计.md)LineUp App、Runtime、MiniApp SDK、Surface/Capability 安全与后续迭代的权威架构设计 - [设计/README.md](设计/README.md):当前设计文档入口和文档分工说明
- [APP架构设计.md](设计/APP架构设计.md)LineUp App、Runtime、MiniApp SDK、Surface/Capability 安全与后续迭代的权威架构设计;
- [程序文件清单与功能说明.md](程序文件清单与功能说明.md):客户端 Runtime、Chat Core App、Tauri/Web Host 与测试的文件清单; - [程序文件清单与功能说明.md](程序文件清单与功能说明.md):客户端 Runtime、Chat Core App、Tauri/Web Host 与测试的文件清单;
- [tauri/src/README.md](tauri/src/README.md):源码目录、依赖方向与模块放置规则; - [tauri/src/README.md](tauri/src/README.md):源码目录、依赖方向与模块放置规则;
- [tauri/README.md](tauri/README.md)Tauri/Web Host 的运行、构建、行为回归和历史里程碑; - [tauri/README.md](tauri/README.md)Tauri/Web Host 的运行、构建、行为回归和历史里程碑;
- [迭代/](迭代/00.base/00.base.md):按迭代目录记录当前基线、设计评审和后续 Runtime Kernel / 应用编排目标; - [迭代/](迭代/00.base/00.base.md):按迭代目录记录当前基线、设计评审和后续 Runtime Kernel / 应用编排目标;
- [LineUp App 最终设计方案](../设计/02.正式方案/app_final_design.md):当前架构的唯一汇总入口; - [LineUp App 最终设计方案](设计/02.正式方案/app_final_design.md):当前架构的唯一汇总入口;
- [LineUp App 层架构方案](../设计/02.正式方案/lineup-app-layer-architecture.md):M0~M4 历史实施记录与迁移基础; - [LineUp App 层架构方案](设计/02.正式方案/lineup-app-layer-architecture.md):M0~M4 历史实施记录与迁移基础;
- [LineUp Runtime 与 App SDK 架构方案](../设计/02.正式方案/lineup-runtime-sdk-architecture.md)Runtime / SDK 的详细契约来源; - [LineUp Runtime 与 App SDK 架构方案](设计/02.正式方案/lineup-runtime-sdk-architecture.md)Runtime / SDK 的详细契约来源;
- [LineUp UI Surface 与 App Capability 协议](../设计/02.正式方案/lineup-ui-surface-protocol.md)Surface sandbox 和 Capability Gateway 协议; - [LineUp UI Surface 与 App Capability 协议](设计/02.正式方案/lineup-ui-surface-protocol.md)Surface sandbox 和 Capability Gateway 协议;
## 工作区目录 ## 工作区目录
```text ```text
lineup-app/ lineup-app/
├── README.md # LineUp App 工作区入口 ├── README.md # LineUp App 工作区入口
├── APP架构设计.md # 当前权威架构、SDK 与发布安全设计 ├── 设计/ # 当前设计文档
│ ├── README.md
│ ├── APP架构设计.md
│ └── 02.正式方案/
└── tauri/ # Tauri Desktop + Web Reference Host └── tauri/ # Tauri Desktop + Web Reference Host
├── src/ # Runtime、Core App 与 Host 组合入口 ├── src/ # Runtime、Core App 与 Host 组合入口
└── src-tauri/ # Tauri Rust Host └── src-tauri/ # Tauri Rust Host
+1 -1
View File
@@ -29,7 +29,7 @@ Surface、Capability、签名 Bundle 与隔离 bridge 已有 M2M4 的实现
## Milestone 0 当前行为基线 ## Milestone 0 当前行为基线
本节记录 Runtime 重构前已经由 Mac 开发态验证的行为。它是 M0 的回归基线,不代表最终模块结构;正式阶段任务和准入门槛见 [App Layer 架构方案 §9.1](../../设计/02.正式方案/lineup-app-layer-architecture.md#91-阶段任务清单与硬性准入门槛)。 本节记录 Runtime 重构前已经由 Mac 开发态验证的行为。它是 M0 的回归基线,不代表最终模块结构;正式阶段任务和准入门槛见 [App Layer 架构方案 §9.1](../设计/02.正式方案/lineup-app-layer-architecture.md#91-阶段任务清单与硬性准入门槛)。
| 范围 | 当前行为 | 当前实现位置 | 重构后必须保持 | | 范围 | 当前行为 | 当前实现位置 | 重构后必须保持 |
|---|---|---|---| |---|---|---|---|
+4 -4
View File
@@ -14,7 +14,7 @@
}, },
"devDependencies": { "devDependencies": {
"@tauri-apps/cli": "^2.0.0", "@tauri-apps/cli": "^2.0.0",
"typescript": "^5.7.3", "typescript": "^6.0.3",
"vite": "^6.1.0", "vite": "^6.1.0",
"vitest": "^3.2.7" "vitest": "^3.2.7"
} }
@@ -1732,9 +1732,9 @@
} }
}, },
"node_modules/typescript": { "node_modules/typescript": {
"version": "5.9.3", "version": "6.0.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"bin": { "bin": {
+1 -1
View File
@@ -20,7 +20,7 @@
}, },
"devDependencies": { "devDependencies": {
"@tauri-apps/cli": "^2.0.0", "@tauri-apps/cli": "^2.0.0",
"typescript": "^5.7.3", "typescript": "^6.0.3",
"vite": "^6.1.0", "vite": "^6.1.0",
"vitest": "^3.2.7" "vitest": "^3.2.7"
} }
+4
View File
@@ -0,0 +1,4 @@
declare module "*.css" {
const stylesheet: string;
export default stylesheet;
}
+1 -2
View File
@@ -6,9 +6,8 @@
"lib": ["ES2022", "DOM", "DOM.Iterable"], "lib": ["ES2022", "DOM", "DOM.Iterable"],
"skipLibCheck": true, "skipLibCheck": true,
"moduleResolution": "bundler", "moduleResolution": "bundler",
"baseUrl": ".",
"paths": { "paths": {
"@/*": ["src/*"] "@/*": ["./src/*"]
}, },
"allowImportingTsExtensions": false, "allowImportingTsExtensions": false,
"resolveJsonModule": true, "resolveJsonModule": true,
+157 -111
View File
@@ -1,159 +1,205 @@
# LineUp App 程序文件清单与功能说明 # LineUp App 程序文件清单与功能说明
> 最后核验:2026-08-04Asia/Shanghai > 最后核验:2026-08-06Asia/Shanghai
> >
> 本文 `lineup-app/` 客户端源码导航,覆盖 Tauri/Desktop Host、Web Reference Host、 > 本文按“模块”整理 `lineup-app/` 当前客户端代码。每个模块都说明它负责什么、对应哪些程序文件,以及它与其他模块的边界。
> `LineUpRuntime`、Interact MiniApp(当前兼容名 Chat)与客户端测试。跨项目的 AppServer、Hermes Adapter、 > LineUp App 的设计文档入口见 [设计/README.md](设计/README.md)。跨项目的 AppServer、Hermes Adapter、WuKongIM 和运行配置见[根程序文件清单](../程序文件清单与功能说明.md)。
> WuKongIM 和运行配置见[根程序文件清单](../程序文件清单与功能说明.md)。
## 1. 当前客户端怎样运行 ## 一、客户端整体结构
LineUp 不是“聊天页面直接连 Agent”。用户首先打开的是一个运行外壳:正式交付时是 Tauri LineUp App 不是一个直接连 Agent 的聊天页面,而是一个由 Runtime 托管多个 App 的客户端。
桌面窗口,开发和联调时可在浏览器中打开 Web Reference Host。两种外壳都会启动同一个 用户打开的是 Tauri 桌面外壳或浏览器开发外壳;外壳启动 Runtime;Runtime 再装载系统级
RuntimeRuntime 再加载默认 Chat,并负责 Chat 与 AppServer / Remote Agent 之间的全部 Interact App 和其他 MiniApp。
通信。
```text ```text
Tauri Desktop Host / Web Reference Host Tauri 桌面外壳 / Web 浏览器外壳
main.ts(启动时把 Host、Runtime 与默认 App 接起来) 启动装配模块
→ LineUpRuntime → LineUp Runtime
→ CoreAppRegistry → chat Core App ├── 系统级 Interact App(当前包含 IM 模式)
→ ChatRuntimeSDK ├── bundled MiniApp:任务面板
└── bundled MiniApp:白板
→ AppServer / Remote Agent → AppServer / Remote Agent
``` ```
当前唯一的客户端实现与验收基线是 Tauri 2 Desktop Host + Web Reference Host。两种 Host 必须保持的边界:
复用同一份 TypeScript Runtime 与 Chat Core App,不是两套客户端。`main.ts` 只在启动时把
Host、`LineUpRuntime` 和默认 App 接起来;网络传输、消息存储、同步循环、待发送队列、
scope 路由和旧 `lineup.v1` 兼容都由 Runtime 统一管理。
## 2. 工作区顶层文件 - 网络连接、消息同步、本地存储、待发送队列和会话恢复只能由 Runtime 负责。
- Interact 是系统级 MiniApp,负责人与 Agent 的主要交互;其中 IM 是当前已启用的交互模式。
- 任务面板和白板是普通 `bundled` MiniApp,必须通过 MiniApp SDK 和受限 Surface 运行。
- MiniApp 不能直接访问 Transport、Conversation Store 或原始协议解析器。
- 应用内部的按钮、表单和编辑动作属于该 MiniApp 自己的业务逻辑;只有人与 Agent 的交互才进入 Interact 会话。
| 文件 / 目录 | 功能 | ## 二、工作区入口模块
|---|---|
| `README.md` | LineUp App 工作区入口、当前实现摘要、开发与文档导航。 |
| `程序文件清单与功能说明.md` | 本文:客户端源码与测试导航。 |
| `APP架构设计.md` | LineUp App、Runtime、MiniApp SDK、Surface/Capability 安全、发布约束和后续路线。 |
| `tauri/` | Tauri Desktop Host 与 Web Reference Host 的工程目录。 |
## 3. Tauri/Web 工程入口 | 中文模块名 | 对应程序 | 作用 |
|---|---|---|
| 工作区说明 | `README.md` | 当前客户端基线、开发命令、文档入口和 Host 说明。 |
| 设计文档 | `设计/README.md``设计/APP架构设计.md``设计/02.正式方案/` | 当前架构、Runtime、SDK、Surface、Capability 和 MiniApp 约束。 |
| 迭代与评审记录 | `迭代/` | 每次迭代的目标、设计评审、验收评审和遗留问题。 |
| 程序清单 | `程序文件清单与功能说明.md` | 本文,按模块说明客户端源码。 |
| Tauri/Web 工程 | `tauri/` | TypeScript 前端、Vite 工程和 Tauri Rust 外壳。 |
目录:`tauri/` ## 三、启动与运行外壳模块
| 文件 / 目录 | 功能 | 这一层只负责“把程序启动起来”,不负责业务通信和消息处理。
|---|---|
| `package.json` | Vite、Vitest、Tauri CLI 与开发/构建脚本。 |
| `vite.config.ts` | Vite/Vitest 的 `@/ → src/` 源码别名。 |
| `tsconfig.json` | TypeScript 严格检查与同一 `@/` 路径别名。 |
| `index.html` | Vite 页面入口。 |
| `scripts/tauri.sh` | Tauri/Rust 工具链包装脚本。 |
| `src/` | TypeScript Host、Runtime、Core App 与测试。 |
| `src-tauri/` | Tauri Rust Host、窗口配置、能力声明和图标。 |
| `README.md` | Tauri/Web Host 的运行、构建、回归和历史里程碑。 |
## 4. TypeScript Runtime 与 Chat Core App | 中文模块名 | 对应程序 | 作用 |
|---|---|---|
| 启动装配 | `tauri/src/main.ts` | 创建 Host 适配、LineUp Runtime 和默认应用;不直接处理网络、存储或 Chat Renderer。 |
| Web 开发外壳 | `tauri/index.html``tauri/vite.config.ts` | 提供浏览器中的 Web Reference Host、源码别名和开发构建入口。 |
| TypeScript 工程配置 | `tauri/tsconfig.json``tauri/package.json``tauri/package-lock.json` | TypeScript 检查、Vite、Vitest、Tauri CLI 和开发脚本。 |
| Tauri 构建脚本 | `tauri/scripts/tauri.sh` | 统一调用 Tauri/Rust 工具链。 |
| Tauri 桌面外壳 | `tauri/src-tauri/src/main.rs``tauri/src-tauri/src/lib.rs` | 创建正式桌面窗口并运行 Tauri 应用。 |
| 桌面权限与配置 | `tauri/src-tauri/tauri.conf.json``tauri/src-tauri/capabilities/default.json``tauri/src-tauri/Info.plist``tauri/src-tauri/build.rs` | 窗口、应用元数据、系统权限、macOS WebView/ATS 和 Rust 构建配置。 |
目录:`tauri/src/`。完整依赖方向见 [src/README.md](tauri/src/README.md)。 ## 四、Runtime 核心协调模块
### 4.1 Host 组合与 Chat Core App Runtime 是客户端的唯一协调中心。所有 App 都通过它获得自己范围内的数据和能力。
| 文件 / 目录 | 功能 | ### 4.1 Runtime 总协调
|---|---|
| `main.ts` | 应用启动装配入口:创建 Runtime,并请求通用 `RuntimeAppHost` 根据 App Registry 挂载默认 Core App。它不直接导入 Chat Renderer,也不拥有网络传输、消息存储、同步循环或待发送队列。 |
| `core-apps/chat/chat-shell.ts` | Chat Core App 的可信 DOM Shell。 |
| `core-apps/chat/chat-app-host.ts` | Chat Core App 的 Host 装配器:集中加载 Chat 样式、Shell、Renderer、DOM 上下文和 Chat SDK,避免这些细节进入 `main.ts`。 |
| `core-apps/chat/trusted-dom-renderers.ts` | 已验证消息到可信 DOM:Markdown、消息、交互卡、任务、执行摘要、Surface、Capability、Artifact 与 fallback。 |
| `core-apps/chat/renderer-registry.ts` | 按受信任 `ConversationItem.kind` 分派 Chat Renderer。 |
| `core-apps/chat/styles/` | Chat Shell、能力卡片、执行摘要样式。 |
### 4.2 App 管理、SDK 与 Runtime 协调 | 中文模块名 | 对应程序 | 作用 |
|---|---|---|
| Runtime 总协调器 | `tauri/src/runtime/coordination/lineup-runtime.ts` | 统一持有 Transport、会话 Store、同步循环、outbox、作用域筛选、App Inbox、协议兼容和 SDK 投影。 |
| 交互内核 | `tauri/src/runtime/coordination/interaction-kernel.ts` | 解码受信消息、抑制重复消息、整理 Agent 状态、Tool/Task 投影;不直接渲染页面。 |
| Agent 交互服务 | `tauri/src/runtime/coordination/agent-interaction-service.ts` | 组织 Agent 交互请求、标准交互结果和 Runtime 内部事件。 |
| App 编排器 | `tauri/src/runtime/coordination/app-orchestrator.ts` | 根据 Agent Tool 调用启动、切换、恢复或关闭目标 MiniApp。 |
| 运行时信封 | `tauri/src/runtime/coordination/runtime-envelope.ts` | 校验 `app_scope``conversation_id``app_session_id` 等上下文,并兼容旧消息作用域。 |
| 文件 | 功能 | ### 4.2 App 实例、焦点和生命周期
|---|---|
| `runtime/coordination/lineup-runtime.ts` | Runtime 唯一协调器:持有 Transport、Conversation Store、sync loop、outbox、scope 筛选、`lineup.v1` 兼容、可靠 App Inbox 与 Chat SDK 投影。 |
| `runtime/app-management/app-registry.ts` | 本地 Core App Registry;当前静态注册默认/恢复 `chat`。 |
| `runtime/app-management/app-sdk.ts` | 当前 Chat/IM Runtime SDKCore App 与 Runtime 之间的受限接口;提供状态/消息订阅、Inbox ACK、Runtime Action、Tool/Task 投影。Runtime 通过 `openApp(app_scope)` 选择对应 SDK。 |
| `runtime/app-management/runtime-app-host.ts` | 从 Runtime App Registry 解析默认 App,再通过 Core App Host Registry 找到对应装配器并挂载可信 Core App。 |
| `runtime/coordination/interaction-kernel.ts` | 无副作用协议入口:decode、重复抑制、Agent 状态、Tool/Task 投影。 |
| `runtime/coordination/runtime-envelope.ts` | 内部 `RuntimeEnvelope``app_scope + conversation_id` 校验及旧协议作用域映射。 |
| `runtime/coordination/tool-call-state.ts` | `choice / confirm / input` 交互状态机。 |
| `runtime/coordination/task-state.ts` | `agent.progress``operation_id` 聚合。 |
| `runtime/coordination/execution-progress-state.ts` | 按 `execution_id` 关联 ACP 实时步骤。 |
### 4.3 通信、持久化与协议 | 中文模块名 | 对应程序 | 作用 |
|---|---|---|
| App 实例管理 | `tauri/src/runtime/app-management/app-instance-manager.ts` | 保存每个 App instance 的状态、所属会话、父子关系和恢复信息。 |
| App 焦点管理 | `tauri/src/runtime/app-management/app-focus-manager.ts` | 维护前台 App 的焦点栈;切换应用时由 Runtime 调整,不由 MiniApp 自己决定。 |
| App 生命周期管理 | `tauri/src/runtime/app-management/app-lifecycle-manager.ts` | 统一处理启动、前台、后台、挂起、关闭、失败和恢复。 |
| App 注册表 | `tauri/src/runtime/app-management/app-registry.ts` | 保存 Runtime 已知的内置 App 及其作用域;当前包括 Interact 和 bundled MiniApp 注册信息。 |
| App Host 装配 | `tauri/src/runtime/app-management/runtime-app-host.ts` | 根据注册表找到对应 Host 装配器并挂载可信 App。 |
| App SDK 投影 | `tauri/src/runtime/app-management/app-sdk.ts` | 向系统级 App 提供受限的 Runtime 状态、消息、Inbox、工具调用和动作接口。 |
| 文件 | 功能 | ## 五、MiniApp SDK 与应用契约模块
|---|---|
| `runtime/communication/transport-adapter.ts` | HTTP Transport:登录、发送、同步、超时和响应校验。 |
| `runtime/persistence/conversation-store.ts` | 会话持久化:cursor、消息、typed outbox、App Inbox、Tool/Task、摘要、Surface/Capability 快照。 |
| `runtime/protocol/lineup-v1.ts` | LineUp v1 受限协议模型与解析边界。 |
| `runtime/protocol/golden/lineup-v1.json` | `lineup-v1-golden-1` Runtime compatibility fixture。 |
### 4.4 Surface、能力、Artifact 与 Inventory 这一层定义普通 MiniApp 如何被 Runtime 接受和运行。它不负责加载任意代码,也不直接授予系统权限。
| 文件 | 功能 | | 中文模块名 | 对应程序 | 作用 |
|---|---| |---|---|---|
| `runtime/surfaces/surface-registry.ts` | 开发期 Surface Manifest 与本地启用注册表;仅精确 app id/version 可用。 | | MiniApp 清单契约 | `tauri/src/runtime/app-management/miniapp-manifest.ts` | 定义 `system | bundled`、工具、订阅、请求能力、Surface 和最低 Host 版本,并执行静态校验。 |
| `runtime/surfaces/surface-instance-manager.ts` | `open / ready / patch / close / restore` 的纯状态生命周期、幂等与冲突拒绝。 | | MiniApp SDK 接口 | `tauri/src/runtime/app-management/miniapp-sdk.ts` | 提供 MiniApp 自己的会话上下文、Inbox、工具进度/完成/失败/取消、生命周期、Surface 和能力请求。 |
| `runtime/surfaces/isolated-surface-host.ts` | opaque-origin iframe 宿主;`sandbox="allow-scripts"`、严格 CSP、仅受限 bridge。 | | SDK 兼容契约 | `tauri/src/runtime/app-management/golden/miniapp-sdk-v1.json` | 冻结 SDK v1 的关键字段和示例,供实现与回归测试对照。 |
| `runtime/surfaces/production-surface-manifest.ts` | 生产 Manifestimmutable artifact、版本、大小、SHA-256、Ed25519、key id、最小 Host、权限 allowlist。 | | MiniApp 工具注册 | `tauri/src/runtime/coordination/miniapp-tool-schema.ts``tool-router.ts` | 定义工具输入输出、目标 App、前台要求和调用路由。 |
| `runtime/surfaces/production-surface-policy.ts` | production admission policy:只允许已验证的精确 app/version 创建实例。 | | MiniApp 工具状态 | `tauri/src/runtime/coordination/miniapp-tool-state.ts` | 保存工具调用的状态、进度、完成、失败和取消结果。 |
| `runtime/surfaces/surface-bundle-cache.ts` | HTTPS 下载、Ed25519 验签、大小/SHA-256 校验、verified cache、失效与回滚。 |
| `runtime/inventory/client-inventory.ts` | 生成 revisioned `lineup.v1.client.inventory`。 |
| `runtime/capabilities/capability-registry.ts` | 能力声明、风险等级、可见性与参数 schema 校验。 |
| `runtime/capabilities/capability-call-state.ts` | 能力调用状态机:`pending → approved → executing → terminal`。 |
| `runtime/capabilities/capability-executor.ts` | 调用 Host handler,并将结果归约为安全确定的 `app.result`。 |
| `runtime/capabilities/capability-audit.ts` | 最小审计:call id、能力、风险、处置、时间;不保存敏感参数。 |
| `runtime/artifacts/artifact-state.ts` | Artifact 元数据状态:名称、MIME、大小、完整性。 |
| `runtime/artifacts/artifact-content-cache.ts` | Host-owned 易失内容缓存;内容不进入 Conversation Store。 |
## 5. Tauri Rust Host ## 六、Interact 系统级 App 模块
目录:`tauri/src-tauri/` Interact 是系统级核心 App,负责人与 Agent 的交互。当前实现以 IM 为主,未来可在同一系统级
交互 App 中扩展其他交互模式。标准 `notice``choice``confirm``input` 等交互,都是
Agent 在会话中向用户确认信息的交互记录,不是普通 MiniApp 的内部表单组件。
| 文件 | 功能 | | 中文模块名 | 对应程序 | 作用 |
|---|---| |---|---|---|
| `src/main.rs` | Tauri 桌面二进制入口。 | | Interact App 外壳 | `tauri/src/core-apps/chat/chat-app-host.ts``chat-shell.ts` | 装配系统级 Interact 的可信 DOM、样式、Renderer 和 SDK。当前目录仍使用 `chat` 兼容目录名。 |
| `src/lib.rs` | Tauri 应用构造与运行库入口。 | | Interact 模式管理 | `tauri/src/core-apps/chat/interaction-mode-registry.ts``interaction-runtime.ts` | 注册和切换 IM 等交互模式;当前默认模式为 `im`。 |
| `tauri.conf.json` | 窗口、应用元数据与构建配置。 | | 消息与交互卡片渲染 | `tauri/src/core-apps/chat/trusted-dom-renderers.ts``renderer-registry.ts` | 将 Runtime 已筛选的消息、Agent 状态、交互卡、任务、执行摘要、Surface、Capability 和 Artifact 渲染为可信 DOM。 |
| `capabilities/default.json` | Tauri 权限声明;当前只保留核心默认能力。 | | Interact 样式 | `tauri/src/core-apps/chat/styles/app.css``capability-card.css``execution-progress.css` | IM 页面、能力卡片和执行进度的视觉样式。 |
| `Info.plist` | macOS WebView / ATS 兼容配置。 | | 标准交互状态 | `tauri/src/runtime/coordination/standard-interaction-contract.ts``tool-call-state.ts` | 定义 Agent 提问、用户回答、过期、取消和关闭等状态;上下文中携带 IM 会话和 App 子会话标识。 |
| `build.rs` | Tauri/Rust 构建脚本入口。 | | 任务与执行展示状态 | `tauri/src/runtime/coordination/task-state.ts``execution-progress-state.ts` | 分别聚合 Agent 任务进度和 ACP 执行步骤,供 Interact 展示。 |
## 6. 客户端测试与构建 ## 七、普通 bundled MiniApp 模块
`src/runtime/**` 模块的 `.test.ts` 与实现同目录放置,主要覆盖 Runtime/SDK、协议与 这些 App 与其他 MiniApp 使用同一套 SDK 和受限 Surface,不是系统级 App。它们的内部编辑、按钮和表单
Kernel、Store/App Inbox、Tool Call、Task、执行摘要、Surface、Capability、Artifact、 操作不自动写入 IM;只有 Agent 通过 Tool 与它们交互时,才通过 Runtime 产生可追踪的工具调用。
生产 Bundle 与 golden fixture。
`runtime/coordination/lineup-runtime.test.ts` 覆盖 MVP-R1 的 Core App Registry、scope | 中文模块名 | 对应程序 | 作用 |
筛选、`lineup.v1` 兼容、App Inbox 恢复、去重和 Runtime Action 边界; |---|---|---|
`runtime/app-management/runtime-app-host.test.ts` 验证默认 Chat 由 Runtime Registry 加载。 | 任务面板 MiniApp | `tauri/src/core-apps/task-dashboard/task-dashboard-miniapp.ts` | 验证 MiniApp Inbox、工具进度/结果、任务创建和生命周期;Agent 可通过 `task-dashboard.open/update` 操作它。 |
| 任务面板测试 | `tauri/src/core-apps/task-dashboard/task-dashboard-miniapp.test.ts` | 验证任务面板遵守 MiniApp SDK 和工具调用边界。 |
| 白板 MiniApp | `tauri/src/core-apps/whiteboard/whiteboard-miniapp.ts` | 验证受限 Surface、内部状态编辑和 Artifact 导出;Agent 可通过 `whiteboard.open/submit` 操作它。 |
| 白板测试 | `tauri/src/core-apps/whiteboard/whiteboard-miniapp.test.ts` | 验证白板内部编辑不进入 IM transcript,导出时通过 Runtime 处理 Artifact 元数据。 |
| 参考 MiniApp 装配 | `tauri/src/runtime/app-management/reference-miniapps.ts``reference-miniapps.test.ts` | 注册和验证任务面板、白板等 bundled MiniApp 的 SDK 接入方式。 |
## 八、通信、协议与会话存储模块
这些模块是 Runtime 的内部基础设施,MiniApp 不得直接调用。
| 中文模块名 | 对应程序 | 作用 |
|---|---|---|
| AppServer 通信 | `tauri/src/runtime/communication/transport-adapter.ts` | 负责登录、发送、同步、超时处理和响应校验。 |
| 会话与消息存储 | `tauri/src/runtime/persistence/conversation-store.ts` | 保存会话、消息、cursor、outbox、App Inbox、工具/任务、摘要和 Surface/Capability 快照。 |
| Runtime v1 协议 | `tauri/src/runtime/protocol/lineup-v1.ts` | 定义和解析当前客户端兼容的 `lineup.v1` 消息及 JSON 类型。 |
| 协议黄金样例 | `tauri/src/runtime/protocol/golden/lineup-v1.json``golden-protocol.test.ts` | 固定兼容协议的样例,防止后续修改破坏 Agent 通信。 |
| Runtime 信封与作用域路由 | `tauri/src/runtime/coordination/runtime-envelope.ts``lineup-runtime.ts` | 确保消息只投递给对应的 Interact 会话或 MiniApp 子会话。 |
## 九、工具调用与标准能力模块
工具调用由 Agent 发起,但最终由 Runtime 校验、路由和记录;MiniApp 只能处理分配给自己实例的调用。
| 中文模块名 | 对应程序 | 作用 |
|---|---|---|
| 工具调用路由 | `tauri/src/runtime/coordination/tool-router.ts` | 根据工具描述和目标 App,将调用送到 Interact 或指定 MiniApp。 |
| 工具调用状态 | `tauri/src/runtime/coordination/tool-call-state.ts``miniapp-tool-state.ts` | 管理 pending、执行中、完成、失败、取消和过期等状态。 |
| 能力注册 | `tauri/src/runtime/capabilities/capability-registry.ts` | 声明能力、风险等级、可见性和参数 schema。 |
| 能力调用状态 | `tauri/src/runtime/capabilities/capability-call-state.ts` | 管理能力调用的确认、执行和最终状态。 |
| 能力执行器 | `tauri/src/runtime/capabilities/capability-executor.ts` | 调用经过授权的 Host handler,并把结果收敛为安全的 `app.result`。 |
| 能力审计 | `tauri/src/runtime/capabilities/capability-audit.ts` | 记录调用标识、能力、风险和处置,不保存敏感参数。 |
| 客户端清单 | `tauri/src/runtime/inventory/client-inventory.ts` | 生成带 revision 的客户端能力和工具清单,供 Agent 了解当前可用能力。 |
## 十、Surface、Artifact 与隔离模块
普通 bundled MiniApp 的界面运行在受限 Surface 中。Surface 是显示和交互边界,不等于 MiniApp 自己获得了系统权限。
| 中文模块名 | 对应程序 | 作用 |
|---|---|---|
| Surface 注册 | `tauri/src/runtime/surfaces/surface-registry.ts` | 保存开发期已知的 Surface Manifest,并按精确 App 标识和版本启用。 |
| Surface 实例生命周期 | `tauri/src/runtime/surfaces/surface-instance-manager.ts` | 管理 `open / ready / patch / close / restore`,处理幂等和冲突。 |
| 隔离 Surface 宿主 | `tauri/src/runtime/surfaces/isolated-surface-host.ts` | 使用 opaque-origin iframe、`sandbox="allow-scripts"`、严格 CSP 和受限 bridge。 |
| 生产 Surface 清单 | `tauri/src/runtime/surfaces/production-surface-manifest.ts` | 保存不可变资源、版本、大小、SHA-256、Ed25519、key id、最低 Host 和权限白名单。 |
| 生产准入策略 | `tauri/src/runtime/surfaces/production-surface-policy.ts` | 只允许已验证的精确 App/版本创建生产 Surface。 |
| Surface Bundle 缓存 | `tauri/src/runtime/surfaces/surface-bundle-cache.ts` | 下载、验签、大小和 SHA-256 校验、verified cache、失效与回滚。 |
| Artifact 元数据 | `tauri/src/runtime/artifacts/artifact-state.ts` | 保存 Artifact 名称、MIME、大小和完整性等元数据。 |
| Artifact 内容缓存 | `tauri/src/runtime/artifacts/artifact-content-cache.ts` | 保存由 Host 管理的短生命周期内容;具体内容不进入会话消息存储。 |
## 十一、自动化测试与契约样例
测试文件与被测模块放在同一目录,覆盖 Runtime、SDK、协议、应用生命周期和 Surface 安全边界。
| 中文测试范围 | 对应程序 | 验证内容 |
|---|---|---|
| Runtime 主流程 | `runtime/coordination/lineup-runtime.test.ts` | Core App 注册、作用域筛选、协议兼容、App Inbox 恢复、去重和 Runtime Action。 |
| App 生命周期 | `runtime/app-management/app-lifecycle-manager.test.ts``runtime-app-host.test.ts` | App 启动、前后台切换、关闭、恢复以及由 Registry 装载 App。 |
| MiniApp SDK 契约 | `miniapp-sdk-golden-contract.test.ts``golden/miniapp-sdk-v1.json` | SDK v1 字段、状态和 Golden Fixture。 |
| 参考 MiniApp | `reference-miniapps.test.ts``core-apps/task-dashboard/*.test.ts``core-apps/whiteboard/*.test.ts` | 任务面板和白板是否只通过 SDK、Tool 和 Surface 工作。 |
| 协议兼容 | `runtime/protocol/golden-protocol.test.ts``runtime/protocol/golden/lineup-v1.json` | `lineup.v1` 解码和兼容样例。 |
| 工具、任务和执行进度 | `runtime/coordination/*tool*.test.ts``task-state.test.ts``execution-progress-state.test.ts` | 工具调用路由、状态变化、任务聚合和执行步骤展示。 |
| 能力安全 | `runtime/capabilities/*test.ts` | 能力注册、确认、执行、失败和最小审计。 |
| Surface 与 Bundle 安全 | `runtime/surfaces/*test.ts` | 隔离宿主、实例生命周期、Manifest、验签、缓存和生产准入。 |
| 会话存储与恢复 | `runtime/persistence/conversation-store.test.ts` | 消息、cursor、outbox、Inbox 和工作区快照恢复。 |
常用命令:
```bash ```bash
cd lineup-app/tauri cd lineup-app/tauri
# Runtime / SDK / Renderer 自动化回归 # 自动化测试
npm test -- --run npm test -- --run
# TypeScript 检查 Web production build # TypeScript 检查 Web production build
npm run build npm run build
# Web Reference HostTailscale 开发) # Web Reference Host
npm run web:dev npm run web:dev
# Tauri Desktop Host # Tauri Desktop Host
npm run desktop:dev npm run desktop:dev
``` ```
当前验证基线:23 个测试文件、99 个测试通过,`npm run build` 通过 当前文档按源码盘点;测试数量、构建结果和真实浏览器验收结果应以最近一次迭代验收记录为准
## 7. 相关文档 ## 十二、相关文档
- [工作区 README](README.md):产品基线、MVP-R1、开发入口文档导航。 - [工作区 README](README.md):产品基线、开发入口文档导航。
- [迭代基线与目标](迭代/00.base/00.base.md)`00.base` 已实现内容和 `01.kernel` Runtime Kernel 目标 - [设计文档入口](设计/README.md):当前设计文档的分工和权威入口
- [APP 架构设计](APP架构设计.md)LineUp App、Runtime、MiniApp SDK、发布安全后续阶段 - [APP 架构设计](设计/APP架构设计.md)LineUp App、Runtime、MiniApp SDK、发布安全后续路线
- [Tauri/Web 源码导航](tauri/src/README.md)目录边界与依赖方向 - [Tauri/Web 源码导航](tauri/src/README.md)源码目录、依赖方向和新增模块规则
- [Tauri/Web Host README](tauri/README.md)Host 运行、构建、行为回归历史记录。 - [Tauri/Web Host README](tauri/README.md)Host 运行、构建、行为回归历史记录。
- [当前迭代](迭代/03.sdk_and_coreapp/03.sdk_and_coreapp.md)MiniApp SDK v1 和内置 MiniApp 的实现定义。
- [根程序文件清单](../程序文件清单与功能说明.md)AppServer、Hermes、WuKongIM 和运行配置。 - [根程序文件清单](../程序文件清单与功能说明.md)AppServer、Hermes、WuKongIM 和运行配置。
- [App 最终设计方案](../设计/02.正式方案/app_final_design.md):架构决策的唯一汇总入口。
+868
View File
@@ -0,0 +1,868 @@
# LineUp App 最终设计方案
**版本:** 1.0(当前开发基线)
**状态:** 当前 App 设计的唯一汇总入口
**日期:** 2026-08-06
**来源:** [App 层架构方案](lineup-app-layer-architecture.md)、[Runtime 与 App SDK 架构方案](lineup-runtime-sdk-architecture.md)、[UI Surface 与 App Capability 协议](lineup-ui-surface-protocol.md)
---
## 0. 一句话定义
**LineUp 是运行在用户设备上的协作 Runtime,也就是整个产品的本地协调中心。**
Runtime 负责连接 AppServer 和 Remote Agent,保存会话与消息,管理应用、工具、权限和
本地恢复。图文聊天、应用注册表、语音对话、画板和游戏则是在这个底座上运行的 App。
用户使用 App 完成操作,Agent 发来消息或请求;两边都先交给 Runtime 处理,因此任何 App
都不需要、也不能自己处理连接、登录态或系统权限。
```text
Remote Agent
│ 标准 LineUp 消息
AppServer / IM
┌─────────────────────────────────────────────────────────┐
│ LineUp Runtime │
│ │
│ 连接 · 会话 · 消息筛选 · App 管理 · Tool 管理 │
│ 权限 · Artifact · 存储 · Outbox · 恢复 · 审计 │
└─────────────┬───────────────────────────┬───────────────┘
│ Runtime SDK │ Host Provider
▼ ▼
Core / Installed App Tauri / OS
chat · app-registry 文件 · 麦克风
voice · whiteboard 通知 · 窗口
game · … 安全存储
```
## 1. 本方案的结论与优先级
本文件收敛正式方案目录下的三份已有文档,并在冲突处做出当前开发阶段的明确选择。
| 主题 | 最终决定 |
|---|---|
| App 的本体 | 整个产品是 `LineUpRuntime`;聊天不是 Runtime 本身。默认的 `Interaction App` 负责组织人与 Agent 的主交互,当前实现形态是 `chat`/图文 IM。 |
| 默认入口 | `Interaction App` 是当前默认和 Recovery App;当前默认模式是 `im`(代码兼容作用域仍为 `chat`),以后可切换到实时音频或视频模式。 |
| App 之间的关系 | App 只调用 Runtime SDK,不直接访问 AppServer、Agent、另一个 App 或 Tauri 特权 API。 |
| Agent 交互 | Agent 只与 Runtime 通信;Runtime 按会话和应用作用域筛选并投递给 App。 |
| 路由最小键 | 所有可路由消息必须有 `app_scope``conversation_id`;可选 `instance_id``operation_id``call_id`。 |
| App 生态阶段 | 当前只使用本地短作用域,如 `chat``whiteboard``draw-and-guess`;暂不引入供应商身份、反向域名 App ID 或全局命名空间。 |
| 丰富交互 | 标准内容先用可信内建组件;复杂互动用受限 Surface;设备/系统动作只能经 Capability Gateway。 |
| Agent 工具 | App 在 Manifest 声明方法,Runtime 汇总为动态 InventoryAgent 只能调用当前 Inventory 中的方法。 |
| Runtime SDK | SDK 提供状态订阅、Agent 消息订阅、Action、Tool、应用导航、Artifact、instance 级业务状态快照、Capability 和生命周期接口。业务状态由 Runtime 持久化和隔离,App 不直接拥有存储。 |
| Host | Tauri Desktop Host 与同代码的 Web Reference Host 是当前唯一实现/验收基线:前者是正式桌面外壳,后者是浏览器开发和验证入口;它们不是两个客户端。不规划独立 Android/Kotlin 客户端或 Wails Host。 |
本文件优先于来源文档中关于**后续 Runtime 重构**的结构描述。来源文档中的 M0~M4 完成记录、当前已实现字段和历史验收事实仍然有效;它们不自动成为新 Runtime 的长期模块边界。
## 2. 系统边界
### 2.1 Runtime、App 与 Host:先分清三者
这三个词经常同时出现,但职责不同:Runtime 是后台协调者,App 是用户看到的功能,Host
是让 Runtime 运行在桌面窗口或浏览器中的外壳。Host 不能绕过 Runtime 直接把系统能力
交给 App 或 Agent。
```text
Runtime
管理连接、状态、应用、工具、权限和副作用。
App
面向用户或 Agent 的功能单元;只能通过 SDK 与 Runtime 协作。
Host
提供操作系统或 WebView 能力;由 Runtime 使用,不直接暴露给 App/Agent。
```
| 主体 | 必须负责 | 明确不负责 |
|---|---|---|
| Runtime | 连接 AppServer/Agent、管理会话与路由、安排 App 生命周期、Tool、Capability、持久化和审计 | 具体页面 DOM、任意 App 的业务 UI。 |
| Chat App | 图文会话、时间线、输入、任务/交互卡片和 Artifact 基础展示 | `fetch` AppServer、同步 cursor、Agent 原始包解析、文件系统。 |
| App Registry App | 让用户查看已安装 App,并请求安装/启用/禁用/移除或选择默认入口 | 直接写 Registry、删除 Bundle、绕过验签。 |
| Installed App | 自己的交互体验、已声明 Tool、已声明事件和私有状态 | Tauri `invoke`、Host DOM、token、任意网络和其他 App 数据。 |
| Tauri Host Provider | 在 Runtime 授权后实现文件、音频、通知、窗口和安全存储等系统操作 | 协议解释、应用策略和 Agent 路由。 |
### 2.2 关键禁止项
```text
App → AppServer / Agent 直接网络连接 禁止
App → 直接构造并发送未校验 Agent Envelope 禁止
Surface → Tauri invoke / 父页面 DOM / 登录态 禁止
Agent → 任意 App JavaScript 函数或 Host 特权 API 禁止
Agent → 静默安装、启用、禁用或移除 App 禁止
Surface Event → 直接执行系统能力 禁止
```
## 3. Runtime 的内部模型
### 3.1 三类输入输出
Runtime 采用 Event / Command / Effect 分层。
```text
Event:已经发生的事实
Agent 文本、任务进度、用户点击、画板变更、录音完成、连接断开。
Command:希望 Runtime 处理的动作
发送消息、调用 Tool、启动 App、启用 App、请求保存文件。
EffectRuntime 决定执行的副作用
网络发送、文件选择、录音、通知、创建 Surface、写存储。
```
处理顺序固定为:
```text
接收 Event / Command
→ 验证与授权
→ 更新 Runtime State
→ 持久化事实 / Outbox
→ 产生 Effect
→ Effect 结果重新进入 Runtime,成为 Event
→ 生成面向 App 的状态投影或消息投递
```
第一版采用“事件驱动状态机 + 必要快照”,不实施完整 Event Sourcing。关键入站事件、用户决定、Tool 终态、outbox 和审计需持久化;纯渲染细节、焦点和滚动位置不必写入 Runtime 事实日志。
### 3.2 顶层状态
```text
identity
用户、设备、认证会话。
connection
AppServer 连接、sync cursor、重试、实时状态、outbox。
conversations
conversation、关联 Agent、消息引用、任务、交互、Artifact 元数据。
apps
App Registry、默认 App、运行实例、每个 App 的可靠 Inbox 与按 instance 隔离的业务状态快照。
tools
Tool 声明、Inventory revision、调用记录、operation 与进度。
capabilities
权限请求、用户决定、系统权限、执行状态与最小审计。
```
### 3.3 Runtime 生命周期
```text
created
→ restoring
→ authenticating
→ synchronizing
→ online
↘ reconnecting / offline_degraded
→ stopping
→ stopped
```
启动时 Runtime 必须恢复 App Registry、默认入口、cursor、outbox、App Inbox、未完成 Tool 和可恢复实例。追平服务器历史后才开始正常实时投递;离线时可接受的用户/App Action 进入 outbox,重连后以幂等键和顺序发送。
## 4. 应用模型
### 4.1 本地应用作用域
当前阶段使用 Runtime 本地注册的 `app_scope`,而不是全球 App 身份:
```text
chat
app-registry
settings
voice
whiteboard
draw-and-guess
runtime
```
`app_scope` 的职责仅是本机启动、消息路由、Tool 路由、存储隔离和实例归属。它不是供应商身份,不要求跨市场唯一,也不承担开放生态的所有权模型。
未来如需市场、多供应商和跨设备分发,可以在 Manifest 中增加稳定身份映射;但不能改变本方案中的 `app_scope + conversation_id` 路由与隔离语义。
### 4.2 应用类型
| 类型 | 典型项 | 来源与执行方式 | 管理规则 |
|---|---|---|---|
| Core App | `chat``app-registry``settings` | 跟随 Runtime 发行的可信代码 | 不可由市场 Bundle 覆盖;`chat` 不可移除。 |
| Installed App | `voice``whiteboard``draw-and-guess` | 经 Runtime 验证的 Bundle,在受限 Surface 中运行 | 可安装、启用、禁用、更新、回滚、移除。 |
| Capability | 录音、选文件、保存、通知 | Tauri/OS 经 Runtime Host Provider 提供 | 不是 App,也不是自动授予的权限。 |
### 4.3 App Registry 与默认入口
Runtime App Manager 是安装和状态的唯一事实源:
```ts
type AppRecord = {
app_scope: AppScope;
kind: "core" | "installed";
installed_version: string;
previous_version?: string;
enabled: boolean;
install_state: "installed" | "updating" | "failed";
active_instance_count: number;
installed_at: string;
enabled_at?: string;
};
interface RuntimeAppManager {
listApps(filter?: AppListFilter): readonly AppRecord[];
getApp(appScope: AppScope): AppRecord | undefined;
install(request: InstallAppRequest): Promise<AppOperation>;
enable(appScope: AppScope): Promise<AppOperation>;
disable(appScope: AppScope, options?: DisableAppOptions): Promise<AppOperation>;
update(appScope: AppScope, targetVersion?: string): Promise<AppOperation>;
rollback(appScope: AppScope): Promise<AppOperation>;
remove(appScope: AppScope, options?: RemoveAppOptions): Promise<AppOperation>;
launch(request: LaunchAppRequest): Promise<AppInstanceHandle>;
closeInstance(instanceID: AppInstanceID): Promise<void>;
}
```
App Registry App 只调用上述接口,不直接管理 Bundle 文件。安装、验证、启用、升级和移除是异步操作,必须有可观察的 `AppOperation`
Runtime Shell 始终独立于上层 App,负责应用切换、全局连接状态、通知和安全恢复。其启动目标优先级:
```text
显式目标(深链接 / 通知)
→ 可安全恢复的前台实例
→ 用户设定的 Default App
→ chat Recovery App
```
`chat` 是当前图文 IM 主入口,也是不可移除的 Recovery App。未来用户可将 `voice` 设为默认入口;这只改变主要交互方式,不改变会话、Agent、outbox 或 Artifact 的归属。
### 4.4 App 实例生命周期
```text
not_running → launching → active → backgrounded → suspended
↘ restoring → active
active / suspended → closing → closed
↘ failed
```
- Chat 与 App Registry 默认是单一全局实例;
- 工具型 App 默认按 `conversation_id` 创建实例,可用 `instance_id` 区分同会话的多个实例;
- 禁用阻止新调用并收口现有实例;移除在实例关闭且用户确认后清理 Bundle/私有数据;
- Surface 被回收时 App 通过 Runtime snapshot 恢复,不能重复发送先前的用户事件。
### 4.5 Runtime 编排、Interact 与扩展 App
`Interaction App` 是默认的人与 Agent 交互应用,但它不是整个 App 生态的调度器。应用
启动、Tool 路由、前后台焦点、实例生命周期和恢复均由 Runtime 管理;Interact 只负责
当前主会话的交互体验,以及把扩展 App 的结果投影回会话。
```text
LineUp Runtime
├── App Registry / App Instance Manager
├── Tool Router / App Router
├── Focus Manager / Lifecycle Manager
└── Conversation / Store / Outbox
├── Interaction AppCore App
│ ├── IM mode:文字、图片、短消息
│ ├── Audio mode:实时语音
│ ├── Video mode:实时视频
│ └── 标准交互原语:choice / confirm / input
└── Installed App
├── whiteboard
├── draw-and-guess
└── task-dashboard
```
Runtime 的职责是判断一个 Agent 请求应由哪个应用实例、交互模式或标准组件承接;Interact
不直接执行任意 Tool,也不负责切换其他 App 的前台状态。它通过 SDK 接收 Runtime 已经
校验过的交互事件,并提交声明性用户 Action。
应用焦点是 Runtime 状态的一部分:
```text
interaction:audio-001 running / foreground
↓ Agent 请求启动 draw-and-guess
interaction:audio-001 background 或 suspended
draw-and-guess:game-001 starting → running / foreground
```
原来的实例不会因为切换前台就被删除。Runtime 保存焦点栈和实例状态,以便游戏结束、用户
退出或新应用失败时恢复原来的 Interaction App 和会话模式。
一次“启动你画我猜”的完整流程是:
```text
Agent launch(draw-and-guess)
→ Runtime 校验 Envelope、Inventory、Manifest、参数和 App 状态
→ 创建 draw-and-guess App Instance
→ 保存当前 Interaction App/Audio Instance 的焦点位置
→ 将旧实例切换为 background / suspended
→ 将新实例切换为 foreground
→ App 通过 SDK 创建自己的 Surface 并接收用户操作
→ 结果经 Runtime 持久化、审计并回传 Agent
→ 游戏结束或关闭后恢复焦点栈中的 Interaction App
```
标准选择框、确认框和输入框属于 Interaction App 的内建交互原语,不需要作为独立安装包;
画板、游戏和复杂任务面板属于可安装扩展 App,与 Interaction App 是 Runtime 上的平级应用。
因此,Runtime 负责“能否调用、调用到哪里、哪个实例在前台以及如何恢复”;Interact 负责
“如何在主交互体验中呈现和协调结果”;扩展 App 负责“具体功能和自己的交互界面”。
## 5. 消息、筛选与实时订阅
### 5.1 统一路由 Envelope
所有 Agent、Runtime、App、User 与 Host 之间的可路由消息都必须带作用域:
```ts
type RuntimeEnvelope = {
v: 1;
id: string;
type: string;
timestamp: string;
sender: {
kind: "agent" | "runtime" | "app" | "user" | "host";
id: string;
};
target: {
kind: "runtime" | "app";
app_scope: AppScope;
instance_id?: AppInstanceID;
};
scope: {
app_scope: AppScope;
conversation_id: ConversationID;
instance_id?: AppInstanceID;
operation_id?: OperationID;
};
correlation?: {
reply_to?: string;
call_id?: ToolCallID;
inventory_revision?: string;
sequence?: number;
};
payload: JsonValue;
};
```
全局 Runtime 事件同样保留作用域:
```text
target.app_scope = runtime
scope.app_scope = runtime
conversation_id = runtime:global
```
### 5.2 现有协议兼容
当前 Tauri 实现与 M0M4 golden fixture 使用 `lineup.v1.*` 类型,以及 Surface payload 内的旧 `app.id` 字段。这些是**当前实现兼容事实**,不能在没有版本迁移和 golden fixture 的情况下直接删除。
Runtime 重构的规则是:
```text
旧 LineUp v1 Envelope
→ Runtime Compatibility Adapter
→ 补齐/映射 app_scope、conversation_id、instance_id
→ RuntimeEnvelope
→ App SDK
```
新的 Runtime/App SDK 边界不得再依赖旧 `app.id` 的供应商命名语义。R0 负责冻结新旧字段的映射表、拒绝规则和双向 fixture;在映射完成前,旧协议继续只由 Runtime 适配层处理,App 永远不直接读取它。
### 5.3 Runtime 筛选链
```text
Transport 原始输入
→ 版本、type、app_scope/conversation_id、大小、schema 校验
→ Agent 身份与会话关联校验
→ id / sequence / cursor 去重与顺序处理
→ App 安装、启用、版本、Host 兼容性校验
→ Tool / Capability、Inventory、参数、策略、App 启动和前台条件校验
→ conversation / instance / operation 所属关系校验
→ Manifest 订阅声明与 SDK 订阅条件求交
→ Runtime Event / App Inbox / cursor 持久化
→ 向目标 App SDK 投递标准化消息
```
Runtime 不广播原始 Agent 消息。相同 conversation 下,Chat 和 Voice 可以收到经 Runtime 投影的 Agent status;白板只收到本实例声明的 patch、Tool 调用和 lifecycle 事件,除非其 Manifest 明确申请并获准其他订阅。
### 5.4 App SDK 的实时 Agent 消息能力
SDK 同时提供实时订阅和可靠 Inbox 补读:
```ts
interface AgentMessageAPI {
list(request?: {
conversation_id?: ConversationID;
after?: AgentMessageCursor;
limit?: number;
}): Promise<AgentMessagePage>;
subscribe(
options: {
conversation_id?: ConversationID;
types?: readonly AgentMessageType[];
include_pending?: boolean;
},
handler: (message: AgentAppMessage) => Promise<void> | void,
): Unsubscribe;
acknowledge(message_id: string): Promise<void>;
}
```
投递语义:
1. Runtime 先校验、标准化和持久化,后调用订阅者;
2. 每条消息有唯一 `message_id`App 必须幂等处理;
3. 展示类消息可自动 ACK;Tool 调用、状态 patch 和需业务处理的消息要求 App 显式 ACK;
4. App 未运行、暂停或崩溃时,消息进入该 App 的 Inbox;恢复后 `list()``subscribe()` 补齐;
5. App 禁用、移除或不兼容时,Runtime 对关键 Agent 调用返回确定拒绝,不能静默丢弃。
实际投递集是:
```text
Manifest agent_subscriptions
∩ SDK subscribe filter
∩ App 当前权限
∩ conversation / instance scope
∩ Agent target app_scope
∩ Runtime Policy
```
## 6. Runtime SDK v1
SDK 是上层 App 使用 Runtime 的唯一标准入口。Core App 拿到完整 App SDKInstalled App 只得到同一语义的受限 Surface Bridge SDK。
```ts
interface LineUpAppRuntimeSDK {
readonly app: AppContext;
readonly lifecycle: AppLifecycleAPI;
readonly state: AppStateAPI;
readonly agentMessages: AgentMessageAPI;
readonly actions: AppActionAPI;
readonly tools: AppToolAPI;
readonly apps: AppNavigationAPI;
readonly artifacts: ArtifactAPI;
readonly instanceState: MiniAppInstanceStateAPI;
readonly capabilities: CapabilityRequestAPI;
readonly diagnostics: DiagnosticsAPI;
}
```
### 6.1 Context、状态和生命周期
```ts
interface AppContext {
app_scope: AppScope;
app_version: string;
instance_id: AppInstanceID;
kind: "core" | "installed";
entrypoint: string;
scope: {
conversation_id?: ConversationID;
operation_id?: OperationID;
parent_instance_id?: AppInstanceID;
};
granted_permissions: readonly AppPermission[];
}
interface AppStateAPI<ViewModel = unknown> {
snapshot(): ViewModel;
subscribe(listener: (view: ViewModel, change: AppStateChange) => void): Unsubscribe;
}
```
App 只读取按其 Scope 裁剪的 View Model,不读取全量 Runtime State。生命周期包含 `start``foreground``background``suspend``restore``closing`;Runtime 保留禁用、移除和强制收口的最终权力。
### 6.2 Action、Tool 与跨 App 导航
```ts
interface AppActionAPI {
dispatch(action: AppAction): Promise<CommandReceipt>;
}
interface AppToolAPI {
onInvoke(listener: (call: AppToolInvocation) => Promise<AppToolOutcome>): Unsubscribe;
progress(request: { call_id: ToolCallID; progress: ToolProgress }): Promise<void>;
complete(request: { call_id: ToolCallID; result: JsonValue }): Promise<void>;
fail(request: { call_id: ToolCallID; code: AppToolErrorCode; message?: string }): Promise<void>;
}
interface AppNavigationAPI {
listAvailable(): readonly AppSummary[];
launch(request: LaunchAppRequest): Promise<AppInstanceHandle>;
focus(instanceID: AppInstanceID): Promise<void>;
close(instanceID: AppInstanceID): Promise<void>;
openDefaultApp(): Promise<void>;
}
```
App 只能提交声明性 Action,不能构造原始 Agent Envelope。跨 App 打开、聚焦和关闭也必须经 Runtime 校验目标 App 的启用状态、入口、展示模式和会话作用域。
### 6.3 MiniApp instance 业务状态、Artifact 与 Capability
Runtime 为每个 MiniApp instance 提供一份受限的业务状态快照。MiniApp 定义状态的业务语义和
Manifest schemaRuntime 是持久化、隔离、并发裁决、恢复和清理的唯一所有者。它不是供 App 任意
查询或读写的数据库,也不等同于 Conversation Store、Tool/operation Store、outbox 或 Artifact Store。
```ts
interface MiniAppInstanceStateAPI<State extends JsonObject = JsonObject> {
get(): Promise<{
state: State | null;
revision: number;
}>;
replace(request: {
state: State;
expected_revision: number;
}): Promise<{
revision: number;
}>;
}
```
每次调用的存储边界由不可伪造的 SDK context 推导:
```text
app_scope + instance_id
```
App 不得指定、读取或写入其他 App、其他 instance、Conversation Store 或 Runtime 内部记录。Runtime
必须校验 Manifest 声明的 `state_schema``state_schema_version`、大小配额与 `expected_revision`;旧
Surface、重复点击或并发写入不能覆盖较新的快照。刷新、Surface 重载和 Runtime 重启后,Runtime 向
同一个可恢复 instance 投影最后一个有效快照。实例关闭、App 禁用/移除时,Runtime 按 Manifest 的
retention policy 冻结、保留或清理快照,MiniApp 本身无权绕过生命周期复活旧状态。
第一版的 `retention` 只允许 `delete_on_close`(默认,关闭时删除)和 `retain_readonly`(关闭后
保留为历史/新 instance 的受控上下文,但旧 instance 不可再写入)。App 禁用或移除时,Runtime 仍按
用户确认和全局保留策略清理其快照;状态 schema 升级由新 App 版本通过受控读取/替换完成,Runtime 不执行
任意 App 提供的迁移脚本。
业务状态快照不替代 Runtime operation。凡是会影响 Agent Tool 终态、deadline、outbox、焦点、权限或
实例生命周期的动作,仍必须通过 Runtime Command / operation 原子裁决。例如 Pomodoro 的显示状态
可以保存在自己的 instance snapshot,但 `ends_at` 到期、用户中断与唯一 Tool result 必须由 Runtime
的 deadline operation 负责,不能由 MiniApp 自行完成或直接发送结果。
```text
Artifact
Runtime 管理元数据、受限读取、创建、会话引用、下载和用户保存。
Instance State
Runtime 为每个 app_scope + instance_id 提供隔离的 JSON snapshot;管理 schema、revision、配额、
恢复与生命周期清理。UI 动画、滚动位置等短暂渲染状态不必持久化。
Capability
App 以 purpose + input 请求;Runtime 决定是否确认、调用 Host、审计并返回受控结果。
```
Capability SDK 形状:
```ts
interface CapabilityRequestAPI {
request<T extends JsonValue>(request: {
capability: CapabilityName;
purpose: string;
input: JsonValue;
scope?: AppScope;
}): Promise<CapabilityResult<T>>;
}
```
Runtime 必须检查:Manifest 声明、App 启用状态、Host 支持、前台要求、用户确认、系统权限、策略、速率限制和审计。结果只能是 `completed``cancelled_by_user``permission_denied``unsupported_on_host``policy_denied``expired` 或受控 `failed`,不暴露路径、token 或底层原生异常。
## 7. Tool、Inventory 与 Agent 调用
### 7.1 App Tool 声明
每个 App 可以声明 Agent 可调用 Tool。当前的完整定位是:
```text
app_scope / method / contract_version
whiteboard / board.create / 1
voice / voice.request_recording / 1
draw-and-guess / game.start_round / 1
```
Tool Manifest 至少包括:标题、面向 Agent 的说明、输入/输出 JSON Schema、调用模型、超时、幂等性、前台要求、风险等级、App 启动策略和可能使用的 Capability。
调用模型固定为:
| 模型 | 用途 | 示例 |
|---|---|---|
| `query` | 只读、快速 | 查询画板摘要。 |
| `command` | 确定性状态改变 | 创建白板、开始一局游戏。 |
| `interactive` | 必须等待用户参与 | 录音、填写复杂表单。 |
| `operation` | 长时间执行并有进度 | 导出画板、处理大文件。 |
### 7.2 动态 Runtime Inventory
Runtime 向每个活跃 Agent 会话发布 revisioned Inventory。它包含当前可用的标准组件、已启用 App、Surface、Tool 和 Capability;它不是安装命令,也不携带 Bundle 源码、token、文件路径或用户私有内容。
```text
Agent 可见 Tool
= 已验证 Manifest Tool
∩ App enabled
∩ Host supported
∩ 用户 / 组织策略允许
∩ Agent + conversation scope 允许
∩ 所需前置条件满足
```
App 启用、禁用、更新、撤销、Host 能力变化或策略收紧后,Runtime 增加 revision 并重新发布。Agent 的 Tool 调用必须携带 `inventory_revision`;旧 revision 的调用必须安全拒绝并提示 Agent 刷新清单。
### 7.3 Tool 调用闭环
```text
Agent tool.invoke
→ Runtime 校验 Envelope / Inventory / Tool / 参数 / Scope
→ Tool Router 判断直接执行、启动 App、切换前台或等待用户交互
→ App Instance / Focus Manager 创建或切换实例
→ Interaction App、交互模式或扩展 App 承接请求
→ App SDK 发送 progress / result / error
→ Runtime 校验输出、持久化、更新焦点并回传 Agent
```
至少支持以下确定错误码:
```text
cancelled_by_user permission_denied app_disabled
app_not_installed app_version_mismatch tool_not_visible
invalid_arguments foreground_required operation_expired
handler_failed
```
Tool 是 App 的业务方法;Capability 是 Runtime/Host 的系统能力。Tool 可请求 Capability,但不会因声明 Tool 自动获得麦克风、文件或剪贴板权限。
## 8. Surface 与安全边界
### 8.1 标准组件优先
文字、Markdown、图片、链接、状态、任务进度、choice、confirm、input、Artifact 基础预览优先采用 Runtime / Core App 的可信内建渲染器。它们必须可访问、可测试、可离线恢复,并保持 Markdown sanitizer、外链保护和严格 schema。
Surface 仅用于画板、地图、图表、复杂表单、游戏、专业编辑器等内建组件不足以表达的复杂交互。
### 8.2 Installed App Surface
下载型 App 运行在隔离容器中:
```text
iframe sandbox="allow-scripts"
- 不带 allow-same-origin
- 不带 allow-popups / allow-top-navigation / allow-forms
- 默认 CSP 禁止网络和外部脚本
- 只经严格 postMessage / Surface Bridge SDK 通信
```
Runtime/Host 必须验证 `event.source`、当前 `instance_id`、消息类型、事件名、JSON schema、消息大小和声明的投递策略。Surface 只能接收 state patch、触发已声明事件、处理已声明 Tool 调用、通过 Bridge 使用 Runtime 提供的自身 instance 状态快照和请求受控 Capability。
Surface 不能:
```text
读取父页面 DOM、localStorage 或 token
调用 Tauri invoke
访问其他 App 的数据和实例
直接访问 Agent / AppServer
任意联网、导航、弹窗或加载远端脚本
直接执行 app.call / 系统能力
```
用户在 Surface 中的操作只是 App Event;需要系统副作用时,Runtime 仍按 Capability 规则确认、执行和审计。
### 8.3 Bundle 与发布
当前已验证的生产安全原则保持不变:Bundle 必须是不可变 artifact,执行前检查来源、大小、SHA-256、签名、Host 兼容性和回滚条件;验证失败不得进入 active cache。开发期 inline bundle 只能是受限开发 fixture,不是长期市场供应方式。
本阶段仅定义本地 `app_scope`,不定义开放市场发布者身份。Bundle 信任、App 管理和 Tool 可见性仍必须由 Runtime 控制;将来引入供应商身份时须以新 Manifest 版本扩展,不能放宽本节隔离规则。
## 9. App Manifest 最小契约
```json
{
"format": "lineup.app.v1",
"app_scope": "whiteboard",
"version": "1.0.0",
"runtime_sdk": {
"api_version": "1",
"required_features": [
"app.lifecycle.v1",
"app.tools.v1",
"surface.state.v1",
"app.instance-state.v1"
],
"optional_features": ["artifact.create.v1"]
},
"entrypoints": [
{"id": "canvas", "kind": "contextual", "default_eligible": false}
],
"instance_state": {
"state_schema_version": 1,
"state_schema": {"type": "object", "additionalProperties": false},
"max_bytes": 65536,
"retention": "delete_on_close"
},
"agent_subscriptions": [
{"type": "lineup.app.state.patch", "scope": "instance"},
{"type": "lineup.tool.invoke", "scope": "conversation"}
],
"tools": [
{
"method": "board.create",
"contract_version": "1",
"invocation": {"kind": "command", "activation": "launch_if_needed"},
"input_schema": {"type": "object", "additionalProperties": false},
"output_schema": {"type": "object", "additionalProperties": false}
}
]
}
```
Runtime 在安装、启用和启动时验证 SDK API 版本与 feature 集;App 不兼容、未启用或当前 Host 不支持时,不得进入 Inventory、创建实例或接收 Tool 调用。
## 10. Tauri 参考实现的最终模块边界
```text
lineup-app/
├── runtime-core/
│ ├── communication/ AppServer transport、sync、outbox
│ ├── coordination/ event、state、router、policy、audit
│ ├── apps/ app registry、instance manager、default app
│ ├── tools/ tool registry、inventory、call lifecycle
│ ├── capabilities/ capability gateway
│ └── persistence/ runtime store、app inbox、instance state snapshot、artifact metadata
├── runtime-sdk/
│ ├── app.ts Core App SDK
│ ├── manifest.ts App/Tool/Subscription 类型
│ ├── protocol.ts RuntimeEnvelope / schema
│ ├── errors.ts 稳定错误码
│ └── testkit/
├── surface-sdk/
│ ├── bridge.ts sandbox message bridge
│ └── surface.ts Installed App 最小 SDK
└── tauri/
├── src/
│ ├── bootstrap/ 应用启动装配层
│ ├── runtime-host/ Web/Tauri Host Provider adapter
│ ├── shell/ switcher、default、recovery
│ └── core-apps/ chat、app-registry、settings
└── src-tauri/ Rust 文件、音频、通知、窗口 Provider
```
`lineup-app/tauri/src/main.ts` 是当前 Tauri/Web Host 的启动装配入口:它创建 Host 侧适配、
`LineUpRuntime` 与默认 Runtime App Host,并把它们接起来。它不创建或持有 Transport、
Store、sync loop、outbox,也不解析原始 Agent payload。现阶段仍有可信 Renderer、Surface
与 Capability 的 Host 集成代码;后续可以继续迁移这些 UI 适配,但不得把 Runtime 所有权
重新放回 `main.ts`
可直接迁移的现有基础:
| 当前模块 | 最终归属 |
|---|---|
| `transport-adapter.ts` | `runtime-core/communication/` |
| `conversation-store.ts` | `runtime-core/persistence/` |
| `interaction-kernel.ts` | `runtime-core/coordination/` 的协议入口/兼容适配基础 |
| Tool/Task/Execution 状态机 | Chat App 的投影 + Runtime call state |
| `surface-registry.ts` | `runtime-core/apps/` 的 App Registry 基础 |
| `surface-instance-manager.ts` | `runtime-core/apps/` 的 Instance Manager 基础 |
| Bundle manifest/cache/policy | `runtime-core/apps/` 与 Execution Plane |
| `client-inventory.ts` | `runtime-core/tools/` 的动态 Inventory Publisher |
| `capability-*` | `runtime-core/capabilities/` |
| `trusted-dom-renderers.ts` | `tauri/src/core-apps/chat/` |
## 11. 实施顺序
### F0:冻结契约与兼容映射
- 定义 `RuntimeEnvelope``app_scope``conversation_id``instance_id``operation_id``call_id` 的类型和校验;
- 定义旧 `lineup.v1.*` 到 RuntimeEnvelope 的兼容映射;
- 定义 Runtime SDK v1、Surface Bridge SDK v1、App Manifest、Tool Descriptor 和错误码;
- 为全部契约建立 golden fixture;不改变当前可验证的 M0~M4 行为。
### F1Runtime Core 与 Interaction Core App(当前 `chat` 实现)
-`main.ts` 提取单一 `LineUpRuntime`
- Runtime 独占 Transport、Store、outbox、原始消息校验和筛选;
- 将当前图文 IM 迁为 Interaction Core App 的 `chat` 实现;
- 当前 `chat``state.subscribe()``agentMessages.subscribe()` 获取已验证投影,不再依赖 Transport;
- 保持登录、同步、本地回显、Markdown、Tool Call、Task、Artifact 的回归行为。
#### MVP-R1 实施状态(2026-08-04
F0 与 F1 中支撑图文聊天迁移的最小闭环已落地并经自动化回归验证。此处的“完成”仅指下列 MVP 边界;Manifest、Installed App、完整 Tool Inventory 和应用市场仍属于后续阶段。
| MVP 项 | 当前实现 | 验证位置 |
|---|---|---|
| Runtime 单一所有权 | `LineUpRuntime` 唯一创建并持有 `TransportAdapter``ConversationStore``InteractionKernel`、同步循环与 outbox。 | `tauri/src/runtime/coordination/lineup-runtime.ts``lineup-runtime.test.ts` |
| Core App 入口 | `CoreAppRegistry` 记录当前可作为默认入口的 Core App;`CoreAppHostRegistry` 再根据 `app_scope` 找到对应的可信装配器。当前默认实现仍是 `chat`,但 `main.ts` 不再直接依赖 Chat 内部 Renderer 和 Shell。 | `runtime/app-management/app-registry.ts``runtime-app-host.ts``core-apps/chat/chat-app-host.ts``runtime-app-host.test.ts` |
| Chat SDK 边界 | Chat 仅以 `ChatRuntimeSDK` 订阅状态/Agent 消息、读取 Inbox、ACK,并以 Runtime Action 发送文本或交互动作。 | `runtime/app-management/app-sdk.ts``main.ts` |
| 作用域与旧协议兼容 | 入站消息先经 `resolveIncomingScope`;旧 `lineup.v1` 自动映射为当前会话的 `chat` 作用域,显式非法或不匹配的 scope 在投递前拒绝。 | `runtime/coordination/runtime-envelope.ts``lineup-runtime.test.ts` |
| 恢复与幂等 | `ConversationStore` 持久化 App Inbox;未 ACK 消息在 Runtime 重建后恢复,同一 `message_id` 不重复投递。 | `runtime/persistence/conversation-store.ts``conversation-store.test.ts``lineup-runtime.test.ts` |
本阶段不修改 AppServer 或 Hermes 的既有 `lineup.v1` 协议。兼容层只存在于 Runtime 内部,因此上层 Chat App 不读取旧协议字段,也不需要同步升级远端。
### F2App Registry 与默认 App
- 将开发期 Surface Registry 迁为 Runtime App Registry
- 实现 App Instance Manager、App Focus Manager 和生命周期状态(foreground/background/suspended);
- 实现 Runtime Tool Router / App Orchestrator:校验 Tool 后决定直接执行、启动 App、切换前台或等待用户交互;
- 实现 App 启用、禁用、移除、版本记录、实例收口和默认入口选择;
- 实现 `app-registry` Core App
- 将当前 `chat` 作为 Interaction App 的 IM 实现,为后续 Audio/Video 模式预留 entrypoint 和恢复策略。
### F3Tool Registry、Inventory 与 SDK Inbox
- 解析 Manifest Tool/Subscription 并计算可见性;
- 在 Runtime 连接与状态变化时同步 revisioned Inventory 给 AgentTool 可声明是否需要启动 App、是否要求前台以及结束后是否恢复原焦点;
- 实现 Agent Tool → Runtime → App SDK → result/progress 的可靠闭环;
- 将 MVP-R1 已实现的 Chat App Inbox、ACK、断线/崩溃恢复和拒绝码推广为所有受管理 App 的通用可靠投递机制。
- 实现 `app.instance-state.v1`:按 `app_scope + instance_id` 隔离的 schema 校验状态快照、revision
并发控制、配额、重启恢复与 lifecycle 清理;它不得替代 Tool/operation/outbox 的终态裁决。
### F4:第一个 Installed App
- 选择画板或任务面板作为第一个完整 Installed App
- 验收 install → enable → Inventory → Tool 调用 → App 启动/前台切换 → Surface 事件 → Agent result → 原前台恢复 → disable/remove
- 语音/视频属于 Interaction App 的模式或受 Runtime 管理的扩展 App,必须复用 Runtime SDK、Tool、Artifact 和 Capability 通道,不建立独立 Agent 通信链路。
## 12. 完成准入条件
```text
消息与隔离
[ ] 缺少/非法 app_scope 或 conversation_id 的可路由消息被拒绝。
[ ] App 不能收到其他 App 或其他 conversation 的 Agent 原始消息。
[ ] App 未运行时关键消息可从 Inbox 有界恢复,重复投递不重复执行。
应用管理
[ ] 启用/禁用/移除改变 Tool 可见性,并更新 Agent Inventory revision。
[ ] 默认 App 失效时必定回退至 Interaction App 的 IM/`chat` Recovery 入口。
[ ] 禁用/移除能收口活动实例、焦点栈、调用和私有数据清理流程。
[ ] Agent 启动扩展 App 时,Runtime 能将当前前台实例切换到后台,并在扩展结束后恢复原焦点。
工具与能力
[ ] Agent 只能调用当前 Inventory 中、参数 schema 合法的 Tool。
[ ] Tool 的 result/progress/error 经 Runtime 校验、持久化和审计。
[ ] MiniApp 只能读取和替换自身 instance 的 schema 合法状态快照;旧 revision、越界 instance、超配额
和非法 schema 均被 Runtime 拒绝,刷新/重启后仅恢复最后一个有效版本。
[ ] 业务状态快照不能直接完成 Tool、写 outbox、改变焦点或绕过实例生命周期。
[ ] App / Surface 无法绕过 Capability Gateway 获得系统权限。
安全
[ ] Installed App 无法访问 Tauri invoke、Host DOM、token、任意网络或其他 App 数据。
[ ] Bundle 只有在完整性和签名验证后才可运行;失败可回滚且不污染 active cache。
```
## 13. 旧文档的后续定位
| 文档 | 保留价值 | 在本方案后的定位 |
|---|---|---|
| [App 层架构方案](lineup-app-layer-architecture.md) | M0~M4 已实现边界、测试和验收事实;Markdown、Surface、Capability 原则 | 迁移基础与历史实施记录。 |
| [Runtime 与 App SDK 架构方案](lineup-runtime-sdk-architecture.md) | Runtime、App Manager、Tool Registry、SDK、消息筛选的完整初稿 | 被本文件收敛后的详细来源;以本文件的 `app_scope` 和实施顺序为准。 |
| [UI Surface 与 App Capability 协议](lineup-ui-surface-protocol.md) | Surface sandbox、bridge、Capability 风险分级、inventory 和 Bundle 安全规则 | 协议细节来源;R0 需完成其旧字段到 RuntimeEnvelope 的版本化映射。 |
以后新增 App 设计、SDK 方法、Agent Tool、Surface 或 Capability 时,先修改本文件的边界/契约,再实施代码和细节协议,避免重新把功能堆回聊天页面或创建绕开 Runtime 的平行通道。
@@ -0,0 +1,132 @@
# LineUp App 层架构与迁移记录
**版本:** 2.0Runtime 基线)
**状态:** 当前实现边界与历史迁移记录
**日期:** 2026-08-04
**最终决策入口:** [LineUp App 最终设计方案](app_final_design.md)
## 1. 当前结论
LineUp 是运行在用户设备上的协作 Runtime,不是某个平台上的独立聊天客户端。可以把
Runtime 理解为本地协调中心:它负责连接、消息、存储和恢复;`chat` 是它首先加载的可信
内置功能。未来的语音、画板、游戏和应用中心也必须使用同一套 Runtime / SDK 边界,不能
各自再建立一条到 Agent 的通信链路。
当前唯一实现与验收基线:
```text
Tauri 2 Desktop Host + Web Reference Host
```
这两个 Host 是同一套 TypeScript Runtime 的两种外壳:Tauri Desktop Host 用于正式桌面
交付及受控系统能力;Web Reference Host 用于浏览器开发、Tailscale 联调和自动化测试。
它们不是两套产品,Web 版也不能替代桌面版的系统能力。独立 Android/Kotlin 客户端与
Wails Host 均不在当前或后续规划范围内;早期实验细节仅保留在 Git 历史,不构成架构或
验收依据。
## 2. App 层边界
```text
Remote Agent / AppServer
│ lineup.v1 wire protocol
┌────────────────────────────────────────────────────────┐
│ LineUpRuntime │
│ Transport · sync loop · Store · Outbox · App Inbox │
│ instance state · scope 路由 · Tool · Capability │
└─────────────────────┬──────────────────────────────────┘
│ Runtime SDK
┌────────────────────────────────────────────────────────┐
│ Core / Installed App │
│ chat · app-registry · voice · whiteboard │
└────────────────────────────────────────────────────────┘
```
| 层 | 必须负责 | 不得负责 |
|---|---|---|
| `LineUpRuntime` | 处理 AppServer/Agent 通信、会话、原始协议兼容、scope 筛选、Store、sync、outbox、App Inbox、Tool 路由、App 实例和前台焦点、权限、按 instance 隔离的 MiniApp 业务状态快照与恢复。 | 具体业务页面 DOM 或任意 MiniApp 的业务语义。 |
| Interaction Core App | 用户实际使用的主交互界面:当前是 Chat/IM,未来包含 Audio/Video 模式、标准交互原语和扩展结果投影。 | 直连 AppServer、维护 cursor、解析 Agent 原始包、调度其他 App 或直接写 Runtime Store。 |
| Runtime SDK | App 与 Runtime 之间唯一的受限接口:提供 snapshot、订阅、Agent 消息、Inbox ACK、Runtime Action、App 导航、生命周期请求及自身 instance 的 schema 校验业务状态快照。 | 把 Transport、token、Host 特权 API、Conversation Store 或其他 App/instance 状态暴露给 App。 |
| Tauri/Web Host | 把 Runtime 放进桌面窗口或浏览器,并提供对应的 DOM/系统能力。 | 解释协议、决定 App 调度、绕过 Runtime 路由和策略。 |
| Surface | 在隔离执行域呈现已验证 Bundle,并经受限 bridge 上报事件。 | 访问 Host DOM、登录态、Tauri API、任意网络。 |
## 3. MVP-R1Runtime 托管 Chat
当前 MVP 已完成并以 Tauri/Web 自动化回归验证以下八项条件:
| 条件 | 当前事实 |
|---|---|
| MVP-01 | `LineUpRuntime` 唯一创建并持有 Transport、`ConversationStore`、sync loop 与 outbox。 |
| MVP-02 | Runtime 从本地 `CoreAppRegistry` 解析默认 `chat``RuntimeAppHost` 负责挂载其 Shell`main.ts` 不创建聊天页面。 |
| MVP-03 | Chat 只经 `ChatRuntimeSDK` 订阅 Agent 消息、状态和 Chat-safe Runtime 事件,并以 Action 发送文本、交互、结果与取消。 |
| MVP-04 | Runtime 向 Chat 投递前验证 `app_scope = chat` 与当前 `conversation_id`;非法/不匹配消息被拒绝。 |
| MVP-05 | Compatibility Adapter 在 Runtime 内将旧 `lineup.v1` 映射为内部 `RuntimeEnvelope`;远端无须同步重写。 |
| MVP-06 | 登录、同步、发送、本地回显、Markdown、Agent 状态、Tool/Task 与刷新恢复保持回归。 |
| MVP-07 | Store 持久化每个 App 的 Inbox;运行时重建后未 ACK 消息可恢复,`message_id` 去重。 |
| MVP-08 | `npm test -- --run` 通过 21 个文件 / 94 个测试;`npm run build` 通过。 |
源代码目录和依赖方向见 [Tauri/Web 源码导航](../../tauri/src/README.md)。
## 4. 当前源码归属
```text
lineup-app/tauri/src/
├── main.ts # 启动装配入口:连接 Tauri/Web Host、Runtime 与默认 App
├── core-apps/chat/ # 当前 Interaction App 的 IM 实现、Renderer、样式
└── runtime/
├── app-management/ # Registry、App Instance、焦点、生命周期、Host
├── communication/ # Transport Adapter
├── coordination/ # Runtime、Kernel、Envelope、Tool/Task/交互编排
├── persistence/ # Conversation Store、Outbox、App Inbox、instance state snapshot
├── protocol/ # lineup.v1 解码与 golden fixture
├── surfaces/ # Surface 生命周期、Bundle、隔离 Host
├── capabilities/ # Registry、执行、审计
├── artifacts/ # Artifact 元数据与缓存
└── inventory/ # Agent 可见 Inventory
```
依赖必须保持单向:
```text
core-apps/interaction(当前 chat → runtime/app-management SDK → runtime/coordination
└→ communication / persistence / protocol
Host adapters → runtime/coordination
Surface → restricted bridge → Runtime Action / Capability Gateway
```
## 5. 历史迁移的保留价值
早期 M0M4 工作建立了当前 Runtime 的可复用安全基础。它们是迁移记录,不是新的功能
排期或平行客户端路线:
| 历史阶段 | 保留成果 | 当前归属 |
|---|---|---|
| M0 | HTTP Transport、Conversation Store、协议解码、Markdown、基础回归 | `communication``persistence``protocol`、Chat Renderer |
| M1 | Tool Call、Task、可靠交互结果、受限执行摘要 | `coordination`、Chat SDK 投影 |
| M2 | 本地 Surface Registry、实例生命周期、隔离 iframe 与恢复 | `surfaces` |
| M3 | Capability Registry、用户确认、审计与受限 Host 执行 | `capabilities` |
| M4 | 签名 Manifest、Bundle 校验/缓存/回滚、golden fixture | `surfaces``protocol/golden` |
早期文档中的阶段性“尚未实现”或旧目录路径不得用来判断当前能力;需要审计细节时通过
Git 历史检索。
## 6. 后续阶段
```text
F2 持久化 App Registry、App Instance/Focus Manager、默认 App 切换
F3 Runtime Tool Router、动态 Inventory、可靠 App SDK Tool 闭环
F4 Interaction App 的 IM/Audio/Video 模式边界与第一个 Installed App
```
未来 App 必须复用 `app_scope + conversation_id`、Runtime SDK、Tool/Capability、Artifact、
Store、outbox 与恢复机制;禁止新建独立 Agent 通信通道。
## 7. 文档关系
| 文档 | 用途 |
|---|---|
| [app_final_design.md](app_final_design.md) | 当前产品、Runtime、App、SDK 与实施优先级的唯一汇总入口。 |
| [lineup-runtime-sdk-architecture.md](lineup-runtime-sdk-architecture.md) | Runtime / SDK 的详细接口与未来 App Manager 契约。 |
| [lineup-ui-surface-protocol.md](lineup-ui-surface-protocol.md) | Surface sandbox、bridge、Capability 和 Bundle 安全协议。 |
| 本文件 | 当前实现边界、源码归属与 M0~M4 的迁移价值。 |
@@ -0,0 +1,769 @@
# LineUp Runtime 与 App SDK 架构方案
**版本:** 0.1(架构基线)
**状态:** 已确认的 Runtime / SDK 方向;尚未完全落地到当前 Tauri 实现
**日期:** 2026-08-06
**关联方案:** [LineUp App 层架构设计方案](lineup-app-layer-architecture.md)、[LineUp UI Surface 与 App Capability 协议](lineup-ui-surface-protocol.md)
> **汇总入口:** 本文是 Runtime / SDK 初稿的详细来源。后续设计以 [LineUp App 最终设计方案](app_final_design.md) 为准;后者收敛了本地 `app_scope`、兼容迁移和实施顺序。
---
## 0. 结论与范围
LineUp 不是“聊天应用里附带一个交互 Runtime”。**LineUp App 本身就是运行在用户设备上的
协作 Runtime**,可以把它理解为本地协调中心:它独占与 AppServer / Remote Agent 的连接,
维护会话和本地应用生态,并为上层应用提供统一的消息、工具、存储、权限和生命周期接口。
聊天只是第一个使用这些接口的内置 App。
```text
Remote Agent
│ LineUp Runtime Envelope
AppServer / IM Transport
┌───────────────────────────────────────────────────────────────┐
│ LineUp Runtime │
│ │
│ Connection · Session · Event Routing · App Manager │
│ Tool Registry · Capability Gateway · Storage · Audit │
└───────────────┬──────────────────────────────┬────────────────┘
│ │
▼ ▼
Core App Installed App
chat whiteboard
app-registry voice
settings draw-and-guess
```
本方案定义:
- Runtime 与 Remote Agent、AppServer、上层 App、Tauri Host 的边界;
- 动态应用列表、应用身份、应用安装/启用/禁用/移除与实例生命周期;
- 应用向 Agent 公布工具方法的标准模型;
- Runtime 对消息的统一 Envelope、筛选、可靠投递与 App SDK 订阅接口;
- Core App、Installed App 和 Tauri Host 的信任分层;
- SDK v1 的最小接口和工程模块边界。
本方案不在本次冻结:市场目录的商业模型、支付、公开开发者身份认证细节、多人/多 Agent 共享工作区、完整事件溯源和后台持续执行策略。它们必须建立在本方案的身份、路由和权限边界上。
## 1. 基本术语
| 术语 | 含义 |
|---|---|
| **Runtime** | 用户设备上的长期协作运行底座;唯一负责 AppServer/Agent 通信、应用管理和 Host 能力调度。 |
| **App** | 用户实际使用的功能单元。Chat、应用注册表、语音、白板和游戏都是 App。 |
| **Core App** | 跟随 LineUp Runtime 一起发布、默认受信任的内置 App,例如 `chat`。 |
| **Installed App** | 从受信来源安装、验证后在受限执行环境中运行的 App。 |
| **App Registry** | Runtime 在本机保存的应用清单,记录安装包、版本、启用状态、实例和回滚信息;它是这些状态的唯一依据。 |
| **Tool** | App 先在 Manifest 中说明、Runtime 再公布给 Agent 的可调用方法。Agent 不能任意调用 App 内部函数。 |
| **Capability** | Runtime / Host 保管的系统能力,例如录音、选择文件、保存 Artifact;App 必须请求,不能自动获得。 |
| **Surface** | 一个受限的交互小界面,例如一块画板、一个语音会话面板或一局游戏。 |
| **Conversation** | 用户与一个主 Agent 协作的一段会话范围;App 实例、工具调用和 Artifact 默认都归属这段会话。 |
## 2. 不可变架构原则
1. **Runtime 是唯一 Agent 通信入口。** App 不直接访问 AppServer、IM SDK、WebSocket、HTTP cursor 或 Agent endpoint。
2. **App 只与 Runtime 通信。** Chat、Voice、Market、白板均通过 SDK 读状态、订阅消息、提交动作和请求能力。
3. **每一条可路由 Runtime 消息必须具有 `app_scope` 与 `conversation_id`。** Runtime 以它们作为本地路由、授权、筛选、持久化和投递的首要键。
4. **原始 Agent payload 不交给 App。** Runtime 完成版本、身份、schema、大小、去重和作用域校验后,才产生可订阅的标准化消息。
5. **应用可调用方法必须先声明、后公布、再调用。** Agent 不执行 App 内任意函数,只能调用当前 Inventory 中精确声明的方法。
6. **系统能力由 Runtime 独占。** Agent 和 App 只能请求 Capability;文件、麦克风、通知、剪贴板、窗口、密钥等均不得直接访问。
7. **应用状态、消息和副作用分离。** Event 是已发生事实,Command 是请求动作,Effect 是 Runtime 执行的受控副作用。
8. **UI 是 Runtime 状态的投影。** App 重启、断网或 Surface 回收后,Runtime 能依据持久化状态恢复到可解释的协作状态。
9. **MiniApp 业务状态由 Runtime 托管。** App 只能通过 SDK 保存其当前 instance 的、Manifest schema
声明的状态快照;不能直接访问浏览器/Host 存储、Conversation Store、Tool/operation Store 或其他 App 数据。
## 3. 运行时分层
```text
┌──────────────────────────────────────────────────────────┐
│ Runtime Shell │
│ 应用切换 · 默认入口 · 连接状态 · 通知 · 安全恢复 │
├──────────────────────────────────────────────────────────┤
│ Core App / Installed App │
│ Interaction AppIM / Audio / Video · App Registry │
│ Settings · Whiteboard · Game · …(Installed App
├──────────────────────────────────────────────────────────┤
│ LineUp App Runtime SDK / Surface Bridge SDK │
├──────────────────────────────────────────────────────────┤
│ LineUp Runtime Core │
│ Communication · Coordination · App Management · Tooling │
├──────────────────────────────────────────────────────────┤
│ Runtime Host Provider │
│ Tauri Desktop / Web Reference Host 的文件、通知、窗口等 │
└──────────────────────────────────────────────────────────┘
```
Runtime 内部有三个平面:
| 平面 | 职责 |
|---|---|
| Communication Plane | 登录、AppServer 连接、历史同步、实时入站、ACK、outbox、重连。 |
| Coordination Plane | Envelope 校验、事件路由、会话/Agent 状态、App 生命周期、Tool Registry、Inventory、策略与审计。 |
| Execution Plane | Tauri/Host Capability、Surface Sandbox、Bundle Cache、Artifact 内容和受控副作用。 |
## 4. 应用作用域
本阶段**不定义跨市场、跨供应商的 App 身份、反向域名命名空间或发布者归属模型**。Runtime 仅维护本机可用的应用作用域键(`app_scope`),用于启动、隔离存储、消息路由和 Tool 路由。
```text
chat
app-registry
settings
voice
whiteboard
draw-and-guess
```
`app_scope` 是 Runtime 本地注册表中的短名称,不承诺在未来开放市场中全局唯一。开放生态时再通过版本化 Manifest 引入稳定 App ID、供应商身份和命名空间映射;届时不得破坏本节定义的 scope 路由语义。
### 4.1 作用域键
| 键 | 用途 |
|---|---|
| `conversation_id` | 协作会话边界;所有可路由消息均必填。 |
| `app_scope` | 消息所属/目标 App 边界;所有可路由消息均必填。 |
| `instance_id` | 可选;精确标识某块白板、语音会话或游戏实例。 |
| `operation_id` | 可选;标识长任务、导出、执行进度或异步工具操作。 |
| `call_id` | 可选;标识 Agent 发起的一次 Tool 调用。 |
Runtime 的全局管理事件也不省略路由键,而使用保留作用域:
```text
app_scope: runtime 或具体 Core App
conversation_id: runtime:global
```
第三方 App 不得使用或伪造上述保留身份。
## 5. Runtime App Manager 与交互编排
### 5.1 应用目录与状态
Runtime 维护本地 `App Registry`,它是 App 安装、版本、信任和启用状态的唯一事实源;
`App Instance Manager` 单独维护运行实例、前后台焦点和生命周期。App Catalog/市场只提供
候选条目;市场 App 不直接写文件、删除 Bundle 或改写 Registry。
```text
Catalog Entry → Downloading → Verifying → Installed → Enabled
│ │
│ ├── Active / Background / Suspended instances
│ └── Disabled
└── Update / Rollback / Remove
```
建议的 App Record
```ts
type AppRecord = {
app_scope: AppScope;
kind: "core" | "installed";
installed_version: string;
previous_version?: string;
enabled: boolean;
install_state: "installed" | "updating" | "failed";
active_instance_count: number;
installed_at: string;
enabled_at?: string;
};
type AppInstanceRecord = {
instance_id: AppInstanceID;
app_scope: AppScope;
conversation_id?: ConversationID;
state: "starting" | "foreground" | "background" | "suspended" | "stopping" | "stopped" | "failed";
parent_instance_id?: AppInstanceID;
started_at: string;
stopped_at?: string;
error?: string;
};
```
### 5.2 Runtime 管理接口
```ts
interface RuntimeAppManager {
listApps(filter?: AppListFilter): readonly AppRecord[];
getApp(appScope: AppScope): AppRecord | undefined;
subscribe(listener: (change: AppRegistryChange) => void): Unsubscribe;
install(request: InstallAppRequest): Promise<AppOperation>;
enable(appScope: AppScope): Promise<AppOperation>;
disable(appScope: AppScope, options?: DisableAppOptions): Promise<AppOperation>;
update(appScope: AppScope, targetVersion?: string): Promise<AppOperation>;
rollback(appScope: AppScope): Promise<AppOperation>;
remove(appScope: AppScope, options?: RemoveAppOptions): Promise<AppOperation>;
launch(request: LaunchAppRequest): Promise<AppInstanceHandle>;
closeInstance(instanceID: AppInstanceID): Promise<void>;
}
interface RuntimeAppOrchestrator {
launch(request: LaunchAppRequest): Promise<AppInstanceHandle>;
foreground(instanceID: AppInstanceID): Promise<AppInstanceHandle>;
background(instanceID: AppInstanceID, reason?: string): Promise<AppInstanceHandle>;
suspend(instanceID: AppInstanceID, reason?: string): Promise<AppInstanceHandle>;
restore(instanceID: AppInstanceID): Promise<AppInstanceHandle>;
closeInstance(instanceID: AppInstanceID): Promise<void>;
getFocusStack(conversationID?: ConversationID): readonly AppInstanceID[];
}
```
安装、验签、升级、禁用和移除是异步操作,必须返回可观察的 `AppOperation`。禁用会阻止新实例和新 Tool 调用,并收口现有实例;移除会在实例关闭及用户确认后清理 Bundle 和 App 私有数据。
### 5.3 默认应用与安全回退
Runtime Shell 不属于任何 App。它负责应用切换、通知、连接状态和安全恢复。用户可选择一个具备 `default_eligible` entrypoint 的已启用 App 作为默认入口:
```text
当前默认:chat → 图文 IM 为主
未来默认:voice → 实时语音为主
```
`chat` 是内建、不可移除的 Recovery App:默认 App 不兼容、被禁用、损坏或启动失败时,Runtime 必须回退到它。
启动优先级:
```text
显式启动目标(深链接/通知)
→ 可安全恢复的前台工作
→ 用户 Default App
→ chat Recovery App
```
### 5.4 前台焦点与 App 间切换
`Interaction App` 是默认的人与 Agent 交互入口,但不是全局调度器。Runtime 的
`App Orchestrator``Tool Router``Focus Manager` 负责决定 Agent 请求由哪个 App、哪个
交互模式或哪个标准组件承接。Interact 只通过 SDK 呈现当前会话并提交用户 Action。
```text
Interaction App / Audio Mode foreground
→ Agent 请求 launch(draw-and-guess)
Runtime 校验 Tool、Manifest、Inventory、参数和前台条件
→ Audio Instance background / suspended
→ Draw-and-Guess Instance starting → foreground
→ 游戏结果经 Runtime 回传 Agent
→ 关闭或结束后按 focus stack 恢复 Interaction App
```
前后台切换必须保留原实例和 `conversation_id` 的关联,不能因为界面暂时不可见就删除
未完成 Tool Call、Surface 或 App Inbox。若目标 App 启动失败,Runtime 应恢复原前台实例并
向 Agent 返回受控的 `app_start_failed``handler_failed` 结果。
## 6. Runtime Tool Registry 与动态 Inventory
### 6.1 App Tool
App 可在 Manifest 中声明 Agent 可调用方法。当前 Tool 由 App Scope、局部方法和契约版本定位:
```text
whiteboard/board.create@1
whiteboard/board.apply_diagram@1
voice/voice.request_recording@1
```
Runtime 内部使用结构化键,而不依赖字符串拼接:
```ts
type ToolKey = {
app_scope: AppScope;
method: string;
contract_version: string;
};
```
每个 Tool 声明至少包含:
- 标题、面向 Agent 的说明、输入/输出 JSON Schema
- `query``command``interactive``operation` 四种调用模型之一;
- 前台要求、超时、幂等规则和风险等级;
- 是否需启动 App 实例、是否允许 Runtime 自动启动;
- 该方法可能请求的 Capability。
### 6.2 可见性与 Inventory
Runtime 向 Agent 公布的工具不是安装包的全部声明,而是动态交集:
```text
Agent 可见 Tool
= 已验证 Manifest Tool
∩ App 已启用
∩ 当前 Host 支持
∩ 用户/组织策略允许
∩ 当前 Agent 和 conversation scope 允许
∩ 所需前置权限满足
```
Inventory 包含 App、Tool、Surface 和 Runtime Capability,并具有 revision。Runtime 在连接建立、App 启用/禁用/升级/撤销、Host 能力变化或策略收紧后重新发布。Agent 调用必须携带其看到的 `inventory_revision`;过期清单的调用应被安全拒绝并提示刷新。
### 6.3 Tool 调用流程
```text
Agent lineup.tool.invoke
→ Runtime 验证 Envelope、Agent、inventory revision、App 状态和参数 schema
→ 创建 call record / 审计记录
→ Tool Router 判断直接执行、启动 App、切换前台、等待用户交互,或创建异步 operation
→ App Orchestrator / Interaction App / Installed App 承接调用
→ App 经 SDK 返回 progress / result / error
→ Runtime 验证输出 schema、持久化、更新焦点并回传 Agent
```
标准终态错误码至少包括:
```text
cancelled_by_user
permission_denied
app_disabled
app_not_installed
app_version_mismatch
tool_not_visible
invalid_arguments
foreground_required
operation_expired
handler_failed
```
## 7. 统一消息 Envelope 与路由
### 7.1 Runtime Envelope
所有 Agent、Runtime、App、User 和 Host 之间的可路由消息使用统一基础 Envelope:
```ts
type RuntimeEnvelope = {
v: 1;
id: string;
type: string;
timestamp: string;
sender: {
kind: "agent" | "runtime" | "app" | "user" | "host";
id: string;
};
target: {
kind: "runtime" | "app";
app_scope: AppScope;
instance_id?: AppInstanceID;
};
scope: {
app_scope: AppScope;
conversation_id: ConversationID;
instance_id?: AppInstanceID;
operation_id?: OperationID;
};
correlation?: {
reply_to?: string;
call_id?: string;
inventory_revision?: string;
sequence?: number;
};
payload: JsonValue;
};
```
`scope.app_scope` 是消息所属的本地应用作用域,`target.app_scope` 是指定的消费 App。通常二者相同;Runtime 协调型消息可使用 `runtime` 作为 target,再由 Runtime 生成安全的 App 投影并分发。
### 7.2 消息分类
第一版类型分组:
```text
lineup.content.* 文本、图片、音频、链接、Artifact 引用
lineup.agent.* presence、status、task、progress
lineup.interaction.* choice、confirm、input、form
lineup.tool.* invoke、accepted、progress、result、error、cancel
lineup.app.* state.patch、event、open、close、lifecycle
lineup.capability.* request、result
lineup.runtime.* inventory、connection、app registry、policy、error
```
具体 schema 将在协议文档版本化;SDK 不暴露未经校验的原始 JSON。
### 7.3 Runtime 筛选链
```text
Transport 收到原始消息
→ 协议:版本、必填 app_scope/conversation_id、type、大小、schema
→ 身份:Agent、用户、会话关联
→ 去重/顺序:id、sequence、cursor
→ App:安装、启用、版本、签名、Host 兼容性
→ Tool/CapabilityInventory、方法、参数、策略、前台条件
→ Scopeconversation、instance、operation 所属关系
→ SubscriptionApp Manifest 声明与 SDK 订阅交集
→ PersistRuntime Event / App Inbox / cursor
→ Deliver:投递给目标 App 的 SDK
```
Runtime 不对所有 App 广播原始消息。一个白板 App 即使与 Chat 位于同一 conversation,也只能收到其 Manifest 声明且 Runtime 授权的实例 patch、Tool 调用或事件。
## 8. Runtime SDK v1
### 8.1 双通道模型
```text
InboundRuntime → App
- 已验证 Agent 消息
- App 专属状态投影
- Tool 调用
- Runtime / App 生命周期
OutboundApp → Runtime
- 用户与 App 声明性 Action
- Tool result / progress / error
- Surface Event
- Capability request
- 可恢复 State Snapshot
```
顶层接口:
```ts
interface LineUpAppRuntimeSDK {
readonly app: AppContext;
readonly lifecycle: AppLifecycleAPI;
readonly state: AppStateAPI;
readonly agentMessages: AgentMessageAPI;
readonly actions: AppActionAPI;
readonly tools: AppToolAPI;
readonly apps: AppNavigationAPI;
readonly artifacts: ArtifactAPI;
readonly instanceState: MiniAppInstanceStateAPI;
readonly capabilities: CapabilityRequestAPI;
readonly diagnostics: DiagnosticsAPI;
}
```
App 得到的是按 App Scope、conversation 和实例作用域裁剪后的接口和 View Model,而不是全量 Runtime State 或原始 Transport。
### 8.2 App Context、状态与生命周期
```ts
interface AppContext {
app_scope: AppScope;
app_version: string;
instance_id: AppInstanceID;
kind: "core" | "installed";
entrypoint: string;
scope: {
conversation_id?: ConversationID;
operation_id?: OperationID;
parent_instance_id?: AppInstanceID;
};
granted_permissions: readonly AppPermission[];
}
interface AppStateAPI<ViewModel = unknown> {
snapshot(): ViewModel;
subscribe(listener: (view: ViewModel, change: AppStateChange) => void): Unsubscribe;
}
```
生命周期包含 `start``foreground``background``suspend``restore``closing`。App 可以保存快照并请求延迟关闭,但 Runtime 保留禁用、移除、内存回收和强制收口的最终权力。
### 8.3 Agent 消息订阅与可靠 Inbox
SDK 提供实时订阅,同时提供持久化 Inbox 补读:
```ts
interface AgentMessageAPI {
list(request?: {
conversation_id?: ConversationID;
after?: AgentMessageCursor;
limit?: number;
}): Promise<AgentMessagePage>;
subscribe(
options: {
conversation_id?: ConversationID;
types?: readonly AgentMessageType[];
include_pending?: boolean;
},
handler: (message: AgentAppMessage) => Promise<void> | void,
): Unsubscribe;
acknowledge(message_id: string): Promise<void>;
}
```
投递语义:
1. Runtime 先验证并持久化,再回调 App;
2. 每条消息有唯一 `message_id`App 必须幂等处理;
3. 展示类消息可自动确认;Tool 调用、状态 patch 等业务消息需 App 显式 ACK;
4. App 未运行、暂停或崩溃时,Runtime 写入该 App Inbox;恢复后通过 `list()``subscribe()` 补齐;
5. App 禁用、移除或不兼容时,Runtime 不静默投递或丢弃关键调用,而向 Agent 返回标准拒绝。
App 的订阅条件只是请求;实际投递集为:
```text
Manifest agent_subscriptions
∩ SDK subscribe filter
∩ App 权限
∩ conversation / instance scope
∩ Agent target app_scope
∩ Runtime Policy
```
### 8.4 Action、Tool、App 导航与 Artifact
App 只提交声明性 Action;不得构造原始 Agent Envelope 或直接访问 Transport
```ts
interface AppActionAPI {
dispatch(action: AppAction): Promise<CommandReceipt>;
}
interface AppToolAPI {
onInvoke(listener: (call: AppToolInvocation) => Promise<AppToolOutcome>): Unsubscribe;
progress(request: { call_id: ToolCallID; progress: ToolProgress }): Promise<void>;
complete(request: { call_id: ToolCallID; result: JsonValue }): Promise<void>;
fail(request: { call_id: ToolCallID; code: AppToolErrorCode; message?: string }): Promise<void>;
}
interface AppNavigationAPI {
listAvailable(): readonly AppSummary[];
launch(request: LaunchAppRequest): Promise<AppInstanceHandle>;
focus(instanceID: AppInstanceID): Promise<void>;
background(instanceID: AppInstanceID, reason?: string): Promise<void>;
suspend(instanceID: AppInstanceID, reason?: string): Promise<void>;
close(instanceID: AppInstanceID): Promise<void>;
openDefaultApp(): Promise<void>;
}
```
`AppNavigationAPI` 只是 App 发给 Runtime 的受限请求接口。真正的 Tool Router、App Instance
Manager 和 Focus Manager 位于 Runtime 内部:它们负责检查 App 是否已安装/启用、是否满足
前台条件、是否需要用户确认,以及切换失败时恢复原前台实例。Interact 可以请求启动扩展
App,但不能直接决定其他 App 的生命周期。
Artifact、媒体与文件通过 Runtime Artifact Store 暴露元数据、受限读取、创建、会话引用和用户保存;App 不取得任意路径或跨 App 文件访问权。
### 8.5 MiniApp instance 状态与 Capability
每个 MiniApp instance 使用 Runtime 管理的、按实例隔离的业务状态快照:
```text
app_scope + instance_id
→ 一份 schema 校验的 JSON state snapshot
→ revisioned replace
→ 恢复同一个未结束 instance 时投影给该 App
```
这不是通用文件系统、键值数据库或跨 instance 查询接口。App 负责定义状态的业务含义;Runtime 负责
根据 Manifest 校验 schema、schema version、大小配额和保留策略,并保证调用方只能操作当前 SDK context
中的 instance。Runtime 也负责 revision 比较、原子写入、重启恢复以及禁用、移除和关闭时的冻结/保留/清理。
第一版 `retention` 仅支持 `delete_on_close`(默认)与 `retain_readonly`;后者只保留历史或向新 instance
提供受控上下文,不能让已关闭 instance 再次写入。App 禁用或移除后的最终清理由 Runtime 按用户确认和全局
保留策略执行;状态 schema 升级只能经新 App 版本的受控读取/替换完成,Runtime 不执行 App 提供的迁移脚本。
```ts
interface MiniAppInstanceStateAPI<State extends JsonObject = JsonObject> {
get(): Promise<{
state: State | null;
revision: number;
}>;
replace(request: {
state: State;
expected_revision: number;
}): Promise<{
revision: number;
}>;
}
```
`expected_revision` 不匹配时 Runtime 返回稳定的 `state_revision_conflict`;非法 schema、越过实例边界或
超出配额时分别返回 `state_invalid``state_scope_mismatch``state_quota_exceeded`。App 不得用状态
快照直接完成 Agent Tool、写 outbox、改变焦点或执行 Capability。涉及 deadline、Tool 终态、outbox、焦点
或生命周期的业务命令仍要走 Runtime 的 Command / operation 路径;Runtime 可在同一原子事务中更新
operation 与 instance state,但两者保持不同的事实来源。
MiniApp 的短暂渲染状态(动画、滚动位置、临时 loading)不要求保存;Conversation / App 子会话保存人与
Agent 可见的静态交互和结果,也不是 MiniApp 业务状态的事实来源。Capability 必须通过统一请求接口:
```ts
interface CapabilityRequestAPI {
request<T extends JsonValue>(request: {
capability: CapabilityName;
purpose: string;
input: JsonValue;
scope?: AppScope;
}): Promise<CapabilityResult<T>>;
}
```
Runtime 检查 Manifest 声明、App 启用状态、Host 支持、前台要求、用户确认、系统权限、策略、限流与审计;App 只能获得受控结果。
## 9. 信任分层与 Surface Bridge SDK
| 层级 | 例子 | 可用接口 | 明确禁止 |
|---|---|---|---|
| Core App | Chat、App Registry、Settings | 完整 App Runtime SDK(仍受 Scope 和 Capability 约束) | 直接绕过 Transport/Capability Gateway。 |
| Installed App | 白板、语音、游戏 | 受限 Surface Bridge SDK:状态、已声明 Tool、事件、当前 instance 的 Runtime 状态快照、Capability request | Tauri invoke、父 DOM、token、任意网络、其他 App 数据。 |
| Host Provider | Tauri Desktop / Web Reference Host 实现 | Runtime 内部 Host Provider API | 向 Runtime 提供系统能力;不直接暴露给 Agent/Surface。 |
下载型 App 使用 `iframe sandbox="allow-scripts"` 或等价隔离容器;不包含 `allow-same-origin`。它经严格 CSP、来源验证和消息 schema 校验的桥接访问 Surface SDK。第一版不支持市场下载包执行本地 Rust、Node、Shell 或任意浏览器特权代码。
## 10. App Manifest 的 Runtime/SDK 声明
每个 App Manifest 除 Bundle、签名和 Surface 外,还应声明 Runtime SDK 与消息/工具契约。当前阶段只使用本地 `app_scope`,不在 Manifest 中固化供应商身份或全局命名空间:
```json
{
"format": "lineup.app.v1",
"app_scope": "whiteboard",
"version": "1.2.0",
"runtime_sdk": {
"api_version": "1",
"required_features": ["app.lifecycle.v1", "app.tools.v1", "surface.state.v1", "app.instance-state.v1"],
"optional_features": ["artifact.create.v1"]
},
"entrypoints": [
{"id": "canvas", "kind": "contextual", "default_eligible": false}
],
"instance_state": {
"state_schema_version": 1,
"state_schema": {"type": "object", "additionalProperties": false},
"max_bytes": 65536,
"retention": "delete_on_close"
},
"agent_subscriptions": [
{"type": "lineup.app.state.patch", "scope": "instance"},
{"type": "lineup.tool.invoke", "scope": "conversation"}
],
"tools": [
{
"method": "board.create",
"contract_version": "1",
"invocation": {"kind": "command", "activation": "launch_if_needed"},
"input_schema": {"type": "object", "additionalProperties": false},
"output_schema": {"type": "object", "additionalProperties": false}
}
]
}
```
Runtime 在安装、启用和启动时进行 SDK 版本及 feature 协商;不兼容 App 不进入可用 Inventory,也不得启动。
## 11. Runtime 状态与恢复
顶层 Runtime State 至少包含:
```text
identity 用户、设备、认证会话
connection AppServer 状态、cursor、重试、outbox
conversations Agent 映射、消息引用、任务、交互、Artifact 元数据
apps App Registry、默认 App、运行实例、App Inbox
app_state 按 app_scope + instance_id 隔离的业务状态快照与 revision
tools 已声明 Tool、可见性、调用与 operation
capabilities 授权、执行状态、最小审计
```
第一版采用“事件驱动状态机 + 必要快照”,而非完整 Event Sourcing:关键入站事件、用户决定、Tool 结果、outbox 和审计记录持久化;渲染细节和短暂 UI 状态不必全部写入事件日志。
Runtime 生命周期:
```text
created → restoring → authenticating → synchronizing → online
↘ reconnecting / offline_degraded
online / offline_degraded → stopping → stopped
```
启动时恢复 App Registry、默认入口、会话 cursor、outbox、App Inbox、未完成 Tool 和可恢复实例;追平历史后再开始实时投递。离线时用户/App Action 进入 outbox,重连后按幂等键和顺序处理。
## 12. 推荐工程边界
```text
lineup-app/
├── runtime-core/
│ ├── communication/ Transport、sync、outbox
│ ├── coordination/ Event、state、router、policy、focus、audit
│ ├── apps/ App Manager、Registry、Instance、Focus、Lifecycle Manager
│ ├── tools/ Tool Registry、Inventory、Router、call lifecycle
│ ├── capabilities/ Capability Gateway
│ └── persistence/ Runtime Store、App Inbox、instance state snapshot、Artifact metadata
├── runtime-sdk/
│ ├── app.ts Core App SDK 类型
│ ├── manifest.ts App/Tool/Subscription Manifest 类型
│ ├── protocol.ts Runtime Envelope 与 schema
│ ├── errors.ts 稳定错误码
│ └── testkit/
├── surface-sdk/
│ ├── bridge.ts sandbox postMessage bridge
│ └── surface.ts Installed App 最小接口
└── tauri/
├── src/
│ ├── bootstrap/ Tauri/Web 的应用启动装配层
│ ├── runtime-host/ Runtime Host Provider 适配
│ ├── core-apps/ chat、app-registry、settings
│ └── shell/ app switcher、default app、recovery
└── src-tauri/ 文件、音频、通知、窗口等 Rust Provider
```
当前 `lineup-app/tauri/src/main.ts` 同时承担 Runtime、Chat、Host Adapter 和开发 Fixture 的职责,是拆分的主要对象。现有 `InteractionKernel`、Transport、Conversation Store、Surface Registry、Instance Manager、Bundle Cache、Capability Registry 与 Inventory Publisher 可作为上述 Runtime Core 的迁移基础。
## 13. 第一阶段落地顺序与验收
### R0:冻结 Runtime/SDK 合约
- 固化 `RuntimeEnvelope`、app scope / conversation ID / instance ID 规则;
- 固化 Event / Command / Effect 边界;
- 定义 `LineUpAppRuntimeSDK``Surface Bridge SDK` 与 Manifest TypeScript 类型;
- 为 Envelope、App Manifest、Tool Descriptor、SDK 错误码准备 golden fixtures。
### R1:建立 Runtime Core 和 Interaction Core App(当前 `chat` 实现)
- 将 Runtime 的创建与装配集中在单一启动入口,不让 `main.ts` 变成通信和业务逻辑的堆放处;
- Runtime 独占 Transport、Store、outbox 和入站筛选;
- 将当前图文 IM 重构为 Interaction Core App 的 `chat` 实现;
- 当前 `chat` 通过 `agentMessages.subscribe()` 获取已验证的 Agent 消息,不再直接依赖 Transport;
- 保持当前登录、同步、本地回显、Markdown、Tool Call、Task 与 Artifact 回归行为。
### R2App Registry Core App
- 将现有开发期 `SurfaceRegistry` 升级为 Runtime App Registry
- 实现 Core App 记录、Installed App 记录、enable/disable/remove 和默认 App 选择;
- 将 Registry UI 实现为 `app-registry`,仅调用 `RuntimeAppManager`
- App 状态变化后正确更新 Runtime Inventory。
### R3Tool Registry 与 App SDK Inbox
- 实现 Manifest Tool / Subscription 解析与可见性筛选;
- 将动态 Inventory 同步给 Agent
- 实现 Agent `tool.invoke` → Runtime → App SDK → `tool.result` 的可靠闭环;
- App 未运行时持久化 Inbox,恢复后可幂等补读。
- 实现 `app.instance-state.v1`Manifest schema / schema version / quota / retention 校验、instance 隔离、
revisioned replace、刷新/重启恢复与关闭/禁用/移除清理;Tool/operation/outbox 不得由该 API 直接改写。
### R4:第一个 Installed App 闭环
- 接入一个已签名的画板或任务面板 App;
- 验收 install → enable → inventory 更新 → Agent 调用 Tool → App 启动 → Surface 事件 → Agent result → disable/remove
- 后续语音 App 复用同一 SDK、Tool、Capability 与 Artifact 通道,而不是再实现独立通信链路。
硬性验收:
```text
1. 缺少或非法 app_scope / conversation_id 的可路由消息被 Runtime 拒绝;
2. App 不会收到其他 App 或其他 conversation 的 Agent 原始消息;
3. App 被禁用后,其 Tool 从 Inventory 移除且新调用被拒绝;
4. 断线/重启后 App Inbox、outbox、Tool 调用和实例状态能有界恢复;
5. 下载型 App 无法访问 Tauri invoke、Host DOM、token 或未授予 Capability
6. 默认 App 不可用时 Runtime 自动进入 chat Recovery App
7. 所有 Tool 调用、权限拒绝与终态结果均可按 app_scope、conversation_id、call_id 审计和测试。
8. MiniApp 只能读写自身当前 instance 的状态快照;非法 schema、旧 revision、跨 instance、超配额以及
关闭后的写入均被稳定拒绝,重启只恢复最后一个有效快照。
```
## 14. 与已有正式方案的关系
- 本文将 [App 层架构方案](lineup-app-layer-architecture.md) 中的 Interaction Runtime 从“聊天 Host 内部模块”收敛为整个 App 的 Runtime,并补充了 App Manager、App Tool Registry、SDK 和消息路由模型。
- 本文不废弃 [UI Surface 与 App Capability 协议](lineup-ui-surface-protocol.md) 中已完成的 Surface 隔离、Capability 确认、生产 Bundle 验签和动态 inventory 原则;后续应将其协议字段迁移/扩展为本文定义的 Runtime Envelope、App Manifest 和 Tool Registry,而不能引入绕开 Runtime 的平行通道。
- 现有 M2/M4 文档和实现使用的 `app id` 是当前 Surface 协议的实现字段。本方案在 Runtime 重构阶段以 `app_scope` 作为本地路由字段;供应商身份和全局命名空间将在后续生态阶段通过独立、版本化的兼容设计重新引入。
- 当前 M0M4 实现可作为 Runtime 的迁移基础,但其现有文件边界不是最终 Runtime/App/SDK 边界。
@@ -0,0 +1,226 @@
# LineUp UI Surface 与 App Capability 协议
**版本:** 1.0(提案)
**状态:** 已有 Web Chat Reference Host
**日期:** 2026-08-02
> **汇总入口:** 本文保留 Surface 与 Capability 的协议和安全细节。后续 Runtime、SDK、App 管理及旧 `app.id` 字段的兼容迁移以 [LineUp App 最终设计方案](app_final_design.md) 为准。
## 1. 目标
LineUp 的 Agent 不应只能回一段文本,也不应获得在宿主 App 任意执行代码的权限。本协议定义一个类似“小程序表现层”的受控扩展模型:
```text
Agent / Adapter
├─ lineup.v1.ui.open / patch / close ─────→ UI Surface Host
│ └─ sandbox HTML + CSS + JS
├─ lineup.v1.app.call ─────→ App Capability Registry
│ └─ 用户确认 / 系统权限 / 本机执行
←─ lineup.v1.ui.event / app.result ────── 用户动作或受控调用结果
```
它有两层,不可混用:
| 层 | 作用 | 能做什么 | 不能做什么 |
|---|---|---|---|
| `UI Surface` | 呈现交互界面 | 显示 HTML/CSS/JS、收集用户事件、接收状态更新 | 读取宿主登录态、直接访问设备能力、直接调用 IM / 网络 |
| `App Capability` | 调用宿主上层应用能力 | 在能力注册、权限和用户确认后打开链接、写剪贴板、选文件、调用原生模块等 | 由 Surface 脚本绕过权限直接调用 |
标准 Markdown、文本、状态、进度、choice、confirm、input 等仍应优先由宿主内置渲染器实现。Surface 适用于仪表盘、地图、复杂表单、图表、可视化编辑器等无法由内置组件良好表达的界面。
## 2. 安全模型(不可省略)
1. Agent 的 UI bundle 被视为**不可信内容**,不是 App 代码的一部分。
2. Web Host 必须使用独立 origin 的 `iframe sandbox="allow-scripts"`。禁止 `allow-same-origin``allow-top-navigation``allow-popups``allow-forms`
3. Surface 的 CSP 至少为 `default-src 'none'; connect-src 'none'; img-src data: blob:; style-src 'unsafe-inline'; script-src 'unsafe-inline'`。默认不得联网、加载远程脚本、访问摄像头或地理位置。
4. 宿主与 Surface 仅用 `postMessage` 通信;宿主必须同时验证 `event.source`、消息命名空间、`instance_id`、事件名、JSON 类型与大小。
5. Surface 事件只是“用户意图”回传。任何上层 App / 原生能力都必须由 Agent 另行发送 `app.call`,再由宿主依据注册表、风险等级和用户授权执行。
6. Content 不得写入宿主 DOM。Markdown 使用解析器后仍须 sanitizerHTML Surface 只能放进 sandbox `srcdoc`
7. 生产环境应只接受已签名或在 Agent allowlist 中的 bundle hashReference Host 先以严格 sandbox 保障隔离,并保留 `app.integrity` 字段用于升级。
## 3. 消息类型
所有消息均使用既有 `lineup.v1` 信封。`conversation_id``id``sender``target` 的规则不变。
| Type | 方向 | 含义 |
|---|---|---|
| `lineup.v1.ui.open` | Agent → Client | 创建或替换一个 Surface 实例 |
| `lineup.v1.ui.patch` | Agent → Client | 向已打开实例推送新的状态;不可注入或替换代码 |
| `lineup.v1.ui.close` | Agent → Client | 关闭实例 |
| `lineup.v1.ui.event` | Client → Agent | Surface 中的用户事件或用户关闭事件 |
| `lineup.v1.client.inventory` | Client → Agent | 当前 Host 的 revisioned 最小接口清单:标准组件、应用中心已启用 app Surface 与 policy 筛选后的 capability |
| `lineup.v1.app.list` | Client → Agent | 可选的兼容 capability-only 投影;不得替代完整 inventory 或宣称安装/授权 |
| `lineup.v1.app.call` | Agent → Client | 请求调用一个声明过的 capability |
| `lineup.v1.app.result` | Client → Agent | 调用完成、拒绝、失败或不支持的结果 |
未知的 `ui.*``app.*` type 只能安全显示或回复 `unsupported`,不得执行。
## 4. UI Surface 合约
### 4.1 打开
```json
{
"v": 1,
"id": "msg_ui_01",
"type": "lineup.v1.ui.open",
"conversation_id": "conv_01",
"sender": {"kind": "agent", "id": "agent_hermes_main"},
"payload": {
"instance_id": "weather.dashboard.01",
"app": {
"id": "com.lineup.weather.dashboard",
"name": "天气面板",
"version": "1.0.0",
"integrity": "sha256-BASE64_DIGEST",
"html": "<main><button id='refresh'>刷新</button></main>",
"css": "main { padding: 16px }",
"js": "document.querySelector('#refresh').onclick=()=>LineUpSurface.event('refresh',{unit:'c'})"
},
"state": {"city": "北京", "temperature": 22}
}
}
```
约束:
- `instance_id` 在一个会话内唯一,格式为 `[A-Za-z0-9._:-]{1,128}`;相同 ID 的 `ui.open` 表示替换旧实例;
- `app.id` 为反向域名风格的稳定应用 ID`version` 为 SemVer
- `html``css``js` 是 Surface bundle;单个 bundle 的生产上限建议为 160 KiB,资源应使用经过 Artifact 管理和签名的本地引用,禁止任意公网 URL;
- `state` 必须是 JSON object。UI bundle 将在 `ready` 后和每次 `ui.patch` 收到它;
- **`ui.patch` 只能更新 `state`,绝不能更新 HTML/CSS/JS。** 若要升级 bundle,关闭旧实例并以新 `version` 打开新实例。
### 4.2 Surface bridge
Host 注入唯一的全局对象:
```js
LineUpSurface.event('refresh', { unit: 'c' })
LineUpSurface.onState((state) => render(state))
LineUpSurface.resize(document.documentElement.scrollHeight)
```
它只允许以下上行消息:
```json
{
"namespace": "lineup.surface.v1",
"type": "event",
"event": "refresh",
"data": {"unit": "c"}
}
```
Host 将其转换为:
```json
{
"type": "lineup.v1.ui.event",
"payload": {
"instance_id": "weather.dashboard.01",
"event": "refresh",
"data": {"unit": "c"}
}
}
```
`event` 采用 `[A-Za-z][A-Za-z0-9._:-]{0,63}``data` 必须为小于 16 KiB 的 JSON object。Surface 不拥有 `app.call` bridge。
### 4.3 状态更新与关闭
```json
{"type":"lineup.v1.ui.patch","payload":{"instance_id":"weather.dashboard.01","state":{"city":"上海","temperature":28}}}
```
```json
{"type":"lineup.v1.ui.close","payload":{"instance_id":"weather.dashboard.01","reason":"completed"}}
```
用户主动关闭时 Client 应回送 `ui.event`,其中 `event``close`
## 5. App Capability 合约
### 5.1 动态 Client Inventory
客户端在会话建立完成后,以及应用中心的 app 启用/停用/升级、Host policy 或 capability 可见性变化时,向**对应 Agent 会话**发送 `client.inventory`。它有单调递增或不可复用的 `revision`Agent 必须用最新 revision 决定可请求的组件、Surface 和能力。收到撤销后的旧 app id、Surface 或 capability 引用时,Client 只返回确定的 `unsupported / revoked` 结果,绝不回退到执行或加载远端 bundle。
```json
{
"type": "lineup.v1.client.inventory",
"payload": {
"revision": "catalog-42",
"standard_components": [
{"id":"choice","version":"1"},
{"id":"confirm","version":"1"},
{"id":"input","version":"1"}
],
"applications": [
{
"id":"com.lineup.svg-canvas",
"version":"1.0.0",
"surfaces":[{"id":"canvas","events":["draw","resize","snapshot"]}]
}
],
"capabilities": [
{"name":"artifact.save","version":"1.0","risk":"user_confirmation"}
]
}
}
```
`applications` 只能列出应用中心中**已启用且已在本地完成相应阶段验证**的应用,不包含 bundle 源码、安装来源、登录态、文件路径或用户内容。SVG 画板这样的 app 只允许 Agent 以 app id 创建受限 Surface,并通过用户触发的 `ui.event(draw / resize / snapshot)` 获取声明性画布事件;inventory 不授予远程脚本注入、读取宿主 DOM 或本机能力权限。
### 5.2 Capability 声明(`app.list` 兼容投影)
客户端可在 inventory 之后或 capability 变化时发送 `app.list` 作为仅包含 capability 的兼容投影。只有 inventory / app.list 中声明且仍未被撤销的 `capability` 才能被请求;声明从不等同于授权。
```json
{
"type": "lineup.v1.app.list",
"payload": {
"capabilities": [
{"name":"app.open_url","version":"1.0","risk":"user_confirmation","input_schema":{"type":"object","required":["url"]}},
{"name":"clipboard.write","version":"1.0","risk":"user_confirmation","input_schema":{"type":"object","required":["text"]}},
{"name":"device.pick_file","version":"1.0","risk":"system_permission","input_schema":{"type":"object"}}
]
}
}
```
风险必须是下列之一:`display_only``user_confirmation``system_permission``restricted`。后两者不能被记住为永久授权,且必须经过原生系统权限或额外身份校验。
### 5.3 调用与结果
```json
{
"type": "lineup.v1.app.call",
"payload": {
"call_id": "call_open_docs_01",
"capability": "app.open_url",
"reason": "打开部署文档供你核对",
"expires_at": "2026-08-02T12:10:00Z",
"arguments": {"url": "https://example.com/docs"}
}
}
```
Client 必须向用户说明 capability 和 `reason`,收到确认后再执行,随后使用相同 `call_id` 回传:
```json
{
"type": "lineup.v1.app.result",
"payload": {
"call_id": "call_open_docs_01",
"status": "completed",
"result": {"opened": true}
}
}
```
`status``completed | rejected | cancelled | expired | unsupported | failed`。同一 `call_id` 必须幂等;调用记录与授权决定应由 Gateway 审计。
## 6. Reference Host 当前实现与阶段边界
截至 2026-08-03Tauri Reference Host 已完成 M0 和 M1-01M1-03:严格 Envelope / Kernel / Store / Renderer 边界,Markdown、status/progress/error、choice、confirm、input 的可信原生渲染与本地状态恢复。它**尚未**实现 `client.inventory` 发送、应用中心、`ui.open / patch / close` 的 Surface Host、远端或本地 app bundle 加载、`app.call` 执行、Capability Registry 或 `app.result` 网络回传。
因此,这份协议中的 Surface、inventory 与 Capability 段落是后续 M2M4 的正式契约,不是当前 Web Chat 已开放的功能。M2 建立应用中心本地启用注册表与隔离 Surface;M3 才生成/更新并通知 `client.inventory`,再实施 Capability policy;M4 负责下载、完整性校验、缓存、回滚与 Host 一致性。当前只以 Tauri Desktop Host 与同代码 Web Reference Host 实现这些边界;不规划独立 Android/iOS/Wails 客户端。
@@ -522,7 +522,7 @@ tauri/src/core-apps/chat/
### 10.3 下一阶段:03.sdk_and_coreapp ### 10.3 下一阶段:03.sdk_and_coreapp
下一阶段不是应用市场,也不是立即建设服务端下载目录。目标见 下一阶段不是应用市场,也不是立即建设服务端下载目录。目标见
[03.sdk_and_coreapp.md](迭代/03.sdk_and_coreapp/03.sdk_and_coreapp.md):定义并验证 MiniApp SDK v1 [03.sdk_and_coreapp.md](../迭代/03.sdk_and_coreapp/03.sdk_and_coreapp.md):定义并验证 MiniApp SDK v1
```text ```text
冻结 AppManifest、ToolDescriptor、Tool Call、App Context、Result/Progress/Error 和错误码 冻结 AppManifest、ToolDescriptor、Tool Call、App Context、Result/Progress/Error 和错误码
@@ -584,10 +584,10 @@ npm run build
## 12. 相关文档与源码导航 ## 12. 相关文档与源码导航
- [迭代/00.base/00.base.md](迭代/00.base/00.base.md)Runtime 托管 Interact IM 的稳定基线。 - [迭代/00.base/00.base.md](../迭代/00.base/00.base.md)Runtime 托管 Interact IM 的稳定基线。
- [迭代/01.kernel/01.kernel.md](迭代/01.kernel/01.kernel.md)Runtime Kernel 与 MiniApp 编排目标和验收。 - [迭代/01.kernel/01.kernel.md](../迭代/01.kernel/01.kernel.md)Runtime Kernel 与 MiniApp 编排目标和验收。
- [tauri/src/README.md](tauri/src/README.md):当前源码目录和依赖方向。 - [tauri/src/README.md](../tauri/src/README.md):当前源码目录和依赖方向。
- [tauri/README.md](tauri/README.md)Tauri/Web Host 的运行、回归与历史实施细节。 - [tauri/README.md](../tauri/README.md)Tauri/Web Host 的运行、回归与历史实施细节。
- [程序文件清单与功能说明.md](程序文件清单与功能说明.md):实现文件和功能说明。 - [程序文件清单与功能说明.md](../程序文件清单与功能说明.md):实现文件和功能说明。
- [LineUp App 最终设计方案](../设计/02.正式方案/app_final_design.md):跨文档详细契约来源; - [LineUp App 最终设计方案](02.正式方案/app_final_design.md):跨文档详细契约来源;
若与本文的产品术语或当前迭代顺序冲突,以本文为准并同步更新上游方案。 若与本文的产品术语或当前迭代顺序冲突,以本文为准并同步更新上游方案。
+20
View File
@@ -0,0 +1,20 @@
# LineUp App 当前设计文档
这里集中放置 LineUp App 当前阶段仍在使用的设计文档。LineUp App 是用户使用的主应用,Runtime 是 App 内部提供给 MiniApp 的核心运行环境;当前设计以这组文档为准。
## 当前权威入口
- [APP架构设计.md](APP架构设计.md):当前产品边界、Runtime、MiniApp、SDK、Interact 以及发布安全约束的总入口。
- [LineUp App 最终设计方案](02.正式方案/app_final_design.md):当前架构、契约和实施顺序的详细汇总。
## 详细方案
- [LineUp App 层架构与迁移记录](02.正式方案/lineup-app-layer-architecture.md):M0~M4 的实施边界、迁移记录和分层规则。
- [LineUp Runtime 与 App SDK 架构方案](02.正式方案/lineup-runtime-sdk-architecture.md)Runtime、App Manager、Tool Registry、SDK 和消息路由的详细方案。
- [LineUp UI Surface 与 App Capability 协议](02.正式方案/lineup-ui-surface-protocol.md)Surface、Capability、权限确认和 Bundle 安全规则。
## 迭代和评审
迭代定义以及每轮设计评审、验收记录保留在 [迭代/](../迭代/README.md)。设计文档描述长期架构和当前阶段的约束,迭代文档描述具体要交付的工作。
根目录下的 `设计/00.records``设计/01.前期分析与设计` 属于历史资料,不作为当前 LineUp App 设计的主入口。
@@ -2,7 +2,7 @@
> 评审日期:2026-08-05 > 评审日期:2026-08-05
> 评审编号:01 > 评审编号:01
> 评审基线:[APP架构设计.md](../../APP架构设计.md) > 评审基线:[APP架构设计.md](../../设计/APP架构设计.md)
> 评审对象:[03.sdk_and_coreapp.md](03.sdk_and_coreapp.md) > 评审对象:[03.sdk_and_coreapp.md](03.sdk_and_coreapp.md)
> 评审方式:独立子 agent 只读评审;本文件记录评审意见,不代表已采纳或已实现。 > 评审方式:独立子 agent 只读评审;本文件记录评审意见,不代表已采纳或已实现。
@@ -79,13 +79,13 @@
Runtime 连接。 Runtime 连接。
本轮评审问题均已得到设计结论,后续进入实现时应以 [03.sdk_and_coreapp.md](03.sdk_and_coreapp.md) 本轮评审问题均已得到设计结论,后续进入实现时应以 [03.sdk_and_coreapp.md](03.sdk_and_coreapp.md)
和 [APP架构设计.md](../../APP架构设计.md) 为准。 和 [APP架构设计.md](../../设计/APP架构设计.md) 为准。
## 2. 阻塞问题 ## 2. 阻塞问题
### B1. Task Dashboard 的可信 DOM / Host adapter 权限突破了当前信任模型 ### B1. Task Dashboard 的可信 DOM / Host adapter 权限突破了当前信任模型
**架构基线**在 [APP架构设计.md](../../APP架构设计.md) 的 MiniApp 信任模型中明确: **架构基线**在 [APP架构设计.md](../../设计/APP架构设计.md) 的 MiniApp 信任模型中明确:
- `Interact / System MiniApp` 可使用可信内建 DOM 组件; - `Interact / System MiniApp` 可使用可信内建 DOM 组件;
- Installed MiniApp 必须经隔离 iframe / Surface Bridge 运行。 - Installed MiniApp 必须经隔离 iframe / Surface Bridge 运行。
@@ -348,6 +348,6 @@ bundled 参考 MiniApp,本阶段就完成其端到端路径。因此删除重
2. 冻结 **I2Renderer → Runtime 的提交/Bridge 契约** 2. 冻结 **I2Renderer → Runtime 的提交/Bridge 契约**
3. 冻结 **I3/I4StandardInteractionRecord 与 Tool Call 的关系,以及 UI result 的唯一返回通道** 3. 冻结 **I3/I4StandardInteractionRecord 与 Tool Call 的关系,以及 UI result 的唯一返回通道**
4. 细化 **I5/I6:schema、状态机、幂等、错误码、持久化与日志最小化** 4. 细化 **I5/I6:schema、状态机、幂等、错误码、持久化与日志最小化**
5. 把 S1~S5 与第 5 节的验收场景回填入 [03.sdk_and_coreapp.md](03.sdk_and_coreapp.md) 和必要的 [APP架构设计.md](../../APP架构设计.md)。 5. 把 S1~S5 与第 5 节的验收场景回填入 [03.sdk_and_coreapp.md](03.sdk_and_coreapp.md) 和必要的 [APP架构设计.md](../../设计/APP架构设计.md)。
在上述收敛前,不建议开始 `standard-interaction-service` 或参考 MiniApp 的实现,以免重新形成 Chat / Interact 专用旁路。 在上述收敛前,不建议开始 `standard-interaction-service` 或参考 MiniApp 的实现,以免重新形成 Chat / Interact 专用旁路。
@@ -3,7 +3,7 @@
> 评审编号:03 > 评审编号:03
> 评审日期:2026-08-05 > 评审日期:2026-08-05
> 评审对象:[03.sdk_and_coreapp.md](03.sdk_and_coreapp.md) > 评审对象:[03.sdk_and_coreapp.md](03.sdk_and_coreapp.md)
> 参考资料:[APP架构设计.md](../../APP架构设计.md)、[01.design_review.md](01.design_review.md)、[02.design_review.md](02.design_review.md) > 参考资料:[APP架构设计.md](../../设计/APP架构设计.md)、[01.design_review.md](01.design_review.md)、[02.design_review.md](02.design_review.md)
> 评审方式:基于当前主定义的独立只读复核;重点检查已确认的边界在契约、实施步骤与验收目标之间是否能够由同一套实现兑现。 > 评审方式:基于当前主定义的独立只读复核;重点检查已确认的边界在契约、实施步骤与验收目标之间是否能够由同一套实现兑现。
> 结论:产品层级、标准交互归属和受限 MiniApp 信任模型已稳定;未发现 P0 架构冲突。经本轮统一收敛,3 项 P1 与 2 项 P3 均已确认并回填主定义文档;后续不再进行纯设计评审,直接进入实现,并在实现完成后做一次关闭式复核。 > 结论:产品层级、标准交互归属和受限 MiniApp 信任模型已稳定;未发现 P0 架构冲突。经本轮统一收敛,3 项 P1 与 2 项 P3 均已确认并回填主定义文档;后续不再进行纯设计评审,直接进入实现,并在实现完成后做一次关闭式复核。
@@ -4,7 +4,7 @@
**状态:** 已完成(P0~P3 问题已清空,代码、自动化测试和真实浏览器验收通过) **状态:** 已完成(P0~P3 问题已清空,代码、自动化测试和真实浏览器验收通过)
**日期:** 2026-08-05 **日期:** 2026-08-05
**前置基线:** [00.base.md](../00.base/00.base.md)、[01.kernel.md](../01.kernel/01.kernel.md) **前置基线:** [00.base.md](../00.base/00.base.md)、[01.kernel.md](../01.kernel/01.kernel.md)
**权威架构:** [APP架构设计.md](../../APP架构设计.md) **权威架构:** [APP架构设计.md](../../设计/APP架构设计.md)
## 1. 迭代目标 ## 1. 迭代目标
@@ -1050,7 +1050,7 @@ fixture,再修改实现,不能在业务代码里悄悄改变契约。
7. **端到端验收与文档回填** 7. **端到端验收与文档回填**
- 运行完整单元测试和生产构建; - 运行完整单元测试和生产构建;
- 通过 Tauri/Web Reference Host 完成代表性浏览器验收; - 通过 Tauri/Web Reference Host 完成代表性浏览器验收;
- 将最终 SDK 形态与参考 MiniApp 结果回填 [APP架构设计.md](../../APP架构设计.md)。 - 将最终 SDK 形态与参考 MiniApp 结果回填 [APP架构设计.md](../../设计/APP架构设计.md)。
## 9. 验收目标 ## 9. 验收目标
@@ -3,7 +3,7 @@
> 评审编号:04 > 评审编号:04
> 评审日期:2026-08-05 > 评审日期:2026-08-05
> 评审对象:[03.sdk_and_coreapp.md](03.sdk_and_coreapp.md) > 评审对象:[03.sdk_and_coreapp.md](03.sdk_and_coreapp.md)
> 架构基线:[APP架构设计.md](../../APP架构设计.md) > 架构基线:[APP架构设计.md](../../设计/APP架构设计.md)
> 参考评审:[01.design_review.md](01.design_review.md)、[02.design_review.md](02.design_review.md)、[03.design_review.md](03.design_review.md) > 参考评审:[01.design_review.md](01.design_review.md)、[02.design_review.md](02.design_review.md)、[03.design_review.md](03.design_review.md)
> 评审方式:主 agent 交叉检查 + 独立子 agent 只读验收;检查构建、自动化测试、Runtime/MiniApp/Host 代码、SDK 契约、Manifest 和真实浏览器路径。 > 评审方式:主 agent 交叉检查 + 独立子 agent 只读验收;检查构建、自动化测试、Runtime/MiniApp/Host 代码、SDK 契约、Manifest 和真实浏览器路径。
> 总体结论:本轮 P0~P3 问题已完成修复,并通过代码、自动化测试和真实浏览器闭环检查;独立验收 agent 已确认本迭代可以标记为“已完成”。 > 总体结论:本轮 P0~P3 问题已完成修复,并通过代码、自动化测试和真实浏览器闭环检查;独立验收 agent 已确认本迭代可以标记为“已完成”。
@@ -3,7 +3,7 @@
> 评审编号:05 > 评审编号:05
> 评审日期:2026-08-06 > 评审日期:2026-08-06
> 评审对象:[03.sdk_and_coreapp.md](03.sdk_and_coreapp.md) > 评审对象:[03.sdk_and_coreapp.md](03.sdk_and_coreapp.md)
> 架构基线:[APP架构设计.md](../../APP架构设计.md) > 架构基线:[APP架构设计.md](../../设计/APP架构设计.md)
> 参考评审:[04.acceptance_review.md](04.acceptance_review.md) > 参考评审:[04.acceptance_review.md](04.acceptance_review.md)
> 评审方式:独立子 agent 只读验收 + 主 agent 逐项复核;检查当前代码、Manifest、SDK 契约、自动化测试、构建和文档证据。 > 评审方式:独立子 agent 只读验收 + 主 agent 逐项复核;检查当前代码、Manifest、SDK 契约、自动化测试、构建和文档证据。
> 总体结论:本轮发现的 P3 契约/证据问题均已逐项修复并分别提交;当前没有遗留 P0~P3 问题。 > 总体结论:本轮发现的 P3 契约/证据问题均已逐项修复并分别提交;当前没有遗留 P0~P3 问题。
@@ -0,0 +1,120 @@
# 04.runtime_workspace 设计评审(一)
**评审编号:** 01
**日期:** 2026-08-06
**评审对象:** [04.runtime_workspace.md](04.runtime_workspace.md)、[03.sdk_and_coreapp.md](../03.sdk_and_coreapp/03.sdk_and_coreapp.md)、[01.kernel.md](../01.kernel/01.kernel.md)、[00.base.md](../00.base/00.base.md)、[plan.md](../plan.md)、[APP架构设计.md](../../设计/APP架构设计.md)
**评审方法:** 对照既有 Runtime 所有权、SDK v1、Tool、生命周期、App 子会话和 Web/Tauri Host 契约,检查第 04 次迭代是否引入相互矛盾或无法按既有边界实现的设定。
**总体结论:** 第 04 次迭代对 MiniApp 隔离、Interact 标准交互、关闭收口和 Host 基线的方向与第 03 次迭代及权威架构一致。Pomodoro 已收敛为 Agent 直接启动的单次专注 operationRuntime 托管 instance state、deadline 和唯一结果;Pomodoro 只渲染与请求退出。D04-01~D04-05 已回填主定义或总体计划,所有 P0~P3 设计问题已清零;D04-06 是有明确触发条件的 P5 遗留项,不阻塞实施。
## 问题清单(Outline
状态标记:🔴 未解决,必须处理;🟡 已提出修复方向,尚未确认或落入主定义;✅ 已解决;⚪ 可延期但必须保留记录。P0~P3 必须在当前迭代处理;P4~P5 可以延期,但必须记录延期原因和重新评估条件。
| 状态 | 优先级 | 编号 | 问题 | 当前结论 / 下一步 |
|---|---:|---|---|---|
| ✅ | P1 | D04-01 | Pomodoro 状态由 Runtime 保存,但 Runtime 又“不解释番茄钟业务”;SDK v1 没有对应的私有状态持久化/恢复契约 | Runtime 已在正式方案中定义按 `app_scope + instance_id` 隔离、Manifest schema 校验、revision 控制的业务状态快照;04 已明确 operation 与 instance state 的不同事实来源和最小数据。 |
| ✅ | P1 | D04-02 | 用户暂停/继续/取消与 Agent Tool 的关系未定义;现有 `sdk.tools.*` 只能终结 Runtime 已投递的 Agent Tool | 已收敛为 Agent Tool `pomodoro.start`(长操作)和 `pomodoro.interrupt`(短操作);不支持暂停/继续。用户以语言请求停止时由 Agent 调用 interrupt;切换/关闭由 Runtime 生命周期以相同规则中断,均不伪造 Agent Tool。 |
| ✅ | P1 | D04-03 | “后台继续计时、到点回传、重启按 `ends_at` 恢复”没有 Runtime deadline 裁决和 Tool 终态规则 | 已确定 Runtime deadline operation 是唯一裁决者:持久化 `ends_at`,到点/中断竞争一个原子终态,唯一 result/outbox;重启已到点结算一次,进程未运行时不承诺即时提醒。 |
| ✅ | P2 | D04-04 | “创建或恢复 App 子会话”与“新 instance 必须新子会话”、以及关闭后 pending Interact 问题仍可回答的既有规则未完整写出 | 已明确仅恢复同一个未结束 instance 才复用子会话;关闭后子会话只读,pending Interact 问题留在主 IM 等待且不得追加到旧子会话;验收已加入该场景。 |
| ✅ | P3 | D04-05 | 总体计划把 Pomodoro 写成第 03 次迭代已完成的参考 MiniApp,并要求第 04 次工作区可切换 Whiteboard;第 04 次定义却将 Pomodoro 作为新验证应用且只承诺 Interact/Pomodoro 切换 | 已更新 `plan.md`:第 03 次参考实现只含 Task Dashboard / WhiteboardPomodoro 在第 04 次引入。Whiteboard 本轮仅保持第 03 次回归,不接入工作区切换或完成范围。 |
| ⚪ | P5 | D04-06 | 未来是否将 SDK 的实现迁入 Rust 层以提升运行效率 | **延期讨论:** 当前没有性能瓶颈证据,且 Web Reference Host / sandbox iframe 中的 SDK 与 UI Bridge 必须保留 TypeScript/浏览器侧实现。未来可评估把状态存储、schema 校验、deadline 调度、Tool/outbox 原子收口等无 UI Runtime Core 下沉到 Rust。重新评估触发:profiling 证明这些路径是热点,或 Rust Runtime Core 成为跨 Host 的正式实现边界。 |
## 通过项
- **信任与隔离没有倒退。** 第 04 次迭代将 Pomodoro 定为 `bundled`,要求受限 Surface/SDK,禁止访问 Transport、Store、Agent、Host DOM、Tauri 和系统能力。这与权威架构对 bundled MiniApp 的限制一致,也避免了第 03 次验收已修复的“业务逻辑回到可信 Host JS”问题。
- **Interact 的归属正确。** `notice / choice / confirm / input` 仍由 Interact 呈现;Pomodoro 前台时仅允许 Interact 覆盖层,视觉位置不改变 owner。这符合既有“标准交互不属于 MiniApp SDK”的规则。
- **关闭收口正确。** 文档保留“停止新普通 Tool 投递 → 未终态 Tool 收敛为 `cancelled(app_closed)` → 已 submitted 结果继续 outbox → 恢复有效前台 App”的顺序;也没有把 Tool 完成错误地等同于关闭 App。
- **Host 范围正确。** Web Reference Host 与 Tauri Desktop Host 作为同一 Runtime/MiniApp 代码的两种 Host 验收,与权威架构一致。
## D04-01:状态所有权与持久化边界未定义
**已解决(2026-08-06)。** 正式方案已增加 `app.instance-state.v1`Runtime 为当前
`app_scope + instance_id` 托管 Manifest schema 校验、revision 控制和 lifecycle 清理的业务状态快照。
本迭代已将 Pomodoro 的 instance snapshot 与 deadline operation 分开:前者服务 UI 恢复,后者是
`ends_at`、Tool 终态和 outbox 的唯一事实来源。以下为发现时的风险分析。
第 04 次定义要求 Runtime“保存计时状态和工作区快照”,并要求 Pomodoro 根据 Runtime 状态刷新;同时又规定 Runtime 不解释番茄钟业务,Pomodoro 负责暂停、继续和取消。它给出的 `timer_id``duration_seconds``started_at``ends_at``remaining_seconds``state` 正是需要跨刷新和重启持久化的业务状态。
但既有 SDK v1 只开放 Inbox、Agent Tool 的 `progress / complete / fail / cancel`、生命周期、Surface 与 Capability。它不提供 MiniApp 私有状态的读取、schema 校验写入、版本迁移或恢复快照 API;并且 Runtime 是 Conversation Store 的唯一所有者,bundled iframe 不能直接写它。若不补契约,实现只能在两条均违反边界的路径中选择:由 Runtime 写死 Pomodoro 的字段/状态机,或由 MiniApp 自己绕过 SDK 访问持久化。
建议把 Runtime 的职责限定为通用的、按 instance 隔离的持久化容器和 deadline-operation 调度,而非理解“番茄钟”。Pomodoro Manifest 应声明其状态 schema 和可恢复 operation schemaMiniApp 通过一个最小、受 Runtime 校验的 SDK 请求提交状态变更;Runtime 负责原子持久化、恢复投影和审计元数据。主定义还应说明:`remaining_seconds` 是派生展示值,还是暂停时的持久化事实值,避免与 `ends_at` 双事实源冲突。
## D04-02:用户控制动作没有合法的 SDK 入口
**已解决(2026-08-06,后续澄清)。** Pomodoro 接受 Agent 的长期 Tool `pomodoro.start` 和短 Tool
`pomodoro.interrupt`;用户不再有暂停或继续入口。用户以 IM / Voice 表达“停止/结束这次专注”时,由 Agent
调用 `pomodoro.interrupt({})`;Runtime 只从该调用所在会话绑定当前 `focusing` instance,负责路由与唯一终态
裁决。切换工作区和关闭则由 Runtime 生命周期以同一中断规则处理,但不伪造 Agent Tool。Runtime 只接受第一
次有效中断;重复/迟到调用只返回稳定回执,不能改写终态或直接写第二条 outbox。以下为发现时的备选分析。
第 04 次迭代要求用户在 Pomodoro 内暂停、继续、取消;又列出 `pomodoro.start / pause / resume / cancel / status`。前置契约中,`sdk.tools.*` 表示 MiniApp 对 Runtime 已投递的 Agent Tool Call 报告进度或唯一终态,不能被用于任意用户动作,更不能由 bundled MiniApp 自行构造 Agent call 或写 outbox。
因此必须先选择并写清一个模型:
1. `pomodoro.pause / resume / cancel / status` 都是 Agent 可调用 Tool,用户点击只请求 Runtime 执行相同的已声明 MiniApp command;或
2. 只有 `pomodoro.start` 是长操作 Tool,用户动作是独立的实例内 command,不会伪造额外 Agent Tool,Runtime 可按产品协议选择是否产生状态事件;或
3. 另一种明确的、同样受 Manifest、schema、instance 和幂等校验约束的模型。
无论选择哪种,需给出 command ID、输入/输出 schema、目标 `instance_id`、重复点击行为、状态非法时的稳定拒绝码,以及关闭竞态下命令被拒绝还是已持久化。否则 Web/Tauri 两个 Host 会分别把按钮实现为局部状态或直接 Tool 操作,无法证明 Runtime 的唯一所有权。
## D04-03:后台/重启到点完成缺少唯一裁决者
**已解决(2026-08-06)。** Runtime 的通用 deadline operation 持久化绝对 `ends_at`;到点、用户中断和
关闭竞争同一原子终态,先成功者产生唯一 Tool result/outbox。自动暗屏、锁屏和 Surface 重载不终止专注;
重启发现已到点时只结算一次。Runtime / Host 完全未运行时不承诺即时提醒。以下为发现时的风险分析。
“后台继续运行”在受限 iframe 不等于存在可靠的定时器:Surface 可能卸载、浏览器页面可能被节流,进程也可能在 deadline 前后重启。仅在 UI 中 `setTimeout` 会导致漏完成、重复完成或把全时长重新开始。第 04 次虽然正确要求重启按 `ends_at` 计算剩余时间,却没有定义 Runtime 在何时把 operation 原子转为 `completed`、谁完成关联 Tool、以及同时发生暂停、取消、App close、恢复和 deadline 时谁胜出。
建议新增一个通用 Runtime deadline-operation 状态机。运行中的 operation 持久化绝对 `ends_at`;恢复时 Runtime 用当前时间重新计算,若已到期则以一次原子转换完成并写唯一 result/outbox,若未到期则投影更新。暂停把剩余时长固化并清除/失效 deadline;恢复从新的 deadline 开始。接受 `AppLifecycleManager.close` 时,先让关闭取得与 operation 完成相同的终态竞争权:先完成者生效,另一个仅收到稳定幂等回执。这样 Runtime 仍不需要知道“番茄钟”,只实现可复用的 deadline 可靠性。
还须明确第一版“App 内完成提示”的含义:它应由 MiniApp 在收到 Runtime 已完成状态时显示;系统通知仍不在范围内。若运行进程完全不存在,到点时不承诺即时可见提示,但下次 Runtime/Host 可运行时必须按已到期状态恢复,不能重置或重复回传。
## D04-04:子会话复用、只读与关闭后问题的措辞不完整
**已解决(2026-08-06)。** 主定义已限定:只有恢复同一个未结束 instance 才能复用子会话;关闭后子会话
只读。仍 pending 的 Interact 标准交互保留在主 IM 中等待回答、dismiss、超时或 Runtime 失败,且不得向
已结束子会话追加记录。以下为发现时的风险分析。
前置契约只允许在“恢复同一个未结束 instance”时复用同一个 App 子会话;以后启动的每个新 instance 都必须新建子会话。第 04 次的“创建或恢复 App 子会话”没有限定这一前提,容易被实现为按 `app_scope` 或旧子会话复用,和“继续处理新建 instance / 新子会话”冲突。
另外,既有规则规定 App 真正关闭后:子会话结束并成为只读历史,仍 pending 的标准交互不被取消,留在 Interact/主 IM 中等待回答、dismiss、超时或 Runtime 失败。第 04 次仅说“已结束子会话只读”,没有写出这个例外;若把回答追加进已关闭子会话,就破坏只读,若关闭时取消问题,又违反 Interact 归属规则。
建议在第 04 次的子会话章节和验收中逐字继承这一关闭后路径,并加一条自动化场景:Pomodoro 关闭时存在带 `app_session_context` 的 pending `choice`,App 覆盖层消失、子会话只读、用户仍可在主 IM 回答,且产生一次结果/outbox。
## D04-05:计划与第 04 次最小范围相互矛盾
**已解决(2026-08-06)。** 总体计划已将 Pomodoro 从第 03 次已完成参考实现中移除,明确它在第 04 次
作为 Agent 直接启动的专注验证应用引入;Whiteboard 在本轮仅保持第 03 次已有回归,不参与工作区切换、
完整闭环或完成验收。以下为发现时的风险分析。
`plan.md` 说第 03 次已完成的参考 MiniApp 包含 Pomodoro,但第 03 次主定义及其验收对象是 Interact、Task Dashboard 和 Whiteboard;第 04 次又明确把 Pomodoro 选为本轮验证应用。与此同时,计划要求第 04 次工作区支持 Interact、Pomodoro、Whiteboard 切换,而第 04 次主定义只承诺 Interact/Pomodoro。
这不会改变底层架构,却会直接导致实现范围、浏览器验收用例和“第一条完整用户流程”的判断不一致。建议以第 04 次主定义选择的“单一 Pomodoro 闭环”为基准:将计划中的“Pomodoro 已完成参考实现”改成“Pomodoro 在第 04 次引入”;对白板明确标注为本轮仅保持既有回归,或若确实要求可切换则把它加入第 04 次工作内容、验收和时间预算。
## D04-06SDK 是否迁入 Rust 层(P5,后续讨论)
这是值得保留的性能和实现演进方向,但当前没有证据表明它阻塞第 04 次迭代。需要先分清 SDK 的
协议/能力语义和 SDK 的运行位置:协议必须跨 Host 保持一致,具体实现不必全部使用同一种语言。
```text
必须留在 TypeScript / 浏览器侧的部分
→ Web Reference Host、bundled MiniApp 的 sandbox iframe、postMessage Surface Bridge、DOM 与 UI 渲染。
适合未来评估迁入 Rust 的 Runtime Core 部分
→ 状态快照持久化、schema 校验、revision 比较、deadline operation 调度、Tool/outbox 原子终态、
生命周期收口和审计。
```
如果把全部 SDK 都迁入 Rustbundled MiniApp 仍必须经浏览器 Bridge 调用 Runtime,反而可能增加
Tauri IPC、序列化和跨语言错误处理开销;它不能替代 Web Reference Host 中必须运行的 TypeScript Bridge。
因此候选方向是“保持版本化 SDK 契约与 TypeScript Surface API,按需把 Runtime 的无 UI 核心实现下沉到 Rust”,
而不是把 MiniApp SDK 整体替换为 Rust。
重新评估前必须先有可重复的 profiling 证据,包括:状态快照读写频率与耗时、deadline/Tool 路由吞吐、主线程
阻塞、Tauri IPC 往返、JSON 序列化成本以及 Web/Tauri 两个 Host 的差异。只有收益大于跨 Host 实现、测试、
调试和错误边界的复杂度时,才为此创建独立设计和迁移迭代。
## 设计就绪条件
D04-01D04-05 已形成决议并回填到 [04.runtime_workspace.md](04.runtime_workspace.md) 与
[plan.md](../plan.md)。所有 P0~P3 设计问题已清零;D04-06 作为 P5 carryover 保留,不阻塞本迭代。
@@ -0,0 +1,178 @@
# 04.runtime_workspace 设计评审(二)
**评审编号:** 02
**日期:** 2026-08-06
**评审对象:** [04.runtime_workspace.md](04.runtime_workspace.md)(实施权威)、[01.design_review.md](01.design_review.md)、[00.base.md](../00.base/00.base.md)、[01.kernel.md](../01.kernel/01.kernel.md)、[03.sdk_and_coreapp.md](../03.sdk_and_coreapp/03.sdk_and_coreapp.md)、[plan.md](../plan.md)、[app_final_design.md](../../设计/02.正式方案/app_final_design.md)、[lineup-runtime-sdk-architecture.md](../../设计/02.正式方案/lineup-runtime-sdk-architecture.md)、[lineup-app-layer-architecture.md](../../设计/02.正式方案/lineup-app-layer-architecture.md)。
**评审方法:** 独立地以第 04 次迭代定义为实现依据,逐项回溯前三次迭代和正式 Runtime 契约;重点检查 instance state / deadline operation 的所有权、`pomodoro.start` 与用户中断的终态竞争、离开/暗屏/重启、App 子会话与 pending Interact、Whiteboard 范围和 Rust P5 延期。
**总体结论:** D04-01D04-09 已确认的方向均已被第 04 次主定义或计划正确吸收:业务快照与 deadline operation 分离、Agent Tool `pomodoro.start` / `pomodoro.interrupt`、到点/中断原子终态、暗屏/锁屏不等于离开、子会话只读与 pending Interact 留在主 IM、Whiteboard 不进入本轮闭环、Rust 仅为 P5 后续评估。D04-07 已澄清为 Agent Tool 路由契约;D04-08 已选择“立即收口、由 Interact 呈现完成结果”;D04-09 已选择 `retain_readonly` 快照保留策略。所有 P0~P3 设计问题已清零,本迭代设计已就绪,待实施。
## 问题清单(Outline
状态标记:🔴 未解决,必须处理;🟡 已提出修复方向,尚未确认或未回填实施权威;✅ 已解决;⚪ 可延期但必须保留记录。P0~P3 必须在当前迭代处理;P4~P5 可以延期,但必须记录延期原因和重新评估条件。
| 状态 | 优先级 | 编号 | 问题 | 当前结论 / 下一步 |
|---|---:|---|---|---|
| ✅ | P1 | D04-07 | `pomodoro.interrupt` 的调用方向与目标绑定未明确。 | 已确定为 Pomodoro 在 Manifest 中声明、由 Agent 调用的短 Tool;Runtime 从调用会话绑定当前 focusing operation,负责路由、原子裁决和稳定回执。 |
| ✅ | P1 | D04-08 | `completed` 后既要求 Pomodoro 显示自身完成提示,又在主流程中要求 Runtime 收口关闭 App、恢复 Interact;没有定义两者的顺序和触发者。 | 已选择立即收口:Runtime 原子完成并投递唯一结果/outbox 后立即关闭 Pomodoro、结束子会话、恢复 Interact;完成提示由 Interact / Agent 呈现。 |
| ✅ | P2 | D04-09 | Pomodoro 要保存 instance snapshot,但没有声明其 `app.instance-state.v1` Manifest 配置、schema 版本/字段、配额和 `retention` 选择。 | 已确定 `app.instance-state.v1` 最小 Manifest:严格 schema v1、4 KiB 配额、`retain_readonly`。关闭后旧快照只作历史展示,不可写入、不可复活为 focusing。 |
| ✅ | — | D04-C1 | instance state 与 deadline operation 的事实来源和持久化边界 | 已正确同步;不构成新问题。 |
| ✅ | — | D04-C2 | `pomodoro.start`、到点/中断竞态和 outbox 唯一性 | 已正确同步;D04-07 补足 Agent Tool 的路由与目标绑定契约。 |
| ✅ | — | D04-C3 | 用户离开、自动暗屏/锁屏、Surface 重载和重启 | 已正确同步;不构成新问题。 |
| ✅ | — | D04-C4 | App 子会话、只读历史和 pending Interact | 已正确同步;不构成新问题。 |
| ✅ | — | D04-C5 | Whiteboard 第 04 次范围 | 已正确同步到主定义和 `plan.md`;不构成新问题。 |
| ⚪ | P5 | D04-C6 | Runtime Core / SDK 是否迁入 Rust | 已保留为延期项;当前不应扩大到本轮实现。重新评估条件仍为 profiling 证明 Runtime Core 是性能热点。 |
## 通过项与一致性证据
### D04-C1instance state 与 deadline operation 的边界已一致
主定义第 2.2、2.3 和第 3 节将 Runtime 定为 schema/revision 受控的 instance snapshot 保存者,同时将
`ends_at`、Tool 终态和 outbox 交给 deadline operation`remaining_seconds` 仅由 UI 按绝对截止时间派生。
这与正式方案的明确边界一致:`app_scope + instance_id` 隔离状态快照,快照不能完成 Tool、写 outbox、改变
焦点或绕过 lifecyclePomodoro 的到期/中断和唯一 Tool result 必须由 Runtime deadline operation 裁决。
这也没有把静态 IM/App 子会话误当作 MiniApp 业务存储:第 04 次主定义仍只让子会话记录人与 Agent 的交互和
结果,符合第 03 次“App 子会话不是 App 操作日志”的规则。
### D04-C2Agent Tool 的终态竞争与 outbox 所有权已一致
第 04 次主定义将 `pomodoro.start({ duration_seconds, activity? })` 定义为长期 Agent operation,并由 Agent
调用短 Tool `pomodoro.interrupt({})` 请求停止当前专注;到点、Agent 中断和关闭竞争一个原子终态,第一成功者
产生一次结果/outbox;重复或迟到的中断只获得稳定幂等回执。
这符合第 03 次对 Tool/交互的“Runtime 原子终态 + 唯一 outbox”模式,也符合正式方案中 App 不能自行完成
Tool 或写 outbox 的限制。D04-07 已补足:用户以语言提出停止意图后,Agent 调用 Pomodoro 声明的 Tool
Runtime 而非 MiniApp 界面负责最终裁决。
### D04-C3:离开、自动暗屏、重启的产品语义已一致
主定义已清楚区分:用户切回 Interact、切到其他 MiniApp 或关闭 Pomodoro 会中断;自动暗屏、锁屏、Surface
重载不会中断;重启按持久化 `ends_at` 恢复或一次性结算;Runtime/Host 完全未运行时不承诺即时系统提醒。
这不再依赖 iframe/UI 定时器,且没有把来电检测、系统免打扰、静音或系统通知偷偷纳入第 04 次范围。
### D04-C4App 子会话和 pending Interact 已一致
主定义限制“仅恢复同一个未结束 instance 时复用同一个子会话”;结束后子会话只读;关闭时仍 pending 的
Interact 标准交互留在主 IM/Interact 中,回答不得追加到旧子会话。该规则与第 03 次的 instance 生命周期、
`pending_interaction_call_ids` 和“关闭不自动取消 Interact 交互”规则一致。前台 Pomodoro 上的 Interact
覆盖层也没有改变交互 owner。
### D04-C5Whiteboard 范围已消除冲突
`04.runtime_workspace.md` 第 5 节与 `plan.md` 第 3 节均明确:Whiteboard 只保持第 03 次已完成的 SDK/隔离
回归,不接入第 04 次工作区切换或完整用户流程;Pomodoro 才是本轮唯一新增的工作区闭环验证应用。
### D04-C6Rust 为正确的 P5 carryover
主定义明确本轮保持 TypeScript Runtime / Web Bridge 基线,且仅在 profiling 已证明 Runtime Core 是热点后另行
评估。该范围不会破坏 Web Reference Host、sandbox iframe、postMessage Bridge 和 UI 必须保留在浏览器侧的
既有边界。
## D04-07:用户中断的 Agent Tool 路由契约
**已解决(2026-08-06,用户决议)。**
`pomodoro.interrupt` 不是 MiniApp 通过 SDK 主动发送的 Runtime command,而是 Pomodoro 在 Manifest 中声明、供
Agent 调用的短 Tool。用户主要经 IM / Voice 向 Agent 表达业务意图;MiniApp 是 Agent 的业务工具,而不是
用户直接操作业务状态的独立应用。Tool Router 从该 Tool 调用的 `conversation_id` 自动绑定当前唯一
`focusing` Pomodoro operation,调用者不能提供 `instance_id``app_scope``operation_id`。Runtime 路由调用、
在与 deadline/close 相同的原子裁决中将长 Tool `pomodoro.start` 收口为 `interrupted`,并给短 Tool 返回
`interrupted``no_active_focusing_operation``operation_already_final` 的稳定回执。若 Surface 不在,Runtime
仍可完成裁决;若存在,只投影最终状态。用户直接离开工作区仍由 Runtime 生命周期中断处理,不伪造 Agent Tool。
以下为发现时、尚未澄清调用方向的风险分析。
第 04 次主定义第 3 节规定用户显式退出通过受限 SDK Runtime command
`pomodoro.interrupt(reason = "user_exit")` 请求;又规定 Runtime 仅接受当前 `focusing` instance 的第一次有效
中断,迟到请求返回幂等回执。这个产品语义正确,但尚不足以决定 SDK/Bridge、Web Host 和 Tauri Host 应如何
实现同一动作。
现有正式 SDK 的唯一通用出站入口是 `actions.dispatch(action: AppAction)`,但没有定义 `AppAction`
schema、Command type、由 context 派生的 instance 绑定、receipt 格式或稳定拒绝码。第 03 次冻结的 Manifest
也只定义 Agent Tool`direct / launch / foreground / operation`)和 `AppNavigationAPI.close`;它没有把
业务 MiniApp 任意命令自动变成合法 Agent Tool。若不冻结该层,至少会出现两种相互冲突的实现:MiniApp 用
`sdk.tools.complete/fail` 伪造 `pomodoro.start` 终态,或 Web/Tauri Host 在 UI 侧直接关闭实例;两者都绕开
了 Runtime 的 deadline/outbox 原子裁决。
建议在主定义中明确一个最小、仅 Runtime 可执行的 command,例如概念上:
```ts
type PomodoroInterruptCommand = {
type: "pomodoro.interrupt";
reason: "user_exit";
// instance_id、app_scope、conversation_id 从不可伪造 SDK context 推导,调用者不得传入。
// Runtime 从当前 instance 关联的 operation / source_tool_call_id 查找目标。
};
type PomodoroInterruptReceipt =
| { accepted: true; operation_id: string; state: "interrupted" }
| { accepted: false; code: "operation_already_final" | "operation_not_focusing" | "instance_closing" };
```
实际字段命名可以不同,但必须同时冻结以下规则:调用者只能操作自己的当前 instance;谁提供或由 Runtime
生成幂等键;`focusing`、deadline、`closing` 与已终态各自的稳定回执;以及 command、deadline 与
`AppLifecycleManager.close` 如何在同一持久化事务或等价 compare-and-set 中竞争唯一终态和唯一 outbox。
Host 的“返回/切换/关闭”应调用同一个 Runtime 内部操作,而不是从 Surface 绕过该 Command。
## D04-08:完成提示与关闭的顺序未定义
**已解决(2026-08-06,用户决议:方案 B)。** Runtime 到达 `ends_at` 后,先原子写入 `completed`、唯一
`pomodoro.start` 结果与 outbox;随后立即关闭 Pomodoro、结束 App 子会话并恢复 Interact。Pomodoro 不显示
独立的完成提示;完成结果由 Interact / Agent 呈现。关闭后的 outbox 重试不依赖 Pomodoro Surface,且不得再次
完成 Tool。完成与关闭并发时,已提交的 `completed` 终态不得被 `cancelled(app_closed)` 改写。
以下为决议前的风险分析。
主定义同时作出了两项要求:Pomodoro 到时间“显示自己的完成提醒”(第 2.3、3、4.4 节),迭代目标的主流程又
写为“到时间显示完成提醒并回传结果 → Runtime 收口并关闭 App,恢复 Interact”。但它没有规定完成态是否先
投影给仍存活的 Surface、提示展示多久或由谁确认、何时调用 `AppLifecycleManager.close`、以及 App 子会话在
哪个时点结束。
这是可观测行为的分歧,不是纯 UI 细节。若 Runtime 原子完成后立即按一般收口关闭 instanceSurface 会先被
卸载,Pomodoro 无法兑现“App 内完成提示”;若 UI 本地自行显示后再关闭,则可能在重启、旧 Surface 或重复
回调下与已提交 outbox 脱节。第 03 次的既有规则还区分“Tool 完成不自动关闭 App/子会话”和
`AppLifecycleManager.close` 才结束子会话;第 04 次为 Pomodoro 采用不同的自动关闭策略是允许的,但必须
明确这是 Pomodoro 的特例及其顺序。
建议二选一并写入工作内容、恢复规则和验收:
1. **保留完成展示窗口。** deadline operation 原子写 `completed` 和唯一 result/outboxRuntime 将终态投影给
PomodoroSurface 在一个明确的受控窗口内显示完成提示;窗口结束、用户确认或用户离开后由 Runtime 发起
`AppLifecycleManager.close`,再结束子会话并恢复 Interact。重启落在窗口内时须能按持久化终态恢复到同一
收口路径,而不得再写结果。
2. **立即收口。** Runtime 完成后立刻关闭 App、结束子会话、恢复 Interact;删除“Pomodoro 显示自己的完成
提示”,或将完成提示明确改为 Interact 的可信呈现而非已关闭 MiniApp 的 UI。
无论选择哪种,验收都应覆盖 `completed` 与 close 并发、已提交 outbox 的重试、终态 UI 不产生第二次 Tool
完成,以及完成前/后 pending Interact 的归属。
## D04-09Pomodoro 的 instance-state Manifest 与关闭后保留策略未确定
**已解决(2026-08-06,用户决议:方案 B)。** Pomodoro 声明 `app.instance-state.v1`,使用严格的 schema
version 1、4 KiB 配额和 `retain_readonly`。快照只保存 UI/历史展示所需的活动、关联 operation、时间和展示
状态;operation 仍是终态、deadline 与 outbox 的唯一事实来源。App 关闭后,旧快照仅供只读历史展示,不能
再写入、不能恢复为 `focusing`,也不能作为新一轮专注的运行状态。
以下为决议前的风险分析。
主定义要求 Pomodoro 通过 SDK 保存展示所需的 instance snapshot,并列出可能字段;正式 Runtime 契约则规定
只有声明 `app.instance-state.v1` 的 Manifest 才能使用 schema/revision 受控状态,并要求声明
`state_schema_version``state_schema``max_bytes``retention`。第 04 次定义尚未选择 Pomodoro 的实际
Manifest 配置,也没有说明关闭后应使用默认 `delete_on_close` 还是 `retain_readonly`
这会直接改变重启/关闭后的可见行为和验收:`delete_on_close` 允许完成或中断时清理 UI snapshot,而历史由
App 子会话和 Tool/operation 记录承载;`retain_readonly` 会保留一个不可写旧 snapshot,只能作为历史或新
instance 的受控上下文。两者都可以符合产品目标,但实现、fixture 和隐私/清理预期不同;不能靠默认值隐式
决定。
建议主定义补一份 Pomodoro 的最小 Manifest 片段或等价表格:required feature、严格 schema(至少允许的展示
字段)、schema version、最大大小和明确 retention。还应说明完成/中断/关闭时 instance snapshot 与 deadline
operation、App 子会话、Tool/outbox 的独立清理顺序,确保“保留 UI 状态”不会被误解为旧 instance 可恢复为
`focusing` 或可再次写入。
## 评审关闭条件
- D04-07D04-09 已回填本轮实施权威 [04.runtime_workspace.md](04.runtime_workspace.md) 和
[plan.md](../plan.md);实施时须依照已冻结的 Tool、完成收口和 Manifest 契约提供 fixture 与自动化验收;
- D04-C6 继续作为 P5 carryover 留在本记录与第一轮记录中;没有 profiling 证据前,不把 Rust 迁移纳入当前
实现范围;
- 本评审只记录发现和建议,未修改第 04 次主定义、正式方案、计划或实现。
@@ -0,0 +1,153 @@
# 04.runtime_workspace 设计评审(三)
**评审编号:** 03
**日期:** 2026-08-06
**评审对象:** [04.runtime_workspace.md](04.runtime_workspace.md)(实施权威)、[01.design_review.md](01.design_review.md)、[02.design_review.md](02.design_review.md)、[00.base.md](../00.base/00.base.md)、[01.kernel.md](../01.kernel/01.kernel.md)、[03.sdk_and_coreapp.md](../03.sdk_and_coreapp/03.sdk_and_coreapp.md)、[plan.md](../plan.md)、[app_final_design.md](../../设计/02.正式方案/app_final_design.md)、[lineup-runtime-sdk-architecture.md](../../设计/02.正式方案/lineup-runtime-sdk-architecture.md)、[lineup-app-layer-architecture.md](../../设计/02.正式方案/lineup-app-layer-architecture.md)。
**评审方法:** 独立以第 04 次主定义作为唯一实施依据,对照前置迭代冻结的 Manifest / Tool Descriptor / 生命周期契约和正式 Runtime 方案。只记录会使本轮实现或验收无法得到唯一结论的问题;不把 Rust 演进、系统通知、真实语音、Whiteboard 工作区或其他范围外设想重新升级为当前问题。
**总体结论:** 已确认的核心方向保持一致:MiniApp 是 Agent 的业务工具;`pomodoro.start` / `pomodoro.interrupt` 由 Agent 调用;deadline、Agent 中断和生命周期中断由 Runtime 原子裁决;完成后立即关闭并由 Interact 呈现;快照采用 `retain_readonly`;子会话和 pending Interact 的归属规则正确;Whiteboard 和 Rust Core 均未误入本轮范围。D04-10~D04-12 已按收敛决议回填:两个 Tool 已有最小可发布 Descriptor,同一会话只允许一轮 `focusing` 专注,当前验收入口限定为 IM、未来 Voice 只复用语义。所有 P0~P3 设计问题已清零,本迭代设计就绪,待实施。
## 问题清单(Outline
状态标记:🔴 未解决,必须处理;🟡 已提出修复方向,尚未确认或未回填实施权威;✅ 已解决;⚪ 可延期但必须保留记录。P0~P3 必须在当前迭代处理;P4~P5 可以延期,但必须记录延期原因和重新评估条件。
| 状态 | 优先级 | 编号 | 问题 | 当前结论 / 下一步 |
|---|---:|---|---|---|
| ✅ | P1 | D04-10 | 已命名 `pomodoro.start` / `pomodoro.interrupt`,但尚未给出能进入 Agent Inventory 的完整 Tool Descriptor,也未明确短 Tool 的 Runtime 与 Pomodoro 各自承担的处理步骤。 | 已冻结两个 Tool 的 v1 Descriptor:输入 / 输出 schema、调用模型、启动/前台策略、超时/幂等和 Runtime 优先的原子裁决顺序。 |
| ✅ | P1 | D04-11 | `interrupt` 假定每个会话只有一个 `focusing` operation,但再次收到同一会话的 `pomodoro.start` 时的规则没有定义。 | 已确定同一 `conversation_id` 只允许一轮 `focusing` operation;不同 call 的第二次 start 稳定拒绝为 `active_focusing_operation`,不创建任何新资源。 |
| ✅ | P2 | D04-12 | 主定义和验收把“IM 或 Voice”写为当前可验收入口,但本迭代明确不实现真实 Audio Mode。 | 已限定第 04 次仅以 IM 验收完整闭环;未来 Voice 复用同一意图和 Tool 语义,不要求本轮实现或验收。 |
| ✅ | — | D04-C7 | Agent 驱动、唯一终态与 outbox | `pomodoro.interrupt` 已不再被误作用户直接 SDK commandAgent Tool、deadline 和 lifecycle 共同进入 Runtime 的原子终态裁决,第一结果唯一。D04-10 仅补 Tool Descriptor 层,未推翻此决议。 |
| ✅ | — | D04-C8 | 完成后的工作区和会话收口 | 已确定 `completed` 后 Runtime 写唯一结果 / outbox,立即关闭 Pomodoro、结束子会话、恢复 Interact;不保留 Pomodoro 完成页。 |
| ✅ | — | D04-C9 | 业务快照、子会话与 Interact | snapshot 只作 UI / 历史展示,`retain_readonly` 旧实例不可写、不可复活;已结束子会话只读,pending 标准交互留在主 IM。 |
| ✅ | — | D04-C10 | 当前范围 | Whiteboard 仅保持第 03 次 SDK / 隔离回归;系统通知、来电检测、免打扰和真实 Audio Mode 均不在第 04 次范围。 |
| ⚪ | P5 | D04-C11 | Runtime Core 是否下沉 Rust | 已在 `plan.md` 留作后续方向;没有 profiling 证明状态、deadline、Tool/outbox 或 lifecycle 是热点之前,不进入第 04 次实施。重新评估触发条件不变。 |
## 已确认的一致性
### Agent 是业务入口,Pomodoro 不是用户直接操作的独立 App
主定义第 2、3 节已清楚表达:用户用当前 IM(未来可用 Voice)向 Agent 说明开始或停止的意图;Agent 调用
Pomodoro Manifest 声明的 ToolPomodoro 本身只显示和接收 Runtime 投影,不设置暂停、继续或结束专注的业务按钮。
这与前置迭代“Agent Tool 经 Runtime Tool Router 和动态 Inventory 调用、bundled App 不直连 Agent”的边界一致。
### 三种结束来源已有共同的可靠收口点
到达 `ends_at`、Agent 调用 `pomodoro.interrupt({})`、用户返回 Interact / 切换 App / 关闭工作区,已明确竞争同一
Runtime 原子终态。先成功者把长期 `pomodoro.start` 收口为 `completed``interrupted`,并只产生一次结果和
outbox;迟到事件获得稳定回执。自动暗屏、锁屏与 Surface 重载不是退出,刷新或重启按绝对 `ends_at` 恢复或结算。
这符合 Runtime 对 operation、outbox、焦点与生命周期拥有最终权力的正式架构。
### 完成、历史和 Interact 归属已经无冲突
完成路径已选择“立即收口”:Runtime 原子完成后立即关闭 Pomodoro、结束子会话并恢复 Interact,由 Interact /
Agent 呈现结果。`app.instance-state.v1` 的 snapshot 与 deadline operation 分属不同事实来源;Pomodoro 使用严格
schema v1、4 KiB、`retain_readonly`,关闭后只能作为只读历史。已结束子会话同样只读;仍 pending 的标准交互
由 Interact / 主 IM 继续承接,不能追加到旧子会话。
## D04-10:两个 Agent Tool 缺少可执行的 Manifest / 路由契约
**已解决(2026-08-06,收敛决议)。** 主定义已冻结 `pomodoro.start` / `pomodoro.interrupt` 的 v1 Descriptor
Runtime 先校验、定位和原子裁决;Pomodoro Surface 只接收已裁决投影,既不决定终态也不影响短 Tool 的回执。
以下为决议前的风险分析。
### 为什么这是 P1
第 04 次主定义已经确定两个名称和高层语义:
```text
pomodoro.start({ duration_seconds, activity? }) 长期 operation
pomodoro.interrupt({}) 短 Tool
```
但第 03 次迭代冻结的 Tool Descriptor 要求每项 Agent Tool 至少具备稳定 ID、版本、输入 / 输出 JSON Schema、
`handling`、目标 App、前台要求和超时等信息;正式 Runtime 方案还要求声明面向 Agent 的说明、幂等规则、风险和
启动策略。这些字段决定 Runtime 是否创建 instance、何时前台化、如何验证输入、以及何时可向 Agent 发送结果。
当前 Pomodoro Manifest 片段只声明了 `app.instance-state.v1`,未给出这两项 Tool 的等价契约。
这在 `pomodoro.interrupt` 上尤其不能由实现自行猜测:当前主定义同时说“Runtime 将调用路由给该 Pomodoro
instance”与“Runtime 在同一原子裁决中将 `pomodoro.start` 收口”。若没有清晰的 Descriptor 和处理顺序,Web /
Tauri 实现可能分别选择“Surface 收到短 Tool 后自己 complete”或“Runtime 直接给 Agent 回执”。前一种会使
Surface 的存活状况影响中断可靠性,违反已确认的终态所有权;后一种是合理选择,但必须作为契约写明。
### 最小收敛内容
不需要新增用户能力或扩大 SDK。建议在实施权威中为两个 Tool 加一个最小 Manifest 表 / JSON 片段,至少固定:
1. `pomodoro.start``operation` 调用模型、输入 schema`duration_seconds` 为正整数,`activity` 为可选受限字符串)、最终输出 schema(`completed` / `interrupted` 及约定的结果字段)、启动 / 前台策略、超时或由 `ends_at` 约束的规则、幂等键与重复调用结果;
2. `pomodoro.interrupt` 的短调用模型、空对象输入 schema、三种既定稳定回执的输出 schema,以及它不接受目标 ID 的规则;
3. Runtime 在验证、按 `conversation_id` 定位并原子收口后写入短 Tool 自身回执和长期 `start` 的唯一结果 / outboxPomodoro Surface 只接收已裁决状态投影,不能以 `sdk.tools.complete` 决定或补写任何终态;
4. 两项 Tool 在当前 app 未运行、Surface 已卸载、instance 正在 closing、Inventory revision 过期和 schema 非法时的受控拒绝 / 恢复路径。
字段名称不必照搬本记录;关键是由 Runtime 发布到 Agent 的契约能让 Web 与 Tauri 得到同一行为。完成回填后,本项可关闭。
## D04-11:同一会话的第二次 `pomodoro.start` 没有唯一规则
**已解决(2026-08-06,收敛决议)。** 同一 `conversation_id` 只允许一个 `focusing` Pomodoro operation。
不同 `source_tool_call_id` 的第二次 `pomodoro.start` 稳定返回 `active_focusing_operation`,不创建 instance、
子会话、deadline operation、焦点变更或 outbox;Agent 必须先停止旧轮,或等待其已经终态。
以下为决议前的风险分析。
### 为什么这是 P1
主定义让 `pomodoro.interrupt({})` 从调用的 `conversation_id` 绑定“当前唯一的 `focusing` Pomodoro operation”。
`pomodoro.start` 在已有 `focusing` operation 时是否可以再创建一个 instance / 子会话 / deadline operation 尚未
定义。若两个 Host 自行选择不同处理,至少会产生以下不兼容情况:
```text
实现 A:允许第二个 start
→ 同一 conversation 同时存在两个 focusing operation
→ interrupt({}) 无法再唯一定位目标。
实现 B:静默覆盖第一个 start
→ 第一个长期 Tool 没有可靠的 interrupted 结果 / outbox。
实现 C:拒绝第二个 start
→ 需要向 Agent 返回什么稳定结果尚未定义。
```
这不是未来“多个计时器”功能的讨论,而是当前单次专注约束必须明确拒绝或替换的边界。否则无法完成
`pomodoro.interrupt` 的唯一目标验收,也无法实现本轮的唯一 outbox 要求。
### 最小收敛内容
推荐第一版采用最保守规则:同一 `conversation_id` 已有 `focusing` Pomodoro operation 时,新的
`pomodoro.start` 被 Runtime 稳定拒绝(例如 `active_focusing_operation`),不创建任何 instance、子会话、deadline
或 outboxAgent 必须先调用 `pomodoro.interrupt({})`,或在旧 operation 已 `completed` / `interrupted` 后再开始。
若产品希望“新的开始替换旧的开始”,也可采用先原子中断旧 operation、再创建新 operation 的规则,但必须定义两个
Tool 结果 / outbox 的先后和任一事务失败时的恢复,复杂度更高。
无论选择哪种,都应在验收加入:重复 start、并发 start、start 与 interrupt 并发、start 与 deadline 并发,且确认
每个 operation 只有一次终态和一次长期 Tool outbox。
## D04-12:当前 IM 验收与未来 Voice 语义混在一起
**已解决(2026-08-06,收敛决议)。** 第 04 次仅通过 IM 验证完整闭环;未来 Voice 只能复用相同的自然语言
意图、Agent Tool 和 Runtime 语义,本轮不实现或验收 Audio Mode、语音采集、识别或媒体能力。
以下为决议前的风险分析。
### 为什么这是 P2
用户已经确认:当前用户主要以 IM 消息与 Agent 交互,未来 Voice 必须复用同一“自然语言意图 → Agent Tool →
Runtime”模型。这个语义是正确的。可是主定义的目标和验收第 1、4 条目前写成“IM 或 Voice”,同时本迭代范围又
明确排除 Audio Mode 的真实媒体能力。按字面,验收人员无法判断是否必须交付语音采集、识别、语音对话入口或
Voice 端到端测试。
这不要求本轮实现 Voice,也不要求改变 Agent Tool。需要的只是把时间边界写清:第 04 次实际验证当前 IM;未来
Voice 接入后必须把识别出的同类意图映射到相同的两个 Tool,并遵守相同的会话绑定、终态和 outbox 语义。
### 最小收敛内容
将主定义、总体计划和验收中的“IM 或 Voice”改为类似表述:
```text
第 04 次通过 IM 验证用户向 Agent 表达开始 / 停止意图的完整闭环。
未来 Voice 复用相同的 Agent Tool 和 Runtime 语义;本轮不实现或验收真实 Audio Mode、语音采集、识别或媒体能力。
```
然后保留 Web Reference Host 和 Tauri Desktop Host 的 IM 代表性流程验收。回填后,本项可关闭。
## 评审关闭条件
1. D04-10D04-12 已回填 [04.runtime_workspace.md](04.runtime_workspace.md)、[plan.md](../plan.md) 和验收条目;
2. 实施时依据冻结后的 Tool Descriptor 增加合法、非法输入、Inventory 过期、重复 / 并发和 Surface 缺席的 fixture 与自动化验收;
3. D04-C11 继续作为 P5 carryover 留在计划中;没有 profiling 证据前,不启动 Rust 迁移;
4. 本评审只记录发现,未修改主定义、计划、正式方案或实现。
@@ -0,0 +1,338 @@
# LineUp App 迭代定义:Runtime 工作区与 Pomodoro MiniApp
**迭代编号:** 04.runtime_workspace
**状态:** 设计已冻结,待实施
**日期:** 2026-08-06
**前置基线:** [03.sdk_and_coreapp.md](../03.sdk_and_coreapp/03.sdk_and_coreapp.md)
**总体计划:** [plan.md](../plan.md)
**权威架构:** [APP架构设计.md](../../设计/APP架构设计.md)
**冻结说明:** 本定义以 [03.design_review.md](03.design_review.md) 关闭后的决议为实施基线;后续若调整
Pomodoro Tool、Runtime 终态、状态快照或本迭代范围,须通过新的设计评审记录确认。
## 1. 迭代目标
前三次迭代已经完成 Runtime、Interact、MiniApp SDK v1 和参考 MiniApp 的基础契约。本迭代不再扩展
复杂的业务应用,而是把这些基础接到真实的 Web/Tauri 工作区界面,证明用户可以启动、运行、关闭、恢复
一个 MiniApp,并在 Interact 中查看对应的子会话。
本迭代选择一个极简的 **Pomodoro 番茄时钟 MiniApp** 作为 Runtime 验证应用。它服务于写作业、看书、
冥想等单次专注活动:第 04 次中用户通过 **IM** 请求 Agent 立即开始或停止一段固定时长的专注;未来 Voice
复用相同意图与 Tool 语义,但不属于本轮实现或验收。Pomodoro 只负责低干扰显示,不负责任务、项目、统计或
通用烹饪/家务倒计时。
```text
Interact IM
→ Agent 请求启动 Pomodoro
→ Runtime 创建 App instance、App 子会话和 deadline operation
→ Pomodoro 进入前台,Interact 进入后台
→ 用户专注;自动暗屏或锁屏不改变本轮计时
→ 到时间完成,或用户主动离开专注工作区而中断
→ Runtime 回传结果并立即收口关闭 App,恢复 Interact
→ Interact / Agent 呈现本次专注完成结果
→ 子会话在 IM 中折叠保存
→ 重启后按规则恢复或继续处理
```
## 2. 产品和架构边界
### 2.1 Interact
Interact 仍然是系统级 `system` MiniApp,负责人与 Agent 的交互:
- Agent 通过 `pomodoro.start` 请求立即开始一段专注,也可以通过 `pomodoro.interrupt` 结束当前专注;
- Agent 向用户询问是否开始下一轮;
- Agent 需要用户确认时使用 `notice / choice / confirm / input`
- 交互记录属于 Interact 和对应会话,不属于 Pomodoro 的内部 UI。
### 2.2 Runtime
Runtime 负责最终裁决和可靠性:
- 创建和管理 Pomodoro App instance
- 管理前台、后台、挂起、关闭和恢复;
- 校验 Tool、作用域、实例和会话上下文;
- 为每个 App instance 保存 schema 校验、revision 控制的业务状态快照;
- 管理通用 deadline operation:持久化 `ends_at`、裁决完成/中断唯一终态并写唯一 outbox;
- 处理刷新、断线和重启恢复;
- 关闭 App 时停止新 Tool 投递,并收口未完成操作;
- 通过 outbox 可靠回传结果;
- 需要系统通知时通过 Capability Gateway 处理。
### 2.3 Pomodoro MiniApp
Pomodoro 是普通 `bundled` MiniApp,必须使用与其他非系统级 MiniApp 相同的 SDK、受限 Surface 和
Capability 规则。
它只负责:
- 显示活动名称、倒计时和低干扰专注界面;
- 根据 Runtime 投影的 operation 与 instance state 刷新界面;
- 接收 Runtime 路由的 Agent Tool 和状态投影;不以界面按钮直接改变专注业务状态;
- 通过 SDK 保存自身展示所需的业务状态快照;
它不能:
- 直接访问 AppServer、Transport、Conversation Store 或 Agent
- 直接调用 Tauri、系统通知或其他 Host 能力;
- 发起 Interact 标准交互;
- 修改 Runtime 的焦点、Registry 或其他 App 数据。
## 3. Pomodoro 最小模型
Pomodoro App instance 和一次专注 operation 不是同一个对象:`app_session_id` 表示 Interact 中围绕该
instance 的子会话,`instance_id` 表示 MiniApp 实例,`operation_id` 才表示一次实际专注。第一版由
`pomodoro.start` 同时创建它们;它们不在数据模型上互为同义词。
一次专注 operation 只保留以下状态:
```text
focusing 正在专注
completed 到达约定时长
interrupted 用户明确离开、切换工作区或关闭 App 后中断
```
最小 operation 数据:
```text
operation_id
source_tool_call_id
activity?
duration_seconds
started_at
ends_at
state
ended_at?
interruption_reason?
```
运行中只以 `ends_at` 作为时间事实;`remaining_seconds` 是 Pomodoro UI 从 `ends_at - now` 派生的显示值,
不单独持久化。Pomodoro 的 instance snapshot 可以保存活动名称、`operation_id``started_at``ends_at`
与展示状态;它不替代 Runtime operation 的 Tool 终态和 outbox。
Pomodoro 在 Manifest 中声明以下两个由 Agent 调用的 Tool。MiniApp 是 Agent 的业务工具:用户在 IM 中以
自然语言表达开始、停止等意图(未来同样适用于 Voice),由 Agent 决定并调用 ToolPomodoro 的界面不提供
暂停、继续或“结束专注”的业务按钮。
```text
pomodoro.start({ duration_seconds, activity? })
pomodoro.interrupt({})
```
`pomodoro.start` 是长期 Tool operationAgent 调用成功后立即进入 `focusing`,只在 `completed`
`interrupted` 时回传一次业务结果。`pomodoro.interrupt({})` 是短 ToolTool Router 只从该 Agent 调用所在的
`conversation_id` 中绑定当前唯一的 `focusing` Pomodoro operation;调用者不能传入或伪造 `instance_id`
`app_scope``operation_id` 或其他会话目标。Runtime 将调用路由给该 Pomodoro instance,并在同一原子裁决中
`pomodoro.start` 收口为 `interrupted`。若 Surface 已卸载,Runtime 仍必须完成裁决;Surface 存在时只接收
最终状态投影。`pomodoro.interrupt` 的稳定回执为 `interrupted``no_active_focusing_operation`
`operation_already_final`;重复或迟到调用不得重写终态或新增 outbox。用户不需要在 App 内再次点击“开始”,
也没有暂停、继续或恢复入口。
用户切回 Interact、切到其他 MiniApp 或关闭 Pomodoro 时,属于 Runtime 生命周期事件:Runtime 以同一原子
中断规则收口,但不伪造 Agent Tool。自动暗屏、锁屏和 Surface 重载不等于退出。到点、Agent 调用
`pomodoro.interrupt` 与生命周期关闭竞争同一个终态,先成功者生效;后续调用只得到上述稳定回执。到点取得
`completed` 后,Runtime 先原子写入唯一结果/outbox,再立即关闭 Pomodoro、结束子会话并恢复 Interact
Pomodoro 不显示独立完成提示,完成结果由 Interact / Agent 呈现。如果 Agent 要询问用户是否开始下一轮,
必须回到 Interact 的标准交互。
两个 Tool 的 v1 Descriptor 如下。Runtime 只发布通过 Manifest、Inventory revision、会话作用域和输入 schema
校验的 Tool;校验失败、过期 Inventory 或不存在的目标均稳定拒绝,且不启动或唤醒 Pomodoro。
| Tool | 调用模型与启动策略 | 输入 | 输出 / 稳定拒绝 | 幂等、超时与路由顺序 |
|---|---|---|---|---|
| `pomodoro.start` v1 | 长期 `operation`Runtime 创建 instance、App 子会话和 deadline operation 后将 Pomodoro 前台化。 | `{ duration_seconds: 正整数, activity?: 字符串 }`;拒绝额外字段。 | 最终成功结果:`{ state: "completed" \| "interrupted", operation_id, started_at, ends_at, ended_at, interruption_reason? }`;若同一会话已有其他 `focusing` 专注,稳定拒绝 `active_focusing_operation`。 | `source_tool_call_id` 是幂等键:同一调用重试返回既有 operation/既有最终结果;不同调用由同一个 conversation 的活动专注记录作原子 compare-and-set。没有 Host/UI 临时超时,运行期限以持久化 `ends_at` 为准,重启后继续恢复或结算。 |
| `pomodoro.interrupt` v1 | 短 Tool;不启动、唤醒或等待 Pomodoro Surface。 | 空对象 `{}`;不接受 `instance_id``operation_id``app_scope` 或其他目标字段。 | `{ status: "interrupted" \| "no_active_focusing_operation" \| "operation_already_final", operation_id? }`。 | `source_tool_call_id` 是幂等键。Runtime 从调用的 `conversation_id` 绑定当前唯一 `focusing` operation,原子写其 `interrupted` 终态与长期 start 的唯一结果/outbox,再返回短 Tool 回执;Surface 存在时才接收终态投影,不能以回执决定或补写终态。 |
上表中的输入/输出 schema 冻结为以下 JSON SchemaRuntime 在将 Descriptor 发布到 Agent Inventory 前验证它们。
```json
{
"pomodoro.start": {
"input_schema": {
"type": "object",
"additionalProperties": false,
"required": ["duration_seconds"],
"properties": {
"duration_seconds": {"type": "integer", "minimum": 1},
"activity": {"type": "string", "maxLength": 256}
}
},
"result_schema": {
"type": "object",
"additionalProperties": false,
"required": ["state", "operation_id", "started_at", "ends_at", "ended_at"],
"properties": {
"state": {"enum": ["completed", "interrupted"]},
"operation_id": {"type": "string"},
"started_at": {"type": "string"},
"ends_at": {"type": "string"},
"ended_at": {"type": "string"},
"interruption_reason": {"type": "string"}
}
}
},
"pomodoro.interrupt": {
"input_schema": {
"type": "object",
"additionalProperties": false
},
"result_schema": {
"type": "object",
"additionalProperties": false,
"required": ["status"],
"properties": {
"status": {
"enum": ["interrupted", "no_active_focusing_operation", "operation_already_final"]
},
"operation_id": {"type": "string"}
}
}
}
}
```
同一 `conversation_id` 第一版只允许一个 `focusing` Pomodoro operation。不同 `source_tool_call_id` 的第二次
`pomodoro.start` 必须稳定拒绝为 `active_focusing_operation`,且不得创建 instance、子会话、deadline operation、
焦点变更或 outbox;Agent 必须先调用 `pomodoro.interrupt({})`,或等待旧 operation 已成为终态后再开始。
Pomodoro 必须声明 `app.instance-state.v1`,其最小 Manifest 契约如下。该快照只服务界面恢复和关闭后的历史
展示,不替代 operation 的终态、deadline 或 outbox 事实。
```json
{
"features": ["app.instance-state.v1"],
"instance_state": {
"state_schema_version": 1,
"state_schema": {
"type": "object",
"additionalProperties": false,
"required": ["operation_id", "started_at", "ends_at", "display_state"],
"properties": {
"operation_id": {"type": "string"},
"activity": {"type": "string"},
"started_at": {"type": "string"},
"ends_at": {"type": "string"},
"ended_at": {"type": "string"},
"display_state": {"enum": ["focusing", "completed", "interrupted"]},
"interruption_reason": {"type": "string"}
}
},
"max_bytes": 4096,
"retention": "retain_readonly"
}
}
```
关闭后的旧 snapshot 只能和只读 App 子会话一起用于历史展示:旧 instance 不可再次写入、不可恢复为
`focusing`,也不能作为新一轮专注的运行状态;“继续处理”始终创建新的 instance、子会话和 operation。
## 4. 工作内容
### 4.1 工作区界面
- 显示当前前台 App
- 支持由 `pomodoro.start` 从 Interact 切入 Pomodoro,以及用户显式返回 Interact;返回/切换会中断当前
专注 operation,而不是把它作为通用后台计时器继续运行;
- 显示 App 前台、后台、挂起、关闭和恢复状态;
- App 启动失败时恢复 Interact
- 刷新或重启后恢复工作区快照。
### 4.2 生命周期接入
-`AppLifecycleManager``AppFocusManager``AppOrchestrator` 接入真实 Host
- 区分自动暗屏/锁屏、Surface 重载、工作区切换和真正关闭:前两者不终止专注,后两者中断专注;
- Runtime 用持久化 `ends_at` 而非 MiniApp UI 定时器管理 deadline;到点、用户中断和关闭竞争同一唯一终态;
- deadline 取得 `completed` 后,Runtime 依次提交唯一结果/outbox、立即关闭 Pomodoro、结束子会话并恢复
Interact;完成提示由 Interact / Agent 呈现,不保留 Pomodoro 完成展示窗口;
- 关闭后停止向该 instance 投递新 Tool
- 用户退出专注时先将 `pomodoro.start` 终结为 `interrupted` 并提交结果;随后关闭不会将该已终态 Tool 改写为
`cancelled(app_closed)`。其他未终态普通 Tool 仍按 `cancelled(app_closed)` 收口;
- 已提交结果继续通过 outbox 发送;
- 关闭后恢复前一个有效前台 App。
### 4.3 子会话和 Interact 交互
- 创建 Pomodoro instance 时创建 App 子会话;只有恢复同一个未结束 instance 时才恢复同一个子会话;
- 在主 IM 中显示可折叠的 Pomodoro 子会话;
- 子会话只记录人与 Agent 围绕该番茄钟的交互和结果;
- 倒计时和退出按钮等 App 内部操作不写入 IM;
- App 前台时,Interact 的标准交互可以显示在其上方;
- 展示位置变化不改变交互归属;
- 已结束子会话只读;“继续处理”创建新的 instance 和新的子会话;关闭时仍 pending 的 Interact 标准交互
不自动取消,保留在主 IM / Interact 中等待回答、dismiss、超时或 Runtime 失败,且不能再追加到已结束子会话。
### 4.4 恢复和提醒
- 重启后根据 `ends_at` 重新计算剩余时间;若已到点,Runtime 原子转为 `completed` 并只写一次结果/outbox
- 不允许重启后无条件重新开始完整时长;
- 不承诺 Runtime / Host 完全未运行时的即时系统提醒;下次恢复时必须按已到期状态结算,不能重置或重复回传;
- 来电等外部打断预留 `host_interruption` 语义,但第 04 次不实现电话检测、免打扰或静音能力;
- 明确自动暗屏/锁屏、工作区离开、关闭、完成和中断的区别;
- 第一版不实现 Pomodoro App 内完成提示;完成结果由 Interact / Agent 呈现;
- 系统通知作为后续 Capability 验证,不允许 MiniApp 直接调用系统 API。
### 4.5 自动化和真实验收
- 覆盖 `focusing → completed / interrupted` 状态机、`pomodoro.start` 长 Tool、Agent 调用的
`pomodoro.interrupt` 与 Runtime 生命周期中断;
- 覆盖 Tool Descriptor 的合法/非法输入、Inventory 过期、同 call 重试、同会话重复/并发 start、start 与
interrupt/deadline 并发,以及 Surface 缺席时 Runtime 仍可收口;
- 覆盖自动暗屏/锁屏不终止、工作区切换/关闭中断、重复/迟到退出和到点与中断并发时只产生一个终态;
- 覆盖重启前未到点恢复、重启后已到点结算和一次 outbox;
- 覆盖 `completed` 后立即关闭 Pomodoro、子会话只读、Interact 呈现完成结果,以及完成与关闭并发时终态不可改写;
- 覆盖 `app.instance-state.v1` schema、4 KiB 配额与 `retain_readonly`:关闭后的快照只读,不能复活为
`focusing` 或写入新状态;
- 覆盖 App 子会话创建、折叠、只读和继续处理;
- 覆盖 Interact 标准交互在 Pomodoro 前台时仍归 Interact,以及 Pomodoro 关闭后 pending 交互仍可在主 IM
回答但不改写只读子会话;
- 通过 Web Reference Host 完成完整浏览器验收;
- 在 Tauri Desktop Host 完成至少一条代表性流程;
- 检查生命周期、Tool、交互、恢复和拒绝路径日志。
## 5. 不在本迭代范围
- 应用市场、服务端 App Catalog 和远程下载;
- 第三方 MiniApp 发布和在线更新;
- 多 Agent 连接和 Agent 切换;
- Audio Mode 和 Video Mode 的真实媒体能力;
- Pomodoro 统计报表、多个计时器、日历和复杂提醒计划;
- 通用倒计时(如烹饪、停车、家务)以及用户预设后手动开始的 timer 模式;
- 电话检测、系统专注模式、免打扰、静音和系统通知;
- Task Dashboard 的任务、项目、优先级、标签和历史管理;
- Whiteboard 的工作区接入、切换、完整用户流程、多人协作、云端同步和复杂绘图工具;第 04 次只保持第
03 次已有的 SDK / 隔离回归。
- 将 MiniApp SDK 或 Runtime SDK 的实现迁入 Rust;本轮保持现有 TypeScript Runtime / Web Bridge 基线,
未来仅在 profiling 证明 Runtime Core 存在性能热点后另行评估。
## 6. 验收目标
```text
1. 用户可以在 **IM** 中请求 Agent 立即开始或停止一段固定时长的写作业、看书或冥想专注;未来 Voice 必须
复用同一意图和 Tool 语义,但不属于本轮实现或验收。
2. `pomodoro.start` 创建真实 App instance、焦点记录、App 子会话和 deadline operation,并直接进入 `focusing`。
3. Pomodoro 进入前台后,Interact 可以退到后台;自动暗屏、锁屏和 Surface 重载不终止专注。
4. 用户以 IM / Voice 要求 Agent 停止时,Agent 调用 `pomodoro.interrupt({})`;用户返回 Interact、切到其他
MiniApp 或关闭 Pomodoro 时,Runtime 直接处理生命周期中断。两类路径的本轮唯一终态均为 `interrupted`
随后 Interact 恢复前台;Pomodoro 不作为通用后台计时器继续运行。
5. 到 `ends_at` 时,本轮唯一终态为 `completed`Runtime 提交唯一结果/outbox 后立即关闭 Pomodoro、结束子会话
并恢复 Interact,由 Interact / Agent 呈现完成结果;到点和中断并发时只接受第一个原子终态。
6. Runtime 只回传一次 `pomodoro.start` 的 `completed` 或 `interrupted` 结果;`pomodoro.interrupt` 不可伪造
目标、只能绑定当前会话中活动的 `focusing` operation,并对重复/迟到调用给出稳定回执;关闭流程不得将已提交
终态改写。
7. 同一 `conversation_id` 不会同时存在两轮 `focusing` Pomodoro;不同调用的第二次 `pomodoro.start` 稳定拒绝为
`active_focusing_operation`,不创建任何新的 App 或 operation 资源。
8. 刷新或重启后,未到点的本轮按 `ends_at` 恢复;已到点的本轮结算一次而不重置完整时长或重复回传。
9. 子会话在主 IM 中折叠保存,关闭后只读;新的“继续处理”创建新的 instance / 子会话,pending Interact
交互仍可在主 IM 回答但不能向已关闭子会话追加记录。
10. Agent 的标准交互始终由 Interact 负责,Pomodoro 不伪造交互组件。
11. Pomodoro 的 `app.instance-state.v1` 快照符合 schema v1 与 4 KiB 配额;关闭后保留为只读历史,不能写入或
复活旧 instance。
12. MiniApp 无法访问 Transport、Store、Agent、Host DOM、Tauri 或任意系统 API。
13. `npm test -- --run`、`npm run build` 和 Web/Tauri 代表性验收全部通过。
14. P0~P3 设计和验收问题清零。
```
## 7. 后续定位
本迭代完成后,Whiteboard 可以作为下一条 Surface、Artifact 和隔离边界验证应用;Task Dashboard 保留
为后续普通 `bundled` MiniApp,等 Runtime 工作区、SDK 和生命周期稳定后,再单独定义任务管理业务模型。
+6
View File
@@ -5,6 +5,7 @@
```text ```text
迭代/ 迭代/
├── plan.md # 当前阶段之后的总体路线和排期原则
├── 00.base/ ├── 00.base/
│ └── 00.base.md │ └── 00.base.md
├── 01.kernel/ ├── 01.kernel/
@@ -27,6 +28,11 @@
5. 已确认的结论需要回填主定义文档和验收项;评审记录保留原始意见,用于追溯,不能替代主定义文档; 5. 已确认的结论需要回填主定义文档和验收项;评审记录保留原始意见,用于追溯,不能替代主定义文档;
6. 迭代完成后的实现验收、发布复盘等文档也保留在对应目录内,并使用清晰的递增编号。 6. 迭代完成后的实现验收、发布复盘等文档也保留在对应目录内,并使用清晰的递增编号。
## 后续总计划
当前阶段之后的路线、迭代拆分、范围边界和完成标准见 [plan.md](plan.md)。该文件记录已确认的整体方向;
每个具体迭代开始后,仍需在自己的目录中创建主定义文档和独立评审记录。
## 评审优先级与遗留问题 ## 评审优先级与遗留问题
评审问题使用 `P0``P5` 标示处理优先级。优先级表达的是“最晚何时必须解决”,而不是问题描述的 评审问题使用 `P0``P5` 标示处理优先级。优先级表达的是“最晚何时必须解决”,而不是问题描述的
+311
View File
@@ -0,0 +1,311 @@
# LineUp App 后续迭代计划
**更新时间:** 2026-08-06
**计划状态:** 已确认,作为后续迭代拆分和排期依据
## 1. 计划结论
前三个阶段已经建立了 LineUp App 的基础:Runtime 托管 IM、Runtime 具备应用编排能力、MiniApp SDK v1
和两个内置 MiniApp 参考实现已经完成验证。
下一步不建设应用市场,也不马上扩展多 Agent、语音或视频。下一阶段先把已有的 Runtime、SDK 和 MiniApp
契约做成用户真正可以使用的“应用工作区”。
当前推荐路线:
```text
Runtime 工作区与应用闭环
→ 第一个真正可用的 MiniApp(番茄时钟)
→ 本地 App 管理与签名 Bundle
→ 再评估应用分发和市场
```
## 2. 已完成的基础
### 2.1 Runtime 托管 IM
`00.base` 已建立客户端基础闭环:
- Runtime 独占网络连接、同步循环、消息存储、outbox 和 App Inbox
- 登录、同步、本地回显、Markdown 和 Agent 状态保持稳定;
- 入站消息经过作用域校验、去重和恢复;
- Chat 只能通过 SDK 和 Runtime Action 工作。
### 2.2 Runtime 应用编排基础
Runtime 已具备应用实例、焦点和生命周期的核心模型:
- App Registry
- App Instance Manager
- App Focus Manager
- App Lifecycle Manager
- Tool Router 和 App Orchestrator
- App 子会话、前后台切换、关闭和恢复的契约。
### 2.3 MiniApp SDK v1 与参考实现
`03.sdk_and_coreapp` 已完成并通过自动化测试和浏览器验收:
- Interact 是唯一的 `system` MiniApp
- Task Dashboard 和 Whiteboard 都是普通 `bundled` MiniApp 的参考实现;
- MiniApp 通过 SDK 接收 Inbox、Tool、进度、结果、生命周期、Surface 和 Capability 请求;
- 标准 `notice / choice / confirm / input` 属于 Interact 的人与 Agent 交互,不是 MiniApp 内部表单;
- App 子会话、交互归属、关闭收口、继续处理和重启恢复已有明确规则;
- 当前单 Agent MVP 边界保持不变。
需要注意:当前完成主要证明了 Runtime 契约和参考实现正确,用户可见的完整应用工作区仍需下一阶段收敛。
## 3. 第四次迭代:Runtime 工作区与应用闭环
**设计状态:** 已冻结,待实施;冻结基线为
[04.runtime_workspace.md](04.runtime_workspace/04.runtime_workspace.md) 及其
[03.design_review.md](04.runtime_workspace/03.design_review.md)。
建议迭代目录:
```text
迭代/04.runtime_workspace/
```
### 3.1 目标
把 Runtime 的生命周期和会话模型接到真实 Web/Tauri 界面,跑通一条完整的用户流程:
```text
进入 Interact IM
→ Agent 请求启动 Pomodoro 番茄时钟
→ Runtime 创建 App instance、App 子会话和 deadline operation
→ 番茄时钟进入前台,Interact 进入后台
→ 用户进行写作业、看书或冥想等固定时长专注;自动暗屏/锁屏不终止本轮
→ 到时间完成,或用户主动离开 Pomodoro 工作区而中断
→ Runtime 回传唯一结果并关闭 App
→ 子会话结束并在 IM 中折叠保存
→ Interact 恢复
→ 用户查看历史或继续开始下一轮
```
### 3.2 主要工作
1. **接通 App 工作区界面**
- 显示当前前台 App
- 支持由 `pomodoro.start` 从 Interact 进入 Pomodoro,以及用户明确返回 Interact
返回/切换会中断当前专注,不把 Pomodoro 作为通用后台计时器继续运行;
- 显示后台、挂起、关闭和恢复状态;
- App 启动失败时恢复 Interact
- 刷新或重启后恢复工作区。
Whiteboard 在第 04 次只保持第 03 次已有的 SDK/隔离回归,不接入本轮工作区切换或新的完整流程。
2. **接通 App 生命周期**
-`AppLifecycleManager``AppFocusManager``AppOrchestrator` 接入真实 Host
- 区分自动暗屏/锁屏、Surface 重载、工作区切换和真正关闭;前两者不终止专注,后两者中断专注;
- Runtime 使用持久化 `ends_at` 的 deadline operation,而不是 MiniApp UI 定时器;
- 关闭后停止新 Tool 投递;
- 用户退出专注时先将 `pomodoro.start` 终结为 `interrupted`;其他未终态普通 Tool 才收敛为
`cancelled(app_closed)`
- 已提交结果继续通过 outbox 发送;
- 关闭后恢复前一个有效前台 App。
3. **完成 App 子会话展示**
- 主 IM 显示 App 子会话折叠卡片;
- 支持展开已结束子会话;
- 已结束子会话只读;
- “继续处理”创建新 instance 和新子会话;
- 不把 App 内部按钮、表单和编辑动作写入 IM。
4. **完成 Interact 交互覆盖层**
- Interact 前台时,在 IM 中以内联卡片显示标准交互;
- bundled MiniApp 前台时,可以在其上方显示 Interact 的交互层;
- 展示位置变化不改变交互归属;
- App 关闭不自动取消未回答的标准交互;
- Agent 可以通过 `interaction.dismiss` 远程取消交互。
5. **让 Pomodoro 成为第一条完整用户流程**
- 用户在 IM 中以自然语言要求 Agent 开始或结束写作业、看书或冥想等专注;MiniApp 是 Agent 的业务工具,
而不是由用户自行操作业务状态的独立应用。未来 Voice 复用相同意图和 Tool 语义,但不属于本轮实现或验收;
- Agent 以 `pomodoro.start({ duration_seconds, activity? })` 创建长期 Tool operation,并以
`pomodoro.interrupt({})` 请求结束当前专注;
- 同一会话已有 `focusing` 专注时,不同调用的第二次 `pomodoro.start` 稳定拒绝为
`active_focusing_operation`,不创建新的 App、子会话或 deadline operation
- Runtime 创建 Pomodoro instance、App 子会话和 deadline operationPomodoro 直接进入专注界面;
- 到时间得到 `completed`Agent 调用 `pomodoro.interrupt`,或用户切回 Interact、切到其他 MiniApp、关闭
Pomodoro 时得到 `interrupted`;后者由 Runtime 的生命周期处理,不伪造 Agent Tool;不支持暂停、继续或恢复;
- 自动暗屏、锁屏与 Surface 重载不终止专注;刷新或重启后根据 `ends_at` 恢复或结算一次;
- 到时间后 Runtime 回传一次结果并立即关闭 Pomodoro,完成结果由 Interact / Agent 呈现;
- 完成记录和子会话可以在 Interact 中查看。
第一版只保留这些状态和数据:
```text
state = focusing | completed | interrupted
operation_id
source_tool_call_id
activity?
duration_seconds
started_at
ends_at
ended_at?
interruption_reason?
```
最小 Agent Tool
```text
pomodoro.start({ duration_seconds, activity? })
pomodoro.interrupt({})
```
Pomodoro 使用 `app.instance-state.v1` 保存严格 schema v1、最大 4 KiB 的展示快照;关闭后采用
`retain_readonly`,旧快照只用于历史展示,不能再次写入或恢复为运行中的专注。
番茄钟到点后不保留 App 内完成提醒:Runtime 关闭 Pomodoro 并恢复 Interact,由 Interact / Agent 呈现
完成结果。如果以后需要系统通知,再通过 Runtime 的 Capability 请求,不能让 MiniApp 直接调用 Tauri
或操作系统接口。Agent 询问用户是否开始下一轮时,仍然必须使用 Interact 的标准交互。
6. **补充端到端验收**
- Web Reference Host 完整验收;
- Tauri Desktop Host 至少完成一条代表性流程;
- 验证刷新、断线、重启、关闭、恢复和重复提交;
- 检查 Runtime 生命周期、交互、Tool 和恢复日志。
### 3.3 不在本迭代范围
- 应用市场和服务端 App Catalog
- 远程下载、第三方发布和在线更新;
- 多 Agent 连接、切换和多 Agent 会话列表;
- Audio Mode 的真实媒体能力;
- Video Mode 的真实媒体能力;
- Whiteboard 的工作区接入、切换、多人协作和复杂绘图能力;第 04 次只保持其已有回归;
- Task Dashboard 的完整项目管理功能;
- Pomodoro 的统计报表、多个计时器、日历和复杂提醒计划。
### 3.4 完成标准
```text
用户可以在 IM 中请求 Agent 立即开始或停止 Pomodoro 专注;未来 Voice 只复用相同 Tool 语义;
Runtime 可以正确创建、运行、中断、关闭和恢复 Pomodoro App
App 子会话能在 IM 中折叠、展开和继续处理;
标准交互在不同前台 App 下仍归 Interact
到点/中断竞争唯一终态,Tool 和 outbox 收口正确;
到点后立即关闭 Pomodoro 并由 Interact / Agent 呈现完成结果;
Pomodoro 关闭后的业务快照保留为只读历史,不能复活旧 instance;
刷新/重启后 App、焦点、子会话、`ends_at` 专注状态和待处理交互按规则恢复;
Web/Tauri 代表性流程通过端到端验收;
Whiteboard 保持第 03 次回归,但不属于第 04 次工作区闭环或完成范围;
所有 P0P3 评审问题清零。
```
## 4. 第五次迭代:第二个真正可用的隔离 MiniApp
建议迭代目录:
```text
迭代/05.first_isolated_miniapp/
```
第四次迭代完成工作区和 Pomodoro 后,再把另一个 MiniApp 从“参考实现”推进为“真实隔离运行的应用”。
### 4.1 推荐顺序
优先选择 Whiteboard 作为第二条安全和 Surface 验证流程;Task Dashboard 留到后续,避免任务管理业务影响 Runtime 核心设计。
### 4.2 Whiteboard 方向
- 受限 Surface 中的画布状态;
- 状态 patch
- Artifact 导出;
- Artifact 元数据校验;
- 重启恢复;
- 验证不能访问 Host DOM、Tauri、认证状态、任意网络和其他 MiniApp 数据。
暂时不做多人协作、云端同步和复杂绘图工具。
### 4.3 Task Dashboard 的后续定位
Task Dashboard 仍然保留为后续普通 `bundled` MiniApp,但不作为 Runtime 的第一条验证流程。
等工作区、SDK、生命周期和 Surface 边界稳定后,再单独定义任务、项目、状态和历史等业务模型。
## 5. 第六次迭代:本地 App 管理和签名 Bundle
建议迭代目录:
```text
迭代/06.local_app_management/
```
这一阶段仍然不建设在线应用市场,只解决本机的应用管理和安全运行边界:
- App Registry 管理界面;
- 本地安装记录;
- App enable / disable / remove
- 版本记录和回滚;
- 本地签名 Bundle
- Bundle 完整性和签名校验;
- 验证失败不污染当前可运行缓存;
- Inventory 更新和 Agent 可见性变化;
- App 删除时实例、焦点、Inbox、Surface 和私有数据的收口。
## 6. 第七次迭代之后:再评估应用分发和市场
只有在 Runtime 工作区、本地 App 管理、SDK、Surface 和签名 Bundle 都稳定之后,才评估:
- 服务端 App Catalog
- 应用搜索和详情;
- 下载和更新;
- 发布者身份;
- 第三方 MiniApp
- 审核、撤回和安全策略。
应用市场不是当前阶段的基础设施,而是建立在前面几层都稳定之后的分发能力。
## 7. 更后面的方向
### Runtime Core 的 Rust 演进
在 Runtime 工作区已跑通并积累 Web / Tauri 两个 Host 的性能数据后,单独评估是否将部分**无 UI 的 Runtime
Core** 下沉到 Rust,以改善状态处理和原子收口的效率与一致性。这不是第 04 次迭代的工作,也不等于把整个
MiniApp SDK 改写成 RustWeb Reference Host、sandbox iframe、postMessage Bridge、DOM 和 UI 仍须保持在
TypeScript / 浏览器侧。
潜在的 Rust 候选范围:
- instance state 的持久化、schema 校验和 revision 比较;
- deadline operation 调度;
- Tool / outbox 的原子终态裁决;
- lifecycle 收口和审计。
只有在 profiling 显示上述路径存在明确热点时,才建立独立设计与迁移迭代。评估必须同时测量状态快照读写、
deadline / Tool 吞吐、主线程阻塞、Tauri IPC 往返、JSON 序列化成本,以及 Web / Tauri Host 的实际差异;
并证明收益覆盖跨语言实现、测试、调试和错误边界所增加的复杂度。
### 多 Agent
在单 Agent 工作区稳定后再设计:
- Agent 列表和切换;
- 多 Agent 会话;
- 多 Agent outbox
- App 子会话归属;
- Inventory 和权限隔离。
### Audio Mode 与 Video Mode
语音和视频应复用当前 Runtime SDK、Tool、Capability、Artifact 和会话模型,不建立独立的 Agent
通信链路。它们需要单独处理媒体权限、设备选择、实时连接、中断和恢复,因此不进入当前两次迭代。
## 8. 当前排期原则
```text
先完成“真实可用的应用工作区”
再完成“一个真正隔离的 MiniApp”
再完成“本地安装和签名管理”
最后才评估“远程分发和应用市场”
```
任何新增功能都应先回答三个问题:
1. 它是否依赖 Runtime 已经稳定的生命周期和会话模型?
2. 它是否能通过现有 MiniApp SDK、Surface、Capability 和 Artifact 边界实现?
3. 它是否会把应用业务逻辑、网络通信或系统权限重新塞回 Interact 或 `main.ts`
如果前两个问题没有准备好,或者第三个问题答案为“会”,就不应提前进入应用市场或新的 App 类型建设。