Files
my-pi/pi-hermes-memory/docs/0.4/PLAN.md
T
云服务部-叶林立 312bb2ba5a feat(pi-hermes-memory): 导入上游 v0.9.10 源码快照
从官方 Git 仓库导入 chandra447/pi-hermes-memory 在 tag v0.9.10
(df624056a2e8c68bc89ba0a81e1c120856ec9665,2026-10-02)的源码快照。
本次仅导入源码,尚未接入组合包:package.json、加载顺序、依赖与权限策略
均未改动。

- 原样导入 src/、tests/、docs/、scripts/、README、CHANGELOG、PLAN、
  AGENTS 与 LICENSE;该快照共 156 个上游文件。
- 剔除嵌套 .git、上游 .github 工作流、.ralph/、.claude/、node_modules、
  覆盖率与构建产物。
- 新增中文 UPSTREAM.md,记录来源,以及启用前必须完成的待决事项:
  在 pi-compaction 之前注册加载顺序、better-sqlite3 版本与根 allowScripts
  对齐、strip-ansi 解析确认。
- 说明选择 tag 而非 main 的原因:导入时上游 main 已领先至
  24fcd8ad26fc27badb8d7dbaf8034645de07b893(2026-10-11),选 tag 是为
  对应一个已发布、可复现的版本。

尚未接线。启用前还需反转 tests/extension-load.test.ts 中"不得加载
Hermes"的断言,并同步 pi-tool-search 分组、权限策略与文档。

验证:快照 156 个上游文件全部导入,目录内仅多出 UPSTREAM.md 一份;
已确认与上游 main 内容存在差异,证明取的是 tag 而非 main。
2026-10-13 23:19:35 -07:00

161 lines
6.3 KiB
Markdown

# v0.4 Plan: SQLite FTS5 Session Search + Hybrid Memory
## Problem
The current memory architecture has two scaling bottlenecks:
1. **Memory capacity**: MEMORY.md is capped at 2,200 chars. Power users accumulate knowledge faster than consolidation can manage. Important facts get pruned.
2. **No session history search**: Past conversations are stored as JSONL files in `~/.pi/agent/sessions/<project>/`, but there's no way to search them. When the agent needs context from a previous session, it's gone forever.
## Solution: Hybrid Memory Architecture
### Core memory (always injected, unchanged)
- `MEMORY.md` — 5,000 chars (up from 2,200)
- `USER.md` — 5,000 chars (up from 1,375)
- Still injected into every session via `<memory-context>` tags
- Still human-readable, still editable
### Extended memory (SQLite, searchable on demand)
- `~/.pi/agent/memory/sessions.db`
- `memories` table — unlimited entries, searchable via FTS5
- Agent uses `memory_search` tool to query when it needs context
- Not automatically injected — agent must explicitly search
### Session history (SQLite, searchable on demand)
- Same `sessions.db` file
- `sessions` + `messages` tables — all past conversations indexed
- `session_fts` FTS5 index — full-text search across all sessions
- Agent uses `session_search` tool to find relevant past context
## Architecture
```
Session starts
↓
┌─────────────────────────────────────────────────┐
│ System Prompt (always injected) │
│ ┌─────────────────────────────────────────────┐ │
│ │ <memory-context> │ │
│ │ MEMORY (your personal notes) [5,000 chars] │ │
│ │ ═══ END MEMORY ═══ │ │
│ │ </memory-context> │ │
│ │ <memory-context> │ │
│ │ USER PROFILE [5,000 chars] │ │
│ │ ═══ END MEMORY ═══ │ │
│ │ </memory-context> │ │
│ │ <memory-context> │ │
│ │ PROJECT MEMORY [5,000 chars] │ │
│ │ ═══ END MEMORY ═══ │ │
│ │ </memory-context> │ │
│ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
Agent has access to tools:
memory_search("prisma migration")
→ Searches memories table (global + project)
→ Returns top-10 relevant entries
session_search("how we fixed the test hang")
→ Searches session history via FTS5
→ Returns relevant conversation snippets
```
## Data Model
```sql
-- Session metadata
CREATE TABLE sessions (
id TEXT PRIMARY KEY, -- UUID from JSONL
project TEXT NOT NULL, -- decoded cwd path
started_at TEXT NOT NULL, -- ISO timestamp
ended_at TEXT, -- ISO timestamp (null if still running)
message_count INTEGER DEFAULT 0
);
-- All messages from all sessions
CREATE TABLE messages (
id TEXT PRIMARY KEY, -- message ID from JSONL
session_id TEXT NOT NULL REFERENCES sessions(id),
role TEXT NOT NULL, -- 'user', 'assistant', 'system'
content TEXT NOT NULL, -- extracted text content
timestamp TEXT NOT NULL, -- ISO timestamp
tool_calls TEXT -- JSON array of tool call names (for assistant messages)
);
-- FTS5 index for full-text search across messages
CREATE VIRTUAL TABLE message_fts USING fts5(
content,
content='messages',
content_rowid='rowid'
);
-- Extended memory entries (beyond MEMORY.md limit)
CREATE TABLE memories (
id INTEGER PRIMARY KEY AUTOINCREMENT,
project TEXT, -- NULL for global, project name for project-specific
target TEXT NOT NULL, -- 'memory' or 'user'
content TEXT NOT NULL,
created DATE NOT NULL,
last_referenced DATE NOT NULL
);
-- FTS5 index for memory search
CREATE VIRTUAL TABLE memory_fts USING fts5(
content,
content='memories',
content_rowid='id'
);
```
## Key Design Decisions
### 1. Session indexing is lazy (on session end)
- Don't parse JSONL files on every startup
- Index a session when `session_shutdown` fires
- Bulk import existing sessions via `/memory-index-sessions` command
### 2. FTS5 for both memories and sessions
- Keyword search is sufficient for v0.4
- Embeddings deferred to v0.5+ if search quality isn't enough
- `better-sqlite3` includes FTS5 by default
### 3. Single DB file
- `~/.pi/agent/memory/sessions.db` stores everything
- Memories + sessions + FTS indices in one file
- Simple backup (copy one file), simple cleanup
### 4. Agent-driven search
- `memory_search` and `session_search` are LLM tools
- Agent decides when to search (not automatic)
- Avoids injecting irrelevant context into every session
### 5. Char limit increase to 5,000
- MEMORY.md: 2,200 → 5,000 chars
- USER.md: 1,375 → 5,000 chars
- Project MEMORY.md: 2,200 → 5,000 chars
- More room for core memories before consolidation kicks in
## Dependencies
| Package | Purpose | Size |
|---|---|---|
| `better-sqlite3` | SQLite with FTS5 | ~1MB native addon |
## Risks
| Risk | Mitigation |
|---|---|
| `better-sqlite3` is a native C++ addon | Standard for dev tools; CI has build tools |
| FTS5 search quality | Start with keyword search, add embeddings later if needed |
| Session JSONL format changes | Parse defensively, skip unknown message types |
| Large session history (1000+ sessions) | FTS5 handles this well; add pagination to results |
| DB corruption | Atomic writes, WAL mode, backup before migrations |
## Success Criteria
1. `session_search("prisma migration")` returns relevant conversation snippets from past sessions
2. `memory_search("auth setup")` returns relevant entries from extended memory store
3. MEMORY.md limit raised to 5,000 chars without breaking existing functionality
4. Existing session files indexed without data loss
5. All tests pass, zero regressions