@mnemoai/core 1.1.0 → 1.1.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/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +7 -0
- package/dist/cli.js.map +7 -0
- package/dist/index.d.ts +128 -0
- package/dist/index.d.ts.map +1 -0
- package/{index.ts → dist/index.js} +526 -1333
- package/dist/index.js.map +7 -0
- package/dist/src/access-tracker.d.ts +97 -0
- package/dist/src/access-tracker.d.ts.map +1 -0
- package/dist/src/access-tracker.js +184 -0
- package/dist/src/access-tracker.js.map +7 -0
- package/dist/src/adapters/chroma.d.ts +31 -0
- package/dist/src/adapters/chroma.d.ts.map +1 -0
- package/{src/adapters/chroma.ts → dist/src/adapters/chroma.js} +45 -107
- package/dist/src/adapters/chroma.js.map +7 -0
- package/dist/src/adapters/lancedb.d.ts +29 -0
- package/dist/src/adapters/lancedb.d.ts.map +1 -0
- package/{src/adapters/lancedb.ts → dist/src/adapters/lancedb.js} +41 -109
- package/dist/src/adapters/lancedb.js.map +7 -0
- package/dist/src/adapters/pgvector.d.ts +33 -0
- package/dist/src/adapters/pgvector.d.ts.map +1 -0
- package/{src/adapters/pgvector.ts → dist/src/adapters/pgvector.js} +42 -104
- package/dist/src/adapters/pgvector.js.map +7 -0
- package/dist/src/adapters/qdrant.d.ts +34 -0
- package/dist/src/adapters/qdrant.d.ts.map +1 -0
- package/dist/src/adapters/qdrant.js +132 -0
- package/dist/src/adapters/qdrant.js.map +7 -0
- package/dist/src/adaptive-retrieval.d.ts +14 -0
- package/dist/src/adaptive-retrieval.d.ts.map +1 -0
- package/dist/src/adaptive-retrieval.js +52 -0
- package/dist/src/adaptive-retrieval.js.map +7 -0
- package/dist/src/audit-log.d.ts +56 -0
- package/dist/src/audit-log.d.ts.map +1 -0
- package/dist/src/audit-log.js +139 -0
- package/dist/src/audit-log.js.map +7 -0
- package/dist/src/chunker.d.ts +45 -0
- package/dist/src/chunker.d.ts.map +1 -0
- package/dist/src/chunker.js +157 -0
- package/dist/src/chunker.js.map +7 -0
- package/dist/src/config.d.ts +70 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +142 -0
- package/dist/src/config.js.map +7 -0
- package/dist/src/decay-engine.d.ts +73 -0
- package/dist/src/decay-engine.d.ts.map +1 -0
- package/dist/src/decay-engine.js +119 -0
- package/dist/src/decay-engine.js.map +7 -0
- package/dist/src/embedder.d.ts +94 -0
- package/dist/src/embedder.d.ts.map +1 -0
- package/{src/embedder.ts → dist/src/embedder.js} +119 -317
- package/dist/src/embedder.js.map +7 -0
- package/dist/src/extraction-prompts.d.ts +12 -0
- package/dist/src/extraction-prompts.d.ts.map +1 -0
- package/dist/src/extraction-prompts.js +311 -0
- package/dist/src/extraction-prompts.js.map +7 -0
- package/dist/src/license.d.ts +29 -0
- package/dist/src/license.d.ts.map +1 -0
- package/{src/license.ts → dist/src/license.js} +42 -113
- package/dist/src/license.js.map +7 -0
- package/dist/src/llm-client.d.ts +23 -0
- package/dist/src/llm-client.d.ts.map +1 -0
- package/{src/llm-client.ts → dist/src/llm-client.js} +22 -55
- package/dist/src/llm-client.js.map +7 -0
- package/dist/src/logger.d.ts +33 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +35 -0
- package/dist/src/logger.js.map +7 -0
- package/dist/src/mcp-server.d.ts +16 -0
- package/dist/src/mcp-server.d.ts.map +1 -0
- package/{src/mcp-server.ts → dist/src/mcp-server.js} +81 -181
- package/dist/src/mcp-server.js.map +7 -0
- package/dist/src/memory-categories.d.ts +40 -0
- package/dist/src/memory-categories.d.ts.map +1 -0
- package/dist/src/memory-categories.js +33 -0
- package/dist/src/memory-categories.js.map +7 -0
- package/dist/src/memory-upgrader.d.ts +71 -0
- package/dist/src/memory-upgrader.d.ts.map +1 -0
- package/dist/src/memory-upgrader.js +238 -0
- package/dist/src/memory-upgrader.js.map +7 -0
- package/dist/src/migrate.d.ts +47 -0
- package/dist/src/migrate.d.ts.map +1 -0
- package/{src/migrate.ts → dist/src/migrate.js} +57 -165
- package/dist/src/migrate.js.map +7 -0
- package/dist/src/mnemo.d.ts +67 -0
- package/dist/src/mnemo.d.ts.map +1 -0
- package/dist/src/mnemo.js +66 -0
- package/dist/src/mnemo.js.map +7 -0
- package/dist/src/noise-filter.d.ts +23 -0
- package/dist/src/noise-filter.d.ts.map +1 -0
- package/dist/src/noise-filter.js +62 -0
- package/dist/src/noise-filter.js.map +7 -0
- package/dist/src/noise-prototypes.d.ts +40 -0
- package/dist/src/noise-prototypes.d.ts.map +1 -0
- package/dist/src/noise-prototypes.js +116 -0
- package/dist/src/noise-prototypes.js.map +7 -0
- package/dist/src/observability.d.ts +16 -0
- package/dist/src/observability.d.ts.map +1 -0
- package/dist/src/observability.js +53 -0
- package/dist/src/observability.js.map +7 -0
- package/dist/src/query-tracker.d.ts +27 -0
- package/dist/src/query-tracker.d.ts.map +1 -0
- package/dist/src/query-tracker.js +32 -0
- package/dist/src/query-tracker.js.map +7 -0
- package/dist/src/reflection-event-store.d.ts +44 -0
- package/dist/src/reflection-event-store.d.ts.map +1 -0
- package/dist/src/reflection-event-store.js +50 -0
- package/dist/src/reflection-event-store.js.map +7 -0
- package/dist/src/reflection-item-store.d.ts +58 -0
- package/dist/src/reflection-item-store.d.ts.map +1 -0
- package/dist/src/reflection-item-store.js +69 -0
- package/dist/src/reflection-item-store.js.map +7 -0
- package/dist/src/reflection-mapped-metadata.d.ts +47 -0
- package/dist/src/reflection-mapped-metadata.d.ts.map +1 -0
- package/dist/src/reflection-mapped-metadata.js +40 -0
- package/dist/src/reflection-mapped-metadata.js.map +7 -0
- package/dist/src/reflection-metadata.d.ts +11 -0
- package/dist/src/reflection-metadata.d.ts.map +1 -0
- package/dist/src/reflection-metadata.js +24 -0
- package/dist/src/reflection-metadata.js.map +7 -0
- package/dist/src/reflection-ranking.d.ts +13 -0
- package/dist/src/reflection-ranking.d.ts.map +1 -0
- package/{src/reflection-ranking.ts → dist/src/reflection-ranking.js} +12 -21
- package/dist/src/reflection-ranking.js.map +7 -0
- package/dist/src/reflection-retry.d.ts +30 -0
- package/dist/src/reflection-retry.d.ts.map +1 -0
- package/{src/reflection-retry.ts → dist/src/reflection-retry.js} +24 -64
- package/dist/src/reflection-retry.js.map +7 -0
- package/dist/src/reflection-slices.d.ts +42 -0
- package/dist/src/reflection-slices.d.ts.map +1 -0
- package/{src/reflection-slices.ts → dist/src/reflection-slices.js} +60 -136
- package/dist/src/reflection-slices.js.map +7 -0
- package/dist/src/reflection-store.d.ts +85 -0
- package/dist/src/reflection-store.d.ts.map +1 -0
- package/dist/src/reflection-store.js +407 -0
- package/dist/src/reflection-store.js.map +7 -0
- package/dist/src/resonance-state.d.ts +19 -0
- package/dist/src/resonance-state.d.ts.map +1 -0
- package/{src/resonance-state.ts → dist/src/resonance-state.js} +13 -42
- package/dist/src/resonance-state.js.map +7 -0
- package/dist/src/retriever.d.ts +228 -0
- package/dist/src/retriever.d.ts.map +1 -0
- package/dist/src/retriever.js +1006 -0
- package/dist/src/retriever.js.map +7 -0
- package/dist/src/scopes.d.ts +58 -0
- package/dist/src/scopes.d.ts.map +1 -0
- package/dist/src/scopes.js +252 -0
- package/dist/src/scopes.js.map +7 -0
- package/dist/src/self-improvement-files.d.ts +20 -0
- package/dist/src/self-improvement-files.d.ts.map +1 -0
- package/{src/self-improvement-files.ts → dist/src/self-improvement-files.js} +24 -49
- package/dist/src/self-improvement-files.js.map +7 -0
- package/dist/src/semantic-gate.d.ts +24 -0
- package/dist/src/semantic-gate.d.ts.map +1 -0
- package/dist/src/semantic-gate.js +86 -0
- package/dist/src/semantic-gate.js.map +7 -0
- package/dist/src/session-recovery.d.ts +9 -0
- package/dist/src/session-recovery.d.ts.map +1 -0
- package/{src/session-recovery.ts → dist/src/session-recovery.js} +40 -57
- package/dist/src/session-recovery.js.map +7 -0
- package/dist/src/smart-extractor.d.ts +107 -0
- package/dist/src/smart-extractor.d.ts.map +1 -0
- package/{src/smart-extractor.ts → dist/src/smart-extractor.js} +130 -383
- package/dist/src/smart-extractor.js.map +7 -0
- package/dist/src/smart-metadata.d.ts +103 -0
- package/dist/src/smart-metadata.d.ts.map +1 -0
- package/dist/src/smart-metadata.js +361 -0
- package/dist/src/smart-metadata.js.map +7 -0
- package/dist/src/storage-adapter.d.ts +102 -0
- package/dist/src/storage-adapter.d.ts.map +1 -0
- package/dist/src/storage-adapter.js +22 -0
- package/dist/src/storage-adapter.js.map +7 -0
- package/dist/src/store.d.ts +108 -0
- package/dist/src/store.d.ts.map +1 -0
- package/dist/src/store.js +939 -0
- package/dist/src/store.js.map +7 -0
- package/dist/src/tier-manager.d.ts +57 -0
- package/dist/src/tier-manager.d.ts.map +1 -0
- package/dist/src/tier-manager.js +80 -0
- package/dist/src/tier-manager.js.map +7 -0
- package/dist/src/tools.d.ts +43 -0
- package/dist/src/tools.d.ts.map +1 -0
- package/dist/src/tools.js +1075 -0
- package/dist/src/tools.js.map +7 -0
- package/dist/src/wal-recovery.d.ts +30 -0
- package/dist/src/wal-recovery.d.ts.map +1 -0
- package/{src/wal-recovery.ts → dist/src/wal-recovery.js} +26 -79
- package/dist/src/wal-recovery.js.map +7 -0
- package/package.json +21 -2
- package/openclaw.plugin.json +0 -815
- package/src/access-tracker.ts +0 -341
- package/src/adapters/README.md +0 -78
- package/src/adapters/qdrant.ts +0 -191
- package/src/adaptive-retrieval.ts +0 -90
- package/src/audit-log.ts +0 -238
- package/src/chunker.ts +0 -254
- package/src/config.ts +0 -271
- package/src/decay-engine.ts +0 -238
- package/src/extraction-prompts.ts +0 -339
- package/src/memory-categories.ts +0 -71
- package/src/memory-upgrader.ts +0 -388
- package/src/mnemo.ts +0 -142
- package/src/noise-filter.ts +0 -97
- package/src/noise-prototypes.ts +0 -164
- package/src/observability.ts +0 -81
- package/src/query-tracker.ts +0 -57
- package/src/reflection-event-store.ts +0 -98
- package/src/reflection-item-store.ts +0 -112
- package/src/reflection-mapped-metadata.ts +0 -84
- package/src/reflection-metadata.ts +0 -23
- package/src/reflection-store.ts +0 -602
- package/src/retriever.ts +0 -1510
- package/src/scopes.ts +0 -375
- package/src/semantic-gate.ts +0 -121
- package/src/smart-metadata.ts +0 -561
- package/src/storage-adapter.ts +0 -153
- package/src/store.ts +0 -1330
- package/src/tier-manager.ts +0 -189
- package/src/tools.ts +0 -1292
- package/test/core.test.mjs +0 -301
|
@@ -1,60 +1,33 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
/**
|
|
3
|
-
* LanceDB Storage Adapter — Default backend for Mnemo.
|
|
4
|
-
*
|
|
5
|
-
* Implements StorageAdapter using @lancedb/lancedb.
|
|
6
|
-
* This is the reference implementation; other backends should
|
|
7
|
-
* produce equivalent behavior.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import type {
|
|
11
|
-
StorageAdapter,
|
|
12
|
-
MemoryRecord,
|
|
13
|
-
SearchResult,
|
|
14
|
-
QueryOptions,
|
|
15
|
-
} from "../storage-adapter.js";
|
|
16
1
|
import { registerAdapter } from "../storage-adapter.js";
|
|
17
|
-
|
|
18
|
-
/** Strict allowlist sanitizer — prevents SQL injection in LanceDB filters */
|
|
19
|
-
function sanitize(value: string): string {
|
|
2
|
+
function sanitize(value) {
|
|
20
3
|
if (typeof value !== "string") return "";
|
|
21
4
|
return value.replace(/[^a-zA-Z0-9\-_.:@ \u4e00-\u9fff\u3400-\u4dbf]/g, "");
|
|
22
5
|
}
|
|
23
|
-
|
|
24
|
-
// Dynamic import to avoid hard dependency at module level
|
|
25
|
-
let _lancedb: typeof import("@lancedb/lancedb") | null = null;
|
|
26
|
-
|
|
6
|
+
let _lancedb = null;
|
|
27
7
|
async function loadLanceDB() {
|
|
28
8
|
if (!_lancedb) {
|
|
29
9
|
_lancedb = await import("@lancedb/lancedb");
|
|
30
10
|
}
|
|
31
11
|
return _lancedb;
|
|
32
12
|
}
|
|
33
|
-
|
|
34
13
|
const TABLE_NAME = "memories";
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
private vectorDim = 0;
|
|
43
|
-
|
|
44
|
-
async connect(dbPath: string): Promise<void> {
|
|
14
|
+
class LanceDBAdapter {
|
|
15
|
+
name = "lancedb";
|
|
16
|
+
db = null;
|
|
17
|
+
table = null;
|
|
18
|
+
ftsReady = false;
|
|
19
|
+
vectorDim = 0;
|
|
20
|
+
async connect(dbPath) {
|
|
45
21
|
const lancedb = await loadLanceDB();
|
|
46
22
|
this.db = await lancedb.connect(dbPath);
|
|
47
23
|
}
|
|
48
|
-
|
|
49
|
-
async ensureTable(vectorDimensions: number): Promise<void> {
|
|
24
|
+
async ensureTable(vectorDimensions) {
|
|
50
25
|
this.vectorDim = vectorDimensions;
|
|
51
|
-
|
|
52
26
|
try {
|
|
53
27
|
this.table = await this.db.openTable(TABLE_NAME);
|
|
54
28
|
} catch {
|
|
55
|
-
// Table doesn't exist — create with schema
|
|
56
29
|
const lancedb = await loadLanceDB();
|
|
57
|
-
const schemaEntry
|
|
30
|
+
const schemaEntry = {
|
|
58
31
|
id: "__schema__",
|
|
59
32
|
text: "",
|
|
60
33
|
vector: new Array(vectorDimensions).fill(0),
|
|
@@ -62,9 +35,8 @@ export class LanceDBAdapter implements StorageAdapter {
|
|
|
62
35
|
scope: "global",
|
|
63
36
|
importance: 0,
|
|
64
37
|
category: "other",
|
|
65
|
-
metadata: "{}"
|
|
38
|
+
metadata: "{}"
|
|
66
39
|
};
|
|
67
|
-
|
|
68
40
|
try {
|
|
69
41
|
this.table = await this.db.createTable(TABLE_NAME, [schemaEntry]);
|
|
70
42
|
await this.table.delete('id = "__schema__"');
|
|
@@ -76,8 +48,6 @@ export class LanceDBAdapter implements StorageAdapter {
|
|
|
76
48
|
}
|
|
77
49
|
}
|
|
78
50
|
}
|
|
79
|
-
|
|
80
|
-
// Validate dimensions
|
|
81
51
|
const sample = await this.table.query().limit(1).toArray();
|
|
82
52
|
if (sample.length > 0 && sample[0]?.vector?.length) {
|
|
83
53
|
const existing = sample[0].vector.length;
|
|
@@ -87,83 +57,51 @@ export class LanceDBAdapter implements StorageAdapter {
|
|
|
87
57
|
);
|
|
88
58
|
}
|
|
89
59
|
}
|
|
90
|
-
|
|
91
|
-
// Create FTS index
|
|
92
60
|
await this.ensureFullTextIndex();
|
|
93
61
|
}
|
|
94
|
-
|
|
95
|
-
async add(records: MemoryRecord[]): Promise<void> {
|
|
62
|
+
async add(records) {
|
|
96
63
|
if (!this.table) throw new Error("Table not initialized");
|
|
97
64
|
await this.table.add(records);
|
|
98
65
|
}
|
|
99
|
-
|
|
100
|
-
async update(id: string, record: MemoryRecord): Promise<void> {
|
|
66
|
+
async update(id, record) {
|
|
101
67
|
if (!this.table) throw new Error("Table not initialized");
|
|
102
68
|
await this.table.delete(`id = '${sanitize(id)}'`);
|
|
103
69
|
await this.table.add([record]);
|
|
104
70
|
}
|
|
105
|
-
|
|
106
|
-
async delete(filter: string): Promise<void> {
|
|
71
|
+
async delete(filter) {
|
|
107
72
|
if (!this.table) throw new Error("Table not initialized");
|
|
108
73
|
await this.table.delete(filter);
|
|
109
74
|
}
|
|
110
|
-
|
|
111
|
-
async vectorSearch(
|
|
112
|
-
vector: number[],
|
|
113
|
-
limit: number,
|
|
114
|
-
minScore = 0,
|
|
115
|
-
scopeFilter?: string[],
|
|
116
|
-
): Promise<SearchResult[]> {
|
|
75
|
+
async vectorSearch(vector, limit, minScore = 0, scopeFilter) {
|
|
117
76
|
if (!this.table) throw new Error("Table not initialized");
|
|
118
|
-
|
|
119
77
|
let query = this.table.vectorSearch(vector).distanceType("cosine").limit(limit * 3);
|
|
120
|
-
|
|
121
78
|
if (scopeFilter?.length) {
|
|
122
79
|
const scopeExpr = scopeFilter.map((s) => `'${sanitize(s)}'`).join(", ");
|
|
123
80
|
query = query.where(`scope IN (${scopeExpr})`);
|
|
124
81
|
}
|
|
125
|
-
|
|
126
82
|
const raw = await query.toArray();
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
return { record: this.toRecord(row), score };
|
|
133
|
-
})
|
|
134
|
-
.filter((r: SearchResult) => r.score >= minScore)
|
|
135
|
-
.slice(0, limit);
|
|
83
|
+
return raw.map((row) => {
|
|
84
|
+
const distance = row._distance ?? row.distance ?? 1;
|
|
85
|
+
const score = 1 / (1 + distance);
|
|
86
|
+
return { record: this.toRecord(row), score };
|
|
87
|
+
}).filter((r) => r.score >= minScore).slice(0, limit);
|
|
136
88
|
}
|
|
137
|
-
|
|
138
|
-
async fullTextSearch(
|
|
139
|
-
queryText: string,
|
|
140
|
-
limit: number,
|
|
141
|
-
scopeFilter?: string[],
|
|
142
|
-
): Promise<SearchResult[]> {
|
|
89
|
+
async fullTextSearch(queryText, limit, scopeFilter) {
|
|
143
90
|
if (!this.table || !this.ftsReady) return [];
|
|
144
|
-
|
|
145
91
|
let query = this.table.search(queryText, "fts").limit(limit * 2);
|
|
146
|
-
|
|
147
92
|
if (scopeFilter?.length) {
|
|
148
93
|
const scopeExpr = scopeFilter.map((s) => `'${sanitize(s)}'`).join(", ");
|
|
149
94
|
query = query.where(`scope IN (${scopeExpr})`);
|
|
150
95
|
}
|
|
151
|
-
|
|
152
96
|
const raw = await query.toArray();
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
.
|
|
156
|
-
|
|
157
|
-
return { record: this.toRecord(row), score };
|
|
158
|
-
})
|
|
159
|
-
.slice(0, limit);
|
|
97
|
+
return raw.map((row) => {
|
|
98
|
+
const score = row._relevance_score ?? row.score ?? 0.5;
|
|
99
|
+
return { record: this.toRecord(row), score };
|
|
100
|
+
}).slice(0, limit);
|
|
160
101
|
}
|
|
161
|
-
|
|
162
|
-
async query(options: QueryOptions): Promise<MemoryRecord[]> {
|
|
102
|
+
async query(options) {
|
|
163
103
|
if (!this.table) throw new Error("Table not initialized");
|
|
164
|
-
|
|
165
104
|
let q = this.table.query();
|
|
166
|
-
|
|
167
105
|
if (options.select?.length) {
|
|
168
106
|
q = q.select(options.select);
|
|
169
107
|
}
|
|
@@ -173,32 +111,27 @@ export class LanceDBAdapter implements StorageAdapter {
|
|
|
173
111
|
if (options.limit) {
|
|
174
112
|
q = q.limit(options.limit);
|
|
175
113
|
}
|
|
176
|
-
|
|
177
114
|
const raw = await q.toArray();
|
|
178
|
-
return raw.map((row
|
|
115
|
+
return raw.map((row) => this.toRecord(row));
|
|
179
116
|
}
|
|
180
|
-
|
|
181
|
-
async count(filter?: string): Promise<number> {
|
|
117
|
+
async count(filter) {
|
|
182
118
|
if (!this.table) throw new Error("Table not initialized");
|
|
183
119
|
let q = this.table.query();
|
|
184
120
|
if (filter) q = q.where(filter);
|
|
185
121
|
const rows = await q.toArray();
|
|
186
122
|
return rows.length;
|
|
187
123
|
}
|
|
188
|
-
|
|
189
|
-
async ensureFullTextIndex(): Promise<void> {
|
|
124
|
+
async ensureFullTextIndex() {
|
|
190
125
|
if (!this.table) return;
|
|
191
|
-
|
|
192
126
|
try {
|
|
193
127
|
const indices = await this.table.listIndices();
|
|
194
128
|
const hasFts = indices?.some(
|
|
195
|
-
(idx
|
|
129
|
+
(idx) => idx.indexType === "FTS" || idx.columns?.includes("text")
|
|
196
130
|
);
|
|
197
|
-
|
|
198
131
|
if (!hasFts) {
|
|
199
132
|
const lancedb = await loadLanceDB();
|
|
200
133
|
await this.table.createIndex("text", {
|
|
201
|
-
config:
|
|
134
|
+
config: lancedb.Index.fts()
|
|
202
135
|
});
|
|
203
136
|
}
|
|
204
137
|
this.ftsReady = true;
|
|
@@ -206,19 +139,15 @@ export class LanceDBAdapter implements StorageAdapter {
|
|
|
206
139
|
this.ftsReady = false;
|
|
207
140
|
}
|
|
208
141
|
}
|
|
209
|
-
|
|
210
|
-
hasFullTextSearch(): boolean {
|
|
142
|
+
hasFullTextSearch() {
|
|
211
143
|
return this.ftsReady;
|
|
212
144
|
}
|
|
213
|
-
|
|
214
|
-
async close(): Promise<void> {
|
|
145
|
+
async close() {
|
|
215
146
|
this.table = null;
|
|
216
147
|
this.db = null;
|
|
217
148
|
}
|
|
218
|
-
|
|
219
149
|
// ── Helpers ──
|
|
220
|
-
|
|
221
|
-
private toRecord(row: any): MemoryRecord {
|
|
150
|
+
toRecord(row) {
|
|
222
151
|
return {
|
|
223
152
|
id: row.id,
|
|
224
153
|
text: row.text,
|
|
@@ -228,10 +157,13 @@ export class LanceDBAdapter implements StorageAdapter {
|
|
|
228
157
|
importance: row.importance ?? 0.5,
|
|
229
158
|
category: row.category ?? "other",
|
|
230
159
|
metadata: row.metadata ?? "{}",
|
|
231
|
-
...row
|
|
160
|
+
...row
|
|
161
|
+
// preserve extra fields
|
|
232
162
|
};
|
|
233
163
|
}
|
|
234
164
|
}
|
|
235
|
-
|
|
236
|
-
// ── Auto-register ──
|
|
237
165
|
registerAdapter("lancedb", () => new LanceDBAdapter());
|
|
166
|
+
export {
|
|
167
|
+
LanceDBAdapter
|
|
168
|
+
};
|
|
169
|
+
//# sourceMappingURL=lancedb.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/adapters/lancedb.ts"],
|
|
4
|
+
"sourcesContent": ["// SPDX-License-Identifier: MIT\n/**\n * LanceDB Storage Adapter \u2014 Default backend for Mnemo.\n *\n * Implements StorageAdapter using @lancedb/lancedb.\n * This is the reference implementation; other backends should\n * produce equivalent behavior.\n */\n\nimport type {\n StorageAdapter,\n MemoryRecord,\n SearchResult,\n QueryOptions,\n} from \"../storage-adapter.js\";\nimport { registerAdapter } from \"../storage-adapter.js\";\n\n/** Strict allowlist sanitizer \u2014 prevents SQL injection in LanceDB filters */\nfunction sanitize(value: string): string {\n if (typeof value !== \"string\") return \"\";\n return value.replace(/[^a-zA-Z0-9\\-_.:@ \\u4e00-\\u9fff\\u3400-\\u4dbf]/g, \"\");\n}\n\n// Dynamic import to avoid hard dependency at module level\nlet _lancedb: typeof import(\"@lancedb/lancedb\") | null = null;\n\nasync function loadLanceDB() {\n if (!_lancedb) {\n _lancedb = await import(\"@lancedb/lancedb\");\n }\n return _lancedb;\n}\n\nconst TABLE_NAME = \"memories\";\n\nexport class LanceDBAdapter implements StorageAdapter {\n readonly name = \"lancedb\";\n\n private db: any = null;\n private table: any = null;\n private ftsReady = false;\n private vectorDim = 0;\n\n async connect(dbPath: string): Promise<void> {\n const lancedb = await loadLanceDB();\n this.db = await lancedb.connect(dbPath);\n }\n\n async ensureTable(vectorDimensions: number): Promise<void> {\n this.vectorDim = vectorDimensions;\n\n try {\n this.table = await this.db.openTable(TABLE_NAME);\n } catch {\n // Table doesn't exist \u2014 create with schema\n const lancedb = await loadLanceDB();\n const schemaEntry: MemoryRecord = {\n id: \"__schema__\",\n text: \"\",\n vector: new Array(vectorDimensions).fill(0),\n timestamp: 0,\n scope: \"global\",\n importance: 0,\n category: \"other\",\n metadata: \"{}\",\n };\n\n try {\n this.table = await this.db.createTable(TABLE_NAME, [schemaEntry]);\n await this.table.delete('id = \"__schema__\"');\n } catch (err) {\n if (String(err).includes(\"already exists\")) {\n this.table = await this.db.openTable(TABLE_NAME);\n } else {\n throw err;\n }\n }\n }\n\n // Validate dimensions\n const sample = await this.table.query().limit(1).toArray();\n if (sample.length > 0 && sample[0]?.vector?.length) {\n const existing = sample[0].vector.length;\n if (existing !== vectorDimensions) {\n throw new Error(\n `Vector dimension mismatch: table=${existing}, config=${vectorDimensions}`\n );\n }\n }\n\n // Create FTS index\n await this.ensureFullTextIndex();\n }\n\n async add(records: MemoryRecord[]): Promise<void> {\n if (!this.table) throw new Error(\"Table not initialized\");\n await this.table.add(records);\n }\n\n async update(id: string, record: MemoryRecord): Promise<void> {\n if (!this.table) throw new Error(\"Table not initialized\");\n await this.table.delete(`id = '${sanitize(id)}'`);\n await this.table.add([record]);\n }\n\n async delete(filter: string): Promise<void> {\n if (!this.table) throw new Error(\"Table not initialized\");\n await this.table.delete(filter);\n }\n\n async vectorSearch(\n vector: number[],\n limit: number,\n minScore = 0,\n scopeFilter?: string[],\n ): Promise<SearchResult[]> {\n if (!this.table) throw new Error(\"Table not initialized\");\n\n let query = this.table.vectorSearch(vector).distanceType(\"cosine\").limit(limit * 3);\n\n if (scopeFilter?.length) {\n const scopeExpr = scopeFilter.map((s) => `'${sanitize(s)}'`).join(\", \");\n query = query.where(`scope IN (${scopeExpr})`);\n }\n\n const raw = await query.toArray();\n\n return raw\n .map((row: any) => {\n const distance = row._distance ?? row.distance ?? 1;\n const score = 1 / (1 + distance);\n return { record: this.toRecord(row), score };\n })\n .filter((r: SearchResult) => r.score >= minScore)\n .slice(0, limit);\n }\n\n async fullTextSearch(\n queryText: string,\n limit: number,\n scopeFilter?: string[],\n ): Promise<SearchResult[]> {\n if (!this.table || !this.ftsReady) return [];\n\n let query = this.table.search(queryText, \"fts\").limit(limit * 2);\n\n if (scopeFilter?.length) {\n const scopeExpr = scopeFilter.map((s) => `'${sanitize(s)}'`).join(\", \");\n query = query.where(`scope IN (${scopeExpr})`);\n }\n\n const raw = await query.toArray();\n\n return raw\n .map((row: any) => {\n const score = row._relevance_score ?? row.score ?? 0.5;\n return { record: this.toRecord(row), score };\n })\n .slice(0, limit);\n }\n\n async query(options: QueryOptions): Promise<MemoryRecord[]> {\n if (!this.table) throw new Error(\"Table not initialized\");\n\n let q = this.table.query();\n\n if (options.select?.length) {\n q = q.select(options.select);\n }\n if (options.where) {\n q = q.where(options.where);\n }\n if (options.limit) {\n q = q.limit(options.limit);\n }\n\n const raw = await q.toArray();\n return raw.map((row: any) => this.toRecord(row));\n }\n\n async count(filter?: string): Promise<number> {\n if (!this.table) throw new Error(\"Table not initialized\");\n let q = this.table.query();\n if (filter) q = q.where(filter);\n const rows = await q.toArray();\n return rows.length;\n }\n\n async ensureFullTextIndex(): Promise<void> {\n if (!this.table) return;\n\n try {\n const indices = await this.table.listIndices();\n const hasFts = indices?.some(\n (idx: any) => idx.indexType === \"FTS\" || idx.columns?.includes(\"text\"),\n );\n\n if (!hasFts) {\n const lancedb = await loadLanceDB();\n await this.table.createIndex(\"text\", {\n config: (lancedb as any).Index.fts(),\n });\n }\n this.ftsReady = true;\n } catch {\n this.ftsReady = false;\n }\n }\n\n hasFullTextSearch(): boolean {\n return this.ftsReady;\n }\n\n async close(): Promise<void> {\n this.table = null;\n this.db = null;\n }\n\n // \u2500\u2500 Helpers \u2500\u2500\n\n private toRecord(row: any): MemoryRecord {\n return {\n id: row.id,\n text: row.text,\n vector: row.vector ? Array.from(row.vector) : [],\n timestamp: row.timestamp ?? 0,\n scope: row.scope ?? \"global\",\n importance: row.importance ?? 0.5,\n category: row.category ?? \"other\",\n metadata: row.metadata ?? \"{}\",\n ...row, // preserve extra fields\n };\n }\n}\n\n// \u2500\u2500 Auto-register \u2500\u2500\nregisterAdapter(\"lancedb\", () => new LanceDBAdapter());\n"],
|
|
5
|
+
"mappings": "AAeA,SAAS,uBAAuB;AAGhC,SAAS,SAAS,OAAuB;AACvC,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,SAAO,MAAM,QAAQ,kDAAkD,EAAE;AAC3E;AAGA,IAAI,WAAqD;AAEzD,eAAe,cAAc;AAC3B,MAAI,CAAC,UAAU;AACb,eAAW,MAAM,OAAO,kBAAkB;AAAA,EAC5C;AACA,SAAO;AACT;AAEA,MAAM,aAAa;AAEZ,MAAM,eAAyC;AAAA,EAC3C,OAAO;AAAA,EAER,KAAU;AAAA,EACV,QAAa;AAAA,EACb,WAAW;AAAA,EACX,YAAY;AAAA,EAEpB,MAAM,QAAQ,QAA+B;AAC3C,UAAM,UAAU,MAAM,YAAY;AAClC,SAAK,KAAK,MAAM,QAAQ,QAAQ,MAAM;AAAA,EACxC;AAAA,EAEA,MAAM,YAAY,kBAAyC;AACzD,SAAK,YAAY;AAEjB,QAAI;AACF,WAAK,QAAQ,MAAM,KAAK,GAAG,UAAU,UAAU;AAAA,IACjD,QAAQ;AAEN,YAAM,UAAU,MAAM,YAAY;AAClC,YAAM,cAA4B;AAAA,QAChC,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,QAAQ,IAAI,MAAM,gBAAgB,EAAE,KAAK,CAAC;AAAA,QAC1C,WAAW;AAAA,QACX,OAAO;AAAA,QACP,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,UAAU;AAAA,MACZ;AAEA,UAAI;AACF,aAAK,QAAQ,MAAM,KAAK,GAAG,YAAY,YAAY,CAAC,WAAW,CAAC;AAChE,cAAM,KAAK,MAAM,OAAO,mBAAmB;AAAA,MAC7C,SAAS,KAAK;AACZ,YAAI,OAAO,GAAG,EAAE,SAAS,gBAAgB,GAAG;AAC1C,eAAK,QAAQ,MAAM,KAAK,GAAG,UAAU,UAAU;AAAA,QACjD,OAAO;AACL,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAGA,UAAM,SAAS,MAAM,KAAK,MAAM,MAAM,EAAE,MAAM,CAAC,EAAE,QAAQ;AACzD,QAAI,OAAO,SAAS,KAAK,OAAO,CAAC,GAAG,QAAQ,QAAQ;AAClD,YAAM,WAAW,OAAO,CAAC,EAAE,OAAO;AAClC,UAAI,aAAa,kBAAkB;AACjC,cAAM,IAAI;AAAA,UACR,oCAAoC,QAAQ,YAAY,gBAAgB;AAAA,QAC1E;AAAA,MACF;AAAA,IACF;AAGA,UAAM,KAAK,oBAAoB;AAAA,EACjC;AAAA,EAEA,MAAM,IAAI,SAAwC;AAChD,QAAI,CAAC,KAAK,MAAO,OAAM,IAAI,MAAM,uBAAuB;AACxD,UAAM,KAAK,MAAM,IAAI,OAAO;AAAA,EAC9B;AAAA,EAEA,MAAM,OAAO,IAAY,QAAqC;AAC5D,QAAI,CAAC,KAAK,MAAO,OAAM,IAAI,MAAM,uBAAuB;AACxD,UAAM,KAAK,MAAM,OAAO,SAAS,SAAS,EAAE,CAAC,GAAG;AAChD,UAAM,KAAK,MAAM,IAAI,CAAC,MAAM,CAAC;AAAA,EAC/B;AAAA,EAEA,MAAM,OAAO,QAA+B;AAC1C,QAAI,CAAC,KAAK,MAAO,OAAM,IAAI,MAAM,uBAAuB;AACxD,UAAM,KAAK,MAAM,OAAO,MAAM;AAAA,EAChC;AAAA,EAEA,MAAM,aACJ,QACA,OACA,WAAW,GACX,aACyB;AACzB,QAAI,CAAC,KAAK,MAAO,OAAM,IAAI,MAAM,uBAAuB;AAExD,QAAI,QAAQ,KAAK,MAAM,aAAa,MAAM,EAAE,aAAa,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAElF,QAAI,aAAa,QAAQ;AACvB,YAAM,YAAY,YAAY,IAAI,CAAC,MAAM,IAAI,SAAS,CAAC,CAAC,GAAG,EAAE,KAAK,IAAI;AACtE,cAAQ,MAAM,MAAM,aAAa,SAAS,GAAG;AAAA,IAC/C;AAEA,UAAM,MAAM,MAAM,MAAM,QAAQ;AAEhC,WAAO,IACJ,IAAI,CAAC,QAAa;AACjB,YAAM,WAAW,IAAI,aAAa,IAAI,YAAY;AAClD,YAAM,QAAQ,KAAK,IAAI;AACvB,aAAO,EAAE,QAAQ,KAAK,SAAS,GAAG,GAAG,MAAM;AAAA,IAC7C,CAAC,EACA,OAAO,CAAC,MAAoB,EAAE,SAAS,QAAQ,EAC/C,MAAM,GAAG,KAAK;AAAA,EACnB;AAAA,EAEA,MAAM,eACJ,WACA,OACA,aACyB;AACzB,QAAI,CAAC,KAAK,SAAS,CAAC,KAAK,SAAU,QAAO,CAAC;AAE3C,QAAI,QAAQ,KAAK,MAAM,OAAO,WAAW,KAAK,EAAE,MAAM,QAAQ,CAAC;AAE/D,QAAI,aAAa,QAAQ;AACvB,YAAM,YAAY,YAAY,IAAI,CAAC,MAAM,IAAI,SAAS,CAAC,CAAC,GAAG,EAAE,KAAK,IAAI;AACtE,cAAQ,MAAM,MAAM,aAAa,SAAS,GAAG;AAAA,IAC/C;AAEA,UAAM,MAAM,MAAM,MAAM,QAAQ;AAEhC,WAAO,IACJ,IAAI,CAAC,QAAa;AACjB,YAAM,QAAQ,IAAI,oBAAoB,IAAI,SAAS;AACnD,aAAO,EAAE,QAAQ,KAAK,SAAS,GAAG,GAAG,MAAM;AAAA,IAC7C,CAAC,EACA,MAAM,GAAG,KAAK;AAAA,EACnB;AAAA,EAEA,MAAM,MAAM,SAAgD;AAC1D,QAAI,CAAC,KAAK,MAAO,OAAM,IAAI,MAAM,uBAAuB;AAExD,QAAI,IAAI,KAAK,MAAM,MAAM;AAEzB,QAAI,QAAQ,QAAQ,QAAQ;AAC1B,UAAI,EAAE,OAAO,QAAQ,MAAM;AAAA,IAC7B;AACA,QAAI,QAAQ,OAAO;AACjB,UAAI,EAAE,MAAM,QAAQ,KAAK;AAAA,IAC3B;AACA,QAAI,QAAQ,OAAO;AACjB,UAAI,EAAE,MAAM,QAAQ,KAAK;AAAA,IAC3B;AAEA,UAAM,MAAM,MAAM,EAAE,QAAQ;AAC5B,WAAO,IAAI,IAAI,CAAC,QAAa,KAAK,SAAS,GAAG,CAAC;AAAA,EACjD;AAAA,EAEA,MAAM,MAAM,QAAkC;AAC5C,QAAI,CAAC,KAAK,MAAO,OAAM,IAAI,MAAM,uBAAuB;AACxD,QAAI,IAAI,KAAK,MAAM,MAAM;AACzB,QAAI,OAAQ,KAAI,EAAE,MAAM,MAAM;AAC9B,UAAM,OAAO,MAAM,EAAE,QAAQ;AAC7B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,sBAAqC;AACzC,QAAI,CAAC,KAAK,MAAO;AAEjB,QAAI;AACF,YAAM,UAAU,MAAM,KAAK,MAAM,YAAY;AAC7C,YAAM,SAAS,SAAS;AAAA,QACtB,CAAC,QAAa,IAAI,cAAc,SAAS,IAAI,SAAS,SAAS,MAAM;AAAA,MACvE;AAEA,UAAI,CAAC,QAAQ;AACX,cAAM,UAAU,MAAM,YAAY;AAClC,cAAM,KAAK,MAAM,YAAY,QAAQ;AAAA,UACnC,QAAS,QAAgB,MAAM,IAAI;AAAA,QACrC,CAAC;AAAA,MACH;AACA,WAAK,WAAW;AAAA,IAClB,QAAQ;AACN,WAAK,WAAW;AAAA,IAClB;AAAA,EACF;AAAA,EAEA,oBAA6B;AAC3B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,QAAuB;AAC3B,SAAK,QAAQ;AACb,SAAK,KAAK;AAAA,EACZ;AAAA;AAAA,EAIQ,SAAS,KAAwB;AACvC,WAAO;AAAA,MACL,IAAI,IAAI;AAAA,MACR,MAAM,IAAI;AAAA,MACV,QAAQ,IAAI,SAAS,MAAM,KAAK,IAAI,MAAM,IAAI,CAAC;AAAA,MAC/C,WAAW,IAAI,aAAa;AAAA,MAC5B,OAAO,IAAI,SAAS;AAAA,MACpB,YAAY,IAAI,cAAc;AAAA,MAC9B,UAAU,IAAI,YAAY;AAAA,MAC1B,UAAU,IAAI,YAAY;AAAA,MAC1B,GAAG;AAAA;AAAA,IACL;AAAA,EACF;AACF;AAGA,gBAAgB,WAAW,MAAM,IAAI,eAAe,CAAC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PGVector Storage Adapter for Mnemo
|
|
3
|
+
*
|
|
4
|
+
* Requirements:
|
|
5
|
+
* npm install pg pgvector
|
|
6
|
+
* PostgreSQL with pgvector extension enabled
|
|
7
|
+
*
|
|
8
|
+
* Config:
|
|
9
|
+
* storage: "pgvector"
|
|
10
|
+
* storageConfig: { connectionString: "postgres://user:pass@localhost:5432/mnemo" }
|
|
11
|
+
*/
|
|
12
|
+
import type { StorageAdapter, MemoryRecord, SearchResult, QueryOptions } from "../storage-adapter.js";
|
|
13
|
+
export declare class PGVectorAdapter implements StorageAdapter {
|
|
14
|
+
readonly name = "pgvector";
|
|
15
|
+
private pool;
|
|
16
|
+
private vectorDim;
|
|
17
|
+
private connectionString;
|
|
18
|
+
constructor(config?: Record<string, unknown>);
|
|
19
|
+
connect(dbPath: string): Promise<void>;
|
|
20
|
+
ensureTable(vectorDimensions: number): Promise<void>;
|
|
21
|
+
add(records: MemoryRecord[]): Promise<void>;
|
|
22
|
+
update(id: string, record: MemoryRecord): Promise<void>;
|
|
23
|
+
delete(filter: string): Promise<void>;
|
|
24
|
+
vectorSearch(vector: number[], limit: number, minScore?: number, scopeFilter?: string[]): Promise<SearchResult[]>;
|
|
25
|
+
fullTextSearch(queryText: string, limit: number, scopeFilter?: string[]): Promise<SearchResult[]>;
|
|
26
|
+
query(options: QueryOptions): Promise<MemoryRecord[]>;
|
|
27
|
+
count(filter?: string): Promise<number>;
|
|
28
|
+
ensureFullTextIndex(): Promise<void>;
|
|
29
|
+
hasFullTextSearch(): boolean;
|
|
30
|
+
close(): Promise<void>;
|
|
31
|
+
private toRecord;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=pgvector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pgvector.d.ts","sourceRoot":"","sources":["../../../src/adapters/pgvector.ts"],"names":[],"mappings":"AACA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,YAAY,EACb,MAAM,uBAAuB,CAAC;AAK/B,qBAAa,eAAgB,YAAW,cAAc;IACpD,QAAQ,CAAC,IAAI,cAAc;IAE3B,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,gBAAgB,CAAS;gBAErB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAKtC,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUtC,WAAW,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkCpD,GAAG,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB3C,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvD,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUrC,YAAY,CAChB,MAAM,EAAE,MAAM,EAAE,EAChB,KAAK,EAAE,MAAM,EACb,QAAQ,SAAI,EACZ,WAAW,CAAC,EAAE,MAAM,EAAE,GACrB,OAAO,CAAC,YAAY,EAAE,CAAC;IAyBpB,cAAc,CAClB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EAAE,GACrB,OAAO,CAAC,YAAY,EAAE,CAAC;IAyBpB,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IASrD,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAOvC,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAI1C,iBAAiB,IAAI,OAAO;IAItB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAS5B,OAAO,CAAC,QAAQ;CAYjB"}
|
|
@@ -1,51 +1,22 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
/**
|
|
3
|
-
* PGVector Storage Adapter for Mnemo
|
|
4
|
-
*
|
|
5
|
-
* Requirements:
|
|
6
|
-
* npm install pg pgvector
|
|
7
|
-
* PostgreSQL with pgvector extension enabled
|
|
8
|
-
*
|
|
9
|
-
* Config:
|
|
10
|
-
* storage: "pgvector"
|
|
11
|
-
* storageConfig: { connectionString: "postgres://user:pass@localhost:5432/mnemo" }
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import type {
|
|
15
|
-
StorageAdapter,
|
|
16
|
-
MemoryRecord,
|
|
17
|
-
SearchResult,
|
|
18
|
-
QueryOptions,
|
|
19
|
-
} from "../storage-adapter.js";
|
|
20
1
|
import { registerAdapter } from "../storage-adapter.js";
|
|
21
|
-
|
|
22
2
|
const TABLE = "mnemo_memories";
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
constructor(config?: Record<string, unknown>) {
|
|
32
|
-
this.connectionString = (config?.connectionString as string) ||
|
|
33
|
-
"postgres://localhost:5432/mnemo";
|
|
3
|
+
class PGVectorAdapter {
|
|
4
|
+
name = "pgvector";
|
|
5
|
+
pool = null;
|
|
6
|
+
vectorDim = 0;
|
|
7
|
+
connectionString;
|
|
8
|
+
constructor(config) {
|
|
9
|
+
this.connectionString = config?.connectionString || "postgres://localhost:5432/mnemo";
|
|
34
10
|
}
|
|
35
|
-
|
|
36
|
-
async connect(dbPath: string): Promise<void> {
|
|
11
|
+
async connect(dbPath) {
|
|
37
12
|
const { Pool } = await import("pg");
|
|
38
13
|
this.pool = new Pool({
|
|
39
|
-
connectionString: dbPath || this.connectionString
|
|
14
|
+
connectionString: dbPath || this.connectionString
|
|
40
15
|
});
|
|
41
|
-
|
|
42
|
-
// Enable pgvector extension
|
|
43
16
|
await this.pool.query("CREATE EXTENSION IF NOT EXISTS vector");
|
|
44
17
|
}
|
|
45
|
-
|
|
46
|
-
async ensureTable(vectorDimensions: number): Promise<void> {
|
|
18
|
+
async ensureTable(vectorDimensions) {
|
|
47
19
|
this.vectorDim = vectorDimensions;
|
|
48
|
-
|
|
49
20
|
await this.pool.query(`
|
|
50
21
|
CREATE TABLE IF NOT EXISTS ${TABLE} (
|
|
51
22
|
id TEXT PRIMARY KEY,
|
|
@@ -58,26 +29,22 @@ export class PGVectorAdapter implements StorageAdapter {
|
|
|
58
29
|
metadata JSONB DEFAULT '{}'::jsonb
|
|
59
30
|
)
|
|
60
31
|
`);
|
|
61
|
-
|
|
62
|
-
// Create HNSW index for vector search
|
|
63
32
|
await this.pool.query(`
|
|
64
33
|
CREATE INDEX IF NOT EXISTS ${TABLE}_vector_idx
|
|
65
34
|
ON ${TABLE} USING hnsw (vector vector_cosine_ops)
|
|
66
|
-
`).catch(() => {
|
|
67
|
-
|
|
68
|
-
// Create GIN index for full-text search
|
|
35
|
+
`).catch(() => {
|
|
36
|
+
});
|
|
69
37
|
await this.pool.query(`
|
|
70
38
|
CREATE INDEX IF NOT EXISTS ${TABLE}_text_idx
|
|
71
39
|
ON ${TABLE} USING gin (to_tsvector('simple', text))
|
|
72
|
-
`).catch(() => {
|
|
73
|
-
|
|
74
|
-
// Create index on scope for filtering
|
|
40
|
+
`).catch(() => {
|
|
41
|
+
});
|
|
75
42
|
await this.pool.query(`
|
|
76
43
|
CREATE INDEX IF NOT EXISTS ${TABLE}_scope_idx ON ${TABLE} (scope)
|
|
77
|
-
`).catch(() => {
|
|
44
|
+
`).catch(() => {
|
|
45
|
+
});
|
|
78
46
|
}
|
|
79
|
-
|
|
80
|
-
async add(records: MemoryRecord[]): Promise<void> {
|
|
47
|
+
async add(records) {
|
|
81
48
|
for (const r of records) {
|
|
82
49
|
await this.pool.query(
|
|
83
50
|
`INSERT INTO ${TABLE} (id, text, vector, timestamp, scope, importance, category, metadata)
|
|
@@ -90,129 +57,100 @@ export class PGVectorAdapter implements StorageAdapter {
|
|
|
90
57
|
importance = EXCLUDED.importance,
|
|
91
58
|
category = EXCLUDED.category,
|
|
92
59
|
metadata = EXCLUDED.metadata`,
|
|
93
|
-
[r.id, r.text, `[${r.vector.join(",")}]`, r.timestamp, r.scope, r.importance, r.category, r.metadata]
|
|
60
|
+
[r.id, r.text, `[${r.vector.join(",")}]`, r.timestamp, r.scope, r.importance, r.category, r.metadata]
|
|
94
61
|
);
|
|
95
62
|
}
|
|
96
63
|
}
|
|
97
|
-
|
|
98
|
-
async update(id: string, record: MemoryRecord): Promise<void> {
|
|
64
|
+
async update(id, record) {
|
|
99
65
|
await this.add([record]);
|
|
100
66
|
}
|
|
101
|
-
|
|
102
|
-
async delete(filter: string): Promise<void> {
|
|
67
|
+
async delete(filter) {
|
|
103
68
|
const idMatch = filter.match(/id\s*=\s*'([^']+)'/);
|
|
104
69
|
if (idMatch) {
|
|
105
70
|
await this.pool.query(`DELETE FROM ${TABLE} WHERE id = $1`, [idMatch[1]]);
|
|
106
71
|
} else {
|
|
107
|
-
// Pass filter as-is for simple SQL WHERE clauses
|
|
108
72
|
await this.pool.query(`DELETE FROM ${TABLE} WHERE ${filter}`);
|
|
109
73
|
}
|
|
110
74
|
}
|
|
111
|
-
|
|
112
|
-
async vectorSearch(
|
|
113
|
-
vector: number[],
|
|
114
|
-
limit: number,
|
|
115
|
-
minScore = 0,
|
|
116
|
-
scopeFilter?: string[],
|
|
117
|
-
): Promise<SearchResult[]> {
|
|
75
|
+
async vectorSearch(vector, limit, minScore = 0, scopeFilter) {
|
|
118
76
|
const vectorStr = `[${vector.join(",")}]`;
|
|
119
77
|
let query = `
|
|
120
78
|
SELECT *, 1 - (vector <=> $1::vector) AS score
|
|
121
79
|
FROM ${TABLE}
|
|
122
80
|
WHERE 1 - (vector <=> $1::vector) >= $2
|
|
123
81
|
`;
|
|
124
|
-
const params
|
|
125
|
-
|
|
82
|
+
const params = [vectorStr, minScore];
|
|
126
83
|
if (scopeFilter?.length) {
|
|
127
84
|
query += ` AND scope = ANY($3)`;
|
|
128
85
|
params.push(scopeFilter);
|
|
129
86
|
}
|
|
130
|
-
|
|
131
87
|
query += ` ORDER BY vector <=> $1::vector LIMIT $${params.length + 1}`;
|
|
132
88
|
params.push(limit);
|
|
133
|
-
|
|
134
89
|
const result = await this.pool.query(query, params);
|
|
135
|
-
|
|
136
|
-
return result.rows.map((row: any) => ({
|
|
90
|
+
return result.rows.map((row) => ({
|
|
137
91
|
record: this.toRecord(row),
|
|
138
|
-
score: parseFloat(row.score)
|
|
92
|
+
score: parseFloat(row.score)
|
|
139
93
|
}));
|
|
140
94
|
}
|
|
141
|
-
|
|
142
|
-
async fullTextSearch(
|
|
143
|
-
queryText: string,
|
|
144
|
-
limit: number,
|
|
145
|
-
scopeFilter?: string[],
|
|
146
|
-
): Promise<SearchResult[]> {
|
|
147
|
-
// Use PostgreSQL full-text search with ts_rank
|
|
95
|
+
async fullTextSearch(queryText, limit, scopeFilter) {
|
|
148
96
|
let query = `
|
|
149
97
|
SELECT *, ts_rank(to_tsvector('simple', text), plainto_tsquery('simple', $1)) AS score
|
|
150
98
|
FROM ${TABLE}
|
|
151
99
|
WHERE to_tsvector('simple', text) @@ plainto_tsquery('simple', $1)
|
|
152
100
|
`;
|
|
153
|
-
const params
|
|
154
|
-
|
|
101
|
+
const params = [queryText];
|
|
155
102
|
if (scopeFilter?.length) {
|
|
156
103
|
query += ` AND scope = ANY($2)`;
|
|
157
104
|
params.push(scopeFilter);
|
|
158
105
|
}
|
|
159
|
-
|
|
160
106
|
query += ` ORDER BY score DESC LIMIT $${params.length + 1}`;
|
|
161
107
|
params.push(limit);
|
|
162
|
-
|
|
163
108
|
const result = await this.pool.query(query, params);
|
|
164
|
-
|
|
165
|
-
return result.rows.map((row: any) => ({
|
|
109
|
+
return result.rows.map((row) => ({
|
|
166
110
|
record: this.toRecord(row),
|
|
167
|
-
score: parseFloat(row.score)
|
|
111
|
+
score: parseFloat(row.score)
|
|
168
112
|
}));
|
|
169
113
|
}
|
|
170
|
-
|
|
171
|
-
async query(options: QueryOptions): Promise<MemoryRecord[]> {
|
|
114
|
+
async query(options) {
|
|
172
115
|
let query = `SELECT * FROM ${TABLE}`;
|
|
173
116
|
if (options.where) query += ` WHERE ${options.where}`;
|
|
174
117
|
query += ` LIMIT ${options.limit || 100}`;
|
|
175
|
-
|
|
176
118
|
const result = await this.pool.query(query);
|
|
177
|
-
return result.rows.map((row
|
|
119
|
+
return result.rows.map((row) => this.toRecord(row));
|
|
178
120
|
}
|
|
179
|
-
|
|
180
|
-
async count(filter?: string): Promise<number> {
|
|
121
|
+
async count(filter) {
|
|
181
122
|
let query = `SELECT COUNT(*) FROM ${TABLE}`;
|
|
182
123
|
if (filter) query += ` WHERE ${filter}`;
|
|
183
124
|
const result = await this.pool.query(query);
|
|
184
125
|
return parseInt(result.rows[0].count);
|
|
185
126
|
}
|
|
186
|
-
|
|
187
|
-
async ensureFullTextIndex(): Promise<void> {
|
|
188
|
-
// Created in ensureTable
|
|
127
|
+
async ensureFullTextIndex() {
|
|
189
128
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
return true; // PostgreSQL has native full-text search
|
|
129
|
+
hasFullTextSearch() {
|
|
130
|
+
return true;
|
|
193
131
|
}
|
|
194
|
-
|
|
195
|
-
async close(): Promise<void> {
|
|
132
|
+
async close() {
|
|
196
133
|
if (this.pool) {
|
|
197
134
|
await this.pool.end();
|
|
198
135
|
this.pool = null;
|
|
199
136
|
}
|
|
200
137
|
}
|
|
201
|
-
|
|
202
138
|
// ── Helpers ──
|
|
203
|
-
|
|
204
|
-
private toRecord(row: any): MemoryRecord {
|
|
139
|
+
toRecord(row) {
|
|
205
140
|
return {
|
|
206
141
|
id: row.id,
|
|
207
142
|
text: row.text,
|
|
208
|
-
vector: row.vector ?
|
|
143
|
+
vector: row.vector ? typeof row.vector === "string" ? JSON.parse(row.vector) : Array.from(row.vector) : [],
|
|
209
144
|
timestamp: parseInt(row.timestamp) || 0,
|
|
210
145
|
scope: row.scope ?? "global",
|
|
211
146
|
importance: parseFloat(row.importance) || 0.5,
|
|
212
147
|
category: row.category ?? "other",
|
|
213
|
-
metadata: typeof row.metadata === "object" ? JSON.stringify(row.metadata) :
|
|
148
|
+
metadata: typeof row.metadata === "object" ? JSON.stringify(row.metadata) : row.metadata ?? "{}"
|
|
214
149
|
};
|
|
215
150
|
}
|
|
216
151
|
}
|
|
217
|
-
|
|
218
152
|
registerAdapter("pgvector", (config) => new PGVectorAdapter(config));
|
|
153
|
+
export {
|
|
154
|
+
PGVectorAdapter
|
|
155
|
+
};
|
|
156
|
+
//# sourceMappingURL=pgvector.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/adapters/pgvector.ts"],
|
|
4
|
+
"sourcesContent": ["// SPDX-License-Identifier: MIT\n/**\n * PGVector Storage Adapter for Mnemo\n *\n * Requirements:\n * npm install pg pgvector\n * PostgreSQL with pgvector extension enabled\n *\n * Config:\n * storage: \"pgvector\"\n * storageConfig: { connectionString: \"postgres://user:pass@localhost:5432/mnemo\" }\n */\n\nimport type {\n StorageAdapter,\n MemoryRecord,\n SearchResult,\n QueryOptions,\n} from \"../storage-adapter.js\";\nimport { registerAdapter } from \"../storage-adapter.js\";\n\nconst TABLE = \"mnemo_memories\";\n\nexport class PGVectorAdapter implements StorageAdapter {\n readonly name = \"pgvector\";\n\n private pool: any = null;\n private vectorDim = 0;\n private connectionString: string;\n\n constructor(config?: Record<string, unknown>) {\n this.connectionString = (config?.connectionString as string) ||\n \"postgres://localhost:5432/mnemo\";\n }\n\n async connect(dbPath: string): Promise<void> {\n const { Pool } = await import(\"pg\");\n this.pool = new Pool({\n connectionString: dbPath || this.connectionString,\n });\n\n // Enable pgvector extension\n await this.pool.query(\"CREATE EXTENSION IF NOT EXISTS vector\");\n }\n\n async ensureTable(vectorDimensions: number): Promise<void> {\n this.vectorDim = vectorDimensions;\n\n await this.pool.query(`\n CREATE TABLE IF NOT EXISTS ${TABLE} (\n id TEXT PRIMARY KEY,\n text TEXT NOT NULL,\n vector vector(${vectorDimensions}),\n timestamp BIGINT DEFAULT 0,\n scope TEXT DEFAULT 'global',\n importance REAL DEFAULT 0.5,\n category TEXT DEFAULT 'other',\n metadata JSONB DEFAULT '{}'::jsonb\n )\n `);\n\n // Create HNSW index for vector search\n await this.pool.query(`\n CREATE INDEX IF NOT EXISTS ${TABLE}_vector_idx\n ON ${TABLE} USING hnsw (vector vector_cosine_ops)\n `).catch(() => {}); // ignore if already exists\n\n // Create GIN index for full-text search\n await this.pool.query(`\n CREATE INDEX IF NOT EXISTS ${TABLE}_text_idx\n ON ${TABLE} USING gin (to_tsvector('simple', text))\n `).catch(() => {});\n\n // Create index on scope for filtering\n await this.pool.query(`\n CREATE INDEX IF NOT EXISTS ${TABLE}_scope_idx ON ${TABLE} (scope)\n `).catch(() => {});\n }\n\n async add(records: MemoryRecord[]): Promise<void> {\n for (const r of records) {\n await this.pool.query(\n `INSERT INTO ${TABLE} (id, text, vector, timestamp, scope, importance, category, metadata)\n VALUES ($1, $2, $3::vector, $4, $5, $6, $7, $8)\n ON CONFLICT (id) DO UPDATE SET\n text = EXCLUDED.text,\n vector = EXCLUDED.vector,\n timestamp = EXCLUDED.timestamp,\n scope = EXCLUDED.scope,\n importance = EXCLUDED.importance,\n category = EXCLUDED.category,\n metadata = EXCLUDED.metadata`,\n [r.id, r.text, `[${r.vector.join(\",\")}]`, r.timestamp, r.scope, r.importance, r.category, r.metadata],\n );\n }\n }\n\n async update(id: string, record: MemoryRecord): Promise<void> {\n await this.add([record]);\n }\n\n async delete(filter: string): Promise<void> {\n const idMatch = filter.match(/id\\s*=\\s*'([^']+)'/);\n if (idMatch) {\n await this.pool.query(`DELETE FROM ${TABLE} WHERE id = $1`, [idMatch[1]]);\n } else {\n // Pass filter as-is for simple SQL WHERE clauses\n await this.pool.query(`DELETE FROM ${TABLE} WHERE ${filter}`);\n }\n }\n\n async vectorSearch(\n vector: number[],\n limit: number,\n minScore = 0,\n scopeFilter?: string[],\n ): Promise<SearchResult[]> {\n const vectorStr = `[${vector.join(\",\")}]`;\n let query = `\n SELECT *, 1 - (vector <=> $1::vector) AS score\n FROM ${TABLE}\n WHERE 1 - (vector <=> $1::vector) >= $2\n `;\n const params: any[] = [vectorStr, minScore];\n\n if (scopeFilter?.length) {\n query += ` AND scope = ANY($3)`;\n params.push(scopeFilter);\n }\n\n query += ` ORDER BY vector <=> $1::vector LIMIT $${params.length + 1}`;\n params.push(limit);\n\n const result = await this.pool.query(query, params);\n\n return result.rows.map((row: any) => ({\n record: this.toRecord(row),\n score: parseFloat(row.score),\n }));\n }\n\n async fullTextSearch(\n queryText: string,\n limit: number,\n scopeFilter?: string[],\n ): Promise<SearchResult[]> {\n // Use PostgreSQL full-text search with ts_rank\n let query = `\n SELECT *, ts_rank(to_tsvector('simple', text), plainto_tsquery('simple', $1)) AS score\n FROM ${TABLE}\n WHERE to_tsvector('simple', text) @@ plainto_tsquery('simple', $1)\n `;\n const params: any[] = [queryText];\n\n if (scopeFilter?.length) {\n query += ` AND scope = ANY($2)`;\n params.push(scopeFilter);\n }\n\n query += ` ORDER BY score DESC LIMIT $${params.length + 1}`;\n params.push(limit);\n\n const result = await this.pool.query(query, params);\n\n return result.rows.map((row: any) => ({\n record: this.toRecord(row),\n score: parseFloat(row.score),\n }));\n }\n\n async query(options: QueryOptions): Promise<MemoryRecord[]> {\n let query = `SELECT * FROM ${TABLE}`;\n if (options.where) query += ` WHERE ${options.where}`;\n query += ` LIMIT ${options.limit || 100}`;\n\n const result = await this.pool.query(query);\n return result.rows.map((row: any) => this.toRecord(row));\n }\n\n async count(filter?: string): Promise<number> {\n let query = `SELECT COUNT(*) FROM ${TABLE}`;\n if (filter) query += ` WHERE ${filter}`;\n const result = await this.pool.query(query);\n return parseInt(result.rows[0].count);\n }\n\n async ensureFullTextIndex(): Promise<void> {\n // Created in ensureTable\n }\n\n hasFullTextSearch(): boolean {\n return true; // PostgreSQL has native full-text search\n }\n\n async close(): Promise<void> {\n if (this.pool) {\n await this.pool.end();\n this.pool = null;\n }\n }\n\n // \u2500\u2500 Helpers \u2500\u2500\n\n private toRecord(row: any): MemoryRecord {\n return {\n id: row.id,\n text: row.text,\n vector: row.vector ? (typeof row.vector === \"string\" ? JSON.parse(row.vector) : Array.from(row.vector)) : [],\n timestamp: parseInt(row.timestamp) || 0,\n scope: row.scope ?? \"global\",\n importance: parseFloat(row.importance) || 0.5,\n category: row.category ?? \"other\",\n metadata: typeof row.metadata === \"object\" ? JSON.stringify(row.metadata) : (row.metadata ?? \"{}\"),\n };\n }\n}\n\nregisterAdapter(\"pgvector\", (config) => new PGVectorAdapter(config));\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Qdrant Storage Adapter for Mnemo
|
|
3
|
+
*
|
|
4
|
+
* Requirements:
|
|
5
|
+
* npm install @qdrant/js-client-rest
|
|
6
|
+
*
|
|
7
|
+
* Config:
|
|
8
|
+
* storage: "qdrant"
|
|
9
|
+
* storageConfig: { url: "http://localhost:6333", apiKey?: "..." }
|
|
10
|
+
*/
|
|
11
|
+
import type { StorageAdapter, MemoryRecord, SearchResult, QueryOptions } from "../storage-adapter.js";
|
|
12
|
+
export declare class QdrantAdapter implements StorageAdapter {
|
|
13
|
+
readonly name = "qdrant";
|
|
14
|
+
private client;
|
|
15
|
+
private url;
|
|
16
|
+
private apiKey?;
|
|
17
|
+
private vectorDim;
|
|
18
|
+
constructor(config?: Record<string, unknown>);
|
|
19
|
+
connect(): Promise<void>;
|
|
20
|
+
ensureTable(vectorDimensions: number): Promise<void>;
|
|
21
|
+
add(records: MemoryRecord[]): Promise<void>;
|
|
22
|
+
update(id: string, record: MemoryRecord): Promise<void>;
|
|
23
|
+
delete(filter: string): Promise<void>;
|
|
24
|
+
vectorSearch(vector: number[], limit: number, minScore?: number, scopeFilter?: string[]): Promise<SearchResult[]>;
|
|
25
|
+
fullTextSearch(_query: string, _limit: number, _scopeFilter?: string[]): Promise<SearchResult[]>;
|
|
26
|
+
query(options: QueryOptions): Promise<MemoryRecord[]>;
|
|
27
|
+
count(filter?: string): Promise<number>;
|
|
28
|
+
ensureFullTextIndex(): Promise<void>;
|
|
29
|
+
hasFullTextSearch(): boolean;
|
|
30
|
+
close(): Promise<void>;
|
|
31
|
+
private toRecord;
|
|
32
|
+
private parseFilter;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=qdrant.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qdrant.d.ts","sourceRoot":"","sources":["../../../src/adapters/qdrant.ts"],"names":[],"mappings":"AACA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,YAAY,EACb,MAAM,uBAAuB,CAAC;AAK/B,qBAAa,aAAc,YAAW,cAAc;IAClD,QAAQ,CAAC,IAAI,YAAY;IAEzB,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,GAAG,CAAmC;IAC9C,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,SAAS,CAAK;gBAEV,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAKtC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAQxB,WAAW,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBpD,GAAG,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB3C,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvD,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUrC,YAAY,CAChB,MAAM,EAAE,MAAM,EAAE,EAChB,KAAK,EAAE,MAAM,EACb,QAAQ,SAAI,EACZ,WAAW,CAAC,EAAE,MAAM,EAAE,GACrB,OAAO,CAAC,YAAY,EAAE,CAAC;IAmBpB,cAAc,CAClB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,YAAY,EAAE,CAAC;IAMpB,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAerD,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAQvC,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAK1C,iBAAiB,IAAI,OAAO;IAItB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAM5B,OAAO,CAAC,QAAQ;IAahB,OAAO,CAAC,WAAW;CASpB"}
|