feat(role): PreCompact/PostCompact 保全壓縮邊界的上下文

補上最後一個記憶缺口:對話被壓縮時,尚未寫入記憶的內容會永久蒸發。
Stop hook 每輪記錄有部分覆蓋,但短回合會被 ROLE_CAPTURE_MIN_CHARS 門檻濾掉,
那些正是壓縮後再也補不回來的內容。

可行性查證(先確認再實作,不憑推測):
自 CLI binary 取出文件字串確認 harness 確實支援,並非猜測 ——
  | PreCompact  | "manual"/"auto" | Before compaction |
  | PostCompact | "manual"/"auto" | After compaction (receives summary) |
另有 executePreCompactHooks/executePostCompactHooks 等實作符號,
以及 compactSummary/isCompactSummary 欄位名線索。

role_capture.sh:
- 新增 --precompact:壓縮前強制記錄一次,**刻意跳過長度門檻**(門檻的用意是省額度,
  但壓縮後內容永久消失,此時寧可多記)
- 新增 --postcompact:把 harness 產生的摘要存成 daily 記憶,不再呼叫模型,
  等於免費取得一份濃縮備份;寫入前一律經 redact 遮蔽
- 摘要欄位容錯讀取 compactSummary/compact_summary/summary/compaction_summary;
  **取不到時在 log 印出 hook 實際提供的欄位名**,避免 harness 改版後靜默失效
- 一併取用 trigger 欄位以分辨 manual/auto(自動壓縮才是使用者不知情的那種)
- stop_hook_active 的迴圈防護只套用於一般每輪模式

hooks/hooks.json 註冊兩個新事件,指令沿用既有的「先試 CLAUDE_PLUGIN_ROOT →
再依擁有者 marketplace → 全 cache 後援」解析方式,並帶上對應參數。
兩個 hook 一律 exit 0,絕不阻擋壓縮 —— harness 具備 blocked by PreCompact hook
的能力,記憶系統不該用到它。

驗證:一般模式短對話仍被門檻正確濾掉;--precompact 對同一段短對話強制記錄;
--postcompact 正確寫入摘要記憶;欄位名不符時印出實際欄位(session_id,transcript_path,
cwd,trigger,unknownField)而非靜默結束;四條 hook 指令語法正確,且在
CLAUDE_PLUGIN_ROOT 與純後援搜尋兩種情境下都解析到正確腳本與參數。

