@claude-flow/memory 3.0.0-alpha.9 → 3.0.1
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 +308 -37
- package/dist/agent-memory-scope.d.ts.map +1 -1
- package/dist/agent-memory-scope.js +10 -2
- package/dist/agent-memory-scope.js.map +1 -1
- package/dist/agentdb-adapter-key-isolation.test.d.ts +2 -0
- package/dist/agentdb-adapter-key-isolation.test.d.ts.map +1 -0
- package/dist/agentdb-adapter-key-isolation.test.js +175 -0
- package/dist/agentdb-adapter-key-isolation.test.js.map +1 -0
- package/dist/agentdb-adapter-upsert.test.d.ts +2 -0
- package/dist/agentdb-adapter-upsert.test.d.ts.map +1 -0
- package/dist/agentdb-adapter-upsert.test.js +216 -0
- package/dist/agentdb-adapter-upsert.test.js.map +1 -0
- package/dist/agentdb-adapter.d.ts +70 -1
- package/dist/agentdb-adapter.d.ts.map +1 -1
- package/dist/agentdb-adapter.js +365 -32
- package/dist/agentdb-adapter.js.map +1 -1
- package/dist/agentdb-backend.d.ts +25 -0
- package/dist/agentdb-backend.d.ts.map +1 -1
- package/dist/agentdb-backend.js +113 -28
- package/dist/agentdb-backend.js.map +1 -1
- package/dist/agentdb-retrieval-guard.d.ts +76 -0
- package/dist/agentdb-retrieval-guard.d.ts.map +1 -0
- package/dist/agentdb-retrieval-guard.js +77 -0
- package/dist/agentdb-retrieval-guard.js.map +1 -0
- package/dist/agentdb-retrieval-guard.test.d.ts +12 -0
- package/dist/agentdb-retrieval-guard.test.d.ts.map +1 -0
- package/dist/agentdb-retrieval-guard.test.js +129 -0
- package/dist/agentdb-retrieval-guard.test.js.map +1 -0
- package/dist/auto-memory-bridge.d.ts +12 -1
- package/dist/auto-memory-bridge.d.ts.map +1 -1
- package/dist/auto-memory-bridge.js +101 -7
- package/dist/auto-memory-bridge.js.map +1 -1
- package/dist/auto-memory-bridge.test.js +121 -15
- package/dist/auto-memory-bridge.test.js.map +1 -1
- package/dist/auto-memory-index-3224.test.d.ts +2 -0
- package/dist/auto-memory-index-3224.test.d.ts.map +1 -0
- package/dist/auto-memory-index-3224.test.js +77 -0
- package/dist/auto-memory-index-3224.test.js.map +1 -0
- package/dist/consolidator-embedding-benchmark.test.d.ts +39 -0
- package/dist/consolidator-embedding-benchmark.test.d.ts.map +1 -0
- package/dist/consolidator-embedding-benchmark.test.js +366 -0
- package/dist/consolidator-embedding-benchmark.test.js.map +1 -0
- package/dist/consolidator.d.ts +131 -0
- package/dist/consolidator.d.ts.map +1 -0
- package/dist/consolidator.js +309 -0
- package/dist/consolidator.js.map +1 -0
- package/dist/consolidator.test.d.ts +17 -0
- package/dist/consolidator.test.d.ts.map +1 -0
- package/dist/consolidator.test.js +376 -0
- package/dist/consolidator.test.js.map +1 -0
- package/dist/controller-registry.d.ts +290 -0
- package/dist/controller-registry.d.ts.map +1 -0
- package/dist/controller-registry.js +1095 -0
- package/dist/controller-registry.js.map +1 -0
- package/dist/controller-registry.test.d.ts +14 -0
- package/dist/controller-registry.test.d.ts.map +1 -0
- package/dist/controller-registry.test.js +818 -0
- package/dist/controller-registry.test.js.map +1 -0
- package/dist/database-provider.d.ts +14 -2
- package/dist/database-provider.d.ts.map +1 -1
- package/dist/database-provider.js +63 -3
- package/dist/database-provider.js.map +1 -1
- package/dist/database-provider.test.js +56 -3
- package/dist/database-provider.test.js.map +1 -1
- package/dist/entity-tagger.d.ts +31 -0
- package/dist/entity-tagger.d.ts.map +1 -0
- package/dist/entity-tagger.js +80 -0
- package/dist/entity-tagger.js.map +1 -0
- package/dist/entity-tagger.test.d.ts +12 -0
- package/dist/entity-tagger.test.d.ts.map +1 -0
- package/dist/entity-tagger.test.js +70 -0
- package/dist/entity-tagger.test.js.map +1 -0
- package/dist/fts5.test.d.ts +13 -0
- package/dist/fts5.test.d.ts.map +1 -0
- package/dist/fts5.test.js +144 -0
- package/dist/fts5.test.js.map +1 -0
- package/dist/graceful-retrieval.test.d.ts +14 -0
- package/dist/graceful-retrieval.test.d.ts.map +1 -0
- package/dist/graceful-retrieval.test.js +251 -0
- package/dist/graceful-retrieval.test.js.map +1 -0
- package/dist/hnsw-index.d.ts +62 -0
- package/dist/hnsw-index.d.ts.map +1 -1
- package/dist/hnsw-index.js +461 -16
- package/dist/hnsw-index.js.map +1 -1
- package/dist/hnsw-persistence.test.d.ts +13 -0
- package/dist/hnsw-persistence.test.d.ts.map +1 -0
- package/dist/hnsw-persistence.test.js +208 -0
- package/dist/hnsw-persistence.test.js.map +1 -0
- package/dist/hnsw-quantization.test.d.ts +17 -0
- package/dist/hnsw-quantization.test.d.ts.map +1 -0
- package/dist/hnsw-quantization.test.js +140 -0
- package/dist/hnsw-quantization.test.js.map +1 -0
- package/dist/hybrid-backend.d.ts +46 -2
- package/dist/hybrid-backend.d.ts.map +1 -1
- package/dist/hybrid-backend.js +120 -21
- package/dist/hybrid-backend.js.map +1 -1
- package/dist/hybrid-backend.test.js +139 -5
- package/dist/hybrid-backend.test.js.map +1 -1
- package/dist/index.d.ts +164 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +272 -30
- package/dist/index.js.map +1 -1
- package/dist/index.test.d.ts +10 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js +71 -0
- package/dist/index.test.js.map +1 -0
- package/dist/json-security.d.ts +12 -0
- package/dist/json-security.d.ts.map +1 -0
- package/dist/json-security.js +20 -0
- package/dist/json-security.js.map +1 -0
- package/dist/learning-bridge.d.ts +29 -0
- package/dist/learning-bridge.d.ts.map +1 -1
- package/dist/learning-bridge.js +71 -6
- package/dist/learning-bridge.js.map +1 -1
- package/dist/learning-bridge.test.js +181 -1
- package/dist/learning-bridge.test.js.map +1 -1
- package/dist/memory-key.d.ts +3 -0
- package/dist/memory-key.d.ts.map +1 -0
- package/dist/memory-key.js +5 -0
- package/dist/memory-key.js.map +1 -0
- package/dist/migration.d.ts +19 -4
- package/dist/migration.d.ts.map +1 -1
- package/dist/migration.js +99 -24
- package/dist/migration.js.map +1 -1
- package/dist/migration.test.d.ts +11 -0
- package/dist/migration.test.d.ts.map +1 -0
- package/dist/migration.test.js +141 -0
- package/dist/migration.test.js.map +1 -0
- package/dist/mmr-benchmark.test.d.ts +2 -0
- package/dist/mmr-benchmark.test.d.ts.map +1 -0
- package/dist/mmr-benchmark.test.js +286 -0
- package/dist/mmr-benchmark.test.js.map +1 -0
- package/dist/mmr-rerank-cosine-cache.test.d.ts +2 -0
- package/dist/mmr-rerank-cosine-cache.test.d.ts.map +1 -0
- package/dist/mmr-rerank-cosine-cache.test.js +334 -0
- package/dist/mmr-rerank-cosine-cache.test.js.map +1 -0
- package/dist/mmr-rerank-perf.test.d.ts +2 -0
- package/dist/mmr-rerank-perf.test.d.ts.map +1 -0
- package/dist/mmr-rerank-perf.test.js +191 -0
- package/dist/mmr-rerank-perf.test.js.map +1 -0
- package/dist/persistent-sona.d.ts +144 -0
- package/dist/persistent-sona.d.ts.map +1 -0
- package/dist/persistent-sona.js +332 -0
- package/dist/persistent-sona.js.map +1 -0
- package/dist/rvf-backend.d.ts +53 -0
- package/dist/rvf-backend.d.ts.map +1 -0
- package/dist/rvf-backend.js +643 -0
- package/dist/rvf-backend.js.map +1 -0
- package/dist/rvf-learning-store.d.ts +139 -0
- package/dist/rvf-learning-store.d.ts.map +1 -0
- package/dist/rvf-learning-store.js +295 -0
- package/dist/rvf-learning-store.js.map +1 -0
- package/dist/rvf-migration.d.ts +45 -0
- package/dist/rvf-migration.d.ts.map +1 -0
- package/dist/rvf-migration.js +254 -0
- package/dist/rvf-migration.js.map +1 -0
- package/dist/smart-retrieval-scores.test.d.ts +2 -0
- package/dist/smart-retrieval-scores.test.d.ts.map +1 -0
- package/dist/smart-retrieval-scores.test.js +75 -0
- package/dist/smart-retrieval-scores.test.js.map +1 -0
- package/dist/smart-retrieval.d.ts +141 -0
- package/dist/smart-retrieval.d.ts.map +1 -0
- package/dist/smart-retrieval.js +399 -0
- package/dist/smart-retrieval.js.map +1 -0
- package/dist/smart-retrieval.test.d.ts +2 -0
- package/dist/smart-retrieval.test.d.ts.map +1 -0
- package/dist/smart-retrieval.test.js +418 -0
- package/dist/smart-retrieval.test.js.map +1 -0
- package/dist/sqlite-backend.d.ts +10 -0
- package/dist/sqlite-backend.d.ts.map +1 -1
- package/dist/sqlite-backend.js +101 -5
- package/dist/sqlite-backend.js.map +1 -1
- package/dist/sqljs-backend.d.ts +9 -0
- package/dist/sqljs-backend.d.ts.map +1 -1
- package/dist/sqljs-backend.js +91 -3
- package/dist/sqljs-backend.js.map +1 -1
- package/dist/tiered-memory.d.ts +171 -0
- package/dist/tiered-memory.d.ts.map +1 -0
- package/dist/tiered-memory.js +350 -0
- package/dist/tiered-memory.js.map +1 -0
- package/dist/tiered-memory.test.d.ts +9 -0
- package/dist/tiered-memory.test.d.ts.map +1 -0
- package/dist/tiered-memory.test.js +220 -0
- package/dist/tiered-memory.test.js.map +1 -0
- package/dist/types.d.ts +17 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +10 -8
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier-aware store with Zep/Graphiti-style temporal validity, durable when
|
|
3
|
+
* given a SQLite handle.
|
|
4
|
+
*
|
|
5
|
+
* This is the store backing `agentdb_hierarchical-store` / `-recall` when
|
|
6
|
+
* agentdb's native HierarchicalMemory is unavailable (previously an inline
|
|
7
|
+
* stub in controller-registry.ts). It is promoted to a first-class module
|
|
8
|
+
* so temporal knowledge semantics live in one tested place:
|
|
9
|
+
*
|
|
10
|
+
* - Facts may carry a validity window (`validFrom` / `validUntil`).
|
|
11
|
+
* - Conflicting facts are INVALIDATED, not overwritten: `supersedes`
|
|
12
|
+
* stamps the old entry with `validUntil = now` + `supersededBy = <newId>`
|
|
13
|
+
* and archives it — the history stays queryable.
|
|
14
|
+
* - `recall()` filters invalid entries by default; `includeExpired: true`
|
|
15
|
+
* is the audit escape hatch.
|
|
16
|
+
* - Entries without temporal fields behave exactly as before (always valid).
|
|
17
|
+
*
|
|
18
|
+
* Durability (#2887): agentdb dropped its `HierarchicalMemory` export at
|
|
19
|
+
* 3.0.0-alpha.17, so this store — not the native controller — is what every
|
|
20
|
+
* `agentdb_hierarchical-store` call actually lands in. Purely in-memory, that
|
|
21
|
+
* made every such write a silent no-op that still reported success. Pass a
|
|
22
|
+
* better-sqlite3-compatible handle and the store writes through to a
|
|
23
|
+
* `tiered_memory` table and rehydrates from it on construction; without a
|
|
24
|
+
* handle it stays volatile and says so via {@link TieredMemoryStore.isDurable}.
|
|
25
|
+
*
|
|
26
|
+
* API shape is kept duck-type compatible with the previous stub so the CLI
|
|
27
|
+
* memory-bridge keeps working unchanged:
|
|
28
|
+
* store(key, value, tier) recall(query, topK) getTierStats()
|
|
29
|
+
*
|
|
30
|
+
* IMPORTANT: this class must NOT expose both `getStats` and `promote` —
|
|
31
|
+
* that pair is the bridge's detection signal for the REAL agentdb
|
|
32
|
+
* HierarchicalMemory API.
|
|
33
|
+
*
|
|
34
|
+
* @module @claude-flow/memory/tiered-memory
|
|
35
|
+
*/
|
|
36
|
+
const TABLE_DDL = `
|
|
37
|
+
CREATE TABLE IF NOT EXISTS tiered_memory (
|
|
38
|
+
id TEXT PRIMARY KEY,
|
|
39
|
+
key TEXT NOT NULL,
|
|
40
|
+
value TEXT NOT NULL,
|
|
41
|
+
tier TEXT NOT NULL,
|
|
42
|
+
ts INTEGER NOT NULL,
|
|
43
|
+
valid_from TEXT,
|
|
44
|
+
valid_until TEXT,
|
|
45
|
+
superseded_by TEXT,
|
|
46
|
+
archived INTEGER NOT NULL DEFAULT 0
|
|
47
|
+
);
|
|
48
|
+
CREATE INDEX IF NOT EXISTS idx_tiered_memory_key ON tiered_memory(key);
|
|
49
|
+
CREATE INDEX IF NOT EXISTS idx_tiered_memory_tier ON tiered_memory(tier, archived);
|
|
50
|
+
`;
|
|
51
|
+
function rowToEntry(row) {
|
|
52
|
+
const entry = {
|
|
53
|
+
id: row.id,
|
|
54
|
+
key: row.key,
|
|
55
|
+
value: row.value,
|
|
56
|
+
tier: row.tier,
|
|
57
|
+
ts: Number(row.ts),
|
|
58
|
+
};
|
|
59
|
+
if (row.valid_from)
|
|
60
|
+
entry.validFrom = row.valid_from;
|
|
61
|
+
if (row.valid_until)
|
|
62
|
+
entry.validUntil = row.valid_until;
|
|
63
|
+
if (row.superseded_by)
|
|
64
|
+
entry.supersededBy = row.superseded_by;
|
|
65
|
+
return entry;
|
|
66
|
+
}
|
|
67
|
+
const VALID_TIERS = ['working', 'episodic', 'semantic'];
|
|
68
|
+
const MAX_PER_TIER = 5000;
|
|
69
|
+
const MAX_ARCHIVED = 5000;
|
|
70
|
+
const MAX_VALUE_LENGTH = 100_000;
|
|
71
|
+
const MAX_QUERY_LENGTH = 10_000;
|
|
72
|
+
let idCounter = 0;
|
|
73
|
+
function nextId() {
|
|
74
|
+
idCounter = (idCounter + 1) % Number.MAX_SAFE_INTEGER;
|
|
75
|
+
return `tm_${Date.now().toString(36)}_${idCounter.toString(36)}`;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Returns true when the entry is valid at `nowMs`.
|
|
79
|
+
* Entries without temporal fields are always valid (legacy behavior).
|
|
80
|
+
* Unparseable timestamps are ignored (treated as absent) rather than
|
|
81
|
+
* silently hiding the entry.
|
|
82
|
+
*/
|
|
83
|
+
export function isTemporallyValid(entry, nowMs = Date.now()) {
|
|
84
|
+
if (entry.validFrom) {
|
|
85
|
+
const from = Date.parse(entry.validFrom);
|
|
86
|
+
if (!Number.isNaN(from) && from > nowMs)
|
|
87
|
+
return false; // not yet valid
|
|
88
|
+
}
|
|
89
|
+
if (entry.validUntil) {
|
|
90
|
+
const until = Date.parse(entry.validUntil);
|
|
91
|
+
if (!Number.isNaN(until) && until <= nowMs)
|
|
92
|
+
return false; // expired/superseded
|
|
93
|
+
}
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Tier-aware in-memory store with temporal validity and per-tier size
|
|
98
|
+
* limits to prevent unbounded memory growth.
|
|
99
|
+
*/
|
|
100
|
+
export class TieredMemoryStore {
|
|
101
|
+
tiers = {
|
|
102
|
+
working: new Map(),
|
|
103
|
+
episodic: new Map(),
|
|
104
|
+
semantic: new Map(),
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Superseded entries are moved here so a same-key re-store cannot
|
|
108
|
+
* clobber the historical fact. Bounded FIFO.
|
|
109
|
+
*/
|
|
110
|
+
archived = [];
|
|
111
|
+
db = null;
|
|
112
|
+
/**
|
|
113
|
+
* @param options.db better-sqlite3-compatible handle. When supplied the
|
|
114
|
+
* store writes through to `tiered_memory` and rehydrates from it, so
|
|
115
|
+
* entries survive the process. Without it the store is volatile and
|
|
116
|
+
* {@link isDurable} returns false — callers must treat a write as lost
|
|
117
|
+
* on exit rather than reporting success (#2887).
|
|
118
|
+
*/
|
|
119
|
+
constructor(options) {
|
|
120
|
+
const db = options?.db ?? null;
|
|
121
|
+
if (!db)
|
|
122
|
+
return;
|
|
123
|
+
try {
|
|
124
|
+
db.exec(TABLE_DDL);
|
|
125
|
+
this.db = db;
|
|
126
|
+
this.hydrate();
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// Schema creation failed — stay volatile and report it honestly via
|
|
130
|
+
// isDurable() rather than pretending the handle works.
|
|
131
|
+
this.db = null;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/** True when writes are persisted to the backing table. */
|
|
135
|
+
isDurable() {
|
|
136
|
+
return this.db !== null;
|
|
137
|
+
}
|
|
138
|
+
/** Durability mode, for surfacing to MCP callers. */
|
|
139
|
+
getPersistence() {
|
|
140
|
+
return this.db ? 'sqlite' : 'volatile';
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Actual row count in the backing table (not the in-memory maps), so
|
|
144
|
+
* health checks can detect a claimed-write / empty-table mismatch.
|
|
145
|
+
* Returns null when volatile — there is no table to count.
|
|
146
|
+
*/
|
|
147
|
+
countPersisted() {
|
|
148
|
+
if (!this.db)
|
|
149
|
+
return null;
|
|
150
|
+
try {
|
|
151
|
+
const row = this.db.prepare('SELECT COUNT(*) AS n FROM tiered_memory').get();
|
|
152
|
+
return Number(row?.n ?? 0);
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/** Load persisted rows back into the tier maps and the archive. */
|
|
159
|
+
hydrate() {
|
|
160
|
+
if (!this.db)
|
|
161
|
+
return;
|
|
162
|
+
const rows = this.db
|
|
163
|
+
.prepare('SELECT * FROM tiered_memory ORDER BY ts ASC')
|
|
164
|
+
.all();
|
|
165
|
+
for (const row of rows) {
|
|
166
|
+
const entry = rowToEntry(row);
|
|
167
|
+
if (row.archived) {
|
|
168
|
+
this.archived.push(entry);
|
|
169
|
+
if (this.archived.length > MAX_ARCHIVED)
|
|
170
|
+
this.archived.shift();
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
const map = this.tiers[entry.tier] ?? this.tiers.working;
|
|
174
|
+
if (map.size >= MAX_PER_TIER)
|
|
175
|
+
continue;
|
|
176
|
+
map.set(entry.key, entry);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Write-through. Throws on failure so a store that cannot be persisted
|
|
181
|
+
* fails loudly instead of reporting success for a lost write.
|
|
182
|
+
*/
|
|
183
|
+
persist(entry, archived) {
|
|
184
|
+
if (!this.db)
|
|
185
|
+
return;
|
|
186
|
+
this.db
|
|
187
|
+
.prepare(`INSERT INTO tiered_memory (id, key, value, tier, ts, valid_from, valid_until, superseded_by, archived)
|
|
188
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
189
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
190
|
+
key = excluded.key, value = excluded.value, tier = excluded.tier, ts = excluded.ts,
|
|
191
|
+
valid_from = excluded.valid_from, valid_until = excluded.valid_until,
|
|
192
|
+
superseded_by = excluded.superseded_by, archived = excluded.archived`)
|
|
193
|
+
.run(entry.id, entry.key, entry.value, entry.tier, entry.ts, entry.validFrom ?? null, entry.validUntil ?? null, entry.supersededBy ?? null, archived ? 1 : 0);
|
|
194
|
+
}
|
|
195
|
+
/** Drop a persisted row (used by eviction and remove()). */
|
|
196
|
+
unpersist(id) {
|
|
197
|
+
if (!this.db)
|
|
198
|
+
return;
|
|
199
|
+
try {
|
|
200
|
+
this.db.prepare('DELETE FROM tiered_memory WHERE id = ?').run(id);
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
// A failed eviction leaves a stale row; harmless next to losing a write.
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Store an entry. Same-key stores within a tier overwrite (legacy
|
|
208
|
+
* behavior); use `options.supersedes` to invalidate-and-keep instead.
|
|
209
|
+
*/
|
|
210
|
+
store(key, value, tier = 'working', options) {
|
|
211
|
+
const tierName = VALID_TIERS.includes(tier) ? tier : 'working';
|
|
212
|
+
const t = this.tiers[tierName];
|
|
213
|
+
const id = nextId();
|
|
214
|
+
let superseded = null;
|
|
215
|
+
if (options?.supersedes) {
|
|
216
|
+
superseded = this.supersede(options.supersedes, id);
|
|
217
|
+
}
|
|
218
|
+
// Evict oldest if at capacity
|
|
219
|
+
if (t.size >= MAX_PER_TIER) {
|
|
220
|
+
const oldestKey = t.keys().next().value;
|
|
221
|
+
if (oldestKey !== undefined) {
|
|
222
|
+
const evicted = t.get(oldestKey);
|
|
223
|
+
t.delete(oldestKey);
|
|
224
|
+
if (evicted)
|
|
225
|
+
this.unpersist(evicted.id);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
const entry = {
|
|
229
|
+
id,
|
|
230
|
+
key,
|
|
231
|
+
value: value.substring(0, MAX_VALUE_LENGTH),
|
|
232
|
+
tier: tierName,
|
|
233
|
+
ts: Date.now(),
|
|
234
|
+
};
|
|
235
|
+
if (options?.validFrom)
|
|
236
|
+
entry.validFrom = options.validFrom;
|
|
237
|
+
if (options?.validUntil)
|
|
238
|
+
entry.validUntil = options.validUntil;
|
|
239
|
+
// Persist BEFORE publishing to the in-memory map: a throw here must not
|
|
240
|
+
// leave a value visible in-process that never reached disk (#2887).
|
|
241
|
+
const replaced = t.get(key);
|
|
242
|
+
this.persist(entry, false);
|
|
243
|
+
if (replaced && replaced.id !== entry.id)
|
|
244
|
+
this.unpersist(replaced.id);
|
|
245
|
+
t.set(key, entry);
|
|
246
|
+
return {
|
|
247
|
+
id, key, tier: tierName, superseded,
|
|
248
|
+
durable: this.db !== null,
|
|
249
|
+
persistence: this.getPersistence(),
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Invalidate an existing entry (matched by id first, then by key) by
|
|
254
|
+
* stamping `validUntil = now` + `supersededBy = newId` and moving it to
|
|
255
|
+
* the archive. The entry is NOT deleted — `recall(..., { includeExpired:
|
|
256
|
+
* true })` still returns it.
|
|
257
|
+
*/
|
|
258
|
+
supersede(idOrKey, newId) {
|
|
259
|
+
const found = this.findActive(idOrKey);
|
|
260
|
+
if (!found)
|
|
261
|
+
return null;
|
|
262
|
+
const { map, entry } = found;
|
|
263
|
+
const now = new Date().toISOString();
|
|
264
|
+
entry.validUntil = now;
|
|
265
|
+
entry.supersededBy = newId;
|
|
266
|
+
map.delete(entry.key);
|
|
267
|
+
this.persist(entry, true);
|
|
268
|
+
this.archived.push(entry);
|
|
269
|
+
if (this.archived.length > MAX_ARCHIVED) {
|
|
270
|
+
const dropped = this.archived.shift();
|
|
271
|
+
if (dropped)
|
|
272
|
+
this.unpersist(dropped.id);
|
|
273
|
+
}
|
|
274
|
+
return { id: entry.id, key: entry.key, validUntil: now };
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Substring recall across tiers, newest first. By default only
|
|
278
|
+
* temporally-valid entries are returned; pass `{ includeExpired: true }`
|
|
279
|
+
* to audit superseded / expired / future-dated facts too.
|
|
280
|
+
*/
|
|
281
|
+
recall(query, topK = 5, options) {
|
|
282
|
+
const safeTopK = Math.min(Math.max(1, topK), 100);
|
|
283
|
+
const q = query.toLowerCase().substring(0, MAX_QUERY_LENGTH);
|
|
284
|
+
const includeExpired = options?.includeExpired === true;
|
|
285
|
+
const now = Date.now();
|
|
286
|
+
const results = [];
|
|
287
|
+
const consider = (entry) => {
|
|
288
|
+
if (!entry.key.toLowerCase().includes(q) && !entry.value.toLowerCase().includes(q)) {
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
if (!includeExpired && !isTemporallyValid(entry, now))
|
|
292
|
+
return false;
|
|
293
|
+
results.push(entry);
|
|
294
|
+
return true;
|
|
295
|
+
};
|
|
296
|
+
outer: for (const map of Object.values(this.tiers)) {
|
|
297
|
+
for (const entry of map.values()) {
|
|
298
|
+
consider(entry);
|
|
299
|
+
if (results.length >= safeTopK * 3)
|
|
300
|
+
break outer; // early exit for large stores
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
if (includeExpired && results.length < safeTopK * 3) {
|
|
304
|
+
for (const entry of this.archived) {
|
|
305
|
+
consider(entry);
|
|
306
|
+
if (results.length >= safeTopK * 3)
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return results.sort((a, b) => b.ts - a.ts).slice(0, safeTopK);
|
|
311
|
+
}
|
|
312
|
+
/** Hard-delete an active entry by key (used by hierarchical-delete). */
|
|
313
|
+
remove(key) {
|
|
314
|
+
for (const map of Object.values(this.tiers)) {
|
|
315
|
+
const entry = map.get(key);
|
|
316
|
+
if (!entry)
|
|
317
|
+
continue;
|
|
318
|
+
map.delete(key);
|
|
319
|
+
this.unpersist(entry.id);
|
|
320
|
+
return true;
|
|
321
|
+
}
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
324
|
+
/** Per-tier active counts plus the superseded-archive size. */
|
|
325
|
+
getTierStats() {
|
|
326
|
+
const stats = {};
|
|
327
|
+
for (const [name, map] of Object.entries(this.tiers)) {
|
|
328
|
+
stats[name] = map.size;
|
|
329
|
+
}
|
|
330
|
+
stats.superseded = this.archived.length;
|
|
331
|
+
return stats;
|
|
332
|
+
}
|
|
333
|
+
findActive(idOrKey) {
|
|
334
|
+
// Prefer id match (exact provenance), fall back to key match.
|
|
335
|
+
for (const map of Object.values(this.tiers)) {
|
|
336
|
+
for (const entry of map.values()) {
|
|
337
|
+
if (entry.id === idOrKey)
|
|
338
|
+
return { map, entry };
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
for (const map of Object.values(this.tiers)) {
|
|
342
|
+
const entry = map.get(idOrKey);
|
|
343
|
+
if (entry)
|
|
344
|
+
return { map, entry };
|
|
345
|
+
}
|
|
346
|
+
return null;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
export default TieredMemoryStore;
|
|
350
|
+
//# sourceMappingURL=tiered-memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tiered-memory.js","sourceRoot":"","sources":["../src/tiered-memory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for TieredMemoryStore temporal validity (Zep/Graphiti-style).
|
|
3
|
+
*
|
|
4
|
+
* Covers: supersede flow (invalidate, not delete), expired filtering,
|
|
5
|
+
* the includeExpired escape hatch, and backward compatibility for legacy
|
|
6
|
+
* entries without temporal fields.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=tiered-memory.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tiered-memory.test.d.ts","sourceRoot":"","sources":["../src/tiered-memory.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for TieredMemoryStore temporal validity (Zep/Graphiti-style).
|
|
3
|
+
*
|
|
4
|
+
* Covers: supersede flow (invalidate, not delete), expired filtering,
|
|
5
|
+
* the includeExpired escape hatch, and backward compatibility for legacy
|
|
6
|
+
* entries without temporal fields.
|
|
7
|
+
*/
|
|
8
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
9
|
+
import Database from 'better-sqlite3';
|
|
10
|
+
import fs from 'node:fs';
|
|
11
|
+
import os from 'node:os';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import { TieredMemoryStore, isTemporallyValid } from './tiered-memory.js';
|
|
14
|
+
describe('TieredMemoryStore — legacy behavior (backward compatibility)', () => {
|
|
15
|
+
let store;
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
store = new TieredMemoryStore();
|
|
18
|
+
});
|
|
19
|
+
it('stores and recalls entries without temporal fields exactly as before', () => {
|
|
20
|
+
store.store('auth-pattern', 'JWT with refresh tokens', 'semantic');
|
|
21
|
+
store.store('scratch', 'temp note', 'working');
|
|
22
|
+
const results = store.recall('jwt', 5);
|
|
23
|
+
expect(results).toHaveLength(1);
|
|
24
|
+
expect(results[0].key).toBe('auth-pattern');
|
|
25
|
+
expect(results[0].tier).toBe('semantic');
|
|
26
|
+
expect(results[0].validFrom).toBeUndefined();
|
|
27
|
+
expect(results[0].validUntil).toBeUndefined();
|
|
28
|
+
expect(results[0].supersededBy).toBeUndefined();
|
|
29
|
+
});
|
|
30
|
+
it('same-key store within a tier overwrites (legacy semantics)', () => {
|
|
31
|
+
store.store('k1', 'first value', 'working');
|
|
32
|
+
store.store('k1', 'second value', 'working');
|
|
33
|
+
const results = store.recall('value', 10);
|
|
34
|
+
expect(results).toHaveLength(1);
|
|
35
|
+
expect(results[0].value).toBe('second value');
|
|
36
|
+
});
|
|
37
|
+
it('defaults invalid tiers to working', () => {
|
|
38
|
+
store.store('k1', 'v1', 'nonsense-tier');
|
|
39
|
+
expect(store.getTierStats().working).toBe(1);
|
|
40
|
+
});
|
|
41
|
+
it('reports per-tier stats plus superseded archive size', () => {
|
|
42
|
+
store.store('a', 'v', 'working');
|
|
43
|
+
store.store('b', 'v', 'episodic');
|
|
44
|
+
const stats = store.getTierStats();
|
|
45
|
+
expect(stats.working).toBe(1);
|
|
46
|
+
expect(stats.episodic).toBe(1);
|
|
47
|
+
expect(stats.semantic).toBe(0);
|
|
48
|
+
expect(stats.superseded).toBe(0);
|
|
49
|
+
});
|
|
50
|
+
it('remove() hard-deletes an active entry by key', () => {
|
|
51
|
+
store.store('gone', 'delete me', 'working');
|
|
52
|
+
expect(store.remove('gone')).toBe(true);
|
|
53
|
+
expect(store.recall('delete me', 5)).toHaveLength(0);
|
|
54
|
+
expect(store.remove('gone')).toBe(false);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
describe('TieredMemoryStore — supersede flow', () => {
|
|
58
|
+
let store;
|
|
59
|
+
beforeEach(() => {
|
|
60
|
+
store = new TieredMemoryStore();
|
|
61
|
+
});
|
|
62
|
+
it('invalidates (not deletes) the superseded entry and links supersededBy', () => {
|
|
63
|
+
const oldFact = store.store('ceo', 'The CEO is Alice', 'semantic');
|
|
64
|
+
const newFact = store.store('ceo-2026', 'The CEO is Bob', 'semantic', {
|
|
65
|
+
supersedes: oldFact.id,
|
|
66
|
+
});
|
|
67
|
+
expect(newFact.superseded).not.toBeNull();
|
|
68
|
+
expect(newFact.superseded.id).toBe(oldFact.id);
|
|
69
|
+
expect(newFact.superseded.validUntil).toBeTruthy();
|
|
70
|
+
// Default recall: only the new fact is visible
|
|
71
|
+
const current = store.recall('CEO', 10);
|
|
72
|
+
expect(current).toHaveLength(1);
|
|
73
|
+
expect(current[0].key).toBe('ceo-2026');
|
|
74
|
+
// Escape hatch: both facts visible, old one carries the invalidation stamp
|
|
75
|
+
const audit = store.recall('CEO', 10, { includeExpired: true });
|
|
76
|
+
expect(audit).toHaveLength(2);
|
|
77
|
+
const old = audit.find((e) => e.key === 'ceo');
|
|
78
|
+
expect(old).toBeDefined();
|
|
79
|
+
expect(old.supersededBy).toBe(newFact.id);
|
|
80
|
+
expect(Date.parse(old.validUntil)).toBeLessThanOrEqual(Date.now());
|
|
81
|
+
});
|
|
82
|
+
it('resolves supersedes by key when no id matches', () => {
|
|
83
|
+
store.store('policy', 'Old policy text', 'semantic');
|
|
84
|
+
const result = store.store('policy-v2', 'New policy text', 'semantic', {
|
|
85
|
+
supersedes: 'policy',
|
|
86
|
+
});
|
|
87
|
+
expect(result.superseded).not.toBeNull();
|
|
88
|
+
expect(result.superseded.key).toBe('policy');
|
|
89
|
+
expect(store.recall('policy text', 10)).toHaveLength(1);
|
|
90
|
+
expect(store.recall('policy text', 10, { includeExpired: true })).toHaveLength(2);
|
|
91
|
+
});
|
|
92
|
+
it('superseding with the SAME key preserves the old fact in the archive', () => {
|
|
93
|
+
const oldFact = store.store('config', 'timeout=30', 'semantic');
|
|
94
|
+
store.store('config', 'timeout=60', 'semantic', { supersedes: oldFact.id });
|
|
95
|
+
const current = store.recall('timeout', 10);
|
|
96
|
+
expect(current).toHaveLength(1);
|
|
97
|
+
expect(current[0].value).toBe('timeout=60');
|
|
98
|
+
const audit = store.recall('timeout', 10, { includeExpired: true });
|
|
99
|
+
expect(audit).toHaveLength(2);
|
|
100
|
+
expect(audit.map((e) => e.value).sort()).toEqual(['timeout=30', 'timeout=60']);
|
|
101
|
+
});
|
|
102
|
+
it('returns null superseded when the target does not exist', () => {
|
|
103
|
+
const result = store.store('k', 'v', 'working', { supersedes: 'no-such-entry' });
|
|
104
|
+
expect(result.superseded).toBeNull();
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
describe('TieredMemoryStore — validity-window filtering', () => {
|
|
108
|
+
let store;
|
|
109
|
+
beforeEach(() => {
|
|
110
|
+
store = new TieredMemoryStore();
|
|
111
|
+
});
|
|
112
|
+
it('filters entries whose validUntil is in the past by default', () => {
|
|
113
|
+
const past = new Date(Date.now() - 60_000).toISOString();
|
|
114
|
+
store.store('expired-fact', 'promo code SAVE20', 'semantic', { validUntil: past });
|
|
115
|
+
store.store('live-fact', 'promo code SAVE30', 'semantic');
|
|
116
|
+
const results = store.recall('promo code', 10);
|
|
117
|
+
expect(results).toHaveLength(1);
|
|
118
|
+
expect(results[0].key).toBe('live-fact');
|
|
119
|
+
});
|
|
120
|
+
it('includeExpired returns expired entries too (audit escape hatch)', () => {
|
|
121
|
+
const past = new Date(Date.now() - 60_000).toISOString();
|
|
122
|
+
store.store('expired-fact', 'promo code SAVE20', 'semantic', { validUntil: past });
|
|
123
|
+
store.store('live-fact', 'promo code SAVE30', 'semantic');
|
|
124
|
+
const results = store.recall('promo code', 10, { includeExpired: true });
|
|
125
|
+
expect(results).toHaveLength(2);
|
|
126
|
+
});
|
|
127
|
+
it('keeps entries whose validUntil is in the future', () => {
|
|
128
|
+
const future = new Date(Date.now() + 3_600_000).toISOString();
|
|
129
|
+
store.store('ttl-fact', 'valid for one hour', 'working', { validUntil: future });
|
|
130
|
+
expect(store.recall('one hour', 5)).toHaveLength(1);
|
|
131
|
+
});
|
|
132
|
+
it('hides not-yet-valid entries (validFrom in the future) by default', () => {
|
|
133
|
+
const future = new Date(Date.now() + 3_600_000).toISOString();
|
|
134
|
+
store.store('scheduled-fact', 'new pricing takes effect', 'semantic', { validFrom: future });
|
|
135
|
+
expect(store.recall('pricing', 5)).toHaveLength(0);
|
|
136
|
+
expect(store.recall('pricing', 5, { includeExpired: true })).toHaveLength(1);
|
|
137
|
+
});
|
|
138
|
+
it('treats unparseable timestamps as absent instead of hiding the entry', () => {
|
|
139
|
+
store.store('weird', 'garbage timestamp entry', 'working', { validUntil: 'not-a-date' });
|
|
140
|
+
expect(store.recall('garbage', 5)).toHaveLength(1);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
describe('isTemporallyValid', () => {
|
|
144
|
+
const now = Date.parse('2026-07-03T12:00:00Z');
|
|
145
|
+
it('entries without fields are always valid', () => {
|
|
146
|
+
expect(isTemporallyValid({}, now)).toBe(true);
|
|
147
|
+
});
|
|
148
|
+
it('respects validFrom / validUntil boundaries', () => {
|
|
149
|
+
expect(isTemporallyValid({ validFrom: '2026-07-03T13:00:00Z' }, now)).toBe(false);
|
|
150
|
+
expect(isTemporallyValid({ validFrom: '2026-07-03T11:00:00Z' }, now)).toBe(true);
|
|
151
|
+
expect(isTemporallyValid({ validUntil: '2026-07-03T11:00:00Z' }, now)).toBe(false);
|
|
152
|
+
expect(isTemporallyValid({ validUntil: '2026-07-03T13:00:00Z' }, now)).toBe(true);
|
|
153
|
+
// validUntil exactly now → expired (window is half-open)
|
|
154
|
+
expect(isTemporallyValid({ validUntil: '2026-07-03T12:00:00Z' }, now)).toBe(false);
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
describe('TieredMemoryStore — durability (#2887)', () => {
|
|
158
|
+
const dbs = [];
|
|
159
|
+
const dirs = [];
|
|
160
|
+
function freshDbPath() {
|
|
161
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'tiered-durability-'));
|
|
162
|
+
dirs.push(dir);
|
|
163
|
+
return path.join(dir, 'agentdb-memory.db');
|
|
164
|
+
}
|
|
165
|
+
function open(dbPath) {
|
|
166
|
+
const db = new Database(dbPath);
|
|
167
|
+
dbs.push(db);
|
|
168
|
+
return db;
|
|
169
|
+
}
|
|
170
|
+
afterEach(() => {
|
|
171
|
+
for (const db of dbs.splice(0)) {
|
|
172
|
+
try {
|
|
173
|
+
db.close();
|
|
174
|
+
}
|
|
175
|
+
catch { /* already closed */ }
|
|
176
|
+
}
|
|
177
|
+
for (const dir of dirs.splice(0))
|
|
178
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
179
|
+
});
|
|
180
|
+
it('a successful store is queryable on disk, not just in the maps', () => {
|
|
181
|
+
const dbPath = freshDbPath();
|
|
182
|
+
const store = new TieredMemoryStore({ db: open(dbPath) });
|
|
183
|
+
const result = store.store('durable-key', 'DURABLE_VALUE', 'semantic');
|
|
184
|
+
expect(result.durable).toBe(true);
|
|
185
|
+
expect(result.persistence).toBe('sqlite');
|
|
186
|
+
// Read through an INDEPENDENT connection — proves the row is committed,
|
|
187
|
+
// not merely sitting in the writer's in-memory maps.
|
|
188
|
+
const rows = open(dbPath)
|
|
189
|
+
.prepare('SELECT key, value, tier FROM tiered_memory WHERE key = ?')
|
|
190
|
+
.all('durable-key');
|
|
191
|
+
expect(rows).toEqual([{ key: 'durable-key', value: 'DURABLE_VALUE', tier: 'semantic' }]);
|
|
192
|
+
});
|
|
193
|
+
it('rehydrates persisted entries into a brand-new store instance', () => {
|
|
194
|
+
const dbPath = freshDbPath();
|
|
195
|
+
new TieredMemoryStore({ db: open(dbPath) }).store('survives', 'ACROSS_INSTANCES', 'working');
|
|
196
|
+
const reopened = new TieredMemoryStore({ db: open(dbPath) });
|
|
197
|
+
expect(reopened.recall('ACROSS_INSTANCES')).toHaveLength(1);
|
|
198
|
+
expect(reopened.countPersisted()).toBe(1);
|
|
199
|
+
});
|
|
200
|
+
it('reports durable:false — never a bare success — when there is no backing db', () => {
|
|
201
|
+
const store = new TieredMemoryStore();
|
|
202
|
+
const result = store.store('volatile-key', 'LOST_ON_EXIT');
|
|
203
|
+
expect(store.isDurable()).toBe(false);
|
|
204
|
+
expect(result.durable).toBe(false);
|
|
205
|
+
expect(result.persistence).toBe('volatile');
|
|
206
|
+
// No table exists to count, so health checks can't be told a row landed.
|
|
207
|
+
expect(store.countPersisted()).toBeNull();
|
|
208
|
+
});
|
|
209
|
+
it('superseded entries stay auditable on disk, and removal deletes the row', () => {
|
|
210
|
+
const dbPath = freshDbPath();
|
|
211
|
+
const store = new TieredMemoryStore({ db: open(dbPath) });
|
|
212
|
+
const first = store.store('fact', 'v1', 'semantic');
|
|
213
|
+
store.store('fact', 'v2', 'semantic', { supersedes: first.id });
|
|
214
|
+
expect(store.countPersisted()).toBe(2);
|
|
215
|
+
expect(store.recall('fact', 5, { includeExpired: true })).toHaveLength(2);
|
|
216
|
+
expect(store.remove('fact')).toBe(true);
|
|
217
|
+
expect(open(dbPath).prepare('SELECT COUNT(*) AS n FROM tiered_memory WHERE archived = 0').get()).toEqual({ n: 0 });
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
//# sourceMappingURL=tiered-memory.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tiered-memory.test.js","sourceRoot":"","sources":["../src/tiered-memory.test.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -360,6 +360,12 @@ export interface MigrationConfig {
|
|
|
360
360
|
namespaceMapping?: Record<string, string>;
|
|
361
361
|
/** Type mapping */
|
|
362
362
|
typeMapping?: Record<string, MemoryType>;
|
|
363
|
+
/**
|
|
364
|
+
* Max concurrent single-entry embedding calls per migration batch when
|
|
365
|
+
* no batch embedding generator is available (default: 8). Set to 1 to
|
|
366
|
+
* restore fully sequential embedding.
|
|
367
|
+
*/
|
|
368
|
+
embeddingConcurrency?: number;
|
|
363
369
|
}
|
|
364
370
|
/**
|
|
365
371
|
* Migration progress
|
|
@@ -453,6 +459,17 @@ export interface LearningPattern {
|
|
|
453
459
|
* Embedding generator function type
|
|
454
460
|
*/
|
|
455
461
|
export type EmbeddingGenerator = (content: string) => Promise<Float32Array>;
|
|
462
|
+
/**
|
|
463
|
+
* Batch embedding generator function type.
|
|
464
|
+
*
|
|
465
|
+
* Implementations that can run a single padded forward pass over many
|
|
466
|
+
* texts (e.g. transformers.js `tokenizer(texts[])` + one model call)
|
|
467
|
+
* should be exposed through this type — it is dramatically cheaper than
|
|
468
|
+
* N sequential single-text inferences in import/migration hot paths.
|
|
469
|
+
*
|
|
470
|
+
* Contract: MUST return one embedding per input text, in input order.
|
|
471
|
+
*/
|
|
472
|
+
export type BatchEmbeddingGenerator = (contents: string[]) => Promise<Float32Array[]>;
|
|
456
473
|
/**
|
|
457
474
|
* Generates a unique memory ID
|
|
458
475
|
*/
|