@melandlabs/memory-store 0.1.6 → 0.2.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/{config-D6MzksfT.d.ts → config-BYfTzG3h.d.ts} +17 -0
- package/dist/contracts.d.ts +7 -0
- package/dist/contracts.js +0 -2
- package/dist/http.d.ts +1 -1
- package/dist/http.js +355 -67
- package/dist/index.d.ts +2 -2
- package/dist/index.js +287 -52
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +313 -60
- package/dist/policies/memory-graph-correction-policy.js +0 -2
- package/dist/policies/memory-graph-write-policy.js +0 -2
- package/dist/search/unified-search.d.ts +39 -3
- package/dist/search/unified-search.js +311 -56
- package/dist/server/cli-http.js +360 -66
- package/dist/server/cli-mcp.js +318 -59
- package/dist/server/cli-shared.d.ts +1 -1
- package/dist/server/cli-shared.js +0 -2
- package/dist/storage/chroma-memory-index.js +0 -2
- package/dist/storage/postgres-raw-message-factory.d.ts +1 -1
- package/dist/storage/postgres-raw-message-factory.js +0 -2
- package/dist/storage/raw-message-store.d.ts +9 -1
- package/dist/storage/raw-message-store.js +0 -2
- package/dist/storage/sqlite-raw-message-store.d.ts +15 -2
- package/dist/storage/sqlite-raw-message-store.js +8 -3
- package/dist/storage/sqlite-vector-index.d.ts +1 -1
- package/dist/storage/sqlite-vector-index.js +0 -2
- package/package.json +81 -93
- package/dist/contracts.js.map +0 -1
- package/dist/http.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/mcp.js.map +0 -1
- package/dist/policies/memory-graph-correction-policy.js.map +0 -1
- package/dist/policies/memory-graph-write-policy.js.map +0 -1
- package/dist/search/unified-search.js.map +0 -1
- package/dist/server/cli-http.js.map +0 -1
- package/dist/server/cli-mcp.js.map +0 -1
- package/dist/server/cli-shared.js.map +0 -1
- package/dist/storage/chroma-memory-index.js.map +0 -1
- package/dist/storage/postgres-raw-message-factory.js.map +0 -1
- package/dist/storage/raw-message-store.js.map +0 -1
- package/dist/storage/sqlite-raw-message-store.js.map +0 -1
- package/dist/storage/sqlite-vector-index.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -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,9 +70,20 @@ 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
|
function registerPostgresFactory(fn) {
|
|
69
88
|
factory = fn;
|
|
70
89
|
}
|
|
@@ -78,12 +97,30 @@ async function resolvePostgresFactory(env) {
|
|
|
78
97
|
function hasPostgresFactory() {
|
|
79
98
|
return factory !== null;
|
|
80
99
|
}
|
|
81
|
-
var
|
|
82
|
-
var
|
|
100
|
+
var factory;
|
|
101
|
+
var init_postgres_raw_message_factory = __esm({
|
|
102
|
+
"src/storage/postgres-raw-message-factory.ts"() {
|
|
103
|
+
factory = null;
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// src/storage/sqlite-raw-message-store.ts
|
|
108
|
+
var sqlite_raw_message_store_exports = {};
|
|
109
|
+
__export(sqlite_raw_message_store_exports, {
|
|
110
|
+
__resetSQLiteRawMessageManagerForTests: () => __resetSQLiteRawMessageManagerForTests,
|
|
111
|
+
closeSQLiteRawMessageManager: () => closeSQLiteRawMessageManager,
|
|
112
|
+
getSQLiteRawMessageManager: () => getSQLiteRawMessageManager,
|
|
113
|
+
isSQLiteRawMessageStorageAvailable: () => isSQLiteRawMessageStorageAvailable,
|
|
114
|
+
lexicalSearchRawMessages: () => lexicalSearchRawMessages,
|
|
115
|
+
resolveSQLiteRawMessageDbPath: () => resolveSQLiteRawMessageDbPath
|
|
116
|
+
});
|
|
83
117
|
function resolveSQLiteRawMessageDbPath() {
|
|
84
118
|
const fromEnv = process.env.MEMORY_STORE_DB_PATH?.trim();
|
|
85
119
|
return fromEnv && fromEnv.length > 0 ? fromEnv : DEFAULT_SQLITE_PATH;
|
|
86
120
|
}
|
|
121
|
+
function isSQLiteRawMessageStorageAvailable(_env) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
87
124
|
async function getSQLiteRawMessageManager(_env) {
|
|
88
125
|
if (!manager) {
|
|
89
126
|
const dbPath = resolveSQLiteRawMessageDbPath();
|
|
@@ -103,8 +140,35 @@ async function closeSQLiteRawMessageManager() {
|
|
|
103
140
|
await manager.close();
|
|
104
141
|
manager = null;
|
|
105
142
|
}
|
|
143
|
+
function __resetSQLiteRawMessageManagerForTests() {
|
|
144
|
+
manager = null;
|
|
145
|
+
}
|
|
146
|
+
async function lexicalSearchRawMessages(input) {
|
|
147
|
+
const mgr = await getSQLiteRawMessageManager();
|
|
148
|
+
if (typeof mgr.lexicalSearchMessages !== "function") {
|
|
149
|
+
return [];
|
|
150
|
+
}
|
|
151
|
+
return mgr.lexicalSearchMessages(input);
|
|
152
|
+
}
|
|
153
|
+
var manager, DEFAULT_SQLITE_PATH;
|
|
154
|
+
var init_sqlite_raw_message_store = __esm({
|
|
155
|
+
"src/storage/sqlite-raw-message-store.ts"() {
|
|
156
|
+
init_chroma_memory_index();
|
|
157
|
+
manager = null;
|
|
158
|
+
DEFAULT_SQLITE_PATH = join(homedir(), ".opencontext", "memory", "store.db");
|
|
159
|
+
}
|
|
160
|
+
});
|
|
106
161
|
|
|
107
162
|
// src/storage/raw-message-store.ts
|
|
163
|
+
var raw_message_store_exports = {};
|
|
164
|
+
__export(raw_message_store_exports, {
|
|
165
|
+
closeRawMessageStore: () => closeRawMessageStore,
|
|
166
|
+
configureRawMessageStore: () => configureRawMessageStore,
|
|
167
|
+
createRawMessageStore: () => createRawMessageStore,
|
|
168
|
+
getRawMessageManager: () => getRawMessageManager,
|
|
169
|
+
getRawMessageStorageBackend: () => getRawMessageStorageBackend,
|
|
170
|
+
isRawMessageStorageAvailable: () => isRawMessageStorageAvailable
|
|
171
|
+
});
|
|
108
172
|
function resolveBackend(env) {
|
|
109
173
|
const explicit = process.env.OPENCONTEXT_MEMORY_STORE_BACKEND?.trim().toLowerCase();
|
|
110
174
|
if (explicit === "postgres") return "postgres";
|
|
@@ -139,8 +203,6 @@ function createRawMessageStore(options = {}) {
|
|
|
139
203
|
}
|
|
140
204
|
};
|
|
141
205
|
}
|
|
142
|
-
var moduleStore = null;
|
|
143
|
-
var moduleConfig = null;
|
|
144
206
|
function configureRawMessageStore(config) {
|
|
145
207
|
moduleConfig = config;
|
|
146
208
|
moduleStore = createRawMessageStore({ env: config.env });
|
|
@@ -169,6 +231,19 @@ async function closeRawMessageStore() {
|
|
|
169
231
|
await moduleStore.close();
|
|
170
232
|
moduleStore = null;
|
|
171
233
|
}
|
|
234
|
+
var moduleStore, moduleConfig;
|
|
235
|
+
var init_raw_message_store = __esm({
|
|
236
|
+
"src/storage/raw-message-store.ts"() {
|
|
237
|
+
init_postgres_raw_message_factory();
|
|
238
|
+
init_sqlite_raw_message_store();
|
|
239
|
+
moduleStore = null;
|
|
240
|
+
moduleConfig = null;
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// src/search/unified-search.ts
|
|
245
|
+
init_chroma_memory_index();
|
|
246
|
+
init_raw_message_store();
|
|
172
247
|
|
|
173
248
|
// src/search/utilities.ts
|
|
174
249
|
var DEFAULT_LIMIT = 10;
|
|
@@ -198,7 +273,14 @@ function clampUnifiedMemorySearchThreshold(threshold) {
|
|
|
198
273
|
}
|
|
199
274
|
return Math.min(1, Math.max(-1, parsed));
|
|
200
275
|
}
|
|
201
|
-
function mergeUnifiedMemorySearchResults(results, limit) {
|
|
276
|
+
function mergeUnifiedMemorySearchResults(results, limit, options = {}) {
|
|
277
|
+
const strategy = normalizeUnifiedMemoryMergeStrategy(options.strategy);
|
|
278
|
+
if (strategy === "rrf") {
|
|
279
|
+
const lists = options.rankedLists ?? [
|
|
280
|
+
{ name: "memory-semantic", hits: results }
|
|
281
|
+
];
|
|
282
|
+
return mergeUnifiedMemorySearchResultsRrf(lists, limit);
|
|
283
|
+
}
|
|
202
284
|
return [...results].sort((a, b) => {
|
|
203
285
|
const scoreDelta = b.similarity - a.similarity;
|
|
204
286
|
if (scoreDelta !== 0) {
|
|
@@ -207,6 +289,42 @@ function mergeUnifiedMemorySearchResults(results, limit) {
|
|
|
207
289
|
return a.type.localeCompare(b.type) || a.id.localeCompare(b.id);
|
|
208
290
|
}).slice(0, limit);
|
|
209
291
|
}
|
|
292
|
+
function normalizeUnifiedMemoryMergeStrategy(value) {
|
|
293
|
+
return value === "rrf" ? "rrf" : "similarity";
|
|
294
|
+
}
|
|
295
|
+
var DEFAULT_RRF_K = 60;
|
|
296
|
+
function mergeUnifiedMemorySearchResultsRrf(lists, limit, k = DEFAULT_RRF_K) {
|
|
297
|
+
if (!Array.isArray(lists) || lists.length === 0) {
|
|
298
|
+
return [];
|
|
299
|
+
}
|
|
300
|
+
const safeK = Number.isFinite(k) && k > 0 ? k : DEFAULT_RRF_K;
|
|
301
|
+
const scores = /* @__PURE__ */ new Map();
|
|
302
|
+
const order = [];
|
|
303
|
+
for (const list of lists) {
|
|
304
|
+
for (let index = 0; index < list.hits.length; index += 1) {
|
|
305
|
+
const hit = list.hits[index];
|
|
306
|
+
const key = `${hit.type}::${hit.id}`;
|
|
307
|
+
const contribution = 1 / (safeK + index + 1);
|
|
308
|
+
const existing = scores.get(key);
|
|
309
|
+
if (existing) {
|
|
310
|
+
existing.rrf += contribution;
|
|
311
|
+
} else {
|
|
312
|
+
scores.set(key, { hit, rrf: contribution });
|
|
313
|
+
order.push(key);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
const ranked = order.map((key) => scores.get(key)).sort((a, b) => {
|
|
318
|
+
if (b.rrf !== a.rrf) {
|
|
319
|
+
return b.rrf - a.rrf;
|
|
320
|
+
}
|
|
321
|
+
return a.hit.type.localeCompare(b.hit.type) || a.hit.id.localeCompare(b.hit.id);
|
|
322
|
+
}).slice(0, limit);
|
|
323
|
+
return ranked.map(({ hit, rrf }) => ({
|
|
324
|
+
...hit,
|
|
325
|
+
metadata: { ...hit.metadata, rrfScore: rrf }
|
|
326
|
+
}));
|
|
327
|
+
}
|
|
210
328
|
function toKnowledgeResult(result) {
|
|
211
329
|
return {
|
|
212
330
|
type: "knowledge",
|
|
@@ -238,6 +356,9 @@ function isRawMemorySemanticResult(result) {
|
|
|
238
356
|
}
|
|
239
357
|
|
|
240
358
|
// src/search/unified-search.ts
|
|
359
|
+
function deriveLexicalKeywords(query) {
|
|
360
|
+
return query.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((token) => token.length >= 2).slice(0, 16);
|
|
361
|
+
}
|
|
241
362
|
function createUnifiedSearch(deps = {}) {
|
|
242
363
|
const logger = deps.logger ?? console;
|
|
243
364
|
async function searchUnifiedMemory(input) {
|
|
@@ -245,8 +366,8 @@ function createUnifiedSearch(deps = {}) {
|
|
|
245
366
|
const sources = normalizeUnifiedMemorySearchSources(input.sources);
|
|
246
367
|
const limit = clampUnifiedMemorySearchLimit(input.limit);
|
|
247
368
|
const threshold = clampUnifiedMemorySearchThreshold(input.threshold);
|
|
369
|
+
const mergeStrategy = normalizeUnifiedMemoryMergeStrategy(input.mergeStrategy);
|
|
248
370
|
const warnings = [];
|
|
249
|
-
const results = [];
|
|
250
371
|
if (!query) {
|
|
251
372
|
return {
|
|
252
373
|
query,
|
|
@@ -256,17 +377,17 @@ function createUnifiedSearch(deps = {}) {
|
|
|
256
377
|
warnings
|
|
257
378
|
};
|
|
258
379
|
}
|
|
380
|
+
let memorySubs;
|
|
259
381
|
if (sources.includes("memory")) {
|
|
260
382
|
if (isRawMessageStorageAvailable()) {
|
|
261
383
|
try {
|
|
262
|
-
|
|
263
|
-
results.push(...memoryHits);
|
|
384
|
+
memorySubs = await runMemorySource(input, limit, threshold, warnings);
|
|
264
385
|
} catch (error) {
|
|
265
386
|
logger.warn?.("[memory-store] memory source failed:", error);
|
|
266
387
|
warnings.push({
|
|
267
388
|
source: "memory",
|
|
268
389
|
code: "memory_search_failed",
|
|
269
|
-
message: error.message ?? "
|
|
390
|
+
message: `Memory search failed: ${error.message ?? "Unknown error"}. Using keyword search fallback.`
|
|
270
391
|
});
|
|
271
392
|
}
|
|
272
393
|
} else {
|
|
@@ -277,9 +398,10 @@ function createUnifiedSearch(deps = {}) {
|
|
|
277
398
|
});
|
|
278
399
|
}
|
|
279
400
|
}
|
|
401
|
+
const insightHits = [];
|
|
280
402
|
if (sources.includes("insights") && typeof deps.searchInsights === "function") {
|
|
281
403
|
try {
|
|
282
|
-
const
|
|
404
|
+
const hits = await deps.searchInsights({
|
|
283
405
|
userId: input.userId,
|
|
284
406
|
query: input.query,
|
|
285
407
|
limit,
|
|
@@ -288,8 +410,8 @@ function createUnifiedSearch(deps = {}) {
|
|
|
288
410
|
includeArchived: input.includeArchivedInsights,
|
|
289
411
|
authToken: input.authToken
|
|
290
412
|
});
|
|
291
|
-
for (const hit of
|
|
292
|
-
|
|
413
|
+
for (const hit of hits) {
|
|
414
|
+
insightHits.push({
|
|
293
415
|
type: "insight",
|
|
294
416
|
id: hit.id,
|
|
295
417
|
content: hit.content,
|
|
@@ -305,16 +427,11 @@ function createUnifiedSearch(deps = {}) {
|
|
|
305
427
|
message: error.message ?? "insights_search_failed"
|
|
306
428
|
});
|
|
307
429
|
}
|
|
308
|
-
} else if (sources.includes("insights"))
|
|
309
|
-
|
|
310
|
-
source: "insights",
|
|
311
|
-
code: "insights_search_not_configured",
|
|
312
|
-
message: "Insights search is not configured for this host."
|
|
313
|
-
});
|
|
314
|
-
}
|
|
430
|
+
} else if (sources.includes("insights")) ;
|
|
431
|
+
const knowledgeHits = [];
|
|
315
432
|
if (sources.includes("knowledge") && typeof deps.searchKnowledge === "function") {
|
|
316
433
|
try {
|
|
317
|
-
const
|
|
434
|
+
const hits = await deps.searchKnowledge({
|
|
318
435
|
userId: input.userId,
|
|
319
436
|
query: input.query,
|
|
320
437
|
options: {
|
|
@@ -324,8 +441,8 @@ function createUnifiedSearch(deps = {}) {
|
|
|
324
441
|
},
|
|
325
442
|
authToken: input.authToken
|
|
326
443
|
});
|
|
327
|
-
for (const hit of
|
|
328
|
-
|
|
444
|
+
for (const hit of hits) {
|
|
445
|
+
knowledgeHits.push(toKnowledgeResult(hit));
|
|
329
446
|
}
|
|
330
447
|
} catch (error) {
|
|
331
448
|
logger.warn?.("[memory-store] knowledge source failed:", error);
|
|
@@ -335,14 +452,14 @@ function createUnifiedSearch(deps = {}) {
|
|
|
335
452
|
message: error.message ?? "knowledge_search_failed"
|
|
336
453
|
});
|
|
337
454
|
}
|
|
338
|
-
} else if (sources.includes("knowledge"))
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
455
|
+
} else if (sources.includes("knowledge")) ;
|
|
456
|
+
const merged = mergeAcrossSources({
|
|
457
|
+
memorySubs,
|
|
458
|
+
insightHits,
|
|
459
|
+
knowledgeHits,
|
|
460
|
+
limit,
|
|
461
|
+
strategy: mergeStrategy
|
|
462
|
+
});
|
|
346
463
|
return {
|
|
347
464
|
query: input.query,
|
|
348
465
|
sources,
|
|
@@ -351,9 +468,35 @@ function createUnifiedSearch(deps = {}) {
|
|
|
351
468
|
warnings
|
|
352
469
|
};
|
|
353
470
|
}
|
|
354
|
-
async function runMemorySource(input, limit, threshold) {
|
|
471
|
+
async function runMemorySource(input, limit, threshold, warnings) {
|
|
355
472
|
if (typeof deps.embedQuery !== "function") {
|
|
356
|
-
|
|
473
|
+
warnings.push({
|
|
474
|
+
source: "memory",
|
|
475
|
+
code: "memory_lexical_search_fallback",
|
|
476
|
+
message: "Semantic search not configured, using keyword search as fallback"
|
|
477
|
+
});
|
|
478
|
+
const { lexicalSearchRawMessages: lexicalSearchRawMessages2 } = await Promise.resolve().then(() => (init_sqlite_raw_message_store(), sqlite_raw_message_store_exports));
|
|
479
|
+
const keywords = deriveLexicalKeywords(input.query);
|
|
480
|
+
let lexical2 = [];
|
|
481
|
+
if (keywords.length > 0) {
|
|
482
|
+
try {
|
|
483
|
+
const filters2 = input.botIds && input.botIds.length > 0 ? input.botIds : [void 0];
|
|
484
|
+
const results = await Promise.all(
|
|
485
|
+
filters2.map(
|
|
486
|
+
(botId) => lexicalSearchRawMessages2({
|
|
487
|
+
userId: input.userId,
|
|
488
|
+
keywords,
|
|
489
|
+
limit: Math.ceil(limit / filters2.length),
|
|
490
|
+
botId
|
|
491
|
+
})
|
|
492
|
+
)
|
|
493
|
+
);
|
|
494
|
+
lexical2 = results.flat().filter(Boolean).map(toMemoryResult);
|
|
495
|
+
} catch (error) {
|
|
496
|
+
logger.warn?.("[memory-store] Default lexical search failed:", error);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
return { semantic: [], lexical: lexical2 };
|
|
357
500
|
}
|
|
358
501
|
const queryEmbedding = await deps.embedQuery({
|
|
359
502
|
userId: input.userId,
|
|
@@ -361,9 +504,10 @@ function createUnifiedSearch(deps = {}) {
|
|
|
361
504
|
authToken: input.authToken
|
|
362
505
|
});
|
|
363
506
|
const filters = input.botIds && input.botIds.length > 0 ? input.botIds.map((botId) => ({ botId })) : [{}];
|
|
507
|
+
let semantic = [];
|
|
364
508
|
if (isRawMessageChromaEnabled()) {
|
|
365
509
|
try {
|
|
366
|
-
|
|
510
|
+
semantic = (await Promise.all(
|
|
367
511
|
filters.map((filter) => {
|
|
368
512
|
const botId = "botId" in filter ? filter.botId : void 0;
|
|
369
513
|
return searchRawMessagesWithChroma({
|
|
@@ -378,18 +522,16 @@ function createUnifiedSearch(deps = {}) {
|
|
|
378
522
|
logger.log?.("[memory-store] Raw message semantic search completed", {
|
|
379
523
|
backend: "chroma",
|
|
380
524
|
dimensions: queryEmbedding.length,
|
|
381
|
-
count:
|
|
525
|
+
count: semantic.length
|
|
382
526
|
});
|
|
383
|
-
return chromaHits;
|
|
384
527
|
} catch (error) {
|
|
385
528
|
logger.warn?.(
|
|
386
529
|
"[memory-store] Chroma raw message search failed; falling back to database search:",
|
|
387
530
|
error
|
|
388
531
|
);
|
|
389
532
|
}
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
const rows = (await Promise.all(
|
|
533
|
+
} else if (typeof deps.searchRawMessagesAnn === "function") {
|
|
534
|
+
semantic = (await Promise.all(
|
|
393
535
|
filters.map(
|
|
394
536
|
(filter) => deps.searchRawMessagesAnn({
|
|
395
537
|
userId: input.userId,
|
|
@@ -400,19 +542,114 @@ function createUnifiedSearch(deps = {}) {
|
|
|
400
542
|
})
|
|
401
543
|
)
|
|
402
544
|
)).flat().filter(isRawMemorySemanticResult).map(toMemoryResult);
|
|
403
|
-
return rows;
|
|
404
545
|
}
|
|
405
|
-
|
|
546
|
+
if (semantic.length === 0) {
|
|
547
|
+
try {
|
|
548
|
+
const { getRawMessageManager: getRawMessageManager2 } = await Promise.resolve().then(() => (init_raw_message_store(), raw_message_store_exports));
|
|
549
|
+
const manager2 = await getRawMessageManager2();
|
|
550
|
+
if (typeof manager2.searchMessagesSemantically === "function") {
|
|
551
|
+
const results = await manager2.searchMessagesSemantically({
|
|
552
|
+
userId: input.userId,
|
|
553
|
+
queryEmbedding,
|
|
554
|
+
limit
|
|
555
|
+
});
|
|
556
|
+
semantic = results.map((r) => ({
|
|
557
|
+
type: "memory",
|
|
558
|
+
id: r.id,
|
|
559
|
+
content: r.content,
|
|
560
|
+
similarity: r.similarity,
|
|
561
|
+
metadata: r.metadata ?? {}
|
|
562
|
+
}));
|
|
563
|
+
}
|
|
564
|
+
} catch (error) {
|
|
565
|
+
logger.warn?.("[memory-store] SQLite semantic search failed:", error);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
let lexical = [];
|
|
569
|
+
if (typeof deps.searchRawMessagesLexical === "function") {
|
|
570
|
+
const keywords = deriveLexicalKeywords(input.query);
|
|
571
|
+
if (keywords.length > 0) {
|
|
572
|
+
try {
|
|
573
|
+
const lexFilters = input.botIds && input.botIds.length > 0 ? input.botIds : [void 0];
|
|
574
|
+
lexical = (await Promise.all(
|
|
575
|
+
lexFilters.map(
|
|
576
|
+
(botId) => deps.searchRawMessagesLexical({
|
|
577
|
+
userId: input.userId,
|
|
578
|
+
keywords,
|
|
579
|
+
limit,
|
|
580
|
+
botId
|
|
581
|
+
})
|
|
582
|
+
)
|
|
583
|
+
)).flat().filter(isRawMemorySemanticResult).map((hit) => ({
|
|
584
|
+
...toMemoryResult(hit),
|
|
585
|
+
metadata: { ...hit.metadata, scoring: "bm25" }
|
|
586
|
+
}));
|
|
587
|
+
} catch (error) {
|
|
588
|
+
logger.warn?.("[memory-store] lexical memory search failed:", error);
|
|
589
|
+
warnings.push({
|
|
590
|
+
source: "memory",
|
|
591
|
+
code: "memory_lexical_search_failed",
|
|
592
|
+
message: error.message ?? "memory_lexical_search_failed"
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
} else if (input.mergeStrategy === "rrf") {
|
|
597
|
+
warnings.push({
|
|
598
|
+
source: "memory",
|
|
599
|
+
code: "memory_lexical_search_not_configured",
|
|
600
|
+
message: "RRF merge requested but lexical search is not configured; falling back to semantic-only RRF."
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
return { semantic, lexical };
|
|
406
604
|
}
|
|
407
605
|
async function searchRawMemorySemantically(input) {
|
|
408
606
|
const limit = clampUnifiedMemorySearchLimit(input.limit);
|
|
409
607
|
const threshold = clampUnifiedMemorySearchThreshold(input.threshold);
|
|
410
|
-
|
|
608
|
+
const sub = await runMemorySource(input, limit, threshold, []);
|
|
609
|
+
return mergeAcrossSources({
|
|
610
|
+
memorySubs: sub,
|
|
611
|
+
insightHits: [],
|
|
612
|
+
knowledgeHits: [],
|
|
613
|
+
limit,
|
|
614
|
+
strategy: normalizeUnifiedMemoryMergeStrategy(input.mergeStrategy)
|
|
615
|
+
});
|
|
411
616
|
}
|
|
412
617
|
return { searchUnifiedMemory, searchRawMemorySemantically };
|
|
413
618
|
}
|
|
619
|
+
function mergeAcrossSources(input) {
|
|
620
|
+
const memorySubs = input.memorySubs ?? { semantic: [], lexical: [] };
|
|
621
|
+
const all = [
|
|
622
|
+
...memorySubs.semantic,
|
|
623
|
+
...memorySubs.lexical,
|
|
624
|
+
...input.insightHits,
|
|
625
|
+
...input.knowledgeHits
|
|
626
|
+
];
|
|
627
|
+
if (input.strategy !== "rrf") {
|
|
628
|
+
return mergeUnifiedMemorySearchResults(all, input.limit);
|
|
629
|
+
}
|
|
630
|
+
const lists = [];
|
|
631
|
+
if (memorySubs.semantic.length > 0) {
|
|
632
|
+
lists.push({ name: "memory-semantic", hits: memorySubs.semantic });
|
|
633
|
+
}
|
|
634
|
+
if (memorySubs.lexical.length > 0) {
|
|
635
|
+
lists.push({ name: "memory-bm25", hits: memorySubs.lexical });
|
|
636
|
+
}
|
|
637
|
+
if (input.insightHits.length > 0) {
|
|
638
|
+
lists.push({ name: "insights", hits: input.insightHits });
|
|
639
|
+
}
|
|
640
|
+
if (input.knowledgeHits.length > 0) {
|
|
641
|
+
lists.push({ name: "knowledge", hits: input.knowledgeHits });
|
|
642
|
+
}
|
|
643
|
+
if (lists.length <= 1) {
|
|
644
|
+
return mergeUnifiedMemorySearchResults(all, input.limit);
|
|
645
|
+
}
|
|
646
|
+
return mergeUnifiedMemorySearchResultsRrf(lists, input.limit);
|
|
647
|
+
}
|
|
414
648
|
|
|
415
649
|
// src/index.ts
|
|
650
|
+
init_raw_message_store();
|
|
651
|
+
init_raw_message_store();
|
|
652
|
+
init_postgres_raw_message_factory();
|
|
416
653
|
async function createMemoryStore(config = {}) {
|
|
417
654
|
const raw = createRawMessageStore({ env: config.env });
|
|
418
655
|
const search = createUnifiedSearch(config.unified);
|
|
@@ -427,5 +664,3 @@ async function createMemoryStore(config = {}) {
|
|
|
427
664
|
}
|
|
428
665
|
|
|
429
666
|
export { clampUnifiedMemorySearchLimit, clampUnifiedMemorySearchThreshold, clearPostgresFactory, closeRawMessageStore, createMemoryStore, createRawMessageStore, createUnifiedSearch, getRawMessageManager, getRawMessageStorageBackend, hasPostgresFactory, isRawMemorySemanticResult, isRawMessageStorageAvailable, mergeUnifiedMemorySearchResults, normalizeUnifiedMemorySearchSources, registerPostgresFactory, resolvePostgresFactory, toKnowledgeResult, toMemoryResult };
|
|
430
|
-
//# sourceMappingURL=index.js.map
|
|
431
|
-
//# sourceMappingURL=index.js.map
|
package/dist/mcp.d.ts
CHANGED