Files
shiro-neko/.hermes/plans/memory-compaction-lifelong.md
T
asepharyana 7db69f19da Enhance memory management and compaction features
- Implement global memory layer for cross-project patterns.
- Improve memory entry scoring with recency and tokenization.
- Adjust MAX_TEXT limit from 400 to 800 for better context retention.
- Add TTL pruning for stale memory entries.
- Capture and summarize dropped content during compaction.
- Update tests to reflect changes in memory behavior and compaction logic.
2026-09-08 21:27:47 +07:00

4.9 KiB

Plan: Lifelong Learning — Memory + Compaction Fix

1. Goal

Bikin shiro-neko cukup untuk agent yang belajar terus (lifelong) tanpa ngulang kesalahan setelah context compact / sesi ganti.

Status sekarang:

  • Harness (session + prune + notebook): 7.5/10 — ladder prune, orphan repair, repeat guard sudah benar.
  • Auto-memory: 4/10 — keyword literal, manual remember, boot block hits-only, MAX_TEXT 400, per-project silo, tanpa auto-consolidation.

Target: harness 9/10, memory 8/10 dengan perubahan kecil, backward-compatible, semua tes hijau.

2. Scope

A. Memory (src/memory.ts)

  • Search dari terms.every(includes) strict → scored hybrid (normalize + token + substring + hits + recency). Tetap require every term untuk kompatibilitas tes, tapi ranking jauh lebih baik dan tahan typo minor (underscore/hyphen/punct).
  • Render boot block dari hits-only → diverse: top-hits + most-recent, dedup. Mencegah 20 gotcha lama mengusir decision baru.
  • MAX_TEXT 400 → 800 (potong silent terlalu agresif untuk gotcha/decision berkonteks).
  • Dedup dari exact text===clean → normalized (lower + collapse ws + strip punct) biar near-duplicate tidak dobel.
  • TTL / decay: pruneExpired(90d) untuk entry hits==0 & umur >90d, dipanggil di load/persist. hits diberi recency bonus saat render, bukan decay destructive.
  • Global memory: ~/.shiro-neko/memory/_global.json sebagai layer kedua; per-project tetap utama, global untuk pattern lintas-repo.
  • Auto-extract hook: suggestFromTranscript(messages, model) — 1x generateText yang meringkas sesi jadi 1-3 kandidat memory (dipakai session afterTurn, bukan auto-write diam-diam).

B. Compaction (src/prune.ts + src/session.ts)

  • estimateTokens: len/4 → len/3.6 + messages*8 (akun overhead role/tool envelope; terukur lebih dekat ke cl100k). Threshold tetap 120k.
  • pruneToFit: selalu preserve head (first user goal + first assistant) terlepas ladder, jadi goal tidak hilang di narrowest rung.
  • prepareStep di session: ladder tetap, tapi droppedSpan di-capture by identity dan di-ringkas via 1x generateText menjadi Note (retained from compacted history) user message (lossless compaction). Guarded try/catch — mock/dead model tidak break turn.
  • afterTurn auto-memory: jika turn menambah >=4 pesan dan memory ada, tawarkan 1-3 kandidat via suggestFromTranscript (tidak auto-persist tanpa konfirmasi model; tool remember tetap sumber write).
  • Repeat guard lintas-turn: seen sekarang Map dengan decay per 20 turn (opsional, ringan).
  • Persist: onChange debounce 400ms → flush juga di beforeExit + tiap done (sudah ada), tambah flush on compact.

C. Prompt / Wiring (src/prompt.ts, src/cli.tsx, src/store.ts)

  • Prompt: memory block sekarang labeled Project memory (project + global); notebook tetap survive compaction.
  • cli.tsx: Memory ctor dapat global layer; session.send after done trigger suggest (off jika --no-memory).
  • store: tidak diubah format, hanya notebook persistance tetap.

3. Files Touched

  • src/memory.ts — utama (search, render, MAX_TEXT, dedup, global, TTL, suggest)
  • src/prune.ts — preserveHead, estimate helper export, ladder keep
  • src/session.ts — estimateTokens baru, summarizeDiscarded, afterTurn hook, cross-turn seen
  • src/prompt.ts — minor label (opsional)
  • src/cli.tsx — wiring global memory + afterTurn suggestion
  • test/memory.test.ts — update expectation truncation 400→800, tambah tes diverse/ranking/TTL
  • test/prune.test.ts — tambah preserveHead test
  • test/compact.test.ts — tambah lossless-compaction test (mock summarize)

4. Schema / Types

  • MemoryEntry tetap {id,kind,text,createdAt,hits} — tambah field opsional lastHitAt?: string untuk recency bonus (backward compat: fallback ke createdAt).
  • Config tidak berubah (SHIRO_HOME, maxSpendUsd, etc).
  • File: per-project ${hash(cwd)}.json, global _global.json di root(). Format array JSON sama, corrupted → [].

5. Verification

  • bun run typecheck — harus pass (verbatimModuleSyntax, noUncheckedIndexedAccess)
  • bun test — semua existing + baru hijau; khusus:
    • memory.test: truncation 800, every-term strict tetap, hits+recency ranking, diverse render contains recent
    • prune.test: head goal survive narrowest rung, estimate monotonic
    • compact.test: droppedSpan summarized to retained note, tidak loop
  • bun run build — dist/shiro bisa di-compile
  • Manual: SHIRO_HOME=$(mktemp -d) bun run src/cli.tsx -p "hello" --yolo --json → compacted event + done, memory file terisi

6. Non-Goals (defer)

  • Embedding vector search (butuh dep + infra) — trigram/BM25 cukup untuk sekarang, bisa follow-up.
  • Subagent parallel fan-out — butuh executor custom, defer (catat di ROADMAP).
  • MCP meta-tools — defer.

7. Rollout

  • Implement memory.ts dulu → test
  • prune.ts preserveHead + estimate
  • session.ts summarizeDiscarded + wiring
  • Update tests incremental, typecheck tiap langkah, jangan bulk.