@x-otto/memory 0.0.1-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +161 -0
- package/dist/index.d.ts +1117 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +201 -0
- package/dist/index.js.map +1 -0
- package/package.json +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# @x-otto/memory
|
|
2
|
+
|
|
3
|
+
Agent working memory pipeline: LLM-driven compaction, LLM-free pruning, archive persistence, multi-source AGENTS.md memory, writable cross-session auto-memory, operational learning, and workspace file-state snapshots.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @x-otto/memory
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { MemoryManager, OperationalLearningStore, FileStateManager } from '@x-otto/memory'
|
|
15
|
+
|
|
16
|
+
// Pipeline: prune → compaction → archive
|
|
17
|
+
const memory = new MemoryManager({
|
|
18
|
+
workspaceDir: process.cwd(),
|
|
19
|
+
model: 'claude-sonnet-4-5',
|
|
20
|
+
provider: myProvider,
|
|
21
|
+
})
|
|
22
|
+
const result = await memory.process(messages, sessionId)
|
|
23
|
+
// Returns { messages, summary, archivePath, pruned, compacted }
|
|
24
|
+
|
|
25
|
+
// Token estimation (CJK-aware, no LLM call)
|
|
26
|
+
import { estimateMessagesTokens } from '@x-otto/memory'
|
|
27
|
+
const tokens = estimateMessagesTokens(messages)
|
|
28
|
+
|
|
29
|
+
// Operational learning
|
|
30
|
+
const lessons = new OperationalLearningStore({ path: './.otto/lessons.json' })
|
|
31
|
+
await lessons.save({ tags: ['testing'], trigger: 'flaky test', insight: 'reset state first' })
|
|
32
|
+
|
|
33
|
+
// File state snapshot
|
|
34
|
+
const fsm = new FileStateManager()
|
|
35
|
+
const snapshot = await fsm.capture({ workspaceDir: '.' })
|
|
36
|
+
// snapshot → { tree, recentFiles: { created, modified, deleted } }
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Pipeline: prune → compaction → archive
|
|
40
|
+
|
|
41
|
+
### 1. Prune — no-LLM fast cleanup (`prune.ts`)
|
|
42
|
+
|
|
43
|
+
- Triggered when estimated tokens exceed `prune.trigger` threshold
|
|
44
|
+
- Protection window: last N messages (by token count) are always kept
|
|
45
|
+
- `tool_result` content outside protection → `[output pruned — N tokens]`
|
|
46
|
+
- `tool_call` arguments for write tools (write/edit/apply_patch) truncated beyond `truncateMaxLength`
|
|
47
|
+
- Minimum gain gate: rolls back if net savings < `minimum` tokens
|
|
48
|
+
|
|
49
|
+
### 2. Compaction — LLM-driven summary (`compaction.ts`)
|
|
50
|
+
|
|
51
|
+
- `findCutPoint`: keep recent tokens, align to user/assistant boundary, detect split-turn
|
|
52
|
+
- Separates messages-to-summarize / preserved / turn-prefix region
|
|
53
|
+
- Extracts file operations (read/modified paths) from tool_results
|
|
54
|
+
- Calls injected `summarize(system, messages, opts)` with structured prompt (Goal / Constraints / Progress / Key Decisions / Next Steps / File Operations / Critical Context)
|
|
55
|
+
- Iterative: previous summary + new messages → `UPDATE_SUMMARIZATION_PROMPT`
|
|
56
|
+
- Split turn: generates additional turn-prefix summary via `TURN_PREFIX_SUMMARIZATION_PROMPT`
|
|
57
|
+
|
|
58
|
+
### 3. Archive — persist compaction output (`archive.ts`)
|
|
59
|
+
|
|
60
|
+
- Formats compressed messages + summary as Markdown (single messages >2000 chars truncated)
|
|
61
|
+
- Backends: `InMemoryArchiveStorage` (default), `PersistenceBackedArchiveStorage` (file/HTTP via `@x-otto/persistence`)
|
|
62
|
+
- Factory: `createArchiveStorage(options)` — file default `$OTTO_HOME/agent/archives`
|
|
63
|
+
|
|
64
|
+
## Persistent Memory (`persistent-memory.ts`)
|
|
65
|
+
|
|
66
|
+
Multi-source AGENTS.md loading + writable:
|
|
67
|
+
|
|
68
|
+
| Source | Path | Writable |
|
|
69
|
+
|--------|------|----------|
|
|
70
|
+
| Global user | `~/.otto/AGENTS.md` | ✓ |
|
|
71
|
+
| Project | `./.otto/AGENTS.md` | ✓ (by default) |
|
|
72
|
+
| Community | `./AGENTS.md` | ✗ (read-only) |
|
|
73
|
+
|
|
74
|
+
### MemoryStore backends
|
|
75
|
+
|
|
76
|
+
| Backend | Store | Notes |
|
|
77
|
+
|---------|-------|-------|
|
|
78
|
+
| File system | `FileSystemMemoryStore` | Direct fs — AGENTS.md must stay human-editable, bypasses persistence envelope |
|
|
79
|
+
| In-memory | `InMemoryMemoryStore` | Testing |
|
|
80
|
+
| HTTP | `HttpMemoryStore` | Remote via `@x-otto/persistence` HttpPersistence; 1 source = 1 doc |
|
|
81
|
+
|
|
82
|
+
### AutoMemory (`auto-memory.ts`)
|
|
83
|
+
|
|
84
|
+
Writable cross-session memory with progressive disclosure:
|
|
85
|
+
- `<baseDir>/MEMORY.md` — index with one-line pointers (injected only, keeps tokens low)
|
|
86
|
+
- `<baseDir>/memory/<slug>.md` — per-entry full content, fetched on demand
|
|
87
|
+
- `record(name, content)`, `read(name)`, `forget(name)`, `getInjection()`, `asSource()`
|
|
88
|
+
|
|
89
|
+
### Memory Injection
|
|
90
|
+
|
|
91
|
+
`buildMemoryInjection(sources)` wraps content in `<agent_memory>` + `<memory_guidelines>` blocks for model injection.
|
|
92
|
+
|
|
93
|
+
## Token Estimation (`token-estimator.ts`)
|
|
94
|
+
|
|
95
|
+
CJK-aware classification heuristic (not `length/4`):
|
|
96
|
+
|
|
97
|
+
- CJK: 1 token/char, ASCII/symbols: 0.25–0.5/char → conservatively high (triggers early rather than overflow)
|
|
98
|
+
- `estimateMessageTokens`: content blocks (text/thinking/tool_call), images ~2000 tokens constant, + role overhead
|
|
99
|
+
- `estimateContextTokens`: hybrid — last assistant's usage as baseline, estimate only trailing tail
|
|
100
|
+
- Exports `messageToText` and re-exports `getTokensFromUsage` from `@x-otto/ai`
|
|
101
|
+
|
|
102
|
+
## Operational Learning (`operational-learning.ts`)
|
|
103
|
+
|
|
104
|
+
`OperationalLearningStore` — experience knowledge base:
|
|
105
|
+
|
|
106
|
+
| Method | Description |
|
|
107
|
+
|--------|-------------|
|
|
108
|
+
| `save(input)` | Auto-assigns `lesson_<n>` id, writes snapshot |
|
|
109
|
+
| `search(query, limit)` | Weighted scoring on trigger/insight/tags, increments `appliedCount` |
|
|
110
|
+
| `list(filter)` | Filter by tags / query |
|
|
111
|
+
| `get(id)`, `delete(id)` | Single entry CRUD |
|
|
112
|
+
| `size` | Entry count |
|
|
113
|
+
|
|
114
|
+
Persistence via `@x-otto/persistence` FilePersistence (atomic tmp+rename), single snapshot store. Auto-upgrades pre-M19 flat JSON format on write.
|
|
115
|
+
|
|
116
|
+
## File State Snapshot (`file-state-snapshot.ts`)
|
|
117
|
+
|
|
118
|
+
Read-only workspace snapshot for agent context:
|
|
119
|
+
- `capture({workspaceDir, recentFiles, planStatus})` — directory tree walk (depth ≤4, ≤50 per dir, ignores node_modules/.git/dist) + recent file stat check (birthtime/mtime → created/modified/deleted)
|
|
120
|
+
- `formatSnapshot(snapshot)` — text block for model injection
|
|
121
|
+
- `getLastSnapshot()` — most recent snapshot
|
|
122
|
+
|
|
123
|
+
## Key Files
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
src/
|
|
127
|
+
types.ts # Config types, MemoryStore, ArchiveStorage, ManagerConfig
|
|
128
|
+
memory-manager.ts # Pipeline coordinator + persistent memory facade
|
|
129
|
+
prune.ts # No-LLM pruning (window, tool_result truncation, gain gate)
|
|
130
|
+
compaction.ts # Cut point, LLM summary, split-turn, file ops extraction
|
|
131
|
+
archive.ts # InMemoryArchiveStorage + formatArchive + createArchiveStorage
|
|
132
|
+
persistent-memory.ts # AGENTS.md multi-source + FileSystemMemoryStore / InMemoryMemoryStore
|
|
133
|
+
http-memory-store.ts # Remote HTTP memory store
|
|
134
|
+
auto-memory.ts # Cross-session progressive-disclosure memory
|
|
135
|
+
auto-extract.ts # Auto-memory candidate extraction
|
|
136
|
+
agents-discovery.ts # AGENTS.md path discovery
|
|
137
|
+
memory-extractor.ts # Derive persistable memory entries from session
|
|
138
|
+
token-estimator.ts # CJK-aware token estimation + usage-hybrid context
|
|
139
|
+
defaults.ts # computeMemoryDefaults / resolveContextSize
|
|
140
|
+
operational-learning.ts # Lessons store (CRUD + weighted search + atomic persistence)
|
|
141
|
+
file-state-snapshot.ts # Workspace read-only snapshot
|
|
142
|
+
prompts.ts # Summary prompts + memory/archive injection builders
|
|
143
|
+
constants.ts # Thresholds, paths
|
|
144
|
+
index.ts # Barrel exports
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Dependencies
|
|
148
|
+
|
|
149
|
+
- Internal: `@x-otto/ai` (Message types, getTokensFromUsage), `@x-otto/persistence`, `@x-otto/shared`, `@x-otto/env` (thresholds, tool name constants)
|
|
150
|
+
- External: `js-tiktoken`
|
|
151
|
+
- LLM access: via injected `summarize` callback (not direct)
|
|
152
|
+
|
|
153
|
+
## Testing
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
pnpm --filter @x-otto/memory typecheck
|
|
157
|
+
pnpm --filter @x-otto/memory build
|
|
158
|
+
pnpm vitest run packages/memory/tests/
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
11 test files covering: prune (window, gain rollback), compaction (cut-point, split-turn, iterative, fileOps), archive (memory + persistence), persistent-memory (multi-source, writable, injection), auto-memory (record/read/forget/slug dedup), token estimation (CJK/symbol/image/usage-hybrid), operational learning (CRUD/search/upgrade), file-state-snapshot, prompts, defaults.
|