---
url: /wave-agent/specs/multi-agent/task-background-execution.md
description: '`run_in_background` 后台执行、`TaskStop` 终止、Ctrl-B 前台转后台、`/tasks` 列表与完成通知'
---

# 功能规格说明：任务后台执行与管理

**创建日期**：2026-02-09

## 用户场景与测试 *（必填）*

### 用户故事：后台任务执行（优先级：P1）

作为用户，我希望能够在后台运行复杂或长时间运行的任务，以便在任务处理期间继续与 agent 交互。

**为什么是这个优先级**：这是实现非阻塞工作流的核心功能，对于处理耗时操作时的生产力至关重要。

**独立测试**：可以通过使用 `run_in_background: true` 启动任务并验证 agent 立即返回控制权并附带任务 ID，同时任务继续运行来进行测试。

**验收场景**：

1. **假设**有一个需要大量时间的任务，**当**我使用 `run_in_background: true` 执行它时，**则**我应立即收到唯一的任务 ID 和实时输出日志文件的路径，agent 应准备好接受下一个命令。
2. **假设**后台任务正在运行，**当**我检查系统状态时，**则**我应看到该任务被列为活动状态。
3. **假设**后台任务正在运行，**当**我读取提供的日志文件路径时，**则**我应看到任务的实时输出。

***

### 用户故事：任务输出获取（优先级：P1）

作为用户，我希望能够获取后台任务的输出（无论是在运行中还是完成后），以便查看我所请求操作的结果。

**为什么是这个优先级**：如果无法检查结果，后台任务就毫无用处。这提供了对后台操作的必要可见性。通过日志文件进行实时监控提供了更好的长时间运行任务体验。

**独立测试**：可以通过使用 `Read` 工具读取任务启动时提供的 `outputPath` 来进行测试。

**验收场景**：

1. **假设**后台任务已启动，**当**我使用 `Read` 工具访问 `outputPath` 文件时，**则**我应看到到目前为止生成的输出。
2. **假设**后台任务正在运行，**当**我读取提供的日志文件路径时，**则**我应看到任务的实时输出。

***

### 用户故事：任务终止（优先级：P2）

作为用户，我希望能够停止正在运行的后台任务，如果我意识到它不再需要或行为异常。

**为什么是这个优先级**：提供对系统资源的控制，并允许用户取消错误或失控的操作。

**独立测试**：可以通过对正在运行的任务使用 `TaskStop` 工具并验证任务被终止且其状态更新为已停止/已取消来进行测试。

**验收场景**：

1. **假设**有一个正在运行的后台任务，**当**我使用 `TaskStop` 并传入任务 ID 时，**则**任务应立即终止，我应收到确认信息。

***

### 用户故事：任务管理命令（优先级：P2）

作为用户，我希望在 CLI 中使用 `/tasks` 命令来列出和管理所有后台任务，以便有一个集中的地方来监控进度。

**为什么是这个优先级**：提供用户友好的任务管理界面，无需记住特定的任务 ID 或直接使用底层工具。

**独立测试**：可以在 CLI 中运行 `/tasks` 并验证它显示当前和最近任务的列表及其状态。

**验收场景**：

1. **假设**已启动了多个后台任务，**当**我运行 `/tasks` 时，**则**我应看到一个格式化列表，显示每个任务的任务 ID、类型、状态和启动时间。
2. **假设**遗留的 `/bashes` 命令曾经存在，**当**我尝试使用它时，**则**它应被移除或重定向到 `/tasks` 并附带弃用通知。

***

### 用户故事：前台工具后台化（优先级：P1）

作为在后台运行长时间 bash 命令或子 agent 任务的用户，我希望能在**对话界面里直接点一下**把它移到后台，而不只是靠键盘快捷键：CLI 里按 Ctrl-B，图形界面（桌面端 / VS Code / JetBrains / 远控 Web 页）上点助手消息旁的那颗按钮，手机上同样可用——以便在不等它跑完的情况下继续处理别的事。

**为什么是这个优先级**：这在最初在前台启动的长时间操作期间通过解除用户阻塞来提供即时价值。快捷键只有一个入口，而这个动作在图形界面上此前**没有可见入口**（用户要么知道 Ctrl/Cmd+B，要么就只能等）；手机浏览器更不可能有这颗键。它不改任何语义——按钮与快捷键调的是同一条 `backgroundCurrentTask`。

**独立测试**：运行一个长 bash 命令（例如 `sleep 60`），任选一个入口验证：CLI 里按 Ctrl-B、或在图形界面 / 远控页点助手消息上的后台按钮，命令都在后台继续运行，且该命令出现在 `/tasks` 里。

**验收场景**：

