# 运行时与智能体工具 **版本:** 0.1(当前 Runtime 契约) **状态:** 已确认 **日期:** 2026-08-06 **关联方案:** [LineUp App 最终设计方案](app_final_design.md)、[LineUp Runtime 与 App SDK 架构方案](lineup-runtime-sdk-architecture.md)、[第 04 次迭代:Runtime 工作区与 Pomodoro MiniApp](../../迭代/04.runtime_workspace/04.runtime_workspace.md) --- ## 0. 目的与权威范围 本文定义 Runtime 面向远端 Agent 的工具模型,以及它与本地 MiniApp 界面操作、Host 生命周期事件之间的边界。它是全局 Runtime 设计,Pomodoro 只是当前的具体例子,并不限制本文的适用范围。 本文确认的关键结论是: > **Agent Tool 是 Runtime 发布给远端 Agent 的功能调用说明书。它不是用户点击界面的公共入口,也不是 MiniApp 内部函数的别名。** 用户通常通过 IM 表达自然语言意图,未来也可以通过 Voice 表达;远端 Agent 负责理解意图、选择可见 Tool 并向 Runtime 发起调用。Runtime 负责校验、路由、执行、持久化和回传结果。用户未来可以在 MiniApp 页面点击按钮,但那属于另一条本地 UI Action 入口,不能伪装成 Agent Tool 调用。 本文细化 [LineUp App 最终设计方案](app_final_design.md) 中 Runtime、Tool、状态和边界的结论。后续若修改本文已确认的语义,必须先更新正式方案,再调整迭代定义和技术规范。 ## 1. 术语与对象 | 术语 | 定义 | 不是 | |---|---|---| | **远端 Agent** | 运行在 LineUp 设备外、通过 AppServer / IM Transport 与 Runtime 通信的智能体。它理解用户自然语言,并在可见能力范围内选择 Tool。 | 不是 Runtime 内的计时器、存储或 UI 控制器。 | | **Agent Tool** | MiniApp 在 Manifest 声明、Runtime 校验并发布给远端 Agent 的远程调用契约。它包含名称、说明、输入输出 schema、调用模型、可见性和策略。 | 不是用户按钮,也不是 App 任意 JavaScript 函数。 | | **Agent Inventory** | Runtime 根据 App、Host、权限、策略、会话和 Agent 范围计算出的 Agent Tool 清单及其 revision。 | 不是安装包内全部函数的列表。 | | **Tool Call** | Agent 对 Inventory 内某个 Agent Tool 发起的一次远端调用,带有 call_id、参数和 inventory revision。它可先收到协议回执和进度,最后才收到业务结果。 | 不等于业务 operation,也不等于 App instance。 | | **Tool 协议回执 / 进度** | Runtime 对一条已接受调用的可重放协议事实,例如 `accepted`、`starting`、`activation_ready`、`started`;用于告诉 Agent 调用是否已接收、MiniApp 是否已就绪、业务是否真正开始。 | 不是 Tool 的业务 result,不受业务 output schema 约束,也不等于一次完成记录。 | | **Tool 业务结果** | Tool 的最终业务结论;必须符合该 Tool Manifest 的 output schema,并且对同一 call_id 只持久化、回传一次。 | 不是“请求已收到”或“正在启动”的临时状态。 | | **Runtime 内部业务动作** | Runtime 为实现业务请求执行的受控命令,例如创建 deadline operation、改变焦点、写 outbox、关闭实例。多个入口可以复用同一个动作。 | 不是自动公开给 Agent 的 Tool。 | | **UI Action** | 用户在本地 MiniApp 页面点击、输入或拖动后,经 SDK / Bridge 发送给 Runtime 的本地请求。 | 不发布给 Agent,也不带 Agent 身份。 | | **Host 生命周期意图** | Host 或工作区产生的前后台切换、返回、关闭、恢复、锁屏等本地事实或请求。 | 不是 Agent Tool,也不应伪造成用户的 IM 指令。 | | **MiniApp instance** | 一个 MiniApp 的运行实例;Runtime 管理其生命周期、作用域和启动状态。 | 不必然对应一次业务 operation。 | | **App 子会话** | Interact 中围绕一个 MiniApp instance 保存的、面向人与 Agent 的交互记录。 | 不等于一次专注、计时或其他业务 operation。 | | **MiniApp activation** | Runtime 管理的一次 MiniApp 启动过程:`starting → ready | failed | cancelled`。每个 Agent Tool 声明业务执行前要求的就绪条件。 | 不是 MiniApp 的业务数据,也不是 operation。 | | **MiniApp session data** | Runtime 为当前 `app_scope + app_session_id` 持久化的通用 JSON 数据字典;内容和可变性由 MiniApp 自己定义。 | 不是 Runtime 可理解的 App 业务 schema,也不是 IM 记录或 operation Store。 | | **operation** | Runtime 管理的实际业务执行单元,例如一次有 deadline 的专注。它有独立的状态机和终态。 | 不等于 Tool Call、App 子会话或界面实例。 | ## 2. Agent 的角色、能力范围与边界 ### 2.1 Agent 的职责 远端 Agent 是意图理解者和工具调用者,不是本地 Runtime 的替身。它的职责是: 1. 从用户 IM、Voice 或其他交互内容理解意图; 2. 根据 Runtime 已发布的 Agent Inventory 选择合适的 Tool; 3. 按 Tool schema 构造参数,并携带当前 inventory revision 发起调用; 4. 接收 Runtime 回传的受控结果,在用户会话中解释、追问或发起下一步调用。 当用户说“现在开始 20 分钟的冥想,帮我计时”时,正确链路如下: ~~~text 用户的 IM 消息 → 远端 Agent 理解为启动专注 → Agent 调用 pomodoro.start → Runtime 请求 Pomodoro 进入前台 → Host 确认前台激活后,Runtime 才创建并管理专注 operation → Pomodoro MiniApp 用自身 session data 显示界面 ~~~ Agent 不需要、也不能自己一秒一秒倒数。时间事实由 Runtime 持久化的 deadline 和本地时间裁决;MiniApp 仅根据 Runtime 投影显示剩余时间。 ### 2.2 Agent 可做的事 - 调用当前 Agent Inventory 中、对当前 Agent 和 conversation 可见的 Agent Tool; - 接收 Runtime 回传的 Tool 结果、进度和受控交互结果; - 在会话范围内发送内容、交互或后续 Tool 请求; - 在 Runtime 允许的范围内请求启动 Tool 所需的 MiniApp instance。 ### 2.3 Agent 明确不能做的事 - 不能调用未在当前 Inventory 中声明的 Tool,或绕过 inventory revision、参数 schema、会话和策略校验; - 不能直接读写 Runtime Store、MiniApp instance state、Conversation Store、operation Store、outbox 或审计记录; - 不能直接调用 Tauri、文件、通知、麦克风、窗口或其他 Host 特权能力; - 不能直接执行 MiniApp 的任意函数、修改其 DOM 或访问 Surface Bridge; - 不能指定、伪造或跨会话操控任意 instance_id、operation_id、app_scope; - 不能通过 Tool Call 绕过 App 安装、启用、权限确认、风险策略或 Host 能力限制。 Runtime 对 Agent 输入实行不信任原则:即使调用来自已认证 Agent,也必须重新验证可见性、作用域、幂等、生命周期和输出。 ## 3. 三条独立入口 Runtime 可以接收不同来源的请求,但来源决定身份、校验、审计和可用能力。三者不是同一入口。 | 入口 | 发起者 | Runtime 接收的内容 | 是否进入 Agent Inventory | 主要校验 | 典型示例 | |---|---|---|---|---|---| | **Agent Tool** | 远端 Agent | 有 Agent 身份、call_id 和 inventory revision 的远端 Tool 调用 | 是 | Agent、Inventory、Tool schema、conversation、策略、幂等 | Agent 调用 pomodoro.start。 | | **MiniApp UI Action** | 用户在本地 MiniApp 页面操作 | SDK / Bridge 发送的本地 Action | 否 | 当前 instance、App 权限、UI schema、业务前置状态、用户确认 | 用户未来点击开始计时。 | | **Host 生命周期意图** | Runtime Shell、Host 或系统 | 前后台、返回、关闭、恢复、系统状态等本地事件 | 否 | instance 生命周期、焦点栈、系统策略、operation 收口规则 | 用户离开 Pomodoro 工作区。 | 三条入口的流程如下: ~~~text 一、远端 Agent Tool 用户 IM / Voice → 远端 Agent 理解意图 → Agent Tool Call → Runtime 校验、路由和持久化 → Runtime 内部业务动作 → MiniApp 状态投影 / Agent 结果 outbox 二、本地 UI Action(未来可选) 用户点击 MiniApp 页面 → SDK / Surface Bridge 的本地 Action → Runtime 校验和持久化 → Runtime 内部业务动作 → MiniApp 状态投影;必要时由 Runtime 产生 Agent 可见结果 三、Host 生命周期意图 返回 / 切换工作区 / 关闭 / 恢复 / 系统事件 → Host Lifecycle Intent → Runtime 生命周期与焦点裁决 → Runtime 内部业务动作 / operation 收口 → MiniApp 状态投影 / 必要的 Agent 结果 outbox ~~~ 后两条入口可以在 Runtime 内部复用与 Agent Tool 相同的业务服务。例如未来 UI 的开始按钮与 Agent Tool 的开始调用都可以请求同一个“创建专注 operation”动作。但复用内部动作不改变入口身份:UI Action 不会因此成为 Agent Tool,Host 生命周期也不会因此伪造成 Tool Call。 ## 4. Agent Tool 的发布与调用 ### 4.1 MiniApp 声明,Runtime 发布,Agent 调用 Agent Tool 的权威链条必须保持为: ~~~text MiniApp 源码中的 SDK Tool 声明 → 构建生成 Manifest 的不可执行 Tool 描述 → Runtime 验证 Manifest、App 与 Host 条件 → Runtime 计算并发布动态 Agent Inventory → 远端 Agent 看到 Inventory 后选择 Tool → Agent 发起 Tool Call → Runtime 验证、路由、执行并回传 ~~~ MiniApp 只声明自己支持的候选能力,不能自行向 Agent 宣传、发送或执行 Tool Call。Runtime 是唯一的 Inventory 发布者、远端调用接收者和结果回传者。 Tool 声明的开发者入口是 MiniApp SDK,而不是第二份手写 Manifest:MiniApp 用 `defineAgentTools(...)` 同时声明 公开 method、schema、activation requirement 和 `miniapp_sdk` Tool 的本地 handler。SDK 源码声明是唯一真相;构建阶段 自动生成随 Bundle 安装的 Manifest Tool 描述。该描述供 Runtime 验证、Registry 和 Inventory 使用,但不包含 handler、 私有函数名或其他可执行内容。Bundle 内 SDK 保留 `method → handler` 映射,收到 Runtime 的统一 Tool 调用后在 MiniApp 内部分发。安装包仍可有 App 身份、版本、签名与 Host 能力等基础元数据,但开发者不再维护一份独立的 Tool 清单来重复 描述源码已经定义的能力。`runtime` Tool 只能引用 Runtime 内置的受控执行类型。这样既有类似 MCP Tool 描述文件的稳定 能力契约,也不让 Runtime 知道 MiniApp 的内部实现。 一个 Agent Tool Descriptor 至少应定义: - 稳定的 app_scope、method、contract_version; - 面向 Agent 的业务说明、输入 schema 和输出 schema; - 调用模型,例如 query、command、interactive 或 operation; - 幂等键、超时或终态规则; - 启动就绪条件:`app_ready`(目标 MiniApp session 已 active、可接收方法调用)、`foreground_required` (在 app_ready 的基础上还必须已在前台),或 `activation_not_required`(只操作已有 Runtime 事实,不能因此 启动或唤醒 MiniApp); - 所需权限、风险级别和对前台 / Host 的要求。 Runtime 实际发布给特定 Agent 的清单是动态交集: ~~~text 已验证的 Manifest Tool ∩ App 已安装并启用 ∩ Host 当前支持 ∩ 用户 / 组织策略允许 ∩ 当前 Agent 与 conversation 可见 ∩ 所需前置权限满足 ~~~ ### 4.2 Runtime 收到 Tool Call 后的职责 Runtime 收到远端 Agent Tool Call 后,按以下顺序处理: 1. 验证远端 Envelope、Agent 身份、conversation 关联和 Inventory revision; 2. 验证目标 Agent Tool 当前可见,且参数符合已发布 schema; 3. 用 call_id 执行幂等去重,持久化调用记录和审计; 4. 解析 Tool 所允许的作用域,不接受 Agent 任意指定跨会话目标; 5. 创建或复用 MiniApp activation,并在 Tool 所需的 `app_ready` 或 `foreground_required` 条件满足后,选择内部 执行路径:直接处理、将 method 与已验证参数投递 App SDK、创建 operation 或拒绝;Runtime 不解释参数的 MiniApp 业务含义,也不直接写 MiniApp 的 session data; 6. 原子持久化业务状态、operation 终态与需要回传的 outbox; 7. 仅向相关 MiniApp 投递经过裁剪的状态或调用投影; 8. 将协议回执 / 进度与最终业务结果分别持久化并经 outbox 回传:前者不使用业务 output schema;后者必须通过该 schema 校验。 Tool Call 的成功接收不等于业务已经完成。对于长期 operation,Runtime 可以先确认接受调用,业务真正开始时再报告 进度,之后只在进入唯一终态时回传最终结果。相同 `call_id` 重放时,Runtime 返回已持久化的**最新协议回执或最终 业务结果**,不重新执行业务,也不追加新的 outbox 消息。 ### 4.3 activation 就绪通知与提前到达的后续调用 当 Agent 的一个 Tool 调用使 MiniApp 进入 `starting`,Runtime 必须把 activation 的受控状态作为与该 `call_id` 关联的协议进度通知给发起 Agent: ```text accepted / starting = Runtime 已接受调用,MiniApp 正在准备 activation_ready = MiniApp 已 active / ready;后续要求 app_ready 的 Tool 现在可以接收 activation_failed / activation_cancelled = 本次启动不能继续;依赖它的等待中调用将得到受控失败结果 ``` 这些通知是 Runtime 持久化 activation 后,经 Runtime outbox 发出的事实;MiniApp、Surface 和 Host 只能向 Runtime 报告自己的就绪或失败,不能直接向 Agent 发送通知。公开通知只携带 `call_id`、`app_scope`、状态和受控 reason,不能 把 `instance_id`、`app_session_id` 变成 Agent 可指定或跨会话操控的目标。 Agent 收到 `activation_ready` 后再发送有依赖关系的后续 Tool,是推荐的编排方式;但它不是 Runtime 接收调用的硬前提。 若一条合法、同 conversation / app scope 的 `app_ready` 或 `foreground_required` Tool 在目标 activation 仍为 `starting` 时提前到达,Runtime 必须持久化该调用并把它挂到同一 activation 的等待队列,在 ready 后按已持久化的到达 顺序投递。activation 失败或取消时,Runtime 不执行这些 handler,而为各调用回传稳定的 `app_activation_failed` 或 `app_activation_cancelled`。`activation_not_required` Tool 不进入等待队列,仍立即处理;因此 Pomodoro 在启动中收到 `pomodoro.interrupt` 时可以立即取消启动。 某些 Tool 的业务进度比通用 activation 状态更强时,不应重复发两条没有新增信息的通知。第 04 次的 `pomodoro.start` 在 Host 确认前台的同一提交中同时得到 `activation = ready`、创建 operation 并开始计时,因此只向 Agent 发 `started`;它语义上已包含“Pomodoro ready”,且额外保证“前台已确认、计时已真实开始”。 ## 5. 状态、身份与生命周期不得混同 本节是 Runtime 状态模型的一部分。下列对象可以互相关联,却不能共享语义或被一个 ID 替代。 ~~~text Conversation(人与主 Agent 的协作范围) ├── App 子会话(MiniApp 启动后可在 Interact 中保存的交互记录) ├── MiniApp instance(实际运行的界面 / SDK 上下文) │ ├── activation(starting / ready / failed / cancelled) │ └── session data(该 App 子会话的通用、MiniApp 自解释 JSON 数据) ├── Agent Tool Call(远端调用与其幂等、审计和回执) └── operation(实际业务执行;可无,也可独立于界面按规则收口) ~~~ | 对象 | 最小职责 | 应有的状态 / 身份 | 不能承担的事实 | |---|---|---|---| | Conversation | 用户与主 Agent 的协作边界 | conversation_id | 不能表示某次业务执行。 | | App 子会话 | 保存围绕 MiniApp 的可见交互与历史 | app_session_id 或等价记录 | 不能替代 MiniApp instance 或 operation。 | | MiniApp instance | 管理运行、焦点、挂起、关闭和 SDK scope | instance_id、生命周期状态 | 不自动代表一次业务 operation。 | | MiniApp activation | 将 App 准备为 active / ready 的过程;某些 Tool 还要求成为前台 | instance_id、app_session_id、starting / ready / failed / cancelled | 不是业务 operation,不能自行产生 deadline 或终态。 | | MiniApp session data | MiniApp 自己的业务 / 展示数据 | app_scope 加 app_session_id 加 revision | Runtime 不理解内容;不能裁决 deadline、Tool 终态或 outbox。 | | Agent Tool Call | 一次远端请求、幂等与审计 | call_id、Tool key、inventory revision | 不能替代长期 operation。 | | operation | 实际业务过程、deadline、进度和唯一终态 | operation_id、业务状态机 | 不等于一次 MiniApp 启动或 App 子会话。 | 因此,一个 MiniApp 会话或 instance 启动时未必启动业务 operation;一个 operation 也不应靠 UI 是否存在来判断是否完成。Tool 可以声明其业务开始是否需要前台:例如 `pomodoro.start` 只有在用户确实进入前台专注界面后才创建 operation;未来 `todo.add` 则可以在后台数据上下文就绪后完成。具体 Tool 的就绪条件不能上升为 Runtime 的统一前台要求。 Runtime 可以在一个原子事务中同时更新 operation、activation、session data 和 outbox,但它们仍保留各自的事实来源和恢复规则。 ## 6. 各层能力边界 | 主体 | 负责什么 | 可以请求什么 | 明确禁止 | |---|---|---|---| | **用户** | 通过 IM / Voice 表达意图;未来可直接操作 MiniApp UI。 | Agent 对话;本地 UI Action。 | 不直接调用 Agent Tool 协议或 Runtime 内部 Store。 | | **远端 Agent** | 意图理解、Tool 选择、调用参数和会话回复。 | 当前 Inventory 中的 Agent Tool。 | 直接访问 Host、Store、MiniApp DOM 或任意 App 函数。 | | **Runtime** | Agent 通信、Tool Registry、校验、路由、状态、operation、生命周期、持久化、outbox、审计。 | 通过 Host Provider 使用受控系统能力;向 App 投递受限 SDK 投影。 | 将 Transport、密钥或跨 App 数据直接暴露给 Agent / MiniApp。 | | **MiniApp** | 自己的界面、已声明业务处理和当前 App 子会话的 session data。 | SDK 提供的投影、声明性 Action、Capability request。 | 自行连接 Agent / AppServer、直接写 Runtime Store、直接使用 Tauri / Host。 | | **Surface / UI** | 渲染和收集本地用户事件。 | 受限 Surface Bridge。 | 假冒 Agent、构造 Agent Tool Call、直接操作 Host DOM 或特权 API。 | | **Host** | 提供窗口、通知、文件、音频等运行环境和系统事实。 | 向 Runtime 报告生命周期意图。 | 直接改变 MiniApp 业务状态、直接向 Agent 发布工具或交付特权能力。 | 特别地,Host 只报告本地事实或意图,最终如何改变业务状态由 Runtime 的业务规则裁决。例如“用户离开专注工作区”可触发 Runtime 中断当前专注,但 Host 不是在调用 pomodoro.interrupt,也不能假装成 Agent。 ## 7. Pomodoro:第 04 次迭代的具体应用 第 04 次迭代用 Pomodoro 验证的是第一条入口,即 Agent Tool 到 Runtime 再到 MiniApp 投影。其冻结模型为: ~~~text 用户在 IM 中说:现在开始 20 分钟的冥想,帮我计时 → 远端 Agent 调用 pomodoro.start → Runtime 创建 Pomodoro instance、App 子会话和 activation(starting) → Host 确认 Pomodoro 已成为当前前台 App → Runtime 创建 deadline operation,Pomodoro 进入 focusing 并被动显示 用户在 IM 中说:停止或结束这次专注 → 远端 Agent 调用 pomodoro.interrupt → 若仍在 starting,Runtime 取消启动;若已 focusing,Runtime 原子收口当前 operation → Pomodoro 只接收通用 lifecycle 关闭通知 ~~~ 本迭代的 pomodoro.start 把“Pomodoro 已成为用户当前前台界面”作为开始专注的前提:Runtime 接受调用并创建 `starting` activation 后,先向 Agent 回传 `accepted / starting` 协议回执;这只能表示“正在进入专注模式”,不能说 “已经开始计时”。Host 前台确认与 operation 创建成功后,Runtime 再回传 `started` 进度,此时 Agent 才能说“已开始 为你计时”。确认之前不存在 operation、倒计时或专注 IM 记录;最终无法前台激活时,Runtime 回传符合 start output schema 的 `not_started` 业务结果并恢复 Interact。pomodoro.interrupt 由 Agent 调用,而不是 Runtime 私下调用 Pomodoro: 它可取消当前启动尝试,或收口当前 focusing operation。Runtime 根据调用所在 conversation 定位目标,不接受 Agent 指定 或伪造 instance_id、operation_id 等目标。 当前 Pomodoro Surface 不实现开始、暂停、继续、停止等业务按钮。未来如果引入“用户先让 Agent 设定时长、随后自己点击开始”之类的 UI,按钮的 onClick 应产生独立的本地 UI Action;Runtime 可以让它复用创建 operation 的内部动作,但不得改变当前 Agent Tool 的含义,也不要求为第 04 次迭代提前加入两阶段 Tool 模型。 用户切回 Interact、切至其他 MiniApp 或关闭 Pomodoro 属于 Host 生命周期意图。Runtime 按 Pomodoro 的业务规则将其收口为 interrupted,但不伪造一条 Agent Tool Call;自动暗屏、锁屏和 Surface 重载则不等于离开专注。 ## 8. 对协议与实现的约束 1. Agent Inventory 只能包含 Agent Tool Descriptor;不得包含 UI Action、Host 生命周期事件或 MiniApp 任意内部方法。 2. Runtime 必须分别记录 Agent Tool Call、UI Action 和 Host 生命周期意图的来源、身份、关联 ID 与审计类型;不得用一种来源伪造另一种。 3. UI Action 的本地 Bridge 协议可在后续版本独立设计,但其入口、权限和审计不得依赖远端 Agent 身份或 inventory revision。 4. Runtime 内部业务服务可由多个入口复用,但每个入口都必须先完成自己的授权、作用域和幂等校验。 5. MiniApp session data 只能保存当前 App 子会话的 MiniApp 自定义 JSON 数据;不能借此完成 Tool、operation、outbox、焦点或 Host Capability 的特权动作。 6. Agent Tool 的调用结果必须由 Runtime 校验 schema、持久化并经 outbox 回传;MiniApp 不得直接向 Agent 或 Transport 发送结果。 7. 在没有明确产品决议前,不得为了未来 UI 的可能性改变已发布 Agent Tool 的语义,或向当前 Inventory 额外加入预设、打开、准备等 Tool。 8. 对 operation、activation、session data、Tool receipt、outbox 和工作区目标的同一次业务变更,Runtime 必须先原子持久化事实, 再让 Lifecycle、Host 和 Surface 对账;持久化失败不得改变任何层,提交后的 UI / Host 失败不得回滚已提交事实。 ## 9. 非目标 本文不定义: - Voice 的具体协议或语音识别实现;它未来只需复用“用户表达意图,再由 Agent 调用 Tool”的语义; - UI Action 的具体事件名称、Bridge 线协议或按钮设计; - 允许用户绕过 Agent 调用远端 Agent Tool; - 允许 MiniApp 直接与 Agent、AppServer、Tauri 或任意系统能力通信; - 将所有 MiniApp 都强制设计为有 operation 的应用; - 因未来 UI 交互扩展而修改第 04 次 Pomodoro 已冻结的直接开始模型。