@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/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 { join, dirname } from 'path';
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
- // src/mcp.ts
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
- // src/storage/chroma-memory-index.ts
37
- var DEFAULT_RAW_MESSAGES_COLLECTION = "opencontext_raw_messages";
38
- var RAW_VECTOR_BACKEND_ENV_KEYS = [
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 manager = null;
155
- var DEFAULT_SQLITE_PATH = join(homedir(), ".opencontext", "memory", "store.db");
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
- var moduleStore = null;
216
- var moduleConfig = null;
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 ?? "memory_search_failed"
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
- throw new Error("embedQuery is not configured");
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 { join, dirname } from 'path';
5
+ import { dirname, join } from 'path';
6
6
  import { SQLiteRawMessageManager } from '@melandlabs/sqlite';
7
7
 
8
- // src/storage/chroma-memory-index.ts
9
- var DEFAULT_RAW_MESSAGES_COLLECTION = "opencontext_raw_messages";
10
- var RAW_VECTOR_BACKEND_ENV_KEYS = [
11
- "RAW_MESSAGE_VECTOR_STORE_BACKEND",
12
- "MEMORY_VECTOR_STORE_BACKEND",
13
- "VECTOR_STORE_BACKEND"
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 manager = null;
75
- var DEFAULT_SQLITE_PATH = join(homedir(), ".opencontext", "memory", "store.db");
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
- var moduleStore = null;
136
- var moduleConfig = null;
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 ?? "memory_search_failed"
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
- throw new Error("embedQuery is not configured");
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);