[建议] 任务卡在下载/安装时无法停止:不可中断的工具使 cancel 无法生效(协作式契约无强制力) [Suggestion] Non-interruptible tools make cancel ineffective: the cooperative execute contract has no teeth #3400
Replies: 2 comments 3 replies
|
The current rc.8 source suggests a useful distinction for this report: The tools contract is deliberately cooperative: every tool gets There is a second distinction after restart. The old OS process/promise cannot resume. Cold Session recovery closes interrupted calls with I wrote up the full evidence timeline, live containment sequence, UI states ( The key source seams are |
|
denial123789 已经把这帖的两个层面(运行中锁死 + 跨重启二次锁死)讲得很透,我补充一个家族视角和一个恢复契约的精确机制确认。 1. 这是"工具工作不可被宿主抢占"家族的第 3 个报告。
共同根因: 2. 第二层锁死(跨重启)的恢复契约机制——你的插件确实无法解决,且根因在 repair.ts 而非 resume。 3. 修复方向补充(在 denial123789 的 12 门之上):
家族闭环:#1607/#2544(unbounded-wait)+ #3477(spawnSync 死锁)+ #3400(不可中断工具)= 同一"协作式契约无强制力"根因的三个严重度档位。修复 = 契约禁止同步阻塞 + 工具层进程树终止 API + 恢复决策硬门 + 取消状态可视化。 |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
摘要 / Summary
当 agent 卡在一个长时间运行的前台工具调用上(例如
pip install torch或curl -o在网络不稳定时下载 2.5GB 大文件),原生的「停止」按钮和
session.cancel都无法及时终止任务。需要修正此前的表述:session.cancel本身不是被排队——宿主调用
agent.cancel({ kind: "user" }, { keepInbox: true })会立即返回{ accepted: true };但该确认只证明 agent 信号被中止,不证明已启动的工具/子进程树/管道/插件 promise 已收敛(quiescence)。不可中断的工具拒绝 settle,会话因此冻结到工具结束或超时。
When the agent is stuck waiting on a long-running foreground tool call (e.g.
pip install torchor acurl -odownload over a slow/unstable network), neither the native Stop button norsession.cancelcan stop the task in time. Note:session.cancelis not queued — the host callsagent.cancel({ kind: "user" }, { keepInbox: true })and immediately gets{ accepted: true }, which only proves the agent signal was aborted, not that the started tool/child tree/pipe/plugin promise reached quiescence. A non-interruptible tool refuses to settle, so the session stays frozen until the tool finishes or times out.复现步骤 / Repro
curl -o big.zip <url>或pip install)。session.cancel。影响 / Impact
在国内网络环境下非常常见:pip / GitHub 下载频繁卡顿或超时。用户会陷入"停不掉、也进行不下去"的局面,
只能重启 DSH。这对国内用户是很高频的痛点。
Very common in CN networks where pip/GitHub downloads frequently hang or time out. Users are left with a task they can neither finish nor stop, forcing a DSH restart.
衍生问题(跨启动)/ Follow-up: triggerable second lock across restarts
通过杀进程解决第一层锁死之后,还存在更隐蔽的第二层问题:
DSH 重启并重新连接后,不会主动恢复上一个等待;但当用户输入「继续」「继续上一个任务」「恢复刚才的任务」
等恢复类提示词时,会触发 agent 对一个【已经不存在于新进程中的任务】发起恢复/重试,于是再次陷入对
该空壳任务的返回值等待,暂停键/停止键再次全部失效,只能再次重启。
After killing the stuck process, a subtler second layer remains:
DSH does NOT automatically resume the old wait after restart and reconnect. But when the user sends
resume-style prompts like "continue", "continue the previous task", or "resume the last task",
the agent is triggered to resume/retry a task that no longer exists in the new process, and falls back
into waiting on its phantom return value — Stop/cancel become unresponsive again, forcing another restart.
家族汇总 / Family summary
这是「工具工作不可被宿主抢占」家族的第 3 个报告,与两个既有报告共享同一根因:
共同根因:
packages/core/tools/src/index.ts:222-233的 execute 契约是协作式——registry "cannot hard-kill same-process code",工具必须自行观察exec.signal并让工作达到 quiescence。契约对不合作的工具没有任何强制力,一个不观察 signal 的插件就能让会话无限期冻结。This is the 3rd report of the "tool work cannot be preempted by the host" family (#1607/#2544 unbounded-wait, #3477 spawnSync deadlock, #3400 non-interruptible tools), sharing one root cause: the cooperative execute contract at
core/tools/src/index.ts:222-233has no enforcement against uncooperative tools.两条 API 诉求 / API requests
① 工具层进程树终止能力
dsh-subprocess已存在树作用域终止契约,但未暴露到tools/execute工具层;packages/core/tools/README.md#cancellation、packages/host/apiproxy/src/api-proxy.ts:2617-2633② 中断恢复的强制决策点
interruptedTurnClosers(core/session/src/repair.ts:27)合成 closers,TOOL_OUTCOME_UNKNOWN(repair.ts:13-16)的恢复提示文本(repair.ts:104)引导模型"只在只读/幂等时重试",但这是提示而非强制;TOOL_OUTCOME_UNKNOWN的调用重试前必须显式选择(验证外部状态 / 询问用户 / 放弃),使恢复契约从"建议"变为"硬门"。建议修复方案 / Suggested fix
TOOL_OUTCOME_UNKNOWN恢复语义升级为结构化决策点;参考实现 / Reference implementation
我开发了一个插件解决了第一层问题(运行中的锁死):宿主按卡住工具的命令行特征匹配并强制杀掉子进程,
使工具调用立即返回——用户因此获得一键「急停」(带防误触确认,外加下载进度检测),并正在落地:
急停后的真实 stopping 状态展示(accepted / stopping / idle 三态)与
TOOL_OUTCOME_UNKNOWN的结构化恢复决策。注意:该插件【无法解决】上述跨启动的触发式二次锁死,它需要 DSH 官方在会话恢复/重试机制层面修复。
I built a plugin that solves the first layer (in-session lockup): the host matches the stuck tool's command-line
fingerprint and force-kills the child process — one-click "emergency stop" with a confirmation dialog and live
download-progress detection. It is an emergency workaround; the real fix belongs in the tool execution layer.
🔗 https://github.com/ningmengxr/dsh-task-control (npm:
dsh-task-control)Analysis credits / 分析来源
谢谢!Thanks!
All reactions