@seanhogg/builderforce-memory 2026.10.28 → 2026.10.29
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/ingest/IngestionPipeline.d.ts +1 -8
- package/dist/ingest/IngestionPipeline.d.ts.map +1 -1
- package/dist/ingest/IngestionPipeline.js +3 -15
- package/dist/ingest/IngestionPipeline.js.map +1 -1
- package/dist/ingest/docsExtract.d.ts +30 -0
- package/dist/ingest/docsExtract.d.ts.map +1 -0
- package/dist/ingest/docsExtract.js +221 -0
- package/dist/ingest/docsExtract.js.map +1 -0
- package/dist/ingest/hash.d.ts +15 -0
- package/dist/ingest/hash.d.ts.map +1 -0
- package/dist/ingest/hash.js +22 -0
- package/dist/ingest/hash.js.map +1 -0
- package/dist/ingest/parsers.d.ts.map +1 -1
- package/dist/ingest/parsers.js +4 -0
- package/dist/ingest/parsers.js.map +1 -1
- package/dist/ingest/types.d.ts +7 -0
- package/dist/ingest/types.d.ts.map +1 -1
- package/dist/ingest/types.js.map +1 -1
- package/dist/knowledge/build.d.ts +24 -0
- package/dist/knowledge/build.d.ts.map +1 -0
- package/dist/knowledge/build.js +263 -0
- package/dist/knowledge/build.js.map +1 -0
- package/dist/knowledge/cards.d.ts +17 -0
- package/dist/knowledge/cards.d.ts.map +1 -0
- package/dist/knowledge/cards.js +118 -0
- package/dist/knowledge/cards.js.map +1 -0
- package/dist/knowledge/findings.d.ts +24 -0
- package/dist/knowledge/findings.d.ts.map +1 -0
- package/dist/knowledge/findings.js +152 -0
- package/dist/knowledge/findings.js.map +1 -0
- package/dist/knowledge/importance.d.ts +21 -0
- package/dist/knowledge/importance.d.ts.map +1 -0
- package/dist/knowledge/importance.js +70 -0
- package/dist/knowledge/importance.js.map +1 -0
- package/dist/knowledge/index.d.ts +31 -0
- package/dist/knowledge/index.d.ts.map +1 -0
- package/dist/knowledge/index.js +26 -0
- package/dist/knowledge/index.js.map +1 -0
- package/dist/knowledge/judge.d.ts +86 -0
- package/dist/knowledge/judge.d.ts.map +1 -0
- package/dist/knowledge/judge.js +213 -0
- package/dist/knowledge/judge.js.map +1 -0
- package/dist/knowledge/model.d.ts +333 -0
- package/dist/knowledge/model.d.ts.map +1 -0
- package/dist/knowledge/model.js +13 -0
- package/dist/knowledge/model.js.map +1 -0
- package/dist/knowledge/packs/docs.d.ts +17 -0
- package/dist/knowledge/packs/docs.d.ts.map +1 -0
- package/dist/knowledge/packs/docs.js +89 -0
- package/dist/knowledge/packs/docs.js.map +1 -0
- package/dist/knowledge/partitions.d.ts +31 -0
- package/dist/knowledge/partitions.d.ts.map +1 -0
- package/dist/knowledge/partitions.js +135 -0
- package/dist/knowledge/partitions.js.map +1 -0
- package/dist/knowledge/plan.d.ts +33 -0
- package/dist/knowledge/plan.d.ts.map +1 -0
- package/dist/knowledge/plan.js +89 -0
- package/dist/knowledge/plan.js.map +1 -0
- package/dist/knowledge/refs.d.ts +40 -0
- package/dist/knowledge/refs.d.ts.map +1 -0
- package/dist/knowledge/refs.js +102 -0
- package/dist/knowledge/refs.js.map +1 -0
- package/dist/knowledge/resolve.d.ts +35 -0
- package/dist/knowledge/resolve.d.ts.map +1 -0
- package/dist/knowledge/resolve.js +67 -0
- package/dist/knowledge/resolve.js.map +1 -0
- package/dist/knowledge/review.d.ts +23 -0
- package/dist/knowledge/review.d.ts.map +1 -0
- package/dist/knowledge/review.js +233 -0
- package/dist/knowledge/review.js.map +1 -0
- package/dist/knowledge/sources.d.ts +47 -0
- package/dist/knowledge/sources.d.ts.map +1 -0
- package/dist/knowledge/sources.js +136 -0
- package/dist/knowledge/sources.js.map +1 -0
- package/dist/knowledge/stores/localSnapshotStore.d.ts +50 -0
- package/dist/knowledge/stores/localSnapshotStore.d.ts.map +1 -0
- package/dist/knowledge/stores/localSnapshotStore.js +125 -0
- package/dist/knowledge/stores/localSnapshotStore.js.map +1 -0
- package/dist/knowledge/trace.d.ts +32 -0
- package/dist/knowledge/trace.d.ts.map +1 -0
- package/dist/knowledge/trace.js +102 -0
- package/dist/knowledge/trace.js.map +1 -0
- package/dist/knowledge/truncate.d.ts +24 -0
- package/dist/knowledge/truncate.d.ts.map +1 -0
- package/dist/knowledge/truncate.js +128 -0
- package/dist/knowledge/truncate.js.map +1 -0
- package/dist/memory/SemanticRecall.d.ts.map +1 -1
- package/dist/memory/SemanticRecall.js +3 -1
- package/dist/memory/SemanticRecall.js.map +1 -1
- package/dist/retrieval/HybridRetriever.d.ts.map +1 -1
- package/dist/retrieval/HybridRetriever.js +3 -1
- package/dist/retrieval/HybridRetriever.js.map +1 -1
- package/dist/retrieval/bm25.d.ts +3 -2
- package/dist/retrieval/bm25.d.ts.map +1 -1
- package/dist/retrieval/bm25.js +5 -3
- package/dist/retrieval/bm25.js.map +1 -1
- package/dist/retrieval/fusion.d.ts +2 -1
- package/dist/retrieval/fusion.d.ts.map +1 -1
- package/dist/retrieval/fusion.js +4 -2
- package/dist/retrieval/fusion.js.map +1 -1
- package/dist/retrieval/hnsw.d.ts +49 -11
- package/dist/retrieval/hnsw.d.ts.map +1 -1
- package/dist/retrieval/hnsw.js +57 -29
- package/dist/retrieval/hnsw.js.map +1 -1
- package/dist/retrieval/index.d.ts +7 -3
- package/dist/retrieval/index.d.ts.map +1 -1
- package/dist/retrieval/index.js +5 -2
- package/dist/retrieval/index.js.map +1 -1
- package/dist/retrieval/knowledge-index/bytes.d.ts +43 -0
- package/dist/retrieval/knowledge-index/bytes.d.ts.map +1 -0
- package/dist/retrieval/knowledge-index/bytes.js +151 -0
- package/dist/retrieval/knowledge-index/bytes.js.map +1 -0
- package/dist/retrieval/knowledge-index/cascade.d.ts +37 -0
- package/dist/retrieval/knowledge-index/cascade.d.ts.map +1 -0
- package/dist/retrieval/knowledge-index/cascade.js +111 -0
- package/dist/retrieval/knowledge-index/cascade.js.map +1 -0
- package/dist/retrieval/knowledge-index/compact.d.ts +18 -0
- package/dist/retrieval/knowledge-index/compact.d.ts.map +1 -0
- package/dist/retrieval/knowledge-index/compact.js +64 -0
- package/dist/retrieval/knowledge-index/compact.js.map +1 -0
- package/dist/retrieval/knowledge-index/csr.d.ts +41 -0
- package/dist/retrieval/knowledge-index/csr.d.ts.map +1 -0
- package/dist/retrieval/knowledge-index/csr.js +76 -0
- package/dist/retrieval/knowledge-index/csr.js.map +1 -0
- package/dist/retrieval/knowledge-index/digest.d.ts +21 -0
- package/dist/retrieval/knowledge-index/digest.d.ts.map +1 -0
- package/dist/retrieval/knowledge-index/digest.js +50 -0
- package/dist/retrieval/knowledge-index/digest.js.map +1 -0
- package/dist/retrieval/knowledge-index/embeddings.d.ts +32 -0
- package/dist/retrieval/knowledge-index/embeddings.d.ts.map +1 -0
- package/dist/retrieval/knowledge-index/embeddings.js +78 -0
- package/dist/retrieval/knowledge-index/embeddings.js.map +1 -0
- package/dist/retrieval/knowledge-index/expand.d.ts +19 -0
- package/dist/retrieval/knowledge-index/expand.d.ts.map +1 -0
- package/dist/retrieval/knowledge-index/expand.js +49 -0
- package/dist/retrieval/knowledge-index/expand.js.map +1 -0
- package/dist/retrieval/knowledge-index/index.d.ts +40 -0
- package/dist/retrieval/knowledge-index/index.d.ts.map +1 -0
- package/dist/retrieval/knowledge-index/index.js +134 -0
- package/dist/retrieval/knowledge-index/index.js.map +1 -0
- package/dist/retrieval/knowledge-index/lexical.d.ts +26 -0
- package/dist/retrieval/knowledge-index/lexical.d.ts.map +1 -0
- package/dist/retrieval/knowledge-index/lexical.js +76 -0
- package/dist/retrieval/knowledge-index/lexical.js.map +1 -0
- package/dist/retrieval/knowledge-index/pairs.d.ts +22 -0
- package/dist/retrieval/knowledge-index/pairs.d.ts.map +1 -0
- package/dist/retrieval/knowledge-index/pairs.js +51 -0
- package/dist/retrieval/knowledge-index/pairs.js.map +1 -0
- package/dist/retrieval/knowledge-index/prune.d.ts +21 -0
- package/dist/retrieval/knowledge-index/prune.d.ts.map +1 -0
- package/dist/retrieval/knowledge-index/prune.js +43 -0
- package/dist/retrieval/knowledge-index/prune.js.map +1 -0
- package/dist/retrieval/knowledge-index/quantize.d.ts +37 -0
- package/dist/retrieval/knowledge-index/quantize.d.ts.map +1 -0
- package/dist/retrieval/knowledge-index/quantize.js +77 -0
- package/dist/retrieval/knowledge-index/quantize.js.map +1 -0
- package/dist/retrieval/knowledge-index/serialize.d.ts +18 -0
- package/dist/retrieval/knowledge-index/serialize.d.ts.map +1 -0
- package/dist/retrieval/knowledge-index/serialize.js +123 -0
- package/dist/retrieval/knowledge-index/serialize.js.map +1 -0
- package/dist/retrieval/knowledge-index/sha256.d.ts +30 -0
- package/dist/retrieval/knowledge-index/sha256.d.ts.map +1 -0
- package/dist/retrieval/knowledge-index/sha256.js +130 -0
- package/dist/retrieval/knowledge-index/sha256.js.map +1 -0
- package/dist/retrieval/knowledge-index/state.d.ts +55 -0
- package/dist/retrieval/knowledge-index/state.d.ts.map +1 -0
- package/dist/retrieval/knowledge-index/state.js +67 -0
- package/dist/retrieval/knowledge-index/state.js.map +1 -0
- package/dist/retrieval/knowledge-index/tokenize.d.ts +20 -0
- package/dist/retrieval/knowledge-index/tokenize.d.ts.map +1 -0
- package/dist/retrieval/knowledge-index/tokenize.js +42 -0
- package/dist/retrieval/knowledge-index/tokenize.js.map +1 -0
- package/dist/retrieval/knowledge-index/traverse.d.ts +26 -0
- package/dist/retrieval/knowledge-index/traverse.d.ts.map +1 -0
- package/dist/retrieval/knowledge-index/traverse.js +90 -0
- package/dist/retrieval/knowledge-index/traverse.js.map +1 -0
- package/dist/retrieval/knowledge-index/types.d.ts +85 -0
- package/dist/retrieval/knowledge-index/types.d.ts.map +1 -0
- package/dist/retrieval/knowledge-index/types.js +9 -0
- package/dist/retrieval/knowledge-index/types.js.map +1 -0
- package/dist/retrieval/mmr.d.ts +11 -4
- package/dist/retrieval/mmr.d.ts.map +1 -1
- package/dist/retrieval/mmr.js +28 -8
- package/dist/retrieval/mmr.js.map +1 -1
- package/dist/retrieval/order.d.ts +41 -0
- package/dist/retrieval/order.d.ts.map +1 -0
- package/dist/retrieval/order.js +54 -0
- package/dist/retrieval/order.js.map +1 -0
- package/dist/retrieval/weightedFusion.d.ts +2 -1
- package/dist/retrieval/weightedFusion.d.ts.map +1 -1
- package/dist/retrieval/weightedFusion.js +7 -5
- package/dist/retrieval/weightedFusion.js.map +1 -1
- package/dist/vectorstore/MemoryVectorStore.d.ts.map +1 -1
- package/dist/vectorstore/MemoryVectorStore.js +2 -1
- package/dist/vectorstore/MemoryVectorStore.js.map +1 -1
- package/package.json +8 -3
- package/src/ingest/IngestionPipeline.ts +3 -15
- package/src/ingest/docsExtract.ts +219 -0
- package/src/ingest/hash.ts +22 -0
- package/src/ingest/parsers.ts +4 -0
- package/src/ingest/types.ts +7 -0
- package/src/knowledge/build.test.ts +150 -0
- package/src/knowledge/build.ts +266 -0
- package/src/knowledge/cards.ts +130 -0
- package/src/knowledge/docs.test.ts +118 -0
- package/src/knowledge/findings.ts +159 -0
- package/src/knowledge/importance.ts +72 -0
- package/src/knowledge/index.ts +53 -0
- package/src/knowledge/judge.ts +231 -0
- package/src/knowledge/model.ts +312 -0
- package/src/knowledge/packs/docs.ts +91 -0
- package/src/knowledge/partitions.test.ts +98 -0
- package/src/knowledge/partitions.ts +119 -0
- package/src/knowledge/plan.ts +115 -0
- package/src/knowledge/refs.ts +108 -0
- package/src/knowledge/resolve.ts +78 -0
- package/src/knowledge/review.test.ts +180 -0
- package/src/knowledge/review.ts +235 -0
- package/src/knowledge/sources.ts +146 -0
- package/src/knowledge/stores/localSnapshotStore.test.ts +82 -0
- package/src/knowledge/stores/localSnapshotStore.ts +159 -0
- package/src/knowledge/testkit.test-util.ts +92 -0
- package/src/knowledge/trace.test.ts +91 -0
- package/src/knowledge/trace.ts +111 -0
- package/src/knowledge/truncate.ts +118 -0
- package/src/memory/SemanticRecall.ts +3 -1
- package/src/retrieval/HybridRetriever.ts +3 -1
- package/src/retrieval/bm25.ts +5 -3
- package/src/retrieval/fusion.ts +5 -2
- package/src/retrieval/hnsw.ts +82 -35
- package/src/retrieval/index.ts +17 -3
- package/src/retrieval/knowledge-index/bytes.ts +166 -0
- package/src/retrieval/knowledge-index/cascade.ts +125 -0
- package/src/retrieval/knowledge-index/compact.ts +68 -0
- package/src/retrieval/knowledge-index/csr.ts +102 -0
- package/src/retrieval/knowledge-index/digest.ts +54 -0
- package/src/retrieval/knowledge-index/embeddings.ts +85 -0
- package/src/retrieval/knowledge-index/expand.ts +55 -0
- package/src/retrieval/knowledge-index/index.ts +162 -0
- package/src/retrieval/knowledge-index/lexical.ts +78 -0
- package/src/retrieval/knowledge-index/pairs.ts +57 -0
- package/src/retrieval/knowledge-index/prune.ts +48 -0
- package/src/retrieval/knowledge-index/quantize.ts +78 -0
- package/src/retrieval/knowledge-index/serialize.ts +124 -0
- package/src/retrieval/knowledge-index/sha256.ts +122 -0
- package/src/retrieval/knowledge-index/state.ts +108 -0
- package/src/retrieval/knowledge-index/tokenize.ts +41 -0
- package/src/retrieval/knowledge-index/traverse.ts +95 -0
- package/src/retrieval/knowledge-index/types.ts +78 -0
- package/src/retrieval/mmr.ts +35 -10
- package/src/retrieval/order.ts +68 -0
- package/src/retrieval/weightedFusion.ts +8 -5
- package/src/vectorstore/MemoryVectorStore.ts +2 -1
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The knowledge index — a deterministic, LEANN-style index over knowledge-graph
|
|
3
|
+
* cards (design: Builderforce.ai/docs/design/deterministic-knowledge-index.md).
|
|
4
|
+
*
|
|
5
|
+
* Exact → lexical → dense cascade; int8 codes with integer traversal; a
|
|
6
|
+
* high-degree-preserving pruned graph stored as CSR; float vectors recomputed
|
|
7
|
+
* only for the candidates being reranked. Every result is a pure function of
|
|
8
|
+
* `(digest(), query, opts)`.
|
|
9
|
+
*
|
|
10
|
+
* Runs in a Worker, the browser and Node: no Node-only API anywhere.
|
|
11
|
+
*/
|
|
12
|
+
import type { EmbedderPort, IndexParams, KnowledgeIndex } from './types.js';
|
|
13
|
+
export interface KnowledgeIndexStorage {
|
|
14
|
+
nodes: number;
|
|
15
|
+
codeBytes: number;
|
|
16
|
+
graphBytes: number;
|
|
17
|
+
/** What the same nodes would take as float32 vectors. */
|
|
18
|
+
float32Bytes: number;
|
|
19
|
+
}
|
|
20
|
+
/** The concrete index type: the contract plus diagnostics. */
|
|
21
|
+
export type DeterministicKnowledgeIndexType = KnowledgeIndex & {
|
|
22
|
+
denseCandidates(q: string, n: number): Promise<string[]>;
|
|
23
|
+
storage(): KnowledgeIndexStorage;
|
|
24
|
+
};
|
|
25
|
+
export declare function createKnowledgeIndex(opts?: {
|
|
26
|
+
embedder?: EmbedderPort;
|
|
27
|
+
params?: Partial<IndexParams>;
|
|
28
|
+
}): DeterministicKnowledgeIndexType;
|
|
29
|
+
/**
|
|
30
|
+
* Loads a serialized index. With no embedder, or one of another fingerprint, the
|
|
31
|
+
* dense tier is absent until `compact()` re-embeds every card under the new one.
|
|
32
|
+
*/
|
|
33
|
+
export declare function loadKnowledgeIndex(bytes: Uint8Array, embedder?: EmbedderPort): DeterministicKnowledgeIndexType;
|
|
34
|
+
export type { EmbedderPort, GraphNeighbours, IndexDoc, IndexHit, IndexParams, IndexTier, KnowledgeIndex, SimilarPair } from './types.js';
|
|
35
|
+
export { DEFAULT_INDEX_PARAMS } from './state.js';
|
|
36
|
+
export { codeTokenize } from './tokenize.js';
|
|
37
|
+
export { hashDocText } from './digest.js';
|
|
38
|
+
export { sha256, sha256Hex, Sha256 } from './sha256.js';
|
|
39
|
+
export { EXPAND_HOP_DECAY } from './expand.js';
|
|
40
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/retrieval/knowledge-index/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAuC,WAAW,EAAa,cAAc,EAAe,MAAM,YAAY,CAAC;AAoHzI,MAAM,WAAW,qBAAqB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,YAAY,EAAE,MAAM,CAAC;CACxB;AAED,8DAA8D;AAC9D,MAAM,MAAM,+BAA+B,GAAG,cAAc,GAAG;IAC3D,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACzD,OAAO,IAAI,qBAAqB,CAAC;CACpC,CAAC;AAEF,wBAAgB,oBAAoB,CAChC,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,YAAY,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAA;CAAO,GACtE,+BAA+B,CAEjC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,YAAY,GAAG,+BAA+B,CAE9G;AAED,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzI,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The knowledge index — a deterministic, LEANN-style index over knowledge-graph
|
|
3
|
+
* cards (design: Builderforce.ai/docs/design/deterministic-knowledge-index.md).
|
|
4
|
+
*
|
|
5
|
+
* Exact → lexical → dense cascade; int8 codes with integer traversal; a
|
|
6
|
+
* high-degree-preserving pruned graph stored as CSR; float vectors recomputed
|
|
7
|
+
* only for the candidates being reranked. Every result is a pure function of
|
|
8
|
+
* `(digest(), query, opts)`.
|
|
9
|
+
*
|
|
10
|
+
* Runs in a Worker, the browser and Node: no Node-only API anywhere.
|
|
11
|
+
*/
|
|
12
|
+
import { availableTiers, canonicalKeys, createState, denseReady, graphNode, indexKeys } from './state.js';
|
|
13
|
+
import { EmbeddingCache } from './embeddings.js';
|
|
14
|
+
import { cascadeSearch, denseCandidates } from './cascade.js';
|
|
15
|
+
import { compactState } from './compact.js';
|
|
16
|
+
import { expandHits } from './expand.js';
|
|
17
|
+
import { similarPairs } from './pairs.js';
|
|
18
|
+
import { hashDocText, stateDigest } from './digest.js';
|
|
19
|
+
import { deserializeState, serializeState } from './serialize.js';
|
|
20
|
+
class DeterministicKnowledgeIndex {
|
|
21
|
+
_state;
|
|
22
|
+
_embedder;
|
|
23
|
+
_cache;
|
|
24
|
+
_digest = null;
|
|
25
|
+
constructor(_state, _embedder) {
|
|
26
|
+
this._state = _state;
|
|
27
|
+
this._embedder = _embedder;
|
|
28
|
+
this._cache = _embedder ? new EmbeddingCache(_embedder) : undefined;
|
|
29
|
+
}
|
|
30
|
+
get _ctx() {
|
|
31
|
+
return { state: this._state, embedder: this._embedder, cache: this._cache };
|
|
32
|
+
}
|
|
33
|
+
async upsert(docs) {
|
|
34
|
+
const s = this._state;
|
|
35
|
+
const changed = [];
|
|
36
|
+
for (const d of docs) {
|
|
37
|
+
const entry = { id: d.id, text: d.text, keys: canonicalKeys(d.keys), hash: d.hash ?? hashDocText(d.text) };
|
|
38
|
+
const prev = s.docs.get(d.id);
|
|
39
|
+
if (prev)
|
|
40
|
+
indexKeys(s, prev, false);
|
|
41
|
+
if (prev && prev.hash === entry.hash) {
|
|
42
|
+
prev.keys = entry.keys;
|
|
43
|
+
indexKeys(s, prev, true);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
s.docs.set(entry.id, entry);
|
|
47
|
+
indexKeys(s, entry, true);
|
|
48
|
+
s.lexical.set(entry.id, entry.text);
|
|
49
|
+
changed.push(entry);
|
|
50
|
+
}
|
|
51
|
+
this._digest = null;
|
|
52
|
+
if (!denseReady(s, this._embedder) || !this._cache)
|
|
53
|
+
return;
|
|
54
|
+
// Only the cards that are live and not already coded in the graph need a vector.
|
|
55
|
+
const toEmbed = changed.filter((e) => s.docs.get(e.id) === e && graphNode(s, e.id) < 0);
|
|
56
|
+
const vecs = await this._cache.vectors(toEmbed);
|
|
57
|
+
toEmbed.forEach((e, i) => { e.vec = vecs[i]; });
|
|
58
|
+
}
|
|
59
|
+
remove(ids) {
|
|
60
|
+
const s = this._state;
|
|
61
|
+
for (const id of ids) {
|
|
62
|
+
const doc = s.docs.get(id);
|
|
63
|
+
if (!doc)
|
|
64
|
+
continue;
|
|
65
|
+
indexKeys(s, doc, false);
|
|
66
|
+
s.lexical.delete(id);
|
|
67
|
+
s.docs.delete(id);
|
|
68
|
+
}
|
|
69
|
+
this._digest = null;
|
|
70
|
+
}
|
|
71
|
+
search(q, opts) {
|
|
72
|
+
return cascadeSearch(this._ctx, q, opts);
|
|
73
|
+
}
|
|
74
|
+
expand(hits, graph, opts) {
|
|
75
|
+
return expandHits(hits, graph, opts);
|
|
76
|
+
}
|
|
77
|
+
similarPairs(opts) {
|
|
78
|
+
return similarPairs(this._state, opts);
|
|
79
|
+
}
|
|
80
|
+
async compact() {
|
|
81
|
+
await compactState(this._state, this._embedder, this._cache);
|
|
82
|
+
this._digest = null;
|
|
83
|
+
}
|
|
84
|
+
digest() {
|
|
85
|
+
return (this._digest ??= stateDigest(this._state));
|
|
86
|
+
}
|
|
87
|
+
tiers() {
|
|
88
|
+
return availableTiers(this._state, this._embedder);
|
|
89
|
+
}
|
|
90
|
+
size() {
|
|
91
|
+
return this._state.docs.size;
|
|
92
|
+
}
|
|
93
|
+
serialize() {
|
|
94
|
+
return serializeState(this._state);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Diagnostics: the dense candidate ids for `q` before the float rerank (the
|
|
98
|
+
* integer graph walk plus not-yet-compacted cards). Empty without the dense tier.
|
|
99
|
+
*/
|
|
100
|
+
async denseCandidates(q, n) {
|
|
101
|
+
if (!denseReady(this._state, this._embedder) || !this._cache)
|
|
102
|
+
return [];
|
|
103
|
+
return denseCandidates(this._ctx, await this._cache.query(q), n);
|
|
104
|
+
}
|
|
105
|
+
/** Diagnostics: stored bytes of the int8 codes and the CSR graph, against float32. */
|
|
106
|
+
storage() {
|
|
107
|
+
const c = this._state.compacted;
|
|
108
|
+
if (!c)
|
|
109
|
+
return { nodes: 0, codeBytes: 0, graphBytes: 0, float32Bytes: 0 };
|
|
110
|
+
let codeBytes = 0;
|
|
111
|
+
for (const code of c.codes)
|
|
112
|
+
codeBytes += code?.byteLength ?? 0;
|
|
113
|
+
let graphBytes = 0;
|
|
114
|
+
for (const l of c.graph.layers)
|
|
115
|
+
graphBytes += (l.nodes?.byteLength ?? 0) + l.offsets.byteLength + l.neighbours.byteLength;
|
|
116
|
+
return { nodes: c.ids.length, codeBytes, graphBytes, float32Bytes: c.ids.length * this._state.dims * 4 };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
export function createKnowledgeIndex(opts = {}) {
|
|
120
|
+
return new DeterministicKnowledgeIndex(createState(opts.params, opts.embedder), opts.embedder);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Loads a serialized index. With no embedder, or one of another fingerprint, the
|
|
124
|
+
* dense tier is absent until `compact()` re-embeds every card under the new one.
|
|
125
|
+
*/
|
|
126
|
+
export function loadKnowledgeIndex(bytes, embedder) {
|
|
127
|
+
return new DeterministicKnowledgeIndex(deserializeState(bytes), embedder);
|
|
128
|
+
}
|
|
129
|
+
export { DEFAULT_INDEX_PARAMS } from './state.js';
|
|
130
|
+
export { codeTokenize } from './tokenize.js';
|
|
131
|
+
export { hashDocText } from './digest.js';
|
|
132
|
+
export { sha256, sha256Hex, Sha256 } from './sha256.js';
|
|
133
|
+
export { EXPAND_HOP_DECAY } from './expand.js';
|
|
134
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/retrieval/knowledge-index/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAkC,MAAM,YAAY,CAAC;AAC1I,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,eAAe,EAAsB,MAAM,cAAc,CAAC;AAClF,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAElE,MAAM,2BAA2B;IAKR;IACA;IALJ,MAAM,CAA6B;IAC5C,OAAO,GAAkB,IAAI,CAAC;IAEtC,YACqB,MAAkB,EAClB,SAAmC;QADnC,WAAM,GAAN,MAAM,CAAY;QAClB,cAAS,GAAT,SAAS,CAA0B;QAEpD,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACxE,CAAC;IAED,IAAY,IAAI;QACZ,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;IAChF,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAgB;QACzB,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;QACtB,MAAM,OAAO,GAAe,EAAE,CAAC;QAC/B,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACnB,MAAM,KAAK,GAAa,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YACrH,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC9B,IAAI,IAAI;gBAAE,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YACpC,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,EAAE,CAAC;gBACnC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;gBACvB,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;gBACzB,SAAS;YACb,CAAC;YACD,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAC5B,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;YAC1B,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACpC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO;QAC3D,iFAAiF;QACjF,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QACxF,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAChD,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,CAAC,GAAa;QAChB,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;QACtB,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;YACnB,MAAM,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC3B,IAAI,CAAC,GAAG;gBAAE,SAAS;YACnB,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;YACzB,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACrB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACtB,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACxB,CAAC;IAED,MAAM,CAAC,CAAS,EAAE,IAA0C;QACxD,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;IAC7C,CAAC;IAED,MAAM,CAAC,IAAgB,EAAE,KAAsB,EAAE,IAA6C;QAC1F,OAAO,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IACzC,CAAC;IAED,YAAY,CAAC,IAAoE;QAC7E,OAAO,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,OAAO;QACT,MAAM,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7D,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACxB,CAAC;IAED,MAAM;QACF,OAAO,CAAC,IAAI,CAAC,OAAO,KAAK,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IACvD,CAAC;IAED,KAAK;QACD,OAAO,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IACvD,CAAC;IAED,IAAI;QACA,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;IACjC,CAAC;IAED,SAAS;QACL,OAAO,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,eAAe,CAAC,CAAS,EAAE,CAAS;QACtC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,CAAC;QACxE,OAAO,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACrE,CAAC;IAED,sFAAsF;IACtF,OAAO;QACH,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC;QAChC,IAAI,CAAC,CAAC;YAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC;QAC1E,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,KAAK;YAAE,SAAS,IAAI,IAAI,EAAE,UAAU,IAAI,CAAC,CAAC;QAC/D,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM;YAAE,UAAU,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,UAAU,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC;QAC1H,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;IAC7G,CAAC;CACJ;AAgBD,MAAM,UAAU,oBAAoB,CAChC,OAAmE,EAAE;IAErE,OAAO,IAAI,2BAA2B,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;AACnG,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAiB,EAAE,QAAuB;IACzE,OAAO,IAAI,2BAA2B,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAC;AAC9E,CAAC;AAGD,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lexical.ts — the knowledge index's BM25 tier, as an incremental inverted index.
|
|
3
|
+
*
|
|
4
|
+
* `bm25Search` rebuilds its term table per call, which is right for a bounded
|
|
5
|
+
* candidate set and wrong for 50k cards queried on every prompt. This keeps the
|
|
6
|
+
* postings across upserts and scores with the SAME Okapi core (`bm25Idf`,
|
|
7
|
+
* `bm25LengthNorm`, `bm25TermScore`) — the formula is not restated here.
|
|
8
|
+
*/
|
|
9
|
+
export interface LexicalHit {
|
|
10
|
+
id: string;
|
|
11
|
+
score: number;
|
|
12
|
+
}
|
|
13
|
+
export declare class LexicalIndex {
|
|
14
|
+
/** term → (doc id → term frequency). */
|
|
15
|
+
private readonly _postings;
|
|
16
|
+
/** doc id → its distinct terms and token count. */
|
|
17
|
+
private readonly _docs;
|
|
18
|
+
private _totalLen;
|
|
19
|
+
get size(): number;
|
|
20
|
+
/** Indexes (or re-indexes) one document. */
|
|
21
|
+
set(id: string, text: string): void;
|
|
22
|
+
delete(id: string): void;
|
|
23
|
+
/** BM25 hits for `query`, best first ({@link compareHits}), at most `limit`. */
|
|
24
|
+
search(query: string, limit: number): LexicalHit[];
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=lexical.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lexical.d.ts","sourceRoot":"","sources":["../../../src/retrieval/knowledge-index/lexical.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,MAAM,WAAW,UAAU;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,YAAY;IACrB,wCAAwC;IACxC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0C;IACpE,mDAAmD;IACnD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuD;IAC7E,OAAO,CAAC,SAAS,CAAK;IAEtB,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,4CAA4C;IAC5C,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAcnC,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAYxB,gFAAgF;IAChF,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE;CAoBrD"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lexical.ts — the knowledge index's BM25 tier, as an incremental inverted index.
|
|
3
|
+
*
|
|
4
|
+
* `bm25Search` rebuilds its term table per call, which is right for a bounded
|
|
5
|
+
* candidate set and wrong for 50k cards queried on every prompt. This keeps the
|
|
6
|
+
* postings across upserts and scores with the SAME Okapi core (`bm25Idf`,
|
|
7
|
+
* `bm25LengthNorm`, `bm25TermScore`) — the formula is not restated here.
|
|
8
|
+
*/
|
|
9
|
+
import { bm25Idf, bm25LengthNorm, bm25TermScore } from '../bm25.js';
|
|
10
|
+
import { compareHits } from '../order.js';
|
|
11
|
+
import { codeTokenize } from './tokenize.js';
|
|
12
|
+
export class LexicalIndex {
|
|
13
|
+
/** term → (doc id → term frequency). */
|
|
14
|
+
_postings = new Map();
|
|
15
|
+
/** doc id → its distinct terms and token count. */
|
|
16
|
+
_docs = new Map();
|
|
17
|
+
_totalLen = 0;
|
|
18
|
+
get size() {
|
|
19
|
+
return this._docs.size;
|
|
20
|
+
}
|
|
21
|
+
/** Indexes (or re-indexes) one document. */
|
|
22
|
+
set(id, text) {
|
|
23
|
+
this.delete(id);
|
|
24
|
+
const tokens = codeTokenize(text);
|
|
25
|
+
const tf = new Map();
|
|
26
|
+
for (const t of tokens)
|
|
27
|
+
tf.set(t, (tf.get(t) ?? 0) + 1);
|
|
28
|
+
for (const [term, f] of tf) {
|
|
29
|
+
let posting = this._postings.get(term);
|
|
30
|
+
if (!posting)
|
|
31
|
+
this._postings.set(term, (posting = new Map()));
|
|
32
|
+
posting.set(id, f);
|
|
33
|
+
}
|
|
34
|
+
this._docs.set(id, { terms: [...tf.keys()], len: tokens.length });
|
|
35
|
+
this._totalLen += tokens.length;
|
|
36
|
+
}
|
|
37
|
+
delete(id) {
|
|
38
|
+
const doc = this._docs.get(id);
|
|
39
|
+
if (!doc)
|
|
40
|
+
return;
|
|
41
|
+
for (const term of doc.terms) {
|
|
42
|
+
const posting = this._postings.get(term);
|
|
43
|
+
posting?.delete(id);
|
|
44
|
+
if (posting && posting.size === 0)
|
|
45
|
+
this._postings.delete(term);
|
|
46
|
+
}
|
|
47
|
+
this._totalLen -= doc.len;
|
|
48
|
+
this._docs.delete(id);
|
|
49
|
+
}
|
|
50
|
+
/** BM25 hits for `query`, best first ({@link compareHits}), at most `limit`. */
|
|
51
|
+
search(query, limit) {
|
|
52
|
+
const n = this._docs.size;
|
|
53
|
+
if (n === 0 || limit <= 0)
|
|
54
|
+
return [];
|
|
55
|
+
const terms = [...new Set(codeTokenize(query))].sort();
|
|
56
|
+
const avgdl = this._totalLen / n || 1;
|
|
57
|
+
const scores = new Map();
|
|
58
|
+
// Terms in sorted order, so each doc's sum is accumulated in the same order everywhere.
|
|
59
|
+
for (const term of terms) {
|
|
60
|
+
const posting = this._postings.get(term);
|
|
61
|
+
if (!posting)
|
|
62
|
+
continue;
|
|
63
|
+
const idf = bm25Idf(n, posting.size);
|
|
64
|
+
for (const [id, f] of posting) {
|
|
65
|
+
const norm = bm25LengthNorm(this._docs.get(id).len, avgdl);
|
|
66
|
+
scores.set(id, (scores.get(id) ?? 0) + bm25TermScore(f, idf, norm));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const hits = [];
|
|
70
|
+
for (const [id, score] of scores)
|
|
71
|
+
if (score > 0)
|
|
72
|
+
hits.push({ id, score });
|
|
73
|
+
return hits.sort(compareHits).slice(0, limit);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=lexical.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lexical.js","sourceRoot":"","sources":["../../../src/retrieval/knowledge-index/lexical.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pairs.ts — near-duplicate pairs over the int8 codes (the Duplication lens,
|
|
3
|
+
* review-time entity resolution, contradiction candidates).
|
|
4
|
+
*
|
|
5
|
+
* Near-duplicates are each other's nearest neighbours, so the candidate pairs are
|
|
6
|
+
* the compacted graph's edges on every layer rather than all n² pairs. Similarity
|
|
7
|
+
* is {@link cosineInt8} (exact integers, correctly-rounded sqrt/division). The
|
|
8
|
+
* order is total: similarity (quantized 1e-4) descending, then `a`, then `b`, and
|
|
9
|
+
* `a < b` by id in every pair.
|
|
10
|
+
*
|
|
11
|
+
* Cards not yet compacted, and lean-mode nodes whose codes were dropped, are not
|
|
12
|
+
* paired until the next compaction (the call is synchronous; it never embeds).
|
|
13
|
+
*/
|
|
14
|
+
import type { SimilarPair } from './types.js';
|
|
15
|
+
import { type IndexState } from './state.js';
|
|
16
|
+
export interface SimilarPairsOptions {
|
|
17
|
+
minSimilarity: number;
|
|
18
|
+
maxPairs: number;
|
|
19
|
+
idPrefix?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function similarPairs(state: IndexState, opts: SimilarPairsOptions): SimilarPair[];
|
|
22
|
+
//# sourceMappingURL=pairs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pairs.d.ts","sourceRoot":"","sources":["../../../src/retrieval/knowledge-index/pairs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAa,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAIxD,MAAM,WAAW,mBAAmB;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,mBAAmB,GAAG,WAAW,EAAE,CA8BxF"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pairs.ts — near-duplicate pairs over the int8 codes (the Duplication lens,
|
|
3
|
+
* review-time entity resolution, contradiction candidates).
|
|
4
|
+
*
|
|
5
|
+
* Near-duplicates are each other's nearest neighbours, so the candidate pairs are
|
|
6
|
+
* the compacted graph's edges on every layer rather than all n² pairs. Similarity
|
|
7
|
+
* is {@link cosineInt8} (exact integers, correctly-rounded sqrt/division). The
|
|
8
|
+
* order is total: similarity (quantized 1e-4) descending, then `a`, then `b`, and
|
|
9
|
+
* `a < b` by id in every pair.
|
|
10
|
+
*
|
|
11
|
+
* Cards not yet compacted, and lean-mode nodes whose codes were dropped, are not
|
|
12
|
+
* paired until the next compaction (the call is synchronous; it never embeds).
|
|
13
|
+
*/
|
|
14
|
+
import { compareIds, quantizeScore, DENSE_SCORE_QUANTUM } from '../order.js';
|
|
15
|
+
import { graphNode } from './state.js';
|
|
16
|
+
import { neighboursOf } from './csr.js';
|
|
17
|
+
import { cosineInt8 } from './quantize.js';
|
|
18
|
+
export function similarPairs(state, opts) {
|
|
19
|
+
const c = state.compacted;
|
|
20
|
+
if (!c || opts.maxPairs <= 0)
|
|
21
|
+
return [];
|
|
22
|
+
const prefix = opts.idPrefix ?? '';
|
|
23
|
+
const usable = (node) => !!c.codes[node] && c.ids[node].startsWith(prefix) && graphNode(state, c.ids[node]) === node;
|
|
24
|
+
const seen = new Set();
|
|
25
|
+
const pairs = [];
|
|
26
|
+
for (let a = 0; a < c.ids.length; a++) {
|
|
27
|
+
if (!usable(a))
|
|
28
|
+
continue;
|
|
29
|
+
for (const layer of c.graph.layers) {
|
|
30
|
+
for (const b of neighboursOf(layer, a)) {
|
|
31
|
+
if (b === a || !usable(b))
|
|
32
|
+
continue;
|
|
33
|
+
const lo = Math.min(a, b);
|
|
34
|
+
const hi = Math.max(a, b);
|
|
35
|
+
const key = `${lo}:${hi}`;
|
|
36
|
+
if (seen.has(key))
|
|
37
|
+
continue;
|
|
38
|
+
seen.add(key);
|
|
39
|
+
const similarity = cosineInt8(c.codes[lo], c.codes[hi]);
|
|
40
|
+
if (similarity >= opts.minSimilarity) {
|
|
41
|
+
pairs.push({ a: c.ids[lo], b: c.ids[hi], similarity, q: quantizeScore(similarity, DENSE_SCORE_QUANTUM) });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return pairs
|
|
47
|
+
.sort((x, y) => (y.q - x.q) || compareIds(x.a, y.a) || compareIds(x.b, y.b))
|
|
48
|
+
.slice(0, opts.maxPairs)
|
|
49
|
+
.map(({ a, b, similarity }) => ({ a, b, similarity }));
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=pairs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pairs.js","sourceRoot":"","sources":["../../../src/retrieval/knowledge-index/pairs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* prune.ts — high-degree-preserving pruning of the base layer (the LEANN storage
|
|
3
|
+
* technique).
|
|
4
|
+
*
|
|
5
|
+
* Most of a graph index's bytes are base-layer edges. Searches route through the
|
|
6
|
+
* few well-connected hubs, so those keep their full degree and every other node
|
|
7
|
+
* keeps half: the top `hubShare` of nodes by in-degree keep `m` edges, the rest
|
|
8
|
+
* `m / 2`. Upper layers are tiny and stay unpruned.
|
|
9
|
+
*
|
|
10
|
+
* Every choice is a total order (in-degree, then node index; similarity, then
|
|
11
|
+
* node index — and node index is id order), so pruning is deterministic.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Prunes base-layer rows. `similarity(a, b)` scores two nodes (higher = nearer).
|
|
15
|
+
* Each kept row is ordered nearest first.
|
|
16
|
+
*/
|
|
17
|
+
export declare function pruneBaseLayer(rows: ReadonlyArray<readonly number[]>, m: number, hubShare: number, similarity: (a: number, b: number) => number): {
|
|
18
|
+
rows: number[][];
|
|
19
|
+
hubs: Uint8Array;
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=prune.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prune.d.ts","sourceRoot":"","sources":["../../../src/retrieval/knowledge-index/prune.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH;;;GAGG;AACH,wBAAgB,cAAc,CAC1B,IAAI,EAAE,aAAa,CAAC,SAAS,MAAM,EAAE,CAAC,EACtC,CAAC,EAAE,MAAM,EACT,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,MAAM,GAC7C;IAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,CAuBxC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* prune.ts — high-degree-preserving pruning of the base layer (the LEANN storage
|
|
3
|
+
* technique).
|
|
4
|
+
*
|
|
5
|
+
* Most of a graph index's bytes are base-layer edges. Searches route through the
|
|
6
|
+
* few well-connected hubs, so those keep their full degree and every other node
|
|
7
|
+
* keeps half: the top `hubShare` of nodes by in-degree keep `m` edges, the rest
|
|
8
|
+
* `m / 2`. Upper layers are tiny and stay unpruned.
|
|
9
|
+
*
|
|
10
|
+
* Every choice is a total order (in-degree, then node index; similarity, then
|
|
11
|
+
* node index — and node index is id order), so pruning is deterministic.
|
|
12
|
+
*/
|
|
13
|
+
import { compareScoreThenId, DENSE_SCORE_QUANTUM } from '../order.js';
|
|
14
|
+
/**
|
|
15
|
+
* Prunes base-layer rows. `similarity(a, b)` scores two nodes (higher = nearer).
|
|
16
|
+
* Each kept row is ordered nearest first.
|
|
17
|
+
*/
|
|
18
|
+
export function pruneBaseLayer(rows, m, hubShare, similarity) {
|
|
19
|
+
const n = rows.length;
|
|
20
|
+
const inDegree = new Uint32Array(n);
|
|
21
|
+
for (const row of rows)
|
|
22
|
+
for (const to of row)
|
|
23
|
+
inDegree[to] += 1;
|
|
24
|
+
const hubs = new Uint8Array(n);
|
|
25
|
+
const hubCount = n === 0 ? 0 : Math.min(n, Math.max(1, Math.ceil(n * Math.max(0, hubShare))));
|
|
26
|
+
const byDegree = Array.from({ length: n }, (_, i) => i)
|
|
27
|
+
.sort((a, b) => inDegree[b] - inDegree[a] || a - b);
|
|
28
|
+
for (let i = 0; i < hubCount; i++)
|
|
29
|
+
hubs[byDegree[i]] = 1;
|
|
30
|
+
const full = Math.max(1, m);
|
|
31
|
+
const half = Math.max(1, Math.floor(m / 2));
|
|
32
|
+
const pruned = rows.map((row, node) => {
|
|
33
|
+
const keep = hubs[node] ? full : half;
|
|
34
|
+
return [...new Set(row)]
|
|
35
|
+
.filter((to) => to !== node)
|
|
36
|
+
.map((to) => ({ to, score: similarity(node, to) }))
|
|
37
|
+
.sort((a, b) => compareScoreThenId(a.score, a.to, b.score, b.to, DENSE_SCORE_QUANTUM))
|
|
38
|
+
.slice(0, keep)
|
|
39
|
+
.map((e) => e.to);
|
|
40
|
+
});
|
|
41
|
+
return { rows: pruned, hubs };
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=prune.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prune.js","sourceRoot":"","sources":["../../../src/retrieval/knowledge-index/prune.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEtE;;;GAGG;AACH,MAAM,UAAU,cAAc,CAC1B,IAAsC,EACtC,CAAS,EACT,QAAgB,EAChB,UAA4C;IAE5C,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;IACtB,MAAM,QAAQ,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC;IACpC,KAAK,MAAM,GAAG,IAAI,IAAI;QAAE,KAAK,MAAM,EAAE,IAAI,GAAG;YAAE,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;IAEhE,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9F,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;SAClD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAE,GAAG,QAAQ,CAAC,CAAC,CAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE;QAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC,GAAG,CAAC,CAAC;IAE1D,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;QAClC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QACtC,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;aACnB,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,IAAI,CAAC;aAC3B,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;aAClD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,mBAAmB,CAAC,CAAC;aACrF,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC;aACd,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* quantize.ts — int8 codes with one symmetric per-index scale.
|
|
3
|
+
*
|
|
4
|
+
* Graph traversal compares int8 codes with integer dot products. A sum of
|
|
5
|
+
* int8×int8 products stays far inside 2^53, so it is exact in a JS number and
|
|
6
|
+
* bit-identical on every platform — the float noise between a CPU and a WebGPU
|
|
7
|
+
* embedding only matters where a component sits on a rounding boundary.
|
|
8
|
+
*
|
|
9
|
+
* The scale is fitted once (at the index's first compaction) and then fixed, so a
|
|
10
|
+
* code never changes meaning while the index lives.
|
|
11
|
+
*/
|
|
12
|
+
/** Largest code magnitude; symmetric, so -128 is never produced. */
|
|
13
|
+
export declare const CODE_MAX = 127;
|
|
14
|
+
/**
|
|
15
|
+
* A unit-norm Float32 copy of `v`. Every embedder behind the port already emits
|
|
16
|
+
* L2-normalised vectors; those (|‖v‖² − 1| ≤ 1e-3) are copied as-is, so a
|
|
17
|
+
* last-bit difference between two hosts' embeddings is not amplified by a
|
|
18
|
+
* renormalisation. Anything else is normalised; a zero vector stays zero.
|
|
19
|
+
*/
|
|
20
|
+
export declare function toUnit(v: ArrayLike<number>): Float32Array;
|
|
21
|
+
/**
|
|
22
|
+
* The symmetric scale for a set of (normalised) vectors: CODE_MAX over the largest
|
|
23
|
+
* component magnitude, rounded UP to 1/64 first so a little float noise in the
|
|
24
|
+
* maximum does not move the scale.
|
|
25
|
+
*/
|
|
26
|
+
export declare function fitScale(vectors: Iterable<ArrayLike<number>>): number;
|
|
27
|
+
/** int8 codes of `v` at `scale`, clamped to ±CODE_MAX. */
|
|
28
|
+
export declare function quantize(v: ArrayLike<number>, scale: number): Int8Array;
|
|
29
|
+
/** Exact integer dot product of two code vectors. */
|
|
30
|
+
export declare function dotInt8(a: Int8Array, b: Int8Array): number;
|
|
31
|
+
/**
|
|
32
|
+
* Cosine of two code vectors: an exact integer dot over exact integer norms, then
|
|
33
|
+
* IEEE `sqrt` and division — both correctly rounded, so the result is the same
|
|
34
|
+
* everywhere. 0 when either is a zero vector.
|
|
35
|
+
*/
|
|
36
|
+
export declare function cosineInt8(a: Int8Array, b: Int8Array): number;
|
|
37
|
+
//# sourceMappingURL=quantize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quantize.d.ts","sourceRoot":"","sources":["../../../src/retrieval/knowledge-index/quantize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,oEAAoE;AACpE,eAAO,MAAM,QAAQ,MAAM,CAAC;AAK5B;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,YAAY,CAQzD;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAUrE;AAED,0DAA0D;AAC1D,wBAAgB,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,CAOvE;AAED,qDAAqD;AACrD,wBAAgB,OAAO,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,MAAM,CAK1D;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,MAAM,CAG7D"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* quantize.ts — int8 codes with one symmetric per-index scale.
|
|
3
|
+
*
|
|
4
|
+
* Graph traversal compares int8 codes with integer dot products. A sum of
|
|
5
|
+
* int8×int8 products stays far inside 2^53, so it is exact in a JS number and
|
|
6
|
+
* bit-identical on every platform — the float noise between a CPU and a WebGPU
|
|
7
|
+
* embedding only matters where a component sits on a rounding boundary.
|
|
8
|
+
*
|
|
9
|
+
* The scale is fitted once (at the index's first compaction) and then fixed, so a
|
|
10
|
+
* code never changes meaning while the index lives.
|
|
11
|
+
*/
|
|
12
|
+
/** Largest code magnitude; symmetric, so -128 is never produced. */
|
|
13
|
+
export const CODE_MAX = 127;
|
|
14
|
+
/** How far from unit norm a vector may be and still be taken as already normalised. */
|
|
15
|
+
const UNIT_TOLERANCE = 1e-3;
|
|
16
|
+
/**
|
|
17
|
+
* A unit-norm Float32 copy of `v`. Every embedder behind the port already emits
|
|
18
|
+
* L2-normalised vectors; those (|‖v‖² − 1| ≤ 1e-3) are copied as-is, so a
|
|
19
|
+
* last-bit difference between two hosts' embeddings is not amplified by a
|
|
20
|
+
* renormalisation. Anything else is normalised; a zero vector stays zero.
|
|
21
|
+
*/
|
|
22
|
+
export function toUnit(v) {
|
|
23
|
+
let sum = 0;
|
|
24
|
+
for (let i = 0; i < v.length; i++)
|
|
25
|
+
sum += v[i] * v[i];
|
|
26
|
+
const out = Float32Array.from(v);
|
|
27
|
+
if (sum === 0 || Math.abs(sum - 1) <= UNIT_TOLERANCE)
|
|
28
|
+
return out;
|
|
29
|
+
const norm = Math.sqrt(sum);
|
|
30
|
+
for (let i = 0; i < out.length; i++)
|
|
31
|
+
out[i] = out[i] / norm;
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The symmetric scale for a set of (normalised) vectors: CODE_MAX over the largest
|
|
36
|
+
* component magnitude, rounded UP to 1/64 first so a little float noise in the
|
|
37
|
+
* maximum does not move the scale.
|
|
38
|
+
*/
|
|
39
|
+
export function fitScale(vectors) {
|
|
40
|
+
let maxAbs = 0;
|
|
41
|
+
for (const v of vectors) {
|
|
42
|
+
for (let i = 0; i < v.length; i++) {
|
|
43
|
+
const a = Math.abs(v[i]);
|
|
44
|
+
if (a > maxAbs)
|
|
45
|
+
maxAbs = a;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const bound = Math.max(1, Math.ceil(maxAbs * 64)) / 64;
|
|
49
|
+
return CODE_MAX / bound;
|
|
50
|
+
}
|
|
51
|
+
/** int8 codes of `v` at `scale`, clamped to ±CODE_MAX. */
|
|
52
|
+
export function quantize(v, scale) {
|
|
53
|
+
const out = new Int8Array(v.length);
|
|
54
|
+
for (let i = 0; i < v.length; i++) {
|
|
55
|
+
const q = Math.round(v[i] * scale);
|
|
56
|
+
out[i] = q > CODE_MAX ? CODE_MAX : q < -CODE_MAX ? -CODE_MAX : q;
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
/** Exact integer dot product of two code vectors. */
|
|
61
|
+
export function dotInt8(a, b) {
|
|
62
|
+
const n = Math.min(a.length, b.length);
|
|
63
|
+
let dot = 0;
|
|
64
|
+
for (let i = 0; i < n; i++)
|
|
65
|
+
dot += a[i] * b[i];
|
|
66
|
+
return dot;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Cosine of two code vectors: an exact integer dot over exact integer norms, then
|
|
70
|
+
* IEEE `sqrt` and division — both correctly rounded, so the result is the same
|
|
71
|
+
* everywhere. 0 when either is a zero vector.
|
|
72
|
+
*/
|
|
73
|
+
export function cosineInt8(a, b) {
|
|
74
|
+
const denom = Math.sqrt(dotInt8(a, a)) * Math.sqrt(dotInt8(b, b));
|
|
75
|
+
return denom === 0 ? 0 : dotInt8(a, b) / denom;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=quantize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quantize.js","sourceRoot":"","sources":["../../../src/retrieval/knowledge-index/quantize.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* serialize.ts — the versioned binary form of an index state.
|
|
3
|
+
*
|
|
4
|
+
* Layout (little-endian, via `bytes.ts`):
|
|
5
|
+
* magic "BFKI" · u32 version
|
|
6
|
+
* fingerprint · dims · scale · params
|
|
7
|
+
* docs (id order): id · text · hash · keys · optional pending float vector
|
|
8
|
+
* u8 compacted? → node ids · node hashes · hubs · code-present flags · codes · graph
|
|
9
|
+
*
|
|
10
|
+
* Texts travel with the index because the lexical tier, the recompute path and a
|
|
11
|
+
* re-embed under a new fingerprint all need them. Loading rebuilds the derived
|
|
12
|
+
* structures (key map, BM25 postings) and gives back the same digest.
|
|
13
|
+
*/
|
|
14
|
+
import { type IndexState } from './state.js';
|
|
15
|
+
export declare const SERIALIZE_VERSION = 1;
|
|
16
|
+
export declare function serializeState(state: IndexState): Uint8Array;
|
|
17
|
+
export declare function deserializeState(bytes: Uint8Array): IndexState;
|
|
18
|
+
//# sourceMappingURL=serialize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../../../src/retrieval/knowledge-index/serialize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,EAAyD,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAMpG,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAEnC,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CA2B5D;AAcD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CA0D9D"}
|