19 KiB
LineUp App 迭代定义:Runtime 工作区与 Pomodoro MiniApp
迭代编号: 04.runtime_workspace 状态: 设计已冻结,待实施 日期: 2026-08-06 前置基线: 03.sdk_and_coreapp.md 总体计划: plan.md 权威架构: APP架构设计.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 只负责低干扰显示,不负责任务、项目、统计或 通用烹饪/家务倒计时。
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 只保留以下状态:
focusing 正在专注
completed 到达约定时长
interrupted 用户明确离开、切换工作区或关闭 App 后中断
最小 operation 数据:
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 决定并调用 Tool;Pomodoro 的界面不提供 暂停、继续或“结束专注”的业务按钮。
pomodoro.start({ duration_seconds, activity? })
pomodoro.interrupt({})
pomodoro.start 是长期 Tool operation:Agent 调用成功后立即进入 focusing,只在 completed 或
interrupted 时回传一次业务结果。pomodoro.interrupt({}) 是短 Tool:Tool 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 Schema;Runtime 在将 Descriptor 发布到 Agent Inventory 前验证它们。
{
"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 事实。
{
"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.v1schema、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. 验收目标
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 和生命周期稳定后,再单独定义任务管理业务模型。