@melandlabs/memory-store 0.2.0 → 0.2.2
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/http.js +211 -44
- package/dist/index.js +143 -29
- package/dist/mcp.js +169 -37
- package/dist/search/unified-search.js +166 -32
- package/dist/server/cli-http.js +236 -48
- package/dist/server/cli-mcp.js +194 -41
- package/dist/server/cli-shared.js +20 -5
- package/package.json +81 -93
package/dist/mcp.js
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
-
import { z } from 'zod';
|
|
4
1
|
import { buildMemoryRecordEmbeddingDocument } from '@melandlabs/ai/memory';
|
|
5
2
|
import { ChromaVectorStore } from '@melandlabs/rag';
|
|
6
3
|
import { mkdirSync } from 'fs';
|
|
7
4
|
import { homedir } from 'os';
|
|
8
|
-
import {
|
|
5
|
+
import { dirname, join } from 'path';
|
|
9
6
|
import { SQLiteRawMessageManager } from '@melandlabs/sqlite';
|
|
7
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
8
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
9
|
+
import { z } from 'zod';
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
var __defProp = Object.defineProperty;
|
|
12
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
13
|
+
var __esm = (fn, res) => function __init() {
|
|
14
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
15
|
+
};
|
|
16
|
+
var __export = (target, all) => {
|
|
17
|
+
for (var name in all)
|
|
18
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
19
|
+
};
|
|
12
20
|
|
|
13
21
|
// src/contracts.ts
|
|
14
22
|
function normalizeTimestampToMs(value) {
|
|
@@ -32,14 +40,10 @@ function rawMessageToMemoryRecord(message) {
|
|
|
32
40
|
embeddingContentHash: message.embeddingContentHash
|
|
33
41
|
};
|
|
34
42
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"RAW_MESSAGE_VECTOR_STORE_BACKEND",
|
|
40
|
-
"MEMORY_VECTOR_STORE_BACKEND",
|
|
41
|
-
"VECTOR_STORE_BACKEND"
|
|
42
|
-
];
|
|
43
|
+
var init_contracts = __esm({
|
|
44
|
+
"src/contracts.ts"() {
|
|
45
|
+
}
|
|
46
|
+
});
|
|
43
47
|
function getBackend(keys) {
|
|
44
48
|
for (const key of keys) {
|
|
45
49
|
const value = process.env[key]?.trim().toLowerCase();
|
|
@@ -142,21 +146,51 @@ async function searchRawMessagesWithChroma(input) {
|
|
|
142
146
|
metadata: result.metadata ?? {}
|
|
143
147
|
})).slice(0, input.limit);
|
|
144
148
|
}
|
|
149
|
+
var DEFAULT_RAW_MESSAGES_COLLECTION, RAW_VECTOR_BACKEND_ENV_KEYS;
|
|
150
|
+
var init_chroma_memory_index = __esm({
|
|
151
|
+
"src/storage/chroma-memory-index.ts"() {
|
|
152
|
+
init_contracts();
|
|
153
|
+
DEFAULT_RAW_MESSAGES_COLLECTION = "opencontext_raw_messages";
|
|
154
|
+
RAW_VECTOR_BACKEND_ENV_KEYS = [
|
|
155
|
+
"RAW_MESSAGE_VECTOR_STORE_BACKEND",
|
|
156
|
+
"MEMORY_VECTOR_STORE_BACKEND",
|
|
157
|
+
"VECTOR_STORE_BACKEND"
|
|
158
|
+
];
|
|
159
|
+
}
|
|
160
|
+
});
|
|
145
161
|
|
|
146
162
|
// src/storage/postgres-raw-message-factory.ts
|
|
147
|
-
var factory = null;
|
|
148
163
|
async function resolvePostgresFactory(env) {
|
|
149
|
-
return null;
|
|
164
|
+
if (!factory) return null;
|
|
165
|
+
return await factory(env);
|
|
150
166
|
}
|
|
151
167
|
function hasPostgresFactory() {
|
|
152
168
|
return factory !== null;
|
|
153
169
|
}
|
|
154
|
-
var
|
|
155
|
-
var
|
|
170
|
+
var factory;
|
|
171
|
+
var init_postgres_raw_message_factory = __esm({
|
|
172
|
+
"src/storage/postgres-raw-message-factory.ts"() {
|
|
173
|
+
factory = null;
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// src/storage/sqlite-raw-message-store.ts
|
|
178
|
+
var sqlite_raw_message_store_exports = {};
|
|
179
|
+
__export(sqlite_raw_message_store_exports, {
|
|
180
|
+
__resetSQLiteRawMessageManagerForTests: () => __resetSQLiteRawMessageManagerForTests,
|
|
181
|
+
closeSQLiteRawMessageManager: () => closeSQLiteRawMessageManager,
|
|
182
|
+
getSQLiteRawMessageManager: () => getSQLiteRawMessageManager,
|
|
183
|
+
isSQLiteRawMessageStorageAvailable: () => isSQLiteRawMessageStorageAvailable,
|
|
184
|
+
lexicalSearchRawMessages: () => lexicalSearchRawMessages,
|
|
185
|
+
resolveSQLiteRawMessageDbPath: () => resolveSQLiteRawMessageDbPath
|
|
186
|
+
});
|
|
156
187
|
function resolveSQLiteRawMessageDbPath() {
|
|
157
188
|
const fromEnv = process.env.MEMORY_STORE_DB_PATH?.trim();
|
|
158
189
|
return fromEnv && fromEnv.length > 0 ? fromEnv : DEFAULT_SQLITE_PATH;
|
|
159
190
|
}
|
|
191
|
+
function isSQLiteRawMessageStorageAvailable(_env) {
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
160
194
|
async function getSQLiteRawMessageManager(_env) {
|
|
161
195
|
if (!manager) {
|
|
162
196
|
const dbPath = resolveSQLiteRawMessageDbPath();
|
|
@@ -176,8 +210,35 @@ async function closeSQLiteRawMessageManager() {
|
|
|
176
210
|
await manager.close();
|
|
177
211
|
manager = null;
|
|
178
212
|
}
|
|
213
|
+
function __resetSQLiteRawMessageManagerForTests() {
|
|
214
|
+
manager = null;
|
|
215
|
+
}
|
|
216
|
+
async function lexicalSearchRawMessages(input) {
|
|
217
|
+
const mgr = await getSQLiteRawMessageManager();
|
|
218
|
+
if (typeof mgr.lexicalSearchMessages !== "function") {
|
|
219
|
+
return [];
|
|
220
|
+
}
|
|
221
|
+
return mgr.lexicalSearchMessages(input);
|
|
222
|
+
}
|
|
223
|
+
var manager, DEFAULT_SQLITE_PATH;
|
|
224
|
+
var init_sqlite_raw_message_store = __esm({
|
|
225
|
+
"src/storage/sqlite-raw-message-store.ts"() {
|
|
226
|
+
init_chroma_memory_index();
|
|
227
|
+
manager = null;
|
|
228
|
+
DEFAULT_SQLITE_PATH = join(homedir(), ".opencontext", "memory", "store.db");
|
|
229
|
+
}
|
|
230
|
+
});
|
|
179
231
|
|
|
180
232
|
// src/storage/raw-message-store.ts
|
|
233
|
+
var raw_message_store_exports = {};
|
|
234
|
+
__export(raw_message_store_exports, {
|
|
235
|
+
closeRawMessageStore: () => closeRawMessageStore,
|
|
236
|
+
configureRawMessageStore: () => configureRawMessageStore,
|
|
237
|
+
createRawMessageStore: () => createRawMessageStore,
|
|
238
|
+
getRawMessageManager: () => getRawMessageManager,
|
|
239
|
+
getRawMessageStorageBackend: () => getRawMessageStorageBackend,
|
|
240
|
+
isRawMessageStorageAvailable: () => isRawMessageStorageAvailable
|
|
241
|
+
});
|
|
181
242
|
function resolveBackend(env) {
|
|
182
243
|
const explicit = process.env.OPENCONTEXT_MEMORY_STORE_BACKEND?.trim().toLowerCase();
|
|
183
244
|
if (explicit === "postgres") return "postgres";
|
|
@@ -187,7 +248,7 @@ function resolveEnv(_env) {
|
|
|
187
248
|
return {};
|
|
188
249
|
}
|
|
189
250
|
function createRawMessageStore(options = {}) {
|
|
190
|
-
resolveEnv(options.env);
|
|
251
|
+
const env = resolveEnv(options.env);
|
|
191
252
|
return {
|
|
192
253
|
getBackend() {
|
|
193
254
|
return resolveBackend();
|
|
@@ -197,7 +258,7 @@ function createRawMessageStore(options = {}) {
|
|
|
197
258
|
},
|
|
198
259
|
async getManager() {
|
|
199
260
|
if (resolveBackend() === "postgres") {
|
|
200
|
-
const pg = await resolvePostgresFactory();
|
|
261
|
+
const pg = await resolvePostgresFactory(env);
|
|
201
262
|
if (!pg) {
|
|
202
263
|
throw new Error(
|
|
203
264
|
"OPENCONTEXT_MEMORY_STORE_BACKEND=postgres but no Postgres factory is registered. Call registerPostgresFactory() at startup, or unset the env var to use the default SQLite backend."
|
|
@@ -212,14 +273,47 @@ function createRawMessageStore(options = {}) {
|
|
|
212
273
|
}
|
|
213
274
|
};
|
|
214
275
|
}
|
|
215
|
-
|
|
216
|
-
|
|
276
|
+
function configureRawMessageStore(config) {
|
|
277
|
+
moduleConfig = config;
|
|
278
|
+
moduleStore = createRawMessageStore({ env: config.env });
|
|
279
|
+
return moduleStore;
|
|
280
|
+
}
|
|
281
|
+
function getRawMessageStorageBackend() {
|
|
282
|
+
if (!moduleStore) {
|
|
283
|
+
moduleStore = createRawMessageStore({ env: moduleConfig?.env });
|
|
284
|
+
}
|
|
285
|
+
return moduleStore.getBackend();
|
|
286
|
+
}
|
|
217
287
|
function isRawMessageStorageAvailable() {
|
|
218
288
|
if (!moduleStore) {
|
|
219
289
|
moduleStore = createRawMessageStore({ env: moduleConfig?.env });
|
|
220
290
|
}
|
|
221
291
|
return moduleStore.isAvailable();
|
|
222
292
|
}
|
|
293
|
+
async function getRawMessageManager() {
|
|
294
|
+
if (!moduleStore) {
|
|
295
|
+
moduleStore = createRawMessageStore({ env: moduleConfig?.env });
|
|
296
|
+
}
|
|
297
|
+
return moduleStore.getManager();
|
|
298
|
+
}
|
|
299
|
+
async function closeRawMessageStore() {
|
|
300
|
+
if (!moduleStore) return;
|
|
301
|
+
await moduleStore.close();
|
|
302
|
+
moduleStore = null;
|
|
303
|
+
}
|
|
304
|
+
var moduleStore, moduleConfig;
|
|
305
|
+
var init_raw_message_store = __esm({
|
|
306
|
+
"src/storage/raw-message-store.ts"() {
|
|
307
|
+
init_postgres_raw_message_factory();
|
|
308
|
+
init_sqlite_raw_message_store();
|
|
309
|
+
moduleStore = null;
|
|
310
|
+
moduleConfig = null;
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
// src/search/unified-search.ts
|
|
315
|
+
init_chroma_memory_index();
|
|
316
|
+
init_raw_message_store();
|
|
223
317
|
|
|
224
318
|
// src/search/utilities.ts
|
|
225
319
|
var DEFAULT_LIMIT = 10;
|
|
@@ -363,7 +457,7 @@ function createUnifiedSearch(deps = {}) {
|
|
|
363
457
|
warnings.push({
|
|
364
458
|
source: "memory",
|
|
365
459
|
code: "memory_search_failed",
|
|
366
|
-
message: error.message ?? "
|
|
460
|
+
message: `Memory search failed: ${error.message ?? "Unknown error"}. Using keyword search fallback.`
|
|
367
461
|
});
|
|
368
462
|
}
|
|
369
463
|
} else {
|
|
@@ -403,13 +497,7 @@ function createUnifiedSearch(deps = {}) {
|
|
|
403
497
|
message: error.message ?? "insights_search_failed"
|
|
404
498
|
});
|
|
405
499
|
}
|
|
406
|
-
} else if (sources.includes("insights"))
|
|
407
|
-
warnings.push({
|
|
408
|
-
source: "insights",
|
|
409
|
-
code: "insights_search_not_configured",
|
|
410
|
-
message: "Insights search is not configured for this host."
|
|
411
|
-
});
|
|
412
|
-
}
|
|
500
|
+
} else if (sources.includes("insights")) ;
|
|
413
501
|
const knowledgeHits = [];
|
|
414
502
|
if (sources.includes("knowledge") && typeof deps.searchKnowledge === "function") {
|
|
415
503
|
try {
|
|
@@ -434,13 +522,7 @@ function createUnifiedSearch(deps = {}) {
|
|
|
434
522
|
message: error.message ?? "knowledge_search_failed"
|
|
435
523
|
});
|
|
436
524
|
}
|
|
437
|
-
} else if (sources.includes("knowledge"))
|
|
438
|
-
warnings.push({
|
|
439
|
-
source: "knowledge",
|
|
440
|
-
code: "knowledge_search_not_configured",
|
|
441
|
-
message: "Knowledge search is not configured for this host."
|
|
442
|
-
});
|
|
443
|
-
}
|
|
525
|
+
} else if (sources.includes("knowledge")) ;
|
|
444
526
|
const merged = mergeAcrossSources({
|
|
445
527
|
memorySubs,
|
|
446
528
|
insightHits,
|
|
@@ -458,7 +540,33 @@ function createUnifiedSearch(deps = {}) {
|
|
|
458
540
|
}
|
|
459
541
|
async function runMemorySource(input, limit, threshold, warnings) {
|
|
460
542
|
if (typeof deps.embedQuery !== "function") {
|
|
461
|
-
|
|
543
|
+
warnings.push({
|
|
544
|
+
source: "memory",
|
|
545
|
+
code: "memory_lexical_search_fallback",
|
|
546
|
+
message: "Semantic search not configured, using keyword search as fallback"
|
|
547
|
+
});
|
|
548
|
+
const { lexicalSearchRawMessages: lexicalSearchRawMessages2 } = await Promise.resolve().then(() => (init_sqlite_raw_message_store(), sqlite_raw_message_store_exports));
|
|
549
|
+
const keywords = deriveLexicalKeywords(input.query);
|
|
550
|
+
let lexical2 = [];
|
|
551
|
+
if (keywords.length > 0) {
|
|
552
|
+
try {
|
|
553
|
+
const filters2 = input.botIds && input.botIds.length > 0 ? input.botIds : [void 0];
|
|
554
|
+
const results = await Promise.all(
|
|
555
|
+
filters2.map(
|
|
556
|
+
(botId) => lexicalSearchRawMessages2({
|
|
557
|
+
userId: input.userId,
|
|
558
|
+
keywords,
|
|
559
|
+
limit: Math.ceil(limit / filters2.length),
|
|
560
|
+
botId
|
|
561
|
+
})
|
|
562
|
+
)
|
|
563
|
+
);
|
|
564
|
+
lexical2 = results.flat().filter(Boolean).map(toMemoryResult);
|
|
565
|
+
} catch (error) {
|
|
566
|
+
logger.warn?.("[memory-store] Default lexical search failed:", error);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
return { semantic: [], lexical: lexical2 };
|
|
462
570
|
}
|
|
463
571
|
const queryEmbedding = await deps.embedQuery({
|
|
464
572
|
userId: input.userId,
|
|
@@ -505,6 +613,28 @@ function createUnifiedSearch(deps = {}) {
|
|
|
505
613
|
)
|
|
506
614
|
)).flat().filter(isRawMemorySemanticResult).map(toMemoryResult);
|
|
507
615
|
}
|
|
616
|
+
if (semantic.length === 0) {
|
|
617
|
+
try {
|
|
618
|
+
const { getRawMessageManager: getRawMessageManager2 } = await Promise.resolve().then(() => (init_raw_message_store(), raw_message_store_exports));
|
|
619
|
+
const manager2 = await getRawMessageManager2();
|
|
620
|
+
if (typeof manager2.searchMessagesSemantically === "function") {
|
|
621
|
+
const results = await manager2.searchMessagesSemantically({
|
|
622
|
+
userId: input.userId,
|
|
623
|
+
queryEmbedding,
|
|
624
|
+
limit
|
|
625
|
+
});
|
|
626
|
+
semantic = results.map((r) => ({
|
|
627
|
+
type: "memory",
|
|
628
|
+
id: r.id,
|
|
629
|
+
content: r.content,
|
|
630
|
+
similarity: r.similarity,
|
|
631
|
+
metadata: r.metadata ?? {}
|
|
632
|
+
}));
|
|
633
|
+
}
|
|
634
|
+
} catch (error) {
|
|
635
|
+
logger.warn?.("[memory-store] SQLite semantic search failed:", error);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
508
638
|
let lexical = [];
|
|
509
639
|
if (typeof deps.searchRawMessagesLexical === "function") {
|
|
510
640
|
const keywords = deriveLexicalKeywords(input.query);
|
|
@@ -587,6 +717,8 @@ function mergeAcrossSources(input) {
|
|
|
587
717
|
}
|
|
588
718
|
|
|
589
719
|
// src/mcp.ts
|
|
720
|
+
init_chroma_memory_index();
|
|
721
|
+
init_raw_message_store();
|
|
590
722
|
var DEFAULT_NAME = "@melandlabs/memory-store";
|
|
591
723
|
var DEFAULT_VERSION = "0.1.0";
|
|
592
724
|
async function embedMissingMessages(messages, deps) {
|
|
@@ -2,16 +2,24 @@ import '@melandlabs/ai/memory';
|
|
|
2
2
|
import { ChromaVectorStore } from '@melandlabs/rag';
|
|
3
3
|
import { mkdirSync } from 'fs';
|
|
4
4
|
import { homedir } from 'os';
|
|
5
|
-
import {
|
|
5
|
+
import { dirname, join } from 'path';
|
|
6
6
|
import { SQLiteRawMessageManager } from '@melandlabs/sqlite';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
var
|
|
10
|
-
var
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
var __defProp = Object.defineProperty;
|
|
9
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
10
|
+
var __esm = (fn, res) => function __init() {
|
|
11
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
12
|
+
};
|
|
13
|
+
var __export = (target, all) => {
|
|
14
|
+
for (var name in all)
|
|
15
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// src/contracts.ts
|
|
19
|
+
var init_contracts = __esm({
|
|
20
|
+
"src/contracts.ts"() {
|
|
21
|
+
}
|
|
22
|
+
});
|
|
15
23
|
function getBackend(keys) {
|
|
16
24
|
for (const key of keys) {
|
|
17
25
|
const value = process.env[key]?.trim().toLowerCase();
|
|
@@ -62,21 +70,51 @@ async function searchRawMessagesWithChroma(input) {
|
|
|
62
70
|
metadata: result.metadata ?? {}
|
|
63
71
|
})).slice(0, input.limit);
|
|
64
72
|
}
|
|
73
|
+
var DEFAULT_RAW_MESSAGES_COLLECTION, RAW_VECTOR_BACKEND_ENV_KEYS;
|
|
74
|
+
var init_chroma_memory_index = __esm({
|
|
75
|
+
"src/storage/chroma-memory-index.ts"() {
|
|
76
|
+
init_contracts();
|
|
77
|
+
DEFAULT_RAW_MESSAGES_COLLECTION = "opencontext_raw_messages";
|
|
78
|
+
RAW_VECTOR_BACKEND_ENV_KEYS = [
|
|
79
|
+
"RAW_MESSAGE_VECTOR_STORE_BACKEND",
|
|
80
|
+
"MEMORY_VECTOR_STORE_BACKEND",
|
|
81
|
+
"VECTOR_STORE_BACKEND"
|
|
82
|
+
];
|
|
83
|
+
}
|
|
84
|
+
});
|
|
65
85
|
|
|
66
86
|
// src/storage/postgres-raw-message-factory.ts
|
|
67
|
-
var factory = null;
|
|
68
87
|
async function resolvePostgresFactory(env) {
|
|
69
|
-
return null;
|
|
88
|
+
if (!factory) return null;
|
|
89
|
+
return await factory(env);
|
|
70
90
|
}
|
|
71
91
|
function hasPostgresFactory() {
|
|
72
92
|
return factory !== null;
|
|
73
93
|
}
|
|
74
|
-
var
|
|
75
|
-
var
|
|
94
|
+
var factory;
|
|
95
|
+
var init_postgres_raw_message_factory = __esm({
|
|
96
|
+
"src/storage/postgres-raw-message-factory.ts"() {
|
|
97
|
+
factory = null;
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// src/storage/sqlite-raw-message-store.ts
|
|
102
|
+
var sqlite_raw_message_store_exports = {};
|
|
103
|
+
__export(sqlite_raw_message_store_exports, {
|
|
104
|
+
__resetSQLiteRawMessageManagerForTests: () => __resetSQLiteRawMessageManagerForTests,
|
|
105
|
+
closeSQLiteRawMessageManager: () => closeSQLiteRawMessageManager,
|
|
106
|
+
getSQLiteRawMessageManager: () => getSQLiteRawMessageManager,
|
|
107
|
+
isSQLiteRawMessageStorageAvailable: () => isSQLiteRawMessageStorageAvailable,
|
|
108
|
+
lexicalSearchRawMessages: () => lexicalSearchRawMessages,
|
|
109
|
+
resolveSQLiteRawMessageDbPath: () => resolveSQLiteRawMessageDbPath
|
|
110
|
+
});
|
|
76
111
|
function resolveSQLiteRawMessageDbPath() {
|
|
77
112
|
const fromEnv = process.env.MEMORY_STORE_DB_PATH?.trim();
|
|
78
113
|
return fromEnv && fromEnv.length > 0 ? fromEnv : DEFAULT_SQLITE_PATH;
|
|
79
114
|
}
|
|
115
|
+
function isSQLiteRawMessageStorageAvailable(_env) {
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
80
118
|
async function getSQLiteRawMessageManager(_env) {
|
|
81
119
|
if (!manager) {
|
|
82
120
|
const dbPath = resolveSQLiteRawMessageDbPath();
|
|
@@ -96,8 +134,35 @@ async function closeSQLiteRawMessageManager() {
|
|
|
96
134
|
await manager.close();
|
|
97
135
|
manager = null;
|
|
98
136
|
}
|
|
137
|
+
function __resetSQLiteRawMessageManagerForTests() {
|
|
138
|
+
manager = null;
|
|
139
|
+
}
|
|
140
|
+
async function lexicalSearchRawMessages(input) {
|
|
141
|
+
const mgr = await getSQLiteRawMessageManager();
|
|
142
|
+
if (typeof mgr.lexicalSearchMessages !== "function") {
|
|
143
|
+
return [];
|
|
144
|
+
}
|
|
145
|
+
return mgr.lexicalSearchMessages(input);
|
|
146
|
+
}
|
|
147
|
+
var manager, DEFAULT_SQLITE_PATH;
|
|
148
|
+
var init_sqlite_raw_message_store = __esm({
|
|
149
|
+
"src/storage/sqlite-raw-message-store.ts"() {
|
|
150
|
+
init_chroma_memory_index();
|
|
151
|
+
manager = null;
|
|
152
|
+
DEFAULT_SQLITE_PATH = join(homedir(), ".opencontext", "memory", "store.db");
|
|
153
|
+
}
|
|
154
|
+
});
|
|
99
155
|
|
|
100
156
|
// src/storage/raw-message-store.ts
|
|
157
|
+
var raw_message_store_exports = {};
|
|
158
|
+
__export(raw_message_store_exports, {
|
|
159
|
+
closeRawMessageStore: () => closeRawMessageStore,
|
|
160
|
+
configureRawMessageStore: () => configureRawMessageStore,
|
|
161
|
+
createRawMessageStore: () => createRawMessageStore,
|
|
162
|
+
getRawMessageManager: () => getRawMessageManager,
|
|
163
|
+
getRawMessageStorageBackend: () => getRawMessageStorageBackend,
|
|
164
|
+
isRawMessageStorageAvailable: () => isRawMessageStorageAvailable
|
|
165
|
+
});
|
|
101
166
|
function resolveBackend(env) {
|
|
102
167
|
const explicit = process.env.OPENCONTEXT_MEMORY_STORE_BACKEND?.trim().toLowerCase();
|
|
103
168
|
if (explicit === "postgres") return "postgres";
|
|
@@ -107,7 +172,7 @@ function resolveEnv(_env) {
|
|
|
107
172
|
return {};
|
|
108
173
|
}
|
|
109
174
|
function createRawMessageStore(options = {}) {
|
|
110
|
-
resolveEnv(options.env);
|
|
175
|
+
const env = resolveEnv(options.env);
|
|
111
176
|
return {
|
|
112
177
|
getBackend() {
|
|
113
178
|
return resolveBackend();
|
|
@@ -117,7 +182,7 @@ function createRawMessageStore(options = {}) {
|
|
|
117
182
|
},
|
|
118
183
|
async getManager() {
|
|
119
184
|
if (resolveBackend() === "postgres") {
|
|
120
|
-
const pg = await resolvePostgresFactory();
|
|
185
|
+
const pg = await resolvePostgresFactory(env);
|
|
121
186
|
if (!pg) {
|
|
122
187
|
throw new Error(
|
|
123
188
|
"OPENCONTEXT_MEMORY_STORE_BACKEND=postgres but no Postgres factory is registered. Call registerPostgresFactory() at startup, or unset the env var to use the default SQLite backend."
|
|
@@ -132,14 +197,47 @@ function createRawMessageStore(options = {}) {
|
|
|
132
197
|
}
|
|
133
198
|
};
|
|
134
199
|
}
|
|
135
|
-
|
|
136
|
-
|
|
200
|
+
function configureRawMessageStore(config) {
|
|
201
|
+
moduleConfig = config;
|
|
202
|
+
moduleStore = createRawMessageStore({ env: config.env });
|
|
203
|
+
return moduleStore;
|
|
204
|
+
}
|
|
205
|
+
function getRawMessageStorageBackend() {
|
|
206
|
+
if (!moduleStore) {
|
|
207
|
+
moduleStore = createRawMessageStore({ env: moduleConfig?.env });
|
|
208
|
+
}
|
|
209
|
+
return moduleStore.getBackend();
|
|
210
|
+
}
|
|
137
211
|
function isRawMessageStorageAvailable() {
|
|
138
212
|
if (!moduleStore) {
|
|
139
213
|
moduleStore = createRawMessageStore({ env: moduleConfig?.env });
|
|
140
214
|
}
|
|
141
215
|
return moduleStore.isAvailable();
|
|
142
216
|
}
|
|
217
|
+
async function getRawMessageManager() {
|
|
218
|
+
if (!moduleStore) {
|
|
219
|
+
moduleStore = createRawMessageStore({ env: moduleConfig?.env });
|
|
220
|
+
}
|
|
221
|
+
return moduleStore.getManager();
|
|
222
|
+
}
|
|
223
|
+
async function closeRawMessageStore() {
|
|
224
|
+
if (!moduleStore) return;
|
|
225
|
+
await moduleStore.close();
|
|
226
|
+
moduleStore = null;
|
|
227
|
+
}
|
|
228
|
+
var moduleStore, moduleConfig;
|
|
229
|
+
var init_raw_message_store = __esm({
|
|
230
|
+
"src/storage/raw-message-store.ts"() {
|
|
231
|
+
init_postgres_raw_message_factory();
|
|
232
|
+
init_sqlite_raw_message_store();
|
|
233
|
+
moduleStore = null;
|
|
234
|
+
moduleConfig = null;
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// src/search/unified-search.ts
|
|
239
|
+
init_chroma_memory_index();
|
|
240
|
+
init_raw_message_store();
|
|
143
241
|
|
|
144
242
|
// src/search/utilities.ts
|
|
145
243
|
var DEFAULT_LIMIT = 10;
|
|
@@ -283,7 +381,7 @@ function createUnifiedSearch(deps = {}) {
|
|
|
283
381
|
warnings.push({
|
|
284
382
|
source: "memory",
|
|
285
383
|
code: "memory_search_failed",
|
|
286
|
-
message: error.message ?? "
|
|
384
|
+
message: `Memory search failed: ${error.message ?? "Unknown error"}. Using keyword search fallback.`
|
|
287
385
|
});
|
|
288
386
|
}
|
|
289
387
|
} else {
|
|
@@ -323,13 +421,7 @@ function createUnifiedSearch(deps = {}) {
|
|
|
323
421
|
message: error.message ?? "insights_search_failed"
|
|
324
422
|
});
|
|
325
423
|
}
|
|
326
|
-
} else if (sources.includes("insights"))
|
|
327
|
-
warnings.push({
|
|
328
|
-
source: "insights",
|
|
329
|
-
code: "insights_search_not_configured",
|
|
330
|
-
message: "Insights search is not configured for this host."
|
|
331
|
-
});
|
|
332
|
-
}
|
|
424
|
+
} else if (sources.includes("insights")) ;
|
|
333
425
|
const knowledgeHits = [];
|
|
334
426
|
if (sources.includes("knowledge") && typeof deps.searchKnowledge === "function") {
|
|
335
427
|
try {
|
|
@@ -354,13 +446,7 @@ function createUnifiedSearch(deps = {}) {
|
|
|
354
446
|
message: error.message ?? "knowledge_search_failed"
|
|
355
447
|
});
|
|
356
448
|
}
|
|
357
|
-
} else if (sources.includes("knowledge"))
|
|
358
|
-
warnings.push({
|
|
359
|
-
source: "knowledge",
|
|
360
|
-
code: "knowledge_search_not_configured",
|
|
361
|
-
message: "Knowledge search is not configured for this host."
|
|
362
|
-
});
|
|
363
|
-
}
|
|
449
|
+
} else if (sources.includes("knowledge")) ;
|
|
364
450
|
const merged = mergeAcrossSources({
|
|
365
451
|
memorySubs,
|
|
366
452
|
insightHits,
|
|
@@ -378,7 +464,33 @@ function createUnifiedSearch(deps = {}) {
|
|
|
378
464
|
}
|
|
379
465
|
async function runMemorySource(input, limit, threshold, warnings) {
|
|
380
466
|
if (typeof deps.embedQuery !== "function") {
|
|
381
|
-
|
|
467
|
+
warnings.push({
|
|
468
|
+
source: "memory",
|
|
469
|
+
code: "memory_lexical_search_fallback",
|
|
470
|
+
message: "Semantic search not configured, using keyword search as fallback"
|
|
471
|
+
});
|
|
472
|
+
const { lexicalSearchRawMessages: lexicalSearchRawMessages2 } = await Promise.resolve().then(() => (init_sqlite_raw_message_store(), sqlite_raw_message_store_exports));
|
|
473
|
+
const keywords = deriveLexicalKeywords(input.query);
|
|
474
|
+
let lexical2 = [];
|
|
475
|
+
if (keywords.length > 0) {
|
|
476
|
+
try {
|
|
477
|
+
const filters2 = input.botIds && input.botIds.length > 0 ? input.botIds : [void 0];
|
|
478
|
+
const results = await Promise.all(
|
|
479
|
+
filters2.map(
|
|
480
|
+
(botId) => lexicalSearchRawMessages2({
|
|
481
|
+
userId: input.userId,
|
|
482
|
+
keywords,
|
|
483
|
+
limit: Math.ceil(limit / filters2.length),
|
|
484
|
+
botId
|
|
485
|
+
})
|
|
486
|
+
)
|
|
487
|
+
);
|
|
488
|
+
lexical2 = results.flat().filter(Boolean).map(toMemoryResult);
|
|
489
|
+
} catch (error) {
|
|
490
|
+
logger.warn?.("[memory-store] Default lexical search failed:", error);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
return { semantic: [], lexical: lexical2 };
|
|
382
494
|
}
|
|
383
495
|
const queryEmbedding = await deps.embedQuery({
|
|
384
496
|
userId: input.userId,
|
|
@@ -425,6 +537,28 @@ function createUnifiedSearch(deps = {}) {
|
|
|
425
537
|
)
|
|
426
538
|
)).flat().filter(isRawMemorySemanticResult).map(toMemoryResult);
|
|
427
539
|
}
|
|
540
|
+
if (semantic.length === 0) {
|
|
541
|
+
try {
|
|
542
|
+
const { getRawMessageManager: getRawMessageManager2 } = await Promise.resolve().then(() => (init_raw_message_store(), raw_message_store_exports));
|
|
543
|
+
const manager2 = await getRawMessageManager2();
|
|
544
|
+
if (typeof manager2.searchMessagesSemantically === "function") {
|
|
545
|
+
const results = await manager2.searchMessagesSemantically({
|
|
546
|
+
userId: input.userId,
|
|
547
|
+
queryEmbedding,
|
|
548
|
+
limit
|
|
549
|
+
});
|
|
550
|
+
semantic = results.map((r) => ({
|
|
551
|
+
type: "memory",
|
|
552
|
+
id: r.id,
|
|
553
|
+
content: r.content,
|
|
554
|
+
similarity: r.similarity,
|
|
555
|
+
metadata: r.metadata ?? {}
|
|
556
|
+
}));
|
|
557
|
+
}
|
|
558
|
+
} catch (error) {
|
|
559
|
+
logger.warn?.("[memory-store] SQLite semantic search failed:", error);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
428
562
|
let lexical = [];
|
|
429
563
|
if (typeof deps.searchRawMessagesLexical === "function") {
|
|
430
564
|
const keywords = deriveLexicalKeywords(input.query);
|