dsh-commander
DeepSeek Harness Web GUI 的指挥官插件:把任意一个对话升级成「指挥官」,它的模型可以在回复里派发任务给其他对话(worker)并行执行;插件自动送达任务、监视 worker、把结果摘要以「回执」注入指挥官会话,形成无人值守的多窗口协作闭环。
一键安装:
dsh plugin add qwert702/dsh-commander装完重启 harness(
dsh web)、刷新页面即可生效。会话头部会出现「成为指挥官」按钮。
功能
一键激活/停用:会话头部点「成为指挥官」→ 确认后,插件把一份协议简报(指挥官规则 + 从会话列表实时生成的 worker 花名册)静默注入该会话(不触发模型回合、不烧 token);再次点击徽章可打开面板「停止指挥」。
协议派发:指挥官的模型在回复中原样输出任务块,插件解析后自动执行:
<dsh-dispatch target="#1" title="新会话标题(可选)"> 交给 worker 的完整、自包含的任务描述 </dsh-dispatch>target填花名册别名(#1)或完整会话 id;省略则自动新建 worker 会话(继承指挥官工作目录,并自动标注[T3] 任务摘要…式侧边栏标题;有title则以 title 为准)。- 广播派发:
target="#1,#2"同一任务发给多个 worker 并行;target="all"发给花名册全部会话。 - 上下文继承:
fork="commander"(或fork="<会话id>")配合省略 target 时改走会话分叉——新 worker 天然携带源会话的全部背景,任务文本不必再自包含(代价:继承前缀消耗更多 token)。 - 依赖编排:块可带
tid="a"命名自己;另一块depends="a,b"会等这些前序任务全部完成后才派发,任一前序失败则连锁取消(fail-fast)。 - 一次回复可含多个块,逐个送达。
同 worker 串行化:引擎按 worker 加发送锁——同一 worker 上一次任务未结算时后续任务自动排队(面板显示「排队中」),baseline 探针在持锁后才执行,回执归因永不串台;人类正在占用 worker 时同样让位。
负载均衡简报:协议简报自带每个 worker 的实时任务负载(空闲 / 进行中 N 个),并明确要求相互独立的任务分散到不同 worker、优先低负载会话——杜绝「全部压给同一个对话」。
循环防护:派发给另一个激活中的指挥官允许但计入
commanderHops预算(默认 10),超限拒绝,杜绝 A→B→A 乒乓烧 token。用量统计:回执自动附带耗时与输出 token 数(聚合自回合 usage),面板每行可见
⏱12s · ~579 tok。结果自动回流:worker 完成回合后,插件从 host 事件日志提取其新增输出,截为摘要,以
[指挥官回执 · #N 「标题」] 状态:…的消息 queue 进指挥官会话——指挥官被唤醒继续汇总或继续派发,无需人工复制粘贴。产物回收:回执自动附带 worker 的变更文件清单(从 write/edit 工具调用投影,去重保序),面板任务行显示 📄N 徽标、路径点击即复制——产出不再只是一段话。
全文结果:面板「全文」按钮拉取该任务的完整输出(200KB 上限内不截断),摘要之外随时可查原文。
中断自动续跑:worker 回合被截断(token 上限)或异常中止(aborted/error)时,插件自动向该 worker 发送续跑指令("从中断处继续执行原始任务"),最多
maxContinuations次;最终回执聚合中断前后全部输出并标注续跑次数。手动取消与人工接管永不触发续跑。延迟派发:
<dsh-dispatch delay="10m" ...>支持30s / 10m / 1h或纯秒数;任务进入「定时中」,到点自动走完整派发管线(含锁/排队/回执),重启后未到点的任务照常计时。失败自动换人(failover):续跑仍救不回来的失败任务,自动改派给负载最低的空闲 worker 重跑同一任务(
maxFailovers预算沿链继承,杜绝无限换人);面板标注「已换人」,回执注明改派去向。审批一键操作:worker 卡在权限确认时,任务行出现 ✓批 / ✗拒 按钮——在指挥官面板里直接应答,不用跳进 worker 窗口。
开池模板:面板「开池」表单输入角色 + 数量 + 热身指令模板(支持
{role} {i} {n}占位符),一键批量创建同角色 worker 并预派热身任务。派发前确认模式:
confirmDispatch: true时每批任务先挂起,面板点「全部放行」才真正发送——给自动化加一道总闸。批次汇总回执:一次派发的多个任务全部结算后,额外注入一条
[指挥官批次汇总 · N 项已全部结算],逐项带状态与结果预览,指挥官一眼消化整波结果。任务面板:头部徽章显示进行中任务数,点击下拉面板:
- 任务列表:状态点(排队/等依赖/运行/完成/失败/已接管)/ 目标 / 摘要 / 耗时与 token / 打开会话;
- 手动直派:选 worker + 输任务直接发送,绕过模型协议的逃生门(仍受并发上限、worker 锁、回执闭环约束);
- 停止:运行中任务随时取消;重试:失败/阻塞任务一键重发;排队任务可 立即发 强制投递;
- 徽标:「待确认」(worker 在等权限确认)/「超时」(超过
stuckTimeoutMs)/「排队久」(目标长时间未空闲,提示用立即发); - 花名册区:各会话运行状态点 + 刷新花名册。
设置面板:「设置」展开即可调轮询间隔/并发上限/回执开关/通知等,保存即写回
~/.dsh/settings.yaml的命名空间并即时生效,无需手动改文件重启。原生设置页:dsh 侧边栏「设置」面板新增**「指挥官」导航页**——轮询间隔、并发上限、一次最多开几个对话、续跑/换人次数、确认模式、回执与通知等全部字段就地编辑,保存写回
~/.dsh/settings.yaml并即时生效;手动改 yaml 也会实时同步到界面。任务统计(按项目 / 总计):同一设置页顶部实时汇总各项目(按 worker 工作目录)的任务数、成功率、平均耗时与变更文件数,底部固定「总计」行。
报告导出:一键把全部任务+结果复制为 Markdown 归档。
人工接管检测:worker 的 baseline 之后若出现真人消息(非插件注入),该任务标记「已接管」并不再自动回执——避免和正在亲自操作的人抢话。
全局悬浮指示器:任何会话右下角都有小挂件列出各激活指挥官及其进行中任务数,点击直达对应会话——人在别处干活也不漏进度。
后台桌面通知:标签页在后台时,批次结算/任务失败/worker 卡住会发系统通知(首次激活时请求权限)。
负载均衡简报:花名册注入时附带每个 worker 的实时任务数(空闲/进行中 N),并明确要求模型"独立任务必须派给不同 worker、优先选空闲会话"——杜绝把所有任务压给同一个对话。
重启不丢指挥官:激活状态双写持久——浏览器 localStorage(页面刷新恢复)+ host 端
<dsh-home>/dsh-commander/registry.json(harness 重启、换端口、换浏览器都照常恢复)。引擎启动时合并两个来源,会话仍存在的指挥官自动重新上岗(游标钉在最新尾部,历史输出绝不重复执行)。任务历史持久化:任务表实时镜像到 localStorage(保留最近 100 条),页面刷新后自动恢复;未完成任务由监视器重新结算补发回执。
后台运行:引擎挂在模块层而不是组件层——轮询走 host 事件日志路由,不依赖当前浏览器停留在哪个对话。
安全护栏
- 仅当指挥官空闲时才解析新输出;同一批输出只处理一次(游标推进,at-most-once)。
- 游标探测失败即拒绝上岗:恢复/激活时若无法确认会话尾部锚点(重试 3 次仍失败),该指挥官跳过恢复或激活中止——绝不回退到 cursor 0,从根上杜绝"重启后历史任务被当新指令重放"。
- 上限:并发任务 5 / 单条消息块数 8 / 单任务字数 4000 / 单次激活累计派发 50(防失控循环),批次间隔 ≥1s。
- 拒绝自指(target=指挥官自己);prompt 被拒标记为「已阻塞」并在面板可见,不做重试风暴。
- 简报注入在 host 端 fail-closed:会话不存在 / 回合进行中 / 超长文本一律拒绝。
工作原理
- host 半区(
lib/index.js):设置命名空间dsh-commander+ 五条路由:GET /api/dsh-commander/config— 解析后的配置(POST 为设置面板白名单写回);POST /api/dsh-commander/inject {sessionId,text}— 把简报作为一条 plugin 来源的 user 消息静默追加进会话(context-compressor 同款 checkpoint 手法,不开回合);GET /api/dsh-commander/events?sessionId&cursor&limit— 只读投影:cursor 之后已定型的 assistant 文本 + 最后一个turn/end原因 + 真人消息计数(接管信号)+ 变更文件与工具统计 + 全日志尾部锚点;GET /api/dsh-commander/fullresult?sessionId&baseline— 任务完整输出(面板「全文」数据源);GET|POST /api/dsh-commander/registry— 持久指挥官注册表(~/.dsh/dsh-commander/registry.json),重启存活的关键。
- 浏览器半区(
lib/client.js):模块级引擎单例以 ~2s 轮询每个激活指挥官的 events 尾部 → 正则解析<dsh-dispatch>块 → 广播展开(#1,#2/all)→ 纯函数策略闸门(并发/条数/累计上限)→ 经客户端 sessions 运行时binding(target).prompt(task,'queue')送达(或create({cwd})新建)→ 订阅sessions.list快照监视 worker 的 running 标志与 pendingInteraction(侧边栏同源信号)→ 结算后把回执 prompt 回指挥官;整批结算再补一条批次汇总。 - UI:两个增量坐席——
conversation.session.header.actions(徽章+面板,与家族其他插件同款)与shell.overlay(全局悬浮指示器),不替换任何原厂组合。
设置(可选)
在 ~/.dsh/settings.yaml 添加命名空间 dsh-commander:
dsh-commander:
enabled: true # 总开关
maxOutstanding: 5 # 并发进行中任务上限
maxPerMessage: 8 # 单条回复最多解析的任务块数
maxTaskChars: 4000 # 单个任务文本截断长度
summaryMaxChars: 800 # 回执摘要截断长度
pollIntervalMs: 2000 # 引擎轮询间隔(毫秒)
autoReport: true # 是否把结果回执/批次汇总注入指挥官会话
stuckTimeoutMs: 600000 # 运行多久后标记「超时」(毫秒)
autoLabelWorkers: true # 自动新建的 worker 是否标注 [T#n] 标题
maxCommanderHops: 10 # 跨指挥官派发预算(防循环)
notify: true # 后台桌面通知
maxContinuations: 2 # 回合中断后自动续跑次数上限(0=关闭)
maxFailovers: 1 # 失败后自动换人重试次数(0=关闭)
maxNewWorkersPerBatch: 3 # 单条回复最多自动新建几个对话(0=禁止自动新建)
confirmDispatch: false # 派发前需人工在面板「放行」
不配置即用以上默认值;也可在 dsh 原生设置面板的「指挥官」页或任务面板「设置」区修改(写回此文件并即时生效)。
使用建议
- 给指挥官下达的总目标请说清「可以拆分派发给多个 worker」;模型自己决定拆几个任务、要不要开新窗口。
- 任务文本务必自包含——worker 看不到指挥官的任何上下文(简报里已反复提醒模型)。
- 面板出现「待确认」徽标时,说明 worker 在等权限确认,点「打开」去处理即可。
- 不想让它继续跑的任务随时「停止」;跑挂了的点「重试」。
- 多个会话可各自激活为指挥官互派任务,但请注意这会真的互相烧 token。
仓库布局
lib/index.js— 插件 host 半区:设置命名空间 + 注入/事件两条路由。lib/client.js— 浏览器半区:协议解析、广播展开、策略闸门、花名册、引擎(激活/轮询/派发/监视/回执/批次汇总/取消重试)、头部徽章面板、全局指示器(手写 bundle,与家族其他插件同技术路线)。test/smoke.cjs—node test/smoke.cjs:语法检查 + host 四路由全分支(校验矩阵/checkpoint 追加/尾投影锚点/真人消息计数/设置写回白名单/持久注册表)+ client 纯函数与完整编排回路(激活→派发→结算回执→自动新建→广播+批次汇总→同 worker 串行化归因→跳数防护→fork 继承→tid/depends 依赖链→用量聚合→人工接管→中断续跑→取消重试→强发→直派→报告→通知节流→持久化)+ SSR 断言。无 harness 安装时(CI)自动降级为语法+结构标记检查。.github/workflows/smoke.yml— push/PR 自动跑冒烟(windows-latest,无私有依赖也能过)。
已知限制
- 浏览器在线才有调度:轮询和派发都发生在网页端;关掉标签页任务不会派发(已在跑的回合在 host 侧不受影响)。harness 重启同理。
- worker 需要人工确认时不代答:权限请求会让任务停在「待确认」,需要你手动处理——这是有意设计,插件绝不代替人做决定。
- 任务历史保留最近 100 条:更早的记录会被裁剪掉(回合本身照常进行)。
- 摘要来自文本块:worker 若只产出工具调用没有最终文字,回执摘要是「(该回合没有产生文本输出)」。
- 同名目标按精确匹配:target 写会话标题时必须与侧边栏显示名完全一致,推荐用别名或 id。
- 配置读取一次:浏览器半区页面加载时读一次配置,改设置需刷新。
- 人工接管的判定是启发式:只要 baseline 后出现过真人消息就算接管;若那只是巧合插话而模型仍期望回执,可在指挥官里手动让它询问 worker 进度。
License
MIT
No comments yet. Be the first to write one.