@melandlabs/memory-store 0.2.0 → 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/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 +216 -43
- package/dist/server/cli-mcp.js +174 -36
- package/dist/server/cli-shared.js +0 -0
- package/package.json +81 -93
package/dist/http.js
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
|
-
import { serve } from '@hono/node-server';
|
|
2
|
-
import { Hono } from 'hono';
|
|
3
1
|
import { buildMemoryRecordEmbeddingDocument } from '@melandlabs/ai/memory';
|
|
4
2
|
import { ChromaVectorStore } from '@melandlabs/rag';
|
|
5
3
|
import { mkdirSync } from 'fs';
|
|
6
4
|
import { homedir } from 'os';
|
|
7
|
-
import {
|
|
5
|
+
import { dirname, join } from 'path';
|
|
8
6
|
import { SQLiteRawMessageManager } from '@melandlabs/sqlite';
|
|
7
|
+
import { serve } from '@hono/node-server';
|
|
8
|
+
import { Hono } from 'hono';
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
var __defProp = Object.defineProperty;
|
|
11
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
12
|
+
var __esm = (fn, res) => function __init() {
|
|
13
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
14
|
+
};
|
|
15
|
+
var __export = (target, all) => {
|
|
16
|
+
for (var name in all)
|
|
17
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
18
|
+
};
|
|
11
19
|
|
|
12
20
|
// src/contracts.ts
|
|
13
21
|
function normalizeTimestampToMs(value) {
|
|
@@ -31,14 +39,10 @@ function rawMessageToMemoryRecord(message) {
|
|
|
31
39
|
embeddingContentHash: message.embeddingContentHash
|
|
32
40
|
};
|
|
33
41
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
"RAW_MESSAGE_VECTOR_STORE_BACKEND",
|
|
39
|
-
"MEMORY_VECTOR_STORE_BACKEND",
|
|
40
|
-
"VECTOR_STORE_BACKEND"
|
|
41
|
-
];
|
|
42
|
+
var init_contracts = __esm({
|
|
43
|
+
"src/contracts.ts"() {
|
|
44
|
+
}
|
|
45
|
+
});
|
|
42
46
|
function getBackend(keys) {
|
|
43
47
|
for (const key of keys) {
|
|
44
48
|
const value = process.env[key]?.trim().toLowerCase();
|
|
@@ -141,21 +145,51 @@ async function searchRawMessagesWithChroma(input) {
|
|
|
141
145
|
metadata: result.metadata ?? {}
|
|
142
146
|
})).slice(0, input.limit);
|
|
143
147
|
}
|
|
148
|
+
var DEFAULT_RAW_MESSAGES_COLLECTION, RAW_VECTOR_BACKEND_ENV_KEYS;
|
|
149
|
+
var init_chroma_memory_index = __esm({
|
|
150
|
+
"src/storage/chroma-memory-index.ts"() {
|
|
151
|
+
init_contracts();
|
|
152
|
+
DEFAULT_RAW_MESSAGES_COLLECTION = "opencontext_raw_messages";
|
|
153
|
+
RAW_VECTOR_BACKEND_ENV_KEYS = [
|
|
154
|
+
"RAW_MESSAGE_VECTOR_STORE_BACKEND",
|
|
155
|
+
"MEMORY_VECTOR_STORE_BACKEND",
|
|
156
|
+
"VECTOR_STORE_BACKEND"
|
|
157
|
+
];
|
|
158
|
+
}
|
|
159
|
+
});
|
|
144
160
|
|
|
145
161
|
// src/storage/postgres-raw-message-factory.ts
|
|
146
|
-
var factory = null;
|
|
147
162
|
async function resolvePostgresFactory(env) {
|
|
148
|
-
return null;
|
|
163
|
+
if (!factory) return null;
|
|
164
|
+
return await factory(env);
|
|
149
165
|
}
|
|
150
166
|
function hasPostgresFactory() {
|
|
151
167
|
return factory !== null;
|
|
152
168
|
}
|
|
153
|
-
var
|
|
154
|
-
var
|
|
169
|
+
var factory;
|
|
170
|
+
var init_postgres_raw_message_factory = __esm({
|
|
171
|
+
"src/storage/postgres-raw-message-factory.ts"() {
|
|
172
|
+
factory = null;
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// src/storage/sqlite-raw-message-store.ts
|
|
177
|
+
var sqlite_raw_message_store_exports = {};
|
|
178
|
+
__export(sqlite_raw_message_store_exports, {
|
|
179
|
+
__resetSQLiteRawMessageManagerForTests: () => __resetSQLiteRawMessageManagerForTests,
|
|
180
|
+
closeSQLiteRawMessageManager: () => closeSQLiteRawMessageManager,
|
|
181
|
+
getSQLiteRawMessageManager: () => getSQLiteRawMessageManager,
|
|
182
|
+
isSQLiteRawMessageStorageAvailable: () => isSQLiteRawMessageStorageAvailable,
|
|
183
|
+
lexicalSearchRawMessages: () => lexicalSearchRawMessages,
|
|
184
|
+
resolveSQLiteRawMessageDbPath: () => resolveSQLiteRawMessageDbPath
|
|
185
|
+
});
|
|
155
186
|
function resolveSQLiteRawMessageDbPath() {
|
|
156
187
|
const fromEnv = process.env.MEMORY_STORE_DB_PATH?.trim();
|
|
157
188
|
return fromEnv && fromEnv.length > 0 ? fromEnv : DEFAULT_SQLITE_PATH;
|
|
158
189
|
}
|
|
190
|
+
function isSQLiteRawMessageStorageAvailable(_env) {
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
159
193
|
async function getSQLiteRawMessageManager(_env) {
|
|
160
194
|
if (!manager) {
|
|
161
195
|
const dbPath = resolveSQLiteRawMessageDbPath();
|
|
@@ -175,8 +209,35 @@ async function closeSQLiteRawMessageManager() {
|
|
|
175
209
|
await manager.close();
|
|
176
210
|
manager = null;
|
|
177
211
|
}
|
|
212
|
+
function __resetSQLiteRawMessageManagerForTests() {
|
|
213
|
+
manager = null;
|
|
214
|
+
}
|
|
215
|
+
async function lexicalSearchRawMessages(input) {
|
|
216
|
+
const mgr = await getSQLiteRawMessageManager();
|
|
217
|
+
if (typeof mgr.lexicalSearchMessages !== "function") {
|
|
218
|
+
return [];
|
|
219
|
+
}
|
|
220
|
+
return mgr.lexicalSearchMessages(input);
|
|
221
|
+
}
|
|
222
|
+
var manager, DEFAULT_SQLITE_PATH;
|
|
223
|
+
var init_sqlite_raw_message_store = __esm({
|
|
224
|
+
"src/storage/sqlite-raw-message-store.ts"() {
|
|
225
|
+
init_chroma_memory_index();
|
|
226
|
+
manager = null;
|
|
227
|
+
DEFAULT_SQLITE_PATH = join(homedir(), ".opencontext", "memory", "store.db");
|
|
228
|
+
}
|
|
229
|
+
});
|
|
178
230
|
|
|
179
231
|
// src/storage/raw-message-store.ts
|
|
232
|
+
var raw_message_store_exports = {};
|
|
233
|
+
__export(raw_message_store_exports, {
|
|
234
|
+
closeRawMessageStore: () => closeRawMessageStore,
|
|
235
|
+
configureRawMessageStore: () => configureRawMessageStore,
|
|
236
|
+
createRawMessageStore: () => createRawMessageStore,
|
|
237
|
+
getRawMessageManager: () => getRawMessageManager,
|
|
238
|
+
getRawMessageStorageBackend: () => getRawMessageStorageBackend,
|
|
239
|
+
isRawMessageStorageAvailable: () => isRawMessageStorageAvailable
|
|
240
|
+
});
|
|
180
241
|
function resolveBackend(env) {
|
|
181
242
|
const explicit = process.env.OPENCONTEXT_MEMORY_STORE_BACKEND?.trim().toLowerCase();
|
|
182
243
|
if (explicit === "postgres") return "postgres";
|
|
@@ -186,7 +247,7 @@ function resolveEnv(_env) {
|
|
|
186
247
|
return {};
|
|
187
248
|
}
|
|
188
249
|
function createRawMessageStore(options = {}) {
|
|
189
|
-
resolveEnv(options.env);
|
|
250
|
+
const env = resolveEnv(options.env);
|
|
190
251
|
return {
|
|
191
252
|
getBackend() {
|
|
192
253
|
return resolveBackend();
|
|
@@ -196,7 +257,7 @@ function createRawMessageStore(options = {}) {
|
|
|
196
257
|
},
|
|
197
258
|
async getManager() {
|
|
198
259
|
if (resolveBackend() === "postgres") {
|
|
199
|
-
const pg = await resolvePostgresFactory();
|
|
260
|
+
const pg = await resolvePostgresFactory(env);
|
|
200
261
|
if (!pg) {
|
|
201
262
|
throw new Error(
|
|
202
263
|
"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."
|
|
@@ -211,14 +272,47 @@ function createRawMessageStore(options = {}) {
|
|
|
211
272
|
}
|
|
212
273
|
};
|
|
213
274
|
}
|
|
214
|
-
|
|
215
|
-
|
|
275
|
+
function configureRawMessageStore(config) {
|
|
276
|
+
moduleConfig = config;
|
|
277
|
+
moduleStore = createRawMessageStore({ env: config.env });
|
|
278
|
+
return moduleStore;
|
|
279
|
+
}
|
|
280
|
+
function getRawMessageStorageBackend() {
|
|
281
|
+
if (!moduleStore) {
|
|
282
|
+
moduleStore = createRawMessageStore({ env: moduleConfig?.env });
|
|
283
|
+
}
|
|
284
|
+
return moduleStore.getBackend();
|
|
285
|
+
}
|
|
216
286
|
function isRawMessageStorageAvailable() {
|
|
217
287
|
if (!moduleStore) {
|
|
218
288
|
moduleStore = createRawMessageStore({ env: moduleConfig?.env });
|
|
219
289
|
}
|
|
220
290
|
return moduleStore.isAvailable();
|
|
221
291
|
}
|
|
292
|
+
async function getRawMessageManager() {
|
|
293
|
+
if (!moduleStore) {
|
|
294
|
+
moduleStore = createRawMessageStore({ env: moduleConfig?.env });
|
|
295
|
+
}
|
|
296
|
+
return moduleStore.getManager();
|
|
297
|
+
}
|
|
298
|
+
async function closeRawMessageStore() {
|
|
299
|
+
if (!moduleStore) return;
|
|
300
|
+
await moduleStore.close();
|
|
301
|
+
moduleStore = null;
|
|
302
|
+
}
|
|
303
|
+
var moduleStore, moduleConfig;
|
|
304
|
+
var init_raw_message_store = __esm({
|
|
305
|
+
"src/storage/raw-message-store.ts"() {
|
|
306
|
+
init_postgres_raw_message_factory();
|
|
307
|
+
init_sqlite_raw_message_store();
|
|
308
|
+
moduleStore = null;
|
|
309
|
+
moduleConfig = null;
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
// src/search/unified-search.ts
|
|
314
|
+
init_chroma_memory_index();
|
|
315
|
+
init_raw_message_store();
|
|
222
316
|
|
|
223
317
|
// src/search/utilities.ts
|
|
224
318
|
var DEFAULT_LIMIT = 10;
|
|
@@ -362,7 +456,7 @@ function createUnifiedSearch(deps = {}) {
|
|
|
362
456
|
warnings.push({
|
|
363
457
|
source: "memory",
|
|
364
458
|
code: "memory_search_failed",
|
|
365
|
-
message: error.message ?? "
|
|
459
|
+
message: `Memory search failed: ${error.message ?? "Unknown error"}. Using keyword search fallback.`
|
|
366
460
|
});
|
|
367
461
|
}
|
|
368
462
|
} else {
|
|
@@ -402,13 +496,7 @@ function createUnifiedSearch(deps = {}) {
|
|
|
402
496
|
message: error.message ?? "insights_search_failed"
|
|
403
497
|
});
|
|
404
498
|
}
|
|
405
|
-
} else if (sources.includes("insights"))
|
|
406
|
-
warnings.push({
|
|
407
|
-
source: "insights",
|
|
408
|
-
code: "insights_search_not_configured",
|
|
409
|
-
message: "Insights search is not configured for this host."
|
|
410
|
-
});
|
|
411
|
-
}
|
|
499
|
+
} else if (sources.includes("insights")) ;
|
|
412
500
|
const knowledgeHits = [];
|
|
413
501
|
if (sources.includes("knowledge") && typeof deps.searchKnowledge === "function") {
|
|
414
502
|
try {
|
|
@@ -433,13 +521,7 @@ function createUnifiedSearch(deps = {}) {
|
|
|
433
521
|
message: error.message ?? "knowledge_search_failed"
|
|
434
522
|
});
|
|
435
523
|
}
|
|
436
|
-
} else if (sources.includes("knowledge"))
|
|
437
|
-
warnings.push({
|
|
438
|
-
source: "knowledge",
|
|
439
|
-
code: "knowledge_search_not_configured",
|
|
440
|
-
message: "Knowledge search is not configured for this host."
|
|
441
|
-
});
|
|
442
|
-
}
|
|
524
|
+
} else if (sources.includes("knowledge")) ;
|
|
443
525
|
const merged = mergeAcrossSources({
|
|
444
526
|
memorySubs,
|
|
445
527
|
insightHits,
|
|
@@ -457,7 +539,33 @@ function createUnifiedSearch(deps = {}) {
|
|
|
457
539
|
}
|
|
458
540
|
async function runMemorySource(input, limit, threshold, warnings) {
|
|
459
541
|
if (typeof deps.embedQuery !== "function") {
|
|
460
|
-
|
|
542
|
+
warnings.push({
|
|
543
|
+
source: "memory",
|
|
544
|
+
code: "memory_lexical_search_fallback",
|
|
545
|
+
message: "Semantic search not configured, using keyword search as fallback"
|
|
546
|
+
});
|
|
547
|
+
const { lexicalSearchRawMessages: lexicalSearchRawMessages2 } = await Promise.resolve().then(() => (init_sqlite_raw_message_store(), sqlite_raw_message_store_exports));
|
|
548
|
+
const keywords = deriveLexicalKeywords(input.query);
|
|
549
|
+
let lexical2 = [];
|
|
550
|
+
if (keywords.length > 0) {
|
|
551
|
+
try {
|
|
552
|
+
const filters2 = input.botIds && input.botIds.length > 0 ? input.botIds : [void 0];
|
|
553
|
+
const results = await Promise.all(
|
|
554
|
+
filters2.map(
|
|
555
|
+
(botId) => lexicalSearchRawMessages2({
|
|
556
|
+
userId: input.userId,
|
|
557
|
+
keywords,
|
|
558
|
+
limit: Math.ceil(limit / filters2.length),
|
|
559
|
+
botId
|
|
560
|
+
})
|
|
561
|
+
)
|
|
562
|
+
);
|
|
563
|
+
lexical2 = results.flat().filter(Boolean).map(toMemoryResult);
|
|
564
|
+
} catch (error) {
|
|
565
|
+
logger.warn?.("[memory-store] Default lexical search failed:", error);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
return { semantic: [], lexical: lexical2 };
|
|
461
569
|
}
|
|
462
570
|
const queryEmbedding = await deps.embedQuery({
|
|
463
571
|
userId: input.userId,
|
|
@@ -504,6 +612,28 @@ function createUnifiedSearch(deps = {}) {
|
|
|
504
612
|
)
|
|
505
613
|
)).flat().filter(isRawMemorySemanticResult).map(toMemoryResult);
|
|
506
614
|
}
|
|
615
|
+
if (semantic.length === 0) {
|
|
616
|
+
try {
|
|
617
|
+
const { getRawMessageManager: getRawMessageManager2 } = await Promise.resolve().then(() => (init_raw_message_store(), raw_message_store_exports));
|
|
618
|
+
const manager2 = await getRawMessageManager2();
|
|
619
|
+
if (typeof manager2.searchMessagesSemantically === "function") {
|
|
620
|
+
const results = await manager2.searchMessagesSemantically({
|
|
621
|
+
userId: input.userId,
|
|
622
|
+
queryEmbedding,
|
|
623
|
+
limit
|
|
624
|
+
});
|
|
625
|
+
semantic = results.map((r) => ({
|
|
626
|
+
type: "memory",
|
|
627
|
+
id: r.id,
|
|
628
|
+
content: r.content,
|
|
629
|
+
similarity: r.similarity,
|
|
630
|
+
metadata: r.metadata ?? {}
|
|
631
|
+
}));
|
|
632
|
+
}
|
|
633
|
+
} catch (error) {
|
|
634
|
+
logger.warn?.("[memory-store] SQLite semantic search failed:", error);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
507
637
|
let lexical = [];
|
|
508
638
|
if (typeof deps.searchRawMessagesLexical === "function") {
|
|
509
639
|
const keywords = deriveLexicalKeywords(input.query);
|
|
@@ -586,6 +716,8 @@ function mergeAcrossSources(input) {
|
|
|
586
716
|
}
|
|
587
717
|
|
|
588
718
|
// src/http.ts
|
|
719
|
+
init_chroma_memory_index();
|
|
720
|
+
init_raw_message_store();
|
|
589
721
|
async function embedMissingMessages(messages, deps) {
|
|
590
722
|
if (typeof deps.embedQuery !== "function") {
|
|
591
723
|
return messages;
|
|
@@ -620,7 +752,23 @@ async function startHttpServer(options = {}) {
|
|
|
620
752
|
const rawStore = createRawMessageStore({
|
|
621
753
|
env: options.env
|
|
622
754
|
});
|
|
623
|
-
const
|
|
755
|
+
const manager2 = await rawStore.getManager();
|
|
756
|
+
const search = createUnifiedSearch({
|
|
757
|
+
...options.unified,
|
|
758
|
+
searchRawMessagesLexical: async (input) => {
|
|
759
|
+
if (typeof manager2.lexicalSearchMessages === "function") {
|
|
760
|
+
const results = await manager2.lexicalSearchMessages(input);
|
|
761
|
+
return results.filter(Boolean).map((r) => ({
|
|
762
|
+
type: "memory",
|
|
763
|
+
id: r.id,
|
|
764
|
+
content: r.content,
|
|
765
|
+
similarity: r.similarity,
|
|
766
|
+
metadata: r.metadata ?? {}
|
|
767
|
+
}));
|
|
768
|
+
}
|
|
769
|
+
return [];
|
|
770
|
+
}
|
|
771
|
+
});
|
|
624
772
|
const app = new Hono();
|
|
625
773
|
app.get("/health", (c) => c.json({ ok: true, store: "memory", ts: Date.now() }));
|
|
626
774
|
app.post("/v1/search", async (c) => {
|
|
@@ -648,20 +796,20 @@ async function startHttpServer(options = {}) {
|
|
|
648
796
|
if (!Array.isArray(body.messages) || !body.userId) {
|
|
649
797
|
return c.json({ error: "userId and messages[] required" }, 400);
|
|
650
798
|
}
|
|
651
|
-
const
|
|
799
|
+
const manager3 = await rawStore.getManager();
|
|
652
800
|
const incoming = body.messages;
|
|
653
801
|
const messages = body.embedOnInsert === true ? await embedMissingMessages(
|
|
654
802
|
incoming.map((m) => ({ ...m, userId: m.userId ?? body.userId })),
|
|
655
803
|
options.unified ?? {}
|
|
656
804
|
) : incoming.map((m) => ({ ...m, userId: m.userId ?? body.userId }));
|
|
657
805
|
let result;
|
|
658
|
-
if (typeof
|
|
659
|
-
result = await
|
|
806
|
+
if (typeof manager3.upsertRawMessages === "function") {
|
|
807
|
+
result = await manager3.upsertRawMessages({
|
|
660
808
|
userId: body.userId,
|
|
661
809
|
messages
|
|
662
810
|
});
|
|
663
|
-
} else if (typeof
|
|
664
|
-
const ids = await
|
|
811
|
+
} else if (typeof manager3.storeMessages === "function") {
|
|
812
|
+
const ids = await manager3.storeMessages(messages);
|
|
665
813
|
result = { inserted: ids.length, ids };
|
|
666
814
|
} else {
|
|
667
815
|
return c.json(
|
|
@@ -676,14 +824,33 @@ async function startHttpServer(options = {}) {
|
|
|
676
824
|
} catch (error) {
|
|
677
825
|
console.warn("[memory-store/http] chroma upsert failed:", error);
|
|
678
826
|
}
|
|
827
|
+
try {
|
|
828
|
+
const messagesWithEmbeddings = messages.filter(
|
|
829
|
+
(m) => Array.isArray(m.embedding) && m.embedding.length > 0
|
|
830
|
+
);
|
|
831
|
+
if (messagesWithEmbeddings.length > 0) {
|
|
832
|
+
for (const message of messagesWithEmbeddings) {
|
|
833
|
+
if (typeof manager3.upsertVectorForMessage === "function") {
|
|
834
|
+
manager3.upsertVectorForMessage(message.messageId, message.embedding);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
console.log(
|
|
838
|
+
"[memory-store/http] Updated sqlite-vec vector table for",
|
|
839
|
+
messagesWithEmbeddings.length,
|
|
840
|
+
"message(s)"
|
|
841
|
+
);
|
|
842
|
+
}
|
|
843
|
+
} catch (error) {
|
|
844
|
+
console.warn("[memory-store/http] sqlite-vec vector update failed:", error);
|
|
845
|
+
}
|
|
679
846
|
return c.json({ ok: true, count: messages.length, result });
|
|
680
847
|
});
|
|
681
848
|
app.get("/v1/raw-messages/:id", async (c) => {
|
|
682
849
|
const id = c.req.param("id");
|
|
683
850
|
const userId = c.req.query("userId");
|
|
684
851
|
if (!userId) return c.json({ error: "userId query param required" }, 400);
|
|
685
|
-
const
|
|
686
|
-
const row = await
|
|
852
|
+
const manager3 = await rawStore.getManager();
|
|
853
|
+
const row = await manager3.getMessageById?.(id);
|
|
687
854
|
if (!row) return c.json({ error: "not found" }, 404);
|
|
688
855
|
return c.json({ message: row });
|
|
689
856
|
});
|
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;
|
|
@@ -312,7 +387,7 @@ function createUnifiedSearch(deps = {}) {
|
|
|
312
387
|
warnings.push({
|
|
313
388
|
source: "memory",
|
|
314
389
|
code: "memory_search_failed",
|
|
315
|
-
message: error.message ?? "
|
|
390
|
+
message: `Memory search failed: ${error.message ?? "Unknown error"}. Using keyword search fallback.`
|
|
316
391
|
});
|
|
317
392
|
}
|
|
318
393
|
} else {
|
|
@@ -352,13 +427,7 @@ function createUnifiedSearch(deps = {}) {
|
|
|
352
427
|
message: error.message ?? "insights_search_failed"
|
|
353
428
|
});
|
|
354
429
|
}
|
|
355
|
-
} else if (sources.includes("insights"))
|
|
356
|
-
warnings.push({
|
|
357
|
-
source: "insights",
|
|
358
|
-
code: "insights_search_not_configured",
|
|
359
|
-
message: "Insights search is not configured for this host."
|
|
360
|
-
});
|
|
361
|
-
}
|
|
430
|
+
} else if (sources.includes("insights")) ;
|
|
362
431
|
const knowledgeHits = [];
|
|
363
432
|
if (sources.includes("knowledge") && typeof deps.searchKnowledge === "function") {
|
|
364
433
|
try {
|
|
@@ -383,13 +452,7 @@ function createUnifiedSearch(deps = {}) {
|
|
|
383
452
|
message: error.message ?? "knowledge_search_failed"
|
|
384
453
|
});
|
|
385
454
|
}
|
|
386
|
-
} else if (sources.includes("knowledge"))
|
|
387
|
-
warnings.push({
|
|
388
|
-
source: "knowledge",
|
|
389
|
-
code: "knowledge_search_not_configured",
|
|
390
|
-
message: "Knowledge search is not configured for this host."
|
|
391
|
-
});
|
|
392
|
-
}
|
|
455
|
+
} else if (sources.includes("knowledge")) ;
|
|
393
456
|
const merged = mergeAcrossSources({
|
|
394
457
|
memorySubs,
|
|
395
458
|
insightHits,
|
|
@@ -407,7 +470,33 @@ function createUnifiedSearch(deps = {}) {
|
|
|
407
470
|
}
|
|
408
471
|
async function runMemorySource(input, limit, threshold, warnings) {
|
|
409
472
|
if (typeof deps.embedQuery !== "function") {
|
|
410
|
-
|
|
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 };
|
|
411
500
|
}
|
|
412
501
|
const queryEmbedding = await deps.embedQuery({
|
|
413
502
|
userId: input.userId,
|
|
@@ -454,6 +543,28 @@ function createUnifiedSearch(deps = {}) {
|
|
|
454
543
|
)
|
|
455
544
|
)).flat().filter(isRawMemorySemanticResult).map(toMemoryResult);
|
|
456
545
|
}
|
|
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
|
+
}
|
|
457
568
|
let lexical = [];
|
|
458
569
|
if (typeof deps.searchRawMessagesLexical === "function") {
|
|
459
570
|
const keywords = deriveLexicalKeywords(input.query);
|
|
@@ -536,6 +647,9 @@ function mergeAcrossSources(input) {
|
|
|
536
647
|
}
|
|
537
648
|
|
|
538
649
|
// src/index.ts
|
|
650
|
+
init_raw_message_store();
|
|
651
|
+
init_raw_message_store();
|
|
652
|
+
init_postgres_raw_message_factory();
|
|
539
653
|
async function createMemoryStore(config = {}) {
|
|
540
654
|
const raw = createRawMessageStore({ env: config.env });
|
|
541
655
|
const search = createUnifiedSearch(config.unified);
|