版號沿用 0.0.5(master 為 0.0.4,同一 PR 不再累加)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jeffery
2026-07-29 12:01:56 +08:00
co-authored by Claude Opus 5
parent a30fccc627
commit a757f9e4b0
3 changed files with 87 additions and 3 deletions
+9
View File
@@ -12,6 +12,8 @@ description: 角色人格與長期記憶系統的建立與維護 skill。讓 CLI
| --- | --- | --- |
| `hooks/hooks.json``SessionStart` hook | harness 自動 | 啟動 CLI 時依字元預算載入角色定義+高價值記憶,另以獨立預算載入近期逐字對話與未整理工作記憶做工作階段交接,並要求角色在本工作階段第一則回覆主動問候;睡眠時段只回報「角色睡覺中」不載入 |
| `hooks/hooks.json``Stop` hook | harness 自動 | 每輪結束先記錄最後互動時間 → 用本地規則過濾低價值短回合 → 值得保存時才濃縮成一則輕量 inbox 記憶 → 遮蔽 → 寫入 `inbox/` |
| `hooks/hooks.json``PreCompact` hook | harness 自動 | 對話壓縮**前**強制記錄一次(**跳過長度門檻**):壓縮會讓尚未寫入的內容永久蒸發,此時寧可多記 |
| `hooks/hooks.json``PostCompact` hook | harness 自動 | 壓縮**後**把 harness 產生的摘要存成一則 `daily` 記憶,作為該段落的濃縮備份 |
| cron 排程(本 skill 安裝) | 系統排程 | 睡眠時段每小時檢查一次:**有 AI 在運行就不睡**;另可依 CLI 閒置時間自動小睡整理 |
| 本 skill `/jsc-generic:role` | 使用者/助理手動 | `--new``--use``--list``--export``--agent``--migrate``--sleep``--brief``--status``--install-cron``--forget-preview` |
| `scripts/role/role_load.sh` | SessionStart hook | 角色與記憶載入;參考 OpenClaw 的 SOULAGENTSUSERMEMORY 分層,把人格、操作邊界、使用者記憶分開注入,並提供第一則回覆問候提示(單一實作,避免漂移) |
@@ -279,6 +281,8 @@ chmod +x ~/.roles/<角色 ID>.checks/check-gitea-prs.sh
| --- | --- |
| SessionStart | 預設 `ROLE_LOAD_LIMIT=4000`,只載入高優先度全文與中高優先度摘要;低 priority、無 links、久未更新的記憶不進 context。另以兩份**獨立預算**載入交接內容:近期逐字對話(`ROLE_LOAD_DIALOG_LIMIT=4000`)與近期工作記憶摘要(`ROLE_LOAD_INBOX_LIMIT=1200`),見下方「工作階段交接」 |
| SessionStop | 先用本地規則略過短回合與無記憶線索的對話,只有值得保存才呼叫模型做輕量編碼 |
| PreCompact | 壓縮前強制記錄一次,不受 `ROLE_CAPTURE_MIN_CHARS` 限制 —— 這是刻意的例外,因為壓縮後就再也補不回來 |
| PostCompact | 直接沿用 harness 已產生的摘要,**不再呼叫模型**,等於免費取得一份濃縮備份 |
| Sleep | 高成本的去重、合併、抽象化、links 建立與長期記憶型態標記留到睡眠週期,但仍受 `ROLE_SLEEP_COLLECT_LIMIT`、`ROLE_SLEEP_BATCH`、`ROLE_SLEEP_EXISTING_LIMIT` 與 `ROLE_SLEEP_OUTPUT_LIMIT` 控制;沒有 inbox 時只做本地遺忘檢查 |
| Nap | Stop hook 記錄最後互動時間;小睡排程只在閒置時間與 inbox 筆數達門檻時執行,使用同一套 NREM/REM 整理流程 |
| 手動節流 | 可設 `ROLE_CAPTURE_ENABLED=0` 關閉 Stop 記錄,或調低 `ROLE_LOAD_LIMIT`/調高 `ROLE_LOAD_FULL_MIN_PRIORITY` |
@@ -556,6 +560,11 @@ updated: <yyyy/MM/dd HH:mm:ss>
範圍與限制要說清楚:這是**最近數輪**的交接,不是完整歷史;需要完整對話上下文時仍應使用 `resume`。修改此處前請先確認缺口已由其他機制補上,否則不要移除。
- 未整理記憶(`inbox/`)累積到一批睡眠整理量(預設 `ROLE_SLEEP_BATCH=60`)以上時,角色應主動以符合自身設定的語氣提醒「想睡覺」或需要整理記憶;這是建議整理/歸檔的提醒,不代表停止協助使用者。
- **壓縮邊界的上下文保全**:對話被壓縮時,尚未寫入記憶的內容會永久消失。`PreCompact` 於壓縮前強制記錄一次並**跳過長度門檻**(平常短回合會被濾掉,但此時寧可多記);`PostCompact` 把 harness 產生的摘要存成 `daily` 記憶。
摘要欄位以容錯方式讀取(`compactSummary``compact_summary``summary``compaction_summary`)。**取不到時會在 log 印出 hook 實際提供的欄位名**,避免 harness 改版後靜默失效。`trigger` 欄位可分辨 `manual``auto`,自動壓縮才是使用者不知情的那種。
**這兩個 hook 一律 `exit 0`,絕不阻擋壓縮** —— harness 具備「compaction blocked by PreCompact hook」的能力,記憶系統不該用到它。
- **臨時授權會過期(安全機制)**:內容屬於臨時授權、一次性許可、例外放行、暫時解除限制或帶條件的同意時,`expires` 必填。可寫日期(系統自動判斷,過期後**不再注入**,遺忘時優先淘汰且不受分類限制)或條件文字(例如「本工作階段」、「PR 合併後失效」,載入時標示有效範圍由角色自行判斷)。
為什麼需要:一次性許可若被整理成長期規則,日後會造成越權操作。使用者說「這次」、「先」、「暫時」、「今天」、「這個 PR」時幾乎都屬於臨時授權。