初始化 agent_ops 文档治理体系

This commit is contained in:
2026-08-07 16:56:51 +08:00
commit 10840909ab
75 changed files with 15750 additions and 0 deletions
@@ -0,0 +1,785 @@
# LineUp Runtime 与 App SDK 架构方案
**版本:** 0.1(架构基线)
**状态:** 已确认的 Runtime / SDK 方向;尚未完全落地到当前 Tauri 实现
**日期:** 2026-08-06
**相关专题:** [运行时与智能体工具](运行时与智能体工具.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`、兼容迁移和实施顺序。
---
## 0. 结论与范围
LineUp 不是“聊天应用里附带一个交互 Runtime”。**LineUp App 本身就是运行在用户设备上的
协作 Runtime**,可以把它理解为本地协调中心:它独占与 AppServer / Remote Agent 的连接,
维护会话和本地应用生态,并为上层应用提供统一的消息、工具、存储、权限和生命周期接口。
聊天只是第一个使用这些接口的内置 App。
```text
Remote Agent
│ LineUp Runtime Envelope
AppServer / IM Transport
┌───────────────────────────────────────────────────────────────┐
│ LineUp Runtime │
│ │
│ Connection · Session · Event Routing · App Manager │
│ Tool Registry · Capability Gateway · Storage · Audit │
└───────────────┬──────────────────────────────┬────────────────┘
│ │
▼ ▼
Core App Installed App
chat whiteboard
app-registry voice
settings draw-and-guess
```
本方案定义:
- Runtime 与 Remote Agent、AppServer、上层 App、Tauri Host 的边界;
- 动态应用列表、应用身份、应用安装/启用/禁用/移除与实例生命周期;
- 应用向 Agent 公布工具方法的标准模型;
- Runtime 对消息的统一 Envelope、筛选、可靠投递与 App SDK 订阅接口;
- Core App、Installed App 和 Tauri Host 的信任分层;
- SDK v1 的最小接口和工程模块边界。
本方案不在本次冻结:市场目录的商业模型、支付、公开开发者身份认证细节、多人/多 Agent 共享工作区、完整事件溯源和后台持续执行策略。它们必须建立在本方案的身份、路由和权限边界上。
## 1. 基本术语
| 术语 | 含义 |
|---|---|
| **Runtime** | 用户设备上的长期协作运行底座;唯一负责 AppServer/Agent 通信、应用管理和 Host 能力调度。 |
| **App** | 用户实际使用的功能单元。Chat、应用注册表、语音、白板和游戏都是 App。 |
| **Core App** | 跟随 LineUp Runtime 一起发布、默认受信任的内置 App,例如 `chat`。 |
| **Installed App** | 从受信来源安装、验证后在受限执行环境中运行的 App。 |
| **App Registry** | Runtime 在本机保存的应用清单,记录安装包、版本、启用状态、实例和回滚信息;它是这些状态的唯一依据。 |
| **Tool** | App 先在 Manifest 中说明、Runtime 再公布给 Agent 的可调用方法。Agent 不能任意调用 App 内部函数。 |
| **本地 UI Action** | 用户在 MiniApp 界面触发、经 SDK / Bridge 发给 Runtime 的本地请求;可以复用内部业务动作,但不进入 Agent Inventory,也不是 Agent Tool。 |
| **Host 生命周期意图** | Host、工作区或系统发出的返回、切换、关闭、恢复等本地事件;Runtime 按生命周期和业务规则裁决,不能伪造成 Agent Tool。 |
| **Capability** | Runtime / Host 保管的系统能力,例如录音、选择文件、保存 Artifact;App 必须请求,不能自动获得。 |
| **Surface** | 一个受限的交互小界面,例如一块画板、一个语音会话面板或一局游戏。 |
| **Conversation** | 用户与一个主 Agent 协作的一段会话范围;App 实例、工具调用和 Artifact 默认都归属这段会话。 |
## 2. 不可变架构原则
1. **Runtime 是唯一 Agent 通信入口。** App 不直接访问 AppServer、IM SDK、WebSocket、HTTP cursor 或 Agent endpoint。
2. **App 只与 Runtime 通信。** Chat、Voice、Market、白板均通过 SDK 读状态、订阅消息、提交动作和请求能力。
3. **每一条可路由 Runtime 消息必须具有 `app_scope` 与 `conversation_id`。** Runtime 以它们作为本地路由、授权、筛选、持久化和投递的首要键。
4. **原始 Agent payload 不交给 App。** Runtime 完成版本、身份、schema、大小、去重和作用域校验后,才产生可订阅的标准化消息。
5. **应用可调用方法必须先声明、后公布、再调用。** Agent 不执行 App 内任意函数,只能调用当前 Inventory 中精确声明的方法。
6. **系统能力由 Runtime 独占。** Agent 和 App 只能请求 Capability;文件、麦克风、通知、剪贴板、窗口、密钥等均不得直接访问。
7. **应用状态、消息和副作用分离。** Event 是已发生事实,Command 是请求动作,Effect 是 Runtime 执行的受控副作用。
8. **UI 是 Runtime 状态的投影。** App 重启、断网或 Surface 回收后,Runtime 能依据持久化状态恢复到可解释的协作状态。
9. **MiniApp 业务数据由 Runtime 通用托管。** App 只能通过 SDK 保存当前 App 子会话的 JSON 数据字典;Runtime
不理解其业务 schema,但保证隔离、revision、持久化与恢复。App 不能直接访问浏览器/Host 存储、Conversation
Store、Tool/operation Store 或其他 App 数据。
## 3. 运行时分层
```text
┌──────────────────────────────────────────────────────────┐
│ Runtime Shell │
│ 应用切换 · 默认入口 · 连接状态 · 通知 · 安全恢复 │
├──────────────────────────────────────────────────────────┤
│ Core App / Installed App │
│ Interaction AppIM / Audio / Video · App Registry │
│ Settings · Whiteboard · Game · …(Installed App
├──────────────────────────────────────────────────────────┤
│ LineUp App Runtime SDK / Surface Bridge SDK │
├──────────────────────────────────────────────────────────┤
│ LineUp Runtime Core │
│ Communication · Coordination · App Management · Tooling │
├──────────────────────────────────────────────────────────┤
│ Runtime Host Provider │
│ Tauri Desktop / Web Reference Host 的文件、通知、窗口等 │
└──────────────────────────────────────────────────────────┘
```
Runtime 内部有三个平面:
| 平面 | 职责 |
|---|---|
| Communication Plane | 登录、AppServer 连接、历史同步、实时入站、ACK、outbox、重连。 |
| Coordination Plane | Envelope 校验、事件路由、会话/Agent 状态、App 生命周期、Tool Registry、Inventory、策略与审计。 |
| Execution Plane | Tauri/Host Capability、Surface Sandbox、Bundle Cache、Artifact 内容和受控副作用。 |
## 4. 应用作用域
本阶段**不定义跨市场、跨供应商的 App 身份、反向域名命名空间或发布者归属模型**。Runtime 仅维护本机可用的应用作用域键(`app_scope`),用于启动、隔离存储、消息路由和 Tool 路由。
```text
chat
app-registry
settings
voice
whiteboard
draw-and-guess
```
`app_scope` 是 Runtime 本地注册表中的短名称,不承诺在未来开放市场中全局唯一。开放生态时再通过版本化 Manifest 引入稳定 App ID、供应商身份和命名空间映射;届时不得破坏本节定义的 scope 路由语义。
### 4.1 作用域键
| 键 | 用途 |
|---|---|
| `conversation_id` | 协作会话边界;所有可路由消息均必填。 |
| `app_scope` | 消息所属/目标 App 边界;所有可路由消息均必填。 |
| `instance_id` | 可选;精确标识某块白板、语音会话或游戏实例。 |
| `operation_id` | 可选;标识长任务、导出、执行进度或异步工具操作。 |
| `call_id` | 可选;标识 Agent 发起的一次 Tool 调用。 |
Runtime 的全局管理事件也不省略路由键,而使用保留作用域:
```text
app_scope: runtime 或具体 Core App
conversation_id: runtime:global
```
第三方 App 不得使用或伪造上述保留身份。
## 5. Runtime App Manager 与交互编排
### 5.1 应用目录与状态
Runtime 维护本地 `App Registry`,它是 App 安装、版本、信任和启用状态的唯一事实源;
`App Instance Manager` 单独维护运行实例、前后台焦点和生命周期。App Catalog/市场只提供
候选条目;市场 App 不直接写文件、删除 Bundle 或改写 Registry。
```text
Catalog Entry → Downloading → Verifying → Installed → Enabled
│ │
│ ├── Active / Background / Suspended instances
│ └── Disabled
└── Update / Rollback / Remove
```
建议的 App Record
```ts
type AppRecord = {
app_scope: AppScope;
kind: "core" | "installed";
installed_version: string;
previous_version?: string;
enabled: boolean;
install_state: "installed" | "updating" | "failed";
active_instance_count: number;
installed_at: string;
enabled_at?: string;
};
type AppInstanceRecord = {
instance_id: AppInstanceID;
app_scope: AppScope;
conversation_id?: ConversationID;
state: "starting" | "foreground" | "background" | "suspended" | "stopping" | "stopped" | "failed";
parent_instance_id?: AppInstanceID;
started_at: string;
stopped_at?: string;
error?: string;
};
```
### 5.2 Runtime 管理接口
```ts
interface RuntimeAppManager {
listApps(filter?: AppListFilter): readonly AppRecord[];
getApp(appScope: AppScope): AppRecord | undefined;
subscribe(listener: (change: AppRegistryChange) => void): Unsubscribe;
install(request: InstallAppRequest): Promise<AppOperation>;
enable(appScope: AppScope): Promise<AppOperation>;
disable(appScope: AppScope, options?: DisableAppOptions): Promise<AppOperation>;
update(appScope: AppScope, targetVersion?: string): Promise<AppOperation>;
rollback(appScope: AppScope): Promise<AppOperation>;
remove(appScope: AppScope, options?: RemoveAppOptions): Promise<AppOperation>;
launch(request: LaunchAppRequest): Promise<AppInstanceHandle>;
closeInstance(instanceID: AppInstanceID): Promise<void>;
}
interface RuntimeAppOrchestrator {
launch(request: LaunchAppRequest): Promise<AppInstanceHandle>;
foreground(instanceID: AppInstanceID): Promise<AppInstanceHandle>;
background(instanceID: AppInstanceID, reason?: string): Promise<AppInstanceHandle>;
suspend(instanceID: AppInstanceID, reason?: string): Promise<AppInstanceHandle>;
restore(instanceID: AppInstanceID): Promise<AppInstanceHandle>;
closeInstance(instanceID: AppInstanceID): Promise<void>;
getFocusStack(conversationID?: ConversationID): readonly AppInstanceID[];
}
```
安装、验签、升级、禁用和移除是异步操作,必须返回可观察的 `AppOperation`。禁用会阻止新实例和新 Tool 调用,并收口现有实例;移除会在实例关闭及用户确认后清理 Bundle 和 App 私有数据。
### 5.3 默认应用与安全回退
Runtime Shell 不属于任何 App。它负责应用切换、通知、连接状态和安全恢复。用户可选择一个具备 `default_eligible` entrypoint 的已启用 App 作为默认入口:
```text
当前默认:chat → 图文 IM 为主
未来默认:voice → 实时语音为主
```
`chat` 是内建、不可移除的 Recovery App:默认 App 不兼容、被禁用、损坏或启动失败时,Runtime 必须回退到它。
启动优先级:
```text
显式启动目标(深链接/通知)
→ 可安全恢复的前台工作
→ 用户 Default App
→ chat Recovery App
```
### 5.4 前台焦点与 App 间切换
`Interaction App` 是默认的人与 Agent 交互入口,但不是全局调度器。Runtime 的
`App Orchestrator``Tool Router``Focus Manager` 负责决定 Agent 请求由哪个 App、哪个
交互模式或哪个标准组件承接。Interact 只通过 SDK 呈现当前会话并提交用户 Action。
```text
Interaction App / Audio Mode foreground
→ Agent 请求 launch(draw-and-guess)
Runtime 校验 Tool、Manifest、Inventory、参数和前台条件
→ Audio Instance background / suspended
→ Draw-and-Guess Instance starting → foreground
→ 游戏结果经 Runtime 回传 Agent
→ 关闭或结束后按 focus stack 恢复 Interaction App
```
前后台切换必须保留原实例和 `conversation_id` 的关联,不能因为界面暂时不可见就删除
未完成 Tool Call、Surface 或 App Inbox。若目标 App 启动失败,Runtime 应恢复原前台实例并
向 Agent 返回受控的 `app_start_failed``handler_failed` 结果。
## 6. Runtime Tool Registry 与动态 Inventory
本章中的 Tool 专指远端 Agent Tool:它是 Runtime 对 Agent 发布的调用说明书,不是用户 UI 的公共操作入口。Agent Tool、本地 UI Action 与 Host 生命周期意图的完整入口边界,以 [运行时与智能体工具](运行时与智能体工具.md) 为准。
### 6.1 App Tool
App 可在 Manifest 中声明 Agent 可调用方法。当前 Tool 由 App Scope、局部方法和契约版本定位:
```text
whiteboard/board.create@1
whiteboard/board.apply_diagram@1
voice/voice.request_recording@1
```
Runtime 内部使用结构化键,而不依赖字符串拼接:
```ts
type ToolKey = {
app_scope: AppScope;
method: string;
contract_version: string;
};
```
每个 Tool 声明至少包含:
- 标题、面向 Agent 的说明、输入/输出 JSON Schema
- `query``command``interactive``operation` 四种调用模型之一;
- 前台要求、超时、幂等规则和风险等级;
- 是否需启动 App 实例、是否允许 Runtime 自动启动;
- 该方法可能请求的 Capability。
### 6.2 可见性与 Inventory
Runtime 向 Agent 公布的工具不是安装包的全部声明,而是动态交集:
```text
Agent 可见 Tool
= 已验证 Manifest Tool
∩ App 已启用
∩ 当前 Host 支持
∩ 用户/组织策略允许
∩ 当前 Agent 和 conversation scope 允许
∩ 所需前置权限满足
```
Inventory 包含 App、Tool、Surface 和 Runtime Capability,并具有 revision。Runtime 在连接建立、App 启用/禁用/升级/撤销、Host 能力变化或策略收紧后重新发布。Agent 调用必须携带其看到的 `inventory_revision`;过期清单的调用应被安全拒绝并提示刷新。
### 6.3 Tool 调用流程
```text
Agent lineup.tool.invoke
→ Runtime 验证 Envelope、Agent、inventory revision、App 状态和参数 schema
→ 创建 call record / 审计记录
→ Tool Router 判断直接执行、启动 App、切换前台、等待用户交互,或创建异步 operation
→ App Orchestrator / Interaction App / Installed App 承接调用
→ Runtime / App 经 SDK 返回 protocol receipt、progress / result / error
→ Runtime 验证输出 schema、持久化、更新焦点并回传 Agent
```
若调用触发 App activationRuntime 在写入 `starting → ready | failed | cancelled` 后,通过同一 call_id 的受控
protocol receipt / progress 通知 Agent。`activation_ready` 表示 App 已能接收后续 `app_ready` ToolAgent 可据此顺序
编排调用,但 Runtime 仍须持久化并等待提前到达的合法调用,不能把时序正确性外包给 Agent。MiniApp、Surface 和 Host
不直接向 Agent 发送 ready`activation_not_required` Tool 不等待 activation。具体公开字段、等待队列和 Pomodoro
`started` 覆盖 `activation_ready` 的规则,以 [运行时与智能体工具](运行时与智能体工具.md) 为准。
标准终态错误码至少包括:
```text
cancelled_by_user
permission_denied
app_disabled
app_not_installed
app_version_mismatch
tool_not_visible
invalid_arguments
foreground_required
operation_expired
handler_failed
```
## 7. 统一消息 Envelope 与路由
### 7.1 Runtime Envelope
Runtime 对跨边界、需要传输或审计的消息使用统一基础 Envelope。该 Envelope 统一的是消息承载、作用域与校验字段,不把来源不同的入口合并成同一种调用:远端 Agent Tool、本地 UI Action 和 Host 生命周期意图必须保留不同的 sender、来源校验和审计类型。UI 点击不能仅因复用相同内部业务服务就被包装成 Agent Tool Call
```ts
type RuntimeEnvelope = {
v: 1;
id: string;
type: string;
timestamp: string;
sender: {
kind: "agent" | "runtime" | "app" | "user" | "host";
id: string;
};
target: {
kind: "runtime" | "app";
app_scope: AppScope;
instance_id?: AppInstanceID;
};
scope: {
app_scope: AppScope;
conversation_id: ConversationID;
instance_id?: AppInstanceID;
operation_id?: OperationID;
};
correlation?: {
reply_to?: string;
call_id?: string;
inventory_revision?: string;
sequence?: number;
};
payload: JsonValue;
};
```
`scope.app_scope` 是消息所属的本地应用作用域,`target.app_scope` 是指定的消费 App。通常二者相同;Runtime 协调型消息可使用 `runtime` 作为 target,再由 Runtime 生成安全的 App 投影并分发。
### 7.2 消息分类
第一版类型分组:
```text
lineup.content.* 文本、图片、音频、链接、Artifact 引用
lineup.agent.* presence、status、task、progress
lineup.interaction.* choice、confirm、input、form
lineup.tool.* invoke、accepted、progress、result、error、cancel
lineup.app.* state.patch、event、open、close、lifecycle
lineup.capability.* request、result
lineup.runtime.* inventory、connection、app registry、policy、error
```
具体 schema 将在协议文档版本化;SDK 不暴露未经校验的原始 JSON。
### 7.3 Runtime 筛选链
```text
Transport 收到原始消息
→ 协议:版本、必填 app_scope/conversation_id、type、大小、schema
→ 身份:Agent、用户、会话关联
→ 去重/顺序:id、sequence、cursor
→ App:安装、启用、版本、签名、Host 兼容性
→ Tool/CapabilityInventory、方法、参数、策略、前台条件
→ Scopeconversation、instance、operation 所属关系
→ SubscriptionApp Manifest 声明与 SDK 订阅交集
→ PersistRuntime Event / App Inbox / cursor
→ Deliver:投递给目标 App 的 SDK
```
Runtime 不对所有 App 广播原始消息。一个白板 App 即使与 Chat 位于同一 conversation,也只能收到其 Manifest 声明且 Runtime 授权的实例 patch、Tool 调用或事件。
## 8. Runtime SDK v1
### 8.1 双通道模型
```text
InboundRuntime → App
- 已验证 Agent 消息
- App 专属状态投影
- Tool 调用
- Runtime / App 生命周期
OutboundApp → Runtime
- 用户与 App 声明性 Action
- Tool result / progress / error
- Surface Event
- Capability request
- 可恢复 State Snapshot
```
顶层接口:
```ts
interface LineUpAppRuntimeSDK {
readonly app: AppContext;
readonly lifecycle: AppLifecycleAPI;
readonly state: AppStateAPI;
readonly agentMessages: AgentMessageAPI;
readonly actions: AppActionAPI;
readonly tools: AppToolAPI;
readonly apps: AppNavigationAPI;
readonly artifacts: ArtifactAPI;
readonly sessionData: MiniAppSessionDataAPI;
readonly capabilities: CapabilityRequestAPI;
readonly diagnostics: DiagnosticsAPI;
}
```
App 得到的是按 App Scope、conversation 和实例作用域裁剪后的接口和 View Model,而不是全量 Runtime State 或原始 Transport。
本地 UI Action 只经 SDK / Bridge 进入 Runtime;它不调用 Agent Tool、不会进入 Agent Inventory,也不带 Agent 身份。若业务需要,Runtime 可以在完成本地校验后让 UI Action 与 Agent Tool 调用同一个内部业务服务。
### 8.2 App Context、状态与生命周期
```ts
interface AppContext {
app_scope: AppScope;
app_version: string;
instance_id: AppInstanceID;
kind: "core" | "installed";
entrypoint: string;
scope: {
conversation_id?: ConversationID;
operation_id?: OperationID;
parent_instance_id?: AppInstanceID;
};
granted_permissions: readonly AppPermission[];
}
interface AppStateAPI<ViewModel = unknown> {
snapshot(): ViewModel;
subscribe(listener: (view: ViewModel, change: AppStateChange) => void): Unsubscribe;
}
```
生命周期包含 `start``foreground``background``suspend``restore``closing`。App 可以保存快照并请求延迟关闭,但 Runtime 保留禁用、移除、内存回收和强制收口的最终权力。
### 8.3 Agent 消息订阅与可靠 Inbox
SDK 提供实时订阅,同时提供持久化 Inbox 补读:
```ts
interface AgentMessageAPI {
list(request?: {
conversation_id?: ConversationID;
after?: AgentMessageCursor;
limit?: number;
}): Promise<AgentMessagePage>;
subscribe(
options: {
conversation_id?: ConversationID;
types?: readonly AgentMessageType[];
include_pending?: boolean;
},
handler: (message: AgentAppMessage) => Promise<void> | void,
): Unsubscribe;
acknowledge(message_id: string): Promise<void>;
}
```
投递语义:
1. Runtime 先验证并持久化,再回调 App;
2. 每条消息有唯一 `message_id`App 必须幂等处理;
3. 展示类消息可自动确认;Tool 调用、状态 patch 等业务消息需 App 显式 ACK;
4. App 未运行、暂停或崩溃时,Runtime 写入该 App Inbox;恢复后通过 `list()``subscribe()` 补齐;
5. App 禁用、移除或不兼容时,Runtime 不静默投递或丢弃关键调用,而向 Agent 返回标准拒绝。
App 的订阅条件只是请求;实际投递集为:
```text
Manifest agent_subscriptions
∩ SDK subscribe filter
∩ App 权限
∩ conversation / instance scope
∩ Agent target app_scope
∩ Runtime Policy
```
### 8.4 Action、Tool、App 导航与 Artifact
App 只提交声明性 Action;不得构造原始 Agent Envelope 或直接访问 Transport
```ts
interface AppActionAPI {
dispatch(action: AppAction): Promise<CommandReceipt>;
}
interface AppToolAPI {
onInvoke(listener: (call: AppToolInvocation) => Promise<AppToolOutcome>): Unsubscribe;
progress(request: { call_id: ToolCallID; progress: ToolProgress }): Promise<void>;
complete(request: { call_id: ToolCallID; result: JsonValue }): Promise<void>;
fail(request: { call_id: ToolCallID; code: AppToolErrorCode; message?: string }): Promise<void>;
}
interface AppNavigationAPI {
listAvailable(): readonly AppSummary[];
launch(request: LaunchAppRequest): Promise<AppInstanceHandle>;
focus(instanceID: AppInstanceID): Promise<void>;
background(instanceID: AppInstanceID, reason?: string): Promise<void>;
suspend(instanceID: AppInstanceID, reason?: string): Promise<void>;
close(instanceID: AppInstanceID): Promise<void>;
openDefaultApp(): Promise<void>;
}
```
`AppNavigationAPI` 只是 App 发给 Runtime 的受限请求接口。真正的 Tool Router、App Instance
Manager 和 Focus Manager 位于 Runtime 内部:它们负责检查 App 是否已安装/启用、是否满足
前台条件、是否需要用户确认,以及切换失败时恢复原前台实例。Interact 可以请求启动扩展
App,但不能直接决定其他 App 的生命周期。
Artifact、媒体与文件通过 Runtime Artifact Store 暴露元数据、受限读取、创建、会话引用和用户保存;App 不取得任意路径或跨 App 文件访问权。
### 8.5 MiniApp session data 与 Capability
每个 MiniApp App 子会话使用 Runtime 管理的、通用的业务数据字典:
```text
app_scope + app_session_id
→ 一份 MiniApp 自己定义的 JSON 数据字典
→ revisioned replace / subscribe
→ 重启后向同一 App 子会话恢复
```
这不是通用文件系统、键值数据库或跨子会话查询接口。MiniApp 负责定义数据的业务含义、嵌套结构、`current` /
`history`、是否追加历史以及业务上是否可修改;Runtime 不声明或校验 MiniApp 业务 schema。Runtime 只负责从不可
伪造的 SDK context 推导当前 `app_scope + app_session_id`,以及 JSON 合法性、通用配额、安全解析深度、revision
比较、原子写入与重启恢复。关闭、禁用或移除对记录的技术性清理由 Runtime 的全局保留策略负责,但 Runtime 不把
“关闭即业务数据只读”强加给每一个 MiniApp。
```ts
interface MiniAppSessionDataAPI<Data extends JsonObject = JsonObject> {
get(): Promise<{ data: Data | null; revision: number }>;
replace(request: { data: Data; expected_revision: number }): Promise<{ revision: number }>;
subscribe(listener: (snapshot: { data: Data | null; revision: number }) => void): Unsubscribe;
}
```
每个 `app_scope + app_session_id` 的 subscribe / replace 都由 Runtime 在同一串行顺序处理。没有已保存数据时,
`get()` 和订阅首帧均为 `{ data: null, revision: 0 }`;订阅注册时 Runtime 捕获并先投递完整当前快照,之后才投递
revision 严格递增的完整变化。于是读与订阅之间发生的 replace 不会漏掉:它要么在首帧中,要么紧随首帧出现。SDK
忽略重复或旧 revision;发现跳跃或 Bridge 重连时取消旧订阅、重新 `get()` 并建立新订阅。revision CAS 只拒绝陈旧
覆盖,不承担业务合并;多入口协作写入由后续独立的 mutation queue 方案解决。
`expected_revision` 不匹配时 Runtime 返回 `session_data_revision_conflict`;数据不是 JSON、SDK context 已失效或
超出通用配额时分别返回 `session_data_invalid``session_data_unavailable``session_data_quota_exceeded`。App
不得用 session data 直接完成 Agent Tool、写 outbox、改变焦点或执行 Capability。deadline、Tool 终态、outbox、
焦点或生命周期仍走 Runtime 的 Command / operation 路径;Runtime 可以在同一原子事务中更新 operation 与
session data,但二者保持不同的事实来源。
MiniApp 的短暂渲染状态(动画、滚动位置、临时 loading)不要求保存;Conversation / App 子会话保存人与
Agent 可见的静态交互和结果,也不是 MiniApp 业务数据的事实来源。IM 中一旦写入的完成记录是已发生结果的
不可变静态副本,不会随 MiniApp 之后修改 session data 而变化。Capability 必须通过统一请求接口:
```ts
interface CapabilityRequestAPI {
request<T extends JsonValue>(request: {
capability: CapabilityName;
purpose: string;
input: JsonValue;
scope?: AppScope;
}): Promise<CapabilityResult<T>>;
}
```
Runtime 检查 Manifest 声明、App 启用状态、Host 支持、前台要求、用户确认、系统权限、策略、限流与审计;App 只能获得受控结果。
## 9. 信任分层与 Surface Bridge SDK
| 层级 | 例子 | 可用接口 | 明确禁止 |
|---|---|---|---|
| Core App | Chat、App Registry、Settings | 完整 App Runtime SDK(仍受 Scope 和 Capability 约束) | 直接绕过 Transport/Capability Gateway。 |
| Installed App | 白板、语音、游戏 | 受限 Surface Bridge SDK:状态、已声明 Tool、事件、当前 App 子会话的 session data、Capability request | Tauri invoke、父 DOM、token、任意网络、其他 App 数据。 |
| Host Provider | Tauri Desktop / Web Reference Host 实现 | Runtime 内部 Host Provider API | 向 Runtime 提供系统能力;不直接暴露给 Agent/Surface。 |
下载型 App 使用 `iframe sandbox="allow-scripts"` 或等价隔离容器;不包含 `allow-same-origin`。它经严格 CSP、来源验证和消息 schema 校验的桥接访问 Surface SDK。第一版不支持市场下载包执行本地 Rust、Node、Shell 或任意浏览器特权代码。
## 10. App Manifest 的 Runtime/SDK 声明
每个 App Manifest 除 Bundle、签名和 Surface 外,还应声明 Runtime SDK 与消息/工具契约。当前阶段只使用本地 `app_scope`,不在 Manifest 中固化供应商身份或全局命名空间:
Manifest 的 Tool 描述由 MiniApp SDK 的 `defineAgentTools(...)` 在构建期从源码生成。开发者只维护 SDK 中的 Tool
声明和本地 handler;构建产物把不含函数、URL、回调或私有函数名的 schema / policy 描述写入 Manifest,供 Runtime
安装、Registry 与 Agent Inventory 使用。Runtime 向 ready App session 的统一 SDK Tool 接收入口投递 method +
paramsSDK 再在 Bundle 内部按 method 分发 handler。
```json
{
"format": "lineup.app.v1",
"app_scope": "whiteboard",
"version": "1.2.0",
"runtime_sdk": {
"api_version": "1",
"required_features": ["app.lifecycle.v1", "app.tools.v1", "surface.state.v1", "app.session-data.v1"],
"optional_features": ["artifact.create.v1"]
},
"entrypoints": [
{"id": "canvas", "kind": "contextual", "default_eligible": false}
],
"agent_subscriptions": [
{"type": "lineup.app.state.patch", "scope": "instance"},
{"type": "lineup.tool.invoke", "scope": "conversation"}
],
"tools": [
{
"method": "board.create",
"contract_version": "1",
"handling": "direct",
"delivery": "miniapp_sdk",
"activation_requirement": "app_ready",
"input_schema": {"type": "object", "additionalProperties": false},
"output_schema": {"type": "object", "additionalProperties": false}
}
]
}
```
Runtime 在安装、启用和启动时进行 SDK 版本及 feature 协商;不兼容 App 不进入可用 Inventory,也不得启动。
## 11. Runtime 状态与恢复
顶层 Runtime State 至少包含:
```text
identity 用户、设备、认证会话
connection AppServer 状态、cursor、重试、outbox
conversations Agent 映射、消息引用、任务、交互、Artifact 元数据
apps App Registry、默认 App、运行实例、App Inbox
app_state 按 app_scope + app_session_id 隔离的 MiniApp session data、revision 与 activation
tools 已声明 Tool、可见性、调用与 operation
capabilities 授权、执行状态、最小审计
```
第一版采用“事件驱动状态机 + 必要快照”,而非完整 Event Sourcing:关键入站事件、用户决定、Tool 结果、outbox 和审计记录持久化;渲染细节和短暂 UI 状态不必全部写入事件日志。
Runtime 生命周期:
```text
created → restoring → authenticating → synchronizing → online
↘ reconnecting / offline_degraded
online / offline_degraded → stopping → stopped
```
启动时恢复 App Registry、默认入口、会话 cursor、outbox、App Inbox、未完成 Tool 和可恢复实例;追平历史后再开始实时投递。离线时用户/App Action 进入 outbox,重连后按幂等键和顺序处理。
## 12. 推荐工程边界
```text
lineup-app/
├── runtime-core/
│ ├── communication/ Transport、sync、outbox
│ ├── coordination/ Event、state、router、policy、focus、audit
│ ├── apps/ App Manager、Registry、Instance、Focus、Lifecycle Manager
│ ├── tools/ Tool Registry、Inventory、Router、call lifecycle
│ ├── capabilities/ Capability Gateway
│ └── persistence/ Runtime Store、App Inbox、instance state snapshot、Artifact metadata
├── runtime-sdk/
│ ├── app.ts Core App SDK 类型
│ ├── manifest.ts App/Tool/Subscription Manifest 类型
│ ├── protocol.ts Runtime Envelope 与 schema
│ ├── errors.ts 稳定错误码
│ └── testkit/
├── surface-sdk/
│ ├── bridge.ts sandbox postMessage bridge
│ └── surface.ts Installed App 最小接口
└── tauri/
├── src/
│ ├── bootstrap/ Tauri/Web 的应用启动装配层
│ ├── runtime-host/ Runtime Host Provider 适配
│ ├── core-apps/ chat、app-registry、settings
│ └── shell/ app switcher、default app、recovery
└── src-tauri/ 文件、音频、通知、窗口等 Rust Provider
```
当前 `lineup-app/tauri/src/main.ts` 同时承担 Runtime、Chat、Host Adapter 和开发 Fixture 的职责,是拆分的主要对象。现有 `InteractionKernel`、Transport、Conversation Store、Surface Registry、Instance Manager、Bundle Cache、Capability Registry 与 Inventory Publisher 可作为上述 Runtime Core 的迁移基础。
## 13. 第一阶段落地顺序与验收
### R0:冻结 Runtime/SDK 合约
- 固化 `RuntimeEnvelope`、app scope / conversation ID / instance ID 规则;
- 固化 Event / Command / Effect 边界;
- 定义 `LineUpAppRuntimeSDK``Surface Bridge SDK` 与 Manifest TypeScript 类型;
- 为 Envelope、App Manifest、Tool Descriptor、SDK 错误码准备 golden fixtures。
### R1:建立 Runtime Core 和 Interaction Core App(当前 `chat` 实现)
- 将 Runtime 的创建与装配集中在单一启动入口,不让 `main.ts` 变成通信和业务逻辑的堆放处;
- Runtime 独占 Transport、Store、outbox 和入站筛选;
- 将当前图文 IM 重构为 Interaction Core App 的 `chat` 实现;
- 当前 `chat` 通过 `agentMessages.subscribe()` 获取已验证的 Agent 消息,不再直接依赖 Transport;
- 保持当前登录、同步、本地回显、Markdown、Tool Call、Task 与 Artifact 回归行为。
### R2App Registry Core App
- 将现有开发期 `SurfaceRegistry` 升级为 Runtime App Registry
- 实现 Core App 记录、Installed App 记录、enable/disable/remove 和默认 App 选择;
- 将 Registry UI 实现为 `app-registry`,仅调用 `RuntimeAppManager`
- App 状态变化后正确更新 Runtime Inventory。
### R3Tool Registry 与 App SDK Inbox
- 实现 Manifest Tool / Subscription 解析与可见性筛选;
- 将动态 Inventory 同步给 Agent
- 实现 Agent `tool.invoke` → Runtime → App SDK → `tool.result` 的可靠闭环;
- App 未运行时持久化 Inbox,恢复后可幂等补读。
- 实现 `app.session-data.v1`:按 `app_scope + app_session_id` 隔离的通用 JSON 数据、revisioned replace /
subscribe、通用配额、刷新/重启恢复与关闭/禁用/移除清理;Runtime 不校验 MiniApp 业务 schema,且 Tool/
operation/outbox 不得由该 API 直接改写。
### R4:第一个 Installed App 闭环
- 接入一个已签名的画板或任务面板 App;
- 验收 install → enable → inventory 更新 → Agent 调用 Tool → App 启动 → Surface 事件 → Agent result → disable/remove
- 后续语音 App 复用同一 SDK、Tool、Capability 与 Artifact 通道,而不是再实现独立通信链路。
硬性验收:
```text
1. 缺少或非法 app_scope / conversation_id 的可路由消息被 Runtime 拒绝;
2. App 不会收到其他 App 或其他 conversation 的 Agent 原始消息;
3. App 被禁用后,其 Tool 从 Inventory 移除且新调用被拒绝;
4. 断线/重启后 App Inbox、outbox、Tool 调用和实例状态能有界恢复;
5. 下载型 App 无法访问 Tauri invoke、Host DOM、token 或未授予 Capability
6. 默认 App 不可用时 Runtime 自动进入 chat Recovery App
7. 所有 Tool 调用、权限拒绝与终态结果均可按 app_scope、conversation_id、call_id 审计和测试。
8. MiniApp 只能读写自身当前 App 子会话的 session data;非 JSON、旧 revision、跨 App / 子会话、超配额或
失效 SDK context 均被稳定拒绝,重启只恢复最后一个有效数据版本。
```
## 14. 与已有正式方案的关系
[运行时与智能体工具](运行时与智能体工具.md) 进一步冻结了 Agent 的角色、Agent Tool 的发布与调用模型,以及它和本地 UI Action、Host 生命周期意图的三条入口边界;本文的 Tool 与 Inventory 术语均按该专题理解。
- 本文将 [App 层架构方案](lineup-app-layer-architecture.md) 中的 Interaction Runtime 从“聊天 Host 内部模块”收敛为整个 App 的 Runtime,并补充了 App Manager、App Tool Registry、SDK 和消息路由模型。
- 本文不废弃 [UI Surface 与 App Capability 协议](lineup-ui-surface-protocol.md) 中已完成的 Surface 隔离、Capability 确认、生产 Bundle 验签和动态 inventory 原则;后续应将其协议字段迁移/扩展为本文定义的 Runtime Envelope、App Manifest 和 Tool Registry,而不能引入绕开 Runtime 的平行通道。
- 现有 M2/M4 文档和实现使用的 `app id` 是当前 Surface 协议的实现字段。本方案在 Runtime 重构阶段以 `app_scope` 作为本地路由字段;供应商身份和全局命名空间将在后续生态阶段通过独立、版本化的兼容设计重新引入。
- 当前 M0M4 实现可作为 Runtime 的迁移基础,但其现有文件边界不是最终 Runtime/App/SDK 边界。