1. **假设**bash 或任务工具在前台运行，**当**用户看到提示 `[Ctrl-B] Background` 并按 Ctrl-B 时，**则**工具的前台执行结束，任务在后台继续运行。
2. **假设**工具已通过 Ctrl-B 后台化，**当**用户通过 `/tasks` 检查任务状态时，**则**该工具应作为后台任务可见。
3. **假设**本轮存在正在运行的 Bash 或 Agent 工具块，**当**用户在图形界面（桌面端 / VS Code / JetBrains / 远控 Web 页）点助手消息上的后台按钮时，**则**本轮所有前台任务一并转入后台（等效于按 Ctrl/Cmd+B），该按钮随即不再显示，任务出现在 `/tasks` 列表里。
4. **假设**本轮**没有**正在运行的 Bash 或 Agent 工具块（例如模型只是在输出文字），**则**助手消息上不出现后台按钮——界面上不留一个点了没有反应的入口。
5. **假设**用户在远控 Web 页点后台按钮，**则**这台电脑上的会话走同一条链路把本轮转入后台（页面只发 `backgroundCurrentTask`、不做本地状态改动），页面与桌面端看到的是同一结果；宿主不支持该方法时页面给一句可见文案，而不是停在加载中。
6. **假设**同一屏上同时出现用户消息的回滚按钮与助手消息的后台按钮，**则**两者是**同一套消息操作按钮形态**：同一个右上角容器、同一底色与圆角、单一 tooltip，只有图标与文案不同；**Y 轴位置按角色分、不按设备**——用户消息首块是自带内边距的气泡，按钮骑在气泡右肩，有一半压在气泡里、归属看得出；助手消息没有背景盒、首块只有一条很窄的内边距，同样的偏移会把按钮整颗顶到本条消息之外、落进**上一条**消息的盒子里（行间距很紧），所以助手那颗落进本条消息的首行——从消息顶再往下一点、与首行文字同一水平带，而不是贴着盒顶（贴着盒顶时按钮顶边正好压在上一条的盒底线上，仍像挂在上一条的下沿），代价是压住首行正文右侧一小块（2026-11-01 他明确要这个取舍：「跟当前消息重叠，而不是跟上一个消息重叠」）；**显隐方式按设备的悬停能力分档**——能悬停的宿主（IDE / 桌面）一律悬停才出现；触控设备（`hover: none`，手机上的远控页是唯一一例）没有真实悬停，`:hover` 由 tap 建立并粘住，于是是「点一下消息 → 按钮出现 → 再点按钮」的两段式。**这套两段式是 2026-11-01 他定的**：此前触控档是**常显**（为了省掉多一次点击），他判定不可接受——页面上永远挂着两颗按钮，静置时读不出它属于哪条消息（正好叠在上一条消息的底边附近），还压在正文上，明确要求回到默认的「点一下再显示」。**同一档上 tooltip 不显示**：触控设备里 `:hover` 只是 tap 的副产物、不会自己消失，气泡会一直压在这轮内容上（截图里正好压住 Bash 卡片）；信息不丢，触发元素都有 `aria-label`。判据取 `hover: hover`（只有确实能悬停才显示），与 React Aria 同口径。

***

### 用户故事：任务完成通知（优先级：P1）

作为用户，我希望在后台任务完成、失败或被终止时在聊天中自动收到通知，这样我不必手动检查就能知道结果。

**为什么是这个优先级**：如果没有自动通知，用户必须轮询任务状态或记得检查输出，这就违背了后台执行的目的。

**独立测试**：启动一个后台任务，等待其完成，并验证聊天中出现通知，显示任务状态和摘要。

**验收场景**：

1. **假设**后台任务正在运行，**当**任务成功完成时，**则**聊天中应出现带有绿色指示器和摘要消息的通知。
2. **假设**后台任务正在运行，**当**任务失败时，**则**聊天中应出现带有红色指示器和错误摘要的通知。
3. **假设**后台任务正在运行，**当**任务被用户终止时，**则**聊天中应出现带有黄色指示器和摘要的通知。
4. **假设**多个后台任务在 agent 空闲时完成，**则**所有通知应出现在聊天中。
5. **假设**后台任务在 agent 活跃响应时完成，**则**通知应被排队并在当前响应完成后显示。
6. **假设**队列中已有待处理用户消息，**当**后台任务通知同时入队时，**则**系统必须串行处理二者，不会并发触发两个 AI turn，不会出现两个并行的响应 stream。
7. **假设**主 Agent 并发启动 N（N≥3）个后台 subagent 并等待全部完成通知，**当**所有 subagent 完成时，**则**主 Agent 必须收到恰好 N 条完成通知（每个 taskId 恰好一次），且任何通知不得出现在兄弟 subagent 的会话 transcript 中、不得因此重新唤起兄弟 subagent 额外执行一轮。
8. **假设**并发后台 subagent 完成通知入队期间，**当**某个兄弟 subagent 的 AIManager 回合结束时，**则**该 subagent 不得从主 Agent 的 MessageQueue 排空（`drainNotifications`）任何通知；subagent 的通知排空只能作用于其自身容器的独立队列。
9. **假设**主 Agent 在 print 模式（`wave -p`）下等待后台 subagent 完成，**当**最后一个 subagent 完成且其通知已被主 Agent 消费、生成最终响应后，**则**print 模式才允许退出（exit 0）；不得因通知被错误消费者取走导致 `hasPendingMessages`/`hasRunningBackgroundWork`/`isLoading` 提前为假而提前退出。

