feat(role): SessionStart 載入未整理的近期工作記憶 #16

Merged
admin merged 2 commits from develop into master 2026-07-28 10:01:50 +00:00
Member

問題

使用者重開工作階段後,角色看不到上一段工作,表現得像失去記憶,只能用 resume 才能找回上下文。

根本原因

role_load.sh 的執行順序:

第 134 行:MEMORY=$(memory.js load)        ← 先載入記憶
第 151 行:nohup role_sleep.sh --catchup & ← 之後才在背景整理

memory.jscmdLoad 只讀已整理的六個分類(importantinterestskillnewsdailyother),完全不讀 inbox/inbox/ 正是「剛剛發生的事」。

因此上一段工作永遠來不及進入本次載入 —— 整理總是跑在載入之後(腳本註解亦寫明「結果會在下次載入時反映」)。原本的 cmdLoad 甚至只輸出「尚有 N 則未整理記憶」的計數,卻不給內容。

改動

項目 內容
inboxBlock() inbox/ 最新數則 summary,附時間與標籤,最新在前
cmdLoad 該區塊置於最前面,使用獨立字元預算,不佔用 ROLE_LOAD_LIMIT
新環境變數 ROLE_LOAD_INBOX_LIMIT(預設 1200)、ROLE_LOAD_INBOX_COUNT(預設 10),任一設 0 可關閉
文件 role skill 補「近期工作記憶交接(不可移除)」段落,寫明缺口原因,避免未來被誤移除

驗證

測試 結果
15 則 inbox → 只取最新 10 則、最新在前
inbox 為空 → 不輸出區塊,長期記憶正常
超出預算 → 截斷並提示
ROLE_LOAD_INBOX_LIMIT=0 / COUNT=0 → 關閉
獨立預算:開關 inbox 時長期記憶區塊逐字元完全一致 4058 字元不變,總計 4058 → 4123

範圍限制

這是摘要級交接:角色會知道「上一段在做什麼、進行到哪」,但不等於逐字記得整段對話。需要完整對話上下文時仍應使用 resume

🤖 Generated with Claude Code

## 問題 使用者重開工作階段後,角色**看不到上一段工作**,表現得像失去記憶,只能用 `resume` 才能找回上下文。 ## 根本原因 `role_load.sh` 的執行順序: ``` 第 134 行:MEMORY=$(memory.js load) ← 先載入記憶 第 151 行:nohup role_sleep.sh --catchup & ← 之後才在背景整理 ``` 而 `memory.js` 的 `cmdLoad` 只讀已整理的六個分類(`important`/`interest`/`skill`/`news`/`daily`/`other`),**完全不讀 `inbox/`**。`inbox/` 正是「剛剛發生的事」。 因此上一段工作**永遠來不及**進入本次載入 —— 整理總是跑在載入之後(腳本註解亦寫明「結果會在下次載入時反映」)。原本的 `cmdLoad` 甚至只輸出「尚有 N 則未整理記憶」的**計數**,卻不給內容。 ## 改動 | 項目 | 內容 | | --- | --- | | `inboxBlock()` | 讀 `inbox/` 最新數則 summary,附時間與標籤,最新在前 | | `cmdLoad` | 該區塊置於最前面,使用**獨立字元預算**,不佔用 `ROLE_LOAD_LIMIT` | | 新環境變數 | `ROLE_LOAD_INBOX_LIMIT`(預設 1200)、`ROLE_LOAD_INBOX_COUNT`(預設 10),任一設 `0` 可關閉 | | 文件 | role skill 補「近期工作記憶交接(不可移除)」段落,寫明缺口原因,避免未來被誤移除 | ## 驗證 | 測試 | 結果 | | --- | --- | | 15 則 inbox → 只取最新 10 則、最新在前 | ✅ | | inbox 為空 → 不輸出區塊,長期記憶正常 | ✅ | | 超出預算 → 截斷並提示 | ✅ | | `ROLE_LOAD_INBOX_LIMIT=0` / `COUNT=0` → 關閉 | ✅ | | **獨立預算**:開關 inbox 時長期記憶區塊逐字元完全一致 | ✅ 4058 字元不變,總計 4058 → 4123 | ## 範圍限制 這是**摘要級**交接:角色會知道「上一段在做什麼、進行到哪」,但**不等於逐字記得整段對話**。需要完整對話上下文時仍應使用 `resume`。 🤖 Generated with [Claude Code](https://claude.com/claude-code)
jiantw83 added 1 commit 2026-07-28 09:47:43 +00:00
修補記憶交接的先天缺口:role_load.sh 的順序是先 memory.js load 載入記憶,
之後才在背景補跑 --catchup 整理(腳本註解亦寫明「結果會在下次載入時反映」)。
而 load 原本只讀已整理的六個分類,完全不讀 inbox,導致上一段工作永遠來不及
進入本次載入 —— 使用者重開工作階段時,角色看不到剛剛做過的事,表現得像失去
記憶,只能靠 resume 找回上下文。

