Lesson 07 · 記憶

狀態寫到磁碟,活過壓縮

「State that survives compression — because it's outside the conversation.」

⏱ 約 10 分鐘 · 📝 3 個可互動元件 · 🧑‍💻 基於 shareAI-lab · s07_task_system.py

TodoWrite 和 Task 有什麼不同?

s03 的 TodoManager 也能列任務-但它存在記憶體裡。 s06 講的 auto_compact 一觸發,messages[] 被替換成 summary,TodoManager 的狀態就跟著沒了(因為它是 in-memory)。

s07 的 Task 不一樣:每個 task 是一個 .tasks/task_42.json 檔案。 context 被壓也好、進程重啟也好、agent 被換掉也好——只要磁碟檔案還在,任務就還在

# .tasks/task_12.json
{
  "id": 12,
  "subject": "Refactor auth middleware",
  "description": "Extract JWT logic to shared module",
  "status": "pending",
  "blockedBy": [8, 11],   # 必须先完成 #8 和 #11
  "owner": ""
}
選擇規則:臨時待辦(做完這次就忘)用 todo;持久任務(跨會話保留、有依賴)用 task

blockedBy · 依賴圖的脾氣

blockedBy 是 task id 清單-必須這些都 completed 之後,目前 task 才會「可執行」。

s07 的實作有一個精巧的細節:完成一個 task 時,它會自動從所有其他 task 的 blockedBy 清單中移除自己

def _clear_dependency(self, completed_id: int):
    # Scan every task, remove completed_id from their blockedBy
    for f in self.dir.glob("task_*.json"):
        task = json.loads(f.read_text())
        if completed_id in task.get("blockedBy", []):
            task["blockedBy"].remove(completed_id)
            self._save(task)

這樣 agent 不需要維護一張獨立的 "什麼 task unblocked 了" 表-只要遍歷 .tasks/,找 status=="pending" and not blockedBy 的就是現在可執行的。

依賴圖交互

下面這個 widget 給你一個 5 個 task 的依賴圖。點 "complete",看 blockedBy 自動更新,哪些 task 變成「可執行」(綠色高亮)。

經過壓縮還能活嗎?

s06 講過 auto_compact 會把 messages[] 換成一條 summary。但 task 不受影響,因為它在磁碟。 測試一下:讓 agent 做了 5 個 task,壓縮掉對話後,它掃一下 .tasks/,原地能繼續。

Interactive

Widget 1 · Dependency Graph · 點 complete 看依賴更新

5 個 task 的拓樸關係。點任一個 pending 的 task 上的按鈕改變它的狀態,觀察 blockedBy 陣列和「下一個可執行」清單的變化。

Task 列表(.tasks/ 目录)
当前可执行(status=pending, blockedBy=[])
依赖关系图
Interactive

Widget 2 · Compression Survival · task 活過 auto_compact

讓 agent 建 3 個 task,然後觸發 auto_compact(messages 清空),再恢復-看 task 還在不在。

.tasks/ 目录
messages[]
Interactive

Widget 3 · Dependency Chain · 給你一張圖,答哪些 task 現在能動

5 個 task 的依賴關係。答案在給定狀態下,下一步可以動手的是哪些(可能多選)。

答对 0 / 4