前言¶
在 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 再改模式」堵死了:
- 模式在第一次 turn 之後鎖死,
lastTurn不會回退。 - 分叉子會話用
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 中的順序(可單測):
agentPresets.resolve(目標模式)—— 模式無效則不留下半成品會話。sessionQuery.observeSession(源會話)—— 只讀租約讀頭部與完整事件日誌,源會話不被寫入。- 計算切點:默認最後一個完成回合末尾;
atSeq可選,須對應某次turn/end,否則退回默認並在響應裏說明實際切點。無完成回合則拒絕並提示先跑完一輪。 buildForkSeed(events, 切點)—— 複製前綴並打繼承標記(動態加載宿主實現,解析失敗時有本地兜底)。- 一次
ctx.agents.create:帶上seed、inheritedEventCount、meta(含parentSession、isSeeded、agentPreset)、沿用源會話模型的agentOptions,以及setup裏agentPresets.mount—— 以選中模式組裝後再發布,不是發佈後再換。 - 把新會話掛到源會話所在 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。
典型用法¶
-
會話已有多輪,整體換模式繼續
點標題欄模式膠囊 → 選擇目標預設 → 點底部「以「某某模式」新建會話」。新會話繼承到最後一個完成回合末尾,跳轉到新會話繼續。 -
從中間某一輪切開換模式
在該輪完成回覆下方的「分支模式」膠囊中點選目標模式,一次提交。列表會標「切點:第 N 輪末尾」;第 2 輪膠囊只會遷移到第 2 輪結束,之後內容不會跟過去。 -
新開任務前換預設
尚未跑 turn 時,標題欄底部爲「切換爲「某某模式」」,就地切換,不建新會話。 -
自檢模式是否一致
對可疑會話請求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 入口共用同一引擎與路由,適合工作流裏模式切換與歷史切點分支。