enigma-memory 0.1.18 → 0.1.22
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/README.md +76 -24
- package/apps/cli/bin/enigma-desktop.mjs +140 -0
- package/apps/cli/bin/enigma-terminal.mjs +78 -0
- package/apps/cli/bin/enigma.mjs +1923 -285
- package/apps/desktop/electron-main.cjs +217 -0
- package/apps/desktop/package.json +12 -0
- package/apps/desktop/src/app.js +264 -7
- package/apps/desktop/src/index.html +3514 -1373
- package/apps/desktop/src/launch-electron.mjs +51 -0
- package/apps/desktop/src/server.mjs +2914 -0
- package/apps/desktop/src/styles.css +2972 -260
- package/apps/desktop/src/zk-browser-prove.mjs +53 -0
- package/apps/desktop/src/zk-state.mjs +1789 -0
- package/apps/gateway/bin/enigma-gateway.mjs +102 -5
- package/apps/gateway/src/server.mjs +271 -8
- package/apps/ios/EnigmaCore/Package.swift +12 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/EnigmaAPIClient.swift +227 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/Models.swift +278 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/PKCE.swift +96 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/PrivacyMinimizer.swift +187 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/ToolModels.swift +129 -0
- package/apps/ios/EnigmaCore/Tests/EnigmaCoreTests/EnigmaCoreTests.swift +42 -0
- package/apps/ios/EnigmaIOS/Enigma/AppModel.swift +346 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AccentColor.colorset/Contents.json +12 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AppIcon.appiconset/Contents.json +11 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AppIcon.appiconset/EnigmaAppIcon.png +0 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/Contents.json +3 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/LaunchBackground.colorset/Contents.json +12 -0
- package/apps/ios/EnigmaIOS/Enigma/ChatView.swift +181 -0
- package/apps/ios/EnigmaIOS/Enigma/CouncilView.swift +78 -0
- package/apps/ios/EnigmaIOS/Enigma/CreateView.swift +152 -0
- package/apps/ios/EnigmaIOS/Enigma/EnigmaApp.swift +52 -0
- package/apps/ios/EnigmaIOS/Enigma/Info.plist +52 -0
- package/apps/ios/EnigmaIOS/Enigma/NaturalLanguagePrivacyTagger.swift +26 -0
- package/apps/ios/EnigmaIOS/Enigma/OAuthClient.swift +321 -0
- package/apps/ios/EnigmaIOS/Enigma/OnboardingView.swift +105 -0
- package/apps/ios/EnigmaIOS/Enigma/PrivateVaultView.swift +275 -0
- package/apps/ios/EnigmaIOS/Enigma/SecureStore.swift +76 -0
- package/apps/ios/EnigmaIOS/Enigma/SettingsView.swift +60 -0
- package/apps/ios/EnigmaIOS/Enigma/Theme.swift +80 -0
- package/apps/ios/EnigmaIOS/EnigmaIOS.xcodeproj/project.pbxproj +211 -0
- package/apps/ios/EnigmaIOS/EnigmaIOS.xcodeproj/xcshareddata/xcschemes/Enigma.xcscheme +23 -0
- package/apps/native-host/README.md +19 -8
- package/apps/native-host/bin/enigma-native-host.mjs +229 -13
- package/apps/relay/bin/enigma-relay.mjs +103 -5
- package/apps/relay/src/federation-runtime.mjs +618 -0
- package/apps/relay/src/server.mjs +310 -9
- package/apps/verifier/bin/enigma-verify.mjs +327 -11
- package/cortex-v3/circuits/build/intent_vk_bytes.json +35 -0
- package/cortex-v3/circuits/build/sale_vk_bytes.json +35 -0
- package/cortex-v3/circuits/build/vk_bytes.json +32 -0
- package/cortex-v3/proving-assets.json +64 -0
- package/cortex-v3/zk/BUILD-CONTRACT.md +87 -0
- package/cortex-v3/zk/action-transition-vk.json +119 -0
- package/cortex-v3/zk/alias-adversarial.test.mjs +220 -0
- package/cortex-v3/zk/groth16-verify-child.mjs +17 -0
- package/cortex-v3/zk/intent-witness.mjs +365 -0
- package/cortex-v3/zk/intent-witness.test.mjs +485 -0
- package/cortex-v3/zk/proving-assets.mjs +203 -0
- package/cortex-v3/zk/sale-witness.mjs +783 -0
- package/cortex-v3/zk/sale-witness.test.mjs +784 -0
- package/cortex-v3/zk/sealed-sale-release-vk.json +119 -0
- package/cortex-v3/zk/settlement-evidence.mjs +722 -0
- package/cortex-v3/zk/setup-intent.mjs +688 -0
- package/cortex-v3/zk/setup-sale.mjs +666 -0
- package/cortex-v3/zk/setup.mjs +594 -0
- package/cortex-v3/zk/witness.mjs +184 -0
- package/cortex-v3/zk/zk-codec.mjs +232 -0
- package/cortex-v3/zk/zk-codec.test.mjs +293 -0
- package/cortex-v3/zk/zk-settle.mjs +370 -0
- package/cortex-v3/zk/zk-tree.mjs +256 -0
- package/cortex-v3/zk/zk-tree.test.mjs +419 -0
- package/deploy/docker-compose.local-production-simulation.yml +36 -0
- package/docs/browser-extension-install.md +8 -6
- package/docs/client-connectors.md +15 -11
- package/docs/developer-ecosystem.md +15 -13
- package/docs/enigma-memory-ready-conformance.md +11 -9
- package/docs/install-anywhere.md +61 -28
- package/docs/installers-and-desktop.md +8 -7
- package/docs/novelty-invention-candidates.md +161 -161
- package/docs/proof-network-claim-boundaries.md +320 -318
- package/examples/01-quickstart-agent/index.mjs +49 -0
- package/examples/01_agent_memory_quickstart.mjs +57 -0
- package/examples/02-multi-agent-swarm/index.mjs +57 -0
- package/examples/02_cross_model_passport.mjs +64 -0
- package/examples/03-langchain-memory/index.mjs +41 -0
- package/examples/03_poseidon_commitment_verification.mjs +71 -0
- package/examples/04-python-trading-agent/trader.py +49 -0
- package/examples/README.md +27 -0
- package/examples/ci/github-actions.yml +7 -2
- package/package.json +142 -11
- package/packages/adapters/PACKAGE_CONTRACT.md +1 -1
- package/packages/connectors/src/index.js +196 -4
- package/packages/connectors/swarm-router.mjs +168 -0
- package/packages/core/src/index.js +248 -1
- package/packages/core/src/version.mjs +7 -0
- package/packages/dev-tools/package.json +19 -0
- package/packages/dev-tools/src/index.js +4 -0
- package/packages/dev-tools/src/memory-benchmark-suite.js +112 -0
- package/packages/dev-tools/src/swarm-simulator.js +101 -0
- package/packages/dev-tools/src/vault-inspector.js +114 -0
- package/packages/dev-tools/src/vector-benchmark.js +100 -0
- package/packages/developer-platform/src/access-credentials.js +341 -0
- package/packages/developer-platform/src/http.js +132 -0
- package/packages/developer-platform/src/index.js +4 -0
- package/packages/developer-platform/src/usage-http.js +60 -0
- package/packages/developer-platform/src/usage.js +295 -0
- package/packages/enclave-runtime/attestation.mjs +159 -0
- package/packages/enclave-runtime/index.mjs +47 -0
- package/packages/enclave-runtime/session-manager.mjs +253 -0
- package/packages/enclave-runtime/zeroization-proof.mjs +227 -0
- package/packages/enigma-reflex/package.json +14 -0
- package/packages/enigma-reflex/src/index.js +204 -0
- package/packages/enigma-reflex/training/generate-dataset.mjs +40 -0
- package/packages/enigma-reflex/training/requirements.txt +8 -0
- package/packages/enigma-reflex/training/train.py +314 -0
- package/packages/enigma-weave/LICENSE +22 -0
- package/packages/enigma-weave/UPSTREAM.json +21 -0
- package/packages/enigma-weave/package.json +14 -0
- package/packages/enigma-weave/src/index.js +286 -0
- package/packages/hosted-cloud/src/index.js +80 -5
- package/packages/importers/src/index.js +432 -0
- package/packages/inference-runtime/src/browser.js +401 -0
- package/packages/inference-runtime/src/chat.js +265 -0
- package/packages/inference-runtime/src/code.js +407 -0
- package/packages/inference-runtime/src/contracts.js +162 -0
- package/packages/inference-runtime/src/http.js +232 -0
- package/packages/inference-runtime/src/image.js +186 -0
- package/packages/inference-runtime/src/index.js +10 -0
- package/packages/inference-runtime/src/model-router.js +320 -0
- package/packages/inference-runtime/src/platform.js +125 -0
- package/packages/inference-runtime/src/privacy.js +400 -0
- package/packages/inference-runtime/src/video.js +253 -0
- package/packages/mcp-server/README.md +22 -6
- package/packages/mcp-server/bin/enigma-mcp.mjs +2 -1
- package/packages/mcp-server/src/index.js +1418 -105
- package/packages/mcp-server/src/oauth.js +561 -0
- package/packages/mcp-server/src/private-handoff.js +84 -0
- package/packages/mcp-server/src/remote-http.js +273 -0
- package/packages/mcp-server/src/remote-policy.js +72 -0
- package/packages/mcp-server/swarm-bridge.mjs +361 -0
- package/packages/mesh/index.d.ts +283 -0
- package/packages/mesh/package.json +23 -0
- package/packages/mesh/src/crypto.js +189 -0
- package/packages/mesh/src/federation-packets.js +353 -0
- package/packages/mesh/src/gossip.js +311 -0
- package/packages/mesh/src/index.js +6 -0
- package/packages/mesh/src/protocol.js +255 -0
- package/packages/mesh/src/router.js +279 -0
- package/packages/mesh/src/transport.js +306 -0
- package/packages/passport/src/index.js +426 -1
- package/packages/private-economy/src/credits-http.js +100 -0
- package/packages/private-economy/src/credits.js +447 -0
- package/packages/private-economy/src/index.js +5 -0
- package/packages/private-economy/src/payments-http.js +120 -0
- package/packages/private-economy/src/payments.js +509 -0
- package/packages/private-economy/src/x402.js +346 -0
- package/packages/proof-network/PACKAGE_CONTRACT.md +21 -0
- package/packages/rag/index.d.ts +182 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/THIRD_PARTY_LICENSES.txt +207 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/config.json +25 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/onnx/model_quantized.onnx +0 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/sha256-manifest.json +28 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer.json +30686 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer_config.json +15 -0
- package/packages/rag/package.json +27 -0
- package/packages/rag/src/blinded-search.js +109 -0
- package/packages/rag/src/bm25.js +169 -0
- package/packages/rag/src/embeddings.js +459 -0
- package/packages/rag/src/hybrid.js +76 -0
- package/packages/rag/src/index.js +38 -0
- package/packages/rag/src/reranker.js +61 -0
- package/packages/rag/src/research.js +107 -0
- package/packages/rag/src/vector-store.js +430 -0
- package/packages/rag/src/verify-model-artifacts.mjs +4 -0
- package/packages/sdk/index.d.ts +760 -0
- package/packages/sdk/package.json +33 -0
- package/packages/sdk/python/README.md +24 -0
- package/packages/sdk/python/enigma_sdk.py +250 -0
- package/packages/sdk/python/pyproject.toml +34 -0
- package/packages/sdk/python/requirements.txt +1 -0
- package/packages/sdk/python/setup.py +20 -0
- package/packages/sdk/src/federation/capability-grant.js +389 -0
- package/packages/sdk/src/federation/federation-router.js +360 -0
- package/packages/sdk/src/federation/ghostmesh-bridge.js +497 -0
- package/packages/sdk/src/federation/index.js +3 -0
- package/packages/sdk/src/index.js +1796 -0
- package/packages/sdk/src/intelligence/contradiction.js +337 -0
- package/packages/sdk/src/intelligence/decision-engine.js +155 -0
- package/packages/sdk/src/intelligence/index.js +4 -0
- package/packages/sdk/src/intelligence/ontology.js +122 -0
- package/packages/sdk/src/intelligence/temporal.js +123 -0
- package/packages/sdk/src/market-client.js +142 -0
- package/packages/sdk/src/mesh-client.js +110 -0
- package/packages/sdk/src/middleware/index.js +3 -0
- package/packages/sdk/src/middleware/langchain.js +159 -0
- package/packages/sdk/src/middleware/llamaindex.js +101 -0
- package/packages/sdk/src/middleware/vercel-ai.js +112 -0
- package/packages/sdk/src/rag-client.js +85 -0
- package/packages/sdk/src/swarm-orchestrator.js +260 -0
- package/packages/settlement/PACKAGE_CONTRACT.md +1 -1
- package/packages/snapcompact/THIRD_PARTY_LICENSES.txt +40 -0
- package/packages/snapcompact/assets/8x13-latin1.bdf +3837 -0
- package/packages/snapcompact/index.d.ts +284 -0
- package/packages/snapcompact/package.json +25 -0
- package/packages/snapcompact/src/index.js +716 -0
- package/packages/storage/PACKAGE_CONTRACT.md +1 -1
- package/packages/terminal-console/animations.mjs +240 -0
- package/packages/terminal-console/auto-anchor.mjs +220 -0
- package/packages/terminal-console/banner.mjs +91 -0
- package/packages/terminal-console/commands.mjs +459 -0
- package/packages/terminal-console/delegation.mjs +152 -0
- package/packages/terminal-console/index.mjs +5 -0
- package/packages/terminal-console/outbox.mjs +143 -0
- package/packages/terminal-console/phantom-bridge.mjs +637 -0
- package/packages/terminal-console/repl.mjs +136 -0
- package/packages/terminal-console/signer-store.mjs +130 -0
- package/packages/terminal-console/solana-rpc.mjs +214 -0
- package/packages/terminal-console/solana-transport.mjs +189 -0
- package/packages/terminal-tui/dashboard.mjs +214 -0
- package/packages/terminal-tui/index.mjs +28 -0
- package/packages/terminal-tui/merkle-tree-renderer.mjs +268 -0
- package/packages/terminal-tui/telemetry-hud.mjs +137 -0
- package/packages/vault/index.d.ts +449 -0
- package/packages/vault/package.json +27 -0
- package/packages/vault/src/e2ee.mjs +393 -0
- package/packages/vault/src/enclave.js +481 -0
- package/packages/vault/src/erasure.js +207 -0
- package/packages/vault/src/index.js +1018 -155
- package/packages/vault/src/persistence.js +307 -0
- package/packages/vault/src/poseidon.js +354 -0
- package/packages/vault/src/receipt.js +459 -0
- package/scripts/benchmark-optical-context.mjs +166 -0
- package/scripts/bootstrap-enigma.mjs +502 -0
- package/scripts/build-edge-backend-workers.mjs +20 -5
- package/scripts/build-goal-completion-audit.mjs +72 -25
- package/scripts/build-hosted-api-key-lifecycle.mjs +26 -8
- package/scripts/build-hosted-customer-lifecycle.mjs +20 -3
- package/scripts/build-hosted-probe-worker.mjs +19 -4
- package/scripts/build-installer-assets.mjs +41 -21
- package/scripts/build-operator-evidence-starter.mjs +59 -1
- package/scripts/build-production-backend-env-kit.mjs +2 -0
- package/scripts/build-production-unblocker.mjs +3 -0
- package/scripts/check.mjs +17 -3
- package/scripts/collect-hosted-backend-live-evidence.mjs +49 -12
- package/scripts/install-enigma-local.mjs +18 -5
- package/scripts/release-audit.mjs +65 -109
- package/scripts/release-provenance.mjs +6 -0
- package/scripts/run-backend-readiness-smoke.mjs +112 -10
- package/scripts/scan-secrets.mjs +1 -0
- package/scripts/simulate-production-env.mjs +7 -2
- package/scripts/validate-hosted-backend-live.mjs +112 -1
- package/specs/antibody-pack-v1.schema.json +95 -0
- package/specs/antigen-envelope-v1.schema.json +81 -0
- package/specs/boundary-manifest-v1.schema.json +35 -35
- package/specs/capsule-v1.schema.json +55 -55
- package/specs/claim-boundary-manifest-v1.schema.json +22 -22
- package/specs/claim-ledger-v1.schema.json +291 -0
- package/specs/context-passport-v1.schema.json +59 -0
- package/specs/deletion-tombstone-v1.schema.json +26 -26
- package/specs/evidence-packet-v1.schema.json +177 -0
- package/specs/hosted-backend-live-evidence-v1.schema.json +72 -3
- package/specs/immune-scan-report-v1.schema.json +112 -0
- package/specs/lifecycle-receipt-log-v1.schema.json +67 -0
- package/specs/memory-atom-v1.schema.json +59 -0
- package/specs/memory-event-v1.schema.json +42 -42
- package/specs/passport-v1.schema.json +50 -50
- package/specs/proof-of-non-use-v1.schema.json +65 -0
- package/specs/quarantine-record-v1.schema.json +126 -0
- package/specs/receipt-v1.schema.json +61 -61
- package/specs/state-checkpoint-v1.schema.json +37 -37
- package/specs/trust-bundle-v1.schema.json +56 -56
- package/specs/trust-card-v1.schema.json +119 -0
- package/docs/proof-network-launch-plan.md +0 -421
- package/packages/metering/PACKAGE_CONTRACT.md +0 -20
- package/scripts/build-ai-orchestration-plan.mjs +0 -248
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// Enigma RAG Research: Experimental Blinded Retrieval Prototype.
|
|
2
|
+
// WARNING: UNSUPPORTED RESEARCH PROTOTYPE — NOT ZERO-KNOWLEDGE HOMOMORPHIC ENCRYPTION.
|
|
3
|
+
// Orthogonal basis projections preserve dot-product ranking, but an adversarial server
|
|
4
|
+
// can observe query norms and cluster geometries. Local-first search via EncryptedVectorStore
|
|
5
|
+
// is the recommended production architecture.
|
|
6
|
+
import crypto from 'node:crypto';
|
|
7
|
+
import { EMBEDDING_DIM } from './embeddings.js';
|
|
8
|
+
|
|
9
|
+
export const RESEARCH_DISCLAIMER = Object.freeze({
|
|
10
|
+
status: 'experimental_research_prototype',
|
|
11
|
+
homomorphicEncryption: false,
|
|
12
|
+
zeroKnowledgeVerified: false,
|
|
13
|
+
recommendation: 'Use EncryptedVectorStore for local sovereign retrieval.',
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Generates an orthogonal basis matrix Q for research ranking simulations.
|
|
18
|
+
* @param {Buffer|string} seed
|
|
19
|
+
* @param {number} [dim=384]
|
|
20
|
+
* @returns {Float32Array[]}
|
|
21
|
+
*/
|
|
22
|
+
export function generateResearchOrthogonalBasis(seed, dim = EMBEDDING_DIM) {
|
|
23
|
+
const seedBuf = Buffer.isBuffer(seed) ? seed : Buffer.from(seed, 'utf8');
|
|
24
|
+
const basis = [];
|
|
25
|
+
|
|
26
|
+
for (let i = 0; i < dim; i++) {
|
|
27
|
+
const raw = Buffer.from(crypto.hkdfSync('sha256', seedBuf, Buffer.from(`enigma.research.basis.${i}`, 'utf8'), Buffer.alloc(0), dim * 4));
|
|
28
|
+
const vec = new Float32Array(dim);
|
|
29
|
+
for (let j = 0; j < dim; j++) {
|
|
30
|
+
vec[j] = raw.readInt32LE(j * 4) / 2147483648.0;
|
|
31
|
+
}
|
|
32
|
+
basis.push(vec);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Gram-Schmidt orthogonalization
|
|
36
|
+
const ortho = [];
|
|
37
|
+
for (let i = 0; i < dim; i++) {
|
|
38
|
+
const v = new Float32Array(basis[i]);
|
|
39
|
+
for (let j = 0; j < i; j++) {
|
|
40
|
+
const u = ortho[j];
|
|
41
|
+
let dot = 0;
|
|
42
|
+
for (let k = 0; k < dim; k++) dot += basis[i][k] * u[k];
|
|
43
|
+
for (let k = 0; k < dim; k++) v[k] -= dot * u[k];
|
|
44
|
+
}
|
|
45
|
+
let normSq = 0;
|
|
46
|
+
for (let k = 0; k < dim; k++) normSq += v[k] * v[k];
|
|
47
|
+
const norm = Math.sqrt(normSq);
|
|
48
|
+
if (norm > 1e-12) {
|
|
49
|
+
for (let k = 0; k < dim; k++) v[k] /= norm;
|
|
50
|
+
}
|
|
51
|
+
ortho.push(v);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return ortho;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Applies basis transform: v' = Q * v.
|
|
59
|
+
* @param {Float32Array} vector
|
|
60
|
+
* @param {Float32Array[]} basis
|
|
61
|
+
* @returns {Float32Array}
|
|
62
|
+
*/
|
|
63
|
+
export function applyResearchBasisTransform(vector, basis) {
|
|
64
|
+
const dim = vector.length;
|
|
65
|
+
const out = new Float32Array(dim);
|
|
66
|
+
for (let i = 0; i < dim; i++) {
|
|
67
|
+
let sum = 0;
|
|
68
|
+
const row = basis[i];
|
|
69
|
+
for (let j = 0; j < dim; j++) sum += row[j] * vector[j];
|
|
70
|
+
out[i] = sum;
|
|
71
|
+
}
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Transforms query with scalar blinding for prototype evaluation.
|
|
77
|
+
* @param {Float32Array} queryVector
|
|
78
|
+
* @param {Float32Array[]} basis
|
|
79
|
+
* @param {number} [alpha=2.0]
|
|
80
|
+
* @returns {{ blindedVector: Float32Array, alpha: number }}
|
|
81
|
+
*/
|
|
82
|
+
export function createResearchBlindedQuery(queryVector, basis, alpha = 2.0) {
|
|
83
|
+
const rotated = applyResearchBasisTransform(queryVector, basis);
|
|
84
|
+
const blinded = new Float32Array(rotated.length);
|
|
85
|
+
for (let i = 0; i < rotated.length; i++) {
|
|
86
|
+
blinded[i] = rotated[i] * alpha;
|
|
87
|
+
}
|
|
88
|
+
return { blindedVector: blinded, alpha };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Evaluates ranking over basis-transformed documents.
|
|
93
|
+
* @param {Float32Array} blindedQuery
|
|
94
|
+
* @param {Map<string, Float32Array>} transformedDocs
|
|
95
|
+
* @param {number} [topK=5]
|
|
96
|
+
* @returns {Array<{ id: string, score: number }>}
|
|
97
|
+
*/
|
|
98
|
+
export function evaluateResearchBlindedRanking(blindedQuery, transformedDocs, topK = 5) {
|
|
99
|
+
const scores = [];
|
|
100
|
+
for (const [id, docVec] of transformedDocs.entries()) {
|
|
101
|
+
let dot = 0;
|
|
102
|
+
for (let i = 0; i < blindedQuery.length; i++) dot += blindedQuery[i] * docVec[i];
|
|
103
|
+
scores.push({ id, score: dot });
|
|
104
|
+
}
|
|
105
|
+
scores.sort((a, b) => b.score - a.score);
|
|
106
|
+
return scores.slice(0, topK);
|
|
107
|
+
}
|
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
// Enigma Sovereign Encrypted Vector Store & Hybrid RAG Engine.
|
|
2
|
+
// Combines client-side dense vector embeddings, Okapi BM25 lexical inverted indexing,
|
|
3
|
+
// Reciprocal Rank Fusion (RRF), semantic candidate reranking, and AES-256-GCM encryption-at-rest.
|
|
4
|
+
import crypto from 'node:crypto';
|
|
5
|
+
import {
|
|
6
|
+
createEmbeddingProvider,
|
|
7
|
+
cosineSimilarity,
|
|
8
|
+
quantizeVector,
|
|
9
|
+
dequantizeVector,
|
|
10
|
+
EMBEDDING_DIM,
|
|
11
|
+
} from './embeddings.js';
|
|
12
|
+
import { BM25Index } from './bm25.js';
|
|
13
|
+
import { reciprocalRankFusion } from './hybrid.js';
|
|
14
|
+
import { semanticReranker } from './reranker.js';
|
|
15
|
+
|
|
16
|
+
const VECTOR_STORE_AAD = Buffer.from('enigma.encrypted_vectors.v1', 'utf8');
|
|
17
|
+
|
|
18
|
+
export class EncryptedVectorStore {
|
|
19
|
+
/**
|
|
20
|
+
* @param {Object} [options]
|
|
21
|
+
* @param {Object} [options.embeddingProvider]
|
|
22
|
+
* @param {number} [options.dimension=384]
|
|
23
|
+
* @param {boolean} [options.quantize=true]
|
|
24
|
+
*/
|
|
25
|
+
constructor(options = {}) {
|
|
26
|
+
this.dimension = options.dimension || EMBEDDING_DIM;
|
|
27
|
+
this.quantize = options.quantize !== false;
|
|
28
|
+
this.embedder = options.embeddingProvider || createEmbeddingProvider({ dimension: this.dimension });
|
|
29
|
+
/** @type {Map<string, Object>} */
|
|
30
|
+
this.documents = new Map();
|
|
31
|
+
/** @type {Map<string, Int8Array|Float32Array>} */
|
|
32
|
+
this.vectors = new Map();
|
|
33
|
+
/** @type {BM25Index} */
|
|
34
|
+
this.bm25 = new BM25Index();
|
|
35
|
+
/** @type {number} */
|
|
36
|
+
this.epoch = 0;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Asynchronously indexes a memory document into both dense vector store and BM25 index.
|
|
40
|
+
* @param {string} id
|
|
41
|
+
* @param {string} text
|
|
42
|
+
* @param {Object} [metadata={}]
|
|
43
|
+
* @returns {Promise<Object>}
|
|
44
|
+
*/
|
|
45
|
+
async add(id, text, metadata = {}, options = {}) {
|
|
46
|
+
if (!id || typeof id !== 'string') throw new Error('Document ID must be a non-empty string');
|
|
47
|
+
if (!text || typeof text !== 'string') throw new Error('Document text must be a non-empty string');
|
|
48
|
+
|
|
49
|
+
const opEpoch = typeof options.epoch === 'number' ? options.epoch : this.epoch;
|
|
50
|
+
if (options.signal?.aborted) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const floatVec = await this.embedder.embed(text);
|
|
55
|
+
|
|
56
|
+
// Abort guard: If store was cleared or reset while embedding was in flight, do not mutate state
|
|
57
|
+
if (this.epoch !== opEpoch || options.signal?.aborted) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const storedVec = this.quantize ? quantizeVector(floatVec) : floatVec;
|
|
62
|
+
const scope = metadata.scope || 'enigma.global';
|
|
63
|
+
|
|
64
|
+
const doc = {
|
|
65
|
+
id,
|
|
66
|
+
text,
|
|
67
|
+
scope,
|
|
68
|
+
importance: typeof metadata.importance === 'number' ? metadata.importance : 1.0,
|
|
69
|
+
createdAt: metadata.createdAt ?? Date.now(),
|
|
70
|
+
metadata: { ...metadata },
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
this.documents.set(id, doc);
|
|
74
|
+
this.vectors.set(id, storedVec);
|
|
75
|
+
this.bm25.add(id, text, scope);
|
|
76
|
+
|
|
77
|
+
return { id, scope: doc.scope, dimension: this.dimension, quantized: this.quantize };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Synchronous add when using local synchronous embedder.
|
|
82
|
+
* @param {string} id
|
|
83
|
+
* @param {string} text
|
|
84
|
+
* @param {Object} [metadata={}]
|
|
85
|
+
* @returns {Object}
|
|
86
|
+
*/
|
|
87
|
+
addSync(id, text, metadata = {}) {
|
|
88
|
+
if (!id || typeof id !== 'string') throw new Error('Document ID must be a non-empty string');
|
|
89
|
+
if (!text || typeof text !== 'string') throw new Error('Document text must be a non-empty string');
|
|
90
|
+
|
|
91
|
+
const floatVec = this.embedder.embedSync(text);
|
|
92
|
+
const storedVec = this.quantize ? quantizeVector(floatVec) : floatVec;
|
|
93
|
+
const scope = metadata.scope || 'enigma.global';
|
|
94
|
+
|
|
95
|
+
const doc = {
|
|
96
|
+
id,
|
|
97
|
+
text,
|
|
98
|
+
scope,
|
|
99
|
+
importance: typeof metadata.importance === 'number' ? metadata.importance : 1.0,
|
|
100
|
+
createdAt: metadata.createdAt ?? Date.now(),
|
|
101
|
+
metadata: { ...metadata },
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
this.documents.set(id, doc);
|
|
105
|
+
this.vectors.set(id, storedVec);
|
|
106
|
+
this.bm25.add(id, text, scope);
|
|
107
|
+
|
|
108
|
+
return { id, scope: doc.scope, dimension: this.dimension, quantized: this.quantize };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Batch insert memory atoms asynchronously.
|
|
113
|
+
* @param {Array<{ id: string, text: string, metadata?: Object }>} items
|
|
114
|
+
* @returns {Promise<number>}
|
|
115
|
+
*/
|
|
116
|
+
async addBatch(items) {
|
|
117
|
+
if (!Array.isArray(items)) throw new TypeError('items must be an array');
|
|
118
|
+
let count = 0;
|
|
119
|
+
for (const item of items) {
|
|
120
|
+
await this.add(item.id, item.text, item.metadata || {});
|
|
121
|
+
count++;
|
|
122
|
+
}
|
|
123
|
+
return count;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Removes a document by ID from dense and BM25 indices.
|
|
128
|
+
* @param {string} id
|
|
129
|
+
* @returns {boolean}
|
|
130
|
+
*/
|
|
131
|
+
remove(id) {
|
|
132
|
+
this.vectors.delete(id);
|
|
133
|
+
this.bm25.remove(id);
|
|
134
|
+
return this.documents.delete(id);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
delete(id) {
|
|
138
|
+
return this.remove(id);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Updates retrieval metadata without re-embedding non-prose cryptographic payloads.
|
|
143
|
+
* @param {string} id
|
|
144
|
+
* @param {Object} metadata
|
|
145
|
+
* @returns {boolean}
|
|
146
|
+
*/
|
|
147
|
+
updateMetadata(id, metadata) {
|
|
148
|
+
const doc = this.documents.get(id);
|
|
149
|
+
if (!doc) return false;
|
|
150
|
+
doc.metadata = { ...metadata };
|
|
151
|
+
if (typeof metadata.importance === 'number') doc.importance = metadata.importance;
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Resets and zeroes out in-memory vector buffers, documents, and lexical BM25 index maps.
|
|
157
|
+
*/
|
|
158
|
+
clear() {
|
|
159
|
+
this.epoch++;
|
|
160
|
+
for (const vec of this.vectors.values()) {
|
|
161
|
+
if (ArrayBuffer.isView(vec) && typeof vec.fill === 'function') {
|
|
162
|
+
vec.fill(0);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
this.vectors.clear();
|
|
166
|
+
this.documents.clear();
|
|
167
|
+
this.bm25.clear();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
*/
|
|
172
|
+
get size() {
|
|
173
|
+
return this.documents.size;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Hybrid search combining dense semantic vectors, BM25 keyword matching, and candidate reranking.
|
|
178
|
+
* @param {string|Float32Array} query
|
|
179
|
+
* @param {Object} [options]
|
|
180
|
+
* @param {'hybrid'|'dense'|'bm25'} [options.mode='hybrid']
|
|
181
|
+
* @param {number} [options.topK=5]
|
|
182
|
+
* @param {number} [options.threshold=-1.0]
|
|
183
|
+
* @param {string} [options.scope]
|
|
184
|
+
* @param {number} [options.denseWeight=1.0]
|
|
185
|
+
* @param {number} [options.bm25Weight=1.0]
|
|
186
|
+
* @returns {Promise<Array<{ id: string, text: string, score: number, scope: string, metadata: Object }>>}
|
|
187
|
+
*/
|
|
188
|
+
async search(query, options = {}) {
|
|
189
|
+
const searchEpoch = this.epoch;
|
|
190
|
+
if (options.signal?.aborted) return [];
|
|
191
|
+
const mode = options.mode || 'hybrid';
|
|
192
|
+
const topK = Math.max(1, options.topK ?? 5);
|
|
193
|
+
|
|
194
|
+
// If query is raw vector or mode is dense-only
|
|
195
|
+
if (query instanceof Float32Array || mode === 'dense') {
|
|
196
|
+
const queryVec = query instanceof Float32Array ? query : await this.embedder.embed(query);
|
|
197
|
+
if (this.epoch !== searchEpoch || options.signal?.aborted) return [];
|
|
198
|
+
return this.searchByVector(queryVec, options);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// If query is string and mode is BM25-only
|
|
202
|
+
if (mode === 'bm25') {
|
|
203
|
+
if (this.epoch !== searchEpoch || options.signal?.aborted) return [];
|
|
204
|
+
return this.bm25.search(query, { topK, scope: options.scope });
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Hybrid Mode: Dense + BM25 + Reciprocal Rank Fusion + Reranking
|
|
208
|
+
const queryVec = await this.embedder.embed(query);
|
|
209
|
+
if (this.epoch !== searchEpoch || options.signal?.aborted) return [];
|
|
210
|
+
const denseCandidates = this.searchByVector(queryVec, { ...options, topK: topK * 3 });
|
|
211
|
+
const bm25Candidates = this.bm25.search(query, { topK: topK * 3, scope: options.scope });
|
|
212
|
+
|
|
213
|
+
const fused = reciprocalRankFusion(denseCandidates, bm25Candidates, {
|
|
214
|
+
k: 60,
|
|
215
|
+
denseWeight: options.denseWeight ?? 1.0,
|
|
216
|
+
bm25Weight: options.bm25Weight ?? 1.0,
|
|
217
|
+
topK: topK * 2,
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
if (this.epoch !== searchEpoch || options.signal?.aborted) return [];
|
|
221
|
+
return semanticReranker(query, fused, { topK });
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Synchronous search using local synchronous embedder.
|
|
226
|
+
* @param {string|Float32Array} query
|
|
227
|
+
* @param {Object} [options]
|
|
228
|
+
* @returns {Array<Object>}
|
|
229
|
+
*/
|
|
230
|
+
searchSync(query, options = {}) {
|
|
231
|
+
const topK = Math.max(1, options.topK || 5);
|
|
232
|
+
if (query instanceof Float32Array || options.mode === 'dense') {
|
|
233
|
+
const queryVec = query instanceof Float32Array ? query : this.embedder.embedSync(query);
|
|
234
|
+
return this.searchByVector(queryVec, options);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (options.mode === 'bm25') {
|
|
238
|
+
return this.bm25.search(query, { topK, scope: options.scope });
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const queryVec = this.embedder.embedSync(query);
|
|
242
|
+
const denseCandidates = this.searchByVector(queryVec, { ...options, topK: topK * 3 });
|
|
243
|
+
const bm25Candidates = this.bm25.search(query, { topK: topK * 3, scope: options.scope });
|
|
244
|
+
|
|
245
|
+
const fused = reciprocalRankFusion(denseCandidates, bm25Candidates, {
|
|
246
|
+
k: 60,
|
|
247
|
+
denseWeight: options.denseWeight ?? 1.0,
|
|
248
|
+
bm25Weight: options.bm25Weight ?? 1.0,
|
|
249
|
+
topK: topK * 2,
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
return semanticReranker(query, fused, { topK });
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Core vector similarity scoring loop.
|
|
257
|
+
* @param {Float32Array} queryVec
|
|
258
|
+
* @param {Object} [options]
|
|
259
|
+
* @returns {Array<Object>}
|
|
260
|
+
*/
|
|
261
|
+
searchByVector(queryVec, options = {}) {
|
|
262
|
+
const topK = Math.max(1, options.topK || 5);
|
|
263
|
+
const threshold = options.threshold !== undefined ? options.threshold : -1.0;
|
|
264
|
+
const scopeFilter = options.scope;
|
|
265
|
+
|
|
266
|
+
const candidates = [];
|
|
267
|
+
|
|
268
|
+
for (const [id, doc] of this.documents.entries()) {
|
|
269
|
+
if (scopeFilter && doc.scope !== scopeFilter && doc.scope !== 'enigma.global') {
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const rawVec = this.vectors.get(id);
|
|
274
|
+
const docFloatVec = this.quantize ? dequantizeVector(rawVec) : rawVec;
|
|
275
|
+
const sim = cosineSimilarity(queryVec, docFloatVec);
|
|
276
|
+
|
|
277
|
+
if (sim >= threshold) {
|
|
278
|
+
candidates.push({
|
|
279
|
+
id: doc.id,
|
|
280
|
+
text: doc.text,
|
|
281
|
+
score: Math.round(sim * 10000) / 10000,
|
|
282
|
+
cosine: Math.round(sim * 10000) / 10000,
|
|
283
|
+
scope: doc.scope,
|
|
284
|
+
importance: doc.importance,
|
|
285
|
+
createdAt: doc.createdAt,
|
|
286
|
+
metadata: doc.metadata,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
candidates.sort((a, b) => b.score - a.score);
|
|
292
|
+
return candidates.slice(0, topK);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Compiles a token-budgeted prompt context pack.
|
|
297
|
+
* @param {string} query
|
|
298
|
+
* @param {Object} [options]
|
|
299
|
+
* @returns {Promise<{ contextText: string, items: Array, totalChars: number, estimatedTokens: number }>}
|
|
300
|
+
*/
|
|
301
|
+
async compileContextPack(query, options = {}) {
|
|
302
|
+
const packEpoch = this.epoch;
|
|
303
|
+
const maxTokens = options.maxTokens ?? 2000;
|
|
304
|
+
if (typeof maxTokens !== 'number' || !Number.isFinite(maxTokens) || maxTokens < 0) {
|
|
305
|
+
throw new TypeError('maxTokens must be a finite non-negative number');
|
|
306
|
+
}
|
|
307
|
+
const maxChars = maxTokens * 4;
|
|
308
|
+
const results = await this.search(query, options);
|
|
309
|
+
if (this.epoch !== packEpoch || options.signal?.aborted) {
|
|
310
|
+
return { contextText: '', items: [], totalChars: 0, estimatedTokens: 0 };
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const packedItems = [];
|
|
314
|
+
let currentChars = 0;
|
|
315
|
+
|
|
316
|
+
for (const res of results) {
|
|
317
|
+
const itemLen = res.text.length;
|
|
318
|
+
if (currentChars + itemLen > maxChars) break;
|
|
319
|
+
packedItems.push(res);
|
|
320
|
+
currentChars += itemLen;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const contextText = packedItems.map((item, idx) => `[Context #${idx + 1} (${item.scope})]: ${item.text}`).join('\n\n');
|
|
324
|
+
|
|
325
|
+
return {
|
|
326
|
+
contextText,
|
|
327
|
+
items: packedItems,
|
|
328
|
+
totalChars: contextText.length,
|
|
329
|
+
estimatedTokens: Math.ceil(contextText.length / 4),
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Encrypts the entire vector collection at rest using AES-256-GCM.
|
|
335
|
+
* @param {Buffer|string} vaultKey
|
|
336
|
+
* @returns {{ format: string, ciphertext: string, iv: string, authTag: string, count: number }}
|
|
337
|
+
*/
|
|
338
|
+
encryptForVault(vaultKey) {
|
|
339
|
+
const keyBuf = Buffer.isBuffer(vaultKey) ? vaultKey : Buffer.from(vaultKey, 'hex');
|
|
340
|
+
if (keyBuf.length !== 32) throw new Error('vaultKey must be exactly 32 bytes');
|
|
341
|
+
|
|
342
|
+
const serializedData = JSON.stringify({
|
|
343
|
+
version: 3,
|
|
344
|
+
dimension: this.dimension,
|
|
345
|
+
quantized: this.quantize,
|
|
346
|
+
embeddingProviderType: this.embedder.providerType || 'custom',
|
|
347
|
+
documents: Array.from(this.documents.values()),
|
|
348
|
+
vectors: Object.fromEntries(Array.from(this.vectors.entries()).map(([k, v]) => [k, Array.from(v)])),
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
const iv = crypto.randomBytes(12);
|
|
352
|
+
const cipher = crypto.createCipheriv('aes-256-gcm', keyBuf, iv);
|
|
353
|
+
cipher.setAAD(VECTOR_STORE_AAD);
|
|
354
|
+
|
|
355
|
+
const ciphertext = Buffer.concat([cipher.update(Buffer.from(serializedData, 'utf8')), cipher.final()]);
|
|
356
|
+
const authTag = cipher.getAuthTag();
|
|
357
|
+
|
|
358
|
+
return {
|
|
359
|
+
format: 'enigma.encrypted_vectors.v1',
|
|
360
|
+
ciphertext: ciphertext.toString('base64'),
|
|
361
|
+
iv: iv.toString('hex'),
|
|
362
|
+
authTag: authTag.toString('hex'),
|
|
363
|
+
count: this.documents.size,
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Decrypts and restores an encrypted vector store bundle from vault storage.
|
|
369
|
+
* @param {Object} encryptedBundle
|
|
370
|
+
* @param {Buffer|string} vaultKey
|
|
371
|
+
* @param {{ embeddingProvider?: Object }} [options]
|
|
372
|
+
* @returns {EncryptedVectorStore}
|
|
373
|
+
*/
|
|
374
|
+
static decryptFromVault(encryptedBundle, vaultKey, options = {}) {
|
|
375
|
+
if (!encryptedBundle || encryptedBundle.format !== 'enigma.encrypted_vectors.v1') {
|
|
376
|
+
throw new Error('Invalid encrypted vector store bundle format');
|
|
377
|
+
}
|
|
378
|
+
const keyBuf = Buffer.isBuffer(vaultKey) ? vaultKey : Buffer.from(vaultKey, 'hex');
|
|
379
|
+
if (keyBuf.length !== 32) throw new Error('vaultKey must be exactly 32 bytes');
|
|
380
|
+
|
|
381
|
+
const iv = Buffer.from(encryptedBundle.iv, 'hex');
|
|
382
|
+
const authTag = Buffer.from(encryptedBundle.authTag, 'hex');
|
|
383
|
+
const ciphertext = Buffer.from(encryptedBundle.ciphertext, 'base64');
|
|
384
|
+
|
|
385
|
+
const decipher = crypto.createDecipheriv('aes-256-gcm', keyBuf, iv);
|
|
386
|
+
decipher.setAAD(VECTOR_STORE_AAD);
|
|
387
|
+
decipher.setAuthTag(authTag);
|
|
388
|
+
|
|
389
|
+
const decryptedBuf = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
390
|
+
const parsed = JSON.parse(decryptedBuf.toString('utf8'));
|
|
391
|
+
|
|
392
|
+
let embeddingProvider = options.embeddingProvider;
|
|
393
|
+
if (!embeddingProvider) {
|
|
394
|
+
if (parsed.embeddingProviderType === 'local_minilm') {
|
|
395
|
+
embeddingProvider = createEmbeddingProvider({ modelType: 'neural' });
|
|
396
|
+
} else if (parsed.embeddingProviderType === 'lexical_hash') {
|
|
397
|
+
embeddingProvider = createEmbeddingProvider({ modelType: 'lexical' });
|
|
398
|
+
} else {
|
|
399
|
+
throw new Error(
|
|
400
|
+
`Encrypted vector bundle requires an explicit embeddingProvider for provider type "${parsed.embeddingProviderType || 'unrecorded'}"`
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
} else if (
|
|
404
|
+
parsed.embeddingProviderType
|
|
405
|
+
&& parsed.embeddingProviderType !== 'custom'
|
|
406
|
+
&& embeddingProvider.providerType !== parsed.embeddingProviderType
|
|
407
|
+
) {
|
|
408
|
+
throw new Error(
|
|
409
|
+
`Embedding provider type mismatch: bundle requires "${parsed.embeddingProviderType}", received "${embeddingProvider.providerType || 'custom'}"`
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
const store = new EncryptedVectorStore({
|
|
414
|
+
dimension: parsed.dimension || EMBEDDING_DIM,
|
|
415
|
+
quantize: parsed.quantized !== false,
|
|
416
|
+
embeddingProvider,
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
for (const doc of parsed.documents || []) {
|
|
420
|
+
store.documents.set(doc.id, doc);
|
|
421
|
+
store.bm25.add(doc.id, doc.text, doc.scope);
|
|
422
|
+
if (parsed.vectors && parsed.vectors[doc.id]) {
|
|
423
|
+
const raw = parsed.vectors[doc.id];
|
|
424
|
+
store.vectors.set(doc.id, parsed.quantized ? new Int8Array(raw) : new Float32Array(raw));
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return store;
|
|
429
|
+
}
|
|
430
|
+
}
|