Compare commits
5 Commits
934bccb274
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 91982fac33 | |||
| aff5c8e3aa | |||
| 89626546b9 | |||
| ef528a147b | |||
| 359dc1bb66 |
Generated
+4
-4
@@ -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
@@ -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"
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
declare module "*.css" {
|
||||||
|
const stylesheet: string;
|
||||||
|
export default stylesheet;
|
||||||
|
}
|
||||||
+1
-2
@@ -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,
|
||||||
|
|||||||
@@ -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 汇总为动态 Inventory;Agent 只能调用当前 Inventory 中的方法。 |
|
| Agent 工具 | App 在 Manifest 声明方法,Runtime 汇总为动态 Inventory;Agent 只能调用当前 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 schema;Runtime 是持久化、隔离、并发裁决、恢复和清理的唯一所有者。它不是供 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 给 Agent;Tool 可声明是否需要启动 App、是否要求前台以及结束后是否恢复原焦点;
|
- 在 Runtime 连接与状态变化时同步 revisioned Inventory 给 Agent;Tool 可声明是否需要启动 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 数据和可恢复 snapshot,Runtime 负责配额、升级迁移、禁用和移除时的清理。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 直接启动的单次专注 operation:Runtime 托管 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 / Whiteboard;Pomodoro 在第 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 schema;MiniApp 通过一个最小、受 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-06:SDK 是否迁入 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 都迁入 Rust,bundled 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-01~D04-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-01~D04-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-C1:instance 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、改变
|
||||||
|
焦点或绕过 lifecycle;Pomodoro 的到期/中断和唯一 Tool result 必须由 Runtime deadline operation 裁决。
|
||||||
|
|
||||||
|
这也没有把静态 IM/App 子会话误当作 MiniApp 业务存储:第 04 次主定义仍只让子会话记录人与 Agent 的交互和
|
||||||
|
结果,符合第 03 次“App 子会话不是 App 操作日志”的规则。
|
||||||
|
|
||||||
|
### D04-C2:Agent 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-C4:App 子会话和 pending Interact 已一致
|
||||||
|
|
||||||
|
主定义限制“仅恢复同一个未结束 instance 时复用同一个子会话”;结束后子会话只读;关闭时仍 pending 的
|
||||||
|
Interact 标准交互留在主 IM/Interact 中,回答不得追加到旧子会话。该规则与第 03 次的 instance 生命周期、
|
||||||
|
`pending_interaction_call_ids` 和“关闭不自动取消 Interact 交互”规则一致。前台 Pomodoro 上的 Interact
|
||||||
|
覆盖层也没有改变交互 owner。
|
||||||
|
|
||||||
|
### D04-C5:Whiteboard 范围已消除冲突
|
||||||
|
|
||||||
|
`04.runtime_workspace.md` 第 5 节与 `plan.md` 第 3 节均明确:Whiteboard 只保持第 03 次已完成的 SDK/隔离
|
||||||
|
回归,不接入第 04 次工作区切换或完整用户流程;Pomodoro 才是本轮唯一新增的工作区闭环验证应用。
|
||||||
|
|
||||||
|
### D04-C6:Rust 为正确的 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 原子完成后立即按一般收口关闭 instance,Surface 会先被
|
||||||
|
卸载,Pomodoro 无法兑现“App 内完成提示”;若 UI 本地自行显示后再关闭,则可能在重启、旧 Surface 或重复
|
||||||
|
回调下与已提交 outbox 脱节。第 03 次的既有规则还区分“Tool 完成不自动关闭 App/子会话”和
|
||||||
|
`AppLifecycleManager.close` 才结束子会话;第 04 次为 Pomodoro 采用不同的自动关闭策略是允许的,但必须
|
||||||
|
明确这是 Pomodoro 的特例及其顺序。
|
||||||
|
|
||||||
|
建议二选一并写入工作内容、恢复规则和验收:
|
||||||
|
|
||||||
|
1. **保留完成展示窗口。** deadline operation 原子写 `completed` 和唯一 result/outbox,Runtime 将终态投影给
|
||||||
|
Pomodoro;Surface 在一个明确的受控窗口内显示完成提示;窗口结束、用户确认或用户离开后由 Runtime 发起
|
||||||
|
`AppLifecycleManager.close`,再结束子会话并恢复 Interact。重启落在窗口内时须能按持久化终态恢复到同一
|
||||||
|
收口路径,而不得再写结果。
|
||||||
|
2. **立即收口。** Runtime 完成后立刻关闭 App、结束子会话、恢复 Interact;删除“Pomodoro 显示自己的完成
|
||||||
|
提示”,或将完成提示明确改为 Interact 的可信呈现而非已关闭 MiniApp 的 UI。
|
||||||
|
|
||||||
|
无论选择哪种,验收都应覆盖 `completed` 与 close 并发、已提交 outbox 的重试、终态 UI 不产生第二次 Tool
|
||||||
|
完成,以及完成前/后 pending Interact 的归属。
|
||||||
|
|
||||||
|
## D04-09:Pomodoro 的 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-07~D04-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 command;Agent 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 声明的 Tool;Pomodoro 本身只显示和接收 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` 的唯一结果 / outbox;Pomodoro 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
|
||||||
|
或 outbox;Agent 必须先调用 `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-10~D04-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 决定并调用 Tool;Pomodoro 的界面不提供
|
||||||
|
暂停、继续或“结束专注”的业务按钮。
|
||||||
|
|
||||||
|
```text
|
||||||
|
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 前验证它们。
|
||||||
|
|
||||||
|
```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 和生命周期稳定后,再单独定义任务管理业务模型。
|
||||||
@@ -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
@@ -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 operation,Pomodoro 直接进入专注界面;
|
||||||
|
- 到时间得到 `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 次工作区闭环或完成范围;
|
||||||
|
所有 P0~P3 评审问题清零。
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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 改写成 Rust:Web 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 类型建设。
|
||||||
Reference in New Issue
Block a user