Skip to content

✨ feat(web,sidecar,shared,sdk): Bash 手动转后台——运行中命令可由用户一键转入后台 - #856

Merged
CavinHuang merged 2 commits into
mainfrom
feat/bash-manual-background
Aug 30, 2026
Merged

✨ feat(web,sidecar,shared,sdk): Bash 手动转后台——运行中命令可由用户一键转入后台#856
CavinHuang merged 2 commits into
mainfrom
feat/bash-manual-background

Conversation

@CavinHuang

Copy link
Copy Markdown
Owner

⚠️ 基于 #854(feat/background-bash-semantics)堆叠,请先合并前者。

功能

借鉴 ZCode 的"用户手动后台化"能力:当一个 Bash 命令正在前台运行(还没到 15s 自动转后台预算)时,工具卡片上出现**「转入后台」**按钮,点击后命令立即转入后台继续执行,原工具调用立刻返回后台回执,回合恢复响应。

链路

web 运行中 Bash 卡片「转入后台」按钮
  → agent:promote-shell-background RPC(toolUseId + sessionId)
  → sidecar bash-handlers(zod 校验,薄转发)
  → SDK promoteForegroundShellTask(按 toolUseId 查注册表,跨会话/未知 id 拒绝)
  → promoteToBackground:task_started 事件 + 后台回执
  → call() 立即返回回执;完成通知链路照常

实现要点

  • 注册窗口:仅前台等待期内的 durable 任务注册(task.job 存在才注册);direct 路径(独立 SDK 调用方)不支持,fail-closed。
  • 一次性:触发即从注册表摘除;call() 的 finally 兜底清理。
  • 踩坑记录Promise.race 会把 undefinedPromise.resolve 立即兑现——manualPromotion 缺省时绝不能混入 race 数组,否则前台等待被 0ms 击穿、所有前台命令直接落入自动转后台(已由改写前 8 个失败用例实证,现钉在 raceForeground helper 注释里)。
  • 回执文案Command was moved to the background by user: <task_id>_meta.task.backgroundedByUser: true 供 UI/模型区分三种后台入口(显式/自动/手动)。

测试

  • bash.test.ts 55 pass / 2 env-skip:手动 promote 全链路(未知 id 拒绝、跨会话拒绝、回执、ProcessOutput 收尾、task_started 恰好一次)
  • @lume/agent-sdk / @lume/shared / @lume/web typecheck 通过
  • sidecar 存量 typecheck 错误(obsidian vault-facade.test)在 main 基线即存在,与本 PR 无关

前台等待期内(15s 自动转后台预算之前)的 durable Bash 命令按 toolUseId
注册进 SDK 注册表;web 工具卡片对运行中的 Bash 显示"转入后台"按钮,经
agent:promote-shell-background RPC 触发 promote:原工具调用立即收到
后台回执(backgroundedByUser: true),命令与完成通知链路由既有
promoteToBackground 接管。跨会话/未知 toolUseId 拒绝,fail-closed。

- sdk: raceForeground helper 挂接手动晋升 promise;注意 Promise.race
  会把 undefined 经 Promise.resolve 立即兑现,manualPromotion 缺省时
  必须从 race 中剔除,否则前台等待被 0ms 击穿(已钉测试)
- sidecar: bash-handlers 薄转发层 + zod schema + 注册
- web: 运行中 Bash 卡片"转入后台"按钮(ui/Button,失败 toast 降级)

Constraint: 仅 durable 路径可手动转后台——direct 路径(独立 SDK 调用方)无 job 记录,注册表不覆盖
Constraint: 基于 feat/background-bash-semantics(#854)堆叠,合并需先入前者
Rejected: 按 jobId 而非 toolUseId 定位 | 命令运行中回执未产生,UI 拿不到 jobId
Rejected: promote 后保留原前台等待继续等 done | 转后台语义就是立即归还回合
Tested: bash.test.ts 55 pass(含手动 promote 全链路:未知 id/跨会话拒绝、回执、完成通知一次性)
Tested: @lume/agent-sdk、@lume/shared、@lume/web typecheck 通过;sidecar 存量 typecheck 错误在 main 已存在(obsidian vault-facade.test)
@CavinHuang
CavinHuang merged commit 8e038f6 into main Aug 30, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants