@melandlabs/memory-store 0.2.7 → 0.3.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 CHANGED
@@ -1,8 +1,8 @@
1
1
  import { buildMemoryRecordEmbeddingDocument } from '@melandlabs/ai/memory';
2
2
  import { ChromaVectorStore } from '@melandlabs/rag';
3
3
  import { mkdirSync } from 'fs';
4
- import { homedir } from 'os';
5
- import { dirname, join } from 'path';
4
+ import { dirname } from 'path';
5
+ import { getOpenContextPath } from '@melandlabs/env-config';
6
6
  import { SQLiteRawMessageManager } from '@melandlabs/sqlite';
7
7
  import { serve } from '@hono/node-server';
8
8
  import { Hono } from 'hono';
@@ -186,7 +186,7 @@ __export(sqlite_raw_message_store_exports, {
186
186
  function resolveSQLiteRawMessageDbPath(dbPath) {
187
187
  if (dbPath && dbPath.length > 0) return dbPath;
188
188
  const fromEnv = process.env.MEMORY_STORE_DB_PATH?.trim();
189
- return fromEnv && fromEnv.length > 0 ? fromEnv : DEFAULT_SQLITE_PATH;
189
+ return fromEnv && fromEnv.length > 0 ? fromEnv : getOpenContextPath("memory", "store.db");
190
190
  }
191
191
  function isSQLiteRawMessageStorageAvailable(_env) {
192
192
  return true;
@@ -220,12 +220,11 @@ async function lexicalSearchRawMessages(input) {
220
220
  }
221
221
  return mgr.lexicalSearchMessages(input);
222
222
  }
223
- var manager, DEFAULT_SQLITE_PATH;
223
+ var manager;
224
224
  var init_sqlite_raw_message_store = __esm({
225
225
  "src/storage/sqlite-raw-message-store.ts"() {
226
226
  init_chroma_memory_index();
227
227
  manager = null;
228
- DEFAULT_SQLITE_PATH = join(homedir(), ".opencontext", "memory", "store.db");
229
228
  }
230
229
  });
231
230
 
@@ -239,7 +238,7 @@ __export(raw_message_store_exports, {
239
238
  getRawMessageStorageBackend: () => getRawMessageStorageBackend,
240
239
  isRawMessageStorageAvailable: () => isRawMessageStorageAvailable
241
240
  });
242
- function resolveBackend(env) {
241
+ function resolveBackend(_env) {
243
242
  const explicit = process.env.OPENCONTEXT_MEMORY_STORE_BACKEND?.trim().toLowerCase();
244
243
  if (explicit === "postgres") return "postgres";
245
244
  return "sqlite";
@@ -372,6 +371,12 @@ function mergeUnifiedMemorySearchResults(results, limit, options = {}) {
372
371
  function normalizeUnifiedMemoryMergeStrategy(value) {
373
372
  return value === "rrf" ? "rrf" : "similarity";
374
373
  }
374
+ function normalizeUnifiedMemoryReasoningStrategy(value, defaultStrategy = "none") {
375
+ if (value === "rewrite" || value === "iterative") {
376
+ return value;
377
+ }
378
+ return defaultStrategy;
379
+ }
375
380
  var DEFAULT_RRF_K = 60;
376
381
  function mergeUnifiedMemorySearchResultsRrf(lists, limit, k = DEFAULT_RRF_K) {
377
382
  if (!Array.isArray(lists) || lists.length === 0) {
@@ -394,7 +399,13 @@ function mergeUnifiedMemorySearchResultsRrf(lists, limit, k = DEFAULT_RRF_K) {
394
399
  }
395
400
  }
396
401
  }
397
- const ranked = order.map((key) => scores.get(key)).sort((a, b) => {
402
+ const ranked = order.map((key) => {
403
+ const entry = scores.get(key);
404
+ if (!entry) {
405
+ throw new Error(`Invariant violation: missing RRF score for key "${key}"`);
406
+ }
407
+ return entry;
408
+ }).sort((a, b) => {
398
409
  if (b.rrf !== a.rrf) {
399
410
  return b.rrf - a.rrf;
400
411
  }
@@ -439,14 +450,222 @@ function isRawMemorySemanticResult(result) {
439
450
  function deriveLexicalKeywords(query) {
440
451
  return query.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((token) => token.length >= 2).slice(0, 16);
441
452
  }
453
+ function parseDateBoundary(value, role) {
454
+ const trimmed = value.trim();
455
+ if (!trimmed) {
456
+ return void 0;
457
+ }
458
+ const dateOnlyMatch = trimmed.match(/^(\d{4})-(\d{2})-(\d{2})$/);
459
+ if (dateOnlyMatch) {
460
+ const year = Number.parseInt(dateOnlyMatch[1], 10);
461
+ const month = Number.parseInt(dateOnlyMatch[2], 10) - 1;
462
+ const day = Number.parseInt(dateOnlyMatch[3], 10);
463
+ if (role === "from") {
464
+ return Date.UTC(year, month, day);
465
+ }
466
+ return Date.UTC(year, month, day + 1) - 1;
467
+ }
468
+ const parsed = Date.parse(trimmed);
469
+ if (Number.isNaN(parsed)) {
470
+ return void 0;
471
+ }
472
+ return parsed;
473
+ }
474
+ function getCandidateTimestamp(metadata) {
475
+ for (const key of ["timestamp", "createdAt", "time"]) {
476
+ const value = metadata[key];
477
+ if (typeof value === "number") {
478
+ return value;
479
+ }
480
+ if (typeof value === "string") {
481
+ const parsed = Date.parse(value);
482
+ if (!Number.isNaN(parsed)) {
483
+ return parsed;
484
+ }
485
+ }
486
+ }
487
+ return void 0;
488
+ }
489
+ function filterByDateRange(items, dateFrom, dateTo) {
490
+ if (!dateFrom && !dateTo) {
491
+ return items;
492
+ }
493
+ const fromMs = dateFrom ? parseDateBoundary(dateFrom, "from") : void 0;
494
+ const toMs = dateTo ? parseDateBoundary(dateTo, "to") : void 0;
495
+ if (fromMs === void 0 && toMs === void 0) {
496
+ return items;
497
+ }
498
+ return items.filter((item) => {
499
+ const ts = getCandidateTimestamp(item.metadata);
500
+ if (ts === void 0) {
501
+ return true;
502
+ }
503
+ if (fromMs !== void 0 && ts < fromMs) {
504
+ return false;
505
+ }
506
+ if (toMs !== void 0 && ts > toMs) {
507
+ return false;
508
+ }
509
+ return true;
510
+ });
511
+ }
512
+ async function embedQueryVariant(embedQuery, input, query) {
513
+ return embedQuery({
514
+ userId: input.userId,
515
+ query,
516
+ authToken: input.authToken
517
+ });
518
+ }
519
+ async function runSemanticSearchForEmbedding(deps, input, queryEmbedding, limit, threshold, logger) {
520
+ const filters = input.botIds && input.botIds.length > 0 ? input.botIds.map((botId) => ({ botId })) : [{}];
521
+ let semantic = [];
522
+ if (isRawMessageChromaEnabled()) {
523
+ try {
524
+ semantic = (await Promise.all(
525
+ filters.map((filter) => {
526
+ const botId = "botId" in filter ? filter.botId : void 0;
527
+ return searchRawMessagesWithChroma({
528
+ userId: input.userId,
529
+ queryEmbedding,
530
+ limit,
531
+ threshold,
532
+ botId
533
+ });
534
+ })
535
+ )).flat().map(toMemoryResult);
536
+ logger.log?.("[memory-store] Raw message semantic search completed", {
537
+ backend: "chroma",
538
+ dimensions: queryEmbedding.length,
539
+ count: semantic.length
540
+ });
541
+ } catch (error) {
542
+ logger.warn?.(
543
+ "[memory-store] Chroma raw message search failed; falling back to database search:",
544
+ error
545
+ );
546
+ }
547
+ } else if (typeof deps.searchRawMessagesAnn === "function") {
548
+ const searchRawMessagesAnn = deps.searchRawMessagesAnn;
549
+ semantic = (await Promise.all(
550
+ filters.map(
551
+ (filter) => searchRawMessagesAnn({
552
+ userId: input.userId,
553
+ queryEmbedding,
554
+ limit,
555
+ threshold,
556
+ botId: "botId" in filter ? filter.botId : void 0
557
+ })
558
+ )
559
+ )).flat().filter(isRawMemorySemanticResult).map(toMemoryResult);
560
+ }
561
+ if (semantic.length === 0) {
562
+ try {
563
+ const { getRawMessageManager: getRawMessageManager2 } = await Promise.resolve().then(() => (init_raw_message_store(), raw_message_store_exports));
564
+ const manager2 = await getRawMessageManager2();
565
+ if (typeof manager2.searchMessagesSemantically === "function") {
566
+ const results = await manager2.searchMessagesSemantically({
567
+ userId: input.userId,
568
+ queryEmbedding,
569
+ limit,
570
+ threshold
571
+ });
572
+ semantic = results.map((r) => ({
573
+ type: "memory",
574
+ id: r.id,
575
+ content: r.content,
576
+ similarity: r.similarity,
577
+ metadata: r.metadata ?? {}
578
+ }));
579
+ }
580
+ } catch (error) {
581
+ logger.warn?.("[memory-store] SQLite semantic search failed:", error);
582
+ }
583
+ }
584
+ return semantic;
585
+ }
586
+ function mergeByMaxScore(lists) {
587
+ const best = /* @__PURE__ */ new Map();
588
+ for (const list of lists) {
589
+ for (const hit of list) {
590
+ const existing = best.get(hit.id);
591
+ if (!existing || hit.similarity > existing.similarity) {
592
+ best.set(hit.id, hit);
593
+ }
594
+ }
595
+ }
596
+ return Array.from(best.values()).sort((a, b) => b.similarity - a.similarity);
597
+ }
598
+ function toIterativeRecallCandidate(hit) {
599
+ return {
600
+ id: hit.id,
601
+ content: hit.content,
602
+ similarity: hit.similarity,
603
+ metadata: hit.metadata
604
+ };
605
+ }
606
+ async function runLexicalSearchForKeywords(deps, input, keywords, limit, logger) {
607
+ if (keywords.length === 0) {
608
+ return [];
609
+ }
610
+ if (typeof deps.searchRawMessagesLexical === "function") {
611
+ try {
612
+ const filters = input.botIds && input.botIds.length > 0 ? input.botIds : [void 0];
613
+ const searchRawMessagesLexical = deps.searchRawMessagesLexical;
614
+ return (await Promise.all(
615
+ filters.map(
616
+ (botId) => searchRawMessagesLexical({
617
+ userId: input.userId,
618
+ keywords,
619
+ limit: Math.ceil(limit / filters.length),
620
+ botId
621
+ })
622
+ )
623
+ )).flat().filter(isRawMemorySemanticResult).map((hit) => ({
624
+ ...toMemoryResult(hit),
625
+ metadata: { ...hit.metadata, scoring: "bm25" }
626
+ }));
627
+ } catch (error) {
628
+ logger.warn?.("[memory-store] lexical memory search failed:", error);
629
+ }
630
+ }
631
+ try {
632
+ const { lexicalSearchRawMessages: lexicalSearchRawMessages2 } = await Promise.resolve().then(() => (init_sqlite_raw_message_store(), sqlite_raw_message_store_exports));
633
+ const filters = input.botIds && input.botIds.length > 0 ? input.botIds : [void 0];
634
+ return (await Promise.all(
635
+ filters.map(
636
+ (botId) => lexicalSearchRawMessages2({
637
+ userId: input.userId,
638
+ keywords,
639
+ limit: Math.ceil(limit / filters.length),
640
+ botId
641
+ })
642
+ )
643
+ )).flat().filter(Boolean).map(
644
+ (r) => toMemoryResult(
645
+ r
646
+ )
647
+ );
648
+ } catch (error) {
649
+ logger.warn?.("[memory-store] SQLite lexical search failed:", error);
650
+ }
651
+ return [];
652
+ }
442
653
  function createUnifiedSearch(deps = {}) {
443
654
  const logger = deps.logger ?? console;
655
+ function resolveReasoningStrategy(input) {
656
+ const requested = normalizeUnifiedMemoryReasoningStrategy(input.reasoningStrategy);
657
+ if (requested !== "none") {
658
+ return requested;
659
+ }
660
+ return normalizeUnifiedMemoryReasoningStrategy(deps.reasoning?.defaultStrategy, "none");
661
+ }
444
662
  async function searchUnifiedMemory(input) {
445
663
  const query = input.query.trim();
446
664
  const sources = normalizeUnifiedMemorySearchSources(input.sources);
447
665
  const limit = clampUnifiedMemorySearchLimit(input.limit);
448
666
  const threshold = clampUnifiedMemorySearchThreshold(input.threshold);
449
667
  const mergeStrategy = normalizeUnifiedMemoryMergeStrategy(input.mergeStrategy);
668
+ const reasoningStrategy = resolveReasoningStrategy(input);
450
669
  const warnings = [];
451
670
  if (!query) {
452
671
  return {
@@ -458,10 +677,21 @@ function createUnifiedSearch(deps = {}) {
458
677
  };
459
678
  }
460
679
  let memorySubs;
680
+ const reasoningInfo = { strategy: reasoningStrategy };
681
+ if (input.dateFrom || input.dateTo) {
682
+ reasoningInfo.dateRange = { from: input.dateFrom, to: input.dateTo };
683
+ }
461
684
  if (sources.includes("memory")) {
462
685
  if (isRawMessageStorageAvailable()) {
463
686
  try {
464
- memorySubs = await runMemorySource(input, limit, threshold, warnings);
687
+ memorySubs = await runMemorySource(
688
+ input,
689
+ limit,
690
+ threshold,
691
+ warnings,
692
+ reasoningStrategy,
693
+ reasoningInfo
694
+ );
465
695
  } catch (error) {
466
696
  logger.warn?.("[memory-store] memory source failed:", error);
467
697
  warnings.push({
@@ -540,121 +770,155 @@ function createUnifiedSearch(deps = {}) {
540
770
  limit,
541
771
  strategy: mergeStrategy
542
772
  });
543
- return {
773
+ const output = {
544
774
  query: input.query,
545
775
  sources,
546
776
  results: merged,
547
777
  count: merged.length,
548
778
  warnings
549
779
  };
780
+ if (reasoningInfo && (reasoningInfo.strategy !== "none" || reasoningInfo.dateRange !== void 0)) {
781
+ output.reasoning = reasoningInfo;
782
+ }
783
+ return output;
550
784
  }
551
- async function runMemorySource(input, limit, threshold, warnings) {
785
+ async function runMemorySource(input, limit, threshold, warnings, reasoningStrategy = "none", reasoningInfo) {
786
+ if (reasoningStrategy === "iterative" && !deps.reasoning?.iterativePlanner) {
787
+ warnings.push({
788
+ source: "memory",
789
+ code: "memory_iterative_planner_not_configured",
790
+ message: "Iterative reasoning requested but no iterativePlanner is configured; falling back to default search."
791
+ });
792
+ if (reasoningInfo) reasoningInfo.degraded = true;
793
+ }
794
+ if (reasoningStrategy === "rewrite" && !deps.reasoning?.queryRewriter) {
795
+ warnings.push({
796
+ source: "memory",
797
+ code: "memory_query_rewrite_not_configured",
798
+ message: "Rewrite reasoning requested but no queryRewriter is configured; falling back to default search."
799
+ });
800
+ if (reasoningInfo) reasoningInfo.degraded = true;
801
+ }
802
+ if (reasoningStrategy === "iterative" && deps.reasoning?.iterativePlanner) {
803
+ const planner = deps.reasoning.iterativePlanner;
804
+ const result = await planner.plan({
805
+ query: input.query,
806
+ dateFrom: input.dateFrom,
807
+ dateTo: input.dateTo,
808
+ executor: {
809
+ search: async (request) => {
810
+ const keywords2 = request.keywords.length > 0 ? request.keywords : deriveLexicalKeywords(input.query);
811
+ const lexicalHits = await runLexicalSearchForKeywords(deps, input, keywords2, limit, logger);
812
+ let semanticHits = [];
813
+ if (typeof deps.embedQuery === "function") {
814
+ try {
815
+ const semanticQuery = keywords2.join(" ");
816
+ const queryEmbedding = await embedQueryVariant(deps.embedQuery, input, semanticQuery);
817
+ semanticHits = await runSemanticSearchForEmbedding(
818
+ deps,
819
+ input,
820
+ queryEmbedding,
821
+ limit,
822
+ threshold,
823
+ logger
824
+ );
825
+ } catch (error) {
826
+ logger.warn?.(
827
+ "[memory-store] Iterative semantic search failed; using lexical results only:",
828
+ error
829
+ );
830
+ }
831
+ }
832
+ const candidates = filterByDateRange(
833
+ mergeByMaxScore([
834
+ lexicalHits.map(toIterativeRecallCandidate),
835
+ semanticHits.map(toIterativeRecallCandidate)
836
+ ]),
837
+ request.dateFrom,
838
+ request.dateTo
839
+ );
840
+ return { candidates };
841
+ }
842
+ }
843
+ });
844
+ if (reasoningInfo) {
845
+ reasoningInfo.iterations = result.stats.iterations;
846
+ reasoningInfo.evidenceCount = result.evidence.length;
847
+ if (planner.lastDegraded?.()) {
848
+ reasoningInfo.degraded = true;
849
+ }
850
+ }
851
+ const semantic2 = result.evidence.map((candidate) => ({
852
+ type: "memory",
853
+ id: candidate.id,
854
+ content: candidate.content,
855
+ similarity: candidate.similarity,
856
+ metadata: { ...candidate.metadata, reasoning: "iterative" }
857
+ }));
858
+ return { semantic: semantic2, lexical: [] };
859
+ }
552
860
  if (typeof deps.embedQuery !== "function") {
553
861
  warnings.push({
554
862
  source: "memory",
555
863
  code: "memory_lexical_search_fallback",
556
864
  message: "Semantic search not configured, using keyword search as fallback"
557
865
  });
558
- const { lexicalSearchRawMessages: lexicalSearchRawMessages2 } = await Promise.resolve().then(() => (init_sqlite_raw_message_store(), sqlite_raw_message_store_exports));
559
- const keywords = deriveLexicalKeywords(input.query);
560
- let lexical2 = [];
561
- if (keywords.length > 0) {
562
- try {
563
- const filters2 = input.botIds && input.botIds.length > 0 ? input.botIds : [void 0];
564
- const results = await Promise.all(
565
- filters2.map(
566
- (botId) => lexicalSearchRawMessages2({
567
- userId: input.userId,
568
- keywords,
569
- limit: Math.ceil(limit / filters2.length),
570
- botId
571
- })
572
- )
573
- );
574
- lexical2 = results.flat().filter(Boolean).map(toMemoryResult);
575
- } catch (error) {
576
- logger.warn?.("[memory-store] Default lexical search failed:", error);
577
- }
578
- }
866
+ const keywords2 = deriveLexicalKeywords(input.query);
867
+ const lexical2 = filterByDateRange(
868
+ await runLexicalSearchForKeywords(deps, input, keywords2, limit, logger),
869
+ input.dateFrom,
870
+ input.dateTo
871
+ );
579
872
  return { semantic: [], lexical: lexical2 };
580
873
  }
581
- const queryEmbedding = await deps.embedQuery({
582
- userId: input.userId,
583
- query: input.query,
584
- authToken: input.authToken
585
- });
586
- const filters = input.botIds && input.botIds.length > 0 ? input.botIds.map((botId) => ({ botId })) : [{}];
587
874
  let semantic = [];
588
- if (isRawMessageChromaEnabled()) {
875
+ const embedQuery = deps.embedQuery;
876
+ if (reasoningStrategy === "rewrite" && deps.reasoning?.queryRewriter) {
589
877
  try {
590
- semantic = (await Promise.all(
591
- filters.map((filter) => {
592
- const botId = "botId" in filter ? filter.botId : void 0;
593
- return searchRawMessagesWithChroma({
594
- userId: input.userId,
595
- queryEmbedding,
596
- limit,
597
- threshold,
598
- botId
599
- });
600
- })
601
- )).flat().map(toMemoryResult);
602
- logger.log?.("[memory-store] Raw message semantic search completed", {
603
- backend: "chroma",
604
- dimensions: queryEmbedding.length,
605
- count: semantic.length
878
+ const variants = await deps.reasoning.queryRewriter.rewrite({
879
+ query: input.query,
880
+ userId: input.userId,
881
+ authToken: input.authToken
606
882
  });
607
- } catch (error) {
608
- logger.warn?.(
609
- "[memory-store] Chroma raw message search failed; falling back to database search:",
610
- error
883
+ if (reasoningInfo) {
884
+ reasoningInfo.rewrittenQueries = variants;
885
+ if (deps.reasoning.queryRewriter.lastDegraded?.()) {
886
+ reasoningInfo.degraded = true;
887
+ }
888
+ }
889
+ const embeddings = await Promise.all(
890
+ variants.map((variant) => embedQueryVariant(embedQuery, input, variant))
891
+ );
892
+ const lists = await Promise.all(
893
+ embeddings.map(
894
+ (embedding) => runSemanticSearchForEmbedding(deps, input, embedding, limit, threshold, logger)
895
+ )
611
896
  );
897
+ semantic = mergeByMaxScore(lists);
898
+ } catch (error) {
899
+ logger.warn?.("[memory-store] Query rewriting failed; falling back to original query:", error);
900
+ warnings.push({
901
+ source: "memory",
902
+ code: "memory_query_rewrite_failed",
903
+ message: `Query rewriting failed: ${error.message ?? "Unknown error"}. Using original query.`
904
+ });
905
+ if (reasoningInfo) reasoningInfo.degraded = true;
612
906
  }
613
- } else if (typeof deps.searchRawMessagesAnn === "function") {
614
- semantic = (await Promise.all(
615
- filters.map(
616
- (filter) => deps.searchRawMessagesAnn({
617
- userId: input.userId,
618
- queryEmbedding,
619
- limit,
620
- threshold,
621
- botId: "botId" in filter ? filter.botId : void 0
622
- })
623
- )
624
- )).flat().filter(isRawMemorySemanticResult).map(toMemoryResult);
625
907
  }
626
908
  if (semantic.length === 0) {
627
- try {
628
- const { getRawMessageManager: getRawMessageManager2 } = await Promise.resolve().then(() => (init_raw_message_store(), raw_message_store_exports));
629
- const manager2 = await getRawMessageManager2();
630
- if (typeof manager2.searchMessagesSemantically === "function") {
631
- const results = await manager2.searchMessagesSemantically({
632
- userId: input.userId,
633
- queryEmbedding,
634
- limit,
635
- threshold
636
- });
637
- semantic = results.map((r) => ({
638
- type: "memory",
639
- id: r.id,
640
- content: r.content,
641
- similarity: r.similarity,
642
- metadata: r.metadata ?? {}
643
- }));
644
- }
645
- } catch (error) {
646
- logger.warn?.("[memory-store] SQLite semantic search failed:", error);
647
- }
909
+ const queryEmbedding = await embedQueryVariant(embedQuery, input, input.query);
910
+ semantic = await runSemanticSearchForEmbedding(deps, input, queryEmbedding, limit, threshold, logger);
648
911
  }
649
912
  let lexical = [];
650
- if (typeof deps.searchRawMessagesLexical === "function") {
651
- const keywords = deriveLexicalKeywords(input.query);
652
- if (keywords.length > 0) {
913
+ const keywords = deriveLexicalKeywords(input.query);
914
+ if (keywords.length > 0) {
915
+ if (typeof deps.searchRawMessagesLexical === "function") {
653
916
  try {
654
917
  const lexFilters = input.botIds && input.botIds.length > 0 ? input.botIds : [void 0];
918
+ const searchRawMessagesLexical = deps.searchRawMessagesLexical;
655
919
  lexical = (await Promise.all(
656
920
  lexFilters.map(
657
- (botId) => deps.searchRawMessagesLexical({
921
+ (botId) => searchRawMessagesLexical({
658
922
  userId: input.userId,
659
923
  keywords,
660
924
  limit,
@@ -673,20 +937,24 @@ function createUnifiedSearch(deps = {}) {
673
937
  message: error.message ?? "memory_lexical_search_failed"
674
938
  });
675
939
  }
940
+ } else if (input.mergeStrategy === "rrf") {
941
+ warnings.push({
942
+ source: "memory",
943
+ code: "memory_lexical_search_not_configured",
944
+ message: "RRF merge requested but lexical search is not configured; falling back to semantic-only RRF."
945
+ });
676
946
  }
677
- } else if (input.mergeStrategy === "rrf") {
678
- warnings.push({
679
- source: "memory",
680
- code: "memory_lexical_search_not_configured",
681
- message: "RRF merge requested but lexical search is not configured; falling back to semantic-only RRF."
682
- });
683
947
  }
684
- return { semantic, lexical };
948
+ return {
949
+ semantic: filterByDateRange(semantic, input.dateFrom, input.dateTo),
950
+ lexical: filterByDateRange(lexical, input.dateFrom, input.dateTo)
951
+ };
685
952
  }
686
953
  async function searchRawMemorySemantically(input) {
687
954
  const limit = clampUnifiedMemorySearchLimit(input.limit);
688
955
  const threshold = clampUnifiedMemorySearchThreshold(input.threshold);
689
- const sub = await runMemorySource(input, limit, threshold, []);
956
+ const reasoningStrategy = resolveReasoningStrategy(input);
957
+ const sub = await runMemorySource(input, limit, threshold, [], reasoningStrategy);
690
958
  return mergeAcrossSources({
691
959
  memorySubs: sub,
692
960
  insightHits: [],
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { M as MemoryStoreConfig } from './config-Ll6ktm4D.js';
2
- export { E as EmbedQueryFn, a as MemoryStoreDb, b as MemoryStoreEnv, U as UnifiedSearchInsightsResult, c as UnifiedSearchKnowledgeResult, V as VectorBackend } from './config-Ll6ktm4D.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';