# LineUp Runtime 与 App SDK 架构方案 **版本:** 0.1(架构基线) **状态:** 已确认的 Runtime / SDK 方向;尚未完全落地到当前 Tauri 实现 **日期:** 2026-08-04 **关联方案:** [LineUp App 层架构设计方案](lineup-app-layer-architecture.md)、[LineUp UI Surface 与 App Capability 协议](lineup-ui-surface-protocol.md) > **汇总入口:** 本文是 Runtime / SDK 初稿的详细来源。后续设计以 [LineUp App 最终设计方案](app_final_design.md) 为准;后者收敛了本地 `app_scope`、兼容迁移和实施顺序。 --- ## 0. 结论与范围 LineUp 不是“聊天应用里附带一个交互 Runtime”。**LineUp App 本身就是运行在用户设备上的 协作 Runtime**,可以把它理解为本地协调中心:它独占与 AppServer / Remote Agent 的连接, 维护会话和本地应用生态,并为上层应用提供统一的消息、工具、存储、权限和生命周期接口。 聊天只是第一个使用这些接口的内置 App。 ```text Remote Agent │ LineUp Runtime Envelope ▼ AppServer / IM Transport ▼ ┌───────────────────────────────────────────────────────────────┐ │ LineUp Runtime │ │ │ │ Connection · Session · Event Routing · App Manager │ │ Tool Registry · Capability Gateway · Storage · Audit │ └───────────────┬──────────────────────────────┬────────────────┘ │ │ ▼ ▼ Core App Installed App chat whiteboard app-registry voice settings draw-and-guess ``` 本方案定义: - Runtime 与 Remote Agent、AppServer、上层 App、Tauri Host 的边界; - 动态应用列表、应用身份、应用安装/启用/禁用/移除与实例生命周期; - 应用向 Agent 公布工具方法的标准模型; - Runtime 对消息的统一 Envelope、筛选、可靠投递与 App SDK 订阅接口; - Core App、Installed App 和 Tauri Host 的信任分层; - SDK v1 的最小接口和工程模块边界。 本方案不在本次冻结:市场目录的商业模型、支付、公开开发者身份认证细节、多人/多 Agent 共享工作区、完整事件溯源和后台持续执行策略。它们必须建立在本方案的身份、路由和权限边界上。 ## 1. 基本术语 | 术语 | 含义 | |---|---| | **Runtime** | 用户设备上的长期协作运行底座;唯一负责 AppServer/Agent 通信、应用管理和 Host 能力调度。 | | **App** | 用户实际使用的功能单元。Chat、应用注册表、语音、白板和游戏都是 App。 | | **Core App** | 跟随 LineUp Runtime 一起发布、默认受信任的内置 App,例如 `chat`。 | | **Installed App** | 从受信来源安装、验证后在受限执行环境中运行的 App。 | | **App Registry** | Runtime 在本机保存的应用清单,记录安装包、版本、启用状态、实例和回滚信息;它是这些状态的唯一依据。 | | **Tool** | App 先在 Manifest 中说明、Runtime 再公布给 Agent 的可调用方法。Agent 不能任意调用 App 内部函数。 | | **Capability** | Runtime / Host 保管的系统能力,例如录音、选择文件、保存 Artifact;App 必须请求,不能自动获得。 | | **Surface** | 一个受限的交互小界面,例如一块画板、一个语音会话面板或一局游戏。 | | **Conversation** | 用户与一个主 Agent 协作的一段会话范围;App 实例、工具调用和 Artifact 默认都归属这段会话。 | ## 2. 不可变架构原则 1. **Runtime 是唯一 Agent 通信入口。** App 不直接访问 AppServer、IM SDK、WebSocket、HTTP cursor 或 Agent endpoint。 2. **App 只与 Runtime 通信。** Chat、Voice、Market、白板均通过 SDK 读状态、订阅消息、提交动作和请求能力。 3. **每一条可路由 Runtime 消息必须具有 `app_scope` 与 `conversation_id`。** Runtime 以它们作为本地路由、授权、筛选、持久化和投递的首要键。 4. **原始 Agent payload 不交给 App。** Runtime 完成版本、身份、schema、大小、去重和作用域校验后,才产生可订阅的标准化消息。 5. **应用可调用方法必须先声明、后公布、再调用。** Agent 不执行 App 内任意函数,只能调用当前 Inventory 中精确声明的方法。 6. **系统能力由 Runtime 独占。** Agent 和 App 只能请求 Capability;文件、麦克风、通知、剪贴板、窗口、密钥等均不得直接访问。 7. **应用状态、消息和副作用分离。** Event 是已发生事实,Command 是请求动作,Effect 是 Runtime 执行的受控副作用。 8. **UI 是 Runtime 状态的投影。** App 重启、断网或 Surface 回收后,Runtime 能依据持久化状态恢复到可解释的协作状态。 ## 3. 运行时分层 ```text ┌──────────────────────────────────────────────────────────┐ │ Runtime Shell │ │ 应用切换 · 默认入口 · 连接状态 · 通知 · 安全恢复 │ ├──────────────────────────────────────────────────────────┤ │ Core App / Installed App │ │ Interaction App(IM / 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; enable(appScope: AppScope): Promise; disable(appScope: AppScope, options?: DisableAppOptions): Promise; update(appScope: AppScope, targetVersion?: string): Promise; rollback(appScope: AppScope): Promise; remove(appScope: AppScope, options?: RemoveAppOptions): Promise; launch(request: LaunchAppRequest): Promise; closeInstance(instanceID: AppInstanceID): Promise; } interface RuntimeAppOrchestrator { launch(request: LaunchAppRequest): Promise; foreground(instanceID: AppInstanceID): Promise; background(instanceID: AppInstanceID, reason?: string): Promise; suspend(instanceID: AppInstanceID, reason?: string): Promise; restore(instanceID: AppInstanceID): Promise; closeInstance(instanceID: AppInstanceID): Promise; getFocusStack(conversationID?: ConversationID): readonly AppInstanceID[]; } ``` 安装、验签、升级、禁用和移除是异步操作,必须返回可观察的 `AppOperation`。禁用会阻止新实例和新 Tool 调用,并收口现有实例;移除会在实例关闭及用户确认后清理 Bundle 和 App 私有数据。 ### 5.3 默认应用与安全回退 Runtime Shell 不属于任何 App。它负责应用切换、通知、连接状态和安全恢复。用户可选择一个具备 `default_eligible` entrypoint 的已启用 App 作为默认入口: ```text 当前默认:chat → 图文 IM 为主 未来默认:voice → 实时语音为主 ``` `chat` 是内建、不可移除的 Recovery App:默认 App 不兼容、被禁用、损坏或启动失败时,Runtime 必须回退到它。 启动优先级: ```text 显式启动目标(深链接/通知) → 可安全恢复的前台工作 → 用户 Default App → chat Recovery App ``` ### 5.4 前台焦点与 App 间切换 `Interaction App` 是默认的人与 Agent 交互入口,但不是全局调度器。Runtime 的 `App Orchestrator`、`Tool Router` 和 `Focus Manager` 负责决定 Agent 请求由哪个 App、哪个 交互模式或哪个标准组件承接。Interact 只通过 SDK 呈现当前会话并提交用户 Action。 ```text Interaction App / Audio Mode foreground → Agent 请求 launch(draw-and-guess) Runtime 校验 Tool、Manifest、Inventory、参数和前台条件 → Audio Instance background / suspended → Draw-and-Guess Instance starting → foreground → 游戏结果经 Runtime 回传 Agent → 关闭或结束后按 focus stack 恢复 Interaction App ``` 前后台切换必须保留原实例和 `conversation_id` 的关联,不能因为界面暂时不可见就删除 未完成 Tool Call、Surface 或 App Inbox。若目标 App 启动失败,Runtime 应恢复原前台实例并 向 Agent 返回受控的 `app_start_failed` 或 `handler_failed` 结果。 ## 6. Runtime Tool Registry 与动态 Inventory ### 6.1 App Tool App 可在 Manifest 中声明 Agent 可调用方法。当前 Tool 由 App Scope、局部方法和契约版本定位: ```text whiteboard/board.create@1 whiteboard/board.apply_diagram@1 voice/voice.request_recording@1 ``` Runtime 内部使用结构化键,而不依赖字符串拼接: ```ts type ToolKey = { app_scope: AppScope; method: string; contract_version: string; }; ``` 每个 Tool 声明至少包含: - 标题、面向 Agent 的说明、输入/输出 JSON Schema; - `query`、`command`、`interactive`、`operation` 四种调用模型之一; - 前台要求、超时、幂等规则和风险等级; - 是否需启动 App 实例、是否允许 Runtime 自动启动; - 该方法可能请求的 Capability。 ### 6.2 可见性与 Inventory Runtime 向 Agent 公布的工具不是安装包的全部声明,而是动态交集: ```text Agent 可见 Tool = 已验证 Manifest Tool ∩ App 已启用 ∩ 当前 Host 支持 ∩ 用户/组织策略允许 ∩ 当前 Agent 和 conversation scope 允许 ∩ 所需前置权限满足 ``` Inventory 包含 App、Tool、Surface 和 Runtime Capability,并具有 revision。Runtime 在连接建立、App 启用/禁用/升级/撤销、Host 能力变化或策略收紧后重新发布。Agent 调用必须携带其看到的 `inventory_revision`;过期清单的调用应被安全拒绝并提示刷新。 ### 6.3 Tool 调用流程 ```text Agent lineup.tool.invoke → Runtime 验证 Envelope、Agent、inventory revision、App 状态和参数 schema → 创建 call record / 审计记录 → Tool Router 判断直接执行、启动 App、切换前台、等待用户交互,或创建异步 operation → App Orchestrator / Interaction App / Installed App 承接调用 → App 经 SDK 返回 progress / result / error → Runtime 验证输出 schema、持久化、更新焦点并回传 Agent ``` 标准终态错误码至少包括: ```text cancelled_by_user permission_denied app_disabled app_not_installed app_version_mismatch tool_not_visible invalid_arguments foreground_required operation_expired handler_failed ``` ## 7. 统一消息 Envelope 与路由 ### 7.1 Runtime Envelope 所有 Agent、Runtime、App、User 和 Host 之间的可路由消息使用统一基础 Envelope: ```ts type RuntimeEnvelope = { v: 1; id: string; type: string; timestamp: string; sender: { kind: "agent" | "runtime" | "app" | "user" | "host"; id: string; }; target: { kind: "runtime" | "app"; app_scope: AppScope; instance_id?: AppInstanceID; }; scope: { app_scope: AppScope; conversation_id: ConversationID; instance_id?: AppInstanceID; operation_id?: OperationID; }; correlation?: { reply_to?: string; call_id?: string; inventory_revision?: string; sequence?: number; }; payload: JsonValue; }; ``` `scope.app_scope` 是消息所属的本地应用作用域,`target.app_scope` 是指定的消费 App。通常二者相同;Runtime 协调型消息可使用 `runtime` 作为 target,再由 Runtime 生成安全的 App 投影并分发。 ### 7.2 消息分类 第一版类型分组: ```text lineup.content.* 文本、图片、音频、链接、Artifact 引用 lineup.agent.* presence、status、task、progress lineup.interaction.* choice、confirm、input、form lineup.tool.* invoke、accepted、progress、result、error、cancel lineup.app.* state.patch、event、open、close、lifecycle lineup.capability.* request、result lineup.runtime.* inventory、connection、app registry、policy、error ``` 具体 schema 将在协议文档版本化;SDK 不暴露未经校验的原始 JSON。 ### 7.3 Runtime 筛选链 ```text Transport 收到原始消息 → 协议:版本、必填 app_scope/conversation_id、type、大小、schema → 身份:Agent、用户、会话关联 → 去重/顺序:id、sequence、cursor → App:安装、启用、版本、签名、Host 兼容性 → Tool/Capability:Inventory、方法、参数、策略、前台条件 → Scope:conversation、instance、operation 所属关系 → Subscription:App Manifest 声明与 SDK 订阅交集 → Persist:Runtime Event / App Inbox / cursor → Deliver:投递给目标 App 的 SDK ``` Runtime 不对所有 App 广播原始消息。一个白板 App 即使与 Chat 位于同一 conversation,也只能收到其 Manifest 声明且 Runtime 授权的实例 patch、Tool 调用或事件。 ## 8. Runtime SDK v1 ### 8.1 双通道模型 ```text Inbound:Runtime → App - 已验证 Agent 消息 - App 专属状态投影 - Tool 调用 - Runtime / App 生命周期 Outbound:App → 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 storage: ScopedStorageAPI; readonly capabilities: CapabilityRequestAPI; readonly diagnostics: DiagnosticsAPI; } ``` App 得到的是按 App Scope、conversation 和实例作用域裁剪后的接口和 View Model,而不是全量 Runtime State 或原始 Transport。 ### 8.2 App Context、状态与生命周期 ```ts interface AppContext { app_scope: AppScope; app_version: string; instance_id: AppInstanceID; kind: "core" | "installed"; entrypoint: string; scope: { conversation_id?: ConversationID; operation_id?: OperationID; parent_instance_id?: AppInstanceID; }; granted_permissions: readonly AppPermission[]; } interface AppStateAPI { 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; subscribe( options: { conversation_id?: ConversationID; types?: readonly AgentMessageType[]; include_pending?: boolean; }, handler: (message: AgentAppMessage) => Promise | void, ): Unsubscribe; acknowledge(message_id: string): Promise; } ``` 投递语义: 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; } interface AppToolAPI { onInvoke(listener: (call: AppToolInvocation) => Promise): Unsubscribe; progress(request: { call_id: ToolCallID; progress: ToolProgress }): Promise; complete(request: { call_id: ToolCallID; result: JsonValue }): Promise; fail(request: { call_id: ToolCallID; code: AppToolErrorCode; message?: string }): Promise; } interface AppNavigationAPI { listAvailable(): readonly AppSummary[]; launch(request: LaunchAppRequest): Promise; focus(instanceID: AppInstanceID): Promise; background(instanceID: AppInstanceID, reason?: string): Promise; suspend(instanceID: AppInstanceID, reason?: string): Promise; close(instanceID: AppInstanceID): Promise; openDefaultApp(): Promise; } ``` `AppNavigationAPI` 只是 App 发给 Runtime 的受限请求接口。真正的 Tool Router、App Instance Manager 和 Focus Manager 位于 Runtime 内部:它们负责检查 App 是否已安装/启用、是否满足 前台条件、是否需要用户确认,以及切换失败时恢复原前台实例。Interact 可以请求启动扩展 App,但不能直接决定其他 App 的生命周期。 Artifact、媒体与文件通过 Runtime Artifact Store 暴露元数据、受限读取、创建、会话引用和用户保存;App 不取得任意路径或跨 App 文件访问权。 ### 8.5 存储与 Capability 每个 App 使用 Runtime 管理的作用域隔离存储: ```text app-data/chat/ app-data/app-registry/ app-data/voice/ app-data/whiteboard/ ``` SDK 中的 `storage` 提供 JSON 数据和可恢复 snapshot,Runtime 负责配额、升级迁移、禁用和移除时的清理。Capability 必须通过统一请求接口: ```ts interface CapabilityRequestAPI { request(request: { capability: CapabilityName; purpose: string; input: JsonValue; scope?: AppScope; }): Promise>; } ``` 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、事件、隔离存储、Capability request | Tauri invoke、父 DOM、token、任意网络、其他 App 数据。 | | Host Provider | Tauri Desktop / Web Reference Host 实现 | Runtime 内部 Host Provider API | 向 Runtime 提供系统能力;不直接暴露给 Agent/Surface。 | 下载型 App 使用 `iframe sandbox="allow-scripts"` 或等价隔离容器;不包含 `allow-same-origin`。它经严格 CSP、来源验证和消息 schema 校验的桥接访问 Surface SDK。第一版不支持市场下载包执行本地 Rust、Node、Shell 或任意浏览器特权代码。 ## 10. App Manifest 的 Runtime/SDK 声明 每个 App Manifest 除 Bundle、签名和 Surface 外,还应声明 Runtime SDK 与消息/工具契约。当前阶段只使用本地 `app_scope`,不在 Manifest 中固化供应商身份或全局命名空间: ```json { "format": "lineup.app.v1", "app_scope": "whiteboard", "version": "1.2.0", "runtime_sdk": { "api_version": "1", "required_features": ["app.lifecycle.v1", "app.tools.v1", "surface.state.v1"], "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", "invocation": {"kind": "command", "activation": "launch_if_needed"}, "input_schema": {"type": "object", "additionalProperties": false}, "output_schema": {"type": "object", "additionalProperties": false} } ] } ``` Runtime 在安装、启用和启动时进行 SDK 版本及 feature 协商;不兼容 App 不进入可用 Inventory,也不得启动。 ## 11. Runtime 状态与恢复 顶层 Runtime State 至少包含: ```text identity 用户、设备、认证会话 connection AppServer 状态、cursor、重试、outbox conversations Agent 映射、消息引用、任务、交互、Artifact 元数据 apps App Registry、默认 App、运行实例、App Inbox 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、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 回归行为。 ### R2:App Registry Core App - 将现有开发期 `SurfaceRegistry` 升级为 Runtime App Registry; - 实现 Core App 记录、Installed App 记录、enable/disable/remove 和默认 App 选择; - 将 Registry UI 实现为 `app-registry`,仅调用 `RuntimeAppManager`; - App 状态变化后正确更新 Runtime Inventory。 ### R3:Tool Registry 与 App SDK Inbox - 实现 Manifest Tool / Subscription 解析与可见性筛选; - 将动态 Inventory 同步给 Agent; - 实现 Agent `tool.invoke` → Runtime → App SDK → `tool.result` 的可靠闭环; - App 未运行时持久化 Inbox,恢复后可幂等补读。 ### 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 审计和测试。 ``` ## 14. 与已有正式方案的关系 - 本文将 [App 层架构方案](lineup-app-layer-architecture.md) 中的 Interaction Runtime 从“聊天 Host 内部模块”收敛为整个 App 的 Runtime,并补充了 App Manager、App Tool Registry、SDK 和消息路由模型。 - 本文不废弃 [UI Surface 与 App Capability 协议](lineup-ui-surface-protocol.md) 中已完成的 Surface 隔离、Capability 确认、生产 Bundle 验签和动态 inventory 原则;后续应将其协议字段迁移/扩展为本文定义的 Runtime Envelope、App Manifest 和 Tool Registry,而不能引入绕开 Runtime 的平行通道。 - 现有 M2/M4 文档和实现使用的 `app id` 是当前 Surface 协议的实现字段。本方案在 Runtime 重构阶段以 `app_scope` 作为本地路由字段;供应商身份和全局命名空间将在后续生态阶段通过独立、版本化的兼容设计重新引入。 - 当前 M0~M4 实现可作为 Runtime 的迁移基础,但其现有文件边界不是最终 Runtime/App/SDK 边界。