@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.
@@ -1,8 +1,8 @@
1
1
  import '@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
 
8
8
  var __defProp = Object.defineProperty;
@@ -111,7 +111,7 @@ __export(sqlite_raw_message_store_exports, {
111
111
  function resolveSQLiteRawMessageDbPath(dbPath) {
112
112
  if (dbPath && dbPath.length > 0) return dbPath;
113
113
  const fromEnv = process.env.MEMORY_STORE_DB_PATH?.trim();
114
- return fromEnv && fromEnv.length > 0 ? fromEnv : DEFAULT_SQLITE_PATH;
114
+ return fromEnv && fromEnv.length > 0 ? fromEnv : getOpenContextPath("memory", "store.db");
115
115
  }
116
116
  function isSQLiteRawMessageStorageAvailable(_env) {
117
117
  return true;
@@ -145,12 +145,11 @@ async function lexicalSearchRawMessages(input) {
145
145
  }
146
146
  return mgr.lexicalSearchMessages(input);
147
147
  }
148
- var manager, DEFAULT_SQLITE_PATH;
148
+ var manager;
149
149
  var init_sqlite_raw_message_store = __esm({
150
150
  "src/storage/sqlite-raw-message-store.ts"() {
151
151
  init_chroma_memory_index();
152
152
  manager = null;
153
- DEFAULT_SQLITE_PATH = join(homedir(), ".opencontext", "memory", "store.db");
154
153
  }
155
154
  });
156
155
 
@@ -164,7 +163,7 @@ __export(raw_message_store_exports, {
164
163
  getRawMessageStorageBackend: () => getRawMessageStorageBackend,
165
164
  isRawMessageStorageAvailable: () => isRawMessageStorageAvailable
166
165
  });
167
- function resolveBackend(env) {
166
+ function resolveBackend(_env) {
168
167
  const explicit = process.env.OPENCONTEXT_MEMORY_STORE_BACKEND?.trim().toLowerCase();
169
168
  if (explicit === "postgres") return "postgres";
170
169
  return "sqlite";
@@ -297,6 +296,12 @@ function mergeUnifiedMemorySearchResults(results, limit, options = {}) {
297
296
  function normalizeUnifiedMemoryMergeStrategy(value) {
298
297
  return value === "rrf" ? "rrf" : "similarity";
299
298
  }
299
+ function normalizeUnifiedMemoryReasoningStrategy(value, defaultStrategy = "none") {
300
+ if (value === "rewrite" || value === "iterative") {
301
+ return value;
302
+ }
303
+ return defaultStrategy;
304
+ }
300
305
  var DEFAULT_RRF_K = 60;
301
306
  function mergeUnifiedMemorySearchResultsRrf(lists, limit, k = DEFAULT_RRF_K) {
302
307
  if (!Array.isArray(lists) || lists.length === 0) {
@@ -319,7 +324,13 @@ function mergeUnifiedMemorySearchResultsRrf(lists, limit, k = DEFAULT_RRF_K) {
319
324
  }
320
325
  }
321
326
  }
322
- const ranked = order.map((key) => scores.get(key)).sort((a, b) => {
327
+ const ranked = order.map((key) => {
328
+ const entry = scores.get(key);
329
+ if (!entry) {
330
+ throw new Error(`Invariant violation: missing RRF score for key "${key}"`);
331
+ }
332
+ return entry;
333
+ }).sort((a, b) => {
323
334
  if (b.rrf !== a.rrf) {
324
335
  return b.rrf - a.rrf;
325
336
  }
@@ -364,14 +375,222 @@ function isRawMemorySemanticResult(result) {
364
375
  function deriveLexicalKeywords(query) {
365
376
  return query.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((token) => token.length >= 2).slice(0, 16);
366
377
  }
378
+ function parseDateBoundary(value, role) {
379
+ const trimmed = value.trim();
380
+ if (!trimmed) {
381
+ return void 0;
382
+ }
383
+ const dateOnlyMatch = trimmed.match(/^(\d{4})-(\d{2})-(\d{2})$/);
384
+ if (dateOnlyMatch) {
385
+ const year = Number.parseInt(dateOnlyMatch[1], 10);
386
+ const month = Number.parseInt(dateOnlyMatch[2], 10) - 1;
387
+ const day = Number.parseInt(dateOnlyMatch[3], 10);
388
+ if (role === "from") {
389
+ return Date.UTC(year, month, day);
390
+ }
391
+ return Date.UTC(year, month, day + 1) - 1;
392
+ }
393
+ const parsed = Date.parse(trimmed);
394
+ if (Number.isNaN(parsed)) {
395
+ return void 0;
396
+ }
397
+ return parsed;
398
+ }
399
+ function getCandidateTimestamp(metadata) {
400
+ for (const key of ["timestamp", "createdAt", "time"]) {
401
+ const value = metadata[key];
402
+ if (typeof value === "number") {
403
+ return value;
404
+ }
405
+ if (typeof value === "string") {
406
+ const parsed = Date.parse(value);
407
+ if (!Number.isNaN(parsed)) {
408
+ return parsed;
409
+ }
410
+ }
411
+ }
412
+ return void 0;
413
+ }
414
+ function filterByDateRange(items, dateFrom, dateTo) {
415
+ if (!dateFrom && !dateTo) {
416
+ return items;
417
+ }
418
+ const fromMs = dateFrom ? parseDateBoundary(dateFrom, "from") : void 0;
419
+ const toMs = dateTo ? parseDateBoundary(dateTo, "to") : void 0;
420
+ if (fromMs === void 0 && toMs === void 0) {
421
+ return items;
422
+ }
423
+ return items.filter((item) => {
424
+ const ts = getCandidateTimestamp(item.metadata);
425
+ if (ts === void 0) {
426
+ return true;
427
+ }
428
+ if (fromMs !== void 0 && ts < fromMs) {
429
+ return false;
430
+ }
431
+ if (toMs !== void 0 && ts > toMs) {
432
+ return false;
433
+ }
434
+ return true;
435
+ });
436
+ }
437
+ async function embedQueryVariant(embedQuery, input, query) {
438
+ return embedQuery({
439
+ userId: input.userId,
440
+ query,
441
+ authToken: input.authToken
442
+ });
443
+ }
444
+ async function runSemanticSearchForEmbedding(deps, input, queryEmbedding, limit, threshold, logger) {
445
+ const filters = input.botIds && input.botIds.length > 0 ? input.botIds.map((botId) => ({ botId })) : [{}];
446
+ let semantic = [];
447
+ if (isRawMessageChromaEnabled()) {
448
+ try {
449
+ semantic = (await Promise.all(
450
+ filters.map((filter) => {
451
+ const botId = "botId" in filter ? filter.botId : void 0;
452
+ return searchRawMessagesWithChroma({
453
+ userId: input.userId,
454
+ queryEmbedding,
455
+ limit,
456
+ threshold,
457
+ botId
458
+ });
459
+ })
460
+ )).flat().map(toMemoryResult);
461
+ logger.log?.("[memory-store] Raw message semantic search completed", {
462
+ backend: "chroma",
463
+ dimensions: queryEmbedding.length,
464
+ count: semantic.length
465
+ });
466
+ } catch (error) {
467
+ logger.warn?.(
468
+ "[memory-store] Chroma raw message search failed; falling back to database search:",
469
+ error
470
+ );
471
+ }
472
+ } else if (typeof deps.searchRawMessagesAnn === "function") {
473
+ const searchRawMessagesAnn = deps.searchRawMessagesAnn;
474
+ semantic = (await Promise.all(
475
+ filters.map(
476
+ (filter) => searchRawMessagesAnn({
477
+ userId: input.userId,
478
+ queryEmbedding,
479
+ limit,
480
+ threshold,
481
+ botId: "botId" in filter ? filter.botId : void 0
482
+ })
483
+ )
484
+ )).flat().filter(isRawMemorySemanticResult).map(toMemoryResult);
485
+ }
486
+ if (semantic.length === 0) {
487
+ try {
488
+ const { getRawMessageManager: getRawMessageManager2 } = await Promise.resolve().then(() => (init_raw_message_store(), raw_message_store_exports));
489
+ const manager2 = await getRawMessageManager2();
490
+ if (typeof manager2.searchMessagesSemantically === "function") {
491
+ const results = await manager2.searchMessagesSemantically({
492
+ userId: input.userId,
493
+ queryEmbedding,
494
+ limit,
495
+ threshold
496
+ });
497
+ semantic = results.map((r) => ({
498
+ type: "memory",
499
+ id: r.id,
500
+ content: r.content,
501
+ similarity: r.similarity,
502
+ metadata: r.metadata ?? {}
503
+ }));
504
+ }
505
+ } catch (error) {
506
+ logger.warn?.("[memory-store] SQLite semantic search failed:", error);
507
+ }
508
+ }
509
+ return semantic;
510
+ }
511
+ function mergeByMaxScore(lists) {
512
+ const best = /* @__PURE__ */ new Map();
513
+ for (const list of lists) {
514
+ for (const hit of list) {
515
+ const existing = best.get(hit.id);
516
+ if (!existing || hit.similarity > existing.similarity) {
517
+ best.set(hit.id, hit);
518
+ }
519
+ }
520
+ }
521
+ return Array.from(best.values()).sort((a, b) => b.similarity - a.similarity);
522
+ }
523
+ function toIterativeRecallCandidate(hit) {
524
+ return {
525
+ id: hit.id,
526
+ content: hit.content,
527
+ similarity: hit.similarity,
528
+ metadata: hit.metadata
529
+ };
530
+ }
531
+ async function runLexicalSearchForKeywords(deps, input, keywords, limit, logger) {
532
+ if (keywords.length === 0) {
533
+ return [];
534
+ }
535
+ if (typeof deps.searchRawMessagesLexical === "function") {
536
+ try {
537
+ const filters = input.botIds && input.botIds.length > 0 ? input.botIds : [void 0];
538
+ const searchRawMessagesLexical = deps.searchRawMessagesLexical;
539
+ return (await Promise.all(
540
+ filters.map(
541
+ (botId) => searchRawMessagesLexical({
542
+ userId: input.userId,
543
+ keywords,
544
+ limit: Math.ceil(limit / filters.length),
545
+ botId
546
+ })
547
+ )
548
+ )).flat().filter(isRawMemorySemanticResult).map((hit) => ({
549
+ ...toMemoryResult(hit),
550
+ metadata: { ...hit.metadata, scoring: "bm25" }
551
+ }));
552
+ } catch (error) {
553
+ logger.warn?.("[memory-store] lexical memory search failed:", error);
554
+ }
555
+ }
556
+ try {
557
+ const { lexicalSearchRawMessages: lexicalSearchRawMessages2 } = await Promise.resolve().then(() => (init_sqlite_raw_message_store(), sqlite_raw_message_store_exports));
558
+ const filters = input.botIds && input.botIds.length > 0 ? input.botIds : [void 0];
559
+ return (await Promise.all(
560
+ filters.map(
561
+ (botId) => lexicalSearchRawMessages2({
562
+ userId: input.userId,
563
+ keywords,
564
+ limit: Math.ceil(limit / filters.length),
565
+ botId
566
+ })
567
+ )
568
+ )).flat().filter(Boolean).map(
569
+ (r) => toMemoryResult(
570
+ r
571
+ )
572
+ );
573
+ } catch (error) {
574
+ logger.warn?.("[memory-store] SQLite lexical search failed:", error);
575
+ }
576
+ return [];
577
+ }
367
578
  function createUnifiedSearch(deps = {}) {
368
579
  const logger = deps.logger ?? console;
580
+ function resolveReasoningStrategy(input) {
581
+ const requested = normalizeUnifiedMemoryReasoningStrategy(input.reasoningStrategy);
582
+ if (requested !== "none") {
583
+ return requested;
584
+ }
585
+ return normalizeUnifiedMemoryReasoningStrategy(deps.reasoning?.defaultStrategy, "none");
586
+ }
369
587
  async function searchUnifiedMemory(input) {
370
588
  const query = input.query.trim();
371
589
  const sources = normalizeUnifiedMemorySearchSources(input.sources);
372
590
  const limit = clampUnifiedMemorySearchLimit(input.limit);
373
591
  const threshold = clampUnifiedMemorySearchThreshold(input.threshold);
374
592
  const mergeStrategy = normalizeUnifiedMemoryMergeStrategy(input.mergeStrategy);
593
+ const reasoningStrategy = resolveReasoningStrategy(input);
375
594
  const warnings = [];
376
595
  if (!query) {
377
596
  return {
@@ -383,10 +602,21 @@ function createUnifiedSearch(deps = {}) {
383
602
  };
384
603
  }
385
604
  let memorySubs;
605
+ const reasoningInfo = { strategy: reasoningStrategy };
606
+ if (input.dateFrom || input.dateTo) {
607
+ reasoningInfo.dateRange = { from: input.dateFrom, to: input.dateTo };
608
+ }
386
609
  if (sources.includes("memory")) {
387
610
  if (isRawMessageStorageAvailable()) {
388
611
  try {
389
- memorySubs = await runMemorySource(input, limit, threshold, warnings);
612
+ memorySubs = await runMemorySource(
613
+ input,
614
+ limit,
615
+ threshold,
616
+ warnings,
617
+ reasoningStrategy,
618
+ reasoningInfo
619
+ );
390
620
  } catch (error) {
391
621
  logger.warn?.("[memory-store] memory source failed:", error);
392
622
  warnings.push({
@@ -465,121 +695,155 @@ function createUnifiedSearch(deps = {}) {
465
695
  limit,
466
696
  strategy: mergeStrategy
467
697
  });
468
- return {
698
+ const output = {
469
699
  query: input.query,
470
700
  sources,
471
701
  results: merged,
472
702
  count: merged.length,
473
703
  warnings
474
704
  };
705
+ if (reasoningInfo && (reasoningInfo.strategy !== "none" || reasoningInfo.dateRange !== void 0)) {
706
+ output.reasoning = reasoningInfo;
707
+ }
708
+ return output;
475
709
  }
476
- async function runMemorySource(input, limit, threshold, warnings) {
710
+ async function runMemorySource(input, limit, threshold, warnings, reasoningStrategy = "none", reasoningInfo) {
711
+ if (reasoningStrategy === "iterative" && !deps.reasoning?.iterativePlanner) {
712
+ warnings.push({
713
+ source: "memory",
714
+ code: "memory_iterative_planner_not_configured",
715
+ message: "Iterative reasoning requested but no iterativePlanner is configured; falling back to default search."
716
+ });
717
+ if (reasoningInfo) reasoningInfo.degraded = true;
718
+ }
719
+ if (reasoningStrategy === "rewrite" && !deps.reasoning?.queryRewriter) {
720
+ warnings.push({
721
+ source: "memory",
722
+ code: "memory_query_rewrite_not_configured",
723
+ message: "Rewrite reasoning requested but no queryRewriter is configured; falling back to default search."
724
+ });
725
+ if (reasoningInfo) reasoningInfo.degraded = true;
726
+ }
727
+ if (reasoningStrategy === "iterative" && deps.reasoning?.iterativePlanner) {
728
+ const planner = deps.reasoning.iterativePlanner;
729
+ const result = await planner.plan({
730
+ query: input.query,
731
+ dateFrom: input.dateFrom,
732
+ dateTo: input.dateTo,
733
+ executor: {
734
+ search: async (request) => {
735
+ const keywords2 = request.keywords.length > 0 ? request.keywords : deriveLexicalKeywords(input.query);
736
+ const lexicalHits = await runLexicalSearchForKeywords(deps, input, keywords2, limit, logger);
737
+ let semanticHits = [];
738
+ if (typeof deps.embedQuery === "function") {
739
+ try {
740
+ const semanticQuery = keywords2.join(" ");
741
+ const queryEmbedding = await embedQueryVariant(deps.embedQuery, input, semanticQuery);
742
+ semanticHits = await runSemanticSearchForEmbedding(
743
+ deps,
744
+ input,
745
+ queryEmbedding,
746
+ limit,
747
+ threshold,
748
+ logger
749
+ );
750
+ } catch (error) {
751
+ logger.warn?.(
752
+ "[memory-store] Iterative semantic search failed; using lexical results only:",
753
+ error
754
+ );
755
+ }
756
+ }
757
+ const candidates = filterByDateRange(
758
+ mergeByMaxScore([
759
+ lexicalHits.map(toIterativeRecallCandidate),
760
+ semanticHits.map(toIterativeRecallCandidate)
761
+ ]),
762
+ request.dateFrom,
763
+ request.dateTo
764
+ );
765
+ return { candidates };
766
+ }
767
+ }
768
+ });
769
+ if (reasoningInfo) {
770
+ reasoningInfo.iterations = result.stats.iterations;
771
+ reasoningInfo.evidenceCount = result.evidence.length;
772
+ if (planner.lastDegraded?.()) {
773
+ reasoningInfo.degraded = true;
774
+ }
775
+ }
776
+ const semantic2 = result.evidence.map((candidate) => ({
777
+ type: "memory",
778
+ id: candidate.id,
779
+ content: candidate.content,
780
+ similarity: candidate.similarity,
781
+ metadata: { ...candidate.metadata, reasoning: "iterative" }
782
+ }));
783
+ return { semantic: semantic2, lexical: [] };
784
+ }
477
785
  if (typeof deps.embedQuery !== "function") {
478
786
  warnings.push({
479
787
  source: "memory",
480
788
  code: "memory_lexical_search_fallback",
481
789
  message: "Semantic search not configured, using keyword search as fallback"
482
790
  });
483
- const { lexicalSearchRawMessages: lexicalSearchRawMessages2 } = await Promise.resolve().then(() => (init_sqlite_raw_message_store(), sqlite_raw_message_store_exports));
484
- const keywords = deriveLexicalKeywords(input.query);
485
- let lexical2 = [];
486
- if (keywords.length > 0) {
487
- try {
488
- const filters2 = input.botIds && input.botIds.length > 0 ? input.botIds : [void 0];
489
- const results = await Promise.all(
490
- filters2.map(
491
- (botId) => lexicalSearchRawMessages2({
492
- userId: input.userId,
493
- keywords,
494
- limit: Math.ceil(limit / filters2.length),
495
- botId
496
- })
497
- )
498
- );
499
- lexical2 = results.flat().filter(Boolean).map(toMemoryResult);
500
- } catch (error) {
501
- logger.warn?.("[memory-store] Default lexical search failed:", error);
502
- }
503
- }
791
+ const keywords2 = deriveLexicalKeywords(input.query);
792
+ const lexical2 = filterByDateRange(
793
+ await runLexicalSearchForKeywords(deps, input, keywords2, limit, logger),
794
+ input.dateFrom,
795
+ input.dateTo
796
+ );
504
797
  return { semantic: [], lexical: lexical2 };
505
798
  }
506
- const queryEmbedding = await deps.embedQuery({
507
- userId: input.userId,
508
- query: input.query,
509
- authToken: input.authToken
510
- });
511
- const filters = input.botIds && input.botIds.length > 0 ? input.botIds.map((botId) => ({ botId })) : [{}];
512
799
  let semantic = [];
513
- if (isRawMessageChromaEnabled()) {
800
+ const embedQuery = deps.embedQuery;
801
+ if (reasoningStrategy === "rewrite" && deps.reasoning?.queryRewriter) {
514
802
  try {
515
- semantic = (await Promise.all(
516
- filters.map((filter) => {
517
- const botId = "botId" in filter ? filter.botId : void 0;
518
- return searchRawMessagesWithChroma({
519
- userId: input.userId,
520
- queryEmbedding,
521
- limit,
522
- threshold,
523
- botId
524
- });
525
- })
526
- )).flat().map(toMemoryResult);
527
- logger.log?.("[memory-store] Raw message semantic search completed", {
528
- backend: "chroma",
529
- dimensions: queryEmbedding.length,
530
- count: semantic.length
803
+ const variants = await deps.reasoning.queryRewriter.rewrite({
804
+ query: input.query,
805
+ userId: input.userId,
806
+ authToken: input.authToken
531
807
  });
532
- } catch (error) {
533
- logger.warn?.(
534
- "[memory-store] Chroma raw message search failed; falling back to database search:",
535
- error
808
+ if (reasoningInfo) {
809
+ reasoningInfo.rewrittenQueries = variants;
810
+ if (deps.reasoning.queryRewriter.lastDegraded?.()) {
811
+ reasoningInfo.degraded = true;
812
+ }
813
+ }
814
+ const embeddings = await Promise.all(
815
+ variants.map((variant) => embedQueryVariant(embedQuery, input, variant))
536
816
  );
817
+ const lists = await Promise.all(
818
+ embeddings.map(
819
+ (embedding) => runSemanticSearchForEmbedding(deps, input, embedding, limit, threshold, logger)
820
+ )
821
+ );
822
+ semantic = mergeByMaxScore(lists);
823
+ } catch (error) {
824
+ logger.warn?.("[memory-store] Query rewriting failed; falling back to original query:", error);
825
+ warnings.push({
826
+ source: "memory",
827
+ code: "memory_query_rewrite_failed",
828
+ message: `Query rewriting failed: ${error.message ?? "Unknown error"}. Using original query.`
829
+ });
830
+ if (reasoningInfo) reasoningInfo.degraded = true;
537
831
  }
538
- } else if (typeof deps.searchRawMessagesAnn === "function") {
539
- semantic = (await Promise.all(
540
- filters.map(
541
- (filter) => deps.searchRawMessagesAnn({
542
- userId: input.userId,
543
- queryEmbedding,
544
- limit,
545
- threshold,
546
- botId: "botId" in filter ? filter.botId : void 0
547
- })
548
- )
549
- )).flat().filter(isRawMemorySemanticResult).map(toMemoryResult);
550
832
  }
551
833
  if (semantic.length === 0) {
552
- try {
553
- const { getRawMessageManager: getRawMessageManager2 } = await Promise.resolve().then(() => (init_raw_message_store(), raw_message_store_exports));
554
- const manager2 = await getRawMessageManager2();
555
- if (typeof manager2.searchMessagesSemantically === "function") {
556
- const results = await manager2.searchMessagesSemantically({
557
- userId: input.userId,
558
- queryEmbedding,
559
- limit,
560
- threshold
561
- });
562
- semantic = results.map((r) => ({
563
- type: "memory",
564
- id: r.id,
565
- content: r.content,
566
- similarity: r.similarity,
567
- metadata: r.metadata ?? {}
568
- }));
569
- }
570
- } catch (error) {
571
- logger.warn?.("[memory-store] SQLite semantic search failed:", error);
572
- }
834
+ const queryEmbedding = await embedQueryVariant(embedQuery, input, input.query);
835
+ semantic = await runSemanticSearchForEmbedding(deps, input, queryEmbedding, limit, threshold, logger);
573
836
  }
574
837
  let lexical = [];
575
- if (typeof deps.searchRawMessagesLexical === "function") {
576
- const keywords = deriveLexicalKeywords(input.query);
577
- if (keywords.length > 0) {
838
+ const keywords = deriveLexicalKeywords(input.query);
839
+ if (keywords.length > 0) {
840
+ if (typeof deps.searchRawMessagesLexical === "function") {
578
841
  try {
579
842
  const lexFilters = input.botIds && input.botIds.length > 0 ? input.botIds : [void 0];
843
+ const searchRawMessagesLexical = deps.searchRawMessagesLexical;
580
844
  lexical = (await Promise.all(
581
845
  lexFilters.map(
582
- (botId) => deps.searchRawMessagesLexical({
846
+ (botId) => searchRawMessagesLexical({
583
847
  userId: input.userId,
584
848
  keywords,
585
849
  limit,
@@ -598,20 +862,24 @@ function createUnifiedSearch(deps = {}) {
598
862
  message: error.message ?? "memory_lexical_search_failed"
599
863
  });
600
864
  }
865
+ } else if (input.mergeStrategy === "rrf") {
866
+ warnings.push({
867
+ source: "memory",
868
+ code: "memory_lexical_search_not_configured",
869
+ message: "RRF merge requested but lexical search is not configured; falling back to semantic-only RRF."
870
+ });
601
871
  }
602
- } else if (input.mergeStrategy === "rrf") {
603
- warnings.push({
604
- source: "memory",
605
- code: "memory_lexical_search_not_configured",
606
- message: "RRF merge requested but lexical search is not configured; falling back to semantic-only RRF."
607
- });
608
872
  }
609
- return { semantic, lexical };
873
+ return {
874
+ semantic: filterByDateRange(semantic, input.dateFrom, input.dateTo),
875
+ lexical: filterByDateRange(lexical, input.dateFrom, input.dateTo)
876
+ };
610
877
  }
611
878
  async function searchRawMemorySemantically(input) {
612
879
  const limit = clampUnifiedMemorySearchLimit(input.limit);
613
880
  const threshold = clampUnifiedMemorySearchThreshold(input.threshold);
614
- const sub = await runMemorySource(input, limit, threshold, []);
881
+ const reasoningStrategy = resolveReasoningStrategy(input);
882
+ const sub = await runMemorySource(input, limit, threshold, [], reasoningStrategy);
615
883
  return mergeAcrossSources({
616
884
  memorySubs: sub,
617
885
  insightHits: [],
@@ -652,4 +920,4 @@ function mergeAcrossSources(input) {
652
920
  return mergeUnifiedMemorySearchResultsRrf(lists, input.limit);
653
921
  }
654
922
 
655
- export { clampUnifiedMemorySearchLimit, clampUnifiedMemorySearchThreshold, createUnifiedSearch, isRawMemorySemanticResult, mergeUnifiedMemorySearchResults, mergeUnifiedMemorySearchResultsRrf, normalizeUnifiedMemoryMergeStrategy, normalizeUnifiedMemorySearchSources, toKnowledgeResult, toMemoryResult };
923
+ export { clampUnifiedMemorySearchLimit, clampUnifiedMemorySearchThreshold, createUnifiedSearch, isRawMemorySemanticResult, mergeUnifiedMemorySearchResults, mergeUnifiedMemorySearchResultsRrf, normalizeUnifiedMemoryMergeStrategy, normalizeUnifiedMemoryReasoningStrategy, normalizeUnifiedMemorySearchSources, toKnowledgeResult, toMemoryResult };