dsh-foreman:单账本主 loop,把工单派到多台 DSH 设备

前言

在 DeepSeek Harness(DSH)里跑智能体,常见做法是本机一个实例:工单、策略、评估和会话都在同一进程里。当你有多台机器——公司笔记本、宿舍电脑、一台常驻服务器——希望「在一个地方说话、在对应机器的工作区里干活」,而又不想在每台设备上各维护一套账本,就会遇到路由与状态一致性的问题。

下面介绍社区插件 dsh-foreman(维护者 niechao136)。它在服务器侧保留唯一账本(Engine、SQLite、Policy、Tickets、Evals、设备表),通过 Hub 与 Selector 把工单派到远端设备上完整运行的 DSH;设备侧用配套的 dsh-foreman-node 只接单、本地执行并回报,不建工单、不持策略、不打开数据库。项目标注为早期开发中,MIT 许可;不是 DeepSeek 官方产品。

这是什么

一句话定位(摘自项目 README):一个常驻的主 loop,把工单派给多台在线设备上各自完整运行的 DSH,账本只有一份。

架构上,服务器跑 dsh-foreman,每台个人机器装 dsh-foreman-node;设备通过 wss 主动连 Hub。本机也可 target.kind === 'local',行为与不接设备时相同。

当前 package 版本为 0.5.1(以仓库 package.json 为准)。运行时要求 Node ^22.19.0 || >=24.0.0,DSH ^0.2.1-alpha.2。

核心功能

单账本与双层角色

服务器侧集中持有工单、策略与评估;每个项目一条主会话入口,操作者在此对话,主会话负责路由,Worker 在具体工作区目录执行。设备侧插件不承担账本职责。

Selector 与派单时机

accept 工单时,prepareTicket 即选定设备并写入 Ticket.target,再由 newAssignment 复制到 Assignment.target——不是 Executor 选型(Executor 没有写库通道)。

  • 远端目标:以 assign 帧发给对应设备;设备不在线则报 blocked,不伪造 failed,也不悄悄改成本机跑。
  • 本地目标:交给本机 DshExecutor。

断线不会自动重派(避免同活执行两遍);超时转为 blocked,由人处理。

已落地的模块(项目自述)

README 写明:设备注册表、Selector、ForemanExecutor、Hub、回报规则、设备侧插件、文本渲染、迁移脚本、面板设备页、飞书群路由等已实现,测试 1332 项。设计、实现计划与交接见仓库内 docs/superpowers/ 与 HANDOFF.md。

与上游的关系

代码以 dsh-superagent-local 为起点,思想来自 DeepSeek Harness 团队的 Super-agent 原型与研究文档;本项目在多设备与迁移方向上做重写与扩展,并对文中未解问题(如 A2A、安全)采用明确取舍,而非声称已全部解决。

安装与启用

dsh-foreman 在 npm 上以包名 dsh-foreman 发布,并在 package.json 中声明 dsh.bundle(profile bundle)。安装前请确认本机 pnpm 在 PATH 中;社区插件以当前 DSH 进程权限运行,安装前建议自行审阅源码与许可证。

装入 web profile(常见本机 / 面板场景)

生态目录 dsh.works 给出的安装方式为:

dsh plugin --profile web add dsh-foreman

安装或更新 bundle 后需重启对应 profile 的 DSH Web。可用下列命令确认 bundle 层已生效(以你实际使用的 profile 名为准):

dsh --profile web --dump-config

输出中应能看到 dsh-foreman 相关 bundle 层。

独立主 loop 实例(服务器部署示例)

若要把主 loop 与原有 DSH 实例隔离(独立 DSH_HOME、profile、端口),仓库 runbook docs/deploy-loop-instance.md 建议在主 loop 所在 profile安装 foreman,不要在同一实例混装 node 包。示例:

export DSH_HOME=/home/ubuntu/.dsh-loop
dsh --profile loop --dump-config > /dev/null
dsh plugin --profile loop add "github:niechao136/dsh-foreman"

验收时,--dump-config 里应只有 dsh-foreman,不应出现 dsh-foreman-node:

dsh --profile loop --dump-config | grep foreman

设备侧

被派活的笔记本、宿舍电脑等应安装 dsh-foreman-node(npm 包名 dsh-foreman-node)。设备侧安装命令见 dsh-foreman-node 目录条目(示例:dsh plugin --profile web add dsh-foreman-node)。服务器主 loop 实例上只装 foreman,不装 node。

与本插件相关的配置项(独立实例 runbook)

将 examples/profile.cordis.patch.yml 复制到目标 profile 的 cordis.patch.yml 后,runbook 中与 foreman 直接相关的键包括:

- id: dsh-foreman
  config:
    stateDir: /home/ubuntu/.dsh-loop/state/superagent
    hubPort: 8790          # 设备连入的环回端口;0 表示不开 Hub,工单仅本机
    hubIdleMs: 600000      # 设备无心跳多久视为 blocked

hubPort 默认只监听 127.0.0.1;对外常配合隧道(如 cloudflared)使用稳定域名。迁机与更多部署细节见 docs/migration.md。

典型用法

1. 在主 loop 登记设备

runbook 推荐在 Web 面板「设置 › 设备」中登记 id、显示名、可接项目及该机器上的路径,获取 url、deviceId、token(令牌仅展示一次)。

headless 环境可用仓库脚本(路径以 runbook 为准):

cd /path/to/dsh-foreman
export DSH_HOME=/home/ubuntu/.dsh-loop
node scripts/add-device.mjs add --home "$DSH_HOME" --id laptop --name 公司笔记本 --label intranet --root shop='D:\工作\shop'

2. 在设备上配置 node 并连通 Hub

在设备 DSH 的「设置 › 插件 › dsh-foreman-node」中配置 SSH 隧道或 wss:// 枢纽地址,填入主 loop 下发的 deviceId 与 token,映射项目路径后保存并重启设备侧 DSH。主 loop 侧无需因登记而重启。

3. 接受工单时的行为预期

工单 accept 后,若目标设备离线或超时,状态为 blocked,不会自动改派或静默回落本机。确认设备未在执行后,再由人工重试。

4. 飞书群路由(可选)

整台服务器可配置一个飞书机器人,用群区分项目;Policy 中 routing.chats 可同时约束工作区与设备 labels,Selector 只选带匹配标签的设备,选不到则 blocked。示例结构见 runbook 中的 JSON 片段。

适用场景与注意

适合谁: 需要在多台机器上保留各自工作区与执行环境,又希望工单、策略、评估与主会话入口集中在一台(或一组)主 loop 上的 DSH 用户;需求主要来自本机操作者主会话,而非仅 GitHub/飞书触发(虽也支持飞书群路由等能力)。

注意事项:

  1. 项目处于早期开发,API 与部署方式可能变动;重大部署前阅读 HANDOFF.md 与设计文档。
  2. 同一 DSH 实例不宜同时装 foreman 与 foreman-node 作为主 loop 验收标准所描述的那样混用;多实例应使用不同 DSH_HOME。
  3. 插件与 node 均为第三方代码,安装即在本机执行;请核对 MIT 许可与仓库源码。
  4. SkillHub、dsh.works 等目录为社区站点,与 DeepSeek / 幻方无官方从属关系;星标在目录快照中可能为 0,不代表质量结论。

结尾

dsh-foreman 把「一个主 loop、一份账本、多台 Worker」落到可部署的 bundle:派单在 accept 时写入 target,远端不在线则明确 blocked,断线不重派。若你要从单机构型扩展到多设备协同,可从 npm 或 GitHub 安装 foreman,再按 runbook 配 Hub 与设备表。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