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 入口共用同一引擎與路由,適合工作流裏模式切換與歷史切點分支。

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

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

小夜