dsh-agent-preset-branch:在已完成轮次上按新模式分支会话

前言

在 DeepSeek Harness(DSH)里,Agent 预设决定工具层与提示词段落如何组装。会话一旦跑过至少一轮,宿主会把模式锁死:agent-preset-registry 的 select() 在 openTurnStartSeq !== null || lastTurn > 0 时会抛 agent-preset/locked。产品自带的分叉(fork)也只能继承父会话的模式——SessionForkRequest 只有 { sessionId, atSeq },没有 agentPreset 字段。

实际开发里常见需求是:同一段对话已经跑了几轮,想换到「规划」「审查」等另一套 Agent 预设继续,而不是在旧模式里硬聊。下面介绍社区插件 dsh-agent-preset-branch(维护者 lanhui1942),它用「新建会话 + 迁移事件日志前缀」补齐「换模式 + 保留上下文」这一缺口,而不是做 fork。

这是什么

dsh-agent-preset-branch 是 DSH 工作流类插件(GitHub:lanhui1942/dsh-agent-preset-branch,当前 package 版本 1.1.0,MIT 许可证)。一句话:从任意已完成轮次把会话分支到一个新模式——选一个 Agent 预设,就以该模式新建会话,并把当前会话到所选轮次末尾为止的对话迁移过去;迁移复制的是事件日志(不是摘要),不修改源会话。

与前身 dsh-agent-preset-select 的差异在于:对已开始的任务,前者只会以该模式新建空会话,本插件会新建并带上已有对话;未开始的任务两者都是就地切换模式。

为什么不能只靠分叉或事后改模式

DSH 的两条结构约束把「先 fork 再改模式」堵死了:

  1. 模式在第一次 turn 之后锁死,lastTurn 不会回退。
  2. 分叉子会话用 presetForObservation(source) 组装,必然继承父模式;即便先分叉再切模式,仍会被第 1 条拒绝。

因此模式必须在会话组装同一刻定好,内容以 seed 形式交给那次 session.create。宿主已有 session.create({ agentPreset }),缺的是把对话灌进去——本插件把两步合成一次调用。

核心功能

两个入口,同一套引擎

入口 挂载位置 交互
标题栏模式菜单 conversation.session.header.actions 的 agent-preset 格子 先选模式,再点卡片底部提交;未开始会话为就地切换
回合底「分支模式」胶囊 conversation.chat.assistant-actions 的 branch-mode,紧挨产品自带分支按钮 展开列模式,点某个模式即建立分支会话,无第二步
  • 未跑过任何一轮:标题栏底部为「切换为「某某模式」」,走注册表官方 switch 路径。
  • 至少完成一轮:标题栏为「以「某某模式」新建会话」;回合底每轮完成的助手消息行各有胶囊,切点为该轮的 turn/end(atSeq),历史轮与最后一轮共用同一路由,只是切点不同。
  • 本插件不做 fork;与产品自带分支按钮并列,不替换复制、反馈等已有格子。

宿主端迁移顺序(概要)

core.js 中的顺序(可单测):

  1. agentPresets.resolve(目标模式) —— 模式无效则不留下半成品会话。
  2. sessionQuery.observeSession(源会话) —— 只读租约读头部与完整事件日志,源会话不被写入。
  3. 计算切点:默认最后一个完成回合末尾;atSeq 可选,须对应某次 turn/end,否则退回默认并在响应里说明实际切点。无完成回合则拒绝并提示先跑完一轮。
  4. buildForkSeed(events, 切点) —— 复制前缀并打继承标记(动态加载宿主实现,解析失败时有本地兜底)。
  5. 一次 ctx.agents.create:带上 seed、inheritedEventCount、meta(含 parentSession、isSeeded、agentPreset)、沿用源会话模型的 agentOptions,以及 setup 里 agentPresets.mount —— 以选中模式组装后再发布,不是发布后再换。
  6. 把新会话挂到源会话所在 Workspace(subagent 沿血缘上溯),并尝试沿用原标题。

HTTP 路由

路由名 branch 历史沿用,行为是「新建并迁移」:

GET  /dsh-agent-preset-branch/list      可选模式名册 + 默认模式
GET  /dsh-agent-preset-branch/inspect   ?sessionId=…  记录模式 vs 实际组合模式
POST /dsh-agent-preset-branch/branch    { sessionId, agentPreset, title?, atSeq? }
POST /dsh-agent-preset-branch/switch    { sessionId, agentPreset }  (仅未开始会话)

inspect 用于排查「新建了但模式看起来没换」:recordedPreset 与 composedPreset 对照。

安装与启用

插件随 DSH 以 profile 方式加载;装完 需重启 DSH(浏览器端 bundle 可热更新,host.js / core.js 不会)。安装前请自行阅读仓库源码与 MIT 许可证;插件在当前 dsh 进程权限下运行。

三种安装方式(任选其一):

1. 从 tarball(推荐对外分发):

dsh plugin --profile <profile> add <dsh-agent-preset-branch-1.1.0.tgz 的绝对路径>

也可在「设置 → 插件」安装框粘贴同一 .tgz 路径。

2. 指向插件目录:

dsh plugin --profile <profile> add <本目录绝对路径>

3. 手工 link 依赖: 在 profile 的 package.json 中:

"dsh-agent-preset-branch": "link:<本目录绝对路径>"

并加入 dsh.profile.bundles,然后重启 DSH。须用 link: 而非版本号,否则 pnpm 会去 registry 找包。

打包:

npm pack

生成 dsh-agent-preset-branch-<version>.tgz;package.json 的 files 已列运行所需的 6 个文件,无构建步骤、无 npm dependencies。

典型用法

  1. 会话已有多轮,整体换模式继续
    点标题栏模式胶囊 → 选择目标预设 → 点底部「以「某某模式」新建会话」。新会话继承到最后一个完成回合末尾,跳转到新会话继续。

  2. 从中间某一轮切开换模式
    在该轮完成回复下方的「分支模式」胶囊中点选目标模式,一次提交。列表会标「切点:第 N 轮末尾」;第 2 轮胶囊只会迁移到第 2 轮结束,之后内容不会跟过去。

  3. 新开任务前换预设
    尚未跑 turn 时,标题栏底部为「切换为「某某模式」」,就地切换,不建新会话。

  4. 自检模式是否一致
    对可疑会话请求 GET /dsh-agent-preset-branch/inspect?sessionId=…,查看 agrees 与两侧 preset 字段。

适用场景与注意

适合: 需要在同一 Workspace 里保留对话上下文,但换用不同 Agent 预设(不同工具与提示词段落)继续;需要从历史轮次精确切开做 A/B 式模式对比。

务必知晓:

  • 切点只认完成回合的 turn/end;半轮或无效 atSeq 会退回默认切点,不会整单失败也不会切在半轮里。
  • 切在历史轮时,该轮之后、下一轮之前的独立记账类事件不会迁移。
  • 标题栏 agent-preset 格子按 priority 竞争;与 dsh-agent-preset-select 等同槽插件只会显示一个,装本插件时应从 profile 依赖与 dsh.profile.bundles 移除前身。
  • 社区目录 SkillHub 插件页 与 GitHub 仓库由维护者发布,与 DeepSeek / 幻方无官方从属关系;DSH 生态理念是「一切皆插件」,目录站为独立社区索引。

结尾

dsh-agent-preset-branch 把「换 Agent 预设」和「保留到某一轮的对话」绑成一次「新建 + seed 迁移」,绕过 DSH 对 fork 与事后改模式的限制。两处 UI 入口共用同一引擎与路由,适合工作流里模式切换与历史切点分支。

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

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

小夜