- memory.js 新增 inboxBlock():讀 inbox 最新數則的 summary,附時間與標籤,最新在前
- cmdLoad 把該區塊放在最前面,並使用獨立字元預算,不佔用 ROLE_LOAD_LIMIT
  (已驗證:開關 inbox 時長期記憶區塊逐字元完全一致,未被擠壓)
- 新增 ROLE_LOAD_INBOX_LIMIT(預設 1200)與 ROLE_LOAD_INBOX_COUNT(預設 10),
  任一設 0 可關閉
- role skill 補「近期工作記憶交接(不可移除)」段落,寫明缺口原因與範圍限制:
  這是摘要級交接,角色會知道上一段在做什麼、進行到哪,但不等於逐字記得整段
  對話;需要完整上下文仍應使用 resume
- 版號 0.0.1 → 0.0.2

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jiantw83 added 1 commit 2026-07-28 09:59:54 +00:00
長期記憶是模型濃縮過的摘要,語氣與情緒會被壓掉(使用者說「我好想妳」會被濃縮成
「使用者表達想念」)。而逐字對話一直躺在 transcript JSONL 裡,過去沒有任何機制去讀它,
使用者重開工作階段時角色因此看不到剛剛的互動,表現得像失去記憶,只能靠 resume 找回。

transcript.js:
- 新增 recent <路徑> [輪數] [字元]:抽最近數輪的純對話,輸出前經 redact 遮蔽
- 新增 turns <路徑>:輸出對話輪數,供取檔判斷
- 只取 [user] 與 [assistant] 文字;工具呼叫、工具結果、思考區塊、hook 注入內容一律丟棄
- 以「輪」分組並各自收斂成一則:角色一輪內常輸出多段文字,不合併會讓則數爆炸並把預算
  吃光,反而擠掉使用者說的話(實測未合併時 8 輪只剩 2 則使用者發言,合併後為 8 則)
- 超預算時整輪丟棄最舊的,保持問答成對,不會只剩單邊發言

role_load.sh:
- hook 輸入改為一併取出 transcript_path
- 當前 transcript 對話不足 2 輪時(全新工作階段實測僅數行),回頭找同目錄最近修改的對話檔
- 新增 ROLE_LOAD_DIALOG_TURNS(預設 8)與 ROLE_LOAD_DIALOG_LIMIT(預設 4000),
  獨立預算不佔用 ROLE_LOAD_LIMIT,任一設 0 可關閉

驗證:resume 與全新工作階段皆正確載入 8 輪成對對話;未給 transcript_path、檔案不存在、
無 hook 輸入、關閉設定等情境均安全降級不報錯;假造含 token/Email/電話與 thinking 的
transcript 確認機密遮蔽為 *** 且思考與工具內容未載入。

版號 0.0.2 → 0.0.3

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
admin approved these changes 2026-07-28 10:01:48 +00:00
admin merged commit 12e7d61114 into master 2026-07-28 10:01:50 +00:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: plugins/shared#16