docs: freeze runtime workspace iteration design

This commit is contained in:
2026-08-06 14:39:19 +08:00
parent aff5c8e3aa
commit 91982fac33
8 changed files with 849 additions and 119 deletions
+65 -10
View File
@@ -2,7 +2,7 @@
**版本:** 1.0(当前开发基线) **版本:** 1.0(当前开发基线)
**状态:** 当前 App 设计的唯一汇总入口 **状态:** 当前 App 设计的唯一汇总入口
**日期:** 2026-08-04 **日期:** 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) **来源:** [App 层架构方案](lineup-app-layer-architecture.md)、[Runtime 与 App SDK 架构方案](lineup-runtime-sdk-architecture.md)、[UI Surface 与 App Capability 协议](lineup-ui-surface-protocol.md)
--- ---
@@ -50,7 +50,7 @@ AppServer / IM
| App 生态阶段 | 当前只使用本地短作用域,如 `chat``whiteboard``draw-and-guess`;暂不引入供应商身份、反向域名 App ID 或全局命名空间。 | | App 生态阶段 | 当前只使用本地短作用域,如 `chat``whiteboard``draw-and-guess`;暂不引入供应商身份、反向域名 App ID 或全局命名空间。 |
| 丰富交互 | 标准内容先用可信内建组件;复杂互动用受限 Surface;设备/系统动作只能经 Capability Gateway。 | | 丰富交互 | 标准内容先用可信内建组件;复杂互动用受限 Surface;设备/系统动作只能经 Capability Gateway。 |
| Agent 工具 | App 在 Manifest 声明方法,Runtime 汇总为动态 InventoryAgent 只能调用当前 Inventory 中的方法。 | | Agent 工具 | App 在 Manifest 声明方法,Runtime 汇总为动态 InventoryAgent 只能调用当前 Inventory 中的方法。 |
| Runtime SDK | SDK 提供状态订阅、Agent 消息订阅、Action、Tool、应用导航、Artifact、存储、Capability 和生命周期接口。 | | Runtime SDK | SDK 提供状态订阅、Agent 消息订阅、Action、Tool、应用导航、Artifact、instance 级业务状态快照、Capability 和生命周期接口。业务状态由 Runtime 持久化和隔离,App 不直接拥有存储。 |
| Host | Tauri Desktop Host 与同代码的 Web Reference Host 是当前唯一实现/验收基线:前者是正式桌面外壳,后者是浏览器开发和验证入口;它们不是两个客户端。不规划独立 Android/Kotlin 客户端或 Wails Host。 | | Host | Tauri Desktop Host 与同代码的 Web Reference Host 是当前唯一实现/验收基线:前者是正式桌面外壳,后者是浏览器开发和验证入口;它们不是两个客户端。不规划独立 Android/Kotlin 客户端或 Wails Host。 |
本文件优先于来源文档中关于**后续 Runtime 重构**的结构描述。来源文档中的 M0~M4 完成记录、当前已实现字段和历史验收事实仍然有效;它们不自动成为新 Runtime 的长期模块边界。 本文件优先于来源文档中关于**后续 Runtime 重构**的结构描述。来源文档中的 M0~M4 完成记录、当前已实现字段和历史验收事实仍然有效;它们不自动成为新 Runtime 的长期模块边界。
@@ -137,7 +137,7 @@ conversations
conversation、关联 Agent、消息引用、任务、交互、Artifact 元数据。 conversation、关联 Agent、消息引用、任务、交互、Artifact 元数据。
apps apps
App Registry、默认 App、运行实例、每个 App 的可靠 Inbox。 App Registry、默认 App、运行实例、每个 App 的可靠 Inbox 与按 instance 隔离的业务状态快照
tools tools
Tool 声明、Inventory revision、调用记录、operation 与进度。 Tool 声明、Inventory revision、调用记录、operation 与进度。
@@ -449,7 +449,7 @@ interface LineUpAppRuntimeSDK {
readonly tools: AppToolAPI; readonly tools: AppToolAPI;
readonly apps: AppNavigationAPI; readonly apps: AppNavigationAPI;
readonly artifacts: ArtifactAPI; readonly artifacts: ArtifactAPI;
readonly storage: ScopedStorageAPI; readonly instanceState: MiniAppInstanceStateAPI;
readonly capabilities: CapabilityRequestAPI; readonly capabilities: CapabilityRequestAPI;
readonly diagnostics: DiagnosticsAPI; readonly diagnostics: DiagnosticsAPI;
} }
@@ -505,14 +505,57 @@ interface AppNavigationAPI {
App 只能提交声明性 Action,不能构造原始 Agent Envelope。跨 App 打开、聚焦和关闭也必须经 Runtime 校验目标 App 的启用状态、入口、展示模式和会话作用域。 App 只能提交声明性 Action,不能构造原始 Agent Envelope。跨 App 打开、聚焦和关闭也必须经 Runtime 校验目标 App 的启用状态、入口、展示模式和会话作用域。
### 6.3 Artifact、存储与 Capability ### 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 ```text
Artifact Artifact
Runtime 管理元数据、受限读取、创建、会话引用、下载和用户保存。 Runtime 管理元数据、受限读取、创建、会话引用、下载和用户保存。
Storage Instance State
Runtime 为每个 app_scope 提供隔离 JSON 数据与 snapshot;管理配额、迁移和清理。 Runtime 为每个 app_scope + instance_id 提供隔离 JSON snapshot;管理 schema、revision、配额、
恢复与生命周期清理。UI 动画、滚动位置等短暂渲染状态不必持久化。
Capability Capability
App 以 purpose + input 请求;Runtime 决定是否确认、调用 Host、审计并返回受控结果。 App 以 purpose + input 请求;Runtime 决定是否确认、调用 Host、审计并返回受控结果。
@@ -617,7 +660,7 @@ iframe sandbox="allow-scripts"
- 只经严格 postMessage / Surface Bridge SDK 通信 - 只经严格 postMessage / Surface Bridge SDK 通信
``` ```
Runtime/Host 必须验证 `event.source`、当前 `instance_id`、消息类型、事件名、JSON schema、消息大小和声明的投递策略。Surface 只能接收 state patch、触发已声明事件、处理已声明 Tool 调用、使用隔离存储和请求受控 Capability。 Runtime/Host 必须验证 `event.source`、当前 `instance_id`、消息类型、事件名、JSON schema、消息大小和声明的投递策略。Surface 只能接收 state patch、触发已声明事件、处理已声明 Tool 调用、通过 Bridge 使用 Runtime 提供的自身 instance 状态快照和请求受控 Capability。
Surface 不能: Surface 不能:
@@ -650,13 +693,20 @@ Surface 不能:
"required_features": [ "required_features": [
"app.lifecycle.v1", "app.lifecycle.v1",
"app.tools.v1", "app.tools.v1",
"surface.state.v1" "surface.state.v1",
"app.instance-state.v1"
], ],
"optional_features": ["artifact.create.v1"] "optional_features": ["artifact.create.v1"]
}, },
"entrypoints": [ "entrypoints": [
{"id": "canvas", "kind": "contextual", "default_eligible": false} {"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": [ "agent_subscriptions": [
{"type": "lineup.app.state.patch", "scope": "instance"}, {"type": "lineup.app.state.patch", "scope": "instance"},
{"type": "lineup.tool.invoke", "scope": "conversation"} {"type": "lineup.tool.invoke", "scope": "conversation"}
@@ -685,7 +735,7 @@ lineup-app/
│ ├── apps/ app registry、instance manager、default app │ ├── apps/ app registry、instance manager、default app
│ ├── tools/ tool registry、inventory、call lifecycle │ ├── tools/ tool registry、inventory、call lifecycle
│ ├── capabilities/ capability gateway │ ├── capabilities/ capability gateway
│ └── persistence/ runtime store、app inbox、artifact metadata │ └── persistence/ runtime store、app inbox、instance state snapshot、artifact metadata
├── runtime-sdk/ ├── runtime-sdk/
│ ├── app.ts Core App SDK │ ├── app.ts Core App SDK
│ ├── manifest.ts App/Tool/Subscription 类型 │ ├── manifest.ts App/Tool/Subscription 类型
@@ -771,6 +821,8 @@ F0 与 F1 中支撑图文聊天迁移的最小闭环已落地并经自动化回
- 在 Runtime 连接与状态变化时同步 revisioned Inventory 给 AgentTool 可声明是否需要启动 App、是否要求前台以及结束后是否恢复原焦点; - 在 Runtime 连接与状态变化时同步 revisioned Inventory 给 AgentTool 可声明是否需要启动 App、是否要求前台以及结束后是否恢复原焦点;
- 实现 Agent Tool → Runtime → App SDK → result/progress 的可靠闭环; - 实现 Agent Tool → Runtime → App SDK → result/progress 的可靠闭环;
- 将 MVP-R1 已实现的 Chat App Inbox、ACK、断线/崩溃恢复和拒绝码推广为所有受管理 App 的通用可靠投递机制。 - 将 MVP-R1 已实现的 Chat App Inbox、ACK、断线/崩溃恢复和拒绝码推广为所有受管理 App 的通用可靠投递机制。
- 实现 `app.instance-state.v1`:按 `app_scope + instance_id` 隔离的 schema 校验状态快照、revision
并发控制、配额、重启恢复与 lifecycle 清理;它不得替代 Tool/operation/outbox 的终态裁决。
### F4:第一个 Installed App ### F4:第一个 Installed App
@@ -795,6 +847,9 @@ F0 与 F1 中支撑图文聊天迁移的最小闭环已落地并经自动化回
工具与能力 工具与能力
[ ] Agent 只能调用当前 Inventory 中、参数 schema 合法的 Tool。 [ ] Agent 只能调用当前 Inventory 中、参数 schema 合法的 Tool。
[ ] Tool 的 result/progress/error 经 Runtime 校验、持久化和审计。 [ ] Tool 的 result/progress/error 经 Runtime 校验、持久化和审计。
[ ] MiniApp 只能读取和替换自身 instance 的 schema 合法状态快照;旧 revision、越界 instance、超配额
和非法 schema 均被 Runtime 拒绝,刷新/重启后仅恢复最后一个有效版本。
[ ] 业务状态快照不能直接完成 Tool、写 outbox、改变焦点或绕过实例生命周期。
[ ] App / Surface 无法绕过 Capability Gateway 获得系统权限。 [ ] App / Surface 无法绕过 Capability Gateway 获得系统权限。
安全 安全
@@ -33,7 +33,7 @@ Remote Agent / AppServer
┌────────────────────────────────────────────────────────┐ ┌────────────────────────────────────────────────────────┐
│ LineUpRuntime │ │ LineUpRuntime │
│ Transport · sync loop · Store · Outbox · App Inbox │ │ Transport · sync loop · Store · Outbox · App Inbox │
scope 路由 · Compatibility Adapter · Tool · Capability │ instance state · scope 路由 · Tool · Capability
└─────────────────────┬──────────────────────────────────┘ └─────────────────────┬──────────────────────────────────┘
│ Runtime SDK │ Runtime SDK
@@ -45,9 +45,9 @@ Remote Agent / AppServer
| 层 | 必须负责 | 不得负责 | | 层 | 必须负责 | 不得负责 |
|---|---|---| |---|---|---|
| `LineUpRuntime` | 处理 AppServer/Agent 通信、会话、原始协议兼容、scope 筛选、Store、sync、outbox、App Inbox、Tool 路由、App 实例和前台焦点、权限与恢复。 | 具体业务页面 DOM。 | | `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。 | | Interaction Core App | 用户实际使用的主交互界面:当前是 Chat/IM,未来包含 Audio/Video 模式、标准交互原语和扩展结果投影。 | 直连 AppServer、维护 cursor、解析 Agent 原始包、调度其他 App 或直接写 Runtime Store。 |
| Runtime SDK | App 与 Runtime 之间唯一的受限接口:提供 snapshot、订阅、Agent 消息、Inbox ACK、Runtime Action、App 导航生命周期请求。 | 把 Transport、token、Host 特权 API 暴露给 App。 | | 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 路由和策略。 | | Tauri/Web Host | 把 Runtime 放进桌面窗口或浏览器,并提供对应的 DOM/系统能力。 | 解释协议、决定 App 调度、绕过 Runtime 路由和策略。 |
| Surface | 在隔离执行域呈现已验证 Bundle,并经受限 bridge 上报事件。 | 访问 Host DOM、登录态、Tauri API、任意网络。 | | Surface | 在隔离执行域呈现已验证 Bundle,并经受限 bridge 上报事件。 | 访问 Host DOM、登录态、Tauri API、任意网络。 |
@@ -78,7 +78,7 @@ lineup-app/tauri/src/
├── app-management/ # Registry、App Instance、焦点、生命周期、Host ├── app-management/ # Registry、App Instance、焦点、生命周期、Host
├── communication/ # Transport Adapter ├── communication/ # Transport Adapter
├── coordination/ # Runtime、Kernel、Envelope、Tool/Task/交互编排 ├── coordination/ # Runtime、Kernel、Envelope、Tool/Task/交互编排
├── persistence/ # Conversation Store、Outbox、App Inbox ├── persistence/ # Conversation Store、Outbox、App Inbox、instance state snapshot
├── protocol/ # lineup.v1 解码与 golden fixture ├── protocol/ # lineup.v1 解码与 golden fixture
├── surfaces/ # Surface 生命周期、Bundle、隔离 Host ├── surfaces/ # Surface 生命周期、Bundle、隔离 Host
├── capabilities/ # Registry、执行、审计 ├── capabilities/ # Registry、执行、审计
@@ -2,7 +2,7 @@
**版本:** 0.1(架构基线) **版本:** 0.1(架构基线)
**状态:** 已确认的 Runtime / SDK 方向;尚未完全落地到当前 Tauri 实现 **状态:** 已确认的 Runtime / SDK 方向;尚未完全落地到当前 Tauri 实现
**日期:** 2026-08-04 **日期:** 2026-08-06
**关联方案:** [LineUp App 层架构设计方案](lineup-app-layer-architecture.md)、[LineUp UI Surface 与 App Capability 协议](lineup-ui-surface-protocol.md) **关联方案:** [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`、兼容迁移和实施顺序。 > **汇总入口:** 本文是 Runtime / SDK 初稿的详细来源。后续设计以 [LineUp App 最终设计方案](app_final_design.md) 为准;后者收敛了本地 `app_scope`、兼容迁移和实施顺序。
@@ -71,6 +71,8 @@ AppServer / IM Transport
6. **系统能力由 Runtime 独占。** Agent 和 App 只能请求 Capability;文件、麦克风、通知、剪贴板、窗口、密钥等均不得直接访问。 6. **系统能力由 Runtime 独占。** Agent 和 App 只能请求 Capability;文件、麦克风、通知、剪贴板、窗口、密钥等均不得直接访问。
7. **应用状态、消息和副作用分离。** Event 是已发生事实,Command 是请求动作,Effect 是 Runtime 执行的受控副作用。 7. **应用状态、消息和副作用分离。** Event 是已发生事实,Command 是请求动作,Effect 是 Runtime 执行的受控副作用。
8. **UI 是 Runtime 状态的投影。** App 重启、断网或 Surface 回收后,Runtime 能依据持久化状态恢复到可解释的协作状态。 8. **UI 是 Runtime 状态的投影。** App 重启、断网或 Surface 回收后,Runtime 能依据持久化状态恢复到可解释的协作状态。
9. **MiniApp 业务状态由 Runtime 托管。** App 只能通过 SDK 保存其当前 instance 的、Manifest schema
声明的状态快照;不能直接访问浏览器/Host 存储、Conversation Store、Tool/operation Store 或其他 App 数据。
## 3. 运行时分层 ## 3. 运行时分层
@@ -431,7 +433,7 @@ interface LineUpAppRuntimeSDK {
readonly tools: AppToolAPI; readonly tools: AppToolAPI;
readonly apps: AppNavigationAPI; readonly apps: AppNavigationAPI;
readonly artifacts: ArtifactAPI; readonly artifacts: ArtifactAPI;
readonly storage: ScopedStorageAPI; readonly instanceState: MiniAppInstanceStateAPI;
readonly capabilities: CapabilityRequestAPI; readonly capabilities: CapabilityRequestAPI;
readonly diagnostics: DiagnosticsAPI; readonly diagnostics: DiagnosticsAPI;
} }
@@ -542,18 +544,48 @@ App,但不能直接决定其他 App 的生命周期。
Artifact、媒体与文件通过 Runtime Artifact Store 暴露元数据、受限读取、创建、会话引用和用户保存;App 不取得任意路径或跨 App 文件访问权。 Artifact、媒体与文件通过 Runtime Artifact Store 暴露元数据、受限读取、创建、会话引用和用户保存;App 不取得任意路径或跨 App 文件访问权。
### 8.5 存储与 Capability ### 8.5 MiniApp instance 状态与 Capability
每个 App 使用 Runtime 管理的作用域隔离存储 每个 MiniApp instance 使用 Runtime 管理的、按实例隔离的业务状态快照
```text ```text
app-data/chat/ app_scope + instance_id
app-data/app-registry/ → 一份 schema 校验的 JSON state snapshot
app-data/voice/ → revisioned replace
app-data/whiteboard/ → 恢复同一个未结束 instance 时投影给该 App
``` ```
SDK 中的 `storage` 提供 JSON 数据和可恢复 snapshotRuntime 负责配额、升级迁移、禁用和移除时的清理。Capability 必须通过统一请求接口: 这不是通用文件系统、键值数据库或跨 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 ```ts
interface CapabilityRequestAPI { interface CapabilityRequestAPI {
@@ -573,7 +605,7 @@ Runtime 检查 Manifest 声明、App 启用状态、Host 支持、前台要求
| 层级 | 例子 | 可用接口 | 明确禁止 | | 层级 | 例子 | 可用接口 | 明确禁止 |
|---|---|---|---| |---|---|---|---|
| Core App | Chat、App Registry、Settings | 完整 App Runtime SDK(仍受 Scope 和 Capability 约束) | 直接绕过 Transport/Capability Gateway。 | | Core App | Chat、App Registry、Settings | 完整 App Runtime SDK(仍受 Scope 和 Capability 约束) | 直接绕过 Transport/Capability Gateway。 |
| Installed App | 白板、语音、游戏 | 受限 Surface Bridge SDK:状态、已声明 Tool、事件、隔离存储、Capability request | Tauri invoke、父 DOM、token、任意网络、其他 App 数据。 | | 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。 | | 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 或任意浏览器特权代码。 下载型 App 使用 `iframe sandbox="allow-scripts"` 或等价隔离容器;不包含 `allow-same-origin`。它经严格 CSP、来源验证和消息 schema 校验的桥接访问 Surface SDK。第一版不支持市场下载包执行本地 Rust、Node、Shell 或任意浏览器特权代码。
@@ -589,12 +621,18 @@ Runtime 检查 Manifest 声明、App 启用状态、Host 支持、前台要求
"version": "1.2.0", "version": "1.2.0",
"runtime_sdk": { "runtime_sdk": {
"api_version": "1", "api_version": "1",
"required_features": ["app.lifecycle.v1", "app.tools.v1", "surface.state.v1"], "required_features": ["app.lifecycle.v1", "app.tools.v1", "surface.state.v1", "app.instance-state.v1"],
"optional_features": ["artifact.create.v1"] "optional_features": ["artifact.create.v1"]
}, },
"entrypoints": [ "entrypoints": [
{"id": "canvas", "kind": "contextual", "default_eligible": false} {"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": [ "agent_subscriptions": [
{"type": "lineup.app.state.patch", "scope": "instance"}, {"type": "lineup.app.state.patch", "scope": "instance"},
{"type": "lineup.tool.invoke", "scope": "conversation"} {"type": "lineup.tool.invoke", "scope": "conversation"}
@@ -622,6 +660,7 @@ identity 用户、设备、认证会话
connection AppServer 状态、cursor、重试、outbox connection AppServer 状态、cursor、重试、outbox
conversations Agent 映射、消息引用、任务、交互、Artifact 元数据 conversations Agent 映射、消息引用、任务、交互、Artifact 元数据
apps App Registry、默认 App、运行实例、App Inbox apps App Registry、默认 App、运行实例、App Inbox
app_state 按 app_scope + instance_id 隔离的业务状态快照与 revision
tools 已声明 Tool、可见性、调用与 operation tools 已声明 Tool、可见性、调用与 operation
capabilities 授权、执行状态、最小审计 capabilities 授权、执行状态、最小审计
``` ```
@@ -648,7 +687,7 @@ lineup-app/
│ ├── apps/ App Manager、Registry、Instance、Focus、Lifecycle Manager │ ├── apps/ App Manager、Registry、Instance、Focus、Lifecycle Manager
│ ├── tools/ Tool Registry、Inventory、Router、call lifecycle │ ├── tools/ Tool Registry、Inventory、Router、call lifecycle
│ ├── capabilities/ Capability Gateway │ ├── capabilities/ Capability Gateway
│ └── persistence/ Runtime Store、App Inbox、Artifact metadata │ └── persistence/ Runtime Store、App Inbox、instance state snapshot、Artifact metadata
├── runtime-sdk/ ├── runtime-sdk/
│ ├── app.ts Core App SDK 类型 │ ├── app.ts Core App SDK 类型
│ ├── manifest.ts App/Tool/Subscription Manifest 类型 │ ├── manifest.ts App/Tool/Subscription Manifest 类型
@@ -699,6 +738,8 @@ lineup-app/
- 将动态 Inventory 同步给 Agent - 将动态 Inventory 同步给 Agent
- 实现 Agent `tool.invoke` → Runtime → App SDK → `tool.result` 的可靠闭环; - 实现 Agent `tool.invoke` → Runtime → App SDK → `tool.result` 的可靠闭环;
- App 未运行时持久化 Inbox,恢复后可幂等补读。 - App 未运行时持久化 Inbox,恢复后可幂等补读。
- 实现 `app.instance-state.v1`Manifest schema / schema version / quota / retention 校验、instance 隔离、
revisioned replace、刷新/重启恢复与关闭/禁用/移除清理;Tool/operation/outbox 不得由该 API 直接改写。
### R4:第一个 Installed App 闭环 ### R4:第一个 Installed App 闭环
@@ -716,6 +757,8 @@ lineup-app/
5. 下载型 App 无法访问 Tauri invoke、Host DOM、token 或未授予 Capability 5. 下载型 App 无法访问 Tauri invoke、Host DOM、token 或未授予 Capability
6. 默认 App 不可用时 Runtime 自动进入 chat Recovery App 6. 默认 App 不可用时 Runtime 自动进入 chat Recovery App
7. 所有 Tool 调用、权限拒绝与终态结果均可按 app_scope、conversation_id、call_id 审计和测试。 7. 所有 Tool 调用、权限拒绝与终态结果均可按 app_scope、conversation_id、call_id 审计和测试。
8. MiniApp 只能读写自身当前 instance 的状态快照;非法 schema、旧 revision、跨 instance、超配额以及
关闭后的写入均被稳定拒绝,重启只恢复最后一个有效快照。
``` ```
## 14. 与已有正式方案的关系 ## 14. 与已有正式方案的关系
@@ -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. 本评审只记录发现,未修改主定义、计划、正式方案或实现。
@@ -1,30 +1,35 @@
# LineUp App 迭代定义:Runtime 工作区与 Pomodoro MiniApp # LineUp App 迭代定义:Runtime 工作区与 Pomodoro MiniApp
**迭代编号:** 04.runtime_workspace **迭代编号:** 04.runtime_workspace
**状态:** 草稿,待设计评审 **状态:** 设计已冻结,待实施
**日期:** 2026-08-06 **日期:** 2026-08-06
**前置基线:** [03.sdk_and_coreapp.md](../03.sdk_and_coreapp/03.sdk_and_coreapp.md) **前置基线:** [03.sdk_and_coreapp.md](../03.sdk_and_coreapp/03.sdk_and_coreapp.md)
**总体计划:** [plan.md](../plan.md) **总体计划:** [plan.md](../plan.md)
**权威架构:** [APP架构设计.md](../../设计/APP架构设计.md) **权威架构:** [APP架构设计.md](../../设计/APP架构设计.md)
**冻结说明:** 本定义以 [03.design_review.md](03.design_review.md) 关闭后的决议为实施基线;后续若调整
Pomodoro Tool、Runtime 终态、状态快照或本迭代范围,须通过新的设计评审记录确认。
## 1. 迭代目标 ## 1. 迭代目标
前三次迭代已经完成 Runtime、Interact、MiniApp SDK v1 和参考 MiniApp 的基础契约。本迭代不再扩展 前三次迭代已经完成 Runtime、Interact、MiniApp SDK v1 和参考 MiniApp 的基础契约。本迭代不再扩展
复杂的业务应用,而是把这些基础接到真实的 Web/Tauri 工作区界面,证明用户可以启动、切换、后台化、 复杂的业务应用,而是把这些基础接到真实的 Web/Tauri 工作区界面,证明用户可以启动、运行、关闭、恢复
关闭、恢复一个 MiniApp,并在 Interact 中查看对应的子会话。 一个 MiniApp,并在 Interact 中查看对应的子会话。
本迭代选择一个极简的 **Pomodoro 番茄时钟 MiniApp** 作为 Runtime 验证应用。番茄时钟只负责倒计时和 本迭代选择一个极简的 **Pomodoro 番茄时钟 MiniApp** 作为 Runtime 验证应用。它服务于写作业、看书、
自己的完成提醒,不负责任务、项目或复杂业务管理。 冥想等单次专注活动:第 04 次中用户通过 **IM** 请求 Agent 立即开始或停止一段固定时长的专注;未来 Voice
复用相同意图与 Tool 语义,但不属于本轮实现或验收。Pomodoro 只负责低干扰显示,不负责任务、项目、统计或
通用烹饪/家务倒计时。
```text ```text
Interact IM Interact IM
→ Agent 请求启动 Pomodoro → Agent 请求启动 Pomodoro
→ Runtime 创建 App instanceApp 子会话 → Runtime 创建 App instanceApp 子会话和 deadline operation
→ Pomodoro 进入前台,Interact 进入后台 → Pomodoro 进入前台,Interact 进入后台
→ 计时在后台继续运行 用户专注;自动暗屏或锁屏不改变本轮计时
用户暂停、继续、取消或回到 Interact 到时间完成,或用户主动离开专注工作区而中断
到时间显示完成提醒并回传结果 Runtime 回传结果并立即收口关闭 App,恢复 Interact
用户关闭 AppRuntime 收口并恢复 Interact Interact / Agent 呈现本次专注完成结果
→ 子会话在 IM 中折叠保存 → 子会话在 IM 中折叠保存
→ 重启后按规则恢复或继续处理 → 重启后按规则恢复或继续处理
``` ```
@@ -35,7 +40,7 @@ Interact IM
Interact 仍然是系统级 `system` MiniApp,负责人与 Agent 的交互: Interact 仍然是系统级 `system` MiniApp,负责人与 Agent 的交互:
- Agent 请求启动或控制番茄钟 - Agent 通过 `pomodoro.start` 请求立即开始一段专注,也可以通过 `pomodoro.interrupt` 结束当前专注
- Agent 向用户询问是否开始下一轮; - Agent 向用户询问是否开始下一轮;
- Agent 需要用户确认时使用 `notice / choice / confirm / input` - Agent 需要用户确认时使用 `notice / choice / confirm / input`
- 交互记录属于 Interact 和对应会话,不属于 Pomodoro 的内部 UI。 - 交互记录属于 Interact 和对应会话,不属于 Pomodoro 的内部 UI。
@@ -47,7 +52,8 @@ Runtime 负责最终裁决和可靠性:
- 创建和管理 Pomodoro App instance - 创建和管理 Pomodoro App instance
- 管理前台、后台、挂起、关闭和恢复; - 管理前台、后台、挂起、关闭和恢复;
- 校验 Tool、作用域、实例和会话上下文; - 校验 Tool、作用域、实例和会话上下文;
- 保存计时状态和工作区快照; - 为每个 App instance 保存 schema 校验、revision 控制的业务状态快照;
- 管理通用 deadline operation:持久化 `ends_at`、裁决完成/中断唯一终态并写唯一 outbox;
- 处理刷新、断线和重启恢复; - 处理刷新、断线和重启恢复;
- 关闭 App 时停止新 Tool 投递,并收口未完成操作; - 关闭 App 时停止新 Tool 投递,并收口未完成操作;
- 通过 outbox 可靠回传结果; - 通过 outbox 可靠回传结果;
@@ -60,11 +66,10 @@ Capability 规则。
它只负责: 它只负责:
- 显示倒计时 - 显示活动名称、倒计时和低干扰专注界面
- 响应暂停、继续和取消 - 根据 Runtime 投影的 operation 与 instance state 刷新界面
- 根据 Runtime 提供的状态刷新界面 - 接收 Runtime 路由的 Agent Tool 和状态投影;不以界面按钮直接改变专注业务状态
- 到时间显示自己的完成提醒 - 通过 SDK 保存自身展示所需的业务状态快照
- 通过 SDK 报告状态和结果。
它不能: 它不能:
@@ -75,46 +80,159 @@ Capability 规则。
## 3. Pomodoro 最小模型 ## 3. Pomodoro 最小模型
第一版只保留以下状态: Pomodoro App instance 和一次专注 operation 不是同一个对象:`app_session_id` 表示 Interact 中围绕该
instance 的子会话,`instance_id` 表示 MiniApp 实例,`operation_id` 才表示一次实际专注。第一版由
`pomodoro.start` 同时创建它们;它们不在数据模型上互为同义词。
一次专注 operation 只保留以下状态:
```text ```text
idle 尚未开始 focusing 正在专注
running 正在计时 completed 到达约定时长
paused 已暂停 interrupted 用户明确离开、切换工作区或关闭 App 后中断
completed 已完成
cancelled 已取消
``` ```
最小数据: 最小 operation 数据:
```text ```text
timer_id operation_id
source_tool_call_id
activity?
duration_seconds duration_seconds
started_at started_at
ends_at ends_at
remaining_seconds
state state
ended_at?
interruption_reason?
``` ```
建议的最小 Tool 运行中只以 `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 ```text
pomodoro.start pomodoro.start({ duration_seconds, activity? })
pomodoro.pause pomodoro.interrupt({})
pomodoro.resume
pomodoro.cancel
pomodoro.status
``` ```
Runtime 不解释“番茄钟”业务,只管理一个有生命周期的计时操作。计时完成后,Pomodoro 可以显示普通 `pomodoro.start` 是长期 Tool operationAgent 调用成功后立即进入 `focusing`,只在 `completed`
完成提示;如果 Agent 要询问用户是否开始下一轮,必须回到 Interact 的标准交互。 `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. 工作内容
### 4.1 工作区界面 ### 4.1 工作区界面
- 显示当前前台 App - 显示当前前台 App
- 支持 Interact Pomodoro 之间切换; - 支持`pomodoro.start` Interact 切入 Pomodoro,以及用户显式返回 Interact;返回/切换会中断当前
专注 operation,而不是把它作为通用后台计时器继续运行;
- 显示 App 前台、后台、挂起、关闭和恢复状态; - 显示 App 前台、后台、挂起、关闭和恢复状态;
- App 启动失败时恢复 Interact - App 启动失败时恢复 Interact
- 刷新或重启后恢复工作区快照。 - 刷新或重启后恢复工作区快照。
@@ -122,38 +240,51 @@ Runtime 不解释“番茄钟”业务,只管理一个有生命周期的计时
### 4.2 生命周期接入 ### 4.2 生命周期接入
-`AppLifecycleManager``AppFocusManager``AppOrchestrator` 接入真实 Host -`AppLifecycleManager``AppFocusManager``AppOrchestrator` 接入真实 Host
- 区分后台、挂起和真正关闭 - 区分自动暗屏/锁屏、Surface 重载、工作区切换和真正关闭:前两者不终止专注,后两者中断专注
- 后台运行时保持计时 - Runtime 用持久化 `ends_at` 而非 MiniApp UI 定时器管理 deadline;到点、用户中断和关闭竞争同一唯一终态
- deadline 取得 `completed` 后,Runtime 依次提交唯一结果/outbox、立即关闭 Pomodoro、结束子会话并恢复
Interact;完成提示由 Interact / Agent 呈现,不保留 Pomodoro 完成展示窗口;
- 关闭后停止向该 instance 投递新 Tool - 关闭后停止向该 instance 投递新 Tool
- 将未终态普通 Tool 收敛为 `cancelled(app_closed)` - 用户退出专注时先将 `pomodoro.start` 终结为 `interrupted` 并提交结果;随后关闭不会将该已终态 Tool 改写为
`cancelled(app_closed)`。其他未终态普通 Tool 仍按 `cancelled(app_closed)` 收口;
- 已提交结果继续通过 outbox 发送; - 已提交结果继续通过 outbox 发送;
- 关闭后恢复前一个有效前台 App。 - 关闭后恢复前一个有效前台 App。
### 4.3 子会话和 Interact 交互 ### 4.3 子会话和 Interact 交互
- 创建 Pomodoro instance 时创建或恢复 App 子会话; - 创建 Pomodoro instance 时创建 App 子会话;只有恢复同一个未结束 instance 时才恢复同一个子会话;
- 在主 IM 中显示可折叠的 Pomodoro 子会话; - 在主 IM 中显示可折叠的 Pomodoro 子会话;
- 子会话只记录人与 Agent 围绕该番茄钟的交互和结果; - 子会话只记录人与 Agent 围绕该番茄钟的交互和结果;
- 倒计时、暂停按钮、继续按钮等 App 内部操作不写入 IM; - 倒计时和退出按钮等 App 内部操作不写入 IM;
- App 前台时,Interact 的标准交互可以显示在其上方; - App 前台时,Interact 的标准交互可以显示在其上方;
- 展示位置变化不改变交互归属; - 展示位置变化不改变交互归属;
- 已结束子会话只读;“继续处理”创建新的 instance 和新的子会话 - 已结束子会话只读;“继续处理”创建新的 instance 和新的子会话;关闭时仍 pending 的 Interact 标准交互
不自动取消,保留在主 IM / Interact 中等待回答、dismiss、超时或 Runtime 失败,且不能再追加到已结束子会话。
### 4.4 恢复和提醒 ### 4.4 恢复和提醒
- 重启后根据 `ends_at` 重新计算剩余时间; - 重启后根据 `ends_at` 重新计算剩余时间;若已到点,Runtime 原子转为 `completed` 并只写一次结果/outbox
- 不允许重启后无条件重新开始完整时长; - 不允许重启后无条件重新开始完整时长;
- 明确后台、暂停、关闭和完成的区别 - 不承诺 Runtime / Host 完全未运行时的即时系统提醒;下次恢复时必须按已到期状态结算,不能重置或重复回传
- 第一版只实现 App 内完成提示 - 来电等外部打断预留 `host_interruption` 语义,但第 04 次不实现电话检测、免打扰或静音能力
- 明确自动暗屏/锁屏、工作区离开、关闭、完成和中断的区别;
- 第一版不实现 Pomodoro App 内完成提示;完成结果由 Interact / Agent 呈现;
- 系统通知作为后续 Capability 验证,不允许 MiniApp 直接调用系统 API。 - 系统通知作为后续 Capability 验证,不允许 MiniApp 直接调用系统 API。
### 4.5 自动化和真实验收 ### 4.5 自动化和真实验收
- 覆盖 Pomodoro 状态机和 Tool 调用 - 覆盖 `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 子会话创建、折叠、只读和继续处理; - 覆盖 App 子会话创建、折叠、只读和继续处理;
- 覆盖 Interact 标准交互在 Pomodoro 前台时仍归 Interact - 覆盖 Interact 标准交互在 Pomodoro 前台时仍归 Interact,以及 Pomodoro 关闭后 pending 交互仍可在主 IM
回答但不改写只读子会话;
- 通过 Web Reference Host 完成完整浏览器验收; - 通过 Web Reference Host 完成完整浏览器验收;
- 在 Tauri Desktop Host 完成至少一条代表性流程; - 在 Tauri Desktop Host 完成至少一条代表性流程;
- 检查生命周期、Tool、交互、恢复和拒绝路径日志。 - 检查生命周期、Tool、交互、恢复和拒绝路径日志。
@@ -165,23 +296,37 @@ Runtime 不解释“番茄钟”业务,只管理一个有生命周期的计时
- 多 Agent 连接和 Agent 切换; - 多 Agent 连接和 Agent 切换;
- Audio Mode 和 Video Mode 的真实媒体能力; - Audio Mode 和 Video Mode 的真实媒体能力;
- Pomodoro 统计报表、多个计时器、日历和复杂提醒计划; - Pomodoro 统计报表、多个计时器、日历和复杂提醒计划;
- 通用倒计时(如烹饪、停车、家务)以及用户预设后手动开始的 timer 模式;
- 电话检测、系统专注模式、免打扰、静音和系统通知;
- Task Dashboard 的任务、项目、优先级、标签和历史管理; - Task Dashboard 的任务、项目、优先级、标签和历史管理;
- Whiteboard 的多人协作、云端同步和复杂绘图工具 - Whiteboard 的工作区接入、切换、完整用户流程、多人协作、云端同步和复杂绘图工具;第 04 次只保持第
03 次已有的 SDK / 隔离回归。
- 将 MiniApp SDK 或 Runtime SDK 的实现迁入 Rust;本轮保持现有 TypeScript Runtime / Web Bridge 基线,
未来仅在 profiling 证明 Runtime Core 存在性能热点后另行评估。
## 6. 验收目标 ## 6. 验收目标
```text ```text
1. 用户可以从 Interact 启动 Pomodoro。 1. 用户可以在 **IM** 中请求 Agent 立即开始或停止一段固定时长的写作业、看书或冥想专注;未来 Voice 必须
2. Runtime 创建真实 App instance、焦点记录和 App 子会话 复用同一意图和 Tool 语义,但不属于本轮实现或验收
3. Pomodoro 进入前台后,Interact 可以退到后台 2. `pomodoro.start` 创建真实 App instance、焦点记录、App 子会话和 deadline operation,并直接进入 `focusing`
4. Pomodoro 在后台仍然正确计时 3. Pomodoro 进入前台后,Interact 可以退到后台;自动暗屏、锁屏和 Surface 重载不终止专注
5. 用户可以暂停、继续和取消计时。 4. 用户以 IM / Voice 要求 Agent 停止时,Agent 调用 `pomodoro.interrupt({})`;用户返回 Interact、切到其他
6. 到时间后 Pomodoro 显示完成提示,并通过 Runtime 回传结果。 MiniApp 或关闭 Pomodoro 时,Runtime 直接处理生命周期中断。两类路径的本轮唯一终态均为 `interrupted`
7. 用户关闭 Pomodoro 后,未完成操作正确取消,Interact 恢复前台 随后 Interact 恢复前台;Pomodoro 不作为通用后台计时器继续运行
8. 子会话在主 IM 中折叠保存,已结束内容只读。 5. 到 `ends_at` 时,本轮唯一终态为 `completed`Runtime 提交唯一结果/outbox 后立即关闭 Pomodoro、结束子会话
9. 用户选择继续处理时,Runtime 创建新的 instance 和新的 App 子会话 并恢复 Interact,由 Interact / Agent 呈现完成结果;到点和中断并发时只接受第一个原子终态
10. 刷新或重启后,剩余时间、App 状态、焦点和子会话按规则恢复。 6. Runtime 只回传一次 `pomodoro.start` 的 `completed` 或 `interrupted` 结果;`pomodoro.interrupt` 不可伪造
11. Agent 的标准交互始终由 Interact 负责,Pomodoro 不伪造交互组件。 目标、只能绑定当前会话中活动的 `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。 12. MiniApp 无法访问 Transport、Store、Agent、Host DOM、Tauri 或任意系统 API。
13. `npm test -- --run`、`npm run build` 和 Web/Tauri 代表性验收全部通过。 13. `npm test -- --run`、`npm run build` 和 Web/Tauri 代表性验收全部通过。
14. P0~P3 设计和验收问题清零。 14. P0~P3 设计和验收问题清零。
+69 -33
View File
@@ -47,7 +47,7 @@ Runtime 已具备应用实例、焦点和生命周期的核心模型:
`03.sdk_and_coreapp` 已完成并通过自动化测试和浏览器验收: `03.sdk_and_coreapp` 已完成并通过自动化测试和浏览器验收:
- Interact 是唯一的 `system` MiniApp - Interact 是唯一的 `system` MiniApp
- 番茄时钟、Task Dashboard 和 Whiteboard 都是普通 `bundled` MiniApp - Task Dashboard 和 Whiteboard 都是普通 `bundled` MiniApp 的参考实现
- MiniApp 通过 SDK 接收 Inbox、Tool、进度、结果、生命周期、Surface 和 Capability 请求; - MiniApp 通过 SDK 接收 Inbox、Tool、进度、结果、生命周期、Surface 和 Capability 请求;
- 标准 `notice / choice / confirm / input` 属于 Interact 的人与 Agent 交互,不是 MiniApp 内部表单; - 标准 `notice / choice / confirm / input` 属于 Interact 的人与 Agent 交互,不是 MiniApp 内部表单;
- App 子会话、交互归属、关闭收口、继续处理和重启恢复已有明确规则; - App 子会话、交互归属、关闭收口、继续处理和重启恢复已有明确规则;
@@ -57,6 +57,10 @@ Runtime 已具备应用实例、焦点和生命周期的核心模型:
## 3. 第四次迭代: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 ```text
@@ -70,12 +74,11 @@ Runtime 已具备应用实例、焦点和生命周期的核心模型:
```text ```text
进入 Interact IM 进入 Interact IM
→ Agent 请求启动 Pomodoro 番茄时钟 → Agent 请求启动 Pomodoro 番茄时钟
→ Runtime 创建 App instanceApp 子会话 → Runtime 创建 App instanceApp 子会话和 deadline operation
→ 番茄时钟进入前台,Interact 进入后台 → 番茄时钟进入前台,Interact 进入后台
计时在后台继续运行 用户进行写作业、看书或冥想等固定时长专注;自动暗屏/锁屏不终止本轮
用户可以暂停、继续、取消或回到 Interact 到时间完成,或用户主动离开 Pomodoro 工作区而中断
到时间后显示完成提醒并回传结果 Runtime 回传唯一结果并关闭 App
→ 用户关闭 App,Runtime 收口未完成操作
→ 子会话结束并在 IM 中折叠保存 → 子会话结束并在 IM 中折叠保存
→ Interact 恢复 → Interact 恢复
→ 用户查看历史或继续开始下一轮 → 用户查看历史或继续开始下一轮
@@ -85,16 +88,21 @@ Runtime 已具备应用实例、焦点和生命周期的核心模型:
1. **接通 App 工作区界面** 1. **接通 App 工作区界面**
- 显示当前前台 App - 显示当前前台 App
- 支持 InteractPomodoro 番茄时钟、Whiteboard 的切换 - 支持`pomodoro.start` Interact 进入 Pomodoro,以及用户明确返回 Interact
返回/切换会中断当前专注,不把 Pomodoro 作为通用后台计时器继续运行;
- 显示后台、挂起、关闭和恢复状态; - 显示后台、挂起、关闭和恢复状态;
- App 启动失败时恢复 Interact - App 启动失败时恢复 Interact
- 刷新或重启后恢复工作区。 - 刷新或重启后恢复工作区。
Whiteboard 在第 04 次只保持第 03 次已有的 SDK/隔离回归,不接入本轮工作区切换或新的完整流程。
2. **接通 App 生命周期** 2. **接通 App 生命周期**
-`AppLifecycleManager``AppFocusManager``AppOrchestrator` 接入真实 Host -`AppLifecycleManager``AppFocusManager``AppOrchestrator` 接入真实 Host
- 区分后台、挂起和真正关闭 - 区分自动暗屏/锁屏、Surface 重载、工作区切换和真正关闭;前两者不终止专注,后两者中断专注
- Runtime 使用持久化 `ends_at` 的 deadline operation,而不是 MiniApp UI 定时器;
- 关闭后停止新 Tool 投递; - 关闭后停止新 Tool 投递;
- 将未终态普通 Tool 收敛为 `cancelled(app_closed)` - 用户退出专注时先将 `pomodoro.start` 终结为 `interrupted`其他未终态普通 Tool 才收敛为
`cancelled(app_closed)`
- 已提交结果继续通过 outbox 发送; - 已提交结果继续通过 outbox 发送;
- 关闭后恢复前一个有效前台 App。 - 关闭后恢复前一个有效前台 App。
@@ -113,39 +121,46 @@ Runtime 已具备应用实例、焦点和生命周期的核心模型:
- Agent 可以通过 `interaction.dismiss` 远程取消交互。 - Agent 可以通过 `interaction.dismiss` 远程取消交互。
5. **让 Pomodoro 成为第一条完整用户流程** 5. **让 Pomodoro 成为第一条完整用户流程**
- Agent 请求启动一个番茄钟; - 用户在 IM 中以自然语言要求 Agent 开始或结束写作业、看书或冥想等专注;MiniApp 是 Agent 的业务工具,
- Runtime 创建计时实例和 App 子会话 而不是由用户自行操作业务状态的独立应用。未来 Voice 复用相同意图和 Tool 语义,但不属于本轮实现或验收
- 用户可以查看剩余时间、暂停、继续和取消; - Agent 以 `pomodoro.start({ duration_seconds, activity? })` 创建长期 Tool operation,并以
- 番茄钟切到后台后仍能继续计时 `pomodoro.interrupt({})` 请求结束当前专注
- 到时间后显示完成提醒并回传结果; - 同一会话已有 `focusing` 专注时,不同调用的第二次 `pomodoro.start` 稳定拒绝为
- 用户关闭番茄钟时,Runtime 正确取消未完成操作 `active_focusing_operation`,不创建新的 App、子会话或 deadline operation
- 刷新或重启后根据 `ends_at` 恢复剩余时间 - 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 中查看。 - 完成记录和子会话可以在 Interact 中查看。
第一版只保留这些状态和数据: 第一版只保留这些状态和数据:
```text ```text
state = idle | running | paused | completed | cancelled state = focusing | completed | interrupted
timer_id operation_id
source_tool_call_id
activity?
duration_seconds duration_seconds
started_at started_at
ends_at ends_at
remaining_seconds ended_at?
interruption_reason?
``` ```
建议的最小 Tool 最小 Agent Tool
```text ```text
pomodoro.start pomodoro.start({ duration_seconds, activity? })
pomodoro.pause pomodoro.interrupt({})
pomodoro.resume
pomodoro.cancel
pomodoro.status
``` ```
番茄钟到时间后的普通完成提醒属于 MiniApp 自己的业务提示;如果以后需要系统通知,再通过 Pomodoro 使用 `app.instance-state.v1` 保存严格 schema v1、最大 4 KiB 的展示快照;关闭后采用
Runtime 的 Capability 请求,不能让 MiniApp 直接调用 Tauri 或操作系统接口。Agent 询问用户是否 `retain_readonly`,旧快照只用于历史展示,不能再次写入或恢复为运行中的专注。
开始下一轮时,仍然必须使用 Interact 的标准交互。
番茄钟到点后不保留 App 内完成提醒:Runtime 关闭 Pomodoro 并恢复 Interact,由 Interact / Agent 呈现
完成结果。如果以后需要系统通知,再通过 Runtime 的 Capability 请求,不能让 MiniApp 直接调用 Tauri
或操作系统接口。Agent 询问用户是否开始下一轮时,仍然必须使用 Interact 的标准交互。
6. **补充端到端验收** 6. **补充端到端验收**
- Web Reference Host 完整验收; - Web Reference Host 完整验收;
@@ -160,20 +175,23 @@ Runtime 已具备应用实例、焦点和生命周期的核心模型:
- 多 Agent 连接、切换和多 Agent 会话列表; - 多 Agent 连接、切换和多 Agent 会话列表;
- Audio Mode 的真实媒体能力; - Audio Mode 的真实媒体能力;
- Video Mode 的真实媒体能力; - Video Mode 的真实媒体能力;
- Whiteboard 的多人协作和复杂绘图能力; - Whiteboard 的工作区接入、切换、多人协作和复杂绘图能力;第 04 次只保持其已有回归;
- Task Dashboard 的完整项目管理功能; - Task Dashboard 的完整项目管理功能;
- Pomodoro 的统计报表、多个计时器、日历和复杂提醒计划。 - Pomodoro 的统计报表、多个计时器、日历和复杂提醒计划。
### 3.4 完成标准 ### 3.4 完成标准
```text ```text
用户可以 Interact 启动 Pomodoro 番茄时钟 用户可以 IM 中请求 Agent 立即开始或停止 Pomodoro 专注;未来 Voice 只复用相同 Tool 语义
Runtime 可以正确创建、切换、后台化、关闭和恢复 App Runtime 可以正确创建、运行、中断、关闭和恢复 Pomodoro App
App 子会话能在 IM 中折叠、展开和继续处理; App 子会话能在 IM 中折叠、展开和继续处理;
标准交互在不同前台 App 下仍归 Interact 标准交互在不同前台 App 下仍归 Interact
关闭 App 时 Tool 和 outbox 收口正确; 到点/中断竞争唯一终态,Tool 和 outbox 收口正确;
刷新/重启后 App、焦点、子会话、计时剩余时间和待处理交互按规则恢复 到点后立即关闭 Pomodoro 并由 Interact / Agent 呈现完成结果
Pomodoro 关闭后的业务快照保留为只读历史,不能复活旧 instance;
刷新/重启后 App、焦点、子会话、`ends_at` 专注状态和待处理交互按规则恢复;
Web/Tauri 代表性流程通过端到端验收; Web/Tauri 代表性流程通过端到端验收;
Whiteboard 保持第 03 次回归,但不属于第 04 次工作区闭环或完成范围;
所有 P0P3 评审问题清零。 所有 P0P3 评审问题清零。
``` ```
@@ -242,6 +260,24 @@ Task Dashboard 仍然保留为后续普通 `bundled` MiniApp,但不作为 Runt
## 7. 更后面的方向 ## 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 工作区稳定后再设计: