前言¶
在智能體對話裏,歷史隨着輪次增長,遲早需要壓縮。DeepSeek Harness 內置了 /compact,但這個命令在慢鏈路或上游不穩定時有兩個實際問題:agent 忙時它直接拒絕,你這次想壓縮的請求就丟了;它執行期間 composer 處於鎖定狀態,如果 summarizer 卡住不流式返回,你沒有按鈕可按、也沒有地方可輸入。
下面介紹的插件就是對着這兩個問題做的:imrcpan/dsh-compact-enhanced,維護者 imrcpan,分類「工作流」。它把 /compact 請求改成立即返回、在 agent 忙時排隊、後臺執行的方式,並提供 /compact-cancel 取消,同時在斜槓菜單裏用一行狀態提示告訴你現在發生了什麼。
這是什麼¶
一個 DSH(DeepSeek Harness)插件,DSH 本身的理念是「一切皆插件」,能力通過插件拼裝。這插件針對的是「手動觸發上下文壓縮」這一段工作流,不改動模型、不改動提示詞,只改命令的調度與可觀測性。
解決的問題:
- 內置
/compact在 agent 非空閒時拒絕請求,請求會丟失在正在運行的 turn 中間。 - 內置
/compact執行期間命令行 composer 不可用,卡住時無法中斷。 - 完成後沒有方便的方式告訴用戶「到底壓了多少、壓縮是否成功」。
命令與行爲¶
插件提供兩個命令,都不接受參數:
| 命令 | 行爲 |
|---|---|
/compact |
agent 空閒時立即開始;否則排隊,等到當前 turn 結束再開始 |
/compact-cancel |
丟棄排隊中的請求、中止正在運行的 summarizer 請求,或取消由其它命令模塊啓動的壓縮 |
兩個命令都不接受參數。當已有請求在排隊或運行中時,/compact 會拒絕第二個請求,並在報錯中指出用哪個命令取消。
取消這一行什麼時候落定,取決於 abort 是否到達 summarizer:
Compaction cancelled.—— 運行已結束。Cancellation requested; the summarizer has not stopped yet.—— 在cancelTimeoutMs內 summarizer 沒有響應 abort,請求仍在。
會話面板裏看到什麼¶
請求自己的生命週期行會立刻出現:
Compaction started in the background.
Compaction queued; it starts when the current turn ends.
因爲插件把請求命令的 id 作爲 sourceCommandId 傳給壓縮引擎,壓縮事件會掛到這一行上,摘要落地後這一行會升級成標準的壓縮卡片。嘗試結束後,插件會爲同一個 id 再補一條 command/done,記錄結果:
Compacted 42 history items (~12,345 tokens).
No compactable history yet.
Compaction cancelled.
以及 busy、changed、summary、commit、persistence 這幾類已文檔化的失敗文案。
那條額外的 command/done 是刻意加的:命令服務在 handler 返回後就會關閉請求(這正是 composer 能解鎖的原因),所以想在原來那一行上報後臺結果,只能爲同一個 id 再走一次生命週期事件,客戶端會把它摺疊到已有行裏。
斜槓菜單裏的實時狀態¶
/compact 在斜槓菜單裏不是一句固定文案,而是一行狀態,會隨狀態變化,並在有時附加當前會話的 token 估算:
| 狀態 | 菜單行文本 |
|---|---|
| 空閒 | Ready · 12.3k token |
| 在等當前 turn 結束 | Queued · 12.3k token |
| summarizer 正在運行 | Compacting · 12.3k token |
| 拿不到 token 估算 | Ready / Queued / Compacting,不帶 token 部分 |
token 標籤用一位小數加固定 k 單位(Claude Code 風格):3.9k token、12.0k token、0.9k token。估算爲零或拿不到 token 計量時整段省略,所以不會看到 0.0k token。
/compact-cancel 那一行同步狀態:Cancel the queued compaction、Cancel the running compaction,或 No queued or running compaction to cancel。
實現上,插件在命令目錄這一層替換了 commands.list() 裏的 compact 描述符,並去掉內置定義 id,避免客戶端把描述重新本地化回通用文案;狀態每次變化時重新發布 commands/change,下一次打開菜單會重新拉取。代價是菜單行顯示的是原始命令名,丟掉了內置的本地化標籤和圖標——這是爲換取實時狀態做的取捨。
安裝與啓用¶
包本身是一個 DSH bundle:package.json 聲明瞭 dsh.bundle.patch,所以標準安裝會同時掛載命令。
dsh plugin --profile web add github:imrcpan/dsh-compact-enhanced
裝完要重啓 profile,因爲組合關係是在啓動時讀取的。隨包發佈的 cordis.patch.yml 會禁用內置的 command-compact 行並插入插件行,這就騰出了 /compact 這個名字。
從本地 checkout 安裝時,要作爲 bundle 來裝,好讓它的 manifest 生效:
dsh plugin --profile web add /absolute/path/to/dsh-compact-enhanced
file: 依賴也可以被接受,但那樣不會應用 bundle 層,需要手工把 example/cordis.patch.yml 裏的那一行抄進 profile 的 cordis.patch.yml。
典型用法¶
在對話裏直接使用即可:
# 觸發一次壓縮,立即返回
/compact
# 如果排隊中或正在運行,想取消
/compact-cancel
運行環境要求:
- DeepSeek Harness
0.2.1-rc.5(其它 release 可能不同;package.json裏engines寫的是dsh >=0.2.1-rc.2) - Node.js
>=20.3,插件用到了AbortSignal.any
配置項¶
配置是可選的,bundle 層不提供任何配置。
| key | 默認值 | 含義 |
|---|---|---|
retryDelayMs |
250 |
一次啓動與剛好新開的 turn 撞車後,等多久重試 |
maxQueueAttempts |
40 |
重試多少次後把排隊失敗寫進行裏 |
cancelTimeoutMs |
2000 |
取消命令等待被 abort 的運行落定的時長,超時後報告請求仍在 |
實現上的幾點¶
- 命令註冊表不允許同一名重複全局註冊,因此 bundle 層禁用內置
command-compact行,插件用自己的/compact註冊到這個名字。如果 profile 仍然掛載了內置行,插件會捕獲重複註冊並打 warning,保留/compact-cancel,把內置命令留在原處。 - 壓縮入口沒有辦法從 profile 根訪問到:agent preset 把它掛在隔離的 per-agent 組裏,實際
agent.ctx也不暴露它。插件因此用commands.find解析 agent 能用的那個compact定義(通常是 preset 掛載的那個,其 handler 閉包持有隔離服務),該 handler 以插件自己的AbortSignal在後臺運行。找不到其它定義時就退回自己 context 可達的引擎;兩者都不可達時,命令會報告壓縮不可用,而不是靜默地什麼都不做。 - agent preset 自己註冊了 scoped
/compact,會遮蔽全局替換。插件在命令服務這一層處理/compact這一行,所以排隊邏輯作用在目錄解析出的那個定義上;插件卸載時會還原原來的execute方法。 - 取消就是 abort 插件交給被委託 handler(或直接交給引擎)的 signal,因此能作用到 summarizer 請求。
- 一次啓動如果與新開的 turn 搶跑,會在
retryDelayMs後重試,最多maxQueueAttempts次,之後才寫失敗。排隊狀態按 agent 劃分且只在內存裏。 - agent 忙時什麼都不跑:隊列等 agent 空閒,然後在 maintenance 裏啓動,位置正是內置命令本來會跑的地方。
適用場景與注意¶
適合:在慢鏈路或上游不穩定的環境下工作的 DSH 智能體開發者;需要手動壓縮歷史、並且希望壓縮期間不阻塞對話輸入的人;希望取消操作不必等 summarizer 自然結束的人。
需要注意:
- 這個插件以當前 dsh 進程的權限運行,能力邊界就是 profile 裏已有的命令與服務,安裝前應檢查源碼與許可證(MIT)。
- 沒有客戶端按鈕。取消只能靠
/compact-cancel,有效是因爲/compact在 summarizer 啓動前就返回了。 - 隊列在內存裏。host 重啓會結束 turn 並丟掉排隊請求,之後要重新
/compact。 - 自動壓力壓縮沒有被改動,只包裝了手動命令。排隊的請求即使自動壓縮已經做過一輪,仍會執行一次壓縮,因爲插件不知道下一次空閒檢查會發現什麼。
- 取消報告是即時的,但最終這一行要等後臺結果落定。
結尾¶
這個插件的價值很清楚:/compact 從「一次會被拒、無法中斷、結果不可見的請求」變成「立即返回、可排隊、可取消、狀態可見的後臺任務」。代碼量不大,排隊與取消狀態按 agent 保存在內存中,配置只有三個數值項。如果你的使用場景是長會話加不穩定上游,值得一試。
目錄頁:https://www.skillhub.cn/plugins/imrcpan/dsh-compact-enhanced
倉庫:https://github.com/imrcpan/dsh-compact-enhanced