@melandlabs/memory-store 0.2.7 → 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/config-2Q092MUz.d.ts +470 -0
- package/dist/http.d.ts +1 -1
- package/dist/http.js +367 -98
- package/dist/index.d.ts +3 -3
- package/dist/index.js +724 -99
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +370 -98
- package/dist/search/unified-search.d.ts +3 -101
- package/dist/search/unified-search.js +368 -99
- package/dist/server/cli-http.js +376 -98
- package/dist/server/cli-mcp.js +379 -98
- package/dist/server/cli-shared.d.ts +1 -1
- package/dist/server/cli-shared.js +10 -1
- package/dist/storage/postgres-raw-message-factory.d.ts +1 -1
- package/dist/storage/raw-message-store.d.ts +1 -1
- package/dist/storage/raw-message-store.js +1 -1
- package/dist/storage/sqlite-raw-message-store.d.ts +1 -1
- package/dist/storage/sqlite-vector-index.d.ts +1 -1
- package/package.json +10 -9
- package/dist/config-Ll6ktm4D.d.ts +0 -183
package/dist/http.js
CHANGED
|
@@ -239,7 +239,7 @@ __export(raw_message_store_exports, {
|
|
|
239
239
|
getRawMessageStorageBackend: () => getRawMessageStorageBackend,
|
|
240
240
|
isRawMessageStorageAvailable: () => isRawMessageStorageAvailable
|
|
241
241
|
});
|
|
242
|
-
function resolveBackend(
|
|
242
|
+
function resolveBackend(_env) {
|
|
243
243
|
const explicit = process.env.OPENCONTEXT_MEMORY_STORE_BACKEND?.trim().toLowerCase();
|
|
244
244
|
if (explicit === "postgres") return "postgres";
|
|
245
245
|
return "sqlite";
|
|
@@ -372,6 +372,12 @@ function mergeUnifiedMemorySearchResults(results, limit, options = {}) {
|
|
|
372
372
|
function normalizeUnifiedMemoryMergeStrategy(value) {
|
|
373
373
|
return value === "rrf" ? "rrf" : "similarity";
|
|
374
374
|
}
|
|
375
|
+
function normalizeUnifiedMemoryReasoningStrategy(value, defaultStrategy = "none") {
|
|
376
|
+
if (value === "rewrite" || value === "iterative") {
|
|
377
|
+
return value;
|
|
378
|
+
}
|
|
379
|
+
return defaultStrategy;
|
|
380
|
+
}
|
|
375
381
|
var DEFAULT_RRF_K = 60;
|
|
376
382
|
function mergeUnifiedMemorySearchResultsRrf(lists, limit, k = DEFAULT_RRF_K) {
|
|
377
383
|
if (!Array.isArray(lists) || lists.length === 0) {
|
|
@@ -394,7 +400,13 @@ function mergeUnifiedMemorySearchResultsRrf(lists, limit, k = DEFAULT_RRF_K) {
|
|
|
394
400
|
}
|
|
395
401
|
}
|
|
396
402
|
}
|
|
397
|
-
const ranked = order.map((key) =>
|
|
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) => {
|
|
398
410
|
if (b.rrf !== a.rrf) {
|
|
399
411
|
return b.rrf - a.rrf;
|
|
400
412
|
}
|
|
@@ -439,14 +451,222 @@ function isRawMemorySemanticResult(result) {
|
|
|
439
451
|
function deriveLexicalKeywords(query) {
|
|
440
452
|
return query.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((token) => token.length >= 2).slice(0, 16);
|
|
441
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
|
+
}
|
|
442
654
|
function createUnifiedSearch(deps = {}) {
|
|
443
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
|
+
}
|
|
444
663
|
async function searchUnifiedMemory(input) {
|
|
445
664
|
const query = input.query.trim();
|
|
446
665
|
const sources = normalizeUnifiedMemorySearchSources(input.sources);
|
|
447
666
|
const limit = clampUnifiedMemorySearchLimit(input.limit);
|
|
448
667
|
const threshold = clampUnifiedMemorySearchThreshold(input.threshold);
|
|
449
668
|
const mergeStrategy = normalizeUnifiedMemoryMergeStrategy(input.mergeStrategy);
|
|
669
|
+
const reasoningStrategy = resolveReasoningStrategy(input);
|
|
450
670
|
const warnings = [];
|
|
451
671
|
if (!query) {
|
|
452
672
|
return {
|
|
@@ -458,10 +678,21 @@ function createUnifiedSearch(deps = {}) {
|
|
|
458
678
|
};
|
|
459
679
|
}
|
|
460
680
|
let memorySubs;
|
|
681
|
+
const reasoningInfo = { strategy: reasoningStrategy };
|
|
682
|
+
if (input.dateFrom || input.dateTo) {
|
|
683
|
+
reasoningInfo.dateRange = { from: input.dateFrom, to: input.dateTo };
|
|
684
|
+
}
|
|
461
685
|
if (sources.includes("memory")) {
|
|
462
686
|
if (isRawMessageStorageAvailable()) {
|
|
463
687
|
try {
|
|
464
|
-
memorySubs = await runMemorySource(
|
|
688
|
+
memorySubs = await runMemorySource(
|
|
689
|
+
input,
|
|
690
|
+
limit,
|
|
691
|
+
threshold,
|
|
692
|
+
warnings,
|
|
693
|
+
reasoningStrategy,
|
|
694
|
+
reasoningInfo
|
|
695
|
+
);
|
|
465
696
|
} catch (error) {
|
|
466
697
|
logger.warn?.("[memory-store] memory source failed:", error);
|
|
467
698
|
warnings.push({
|
|
@@ -540,121 +771,155 @@ function createUnifiedSearch(deps = {}) {
|
|
|
540
771
|
limit,
|
|
541
772
|
strategy: mergeStrategy
|
|
542
773
|
});
|
|
543
|
-
|
|
774
|
+
const output = {
|
|
544
775
|
query: input.query,
|
|
545
776
|
sources,
|
|
546
777
|
results: merged,
|
|
547
778
|
count: merged.length,
|
|
548
779
|
warnings
|
|
549
780
|
};
|
|
781
|
+
if (reasoningInfo && (reasoningInfo.strategy !== "none" || reasoningInfo.dateRange !== void 0)) {
|
|
782
|
+
output.reasoning = reasoningInfo;
|
|
783
|
+
}
|
|
784
|
+
return output;
|
|
550
785
|
}
|
|
551
|
-
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
|
+
}
|
|
552
861
|
if (typeof deps.embedQuery !== "function") {
|
|
553
862
|
warnings.push({
|
|
554
863
|
source: "memory",
|
|
555
864
|
code: "memory_lexical_search_fallback",
|
|
556
865
|
message: "Semantic search not configured, using keyword search as fallback"
|
|
557
866
|
});
|
|
558
|
-
const
|
|
559
|
-
const
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
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
|
-
}
|
|
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
|
+
);
|
|
579
873
|
return { semantic: [], lexical: lexical2 };
|
|
580
874
|
}
|
|
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
875
|
let semantic = [];
|
|
588
|
-
|
|
876
|
+
const embedQuery = deps.embedQuery;
|
|
877
|
+
if (reasoningStrategy === "rewrite" && deps.reasoning?.queryRewriter) {
|
|
589
878
|
try {
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
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
|
|
879
|
+
const variants = await deps.reasoning.queryRewriter.rewrite({
|
|
880
|
+
query: input.query,
|
|
881
|
+
userId: input.userId,
|
|
882
|
+
authToken: input.authToken
|
|
606
883
|
});
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
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))
|
|
892
|
+
);
|
|
893
|
+
const lists = await Promise.all(
|
|
894
|
+
embeddings.map(
|
|
895
|
+
(embedding) => runSemanticSearchForEmbedding(deps, input, embedding, limit, threshold, logger)
|
|
896
|
+
)
|
|
611
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;
|
|
612
907
|
}
|
|
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
908
|
}
|
|
626
909
|
if (semantic.length === 0) {
|
|
627
|
-
|
|
628
|
-
|
|
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
|
-
}
|
|
910
|
+
const queryEmbedding = await embedQueryVariant(embedQuery, input, input.query);
|
|
911
|
+
semantic = await runSemanticSearchForEmbedding(deps, input, queryEmbedding, limit, threshold, logger);
|
|
648
912
|
}
|
|
649
913
|
let lexical = [];
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
if (
|
|
914
|
+
const keywords = deriveLexicalKeywords(input.query);
|
|
915
|
+
if (keywords.length > 0) {
|
|
916
|
+
if (typeof deps.searchRawMessagesLexical === "function") {
|
|
653
917
|
try {
|
|
654
918
|
const lexFilters = input.botIds && input.botIds.length > 0 ? input.botIds : [void 0];
|
|
919
|
+
const searchRawMessagesLexical = deps.searchRawMessagesLexical;
|
|
655
920
|
lexical = (await Promise.all(
|
|
656
921
|
lexFilters.map(
|
|
657
|
-
(botId) =>
|
|
922
|
+
(botId) => searchRawMessagesLexical({
|
|
658
923
|
userId: input.userId,
|
|
659
924
|
keywords,
|
|
660
925
|
limit,
|
|
@@ -673,20 +938,24 @@ function createUnifiedSearch(deps = {}) {
|
|
|
673
938
|
message: error.message ?? "memory_lexical_search_failed"
|
|
674
939
|
});
|
|
675
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
|
+
});
|
|
676
947
|
}
|
|
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
948
|
}
|
|
684
|
-
return {
|
|
949
|
+
return {
|
|
950
|
+
semantic: filterByDateRange(semantic, input.dateFrom, input.dateTo),
|
|
951
|
+
lexical: filterByDateRange(lexical, input.dateFrom, input.dateTo)
|
|
952
|
+
};
|
|
685
953
|
}
|
|
686
954
|
async function searchRawMemorySemantically(input) {
|
|
687
955
|
const limit = clampUnifiedMemorySearchLimit(input.limit);
|
|
688
956
|
const threshold = clampUnifiedMemorySearchThreshold(input.threshold);
|
|
689
|
-
const
|
|
957
|
+
const reasoningStrategy = resolveReasoningStrategy(input);
|
|
958
|
+
const sub = await runMemorySource(input, limit, threshold, [], reasoningStrategy);
|
|
690
959
|
return mergeAcrossSources({
|
|
691
960
|
memorySubs: sub,
|
|
692
961
|
insightHits: [],
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { M as MemoryStoreConfig } from './config-
|
|
2
|
-
export { E as EmbedQueryFn, a as
|
|
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 {
|
|
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';
|