@melandlabs/memory-store 0.2.6 → 0.3.0

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 CHANGED
@@ -183,16 +183,17 @@ __export(sqlite_raw_message_store_exports, {
183
183
  lexicalSearchRawMessages: () => lexicalSearchRawMessages,
184
184
  resolveSQLiteRawMessageDbPath: () => resolveSQLiteRawMessageDbPath
185
185
  });
186
- function resolveSQLiteRawMessageDbPath() {
186
+ function resolveSQLiteRawMessageDbPath(dbPath) {
187
+ if (dbPath && dbPath.length > 0) return dbPath;
187
188
  const fromEnv = process.env.MEMORY_STORE_DB_PATH?.trim();
188
189
  return fromEnv && fromEnv.length > 0 ? fromEnv : DEFAULT_SQLITE_PATH;
189
190
  }
190
191
  function isSQLiteRawMessageStorageAvailable(_env) {
191
192
  return true;
192
193
  }
193
- async function getSQLiteRawMessageManager(_env) {
194
+ async function getSQLiteRawMessageManager(options = {}) {
194
195
  if (!manager) {
195
- const dbPath = resolveSQLiteRawMessageDbPath();
196
+ const dbPath = resolveSQLiteRawMessageDbPath(options.dbPath);
196
197
  mkdirSync(dirname(dbPath), { recursive: true });
197
198
  manager = new SQLiteRawMessageManager({
198
199
  dbPath,
@@ -238,7 +239,7 @@ __export(raw_message_store_exports, {
238
239
  getRawMessageStorageBackend: () => getRawMessageStorageBackend,
239
240
  isRawMessageStorageAvailable: () => isRawMessageStorageAvailable
240
241
  });
241
- function resolveBackend(env) {
242
+ function resolveBackend(_env) {
242
243
  const explicit = process.env.OPENCONTEXT_MEMORY_STORE_BACKEND?.trim().toLowerCase();
243
244
  if (explicit === "postgres") return "postgres";
244
245
  return "sqlite";
@@ -265,33 +266,43 @@ function createRawMessageStore(options = {}) {
265
266
  }
266
267
  return pg;
267
268
  }
268
- return await getSQLiteRawMessageManager();
269
+ return await getSQLiteRawMessageManager({
270
+ dbPath: options.dbPath
271
+ });
269
272
  },
270
273
  async close() {
271
274
  await closeSQLiteRawMessageManager();
272
275
  }
273
276
  };
274
277
  }
278
+ function resolveDbPath(config) {
279
+ if (!config) return void 0;
280
+ if (config.dbPath) return config.dbPath;
281
+ if (config.db && typeof config.db === "object" && "path" in config.db) {
282
+ return config.db.path;
283
+ }
284
+ return void 0;
285
+ }
275
286
  function configureRawMessageStore(config) {
276
287
  moduleConfig = config;
277
- moduleStore = createRawMessageStore({ env: config.env });
288
+ moduleStore = createRawMessageStore({ env: config.env, dbPath: resolveDbPath(config) });
278
289
  return moduleStore;
279
290
  }
280
291
  function getRawMessageStorageBackend() {
281
292
  if (!moduleStore) {
282
- moduleStore = createRawMessageStore({ env: moduleConfig?.env });
293
+ moduleStore = createRawMessageStore({ env: moduleConfig?.env, dbPath: resolveDbPath(moduleConfig) });
283
294
  }
284
295
  return moduleStore.getBackend();
285
296
  }
286
297
  function isRawMessageStorageAvailable() {
287
298
  if (!moduleStore) {
288
- moduleStore = createRawMessageStore({ env: moduleConfig?.env });
299
+ moduleStore = createRawMessageStore({ env: moduleConfig?.env, dbPath: resolveDbPath(moduleConfig) });
289
300
  }
290
301
  return moduleStore.isAvailable();
291
302
  }
292
303
  async function getRawMessageManager() {
293
304
  if (!moduleStore) {
294
- moduleStore = createRawMessageStore({ env: moduleConfig?.env });
305
+ moduleStore = createRawMessageStore({ env: moduleConfig?.env, dbPath: resolveDbPath(moduleConfig) });
295
306
  }
296
307
  return moduleStore.getManager();
297
308
  }
@@ -361,6 +372,12 @@ function mergeUnifiedMemorySearchResults(results, limit, options = {}) {
361
372
  function normalizeUnifiedMemoryMergeStrategy(value) {
362
373
  return value === "rrf" ? "rrf" : "similarity";
363
374
  }
375
+ function normalizeUnifiedMemoryReasoningStrategy(value, defaultStrategy = "none") {
376
+ if (value === "rewrite" || value === "iterative") {
377
+ return value;
378
+ }
379
+ return defaultStrategy;
380
+ }
364
381
  var DEFAULT_RRF_K = 60;
365
382
  function mergeUnifiedMemorySearchResultsRrf(lists, limit, k = DEFAULT_RRF_K) {
366
383
  if (!Array.isArray(lists) || lists.length === 0) {
@@ -383,7 +400,13 @@ function mergeUnifiedMemorySearchResultsRrf(lists, limit, k = DEFAULT_RRF_K) {
383
400
  }
384
401
  }
385
402
  }
386
- const ranked = order.map((key) => scores.get(key)).sort((a, b) => {
403
+ const ranked = order.map((key) => {
404
+ const entry = scores.get(key);
405
+ if (!entry) {
406
+ throw new Error(`Invariant violation: missing RRF score for key "${key}"`);
407
+ }
408
+ return entry;
409
+ }).sort((a, b) => {
387
410
  if (b.rrf !== a.rrf) {
388
411
  return b.rrf - a.rrf;
389
412
  }
@@ -428,14 +451,222 @@ function isRawMemorySemanticResult(result) {
428
451
  function deriveLexicalKeywords(query) {
429
452
  return query.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((token) => token.length >= 2).slice(0, 16);
430
453
  }
454
+ function parseDateBoundary(value, role) {
455
+ const trimmed = value.trim();
456
+ if (!trimmed) {
457
+ return void 0;
458
+ }
459
+ const dateOnlyMatch = trimmed.match(/^(\d{4})-(\d{2})-(\d{2})$/);
460
+ if (dateOnlyMatch) {
461
+ const year = Number.parseInt(dateOnlyMatch[1], 10);
462
+ const month = Number.parseInt(dateOnlyMatch[2], 10) - 1;
463
+ const day = Number.parseInt(dateOnlyMatch[3], 10);
464
+ if (role === "from") {
465
+ return Date.UTC(year, month, day);
466
+ }
467
+ return Date.UTC(year, month, day + 1) - 1;
468
+ }
469
+ const parsed = Date.parse(trimmed);
470
+ if (Number.isNaN(parsed)) {
471
+ return void 0;
472
+ }
473
+ return parsed;
474
+ }
475
+ function getCandidateTimestamp(metadata) {
476
+ for (const key of ["timestamp", "createdAt", "time"]) {
477
+ const value = metadata[key];
478
+ if (typeof value === "number") {
479
+ return value;
480
+ }
481
+ if (typeof value === "string") {
482
+ const parsed = Date.parse(value);
483
+ if (!Number.isNaN(parsed)) {
484
+ return parsed;
485
+ }
486
+ }
487
+ }
488
+ return void 0;
489
+ }
490
+ function filterByDateRange(items, dateFrom, dateTo) {
491
+ if (!dateFrom && !dateTo) {
492
+ return items;
493
+ }
494
+ const fromMs = dateFrom ? parseDateBoundary(dateFrom, "from") : void 0;
495
+ const toMs = dateTo ? parseDateBoundary(dateTo, "to") : void 0;
496
+ if (fromMs === void 0 && toMs === void 0) {
497
+ return items;
498
+ }
499
+ return items.filter((item) => {
500
+ const ts = getCandidateTimestamp(item.metadata);
501
+ if (ts === void 0) {
502
+ return true;
503
+ }
504
+ if (fromMs !== void 0 && ts < fromMs) {
505
+ return false;
506
+ }
507
+ if (toMs !== void 0 && ts > toMs) {
508
+ return false;
509
+ }
510
+ return true;
511
+ });
512
+ }
513
+ async function embedQueryVariant(embedQuery, input, query) {
514
+ return embedQuery({
515
+ userId: input.userId,
516
+ query,
517
+ authToken: input.authToken
518
+ });
519
+ }
520
+ async function runSemanticSearchForEmbedding(deps, input, queryEmbedding, limit, threshold, logger) {
521
+ const filters = input.botIds && input.botIds.length > 0 ? input.botIds.map((botId) => ({ botId })) : [{}];
522
+ let semantic = [];
523
+ if (isRawMessageChromaEnabled()) {
524
+ try {
525
+ semantic = (await Promise.all(
526
+ filters.map((filter) => {
527
+ const botId = "botId" in filter ? filter.botId : void 0;
528
+ return searchRawMessagesWithChroma({
529
+ userId: input.userId,
530
+ queryEmbedding,
531
+ limit,
532
+ threshold,
533
+ botId
534
+ });
535
+ })
536
+ )).flat().map(toMemoryResult);
537
+ logger.log?.("[memory-store] Raw message semantic search completed", {
538
+ backend: "chroma",
539
+ dimensions: queryEmbedding.length,
540
+ count: semantic.length
541
+ });
542
+ } catch (error) {
543
+ logger.warn?.(
544
+ "[memory-store] Chroma raw message search failed; falling back to database search:",
545
+ error
546
+ );
547
+ }
548
+ } else if (typeof deps.searchRawMessagesAnn === "function") {
549
+ const searchRawMessagesAnn = deps.searchRawMessagesAnn;
550
+ semantic = (await Promise.all(
551
+ filters.map(
552
+ (filter) => searchRawMessagesAnn({
553
+ userId: input.userId,
554
+ queryEmbedding,
555
+ limit,
556
+ threshold,
557
+ botId: "botId" in filter ? filter.botId : void 0
558
+ })
559
+ )
560
+ )).flat().filter(isRawMemorySemanticResult).map(toMemoryResult);
561
+ }
562
+ if (semantic.length === 0) {
563
+ try {
564
+ const { getRawMessageManager: getRawMessageManager2 } = await Promise.resolve().then(() => (init_raw_message_store(), raw_message_store_exports));
565
+ const manager2 = await getRawMessageManager2();
566
+ if (typeof manager2.searchMessagesSemantically === "function") {
567
+ const results = await manager2.searchMessagesSemantically({
568
+ userId: input.userId,
569
+ queryEmbedding,
570
+ limit,
571
+ threshold
572
+ });
573
+ semantic = results.map((r) => ({
574
+ type: "memory",
575
+ id: r.id,
576
+ content: r.content,
577
+ similarity: r.similarity,
578
+ metadata: r.metadata ?? {}
579
+ }));
580
+ }
581
+ } catch (error) {
582
+ logger.warn?.("[memory-store] SQLite semantic search failed:", error);
583
+ }
584
+ }
585
+ return semantic;
586
+ }
587
+ function mergeByMaxScore(lists) {
588
+ const best = /* @__PURE__ */ new Map();
589
+ for (const list of lists) {
590
+ for (const hit of list) {
591
+ const existing = best.get(hit.id);
592
+ if (!existing || hit.similarity > existing.similarity) {
593
+ best.set(hit.id, hit);
594
+ }
595
+ }
596
+ }
597
+ return Array.from(best.values()).sort((a, b) => b.similarity - a.similarity);
598
+ }
599
+ function toIterativeRecallCandidate(hit) {
600
+ return {
601
+ id: hit.id,
602
+ content: hit.content,
603
+ similarity: hit.similarity,
604
+ metadata: hit.metadata
605
+ };
606
+ }
607
+ async function runLexicalSearchForKeywords(deps, input, keywords, limit, logger) {
608
+ if (keywords.length === 0) {
609
+ return [];
610
+ }
611
+ if (typeof deps.searchRawMessagesLexical === "function") {
612
+ try {
613
+ const filters = input.botIds && input.botIds.length > 0 ? input.botIds : [void 0];
614
+ const searchRawMessagesLexical = deps.searchRawMessagesLexical;
615
+ return (await Promise.all(
616
+ filters.map(
617
+ (botId) => searchRawMessagesLexical({
618
+ userId: input.userId,
619
+ keywords,
620
+ limit: Math.ceil(limit / filters.length),
621
+ botId
622
+ })
623
+ )
624
+ )).flat().filter(isRawMemorySemanticResult).map((hit) => ({
625
+ ...toMemoryResult(hit),
626
+ metadata: { ...hit.metadata, scoring: "bm25" }
627
+ }));
628
+ } catch (error) {
629
+ logger.warn?.("[memory-store] lexical memory search failed:", error);
630
+ }
631
+ }
632
+ try {
633
+ const { lexicalSearchRawMessages: lexicalSearchRawMessages2 } = await Promise.resolve().then(() => (init_sqlite_raw_message_store(), sqlite_raw_message_store_exports));
634
+ const filters = input.botIds && input.botIds.length > 0 ? input.botIds : [void 0];
635
+ return (await Promise.all(
636
+ filters.map(
637
+ (botId) => lexicalSearchRawMessages2({
638
+ userId: input.userId,
639
+ keywords,
640
+ limit: Math.ceil(limit / filters.length),
641
+ botId
642
+ })
643
+ )
644
+ )).flat().filter(Boolean).map(
645
+ (r) => toMemoryResult(
646
+ r
647
+ )
648
+ );
649
+ } catch (error) {
650
+ logger.warn?.("[memory-store] SQLite lexical search failed:", error);
651
+ }
652
+ return [];
653
+ }
431
654
  function createUnifiedSearch(deps = {}) {
432
655
  const logger = deps.logger ?? console;
656
+ function resolveReasoningStrategy(input) {
657
+ const requested = normalizeUnifiedMemoryReasoningStrategy(input.reasoningStrategy);
658
+ if (requested !== "none") {
659
+ return requested;
660
+ }
661
+ return normalizeUnifiedMemoryReasoningStrategy(deps.reasoning?.defaultStrategy, "none");
662
+ }
433
663
  async function searchUnifiedMemory(input) {
434
664
  const query = input.query.trim();
435
665
  const sources = normalizeUnifiedMemorySearchSources(input.sources);
436
666
  const limit = clampUnifiedMemorySearchLimit(input.limit);
437
667
  const threshold = clampUnifiedMemorySearchThreshold(input.threshold);
438
668
  const mergeStrategy = normalizeUnifiedMemoryMergeStrategy(input.mergeStrategy);
669
+ const reasoningStrategy = resolveReasoningStrategy(input);
439
670
  const warnings = [];
440
671
  if (!query) {
441
672
  return {
@@ -447,10 +678,21 @@ function createUnifiedSearch(deps = {}) {
447
678
  };
448
679
  }
449
680
  let memorySubs;
681
+ const reasoningInfo = { strategy: reasoningStrategy };
682
+ if (input.dateFrom || input.dateTo) {
683
+ reasoningInfo.dateRange = { from: input.dateFrom, to: input.dateTo };
684
+ }
450
685
  if (sources.includes("memory")) {
451
686
  if (isRawMessageStorageAvailable()) {
452
687
  try {
453
- memorySubs = await runMemorySource(input, limit, threshold, warnings);
688
+ memorySubs = await runMemorySource(
689
+ input,
690
+ limit,
691
+ threshold,
692
+ warnings,
693
+ reasoningStrategy,
694
+ reasoningInfo
695
+ );
454
696
  } catch (error) {
455
697
  logger.warn?.("[memory-store] memory source failed:", error);
456
698
  warnings.push({
@@ -529,120 +771,155 @@ function createUnifiedSearch(deps = {}) {
529
771
  limit,
530
772
  strategy: mergeStrategy
531
773
  });
532
- return {
774
+ const output = {
533
775
  query: input.query,
534
776
  sources,
535
777
  results: merged,
536
778
  count: merged.length,
537
779
  warnings
538
780
  };
781
+ if (reasoningInfo && (reasoningInfo.strategy !== "none" || reasoningInfo.dateRange !== void 0)) {
782
+ output.reasoning = reasoningInfo;
783
+ }
784
+ return output;
539
785
  }
540
- async function runMemorySource(input, limit, threshold, warnings) {
786
+ async function runMemorySource(input, limit, threshold, warnings, reasoningStrategy = "none", reasoningInfo) {
787
+ if (reasoningStrategy === "iterative" && !deps.reasoning?.iterativePlanner) {
788
+ warnings.push({
789
+ source: "memory",
790
+ code: "memory_iterative_planner_not_configured",
791
+ message: "Iterative reasoning requested but no iterativePlanner is configured; falling back to default search."
792
+ });
793
+ if (reasoningInfo) reasoningInfo.degraded = true;
794
+ }
795
+ if (reasoningStrategy === "rewrite" && !deps.reasoning?.queryRewriter) {
796
+ warnings.push({
797
+ source: "memory",
798
+ code: "memory_query_rewrite_not_configured",
799
+ message: "Rewrite reasoning requested but no queryRewriter is configured; falling back to default search."
800
+ });
801
+ if (reasoningInfo) reasoningInfo.degraded = true;
802
+ }
803
+ if (reasoningStrategy === "iterative" && deps.reasoning?.iterativePlanner) {
804
+ const planner = deps.reasoning.iterativePlanner;
805
+ const result = await planner.plan({
806
+ query: input.query,
807
+ dateFrom: input.dateFrom,
808
+ dateTo: input.dateTo,
809
+ executor: {
810
+ search: async (request) => {
811
+ const keywords2 = request.keywords.length > 0 ? request.keywords : deriveLexicalKeywords(input.query);
812
+ const lexicalHits = await runLexicalSearchForKeywords(deps, input, keywords2, limit, logger);
813
+ let semanticHits = [];
814
+ if (typeof deps.embedQuery === "function") {
815
+ try {
816
+ const semanticQuery = keywords2.join(" ");
817
+ const queryEmbedding = await embedQueryVariant(deps.embedQuery, input, semanticQuery);
818
+ semanticHits = await runSemanticSearchForEmbedding(
819
+ deps,
820
+ input,
821
+ queryEmbedding,
822
+ limit,
823
+ threshold,
824
+ logger
825
+ );
826
+ } catch (error) {
827
+ logger.warn?.(
828
+ "[memory-store] Iterative semantic search failed; using lexical results only:",
829
+ error
830
+ );
831
+ }
832
+ }
833
+ const candidates = filterByDateRange(
834
+ mergeByMaxScore([
835
+ lexicalHits.map(toIterativeRecallCandidate),
836
+ semanticHits.map(toIterativeRecallCandidate)
837
+ ]),
838
+ request.dateFrom,
839
+ request.dateTo
840
+ );
841
+ return { candidates };
842
+ }
843
+ }
844
+ });
845
+ if (reasoningInfo) {
846
+ reasoningInfo.iterations = result.stats.iterations;
847
+ reasoningInfo.evidenceCount = result.evidence.length;
848
+ if (planner.lastDegraded?.()) {
849
+ reasoningInfo.degraded = true;
850
+ }
851
+ }
852
+ const semantic2 = result.evidence.map((candidate) => ({
853
+ type: "memory",
854
+ id: candidate.id,
855
+ content: candidate.content,
856
+ similarity: candidate.similarity,
857
+ metadata: { ...candidate.metadata, reasoning: "iterative" }
858
+ }));
859
+ return { semantic: semantic2, lexical: [] };
860
+ }
541
861
  if (typeof deps.embedQuery !== "function") {
542
862
  warnings.push({
543
863
  source: "memory",
544
864
  code: "memory_lexical_search_fallback",
545
865
  message: "Semantic search not configured, using keyword search as fallback"
546
866
  });
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
- }
867
+ const keywords2 = deriveLexicalKeywords(input.query);
868
+ const lexical2 = filterByDateRange(
869
+ await runLexicalSearchForKeywords(deps, input, keywords2, limit, logger),
870
+ input.dateFrom,
871
+ input.dateTo
872
+ );
568
873
  return { semantic: [], lexical: lexical2 };
569
874
  }
570
- const queryEmbedding = await deps.embedQuery({
571
- userId: input.userId,
572
- query: input.query,
573
- authToken: input.authToken
574
- });
575
- const filters = input.botIds && input.botIds.length > 0 ? input.botIds.map((botId) => ({ botId })) : [{}];
576
875
  let semantic = [];
577
- if (isRawMessageChromaEnabled()) {
876
+ const embedQuery = deps.embedQuery;
877
+ if (reasoningStrategy === "rewrite" && deps.reasoning?.queryRewriter) {
578
878
  try {
579
- semantic = (await Promise.all(
580
- filters.map((filter) => {
581
- const botId = "botId" in filter ? filter.botId : void 0;
582
- return searchRawMessagesWithChroma({
583
- userId: input.userId,
584
- queryEmbedding,
585
- limit,
586
- threshold,
587
- botId
588
- });
589
- })
590
- )).flat().map(toMemoryResult);
591
- logger.log?.("[memory-store] Raw message semantic search completed", {
592
- backend: "chroma",
593
- dimensions: queryEmbedding.length,
594
- count: semantic.length
879
+ const variants = await deps.reasoning.queryRewriter.rewrite({
880
+ query: input.query,
881
+ userId: input.userId,
882
+ authToken: input.authToken
595
883
  });
596
- } catch (error) {
597
- logger.warn?.(
598
- "[memory-store] Chroma raw message search failed; falling back to database search:",
599
- error
884
+ if (reasoningInfo) {
885
+ reasoningInfo.rewrittenQueries = variants;
886
+ if (deps.reasoning.queryRewriter.lastDegraded?.()) {
887
+ reasoningInfo.degraded = true;
888
+ }
889
+ }
890
+ const embeddings = await Promise.all(
891
+ variants.map((variant) => embedQueryVariant(embedQuery, input, variant))
600
892
  );
893
+ const lists = await Promise.all(
894
+ embeddings.map(
895
+ (embedding) => runSemanticSearchForEmbedding(deps, input, embedding, limit, threshold, logger)
896
+ )
897
+ );
898
+ semantic = mergeByMaxScore(lists);
899
+ } catch (error) {
900
+ logger.warn?.("[memory-store] Query rewriting failed; falling back to original query:", error);
901
+ warnings.push({
902
+ source: "memory",
903
+ code: "memory_query_rewrite_failed",
904
+ message: `Query rewriting failed: ${error.message ?? "Unknown error"}. Using original query.`
905
+ });
906
+ if (reasoningInfo) reasoningInfo.degraded = true;
601
907
  }
602
- } else if (typeof deps.searchRawMessagesAnn === "function") {
603
- semantic = (await Promise.all(
604
- filters.map(
605
- (filter) => deps.searchRawMessagesAnn({
606
- userId: input.userId,
607
- queryEmbedding,
608
- limit,
609
- threshold,
610
- botId: "botId" in filter ? filter.botId : void 0
611
- })
612
- )
613
- )).flat().filter(isRawMemorySemanticResult).map(toMemoryResult);
614
908
  }
615
909
  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
- }
910
+ const queryEmbedding = await embedQueryVariant(embedQuery, input, input.query);
911
+ semantic = await runSemanticSearchForEmbedding(deps, input, queryEmbedding, limit, threshold, logger);
636
912
  }
637
913
  let lexical = [];
638
- if (typeof deps.searchRawMessagesLexical === "function") {
639
- const keywords = deriveLexicalKeywords(input.query);
640
- if (keywords.length > 0) {
914
+ const keywords = deriveLexicalKeywords(input.query);
915
+ if (keywords.length > 0) {
916
+ if (typeof deps.searchRawMessagesLexical === "function") {
641
917
  try {
642
918
  const lexFilters = input.botIds && input.botIds.length > 0 ? input.botIds : [void 0];
919
+ const searchRawMessagesLexical = deps.searchRawMessagesLexical;
643
920
  lexical = (await Promise.all(
644
921
  lexFilters.map(
645
- (botId) => deps.searchRawMessagesLexical({
922
+ (botId) => searchRawMessagesLexical({
646
923
  userId: input.userId,
647
924
  keywords,
648
925
  limit,
@@ -661,20 +938,24 @@ function createUnifiedSearch(deps = {}) {
661
938
  message: error.message ?? "memory_lexical_search_failed"
662
939
  });
663
940
  }
941
+ } else if (input.mergeStrategy === "rrf") {
942
+ warnings.push({
943
+ source: "memory",
944
+ code: "memory_lexical_search_not_configured",
945
+ message: "RRF merge requested but lexical search is not configured; falling back to semantic-only RRF."
946
+ });
664
947
  }
665
- } else if (input.mergeStrategy === "rrf") {
666
- warnings.push({
667
- source: "memory",
668
- code: "memory_lexical_search_not_configured",
669
- message: "RRF merge requested but lexical search is not configured; falling back to semantic-only RRF."
670
- });
671
948
  }
672
- return { semantic, lexical };
949
+ return {
950
+ semantic: filterByDateRange(semantic, input.dateFrom, input.dateTo),
951
+ lexical: filterByDateRange(lexical, input.dateFrom, input.dateTo)
952
+ };
673
953
  }
674
954
  async function searchRawMemorySemantically(input) {
675
955
  const limit = clampUnifiedMemorySearchLimit(input.limit);
676
956
  const threshold = clampUnifiedMemorySearchThreshold(input.threshold);
677
- const sub = await runMemorySource(input, limit, threshold, []);
957
+ const reasoningStrategy = resolveReasoningStrategy(input);
958
+ const sub = await runMemorySource(input, limit, threshold, [], reasoningStrategy);
678
959
  return mergeAcrossSources({
679
960
  memorySubs: sub,
680
961
  insightHits: [],
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { M as MemoryStoreConfig } from './config-BYfTzG3h.js';
2
- export { E as EmbedQueryFn, a as MemoryStoreDb, b as MemoryStoreEnv, U as UnifiedSearchInsightsResult, c as UnifiedSearchKnowledgeResult, V as VectorBackend } from './config-BYfTzG3h.js';
1
+ import { M as MemoryStoreConfig } from './config-2Q092MUz.js';
2
+ export { E as EmbedQueryFn, I as IterativeRecallCandidate, a as IterativeRecallExecutor, b as IterativeRecallPlanner, c as IterativeRecallPlannerOptions, d as IterativeRecallResult, e as IterativeRecallSearchRequest, f as IterativeRecallSearchResult, g as IterativeRecallStats, h as MemoryStoreDb, i as MemoryStoreEnv, Q as QueryRewriter, j as QueryRewriterInput, k as QueryRewriterOptions, U as UnifiedMemoryReasoningInfo, l as UnifiedMemoryReasoningStrategy, m as UnifiedMemorySearchInput, n as UnifiedMemorySearchOutput, o as UnifiedMemorySearchResult, p as UnifiedMemorySearchSource, q as UnifiedMemorySearchWarning, r as UnifiedSearchInsightsResult, s as UnifiedSearchKnowledgeResult, t as UnifiedSearchReasoningDeps, V as VectorBackend, u as clampUnifiedMemorySearchLimit, v as clampUnifiedMemorySearchThreshold, w as createIdentityIterativePlanner, x as createIdentityRewriter, y as createIterativeRecallPlanner, z as createUserVoiceRewriter, A as isRawMemorySemanticResult, B as mergeUnifiedMemorySearchResults, C as normalizeUnifiedMemoryReasoningStrategy, D as normalizeUnifiedMemorySearchSources, F as toKnowledgeResult, G as toMemoryResult } from './config-2Q092MUz.js';
3
3
  import { UnifiedSearch } from './search/unified-search.js';
4
- export { UnifiedMemorySearchInput, UnifiedMemorySearchOutput, UnifiedMemorySearchResult, UnifiedMemorySearchSource, UnifiedMemorySearchWarning, clampUnifiedMemorySearchLimit, clampUnifiedMemorySearchThreshold, createUnifiedSearch, isRawMemorySemanticResult, mergeUnifiedMemorySearchResults, normalizeUnifiedMemorySearchSources, toKnowledgeResult, toMemoryResult } from './search/unified-search.js';
4
+ export { createUnifiedSearch } from './search/unified-search.js';
5
5
  import { RawMessageStore, getRawMessageManager } from './storage/raw-message-store.js';
6
6
  export { RawMessageStorageBackend, RawMessageStorageManagerWithSearch, closeRawMessageStore, createRawMessageStore, getRawMessageStorageBackend, isRawMessageStorageAvailable } from './storage/raw-message-store.js';
7
7
  export { PostgresFactoryFn, PostgresRawMessageManagerLike, clearPostgresFactory, hasPostgresFactory, registerPostgresFactory, resolvePostgresFactory } from './storage/postgres-raw-message-factory.js';