Skip to content

fix(background-terminals): 多 id 的 bg_kill 被中止后,已结束终端的结果不再丢失 - #849

Open
6iKUN6 wants to merge 1 commit into
openpi-dev:mainfrom
6iKUN6:fix/bg-kill-abort-keeps-settled-results
Open

6iKUN6 wants to merge 1 commit into
openpi-dev:mainfrom
6iKUN6:fix/bg-kill-abort-keeps-settled-results

Conversation

@6iKUN6

@6iKUN6 6iKUN6 commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

Problem

一次 bg_kill 杀多个终端时,如果在等待过程中按了 Esc,已经结束的那些终端的结果会彻底丢失,模型永远不知道它们结束了。

举个例子:

  1. 模型调用 bg_kill(["fast", "slow"])。
  2. fast 收到 SIGTERM 马上就退出了。slow 忽略 SIGTERM,要等大约 2 秒后升级到 SIGKILL。
  3. 用户在这 2 秒里按了 Esc,bg_kill 报 Kill wait aborted; termination continues in the background. 后退出。
  4. 之后 slow 被 SIGKILL 杀掉,结果正常作为后续消息送达模型。
  5. 但 fast 的结果既不在 bg_kill 的返回里(工具已经抛错),也不会作为后续消息送达。

模型以为 fast 还在跑,比如以为 dev server 还开着,后面的判断就会跟着出错。

原因在 extensions/background-terminals/src/manager.ts:

  • kill() 开始时,给要杀的终端加上 "kill interest"。终端在这期间结束时,settle() 会把它标成 consumed,意思是"这次 kill 会自己把结果返回给模型,不用再自动发一份"。index.ts 的 onSettled 看到 consumed 就不再投递。
  • 可是 kill 被中断后,什么都不返回。ensuring 只释放了 interest,没有把那些已经标成 consumed 的结果放回投递队列,它们就丢了。

Value

后台终端是 OpenPI 的核心能力之一。AGENTS.md 要求 runtime 负责"唯一终态和结果投递",每个结束的终端都应该让模型确切知道一次。按 Esc 是最常见的操作,而多 id 的 kill 里只要有一个进程忽略 SIGTERM,就会打开这 2 秒的窗口。

Approach

  • Entry 上加一个 awaitingKillReport 标记。settle() 判定为 consumed 时设为 true,表示"自动投递被跳过,正在等某个 kill 返回它"。
  • kill() 成功拼好报告后,把自己负责的终端的标记清掉,表示结果已经交给调用方。
  • kill() 的 ensuring 里,如果这次 kill 没有成功返回(被中断或失败),在释放 interest 后,对每个仍然 awaitingKillReport、并且已经没有别的 kill 持有 interest 的终端,按普通的非 consumed 方式再调一次 onSettled,交回正常的自动投递流程。
  • 如果还有别的 kill 在等同一个终端,就交给那个 kill 来返回,不重复投递。如果那个 kill 也被中断,最后释放 interest 的那一次会负责交回。
  • 只改了 manager.ts,index.ts 的投递逻辑没动,走的还是原来的 defer、合批、agent_settled 那一套。

Validation

基线是上游 f98d6a4。

修复前后都跑了新加的回归测试:

测试 修复前 修复后
index.test.ts:an aborted multi-id bg_kill still delivers the terminal that already settled,通过真实的 bg_start、bg_kill、agent_settled 走完整流程,检查发给模型的消息 ❌ fast 没有送达(10 秒超时) ✅ fast 和 slow 各送达一次
manager.test.ts:an aborted multi-id kill hands already-settled results back exactly once ❌ fast 只有一次 consumed: true,没有交回 ✅ 交回一次,slow 正常结束
manager.test.ts:an aborted kill does not redeliver results another kill returned(防止重复投递) ✅ ✅

写测试时注意到一点:bg_status 查到已结束的终端时,本来就会把这个结果算作"已经交给模型",所以测试里用 bg_list 轮询状态,不用 bg_status。

其他命令:

  • tests/extensions/background-terminals/ 全部:105/105 通过,连续跑了 3 次。
  • bun run check:通过。
  • bun run test,Node 部分:2461 个,2450 通过、9 跳过、2 失败。
    • 失败的是 tests/extensions/plan-mode/result-rendering.test.ts 里的 a rich plan renders without throwing and keeps its content 和 expanded survives edge-content plans at extreme widths。
    • 这两个在没改过的 main 上本地也失败,上游 CI 是绿的,应该是我本机环境的问题,和这个 PR 无关。
  • bun run test,UI 部分:Node 部分失败后脚本没有继续,我用 bun run test:ui 单独补跑了。
    • 1338 个,1334 通过、4 失败。
    • 失败的都在 tests/web/ 下,是超时类用例,没改过的 main 上本地也会失败。这个 PR 没碰 web 代码。
  • 没有在真实 TUI 里手动按 Esc 验证,只有上面的自动化测试。新测试依赖 trap '' TERM 和 POSIX 信号,在 Windows 上跳过。

Impact

  • 用户可见: 多 id 的 bg_kill 被中止后,已经结束的终端会和其他后台结果一样,作为后续消息显示出来,不再悄悄消失。
  • 模型可见的上下文和工具: 模型会多收到一条之前漏掉的终端结束消息,格式和普通的自动投递一样。工具的参数和返回格式没有变化。
  • 运行时和生命周期: kill 正常完成时行为不变。只有 kill 没能返回结果时,才会把它压下的结果交回自动投递。每个结果最多投递一次。
  • 持久化的配置和数据: 无。
  • 兼容性和风险: 开着的 fix(background-terminals): preserve shell-significant command whitespace #689 / fix(background-terminals): preserve shell-significant command whitespace (integrate #689) #760 也改了 background-terminals/index.ts,但这个 PR 只改了 src/manager.ts,没有重叠。

🤖 Generated with Claude Code

…bg_kill is aborted

A terminal that settles while a bg_kill holds interest skips the automatic
follow-up because that kill is expected to report it. If the kill is
then interrupted (Esc while another id waits for SIGKILL), it reports
nothing and the settled result was lost. Remember which settlements were
suppressed for a kill report and, when an interrupted kill releases the
last interest in them, hand them back to the normal delivery path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions github-actions Bot added the area:background-terminals Background terminal runtime, skill, or tests label Oct 15, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:background-terminals Background terminal runtime, skill, or tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant