在输入区暂停/恢复/取消正在运行的对话任务:强制暂停立即中断并记住被中断的工具,安全暂停等工具/推理完成后再落地,恢复时需确认;默认暂停粒度可在设置中配置(出厂 safe wait)。
安装
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:p2coder/dsh-task-control
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本。请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
English | 中文
任务控制插件(DSH Web):提交对话任务后,除了现有的"停止/取消",还提供 暂停任务、恢复任务 两个控制,以 Cordis 双面插件(宿主端 + 浏览器端)实现。
功能
| 操作 | 行为 |
|---|---|
| 暂停 (Pause) | 两种模式:强制暂停与安全暂停;未显式指定时按设置 →「任务控制」中的默认粒度执行(出厂默认 safe wait)。 |
| · 安全暂停 | 从不中断工作:有工具在执行 → 延迟到安全界限(工具执行完毕、tool/result 落地且无更多 in-flight 工具)才真正暂停;有推理在执行 → 按设置中的推理粒度:wait(默认,不中断 LLM,等推理完成后再暂停)或 stop(终止当前 LLM 输出,恢复时重新推理)。期间 trace 持续记录。 |
| · 强制暂停 | 立即取消正在执行的工具、中断推理输出;暂停状态记住被中断的工具(interruptedTool)。恢复时先查该工具在会话日志中的实际结果:已执行完成 → 直接继续不重跑;被中止/状态未知(可能部分执行)→ 提醒用户"上次暂停时 xxx 工具没有执行完成,将重新执行",由用户选择 重新执行该工具 / 跳过该工具 / 保持暂停。 |
| 恢复 (Resume) | 清除暂停标记,从暂停点继续执行(会话日志即 trace,不重发原始提示词、不重跑已完成工作)。安全暂停:从暂停点继续;若恢复时任务实际仍在运行(暂停未真正落地)→ 仅清除标记,期间工具/模型执行结果正常显示。强制暂停(有被中断工具):必须先确认,用户选择 rerun/skip 后按选择继续。 |
| 取消 (Cancel) | 立即中断当前回合(保留输入队列),清除暂停标记;若有工具在执行,立即终止并在回复中说明其预期目的、提醒检查副作用(文件/进程/网络等)。 |
暂停粒度默认值:在 Web 设置 →「任务控制」中配置(出厂默认
safe+wait)。命令/pause(及输入区暂停按钮)未显式指定模式时按此默认执行;/pause force、/pause safe [stop|wait]显式覆盖。taskControl服务:pause(sessionId, { mode, reason })(缺省字段同样按设置解析)、resume(sessionId, { confirm, choice: 'rerun'|'skip' })。强制暂停后点恢复会弹出三选菜单(重新执行 / 跳过该工具 / 保持暂停)。
状态模型(Route A):暂停/恢复状态不再写入会话日志(task-control/paused / task-control/resumed 是自定义事件类型,harness 的持久化读取器只认内置事件类型清单或带 ignorable 标记的事件,写进去会导致会话在重启后无法加载)。状态改由插件自己的持久化 store 保存(~/.dsh/task-control/<sessionId>.json,原子写;测试可用 DSH_TASK_CONTROL_STATE_DIR 覆盖目录),所有读取方统一走这一个数据源:
- 浏览器 dock:轮询宿主路由
/task-control/state?session=<id>(每 2 秒); - 浏览器设置页:
/task-control/settings路由读写暂停粒度默认值(默认safe+wait),修改后立即生效; taskControl服务state():直接读 store,离线会话(未加载)也能返回暂停状态,重启后暂停态不丢;- dsh-trace-repeat:在每个会话事件上通过
taskControl服务对账暂停门控。
task-batch 等其他插件继续用 taskControl 服务,无需改动。
安装
包内已含 dsh.bundle manifest,安装后自动激活(无需手动修改任何配置):
# 从 GitHub 安装
dsh plugin --profile web add github:p2coder/dsh-task-control
# 发布 npm 后亦可:dsh plugin --profile web add dsh-task-control
安装后完整重启 dsh web(宿主插件不支持运行时热装),并在浏览器中刷新页面。
使用
- 刷新浏览器页面。
- 提交一个任务,agent 运行期间,发送按钮左侧会出现三个图标按钮:
- ⏸ 暂停(运行中可用)
- ▶ 恢复(已暂停时可用)
- ⏹ 取消(运行中或已暂停时可用)
- 按钮组常驻(不随空闲隐藏),仅按状态禁用:空闲/无暂停时暂停与恢复按钮变灰、取消按钮在既非运行也非暂停时变灰。
- 设置 →「任务控制」:配置默认暂停粒度(默认
safe+wait),裸/pause与暂停按钮按此执行。
也可以直接在输入框输入斜杠命令:/pause、/resume、/cancel(命令结果会以普通命令行形式出现在对话中)。
暂停语义(默认跟随设置,出厂为 safe wait):/pause(及 dock 暂停按钮)未显式指定模式时,按设置 →「任务控制」中的默认粒度执行(默认 safe wait:等推理/工具完成后才落地,不中断工作)。显式 /pause force 立即中断当前回合:在途工具被取消、LLM 输出被切断,暂停快照记录被中断的工具(interruptedTool);恢复时需先确认:/resume confirm rerun(重新执行被中断的工具)/ /resume confirm skip(跳过该工具);工具实际已完成的自动跳过、绝不重跑。/pause safe [stop|wait] 显式指定安全暂停:safe wait 落在推理完成后、工具派发前,未派发的工具记录为 deferredTools,恢复同样需确认。
结构
dsh-task-control/
├── package.json # dsh.bundle.patch + dsh.client(platform: web) 声明
├── cordis.patch.yml # 一个双面行:- id: task-control / name: dsh-task-control
├── lib/
│ ├── index.js # 宿主端:/pause /resume /cancel 命令 + taskControl 服务 + 持久化状态/设置 store + /task-control/state、/task-control/settings 路由
│ └── client.js # 浏览器端:composer 工具行按钮组 + 状态轮询 + 设置页「任务控制」面板(__ModuleLoader__ 格式)
└── test/
└── host-smoke.mjs # 宿主端逻辑冒烟测试(node test/host-smoke.mjs)
宿主服务(供其他插件调用)
宿主端发布 taskControl 服务,其他插件可按 sessionId 调用同一套实现(命令与按钮内部也走它):
taskControl.pause(sessionId) → { ok, text } | { ok: false, error } // 按设置默认粒度暂停(默认 safe wait)+ 标记暂停
taskControl.resume(sessionId) → { ok, text } | { ok: false, error } // 清除标记 + 从暂停点继续(不重发原始提示词)
taskControl.cancel(sessionId) → { ok, text } | { ok: false, error } // 中断回合 + 清除标记
taskControl.state(sessionId) → { status, paused, forced, interruptedTool, deferredTools, resumeContent } // status: idle|running|offline(离线也能读暂停态)
消费方(例如 dsh-task-batch 的「全部暂停/恢复/取消」)用 ctx.get("taskControl") 读取,不要复制实现——本服务的语义即唯一事实来源。
已知限制
- 暂停期间的新输入:暂停只拦截"当前回合",不拦截新消息——界面在暂停态仍允许发送(发送会开启新回合)。如需"暂停=彻底冻结会话",需要额外的 composer 提交闸门,暂未实现。
- schedule 定时提醒:暂停不会拦截
dsh-schedule到期的提醒回合(会照常唤醒);goal 自动轮次会被拦截(见上)。 - 子代理:暂停父回合不会中断已派发的子代理,其汇报可能在恢复后到达。
- 恢复语义:恢复 = 从暂停点继续执行(不重发原始提示词、不重跑已完成工作);被强制暂停中断的工具由用户选择重新执行(
rerun)或跳过(skip)。工具的副作用状态按会话日志中的实际结果判断:有完成结果 → 视为已执行;中止/无结果 → 状态未知,提醒用户后由用户决定。 - 状态位置(Route A):暂停状态在插件的持久化 store 里,不在会话日志里——这是有意为之(自定义会话事件会让 harness 拒绝加载该会话)。代价:浏览器 dock 靠 2 秒轮询
/task-control/state获取状态,而非投影订阅;trace-repeat 的暂停标记版本在「暂停/恢复后的下一个会话事件」时写入,纯暂停+恢复且中间无任何事件时不会产生标记版本。暂停粒度默认值存于同一 store 根的settings.json(默认safe+wait),修改后立即生效、无需重启。 - safe wait + 推理输出工具调用(deferredTools):在默认(
safe wait)或显式/pause safe wait时生效,落在推理完成后、工具派发前。此时模型刚输出的工具调用会被内核标记为ABORTED_BEFORE_DISPATCH(未派发、无副作用),并记录为暂停快照的deferredTools。恢复时必须先确认(/resume confirm rerun重新执行 //resume confirm skip跳过;工具实际已完成的自动跳过,绝不重跑)。若浏览器 dock 的 client bundle 未随lib/client.js更新(需重启 dsh web 生效),dock 的恢复按钮仍会直接发不带confirm的/resume,host 返回needConfirmation拒绝——此时请手动输入/resume confirm rerun。注意:这些被 abort 的工具调用仍会以失败记录留在会话日志中(内核appendSkippedToolCall写入),这是方案一(记录+重放)的固有形态;如要彻底消除失败观感需在核心 agent-loop 实现"工具派发前冻结"(方案二,未实施)。裸/pause跟随设置中的默认粒度(出厂safe wait),显式force/safe才走对应路径。
链接
同类插件
Anionex/dsh-turn-rewind★ 56
对话回退:基于持久 Change Ledger 回滚会话与工作区状态。
Nwflower/dsh-chat-import★ 35
把 13 家 coding agent(Claude Code、Codex、ChatGPT、Cursor、Gemini、opencode 等)的完整对话历史导入为可续聊的 DeepSeek Harness 会话,并支持反向导出回 Claude Code。
whyihaveyou/dsh-suite#plugin-session-export★ 31
把 append-only 会话日志导出为按轨迹来源分组的可读 Markdown 或 HTML。
Chinesezjc/dsh-interconnect★ 27
跨实例互联:经 interconnect 服务在多个 DSH 实例间转发消息与事件。
Moeblack/dsh-message-edit★ 22
基于分支的消息编辑、reroll、重试与版本时间线。
hellodigua/dsh-share★ 19
一键分享你的对话。