前言¶
DeepSeek Harness(dsh)的上下文會滿。滿了之後常見的做法是「開個新會話」,於是上一輪聊定的東西、還沒做完的事、對方提過的細節全沒了。如果不清會話,每次都在越來越長的上下文裏燒錢;如果清了,萬一摘要失敗沒人發現,話就丟了。
這個插件把這件事變成一個有先後順序的流程,並且把順序當成硬規矩:先摘要,後清理。摘要不成功,一條都不許刪。
這是什麼¶
dsh-carryover 是一個給 DeepSeek Harness(dsh)用的會話交接插件。
一句話:開新會話之前先把上一段聊過的話寫成筆記;筆記真的落到盤上了才允許刪掉舊會話軌跡。
| 屬性 | 說明 |
|---|---|
| 作者 | JackZo400 |
| 類別 | 記憶 |
| 許可證 | MIT |
| 倉庫 | github.com/JackZo400/dsh-carryover |
安裝¶
使用以下命令安裝:
dsh plugin --profile web add github:JackZo400/dsh-carryover
安裝後需確認三件事:
1. sessionsRoot 指向正確的軌跡目錄(默認 ~/.dsh/sessions)。
2. summary.apiKey 有值(建議使用環境變量 DSH_CARRYOVER_API_KEY)。
3. 維護好映射文件(session-map.json),插件靠它知道誰該被交接。
配置¶
在插件配置中啓用並設置參數:
- insert:
- id: carryover
name: dsh-carryover
config:
enabled: true
sessionsRoot: ~/.dsh/sessions
transcript: auto # 自動挑選版本最大的軌跡文件
workspace: . # 筆記存儲目錄(默認 memory/carryover)
inject: true # 新會話自動帶上筆記
injectOrder: 40 # 注入順序
maxInjectChars: 4000
summary:
baseUrl: https://api.deepseek.com
apiKey: ''
model: deepseek-chat
maxTokens: 900
映射文件(session-map.json):
這是插件工作的核心契約,默認路徑爲 <workspace>/tmp/session-map.json。它定義了通道與會話 ID 的對應關係:
{
"group:demo": { "sessionId": "3f2a...c1", "carried": "1a9b...7e" },
"c2c:alice": { "sessionId": "88d0...4b" }
}
sessionId:當前通道的會話 ID。carried:已經交接過的會話 ID。- key 可以自定義,但必須用來給筆記文件命名。
工作原理¶
交接流程(開新會話前)¶
- 從映射文件中查出當前通道的上一個會話 ID。
- 打開軌跡目錄,解壓
session.v*.jsonl.zstd,剔除系統注入內容,只保留正文。 - 將正文餵給摘要模型,生成便條。
- 將便條追加寫入筆記文件,並讀回來覈對(會話 ID 和摘要內容是否都在)。
- 覈對通過 → 刪除舊軌跡目錄;覈對失敗 → 保留舊軌跡,記錄
KEEP日誌。
接上流程(新會話開始)¶
新會話組裝 system prompt 時,插件反查當前會話屬於哪條通道,將對應的筆記掛進上下文。全文保留在磁盤上,注入時只帶最近的一段。
用法¶
1. 宿主插件調用¶
在開新會話之前調用:
const carryover = ctx.get('carryover')
const r = await carryover.carryOver({ key: 'group:demo' })
if (r.status === 'kept') {
log('沒交接成,舊軌跡留着:', r.reason)
}
status 狀態包括:
- none:無可交接內容。
- done:交接成功,舊軌跡已刪。
- kept:交接失敗,舊軌跡未刪。
2. Agent 工具調用¶
Agent 可以直接調用三個工具:
- carryover_status:查看交接狀態和筆記位置。
- carryover_note:讀取筆記內容。
- carryover_run:執行交接。mode=peek 只預測結果,mode=dry 真摘要但不寫不刪。
3. 讀取筆記¶
其他插件或腳本讀取筆記:
const note = ctx.get('carryover').readNote('group:demo')
4. 獨立使用¶
插件不依賴 dsh 環境,可以在 Node.js 項目中獨立調用:
import { createCarryover } from 'dsh-carryover/carryover'
const engine = createCarryover({
workspace: '/srv/app',
sessionsRoot: '/srv/app/.dsh-sessions',
summarize: async (dialogue) => myOwnSummarizer(dialogue),
})
await engine.carryOver({ key: 'group:demo' })
注意與限制¶
- 依賴 zstd 命令行:軌跡解壓依賴
zstd,因爲node:zlib只能解壓第一幀。 - 不自己找會話:插件不自動猜測哪個會話是上一個,必須依賴映射文件維護。
- 不加密:筆記以明文 markdown 存儲在工作區,敏感內容需自行注意。
- 軌跡版本:軌跡文件名帶版本號(如
session.v4.jsonl.zstd),默認自動挑選最新版本,認不出文件時不會刪除。 - 護欄機制:路徑檢查嚴格,
sessionsRoot之外的路徑、包含..的路徑均不允許刪除,只記賬。