---
url: /wave-agent/specs/commands/btw-command.md
description: >-
  `/btw` 旁路提问：绕过主消息队列、单轮且不执行工具、复用主对话 prompt 前缀，CLI overlay 与 Webview 面板两入口（含远控
  Web 页）
---

# 功能规格说明：BTW 命令

**创建日期**：2026-04-15
**更新日期**：2026-10-30

> 本规格同时覆盖 CLI（packages/code）与 Webview 四入口（VS Code / JetBrains / Desktop，以及手机上的远控 Web 页）。
> CLI 端交互（overlay、↑/↓ 滚动、Esc 关闭）见下方用户故事一、二、三；
> Webview 端交互（BTW 面板、斜杠命令弹窗插入、点击/Esc 关闭、加载状态展示）见用户故事『Webview 端附带提问』。
> 远控 Web 页的**语义与 Panel 交互与其余三端完全一致**，差别只在传输（经中继到 `AgentBridge` 的 `askBtw`，白名单与流式通知的承载见 `remote/remote-web.md` 的「Web 页也能用 `/btw` 旁路提问」故事）。

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

### 用户故事：提出附带问题（优先级：P1）

作为 CLI 用户，我希望输入 `/btw <question>` 来快速提出一个附带问题，以便我可以在不触发工具执行或打断主对话的情况下获得答案。

**验收场景**：

1. **假设**用户处于主对话模式，**当**用户输入 `/btw <question>` 并按下 Enter 时，**则** 附带问题绕过主消息队列并立即处理，`BtwDisplay` 出现并显示问题。
2. **假设** btw 请求发出，**则** 请求复用主对话的 system prompt、工具列表与记忆注入（fork 请求前缀与主对话字节级一致），以命中模型 prompt 缓存（支持缓存标记的模型），并继承主对话的模型与 thinking 参数。
3. **假设** btw 请求发出，**则** 请求仅执行一轮（maxTurns: 1），模型不能调用任何工具；若模型仍返回工具调用，`BtwDisplay` 显示 "(The model tried to call X...)" 提示，不执行工具。
4. **假设** btw 请求的上下文包含主对话消息，**则** 请求只携带最近一次 compact 边界之后的完整消息，并剔除进行中（尚未结束）的 assistant 消息，保证请求前缀与主对话已完成的请求一致。
5. **假设** AI 已响应附带问题，**则** `BtwDisplay` 显示 Markdown 答案。
6. **假设**附带问题不会被添加到主聊天历史或用户输入历史中。

***

### 用户故事：BTW 期间的视觉反馈与交互操作（优先级：P2）

作为 CLI 用户，我希望在附带问题激活时有清晰的视觉指示器，并能够通过键盘快速关闭，以便我可以将其与主对话区分开来并流畅操作。

**验收场景**：

