@claude-flow/memory 3.0.0-alpha.21 → 3.0.0-alpha.23
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/dist/agentdb-backend.d.ts +19 -0
- package/dist/agentdb-backend.d.ts.map +1 -1
- package/dist/agentdb-backend.js +24 -3
- 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/controller-registry.d.ts +27 -5
- package/dist/controller-registry.d.ts.map +1 -1
- package/dist/controller-registry.js +113 -184
- package/dist/controller-registry.js.map +1 -1
- package/dist/controller-registry.test.js +14 -0
- package/dist/controller-registry.test.js.map +1 -1
- package/dist/graceful-retrieval.test.js +59 -0
- package/dist/graceful-retrieval.test.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- 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/smart-retrieval.test.js +3 -0
- package/dist/smart-retrieval.test.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 +4 -3
|
@@ -0,0 +1,171 @@
|
|
|
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
|
+
/** Temporal options accepted by {@link TieredMemoryStore.store}. */
|
|
37
|
+
export interface TemporalStoreOptions {
|
|
38
|
+
/** ISO-8601 timestamp from which the fact is valid (default: always). */
|
|
39
|
+
validFrom?: string;
|
|
40
|
+
/** ISO-8601 timestamp after which the fact is no longer valid. */
|
|
41
|
+
validUntil?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Id (or key) of an existing entry this fact supersedes. The old entry
|
|
44
|
+
* is stamped `validUntil = now`, `supersededBy = <new id>` and archived —
|
|
45
|
+
* never deleted.
|
|
46
|
+
*/
|
|
47
|
+
supersedes?: string;
|
|
48
|
+
}
|
|
49
|
+
/** Options accepted by {@link TieredMemoryStore.recall}. */
|
|
50
|
+
export interface TieredRecallOptions {
|
|
51
|
+
/**
|
|
52
|
+
* Include entries whose validity window has closed (superseded or
|
|
53
|
+
* expired) and entries not yet valid. Audit escape hatch — default false.
|
|
54
|
+
*/
|
|
55
|
+
includeExpired?: boolean;
|
|
56
|
+
}
|
|
57
|
+
/** A stored tiered-memory entry. */
|
|
58
|
+
export interface TieredMemoryEntry {
|
|
59
|
+
id: string;
|
|
60
|
+
key: string;
|
|
61
|
+
value: string;
|
|
62
|
+
tier: string;
|
|
63
|
+
ts: number;
|
|
64
|
+
validFrom?: string;
|
|
65
|
+
validUntil?: string;
|
|
66
|
+
supersededBy?: string;
|
|
67
|
+
}
|
|
68
|
+
/** Result of a store operation. */
|
|
69
|
+
export interface TieredStoreResult {
|
|
70
|
+
id: string;
|
|
71
|
+
key: string;
|
|
72
|
+
tier: string;
|
|
73
|
+
/** Set when `supersedes` matched an existing entry. */
|
|
74
|
+
superseded?: {
|
|
75
|
+
id: string;
|
|
76
|
+
key: string;
|
|
77
|
+
validUntil: string;
|
|
78
|
+
} | null;
|
|
79
|
+
/** True when the entry was written through to the backing SQLite table. */
|
|
80
|
+
durable: boolean;
|
|
81
|
+
/** Where the entry lives: a real table, or process memory only. */
|
|
82
|
+
persistence: TieredPersistence;
|
|
83
|
+
}
|
|
84
|
+
/** Durability mode of a {@link TieredMemoryStore}. */
|
|
85
|
+
export type TieredPersistence = 'sqlite' | 'volatile';
|
|
86
|
+
/**
|
|
87
|
+
* Minimal better-sqlite3-shaped handle. Only the calls this store makes are
|
|
88
|
+
* required, so any driver exposing the same synchronous surface works.
|
|
89
|
+
*/
|
|
90
|
+
export interface TieredMemoryDb {
|
|
91
|
+
exec(sql: string): unknown;
|
|
92
|
+
prepare(sql: string): {
|
|
93
|
+
run(...params: unknown[]): unknown;
|
|
94
|
+
all(...params: unknown[]): unknown[];
|
|
95
|
+
get(...params: unknown[]): unknown;
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Returns true when the entry is valid at `nowMs`.
|
|
100
|
+
* Entries without temporal fields are always valid (legacy behavior).
|
|
101
|
+
* Unparseable timestamps are ignored (treated as absent) rather than
|
|
102
|
+
* silently hiding the entry.
|
|
103
|
+
*/
|
|
104
|
+
export declare function isTemporallyValid(entry: Pick<TieredMemoryEntry, 'validFrom' | 'validUntil'>, nowMs?: number): boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Tier-aware in-memory store with temporal validity and per-tier size
|
|
107
|
+
* limits to prevent unbounded memory growth.
|
|
108
|
+
*/
|
|
109
|
+
export declare class TieredMemoryStore {
|
|
110
|
+
private tiers;
|
|
111
|
+
/**
|
|
112
|
+
* Superseded entries are moved here so a same-key re-store cannot
|
|
113
|
+
* clobber the historical fact. Bounded FIFO.
|
|
114
|
+
*/
|
|
115
|
+
private archived;
|
|
116
|
+
private db;
|
|
117
|
+
/**
|
|
118
|
+
* @param options.db better-sqlite3-compatible handle. When supplied the
|
|
119
|
+
* store writes through to `tiered_memory` and rehydrates from it, so
|
|
120
|
+
* entries survive the process. Without it the store is volatile and
|
|
121
|
+
* {@link isDurable} returns false — callers must treat a write as lost
|
|
122
|
+
* on exit rather than reporting success (#2887).
|
|
123
|
+
*/
|
|
124
|
+
constructor(options?: {
|
|
125
|
+
db?: TieredMemoryDb | null;
|
|
126
|
+
});
|
|
127
|
+
/** True when writes are persisted to the backing table. */
|
|
128
|
+
isDurable(): boolean;
|
|
129
|
+
/** Durability mode, for surfacing to MCP callers. */
|
|
130
|
+
getPersistence(): TieredPersistence;
|
|
131
|
+
/**
|
|
132
|
+
* Actual row count in the backing table (not the in-memory maps), so
|
|
133
|
+
* health checks can detect a claimed-write / empty-table mismatch.
|
|
134
|
+
* Returns null when volatile — there is no table to count.
|
|
135
|
+
*/
|
|
136
|
+
countPersisted(): number | null;
|
|
137
|
+
/** Load persisted rows back into the tier maps and the archive. */
|
|
138
|
+
private hydrate;
|
|
139
|
+
/**
|
|
140
|
+
* Write-through. Throws on failure so a store that cannot be persisted
|
|
141
|
+
* fails loudly instead of reporting success for a lost write.
|
|
142
|
+
*/
|
|
143
|
+
private persist;
|
|
144
|
+
/** Drop a persisted row (used by eviction and remove()). */
|
|
145
|
+
private unpersist;
|
|
146
|
+
/**
|
|
147
|
+
* Store an entry. Same-key stores within a tier overwrite (legacy
|
|
148
|
+
* behavior); use `options.supersedes` to invalidate-and-keep instead.
|
|
149
|
+
*/
|
|
150
|
+
store(key: string, value: string, tier?: string, options?: TemporalStoreOptions): TieredStoreResult;
|
|
151
|
+
/**
|
|
152
|
+
* Invalidate an existing entry (matched by id first, then by key) by
|
|
153
|
+
* stamping `validUntil = now` + `supersededBy = newId` and moving it to
|
|
154
|
+
* the archive. The entry is NOT deleted — `recall(..., { includeExpired:
|
|
155
|
+
* true })` still returns it.
|
|
156
|
+
*/
|
|
157
|
+
supersede(idOrKey: string, newId: string): TieredStoreResult['superseded'];
|
|
158
|
+
/**
|
|
159
|
+
* Substring recall across tiers, newest first. By default only
|
|
160
|
+
* temporally-valid entries are returned; pass `{ includeExpired: true }`
|
|
161
|
+
* to audit superseded / expired / future-dated facts too.
|
|
162
|
+
*/
|
|
163
|
+
recall(query: string, topK?: number, options?: TieredRecallOptions): TieredMemoryEntry[];
|
|
164
|
+
/** Hard-delete an active entry by key (used by hierarchical-delete). */
|
|
165
|
+
remove(key: string): boolean;
|
|
166
|
+
/** Per-tier active counts plus the superseded-archive size. */
|
|
167
|
+
getTierStats(): Record<string, number>;
|
|
168
|
+
private findActive;
|
|
169
|
+
}
|
|
170
|
+
export default TieredMemoryStore;
|
|
171
|
+
//# sourceMappingURL=tiered-memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tiered-memory.d.ts","sourceRoot":"","sources":["../src/tiered-memory.ts"],"names":[],"mappings":"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"}
|
|
@@ -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":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAkEH,MAAM,SAAS,GAAG;;;;;;;;;;;;;;CAcjB,CAAC;AAcF,SAAS,UAAU,CAAC,GAAoB;IACtC,MAAM,KAAK,GAAsB;QAC/B,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;KACnB,CAAC;IACF,IAAI,GAAG,CAAC,UAAU;QAAE,KAAK,CAAC,SAAS,GAAG,GAAG,CAAC,UAAU,CAAC;IACrD,IAAI,GAAG,CAAC,WAAW;QAAE,KAAK,CAAC,UAAU,GAAG,GAAG,CAAC,WAAW,CAAC;IACxD,IAAI,GAAG,CAAC,aAAa;QAAE,KAAK,CAAC,YAAY,GAAG,GAAG,CAAC,aAAa,CAAC;IAC9D,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,WAAW,GAAG,CAAC,SAAS,EAAE,UAAU,EAAE,UAAU,CAAU,CAAC;AACjE,MAAM,YAAY,GAAG,IAAI,CAAC;AAC1B,MAAM,YAAY,GAAG,IAAI,CAAC;AAC1B,MAAM,gBAAgB,GAAG,OAAO,CAAC;AACjC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAEhC,IAAI,SAAS,GAAG,CAAC,CAAC;AAClB,SAAS,MAAM;IACb,SAAS,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,gBAAgB,CAAC;IACtD,OAAO,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;AACnE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAA0D,EAC1D,QAAgB,IAAI,CAAC,GAAG,EAAE;IAE1B,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QACpB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACzC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,KAAK;YAAE,OAAO,KAAK,CAAC,CAAC,gBAAgB;IACzE,CAAC;IACD,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC3C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC,CAAC,qBAAqB;IACjF,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,OAAO,iBAAiB;IACpB,KAAK,GAAmD;QAC9D,OAAO,EAAE,IAAI,GAAG,EAAE;QAClB,QAAQ,EAAE,IAAI,GAAG,EAAE;QACnB,QAAQ,EAAE,IAAI,GAAG,EAAE;KACpB,CAAC;IAEF;;;OAGG;IACK,QAAQ,GAAwB,EAAE,CAAC;IAEnC,EAAE,GAA0B,IAAI,CAAC;IAEzC;;;;;;OAMG;IACH,YAAY,OAAwC;QAClD,MAAM,EAAE,GAAG,OAAO,EAAE,EAAE,IAAI,IAAI,CAAC;QAC/B,IAAI,CAAC,EAAE;YAAE,OAAO;QAChB,IAAI,CAAC;YACH,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACnB,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,CAAC;QAAC,MAAM,CAAC;YACP,oEAAoE;YACpE,uDAAuD;YACvD,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;QACjB,CAAC;IACH,CAAC;IAED,2DAA2D;IAC3D,SAAS;QACP,OAAO,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC;IAC1B,CAAC;IAED,qDAAqD;IACrD,cAAc;QACZ,OAAO,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC;IACzC,CAAC;IAED;;;;OAIG;IACH,cAAc;QACZ,IAAI,CAAC,IAAI,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QAC1B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,yCAAyC,CAAC,CAAC,GAAG,EAAgC,CAAC;YAC3G,OAAO,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,mEAAmE;IAC3D,OAAO;QACb,IAAI,CAAC,IAAI,CAAC,EAAE;YAAE,OAAO;QACrB,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;aACjB,OAAO,CAAC,6CAA6C,CAAC;aACtD,GAAG,EAAuB,CAAC;QAC9B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;YAC9B,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;gBACjB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC1B,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,YAAY;oBAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;gBAC/D,SAAS;YACX,CAAC;YACD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;YACzD,IAAI,GAAG,CAAC,IAAI,IAAI,YAAY;gBAAE,SAAS;YACvC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAED;;;OAGG;IACK,OAAO,CAAC,KAAwB,EAAE,QAAiB;QACzD,IAAI,CAAC,IAAI,CAAC,EAAE;YAAE,OAAO;QACrB,IAAI,CAAC,EAAE;aACJ,OAAO,CACN;;;;;gFAKwE,CACzE;aACA,GAAG,CACF,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EACtD,KAAK,CAAC,SAAS,IAAI,IAAI,EAAE,KAAK,CAAC,UAAU,IAAI,IAAI,EACjD,KAAK,CAAC,YAAY,IAAI,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAC7C,CAAC;IACN,CAAC;IAED,4DAA4D;IACpD,SAAS,CAAC,EAAU;QAC1B,IAAI,CAAC,IAAI,CAAC,EAAE;YAAE,OAAO;QACrB,IAAI,CAAC;YACH,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACpE,CAAC;QAAC,MAAM,CAAC;YACP,yEAAyE;QAC3E,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CACH,GAAW,EACX,KAAa,EACb,OAAe,SAAS,EACxB,OAA8B;QAE9B,MAAM,QAAQ,GAAI,WAAiC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QACtF,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAE/B,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;QACpB,IAAI,UAAU,GAAoC,IAAI,CAAC;QAEvD,IAAI,OAAO,EAAE,UAAU,EAAE,CAAC;YACxB,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;QACtD,CAAC;QAED,8BAA8B;QAC9B,IAAI,CAAC,CAAC,IAAI,IAAI,YAAY,EAAE,CAAC;YAC3B,MAAM,SAAS,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YACxC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;gBAC5B,MAAM,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBACjC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;gBACpB,IAAI,OAAO;oBAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;QAED,MAAM,KAAK,GAAsB;YAC/B,EAAE;YACF,GAAG;YACH,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,gBAAgB,CAAC;YAC3C,IAAI,EAAE,QAAQ;YACd,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;SACf,CAAC;QACF,IAAI,OAAO,EAAE,SAAS;YAAE,KAAK,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;QAC5D,IAAI,OAAO,EAAE,UAAU;YAAE,KAAK,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QAE/D,wEAAwE;QACxE,oEAAoE;QACpE,MAAM,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC3B,IAAI,QAAQ,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,CAAC,EAAE;YAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACtE,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAClB,OAAO;YACL,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU;YACnC,OAAO,EAAE,IAAI,CAAC,EAAE,KAAK,IAAI;YACzB,WAAW,EAAE,IAAI,CAAC,cAAc,EAAE;SACnC,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACH,SAAS,CAAC,OAAe,EAAE,KAAa;QACtC,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QAExB,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;QAC7B,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,KAAK,CAAC,UAAU,GAAG,GAAG,CAAC;QACvB,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC;QAE3B,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC1B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1B,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,YAAY,EAAE,CAAC;YACxC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;YACtC,IAAI,OAAO;gBAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC1C,CAAC;QAED,OAAO,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC;IAC3D,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,KAAa,EAAE,IAAI,GAAG,CAAC,EAAE,OAA6B;QAC3D,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;QAClD,MAAM,CAAC,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC;QAC7D,MAAM,cAAc,GAAG,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;QACxD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,OAAO,GAAwB,EAAE,CAAC;QAExC,MAAM,QAAQ,GAAG,CAAC,KAAwB,EAAW,EAAE;YACrD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnF,OAAO,KAAK,CAAC;YACf,CAAC;YACD,IAAI,CAAC,cAAc,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,GAAG,CAAC;gBAAE,OAAO,KAAK,CAAC;YACpE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpB,OAAO,IAAI,CAAC;QACd,CAAC,CAAC;QAEF,KAAK,EAAE,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACnD,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC;gBACjC,QAAQ,CAAC,KAAK,CAAC,CAAC;gBAChB,IAAI,OAAO,CAAC,MAAM,IAAI,QAAQ,GAAG,CAAC;oBAAE,MAAM,KAAK,CAAC,CAAC,8BAA8B;YACjF,CAAC;QACH,CAAC;QAED,IAAI,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,QAAQ,GAAG,CAAC,EAAE,CAAC;YACpD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClC,QAAQ,CAAC,KAAK,CAAC,CAAC;gBAChB,IAAI,OAAO,CAAC,MAAM,IAAI,QAAQ,GAAG,CAAC;oBAAE,MAAM;YAC5C,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAChE,CAAC;IAED,wEAAwE;IACxE,MAAM,CAAC,GAAW;QAChB,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5C,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC3B,IAAI,CAAC,KAAK;gBAAE,SAAS;YACrB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAChB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACzB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,+DAA+D;IAC/D,YAAY;QACV,MAAM,KAAK,GAA2B,EAAE,CAAC;QACzC,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACrD,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC;QACzB,CAAC;QACD,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QACxC,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,UAAU,CAChB,OAAe;QAEf,8DAA8D;QAC9D,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5C,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC;gBACjC,IAAI,KAAK,CAAC,EAAE,KAAK,OAAO;oBAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;YAClD,CAAC;QACH,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5C,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAC/B,IAAI,KAAK;gBAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;QACnC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAED,eAAe,iBAAiB,CAAC"}
|
|
@@ -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"}
|