@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.
Files changed (220) hide show
  1. package/dist/cli.d.ts +2 -0
  2. package/dist/cli.d.ts.map +1 -0
  3. package/dist/cli.js +7 -0
  4. package/dist/cli.js.map +7 -0
  5. package/dist/index.d.ts +128 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/{index.ts → dist/index.js} +526 -1333
  8. package/dist/index.js.map +7 -0
  9. package/dist/src/access-tracker.d.ts +97 -0
  10. package/dist/src/access-tracker.d.ts.map +1 -0
  11. package/dist/src/access-tracker.js +184 -0
  12. package/dist/src/access-tracker.js.map +7 -0
  13. package/dist/src/adapters/chroma.d.ts +31 -0
  14. package/dist/src/adapters/chroma.d.ts.map +1 -0
  15. package/{src/adapters/chroma.ts → dist/src/adapters/chroma.js} +45 -107
  16. package/dist/src/adapters/chroma.js.map +7 -0
  17. package/dist/src/adapters/lancedb.d.ts +29 -0
  18. package/dist/src/adapters/lancedb.d.ts.map +1 -0
  19. package/{src/adapters/lancedb.ts → dist/src/adapters/lancedb.js} +41 -109
  20. package/dist/src/adapters/lancedb.js.map +7 -0
  21. package/dist/src/adapters/pgvector.d.ts +33 -0
  22. package/dist/src/adapters/pgvector.d.ts.map +1 -0
  23. package/{src/adapters/pgvector.ts → dist/src/adapters/pgvector.js} +42 -104
  24. package/dist/src/adapters/pgvector.js.map +7 -0
  25. package/dist/src/adapters/qdrant.d.ts +34 -0
  26. package/dist/src/adapters/qdrant.d.ts.map +1 -0
  27. package/dist/src/adapters/qdrant.js +132 -0
  28. package/dist/src/adapters/qdrant.js.map +7 -0
  29. package/dist/src/adaptive-retrieval.d.ts +14 -0
  30. package/dist/src/adaptive-retrieval.d.ts.map +1 -0
  31. package/dist/src/adaptive-retrieval.js +52 -0
  32. package/dist/src/adaptive-retrieval.js.map +7 -0
  33. package/dist/src/audit-log.d.ts +56 -0
  34. package/dist/src/audit-log.d.ts.map +1 -0
  35. package/dist/src/audit-log.js +139 -0
  36. package/dist/src/audit-log.js.map +7 -0
  37. package/dist/src/chunker.d.ts +45 -0
  38. package/dist/src/chunker.d.ts.map +1 -0
  39. package/dist/src/chunker.js +157 -0
  40. package/dist/src/chunker.js.map +7 -0
  41. package/dist/src/config.d.ts +70 -0
  42. package/dist/src/config.d.ts.map +1 -0
  43. package/dist/src/config.js +142 -0
  44. package/dist/src/config.js.map +7 -0
  45. package/dist/src/decay-engine.d.ts +73 -0
  46. package/dist/src/decay-engine.d.ts.map +1 -0
  47. package/dist/src/decay-engine.js +119 -0
  48. package/dist/src/decay-engine.js.map +7 -0
  49. package/dist/src/embedder.d.ts +94 -0
  50. package/dist/src/embedder.d.ts.map +1 -0
  51. package/{src/embedder.ts → dist/src/embedder.js} +119 -317
  52. package/dist/src/embedder.js.map +7 -0
  53. package/dist/src/extraction-prompts.d.ts +12 -0
  54. package/dist/src/extraction-prompts.d.ts.map +1 -0
  55. package/dist/src/extraction-prompts.js +311 -0
  56. package/dist/src/extraction-prompts.js.map +7 -0
  57. package/dist/src/license.d.ts +29 -0
  58. package/dist/src/license.d.ts.map +1 -0
  59. package/{src/license.ts → dist/src/license.js} +42 -113
  60. package/dist/src/license.js.map +7 -0
  61. package/dist/src/llm-client.d.ts +23 -0
  62. package/dist/src/llm-client.d.ts.map +1 -0
  63. package/{src/llm-client.ts → dist/src/llm-client.js} +22 -55
  64. package/dist/src/llm-client.js.map +7 -0
  65. package/dist/src/logger.d.ts +33 -0
  66. package/dist/src/logger.d.ts.map +1 -0
  67. package/dist/src/logger.js +35 -0
  68. package/dist/src/logger.js.map +7 -0
  69. package/dist/src/mcp-server.d.ts +16 -0
  70. package/dist/src/mcp-server.d.ts.map +1 -0
  71. package/{src/mcp-server.ts → dist/src/mcp-server.js} +81 -181
  72. package/dist/src/mcp-server.js.map +7 -0
  73. package/dist/src/memory-categories.d.ts +40 -0
  74. package/dist/src/memory-categories.d.ts.map +1 -0
  75. package/dist/src/memory-categories.js +33 -0
  76. package/dist/src/memory-categories.js.map +7 -0
  77. package/dist/src/memory-upgrader.d.ts +71 -0
  78. package/dist/src/memory-upgrader.d.ts.map +1 -0
  79. package/dist/src/memory-upgrader.js +238 -0
  80. package/dist/src/memory-upgrader.js.map +7 -0
  81. package/dist/src/migrate.d.ts +47 -0
  82. package/dist/src/migrate.d.ts.map +1 -0
  83. package/{src/migrate.ts → dist/src/migrate.js} +57 -165
  84. package/dist/src/migrate.js.map +7 -0
  85. package/dist/src/mnemo.d.ts +67 -0
  86. package/dist/src/mnemo.d.ts.map +1 -0
  87. package/dist/src/mnemo.js +66 -0
  88. package/dist/src/mnemo.js.map +7 -0
  89. package/dist/src/noise-filter.d.ts +23 -0
  90. package/dist/src/noise-filter.d.ts.map +1 -0
  91. package/dist/src/noise-filter.js +62 -0
  92. package/dist/src/noise-filter.js.map +7 -0
  93. package/dist/src/noise-prototypes.d.ts +40 -0
  94. package/dist/src/noise-prototypes.d.ts.map +1 -0
  95. package/dist/src/noise-prototypes.js +116 -0
  96. package/dist/src/noise-prototypes.js.map +7 -0
  97. package/dist/src/observability.d.ts +16 -0
  98. package/dist/src/observability.d.ts.map +1 -0
  99. package/dist/src/observability.js +53 -0
  100. package/dist/src/observability.js.map +7 -0
  101. package/dist/src/query-tracker.d.ts +27 -0
  102. package/dist/src/query-tracker.d.ts.map +1 -0
  103. package/dist/src/query-tracker.js +32 -0
  104. package/dist/src/query-tracker.js.map +7 -0
  105. package/dist/src/reflection-event-store.d.ts +44 -0
  106. package/dist/src/reflection-event-store.d.ts.map +1 -0
  107. package/dist/src/reflection-event-store.js +50 -0
  108. package/dist/src/reflection-event-store.js.map +7 -0
  109. package/dist/src/reflection-item-store.d.ts +58 -0
  110. package/dist/src/reflection-item-store.d.ts.map +1 -0
  111. package/dist/src/reflection-item-store.js +69 -0
  112. package/dist/src/reflection-item-store.js.map +7 -0
  113. package/dist/src/reflection-mapped-metadata.d.ts +47 -0
  114. package/dist/src/reflection-mapped-metadata.d.ts.map +1 -0
  115. package/dist/src/reflection-mapped-metadata.js +40 -0
  116. package/dist/src/reflection-mapped-metadata.js.map +7 -0
  117. package/dist/src/reflection-metadata.d.ts +11 -0
  118. package/dist/src/reflection-metadata.d.ts.map +1 -0
  119. package/dist/src/reflection-metadata.js +24 -0
  120. package/dist/src/reflection-metadata.js.map +7 -0
  121. package/dist/src/reflection-ranking.d.ts +13 -0
  122. package/dist/src/reflection-ranking.d.ts.map +1 -0
  123. package/{src/reflection-ranking.ts → dist/src/reflection-ranking.js} +12 -21
  124. package/dist/src/reflection-ranking.js.map +7 -0
  125. package/dist/src/reflection-retry.d.ts +30 -0
  126. package/dist/src/reflection-retry.d.ts.map +1 -0
  127. package/{src/reflection-retry.ts → dist/src/reflection-retry.js} +24 -64
  128. package/dist/src/reflection-retry.js.map +7 -0
  129. package/dist/src/reflection-slices.d.ts +42 -0
  130. package/dist/src/reflection-slices.d.ts.map +1 -0
  131. package/{src/reflection-slices.ts → dist/src/reflection-slices.js} +60 -136
  132. package/dist/src/reflection-slices.js.map +7 -0
  133. package/dist/src/reflection-store.d.ts +85 -0
  134. package/dist/src/reflection-store.d.ts.map +1 -0
  135. package/dist/src/reflection-store.js +407 -0
  136. package/dist/src/reflection-store.js.map +7 -0
  137. package/dist/src/resonance-state.d.ts +19 -0
  138. package/dist/src/resonance-state.d.ts.map +1 -0
  139. package/{src/resonance-state.ts → dist/src/resonance-state.js} +13 -42
  140. package/dist/src/resonance-state.js.map +7 -0
  141. package/dist/src/retriever.d.ts +228 -0
  142. package/dist/src/retriever.d.ts.map +1 -0
  143. package/dist/src/retriever.js +1006 -0
  144. package/dist/src/retriever.js.map +7 -0
  145. package/dist/src/scopes.d.ts +58 -0
  146. package/dist/src/scopes.d.ts.map +1 -0
  147. package/dist/src/scopes.js +252 -0
  148. package/dist/src/scopes.js.map +7 -0
  149. package/dist/src/self-improvement-files.d.ts +20 -0
  150. package/dist/src/self-improvement-files.d.ts.map +1 -0
  151. package/{src/self-improvement-files.ts → dist/src/self-improvement-files.js} +24 -49
  152. package/dist/src/self-improvement-files.js.map +7 -0
  153. package/dist/src/semantic-gate.d.ts +24 -0
  154. package/dist/src/semantic-gate.d.ts.map +1 -0
  155. package/dist/src/semantic-gate.js +86 -0
  156. package/dist/src/semantic-gate.js.map +7 -0
  157. package/dist/src/session-recovery.d.ts +9 -0
  158. package/dist/src/session-recovery.d.ts.map +1 -0
  159. package/{src/session-recovery.ts → dist/src/session-recovery.js} +40 -57
  160. package/dist/src/session-recovery.js.map +7 -0
  161. package/dist/src/smart-extractor.d.ts +107 -0
  162. package/dist/src/smart-extractor.d.ts.map +1 -0
  163. package/{src/smart-extractor.ts → dist/src/smart-extractor.js} +130 -383
  164. package/dist/src/smart-extractor.js.map +7 -0
  165. package/dist/src/smart-metadata.d.ts +103 -0
  166. package/dist/src/smart-metadata.d.ts.map +1 -0
  167. package/dist/src/smart-metadata.js +361 -0
  168. package/dist/src/smart-metadata.js.map +7 -0
  169. package/dist/src/storage-adapter.d.ts +102 -0
  170. package/dist/src/storage-adapter.d.ts.map +1 -0
  171. package/dist/src/storage-adapter.js +22 -0
  172. package/dist/src/storage-adapter.js.map +7 -0
  173. package/dist/src/store.d.ts +108 -0
  174. package/dist/src/store.d.ts.map +1 -0
  175. package/dist/src/store.js +939 -0
  176. package/dist/src/store.js.map +7 -0
  177. package/dist/src/tier-manager.d.ts +57 -0
  178. package/dist/src/tier-manager.d.ts.map +1 -0
  179. package/dist/src/tier-manager.js +80 -0
  180. package/dist/src/tier-manager.js.map +7 -0
  181. package/dist/src/tools.d.ts +43 -0
  182. package/dist/src/tools.d.ts.map +1 -0
  183. package/dist/src/tools.js +1075 -0
  184. package/dist/src/tools.js.map +7 -0
  185. package/dist/src/wal-recovery.d.ts +30 -0
  186. package/dist/src/wal-recovery.d.ts.map +1 -0
  187. package/{src/wal-recovery.ts → dist/src/wal-recovery.js} +26 -79
  188. package/dist/src/wal-recovery.js.map +7 -0
  189. package/package.json +21 -2
  190. package/openclaw.plugin.json +0 -815
  191. package/src/access-tracker.ts +0 -341
  192. package/src/adapters/README.md +0 -78
  193. package/src/adapters/qdrant.ts +0 -191
  194. package/src/adaptive-retrieval.ts +0 -90
  195. package/src/audit-log.ts +0 -238
  196. package/src/chunker.ts +0 -254
  197. package/src/config.ts +0 -271
  198. package/src/decay-engine.ts +0 -238
  199. package/src/extraction-prompts.ts +0 -339
  200. package/src/memory-categories.ts +0 -71
  201. package/src/memory-upgrader.ts +0 -388
  202. package/src/mnemo.ts +0 -142
  203. package/src/noise-filter.ts +0 -97
  204. package/src/noise-prototypes.ts +0 -164
  205. package/src/observability.ts +0 -81
  206. package/src/query-tracker.ts +0 -57
  207. package/src/reflection-event-store.ts +0 -98
  208. package/src/reflection-item-store.ts +0 -112
  209. package/src/reflection-mapped-metadata.ts +0 -84
  210. package/src/reflection-metadata.ts +0 -23
  211. package/src/reflection-store.ts +0 -602
  212. package/src/retriever.ts +0 -1510
  213. package/src/scopes.ts +0 -375
  214. package/src/semantic-gate.ts +0 -121
  215. package/src/smart-metadata.ts +0 -561
  216. package/src/storage-adapter.ts +0 -153
  217. package/src/store.ts +0 -1330
  218. package/src/tier-manager.ts +0 -189
  219. package/src/tools.ts +0 -1292
  220. 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
- export class LanceDBAdapter implements StorageAdapter {
37
- readonly name = "lancedb";
38
-
39
- private db: any = null;
40
- private table: any = null;
41
- private ftsReady = false;
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: MemoryRecord = {
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
- return raw
129
- .map((row: any) => {
130
- const distance = row._distance ?? row.distance ?? 1;
131
- const score = 1 / (1 + distance);
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
- return raw
155
- .map((row: any) => {
156
- const score = row._relevance_score ?? row.score ?? 0.5;
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: any) => this.toRecord(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: any) => idx.indexType === "FTS" || idx.columns?.includes("text"),
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: (lancedb as any).Index.fts(),
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, // preserve extra fields
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": "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",
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
- export class PGVectorAdapter implements StorageAdapter {
25
- readonly name = "pgvector";
26
-
27
- private pool: any = null;
28
- private vectorDim = 0;
29
- private connectionString: string;
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(() => {}); // ignore if already exists
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: any[] = [vectorStr, minScore];
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: any[] = [queryText];
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: any) => this.toRecord(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
- hasFullTextSearch(): boolean {
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 ? (typeof row.vector === "string" ? JSON.parse(row.vector) : Array.from(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) : (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"}