1. **假设**附带问题正在加载，**则** `BtwDisplay` 显示静态 loading 指示（✻）与 "Answering" 文本，并在其后显示当前流式文本的最后 30 个字符（推理与普通文本共用同一尾部通道），直到回答完成（详见"BTW 加载状态"用户故事）。
2. **假设**附带问题正在加载或已回答，**则** `BtwDisplay` 显示 `/btw ` 黄色加粗前缀与 dim 色问题文本。
3. **假设**回答或错误已显示且未超出视口，**则** `BtwDisplay` 底部显示 "Escape to dismiss" 提示；回答超出视口时该提示改为 "↑/↓ to scroll · Esc to dismiss"（见"CLI 长回答滚动"用户故事）。
4. **假设**附带问题处于活动状态，**则** 任务列表（TaskList）隐藏，避免与旁路问题展示争抢空间（对齐 Claude Code：local-jsx 命令显示期间抑制展开的任务列表）。
5. **假设**附带问题处于活动状态，**当**用户按下 **ESC** 时，**则** `BtwDisplay` 关闭，用户返回主对话模式（输入框恢复，任务列表恢复显示）。
6. **假设**附带问题正在加载，**当**用户按下 **ESC** 时，**则** 请求被中止（abort），`BtwDisplay` 关闭。
7. **假设**附带问题处于活动状态，**当**用户按下 **Enter**/**Space**/**Ctrl+C**/**Ctrl+D** 或其他键时，**则** 按键被忽略（overlay 期间仅 ESC 有效，Ctrl+C 不会退出应用）；回答超出视口时 ↑/↓（及 Ctrl+P/Ctrl+N）由回答视口接管用于滚动（见"CLI 长回答滚动"用户故事）。
8. **假设**裸 `/btw`（不带问题）触发 usage 消息显示，**则** 输入行一并隐藏（与问题 overlay 一致），提示 "Escape to dismiss"；**当**用户按下 **ESC** 时，**则** usage 消息关闭，输入行恢复。其他按键（含 Enter/Space/Ctrl+C/Ctrl+D）在 usage 显示期间被忽略。

***

### 用户故事：CLI 长回答滚动（优先级：P2）

作为 CLI 用户，我希望长回答被限制在一个固定高度的视口里、用 ↑/↓ 在里面滚动，以便整帧不溢出终端、输入区不把顶部内容顶掉（对齐 Claude Code 的 `/btw`：固定视口 + 内部滚动，不依赖终端 scrollback）。

**验收场景**：

1. **假设**回答的渲染行数超过视口，**则** 回答绘制在固定高度视口中，帧总行数不超过终端行数；视口高度 = `max(5, 终端行数 - 11)`（11 行为 overlay 自身外观 + 周边界面预留），随终端尺寸变化重新计算。
2. **假设**回答超出视口，**当**用户按下 **↑** 或 **↓** 时，**则** 视口每次滚动 3 行；**Ctrl+P** / **Ctrl+N** 与 ↑/↓ 等效。
3. **假设**回答超出视口，**当**视口已滚到顶部/底部时，**则** 继续按 ↑/↓ 不再移动（无循环滚动）。
4. **假设**回答未超出视口，**则** 回答视口不接管 ↑/↓，按键仍按 overlay 期间"其他键忽略"的规则处理（用户不会看到视口跳动）。
5. **假设**回答超出视口，**则** 底栏提示为 `↑/↓ to scroll · Esc to dismiss`；未超出时保持 `Escape to dismiss`。
6. **假设**回答正在流式加载（"✻ Answering" + 流式尾部），**则** 加载行按原样单行显示，不进入滚动视口，也不显示滚动提示。
7. **假设**回答超出视口，**当**用户按下 **ESC** 时，**则** overlay 依旧关闭（关闭键仍只有 ESC，不引入 Space/Enter/Ctrl+C/Ctrl+D 关闭）。
8. **假设**终端在回答显示期间被缩放，**则** 视口高度按新的终端行数重算，已滚动位置被夹紧到新的合法范围内。
9. **假设**回答里含折行的长行，**则** 折行产生的行也计入视口容量（滚动按终端行而不是 Markdown 逻辑行）。

***

### 用户故事：BTW 加载状态（优先级：P2）

作为 CLI 用户，我希望附带问题加载期间在 "✻ Answering" 后看到当前流式传输文本的最后 30 个字符，以便我知道请求正在进行且能看到输出进度，而不被不完整的流式中间文本干扰。

**验收场景**：

1. **假设**附带问题正在加载且尚无任何流式输出，**则** `BtwDisplay` 显示问题行与静态 loading 指示（✻）+ "Answering" 文本，不显示流式尾部。
2. **假设**附带问题正在加载且模型已输出文本（普通文本或推理内容，推理流经同一尾部通道），**则** `BtwDisplay` 在 "✻ Answering" 后显示该文本的最后 30 个字符；文本不超过 30 字符时原样显示，超过 30 字符时以 `…` 前缀截断（换行折叠为 `\n`，与主对话流式尾部样式一致）。
3. **假设**回答已完成，**则** `BtwDisplay` 将完整答案以 Markdown 渲染显示，"✻ Answering" 加载文本与流式尾部消失。
4. **假设**答案仍在加载，**当**用户按下 **ESC** 时，**则** 请求被中止（abort），`BtwDisplay` 关闭。

***

### 用户故事：Webview 端附带提问（优先级：P1）

作为 Webview 用户（VS Code / JetBrains / Desktop），我希望输入 `/btw <question>` 快速提出旁路问题，以便在不打断主对话、不触发工具执行的情况下获得答案，且附带问题不污染聊天历史。

**验收场景**：

1. **假设**用户处于主对话模式，**当**用户在输入框输入 `/btw <question>` 并按下 Enter 时，**则** 附带问题绕过主消息队列，输入区上方显示 BTW 面板（问题标题 + 加载指示），主对话与输入框不受影响。
2. **假设**用户在斜杠命令弹窗中选择 `/btw`，**则** 输入框插入 `/btw ` 前缀并将光标置于其后等待输入问题，不立即执行。
3. **假设**用户输入不带问题的 `/btw` 并按下 Enter，**则** 不发起请求，BTW 面板标题区域仍显示 `/btw` 标题占位（关闭按钮不漂移到左侧），内容区显示中文 usage 文案 `"用法：/btw <你的问题>"`（与 Webview 的"正在回答"加载文案一致；CLI 端保持与 Claude Code 一致的英文 `"Usage: /btw <your question>"`）。
4. **假设** btw 请求发出，**则** 请求复用主对话的 system prompt、工具列表与记忆注入（fork 请求前缀与主对话字节级一致），并继承主对话的模型与 thinking 参数，仅执行一轮且不执行任何工具（与 CLI 共用同一 `agent.askBtw` fork 路径）。
5. **假设** btw 请求已发出，**则** BTW 面板显示闪烁光标与"正在回答"中文文案作为加载指示（与主对话消息列表的流式光标一致，不使用 emoji），直到回答完成。
6. **假设** btw 请求已发出且模型已输出流式文本，**则** BTW 面板在加载指示（闪烁光标 + "正在回答"）后显示该文本的最后 30 个字符（换行折叠为 `\n`、超过 30 字符以 `…` 前缀截断，与主对话/CLI 流式尾部样式一致）；模型尚无输出时仅显示加载指示，不显示完整流式中间文本。
7. **假设**回答完成，**则** BTW 面板以 Markdown 渲染完整答案，加载指示消失，回答区域可滚动。
8. **假设**附带问题正在加载或已回答，**当**用户点击关闭按钮或按下 **Esc** 时，**则** BTW 面板关闭，输入框恢复主对话模式。
9. **假设**附带问题正在加载且主对话同时在流式输出，**当**用户按下 **Esc** 时，**则** 仅关闭 BTW 面板，不终止正在进行的 agent loop（主对话继续流式输出）。
10. **假设**附带问题正在加载（含流式输出中）时被**手动关闭**（关闭按钮或 Esc），**则** 面板立即消失，迟到的流式增量与最终回答均被丢弃，不显示于界面（与"切走"不同：切走只是隐去，请求继续、切回可恢复——见场景 14）。
11. **假设** btw 请求失败（如 API 错误），**则** BTW 面板显示 "(API error: ...)" 错误信息，不中断主对话。
12. **假设**附带问题不会被添加到主聊天历史或用户输入历史中。
13. **假设**主对话恰好在响应中（assistant 消息未结束）时提出 `/btw`，**则** btw 请求剔除该进行中的消息，从上一轮完成的请求前缀继续。
14. **假设** BTW 面板打开（加载中或已回答），**当**用户切换到另一对话（会话）时，**则** 面板随发起它的对话保留、新对话以干净状态开始（不显示旧对话的附带问题）；**当**用户再切回原对话时，**则** 面板按离开时的样子恢复——已回答的恢复原答案，仍在加载的继续显示"正在回答"并接着接收该请求的流式尾部（切走期间请求不中断、也不丢弃，迟到回复照旧落在它所属的对话上）。
15. **假设**用户在**远控 Web 页**（手机浏览器打开的 `/remote/`）输入 `/btw <question>`，**则** 上述 1–14 条全部照旧成立（同一个 `askBtw` fork 路径、同一个 `BtwPanel`、不污染历史、Esc 只关面板），即页面**不**把 `/btw` 当普通消息发出去；差别只在传输：请求经中继到宿主进程的 `askBtw`，流式尾部来自宿主的 `btwContent` 通知。当页面连的是**前台 CLI 会话**（该宿主尚未接 `/btw`）时，面板显示一句「该宿主不支持」的可见文案，不停在加载中。承载与白名单见 `remote/remote-web.md` 的「Web 页也能用 `/btw` 旁路提问」故事。

***

### 边界情况

* **用户输入不带问题的 `/btw` 怎么办？** 命令不进入 BTW 状态：CLI 显示英文 `"Usage: /btw <your question>"`（与 Claude Code 一致），Webview 显示中文 `"用法：/btw <你的问题>"`；输入行随 usage 消息隐藏，仅按 ESC 关闭，其他按键被忽略。
* **用户提出通常会触发工具的 `/btw` 问题怎么办？** btw 请求携带与主对话相同的工具列表（缓存键一致），但仅执行一轮且不反馈工具结果；模型若尝试调用工具，显示 "(The model tried to call X...)" 提示。
* **请求失败（如 API 错误）怎么办？** `BtwDisplay` 显示 "(API error: ...)" 错误信息，不中断主对话。
* **模型只输出 thinking 而无最终答案怎么办？** `BtwDisplay` 显示 thinking 内容（而非 "No response received"），避免思考阶段输出被丢弃。
* **主对话恰好在响应中（assistant 消息未结束）时提出 `/btw` 怎么办？** btw 请求剔除该进行中的消息，从上一轮完成的请求前缀继续。
* **附带问题不会被添加到主聊天历史或用户输入历史中。**
* **CLI 中回答较长如何滚动？** 回答绘制在固定高度视口内（高度 = `max(5, 终端行数 - 11)`），用 ↑/↓（或 Ctrl+P/Ctrl+N）滚动 3 行，不依赖终端 scrollback；超出视口时底栏提示 `↑/↓ to scroll · Esc to dismiss`，未超出时保持 `Escape to dismiss`。关闭键仍只有 ESC。
* **Webview 中回答较长如何滚动？** BTW 面板回答区域内部滚动（鼠标/触控板），无需 CLI 的 ↑/↓ 键。
* **Webview 中按 Esc 会终止主对话吗？** 不会。BTW 面板打开期间 Esc 在事件捕获阶段被面板拦截（stopPropagation），仅关闭面板；主对话 agent loop（即使正在流式输出）不受影响。
* **模型 thinking 结束后还显示 thinking 内容吗？** 不显示。加载期间只显示流式尾部（当前流式文本的最后 30 个字符），不显示完整中间文本；回答完成后只以 Markdown 渲染最终答案。
* **切换对话时 BTW 面板会残留吗？** 不会残留（不串对话），也不会丢：面板属于发起它的那个对话，切到别的对话时不显示它，新对话始终以干净状态开始；切回来时原样恢复，包括还在"正在回答"的那种（后台请求不中断，流式尾部接着更新）。
* **会话被删除后 BTW 面板会复活吗？** 不会。面板随会话一起消失，此后再进不来那个会话，自然也无从恢复（与面板布局、预览地址等会话级 UI 状态同命运）。
* **桌面端多 pane 并排时切换焦点会关闭 BTW 面板吗？** 不会。BTW 面板是对话级别的，不是焦点级别的：焦点从 pane 1 切到 pane 2 时，pane 1 上已打开的 BTW 面板保持显示；host 仅下发 `desktopPanes`（focusedPaneId 变化）而不推送新会话，各 pane 自己的 currentSession 不变。只有某 pane 绑定的会话真正切换时，该 pane 才换成新会话的视图（原会话的面板随之隐去，切回原会话时照旧恢复）。
