dsh-preset-reload:不重启 dsh 热重载 agent preset

前言

在 DeepSeek Harness(DSH)里改 agent preset——插件代码、人格卡或定义文件——新开的会话通常会拿到新 revision,但已经在跑的会话仍绑在旧 revision 上。注册表里的 bindings 是 WeakMap,无法遍历重绑;mount() 会复用已有 revision,bind() 遇到同一 revision 会直接返回。结果是:改一行文案往往要重启进程,长期在线的机器人会整批掉上下文。

dsh-preset-reload(维护者 CK-Rebi)补的是「定义更新后,把活着的 Agent 搬到新 revision」这一步:重建预设 revision,并重绑运行中的会话,sessionId 与上下文保留,无需重启 dsh。

这是什么

  • 名称:dsh-preset-reload(npm 包名同仓库名)
  • 分类:工作流(社区目录 SkillHub 插件页)
  • 一句话:Hot-reload a DeepSeek Harness agent preset: rebuild its revision and rebind running sessions, without restarting dsh.
  • 源码与文档:GitHub - CK-Rebi/dsh-preset-reload,MIT 许可;当前 package 版本 1.0.1,要求 Node >=20。

它怎么工作

定义文件(例如你构建生成的 cordis.patch.yml)变化后,插件在可配置的防抖窗口内大致做两件事:

  1. (可选但默认开启) 对目标预设行执行 disable → enable,让 Service.init 重跑、register() 产生新 revision——仅改 config 不保证重新注册,这是 DSH 当前机制下的确定触发点。
  2. 调用 recompose(agent.ctx, presetId),把仍活着的同预设 Agent 迁到新 revision。

机制细节与源码说明见仓库内 docs/why-force.md。

核心功能

  • 文件监听 + 防抖:监听 roots 下的文件或目录,默认 debounceMs 800ms 合并连续事件。
  • 自动或手动:auto: true 时保存定义文件即可触发;也可在任意会话调用工具 preset_reload。
  • 强制重挂(force):默认 true,用 disable→enable 确保新 revision;force=false 为轻量 reconcile,可能推不动旧绑定。
  • 审计日志:可选 logFile 记录触发来源、revision 是否更新、重绑了哪些会话。
  • 失败隔离:预设挂载失败记入 record.broken,不会让 profile 启动失败;活会话继续旧 revision,损坏定义不会被 recompose 接受。

验证记录(README):在 DSH 0.2.0-rc.2 上,经 recompose 后工具表从陈旧绑定切换到新定义;?v= 哈希变化在重绑后加载新模块;真实 dsh web 未重启下改定义文件可自动重挂并重绑。

安装与启用

插件以当前 dsh 进程权限运行,安装前请自行查看仓库源码与 MIT 许可证。

方式一:作为 bundle 安装

dsh plugin --profile web add github:CK-Rebi/dsh-preset-reload

装好后在 profile 的 patch 里配置(示例):

- id: preset-reload
  config:
    presets:
      - your-preset-id
    roots:
      - '/path/to/your/bundle/cordis.patch.yml'

方式二:手动加一行(不装包)

在 ~/.dsh/profiles/<profile>/cordis.patch.yml 用绝对 file:// 指向仓库 index.mjs:

- insert:
    - id: preset-reload
      name: 'file:///path/to/dsh-preset-reload/index.mjs'
      config:
        presets:
          - your-preset-id
        roots:
          - '/path/to/your/bundle/cordis.patch.yml'
        force: true

insert 必须落在宿主层(profile 的 patch),不要放进预设内部,否则每次重挂会把自己换掉。

配置项

字段 类型 默认 说明
presets string[] [] 需要重载的预设 id 列表
roots string[] [] 监听路径,文件或目录均可
debounceMs number 800 合并文件事件的静默窗口(毫秒)
auto boolean true 为 false 时仅 preset_reload 工具可触发
force boolean true 是否 disable→enable 强制新 revision
logFile string '' 审计日志路径;空串不写文件

建议 roots 只写定义文件,不要写整个目录,否则无关模块保存也会触发整树重挂。

典型用法

自动重载

构建脚本重新生成定义文件即可,例如:

node scripts/build-preset.mjs

防抖结束后插件完成重挂与重绑。若构建会重算模块 URL 的 ?v= 内容哈希,请直接运行脚本;README 提到某些环境下把构建接管道可能导致脚本静默不写文件。

手动重载

在会话中调用工具:

preset_reload                        # 使用配置里的 presets
preset_reload presetId=your-preset
preset_reload force=false            # 轻量试探,可能推不动

返回示例含义:forced(是否强制路径)、changed(revision 是否更换)、moved(重绑的会话);重绑不依赖 changed 门控。

适用场景与注意

适合:长期运行的 DSH 机器人、频繁改 preset 插件或人格卡、希望开发时少重启、多会话在线的场景。

范围:只处理预设层插件的热重载;宿主层插件包的装卸/升级不在本插件范围内(可与 dsh-hot-installer 共存)。

已知限制(来自 README):

  • 强制重挂会重建预设的 Cordis 子树,进行中的 turn 可能看到工具表瞬时切换;宜在空闲时改或接受切换。
  • force 的 disable→enable 之间有毫秒级窗口,此时新建会话可能找不到该预设。
  • 模块按 URL(含查询串)缓存;改模块却不更新定义里的哈希时,仍可能加载旧代码。
  • peer 依赖 @deepseek-ai/dsh-app-boot 等多段版本区间,需与当前 DSH 版本匹配。

DSH 生态强调「一切皆插件」;社区目录 SkillHub 为独立站点,与 DeepSeek / 幻方无官方从属关系。

结尾

dsh-preset-reload 针对「新会话用新代码、老会话粘旧 revision」这一缺口,用监听定义文件、可选强制重注册与 recompose 重绑,在不动 sessionId 的前提下让 preset 改动落到在线会话。需要安装与配置细节时,可看 SkillHub 目录页 与 GitHub 仓库 README。

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

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

Xiaoye