***

### 用户故事：插件端后台任务管理对话框（优先级：P2）

作为插件端（VS Code 扩展与 JetBrains 插件）用户，我希望能在 IDE 中通过 `/tasks` 命令弹出对话框查看和管理后台任务（shell / 子 agent / 工作流），与 CLI 的 `/tasks` 弹窗体验一致，以便集中监控后台运行的长时间任务、查看输出、必要时终止任务。

**为什么是这个优先级**：插件端以 stdio 子进程方式运行 Agent，目前 `AgentCallbacks.onBackgroundTasksChange` 回调未通过 stdio 协议转发，IDE 完全无法感知后台任务（`run_in_background`、超时自动后台化的任务）。后台任务的结果当前仅在 CLI 可见；IDE 用户无法查看或管理这些任务，与 CLI 体验不一致。

**独立测试**：在插件端中输入 `/tasks`，验证弹出对话框列出后台任务（id、类型、状态、描述、运行时长）；选择某任务查看详情输出；点停止按钮终止运行中任务；任务状态变化时列表实时刷新。

**验收场景**：

1. **假设**有后台任务运行，**当**用户在 IDE 输入 `/tasks` 时，**则**弹出对话框列出所有后台任务（运行中/已完成/失败/已终止），每项显示 id、类型、状态、描述/命令、运行时长
2. **假设**用户在列表中选择某任务，**当**进入详情视图时，**则**显示该任务的 stdout/stderr 输出（末尾若干行）、退出码、日志文件路径
3. **假设**某任务正在运行，**当**用户点击停止按钮时，**则**任务被终止，列表中该任务状态更新为已终止
4. **假设**后台任务状态变化（启动/完成/失败/终止），**当**子进程发送 `backgroundTasksChange` 通知时，**则**对话框实时刷新列表
5. **假设**无后台任务，**当**用户输入 `/tasks` 时，**则**对话框显示空状态提示
6. **假设**IDE 与 CLI 行为需一致，**则**二者任务列表数据模型一致（基于同一 `BackgroundTask` 类型）
7. **假设**所选任务仍在运行，**当**其输出持续产生时，**则**详情视图周期性自动刷新并展示最新输出（运行中的 agent 任务其 stdout 在终态前为空，此时取该任务日志文件尾部的实时内容）；**当**任务进入终态时，**则**停止自动刷新并显示终态输出快照

***

### 边界情况

* **无效任务 ID**：系统如何处理带有不存在 ID 的 `TaskOutput` 或 `TaskStop` 请求？（预期：显示任务未找到的错误消息）。
* **任务已完成**：当 `TaskStop` 被调用在已完成的任务上时会发生什么？（预期：显示任务已完成的提示消息）。
* **输出获取超时**：当 `block: true` 时，`TaskOutput` 如何处理超过指定超时的任务？（预期：返回日志文件的最后几行，并附带仍在运行的状态指示）。
* **并发访问**：来自同一后台任务的多个输出请求。
* **任务日志文件不可读**：运行中的任务其 `outputPath` 文件缺失或读取失败时如何处理？（预期：回退到内存中的 stdout/stderr，不向用户报错）。
* **没有工具运行时按 Ctrl-B**：系统应忽略该按键。
* **没有前台任务时点后台按钮**：按钮本来就不显示（场景 4）；若因时序竞态点到了（工具刚结束），也必须是空操作，不报错、不产生任何可见变化。
* **直接用户 bash 命令（`!command`）**：用户使用 `!` 前缀直接启动的命令不得受 Ctrl-B 影响。
* **超时自动后台化**：当前台 Bash 命令超时时，进程被自动后台化而不是被终止（除非命令以 `sleep` 开头）。这保留了只需要更多时间的长时间运行工作。
* **后台任务无超时**：显式后台化的任务（`run_in_background: true`）忽略默认和显式超时，运行直到完成或手动停止。
* **并发后台 subagent 通知错误路由**：当多个后台 subagent 并发完成时，若 subagent 容器未持有独立 MessageQueue，其 AIManager 回合末会经由 `Container.get()` 的 parent 回退抽干主 Agent 队列，将兄弟任务完成通知注入自身会话并重新唤起自身回合（`shouldRestart`），同时主 Agent 因收不到该通知而提前退出。修复要求每个 subagent 容器注册独立 MessageQueue，且完成通知仅投递并消费于主 Agent 队列。
