@seanhogg/builderforce-memory 2026.6.27 → 2026.6.28
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/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/memory/MemoryStore.d.ts +12 -0
- package/dist/memory/MemoryStore.d.ts.map +1 -1
- package/dist/memory/MemoryStore.js +28 -0
- package/dist/memory/MemoryStore.js.map +1 -1
- package/dist/retrieval/HybridRetriever.d.ts +56 -0
- package/dist/retrieval/HybridRetriever.d.ts.map +1 -0
- package/dist/retrieval/HybridRetriever.js +75 -0
- package/dist/retrieval/HybridRetriever.js.map +1 -0
- package/dist/retrieval/bm25.d.ts +32 -0
- package/dist/retrieval/bm25.d.ts.map +1 -0
- package/dist/retrieval/bm25.js +66 -0
- package/dist/retrieval/bm25.js.map +1 -0
- package/dist/retrieval/chunk.d.ts +33 -0
- package/dist/retrieval/chunk.d.ts.map +1 -0
- package/dist/retrieval/chunk.js +83 -0
- package/dist/retrieval/chunk.js.map +1 -0
- package/dist/retrieval/fusion.d.ts +40 -0
- package/dist/retrieval/fusion.d.ts.map +1 -0
- package/dist/retrieval/fusion.js +64 -0
- package/dist/retrieval/fusion.js.map +1 -0
- package/dist/retrieval/index.d.ts +16 -0
- package/dist/retrieval/index.d.ts.map +1 -0
- package/dist/retrieval/index.js +12 -0
- package/dist/retrieval/index.js.map +1 -0
- package/package.json +8 -4
- package/src/index.ts +48 -0
- package/src/memory/MemoryStore.ts +36 -0
- package/src/retrieval/HybridRetriever.ts +122 -0
- package/src/retrieval/bm25.ts +83 -0
- package/src/retrieval/chunk.ts +101 -0
- package/src/retrieval/fusion.ts +84 -0
- package/src/retrieval/index.ts +24 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rank fusion + diversity reranking.
|
|
3
|
+
*
|
|
4
|
+
* • Reciprocal Rank Fusion (RRF) merges the dense (vector) and sparse (BM25)
|
|
5
|
+
* rankings into one list without needing the two score scales to be
|
|
6
|
+
* commensurable — it fuses on RANK, not raw score. This is the standard,
|
|
7
|
+
* parameter-light way to combine hybrid retrieval signals.
|
|
8
|
+
* • Maximal Marginal Relevance (MMR) reranks the fused list to trade off
|
|
9
|
+
* relevance against novelty, so the top-k isn't five near-duplicate chunks.
|
|
10
|
+
*
|
|
11
|
+
* Pure and zero-dependency.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { cosineSimilarity } from '../similarity/index.js';
|
|
15
|
+
|
|
16
|
+
export interface RankedList {
|
|
17
|
+
/** Ordered ids, most relevant first. */
|
|
18
|
+
ids: string[];
|
|
19
|
+
/** Optional weight for this list in the fusion (default 1). */
|
|
20
|
+
weight?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface FusedHit {
|
|
24
|
+
id: string;
|
|
25
|
+
score: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Reciprocal Rank Fusion over any number of ranked lists.
|
|
30
|
+
* score(d) = Σ_lists weight / (k + rank(d)). `k` (default 60) damps the
|
|
31
|
+
* contribution of low-ranked items; the canonical TREC value.
|
|
32
|
+
*/
|
|
33
|
+
export function reciprocalRankFusion(lists: RankedList[], k = 60): FusedHit[] {
|
|
34
|
+
const acc = new Map<string, number>();
|
|
35
|
+
for (const list of lists) {
|
|
36
|
+
const weight = list.weight ?? 1;
|
|
37
|
+
list.ids.forEach((id, rank) => {
|
|
38
|
+
acc.set(id, (acc.get(id) ?? 0) + weight / (k + rank + 1));
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
return [...acc.entries()]
|
|
42
|
+
.map(([id, score]) => ({ id, score }))
|
|
43
|
+
.sort((a, b) => b.score - a.score);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface MmrCandidate {
|
|
47
|
+
id: string;
|
|
48
|
+
vector: Float32Array;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Maximal Marginal Relevance rerank. Greedily selects up to `topK` candidates,
|
|
53
|
+
* each step maximising `λ·sim(query, d) − (1−λ)·max sim(d, already-selected)`.
|
|
54
|
+
* λ=1 is pure relevance; lower λ injects diversity. Candidates without vectors
|
|
55
|
+
* should be filtered out by the caller (they cannot be MMR-scored).
|
|
56
|
+
*/
|
|
57
|
+
export function maximalMarginalRelevance(
|
|
58
|
+
queryVec: Float32Array,
|
|
59
|
+
candidates: MmrCandidate[],
|
|
60
|
+
topK: number,
|
|
61
|
+
lambda = 0.7,
|
|
62
|
+
): string[] {
|
|
63
|
+
const remaining = [...candidates];
|
|
64
|
+
const selected: MmrCandidate[] = [];
|
|
65
|
+
const relevance = new Map<string, number>();
|
|
66
|
+
for (const c of remaining) relevance.set(c.id, cosineSimilarity(queryVec, c.vector));
|
|
67
|
+
|
|
68
|
+
while (selected.length < topK && remaining.length > 0) {
|
|
69
|
+
let bestIdx = 0;
|
|
70
|
+
let bestScore = -Infinity;
|
|
71
|
+
for (let i = 0; i < remaining.length; i++) {
|
|
72
|
+
const c = remaining[i]!;
|
|
73
|
+
let maxSimToSelected = 0;
|
|
74
|
+
for (const s of selected) {
|
|
75
|
+
const sim = cosineSimilarity(c.vector, s.vector);
|
|
76
|
+
if (sim > maxSimToSelected) maxSimToSelected = sim;
|
|
77
|
+
}
|
|
78
|
+
const mmr = lambda * relevance.get(c.id)! - (1 - lambda) * maxSimToSelected;
|
|
79
|
+
if (mmr > bestScore) { bestScore = mmr; bestIdx = i; }
|
|
80
|
+
}
|
|
81
|
+
selected.push(remaining.splice(bestIdx, 1)[0]!);
|
|
82
|
+
}
|
|
83
|
+
return selected.map(s => s.id);
|
|
84
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retrieval layer — chunking, BM25, rank fusion, and the HybridRetriever.
|
|
3
|
+
*
|
|
4
|
+
* The classic RAG pieces the memory stack previously lacked (chunking, hybrid
|
|
5
|
+
* dense+sparse search, reranking), implemented zero-dependency so they run in the
|
|
6
|
+
* browser, Node, and the SSM runtime alike.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export { chunkText } from './chunk.js';
|
|
10
|
+
export type { Chunk, ChunkOptions } from './chunk.js';
|
|
11
|
+
|
|
12
|
+
export { bm25Search } from './bm25.js';
|
|
13
|
+
export type { Bm25Doc, Bm25Hit, Bm25Options } from './bm25.js';
|
|
14
|
+
|
|
15
|
+
export { reciprocalRankFusion, maximalMarginalRelevance } from './fusion.js';
|
|
16
|
+
export type { RankedList, FusedHit, MmrCandidate } from './fusion.js';
|
|
17
|
+
|
|
18
|
+
export { hybridRetrieve } from './HybridRetriever.js';
|
|
19
|
+
export type {
|
|
20
|
+
RetrievalCandidate,
|
|
21
|
+
HybridQuery,
|
|
22
|
+
HybridRetrieveOptions,
|
|
23
|
+
HybridHit,
|
|
24
|
+
} from './HybridRetriever.js';
|