adaptive-context-memory 1.0.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 +104 -0
- package/dist/core/llmClient.d.ts +14 -0
- package/dist/core/llmClient.d.ts.map +1 -0
- package/dist/core/llmClient.js +68 -0
- package/dist/core/llmClient.js.map +1 -0
- package/dist/core/retry.d.ts +21 -0
- package/dist/core/retry.d.ts.map +1 -0
- package/dist/core/retry.js +68 -0
- package/dist/core/retry.js.map +1 -0
- package/dist/core/settings.d.ts +46 -0
- package/dist/core/settings.d.ts.map +1 -0
- package/dist/core/settings.js +133 -0
- package/dist/core/settings.js.map +1 -0
- package/dist/db/database.d.ts +50 -0
- package/dist/db/database.d.ts.map +1 -0
- package/dist/db/database.js +157 -0
- package/dist/db/database.js.map +1 -0
- package/dist/demo.d.ts +16 -0
- package/dist/demo.d.ts.map +1 -0
- package/dist/demo.js +305 -0
- package/dist/demo.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/memory/add/extractionPhase.d.ts +17 -0
- package/dist/memory/add/extractionPhase.d.ts.map +1 -0
- package/dist/memory/add/extractionPhase.js +48 -0
- package/dist/memory/add/extractionPhase.js.map +1 -0
- package/dist/memory/add/updatePhase.d.ts +11 -0
- package/dist/memory/add/updatePhase.d.ts.map +1 -0
- package/dist/memory/add/updatePhase.js +133 -0
- package/dist/memory/add/updatePhase.js.map +1 -0
- package/dist/memory/bubbleCreator.d.ts +10 -0
- package/dist/memory/bubbleCreator.d.ts.map +1 -0
- package/dist/memory/bubbleCreator.js +46 -0
- package/dist/memory/bubbleCreator.js.map +1 -0
- package/dist/memory/connectionFinder.d.ts +14 -0
- package/dist/memory/connectionFinder.d.ts.map +1 -0
- package/dist/memory/connectionFinder.js +56 -0
- package/dist/memory/connectionFinder.js.map +1 -0
- package/dist/memory/embeddings.d.ts +27 -0
- package/dist/memory/embeddings.d.ts.map +1 -0
- package/dist/memory/embeddings.js +145 -0
- package/dist/memory/embeddings.js.map +1 -0
- package/dist/memory/extractor.d.ts +20 -0
- package/dist/memory/extractor.d.ts.map +1 -0
- package/dist/memory/extractor.js +60 -0
- package/dist/memory/extractor.js.map +1 -0
- package/dist/memory/memory.d.ts +80 -0
- package/dist/memory/memory.d.ts.map +1 -0
- package/dist/memory/memory.js +342 -0
- package/dist/memory/memory.js.map +1 -0
- package/dist/memory/toolClassifier.d.ts +13 -0
- package/dist/memory/toolClassifier.d.ts.map +1 -0
- package/dist/memory/toolClassifier.js +53 -0
- package/dist/memory/toolClassifier.js.map +1 -0
- package/dist/memory/vectorStore.d.ts +40 -0
- package/dist/memory/vectorStore.d.ts.map +1 -0
- package/dist/memory/vectorStore.js +168 -0
- package/dist/memory/vectorStore.js.map +1 -0
- package/dist/summary/summaryGenerator.d.ts +14 -0
- package/dist/summary/summaryGenerator.d.ts.map +1 -0
- package/dist/summary/summaryGenerator.js +66 -0
- package/dist/summary/summaryGenerator.js.map +1 -0
- package/dist/utils/prompts.d.ts +7 -0
- package/dist/utils/prompts.d.ts.map +1 -0
- package/dist/utils/prompts.js +133 -0
- package/dist/utils/prompts.js.map +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ContextMemory v2 — Main class with upgraded search + new utilities.
|
|
3
|
+
*
|
|
4
|
+
* New in v2:
|
|
5
|
+
* - MMR search (Maximum Marginal Relevance) — diverse, non-redundant results
|
|
6
|
+
* - search() accepts filter by category
|
|
7
|
+
* - consolidate() — merge near-duplicate semantic memories via LLM
|
|
8
|
+
* - purgeOldBubbles() — soft-delete episodic bubbles older than N days
|
|
9
|
+
* - getStats() — memory count breakdown
|
|
10
|
+
* - embedText cached (via upgraded embeddings.ts)
|
|
11
|
+
*/
|
|
12
|
+
import type Database from "better-sqlite3";
|
|
13
|
+
import { type ChatMessage } from "./add/extractionPhase.js";
|
|
14
|
+
import { type MemoryRow } from "../db/database.js";
|
|
15
|
+
export interface MemoryResult {
|
|
16
|
+
memoryId: number;
|
|
17
|
+
memory: string;
|
|
18
|
+
type: "semantic" | "bubble" | "connected";
|
|
19
|
+
category: string | null;
|
|
20
|
+
occurredAt: string | null;
|
|
21
|
+
score: number;
|
|
22
|
+
connections: number[];
|
|
23
|
+
}
|
|
24
|
+
export interface SearchResponse {
|
|
25
|
+
query: string;
|
|
26
|
+
total: number;
|
|
27
|
+
results: MemoryResult[];
|
|
28
|
+
}
|
|
29
|
+
export interface AddResponse {
|
|
30
|
+
semantic: string[];
|
|
31
|
+
bubbles: string[];
|
|
32
|
+
}
|
|
33
|
+
export interface SearchOptions {
|
|
34
|
+
limit?: number;
|
|
35
|
+
includeConnections?: boolean;
|
|
36
|
+
/** Filter results to a specific category: 'profile'|'skill'|'preference'|... */
|
|
37
|
+
category?: string;
|
|
38
|
+
/** 0.0 = pure similarity, 1.0 = pure diversity. Default 0.5 */
|
|
39
|
+
mmrLambda?: number;
|
|
40
|
+
/** Disable MMR for raw similarity ranking */
|
|
41
|
+
disableMmr?: boolean;
|
|
42
|
+
}
|
|
43
|
+
export interface MemoryStats {
|
|
44
|
+
total: number;
|
|
45
|
+
semantic: number;
|
|
46
|
+
bubbles: number;
|
|
47
|
+
byCategory: Record<string, number>;
|
|
48
|
+
}
|
|
49
|
+
export declare class ContextMemory {
|
|
50
|
+
private db;
|
|
51
|
+
constructor(db: Database.Database);
|
|
52
|
+
add(messages: ChatMessage[], conversationId: number): Promise<AddResponse>;
|
|
53
|
+
/**
|
|
54
|
+
* Semantic search with MMR re-ranking for diverse, relevant results.
|
|
55
|
+
*/
|
|
56
|
+
search(query: string, conversationId: number, opts?: SearchOptions): Promise<SearchResponse>;
|
|
57
|
+
update(memoryId: number, text: string): Promise<MemoryRow>;
|
|
58
|
+
delete(memoryId: number): {
|
|
59
|
+
deletedMemoryId: number;
|
|
60
|
+
};
|
|
61
|
+
getAll(conversationId: number, category?: string): MemoryRow[];
|
|
62
|
+
/** Returns a breakdown of memory counts for a conversation. */
|
|
63
|
+
getStats(conversationId: number): MemoryStats;
|
|
64
|
+
/**
|
|
65
|
+
* Soft-delete episodic bubbles older than `olderThanDays` days.
|
|
66
|
+
* Returns the number of bubbles deactivated.
|
|
67
|
+
*/
|
|
68
|
+
purgeOldBubbles(conversationId: number, olderThanDays?: number): number;
|
|
69
|
+
/**
|
|
70
|
+
* Find clusters of highly-similar semantic memories and ask the LLM to
|
|
71
|
+
* merge them into a single, comprehensive fact.
|
|
72
|
+
*
|
|
73
|
+
* Only runs on semantic memories (not bubbles).
|
|
74
|
+
* Threshold: cosine similarity > 0.88 → candidate for merging.
|
|
75
|
+
*
|
|
76
|
+
* Returns the number of memories consolidated.
|
|
77
|
+
*/
|
|
78
|
+
consolidate(conversationId: number, threshold?: number): Promise<number>;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/memory/memory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAmB,KAAK,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAY7E,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAG9D,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,UAAU,GAAG,QAAQ,GAAG,WAAW,CAAC;IAC1C,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,gFAAgF;IAChF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AA4DD,qBAAa,aAAa;IACxB,OAAO,CAAC,EAAE,CAAoB;gBAElB,EAAE,EAAE,QAAQ,CAAC,QAAQ;IAK3B,GAAG,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAiBhF;;OAEG;IACG,MAAM,CACV,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,MAAM,EACtB,IAAI,GAAE,aAAkB,GACvB,OAAO,CAAC,cAAc,CAAC;IA6GpB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAkBhE,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG;QAAE,eAAe,EAAE,MAAM,CAAA;KAAE;IAarD,MAAM,CAAC,cAAc,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE;IAQ9D,+DAA+D;IAC/D,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,WAAW;IAoB7C;;;OAGG;IACH,eAAe,CAAC,cAAc,EAAE,MAAM,EAAE,aAAa,SAAK,GAAG,MAAM;IAsBnE;;;;;;;;OAQG;IACG,WAAW,CAAC,cAAc,EAAE,MAAM,EAAE,SAAS,SAAO,GAAG,OAAO,CAAC,MAAM,CAAC;CAmG7E"}
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ContextMemory v2 — Main class with upgraded search + new utilities.
|
|
4
|
+
*
|
|
5
|
+
* New in v2:
|
|
6
|
+
* - MMR search (Maximum Marginal Relevance) — diverse, non-redundant results
|
|
7
|
+
* - search() accepts filter by category
|
|
8
|
+
* - consolidate() — merge near-duplicate semantic memories via LLM
|
|
9
|
+
* - purgeOldBubbles() — soft-delete episodic bubbles older than N days
|
|
10
|
+
* - getStats() — memory count breakdown
|
|
11
|
+
* - embedText cached (via upgraded embeddings.ts)
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.ContextMemory = void 0;
|
|
15
|
+
const extractionPhase_js_1 = require("./add/extractionPhase.js");
|
|
16
|
+
const updatePhase_js_1 = require("./add/updatePhase.js");
|
|
17
|
+
const bubbleCreator_js_1 = require("./bubbleCreator.js");
|
|
18
|
+
const embeddings_js_1 = require("./embeddings.js");
|
|
19
|
+
const llmClient_js_1 = require("../core/llmClient.js");
|
|
20
|
+
const settings_js_1 = require("../core/settings.js");
|
|
21
|
+
const retry_js_1 = require("../core/retry.js");
|
|
22
|
+
const vectorStore_js_1 = require("./vectorStore.js");
|
|
23
|
+
const database_js_1 = require("../db/database.js");
|
|
24
|
+
// ─── MMR (Maximum Marginal Relevance) ────────────────────────────────────────
|
|
25
|
+
/**
|
|
26
|
+
* Re-ranks a candidate set to balance relevance vs. diversity.
|
|
27
|
+
* Prevents returning 5 near-identical memories — ensures each result
|
|
28
|
+
* adds new information.
|
|
29
|
+
*
|
|
30
|
+
* Algorithm:
|
|
31
|
+
* Selected = {}
|
|
32
|
+
* For each step: pick candidate c that maximises:
|
|
33
|
+
* λ * sim(c, query) − (1−λ) * max_{s∈Selected} sim(c, s)
|
|
34
|
+
*
|
|
35
|
+
* λ=1 → pure similarity ranking
|
|
36
|
+
* λ=0 → pure diversity (greedy)
|
|
37
|
+
* λ=0.5 → balanced (recommended)
|
|
38
|
+
*/
|
|
39
|
+
function mmrRerank(candidates, lambda, k) {
|
|
40
|
+
if (candidates.length <= 1)
|
|
41
|
+
return candidates;
|
|
42
|
+
function dot(a, b) {
|
|
43
|
+
let s = 0;
|
|
44
|
+
for (let i = 0; i < a.length; i++)
|
|
45
|
+
s += a[i] * b[i];
|
|
46
|
+
return s;
|
|
47
|
+
}
|
|
48
|
+
const selected = [];
|
|
49
|
+
const remaining = [...candidates];
|
|
50
|
+
while (selected.length < k && remaining.length > 0) {
|
|
51
|
+
let bestIdx = 0;
|
|
52
|
+
let bestScore = -Infinity;
|
|
53
|
+
for (let i = 0; i < remaining.length; i++) {
|
|
54
|
+
const c = remaining[i];
|
|
55
|
+
const relevance = lambda * c.simScore;
|
|
56
|
+
const redundancy = selected.length === 0
|
|
57
|
+
? 0
|
|
58
|
+
: (1 - lambda) * Math.max(...selected.map((s) => dot(c.embedding, s.embedding)));
|
|
59
|
+
const mmrScore = relevance - redundancy;
|
|
60
|
+
if (mmrScore > bestScore) {
|
|
61
|
+
bestScore = mmrScore;
|
|
62
|
+
bestIdx = i;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
selected.push(remaining[bestIdx]);
|
|
66
|
+
remaining.splice(bestIdx, 1);
|
|
67
|
+
}
|
|
68
|
+
return selected;
|
|
69
|
+
}
|
|
70
|
+
// ─── ContextMemory class ──────────────────────────────────────────────────────
|
|
71
|
+
class ContextMemory {
|
|
72
|
+
db;
|
|
73
|
+
constructor(db) {
|
|
74
|
+
this.db = db;
|
|
75
|
+
}
|
|
76
|
+
// ─── add() ─────────────────────────────────────────────────────────────────
|
|
77
|
+
async add(messages, conversationId) {
|
|
78
|
+
const extracted = await (0, extractionPhase_js_1.extractionPhase)(this.db, messages, conversationId);
|
|
79
|
+
if (extracted.semantic.length > 0) {
|
|
80
|
+
await (0, updatePhase_js_1.updatePhase)(this.db, extracted.semantic, conversationId);
|
|
81
|
+
}
|
|
82
|
+
if (extracted.bubbles.length > 0) {
|
|
83
|
+
await (0, bubbleCreator_js_1.createBubbles)(this.db, extracted.bubbles, conversationId, null);
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
semantic: extracted.semantic,
|
|
87
|
+
bubbles: extracted.bubbles.map((b) => b.text),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
// ─── search() ──────────────────────────────────────────────────────────────
|
|
91
|
+
/**
|
|
92
|
+
* Semantic search with MMR re-ranking for diverse, relevant results.
|
|
93
|
+
*/
|
|
94
|
+
async search(query, conversationId, opts = {}) {
|
|
95
|
+
const { limit = 10, includeConnections = true, category, mmrLambda = 0.6, disableMmr = false, } = opts;
|
|
96
|
+
const queryEmbedding = await (0, embeddings_js_1.embedText)(query);
|
|
97
|
+
let store = (0, vectorStore_js_1.getVectorStore)(conversationId);
|
|
98
|
+
if (store.count === 0)
|
|
99
|
+
store = (0, vectorStore_js_1.rebuildIndexFromDb)(this.db, conversationId);
|
|
100
|
+
// Fetch more candidates than needed so MMR has room to diversify
|
|
101
|
+
const rawResults = store.search(queryEmbedding, limit * 3);
|
|
102
|
+
if (rawResults.length === 0)
|
|
103
|
+
return { query, total: 0, results: [] };
|
|
104
|
+
const ids = rawResults.map((r) => r.memoryId);
|
|
105
|
+
const placeholders = ids.map(() => "?").join(",");
|
|
106
|
+
let sql = `SELECT * FROM memories WHERE id IN (${placeholders}) AND is_active = 1`;
|
|
107
|
+
if (category)
|
|
108
|
+
sql += ` AND category = '${category.replace(/'/g, "''")}'`;
|
|
109
|
+
const memories = this.db.prepare(sql).all(...ids);
|
|
110
|
+
if (memories.length === 0)
|
|
111
|
+
return { query, total: 0, results: [] };
|
|
112
|
+
const scoreMap = new Map(rawResults.map((r) => [r.memoryId, r.score]));
|
|
113
|
+
const now = Date.now();
|
|
114
|
+
// Build scored candidates with embeddings for MMR
|
|
115
|
+
const candidates = memories.map((mem) => {
|
|
116
|
+
const similarity = scoreMap.get(mem.id) ?? 0;
|
|
117
|
+
// Recency decay for episodic bubbles (exponential, half-life ~14 days)
|
|
118
|
+
let recency = 1.0;
|
|
119
|
+
if (mem.is_episodic && mem.occurred_at) {
|
|
120
|
+
const daysAgo = (now - new Date(mem.occurred_at).getTime()) / 86_400_000;
|
|
121
|
+
recency = Math.exp(-0.05 * daysAgo);
|
|
122
|
+
}
|
|
123
|
+
const importance = mem.importance ?? 0.5;
|
|
124
|
+
const compositeScore = similarity * Math.sqrt(importance) * recency;
|
|
125
|
+
// Parse stored embedding for MMR diversity calculation
|
|
126
|
+
let embedding = [];
|
|
127
|
+
try {
|
|
128
|
+
embedding = mem.embedding ? JSON.parse(mem.embedding) : [];
|
|
129
|
+
}
|
|
130
|
+
catch { /* use empty */ }
|
|
131
|
+
return { mem, simScore: compositeScore, embedding };
|
|
132
|
+
});
|
|
133
|
+
// MMR re-ranking (or plain sort if disabled)
|
|
134
|
+
const ranked = disableMmr
|
|
135
|
+
? candidates.sort((a, b) => b.simScore - a.simScore).slice(0, limit)
|
|
136
|
+
: mmrRerank(candidates, mmrLambda, limit);
|
|
137
|
+
// Collect connected bubbles
|
|
138
|
+
const resultIds = new Set(ranked.map(({ mem }) => mem.id));
|
|
139
|
+
const connected = [];
|
|
140
|
+
if (includeConnections) {
|
|
141
|
+
for (const { mem } of ranked) {
|
|
142
|
+
const meta = (0, database_js_1.parseMeta)(mem);
|
|
143
|
+
for (const connId of (meta.connections?.bubble_ids ?? []).slice(0, 2)) {
|
|
144
|
+
if (!resultIds.has(connId)) {
|
|
145
|
+
const connMem = this.db
|
|
146
|
+
.prepare("SELECT * FROM memories WHERE id = ? AND is_active = 1")
|
|
147
|
+
.get(connId);
|
|
148
|
+
if (connMem) {
|
|
149
|
+
connected.push(connMem);
|
|
150
|
+
resultIds.add(connId);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// Format
|
|
157
|
+
const results = ranked.map(({ mem, simScore }) => {
|
|
158
|
+
const meta = (0, database_js_1.parseMeta)(mem);
|
|
159
|
+
return {
|
|
160
|
+
memoryId: mem.id,
|
|
161
|
+
memory: mem.memory_text,
|
|
162
|
+
type: mem.is_episodic ? "bubble" : "semantic",
|
|
163
|
+
category: mem.category ?? null,
|
|
164
|
+
occurredAt: mem.occurred_at ?? null,
|
|
165
|
+
score: Math.round(simScore * 10000) / 10000,
|
|
166
|
+
connections: meta.connections?.bubble_ids ?? [],
|
|
167
|
+
};
|
|
168
|
+
});
|
|
169
|
+
for (const conn of connected.slice(0, 3)) {
|
|
170
|
+
results.push({
|
|
171
|
+
memoryId: conn.id,
|
|
172
|
+
memory: conn.memory_text,
|
|
173
|
+
type: "connected",
|
|
174
|
+
category: conn.category ?? null,
|
|
175
|
+
occurredAt: conn.occurred_at ?? null,
|
|
176
|
+
score: 0,
|
|
177
|
+
connections: [],
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
return { query, total: results.length, results };
|
|
181
|
+
}
|
|
182
|
+
// ─── update() ──────────────────────────────────────────────────────────────
|
|
183
|
+
async update(memoryId, text) {
|
|
184
|
+
const mem = this.db.prepare("SELECT * FROM memories WHERE id = ?").get(memoryId);
|
|
185
|
+
if (!mem)
|
|
186
|
+
throw new Error(`Memory ${memoryId} not found`);
|
|
187
|
+
const newEmbedding = await (0, embeddings_js_1.embedText)(text);
|
|
188
|
+
const now = new Date().toISOString();
|
|
189
|
+
this.db
|
|
190
|
+
.prepare("UPDATE memories SET memory_text = ?, embedding = ?, updated_at = ? WHERE id = ?")
|
|
191
|
+
.run(text, JSON.stringify(newEmbedding), now, memoryId);
|
|
192
|
+
const store = (0, vectorStore_js_1.getVectorStore)(mem.conversation_id);
|
|
193
|
+
store.update(memoryId, newEmbedding);
|
|
194
|
+
(0, vectorStore_js_1.saveVectorStore)(mem.conversation_id);
|
|
195
|
+
return this.db.prepare("SELECT * FROM memories WHERE id = ?").get(memoryId);
|
|
196
|
+
}
|
|
197
|
+
// ─── delete() ──────────────────────────────────────────────────────────────
|
|
198
|
+
delete(memoryId) {
|
|
199
|
+
const mem = this.db.prepare("SELECT * FROM memories WHERE id = ?").get(memoryId);
|
|
200
|
+
if (!mem)
|
|
201
|
+
throw new Error(`Memory ${memoryId} not found`);
|
|
202
|
+
this.db.prepare("UPDATE memories SET is_active = 0 WHERE id = ?").run(memoryId);
|
|
203
|
+
const store = (0, vectorStore_js_1.getVectorStore)(mem.conversation_id);
|
|
204
|
+
store.remove(memoryId);
|
|
205
|
+
(0, vectorStore_js_1.saveVectorStore)(mem.conversation_id);
|
|
206
|
+
return { deletedMemoryId: memoryId };
|
|
207
|
+
}
|
|
208
|
+
// ─── getAll() ──────────────────────────────────────────────────────────────
|
|
209
|
+
getAll(conversationId, category) {
|
|
210
|
+
let sql = "SELECT * FROM memories WHERE conversation_id = ? AND is_active = 1";
|
|
211
|
+
if (category)
|
|
212
|
+
sql += ` AND category = '${category.replace(/'/g, "''")}'`;
|
|
213
|
+
sql += " ORDER BY created_at DESC";
|
|
214
|
+
return this.db.prepare(sql).all(conversationId);
|
|
215
|
+
}
|
|
216
|
+
// ─── getStats() ────────────────────────────────────────────────────────────
|
|
217
|
+
/** Returns a breakdown of memory counts for a conversation. */
|
|
218
|
+
getStats(conversationId) {
|
|
219
|
+
const all = this.db
|
|
220
|
+
.prepare("SELECT * FROM memories WHERE conversation_id = ? AND is_active = 1")
|
|
221
|
+
.all(conversationId);
|
|
222
|
+
const byCategory = {};
|
|
223
|
+
for (const m of all) {
|
|
224
|
+
const cat = m.category ?? "uncategorized";
|
|
225
|
+
byCategory[cat] = (byCategory[cat] ?? 0) + 1;
|
|
226
|
+
}
|
|
227
|
+
return {
|
|
228
|
+
total: all.length,
|
|
229
|
+
semantic: all.filter((m) => !m.is_episodic).length,
|
|
230
|
+
bubbles: all.filter((m) => m.is_episodic).length,
|
|
231
|
+
byCategory,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
// ─── purgeOldBubbles() ─────────────────────────────────────────────────────
|
|
235
|
+
/**
|
|
236
|
+
* Soft-delete episodic bubbles older than `olderThanDays` days.
|
|
237
|
+
* Returns the number of bubbles deactivated.
|
|
238
|
+
*/
|
|
239
|
+
purgeOldBubbles(conversationId, olderThanDays = 30) {
|
|
240
|
+
const cutoff = new Date(Date.now() - olderThanDays * 86_400_000).toISOString();
|
|
241
|
+
const res = this.db
|
|
242
|
+
.prepare(`UPDATE memories
|
|
243
|
+
SET is_active = 0
|
|
244
|
+
WHERE conversation_id = ? AND is_episodic = 1 AND is_active = 1
|
|
245
|
+
AND occurred_at < ?`)
|
|
246
|
+
.run(conversationId, cutoff);
|
|
247
|
+
const count = res.changes;
|
|
248
|
+
if (count > 0) {
|
|
249
|
+
// Rebuild vector store to remove purged bubbles
|
|
250
|
+
(0, vectorStore_js_1.rebuildIndexFromDb)(this.db, conversationId);
|
|
251
|
+
const s = (0, settings_js_1.getSettings)();
|
|
252
|
+
if (s.debug)
|
|
253
|
+
console.log(`[ContextMemory] Purged ${count} old bubbles (>${olderThanDays}d)`);
|
|
254
|
+
}
|
|
255
|
+
return count;
|
|
256
|
+
}
|
|
257
|
+
// ─── consolidate() ─────────────────────────────────────────────────────────
|
|
258
|
+
/**
|
|
259
|
+
* Find clusters of highly-similar semantic memories and ask the LLM to
|
|
260
|
+
* merge them into a single, comprehensive fact.
|
|
261
|
+
*
|
|
262
|
+
* Only runs on semantic memories (not bubbles).
|
|
263
|
+
* Threshold: cosine similarity > 0.88 → candidate for merging.
|
|
264
|
+
*
|
|
265
|
+
* Returns the number of memories consolidated.
|
|
266
|
+
*/
|
|
267
|
+
async consolidate(conversationId, threshold = 0.88) {
|
|
268
|
+
const s = (0, settings_js_1.getSettings)();
|
|
269
|
+
const client = (0, llmClient_js_1.getLlmClient)();
|
|
270
|
+
const store = (0, vectorStore_js_1.getVectorStore)(conversationId);
|
|
271
|
+
const semanticMemories = this.db
|
|
272
|
+
.prepare(`SELECT * FROM memories
|
|
273
|
+
WHERE conversation_id = ? AND is_episodic = 0 AND is_active = 1`)
|
|
274
|
+
.all(conversationId);
|
|
275
|
+
if (semanticMemories.length < 2)
|
|
276
|
+
return 0;
|
|
277
|
+
const visited = new Set();
|
|
278
|
+
let consolidatedCount = 0;
|
|
279
|
+
for (const mem of semanticMemories) {
|
|
280
|
+
if (visited.has(mem.id) || !mem.embedding)
|
|
281
|
+
continue;
|
|
282
|
+
const embedding = JSON.parse(mem.embedding);
|
|
283
|
+
const similar = store.search(embedding, 5);
|
|
284
|
+
const cluster = similar
|
|
285
|
+
.filter((r) => r.memoryId !== mem.id && r.score >= threshold)
|
|
286
|
+
.filter((r) => !visited.has(r.memoryId));
|
|
287
|
+
if (cluster.length === 0)
|
|
288
|
+
continue;
|
|
289
|
+
const clusterMemories = cluster
|
|
290
|
+
.map((r) => this.db.prepare("SELECT * FROM memories WHERE id = ?").get(r.memoryId))
|
|
291
|
+
.filter((m) => m != null && m.is_active === 1 && !m.is_episodic);
|
|
292
|
+
if (clusterMemories.length === 0)
|
|
293
|
+
continue;
|
|
294
|
+
const allFacts = [mem, ...clusterMemories];
|
|
295
|
+
const factsList = allFacts.map((m) => `- ${m.memory_text}`).join("\n");
|
|
296
|
+
if (s.debug)
|
|
297
|
+
console.log(`[ContextMemory] Consolidating cluster of ${allFacts.length} memories`);
|
|
298
|
+
// Ask LLM to produce a single merged fact
|
|
299
|
+
const response = await (0, retry_js_1.withRetry)(() => client.chat.completions.create({
|
|
300
|
+
model: s.llmModel,
|
|
301
|
+
messages: [
|
|
302
|
+
{
|
|
303
|
+
role: "system",
|
|
304
|
+
content: "You merge similar memory facts into one comprehensive, concise fact. Start with 'User'. Return ONLY the merged fact text, no explanation.",
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
role: "user",
|
|
308
|
+
content: `Merge these similar facts about the same user into ONE comprehensive fact:\n\n${factsList}\n\nMerged fact:`,
|
|
309
|
+
},
|
|
310
|
+
],
|
|
311
|
+
temperature: 0,
|
|
312
|
+
}));
|
|
313
|
+
const mergedText = (response.choices[0].message.content ?? "").trim();
|
|
314
|
+
if (!mergedText)
|
|
315
|
+
continue;
|
|
316
|
+
const mergedEmbedding = await (0, embeddings_js_1.embedText)(mergedText);
|
|
317
|
+
const now = new Date().toISOString();
|
|
318
|
+
// Deactivate all old memories in the cluster
|
|
319
|
+
const tx = this.db.transaction(() => {
|
|
320
|
+
for (const m of allFacts) {
|
|
321
|
+
this.db.prepare("UPDATE memories SET is_active = 0 WHERE id = ?").run(m.id);
|
|
322
|
+
store.remove(m.id);
|
|
323
|
+
visited.add(m.id);
|
|
324
|
+
}
|
|
325
|
+
// Insert merged memory
|
|
326
|
+
const res = this.db
|
|
327
|
+
.prepare(`INSERT INTO memories
|
|
328
|
+
(conversation_id, memory_text, embedding, category, is_episodic, importance, is_active, created_at, updated_at)
|
|
329
|
+
VALUES (?, ?, ?, ?, 0, 0.7, 1, ?, ?)`)
|
|
330
|
+
.run(conversationId, mergedText, JSON.stringify(mergedEmbedding), allFacts[0].category ?? null, now, now);
|
|
331
|
+
store.add(res.lastInsertRowid, mergedEmbedding);
|
|
332
|
+
});
|
|
333
|
+
tx();
|
|
334
|
+
consolidatedCount += allFacts.length - 1; // net reduction
|
|
335
|
+
}
|
|
336
|
+
if (consolidatedCount > 0)
|
|
337
|
+
(0, vectorStore_js_1.saveVectorStore)(conversationId);
|
|
338
|
+
return consolidatedCount;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
exports.ContextMemory = ContextMemory;
|
|
342
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/memory/memory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Classifier v2 — with retry wrapper + category detection.
|
|
3
|
+
*/
|
|
4
|
+
import type { MemoryRow } from "../db/database.js";
|
|
5
|
+
export type MemoryAction = "ADD" | "UPDATE" | "REPLACE" | "DELETE" | "NOOP";
|
|
6
|
+
export interface ToolDecision {
|
|
7
|
+
action: MemoryAction;
|
|
8
|
+
memoryId: number | null;
|
|
9
|
+
text: string | null;
|
|
10
|
+
category: string | null;
|
|
11
|
+
}
|
|
12
|
+
export declare function llmToolCall(candidateFact: string, similarMemories: MemoryRow[]): Promise<ToolDecision>;
|
|
13
|
+
//# sourceMappingURL=toolClassifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolClassifier.d.ts","sourceRoot":"","sources":["../../src/memory/toolClassifier.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnD,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE5E,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AA+BD,wBAAsB,WAAW,CAC/B,aAAa,EAAE,MAAM,EACrB,eAAe,EAAE,SAAS,EAAE,GAC3B,OAAO,CAAC,YAAY,CAAC,CAyBvB"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Tool Classifier v2 — with retry wrapper + category detection.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.llmToolCall = llmToolCall;
|
|
7
|
+
const llmClient_js_1 = require("../core/llmClient.js");
|
|
8
|
+
const settings_js_1 = require("../core/settings.js");
|
|
9
|
+
const retry_js_1 = require("../core/retry.js");
|
|
10
|
+
const prompts_js_1 = require("../utils/prompts.js");
|
|
11
|
+
function parseDecision(raw, fallbackText, debug) {
|
|
12
|
+
let str = raw.trim();
|
|
13
|
+
const fence = str.match(/```(?:json)?\s*([\s\S]*?)\s*```/);
|
|
14
|
+
if (fence)
|
|
15
|
+
str = fence[1].trim();
|
|
16
|
+
try {
|
|
17
|
+
const parsed = JSON.parse(str);
|
|
18
|
+
const action = (parsed.action?.toUpperCase() ?? "ADD");
|
|
19
|
+
const validActions = ["ADD", "UPDATE", "REPLACE", "DELETE", "NOOP"];
|
|
20
|
+
const safeAction = validActions.includes(action) ? action : "ADD";
|
|
21
|
+
return {
|
|
22
|
+
action: safeAction,
|
|
23
|
+
memoryId: parsed.memory_id ?? null,
|
|
24
|
+
text: parsed.text ?? fallbackText,
|
|
25
|
+
category: parsed.category ?? null,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
catch (e) {
|
|
29
|
+
if (debug)
|
|
30
|
+
console.log("[ContextMemory] Tool classifier parse error:", e);
|
|
31
|
+
return { action: "ADD", memoryId: null, text: fallbackText, category: null };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async function llmToolCall(candidateFact, similarMemories) {
|
|
35
|
+
const s = (0, settings_js_1.getSettings)();
|
|
36
|
+
const client = (0, llmClient_js_1.getLlmClient)();
|
|
37
|
+
const memoryContext = similarMemories.length > 0
|
|
38
|
+
? similarMemories.map((m) => `- ID ${m.id} [${m.category ?? "?"}]: ${m.memory_text}`).join("\n")
|
|
39
|
+
: "No existing memories found.";
|
|
40
|
+
const messages = [
|
|
41
|
+
{ role: "system", content: prompts_js_1.TOOL_CALL_SYSTEM_PROMPT },
|
|
42
|
+
{
|
|
43
|
+
role: "user",
|
|
44
|
+
content: `Candidate fact:\n${candidateFact}\n\nExisting similar memories:\n${memoryContext}\n\nDecide the action.`,
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
const response = await (0, retry_js_1.withRetry)(() => client.chat.completions.create({ model: s.llmModel, messages, temperature: 0 }));
|
|
48
|
+
const raw = response.choices[0].message.content ?? "";
|
|
49
|
+
if (s.debug)
|
|
50
|
+
console.log("[ContextMemory] Tool classifier output:", raw);
|
|
51
|
+
return parseDecision(raw, candidateFact, s.debug);
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=toolClassifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolClassifier.js","sourceRoot":"","sources":["../../src/memory/toolClassifier.ts"],"names":[],"mappings":";AAAA;;GAEG;;AA8CH,kCA4BC;AAxED,uDAAoD;AACpD,qDAAkD;AAClD,+CAA6C;AAC7C,oDAA8D;AAY9D,SAAS,aAAa,CAAC,GAAW,EAAE,YAAoB,EAAE,KAAc;IACtE,IAAI,GAAG,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACrB,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;IAC3D,IAAI,KAAK;QAAE,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAEjC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAK5B,CAAC;QAEF,MAAM,MAAM,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,KAAK,CAAiB,CAAC;QACvE,MAAM,YAAY,GAAmB,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;QACpF,MAAM,UAAU,GAAG,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;QAElE,OAAO;YACL,MAAM,EAAE,UAAU;YAClB,QAAQ,EAAE,MAAM,CAAC,SAAS,IAAI,IAAI;YAClC,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,YAAY;YACjC,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,IAAI;SAClC,CAAC;IACJ,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,KAAK;YAAE,OAAO,CAAC,GAAG,CAAC,8CAA8C,EAAE,CAAC,CAAC,CAAC;QAC1E,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC/E,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,WAAW,CAC/B,aAAqB,EACrB,eAA4B;IAE5B,MAAM,CAAC,GAAG,IAAA,yBAAW,GAAE,CAAC;IACxB,MAAM,MAAM,GAAG,IAAA,2BAAY,GAAE,CAAC;IAE9B,MAAM,aAAa,GACjB,eAAe,CAAC,MAAM,GAAG,CAAC;QACxB,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,QAAQ,IAAI,GAAG,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QAChG,CAAC,CAAC,6BAA6B,CAAC;IAEpC,MAAM,QAAQ,GAAG;QACf,EAAE,IAAI,EAAE,QAAiB,EAAE,OAAO,EAAE,oCAAuB,EAAE;QAC7D;YACE,IAAI,EAAE,MAAe;YACrB,OAAO,EAAE,oBAAoB,aAAa,mCAAmC,aAAa,wBAAwB;SACnH;KACF,CAAC;IAEF,MAAM,QAAQ,GAAG,MAAM,IAAA,oBAAS,EAAC,GAAG,EAAE,CACpC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,CAChF,CAAC;IAEF,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;IACtD,IAAI,CAAC,CAAC,KAAK;QAAE,OAAO,CAAC,GAAG,CAAC,yCAAyC,EAAE,GAAG,CAAC,CAAC;IAEzE,OAAO,aAAa,CAAC,GAAG,EAAE,aAAa,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory vector store for fast cosine-similarity search.
|
|
3
|
+
*
|
|
4
|
+
* TypeScript port of Python vector_store.py (FAISS).
|
|
5
|
+
* Since faiss-node binaries are fragile, we use a pure-JS flat index
|
|
6
|
+
* (cosine similarity via dot product after L2 normalisation).
|
|
7
|
+
* Performance is identical to FAISS IndexFlatIP for datasets < 100k vectors.
|
|
8
|
+
*
|
|
9
|
+
* Persists index maps to ~/.contextmemory/indexes/conv_<id>.json
|
|
10
|
+
*/
|
|
11
|
+
export interface SearchResult {
|
|
12
|
+
memoryId: number;
|
|
13
|
+
score: number;
|
|
14
|
+
}
|
|
15
|
+
export declare class VectorStore {
|
|
16
|
+
/** memoryId → normalised embedding */
|
|
17
|
+
private vectors;
|
|
18
|
+
get count(): number;
|
|
19
|
+
add(memoryId: number, embedding: number[]): void;
|
|
20
|
+
/** Update (remove old + insert new) */
|
|
21
|
+
update(memoryId: number, embedding: number[]): void;
|
|
22
|
+
remove(memoryId: number): void;
|
|
23
|
+
/**
|
|
24
|
+
* Cosine similarity search — O(n) but fast in JS for typical memory sizes.
|
|
25
|
+
* Returns top-k results sorted descending by score.
|
|
26
|
+
*/
|
|
27
|
+
search(queryEmbedding: number[], k?: number): SearchResult[];
|
|
28
|
+
save(filePath: string): void;
|
|
29
|
+
load(filePath: string): boolean;
|
|
30
|
+
}
|
|
31
|
+
export declare function getVectorStore(conversationId: number): VectorStore;
|
|
32
|
+
export declare function saveVectorStore(conversationId: number): void;
|
|
33
|
+
/**
|
|
34
|
+
* Rebuild the vector store from the SQLite database.
|
|
35
|
+
* Called when the index file is missing or corrupted.
|
|
36
|
+
*/
|
|
37
|
+
import type Database from "better-sqlite3";
|
|
38
|
+
export declare function rebuildIndexFromDb(db: Database.Database, conversationId: number): VectorStore;
|
|
39
|
+
export declare function resetVectorStores(): void;
|
|
40
|
+
//# sourceMappingURL=vectorStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vectorStore.d.ts","sourceRoot":"","sources":["../../src/memory/vectorStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAgBD,qBAAa,WAAW;IACtB,sCAAsC;IACtC,OAAO,CAAC,OAAO,CAAoC;IAEnD,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;IAKhD,uCAAuC;IACvC,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;IAInD,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAI9B;;;OAGG;IACH,MAAM,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,CAAC,GAAE,MAAW,GAAG,YAAY,EAAE;IAchE,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAU5B,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;CAahC;AAeD,wBAAgB,cAAc,CAAC,cAAc,EAAE,MAAM,GAAG,WAAW,CAOlE;AAED,wBAAgB,eAAe,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAG5D;AAED;;;GAGG;AACH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAG3C,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,cAAc,EAAE,MAAM,GACrB,WAAW,CAiBb;AAED,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
|