ruvector 0.2.22 → 0.2.25
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 +2 -2
- package/bin/cli.js +211 -63
- package/dist/core/diskann-wrapper.d.ts +53 -0
- package/dist/core/diskann-wrapper.d.ts.map +1 -0
- package/dist/core/diskann-wrapper.js +105 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +4 -1
- package/dist/core/parallel-workers.d.ts.map +1 -1
- package/dist/core/parallel-workers.js +121 -9
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +38 -1
- package/package.json +10 -5
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
**The fastest vector database for Node.js—built in Rust, runs everywhere**
|
|
12
12
|
|
|
13
|
-
Ruvector is a self-learning vector database with **enterprise-grade semantic search**, hybrid retrieval (sparse + dense), Graph RAG, FlashAttention-3, and
|
|
13
|
+
Ruvector is a self-learning vector database with **enterprise-grade semantic search**, hybrid retrieval (sparse + dense), Graph RAG, FlashAttention-3, and DiskANN — all in a single npm package. Unlike cloud-only solutions or Python-first databases, Ruvector is designed for JavaScript/TypeScript developers who need **blazing-fast vector search** without external services.
|
|
14
14
|
|
|
15
15
|
> 🚀 **Sub-millisecond queries** • 🎯 **52,000+ inserts/sec** • 💾 **~50 bytes per vector** • 🌍 **Runs anywhere** • 🧠 **859 tests passing**
|
|
16
16
|
|
|
@@ -40,7 +40,7 @@ npx ruvector hooks init --pretrain --build-agents quality
|
|
|
40
40
|
- **FlashAttention-3** — IO-aware tiled attention, O(N) memory instead of O(N^2)
|
|
41
41
|
- **Graph RAG** — Knowledge graph + community detection for multi-hop queries (30-60% improvement)
|
|
42
42
|
- **Hybrid Search** — Sparse + dense vectors with RRF fusion (20-49% better retrieval)
|
|
43
|
-
- **DiskANN / Vamana** —
|
|
43
|
+
- **DiskANN / Vamana** — SSD-friendly ANN graph with PQ compression for large-scale search
|
|
44
44
|
- **ColBERT Multi-Vector** — Per-token late interaction retrieval (MaxSim)
|
|
45
45
|
- **Matryoshka Embeddings** — Adaptive-dimension search with funnel/cascade modes
|
|
46
46
|
- **MLA** — Multi-Head Latent Attention with ~93% KV-cache compression (DeepSeek-V2/V3)
|
package/bin/cli.js
CHANGED
|
@@ -125,6 +125,21 @@ const program = new Command();
|
|
|
125
125
|
// Get package version from package.json
|
|
126
126
|
const packageJson = require('../package.json');
|
|
127
127
|
|
|
128
|
+
// `@ruvector/gnn@0.1.25` has a native-binding regression where every method
|
|
129
|
+
// throws `Given napi value is not an array` regardless of input shape (verified
|
|
130
|
+
// with both Array<Float32Array> and number[][]). Use this helper to print a
|
|
131
|
+
// pointer to the upstream issue when the CLI-side typed-array conversion is
|
|
132
|
+
// already correct.
|
|
133
|
+
function reportGnnBindingError(error) {
|
|
134
|
+
const msg = error && error.message ? error.message : String(error);
|
|
135
|
+
console.error(chalk.red(msg));
|
|
136
|
+
if (msg.includes('Given napi value is not an array') || msg.includes('TypedArray info failed')) {
|
|
137
|
+
console.error(chalk.yellow(' Note: this is a known regression in the @ruvector/gnn native binding,'));
|
|
138
|
+
console.error(chalk.yellow(' not in the CLI. Track at:'));
|
|
139
|
+
console.error(chalk.white(' https://github.com/ruvnet/ruvector/issues/402'));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
128
143
|
// Version and description (lazy load implementation info)
|
|
129
144
|
program
|
|
130
145
|
.name('ruvector')
|
|
@@ -758,13 +773,16 @@ gnnCmd
|
|
|
758
773
|
if (options.test) {
|
|
759
774
|
spinner.start('Running test forward pass...');
|
|
760
775
|
|
|
761
|
-
//
|
|
762
|
-
|
|
763
|
-
const
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
776
|
+
// The @ruvector/gnn binding requires Float32Array — plain number[] surfaces
|
|
777
|
+
// as `Get TypedArray info failed` from napi-rs.
|
|
778
|
+
const randVec = (n) => {
|
|
779
|
+
const v = new Float32Array(n);
|
|
780
|
+
for (let i = 0; i < n; i++) v[i] = Math.random();
|
|
781
|
+
return v;
|
|
782
|
+
};
|
|
783
|
+
const nodeEmbedding = randVec(inputDim);
|
|
784
|
+
const neighborEmbeddings = [randVec(inputDim), randVec(inputDim)];
|
|
785
|
+
const edgeWeights = new Float32Array([0.6, 0.4]);
|
|
768
786
|
|
|
769
787
|
const output = layer.forward(nodeEmbedding, neighborEmbeddings, edgeWeights);
|
|
770
788
|
spinner.succeed(chalk.green('Forward pass completed'));
|
|
@@ -782,7 +800,7 @@ gnnCmd
|
|
|
782
800
|
}
|
|
783
801
|
} catch (error) {
|
|
784
802
|
spinner.fail(chalk.red('Failed to create GNN layer'));
|
|
785
|
-
|
|
803
|
+
reportGnnBindingError(error);
|
|
786
804
|
process.exit(1);
|
|
787
805
|
}
|
|
788
806
|
});
|
|
@@ -812,7 +830,9 @@ gnnCmd
|
|
|
812
830
|
let totalCompressedSize = 0;
|
|
813
831
|
|
|
814
832
|
for (const embedding of embeddings) {
|
|
815
|
-
const
|
|
833
|
+
const rawVec = embedding.vector || embedding;
|
|
834
|
+
// TensorCompress requires Float32Array.
|
|
835
|
+
const vec = rawVec instanceof Float32Array ? rawVec : new Float32Array(rawVec);
|
|
816
836
|
totalOriginalSize += vec.length * 4; // float32 = 4 bytes
|
|
817
837
|
|
|
818
838
|
let compressed;
|
|
@@ -855,7 +875,7 @@ gnnCmd
|
|
|
855
875
|
}
|
|
856
876
|
} catch (error) {
|
|
857
877
|
spinner.fail(chalk.red('Failed to compress embeddings'));
|
|
858
|
-
|
|
878
|
+
reportGnnBindingError(error);
|
|
859
879
|
process.exit(1);
|
|
860
880
|
}
|
|
861
881
|
});
|
|
@@ -875,12 +895,18 @@ gnnCmd
|
|
|
875
895
|
try {
|
|
876
896
|
const query = JSON.parse(options.query);
|
|
877
897
|
const candidatesData = JSON.parse(fs.readFileSync(options.candidates, 'utf8'));
|
|
878
|
-
|
|
898
|
+
// @ruvector/gnn's differentiableSearch needs Float32Array everywhere; plain
|
|
899
|
+
// number[] surfaces as napi-rs `Get TypedArray info failed`.
|
|
900
|
+
const queryVec = query instanceof Float32Array ? query : new Float32Array(query);
|
|
901
|
+
const candidates = candidatesData.map((c) => {
|
|
902
|
+
const v = c.vector || c;
|
|
903
|
+
return v instanceof Float32Array ? v : new Float32Array(v);
|
|
904
|
+
});
|
|
879
905
|
const k = parseInt(options.topK);
|
|
880
906
|
const temperature = parseFloat(options.temperature);
|
|
881
907
|
|
|
882
908
|
spinner.text = 'Running differentiable search...';
|
|
883
|
-
const result = differentiableSearch(
|
|
909
|
+
const result = differentiableSearch(queryVec, candidates, k, temperature);
|
|
884
910
|
|
|
885
911
|
spinner.succeed(chalk.green(`Found top-${k} results`));
|
|
886
912
|
|
|
@@ -889,17 +915,19 @@ gnnCmd
|
|
|
889
915
|
console.log(chalk.white(` Candidates: ${chalk.yellow(candidates.length)}`));
|
|
890
916
|
console.log(chalk.white(` Temperature: ${chalk.yellow(temperature)}`));
|
|
891
917
|
|
|
918
|
+
// The wrapper exposes `weights`; older native shape used `attention_weights`.
|
|
919
|
+
const weights = result.weights || result.attention_weights || [];
|
|
892
920
|
console.log(chalk.cyan('\nTop-K Results:'));
|
|
893
921
|
for (let i = 0; i < result.indices.length; i++) {
|
|
894
922
|
const idx = result.indices[i];
|
|
895
|
-
const weight =
|
|
923
|
+
const weight = weights[i];
|
|
896
924
|
const id = candidatesData[idx]?.id || `candidate_${idx}`;
|
|
897
925
|
console.log(chalk.white(` ${i + 1}. ${chalk.yellow(id)} (index: ${idx})`));
|
|
898
|
-
console.log(chalk.gray(` Weight: ${weight.toFixed(6)}`));
|
|
926
|
+
console.log(chalk.gray(` Weight: ${weight != null ? weight.toFixed(6) : 'n/a'}`));
|
|
899
927
|
}
|
|
900
928
|
} catch (error) {
|
|
901
929
|
spinner.fail(chalk.red('Failed to run search'));
|
|
902
|
-
|
|
930
|
+
reportGnnBindingError(error);
|
|
903
931
|
process.exit(1);
|
|
904
932
|
}
|
|
905
933
|
});
|
|
@@ -971,59 +999,60 @@ attentionCmd
|
|
|
971
999
|
const spinner = ora('Loading keys...').start();
|
|
972
1000
|
|
|
973
1001
|
try {
|
|
974
|
-
const
|
|
1002
|
+
const queryRaw = JSON.parse(options.query);
|
|
975
1003
|
const keysData = JSON.parse(fs.readFileSync(options.keys, 'utf8'));
|
|
976
|
-
|
|
1004
|
+
// The native @ruvector/attention bindings require Float32Array; passing
|
|
1005
|
+
// plain number[] surfaces as napi-rs `Get TypedArray info failed` or
|
|
1006
|
+
// (when dim is read off a missing arg) `... Undefined into rust type u32`.
|
|
1007
|
+
const toF32 = (v) => (v instanceof Float32Array ? v : new Float32Array(v));
|
|
1008
|
+
const query = toF32(queryRaw);
|
|
1009
|
+
const keys = keysData.map((k) => toF32(k.vector || k));
|
|
977
1010
|
|
|
978
1011
|
let values = keys;
|
|
979
1012
|
if (options.values) {
|
|
980
1013
|
const valuesData = JSON.parse(fs.readFileSync(options.values, 'utf8'));
|
|
981
|
-
values = valuesData.map(v => v.vector || v);
|
|
1014
|
+
values = valuesData.map((v) => toF32(v.vector || v));
|
|
982
1015
|
}
|
|
983
1016
|
|
|
1017
|
+
const dim = query.length;
|
|
1018
|
+
|
|
984
1019
|
spinner.text = `Computing ${options.type} attention...`;
|
|
985
1020
|
|
|
986
1021
|
let result;
|
|
987
1022
|
let attentionWeights;
|
|
988
1023
|
|
|
1024
|
+
// The native @ruvector/attention bindings expose `compute(query, keys, values)`
|
|
1025
|
+
// — a flat Float32Array query plus Float32Array[] keys/values, returning a
|
|
1026
|
+
// flat Float32Array. The older CLI invoked `forward([query], keys, values)`,
|
|
1027
|
+
// which doesn't exist on the current binding (issue #402 §B).
|
|
989
1028
|
switch (options.type) {
|
|
990
1029
|
case 'dot': {
|
|
991
|
-
const attn = new DotProductAttention();
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
result = output[0];
|
|
995
|
-
attentionWeights = attn.getLastWeights ? attn.getLastWeights()[0] : null;
|
|
1030
|
+
const attn = new DotProductAttention(dim);
|
|
1031
|
+
result = attn.compute(query, keys, values);
|
|
1032
|
+
attentionWeights = attn.getLastWeights ? attn.getLastWeights() : null;
|
|
996
1033
|
break;
|
|
997
1034
|
}
|
|
998
1035
|
case 'multi-head': {
|
|
999
1036
|
const numHeads = parseInt(options.heads);
|
|
1000
1037
|
const headDim = parseInt(options.headDim);
|
|
1001
|
-
const attn = new MultiHeadAttention(
|
|
1002
|
-
|
|
1003
|
-
const output = attn.forward(queryMat, keys, values);
|
|
1004
|
-
result = output[0];
|
|
1038
|
+
const attn = new MultiHeadAttention(dim, numHeads, headDim);
|
|
1039
|
+
result = attn.compute(query, keys, values);
|
|
1005
1040
|
break;
|
|
1006
1041
|
}
|
|
1007
1042
|
case 'flash': {
|
|
1008
|
-
const attn = new FlashAttention(
|
|
1009
|
-
|
|
1010
|
-
const output = attn.forward(queryMat, keys, values);
|
|
1011
|
-
result = output[0];
|
|
1043
|
+
const attn = new FlashAttention(dim);
|
|
1044
|
+
result = attn.compute(query, keys, values);
|
|
1012
1045
|
break;
|
|
1013
1046
|
}
|
|
1014
1047
|
case 'hyperbolic': {
|
|
1015
1048
|
const curvature = parseFloat(options.curvature);
|
|
1016
|
-
const attn = new HyperbolicAttention(
|
|
1017
|
-
|
|
1018
|
-
const output = attn.forward(queryMat, keys, values);
|
|
1019
|
-
result = output[0];
|
|
1049
|
+
const attn = new HyperbolicAttention(dim, curvature);
|
|
1050
|
+
result = attn.compute(query, keys, values);
|
|
1020
1051
|
break;
|
|
1021
1052
|
}
|
|
1022
1053
|
case 'linear': {
|
|
1023
|
-
const attn = new LinearAttention(
|
|
1024
|
-
|
|
1025
|
-
const output = attn.forward(queryMat, keys, values);
|
|
1026
|
-
result = output[0];
|
|
1054
|
+
const attn = new LinearAttention(dim);
|
|
1055
|
+
result = attn.compute(query, keys, values);
|
|
1027
1056
|
break;
|
|
1028
1057
|
}
|
|
1029
1058
|
default:
|
|
@@ -1619,7 +1648,8 @@ program
|
|
|
1619
1648
|
console.log(chalk.white(' cargo add ruvector-raft # Raft consensus'));
|
|
1620
1649
|
console.log(chalk.white(' cargo add ruvector-replication # Data replication'));
|
|
1621
1650
|
console.log(chalk.white(' cargo add ruvector-tiny-dancer-core # AI routing'));
|
|
1622
|
-
console.log(chalk.white(' cargo add ruvector-router-core
|
|
1651
|
+
console.log(chalk.white(' cargo add ruvector-router-core # Semantic routing (Rust crate)'));
|
|
1652
|
+
console.log(chalk.white(' npm install @ruvector/router # Semantic routing (npm)'));
|
|
1623
1653
|
console.log('');
|
|
1624
1654
|
|
|
1625
1655
|
console.log(chalk.yellow('Platform-specific notes:'));
|
|
@@ -1737,7 +1767,7 @@ program
|
|
|
1737
1767
|
|
|
1738
1768
|
program
|
|
1739
1769
|
.command('router')
|
|
1740
|
-
.description('AI semantic router operations (requires ruvector
|
|
1770
|
+
.description('AI semantic router operations (requires @ruvector/router)')
|
|
1741
1771
|
.option('--route <text>', 'Route text to best matching intent')
|
|
1742
1772
|
.option('--intents <file>', 'Load intents from JSON file')
|
|
1743
1773
|
.option('--add-intent <name>', 'Add new intent')
|
|
@@ -1758,8 +1788,9 @@ program
|
|
|
1758
1788
|
console.log(chalk.gray(' - Vector-based similarity matching'));
|
|
1759
1789
|
console.log('');
|
|
1760
1790
|
console.log(chalk.cyan(' Status:'), chalk.yellow('Coming Soon'));
|
|
1761
|
-
console.log(chalk.gray(' The
|
|
1762
|
-
console.log(chalk.gray('
|
|
1791
|
+
console.log(chalk.gray(' The router subcommand integration is still in development.'));
|
|
1792
|
+
console.log(chalk.gray(' npm package: npm install @ruvector/router'));
|
|
1793
|
+
console.log(chalk.gray(' Rust crate: cargo add ruvector-router-core'));
|
|
1763
1794
|
console.log('');
|
|
1764
1795
|
console.log(chalk.cyan(' Usage (when available):'));
|
|
1765
1796
|
console.log(chalk.white(' npx ruvector router --route "What is the weather?"'));
|
|
@@ -2534,13 +2565,15 @@ program
|
|
|
2534
2565
|
const spinner = ora('Creating demo database...').start();
|
|
2535
2566
|
|
|
2536
2567
|
try {
|
|
2537
|
-
const db = new VectorDB({ dimensions: 4,
|
|
2568
|
+
const db = new VectorDB({ dimensions: 4, distanceMetric: 'cosine' });
|
|
2538
2569
|
|
|
2539
2570
|
spinner.text = 'Inserting vectors...';
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
db.insert('
|
|
2543
|
-
db.insert('
|
|
2571
|
+
// VectorDBWrapper.insert takes a single object: { id?, vector, metadata? }.
|
|
2572
|
+
// Wrap to Float32Array so the native binding sees the right typed array.
|
|
2573
|
+
await db.insert({ id: 'vec1', vector: new Float32Array([1.0, 0.0, 0.0, 0.0]), metadata: { label: 'x-axis' } });
|
|
2574
|
+
await db.insert({ id: 'vec2', vector: new Float32Array([0.0, 1.0, 0.0, 0.0]), metadata: { label: 'y-axis' } });
|
|
2575
|
+
await db.insert({ id: 'vec3', vector: new Float32Array([0.0, 0.0, 1.0, 0.0]), metadata: { label: 'z-axis' } });
|
|
2576
|
+
await db.insert({ id: 'vec4', vector: new Float32Array([0.7, 0.7, 0.0, 0.0]), metadata: { label: 'xy-diagonal' } });
|
|
2544
2577
|
|
|
2545
2578
|
spinner.succeed('Demo database created with 4 vectors');
|
|
2546
2579
|
|
|
@@ -2551,7 +2584,7 @@ program
|
|
|
2551
2584
|
console.log(chalk.gray(' vec4: [0.7,0.7,0,0] - xy-diagonal'));
|
|
2552
2585
|
|
|
2553
2586
|
console.log(chalk.cyan('\n Searching for nearest to [0.8, 0.6, 0, 0]:'));
|
|
2554
|
-
const results = db.search([0.8, 0.6, 0.0, 0.0], 3);
|
|
2587
|
+
const results = await db.search({ vector: new Float32Array([0.8, 0.6, 0.0, 0.0]), k: 3 });
|
|
2555
2588
|
results.forEach((r, i) => {
|
|
2556
2589
|
console.log(chalk.gray(` ${i + 1}. ${r.id} (score: ${r.score.toFixed(4)})`));
|
|
2557
2590
|
});
|
|
@@ -2577,20 +2610,26 @@ program
|
|
|
2577
2610
|
try {
|
|
2578
2611
|
console.log(chalk.cyan(' Running differentiable search with gradients...\n'));
|
|
2579
2612
|
|
|
2580
|
-
|
|
2613
|
+
// The native @ruvector/gnn binding expects Float32Array typed arrays.
|
|
2614
|
+
const queryVec = new Float32Array([1.0, 0.5, 0.3, 0.1]);
|
|
2581
2615
|
const dbVectors = [
|
|
2582
|
-
[1.0, 0.0, 0.0, 0.0],
|
|
2583
|
-
[0.0, 1.0, 0.0, 0.0],
|
|
2584
|
-
[0.5, 0.5, 0.5, 0.5],
|
|
2585
|
-
[0.9, 0.4, 0.2, 0.1]
|
|
2616
|
+
new Float32Array([1.0, 0.0, 0.0, 0.0]),
|
|
2617
|
+
new Float32Array([0.0, 1.0, 0.0, 0.0]),
|
|
2618
|
+
new Float32Array([0.5, 0.5, 0.5, 0.5]),
|
|
2619
|
+
new Float32Array([0.9, 0.4, 0.2, 0.1]),
|
|
2586
2620
|
];
|
|
2587
2621
|
|
|
2588
2622
|
const result = differentiableSearch(queryVec, dbVectors, 3, 10.0);
|
|
2589
2623
|
|
|
2590
|
-
|
|
2624
|
+
// The wrapper returns `{ indices, weights }`; older binding versions
|
|
2625
|
+
// exposed `attention_weights` instead.
|
|
2626
|
+
const weights = result.weights || result.attention_weights || [];
|
|
2627
|
+
|
|
2628
|
+
console.log(chalk.cyan(' Query:'), JSON.stringify(Array.from(queryVec)));
|
|
2591
2629
|
console.log(chalk.cyan(' Top 3 results:'));
|
|
2592
2630
|
result.indices.forEach((idx, i) => {
|
|
2593
|
-
|
|
2631
|
+
const w = weights[i] != null ? weights[i].toFixed(4) : 'n/a';
|
|
2632
|
+
console.log(chalk.gray(` ${i + 1}. Index ${idx} (attention: ${w})`));
|
|
2594
2633
|
});
|
|
2595
2634
|
|
|
2596
2635
|
console.log(chalk.cyan('\n Gradient flow enabled:'), chalk.green('Yes'));
|
|
@@ -2598,7 +2637,19 @@ program
|
|
|
2598
2637
|
|
|
2599
2638
|
console.log(chalk.green('\n GNN demo complete!'));
|
|
2600
2639
|
} catch (error) {
|
|
2601
|
-
|
|
2640
|
+
// `@ruvector/gnn@0.1.25`'s native binding has a regression where every
|
|
2641
|
+
// method throws `Given napi value is not an array`, regardless of the
|
|
2642
|
+
// input shape (verified with both Array<Float32Array> and number[][]).
|
|
2643
|
+
// Surface that explicitly so users don't think it's their CLI install.
|
|
2644
|
+
const msg = error && error.message ? error.message : String(error);
|
|
2645
|
+
if (msg.includes('not an array') || msg.includes('TypedArray')) {
|
|
2646
|
+
console.error(chalk.red(` GNN demo failed: ${msg}`));
|
|
2647
|
+
console.error(chalk.yellow('\n This looks like a regression in the @ruvector/gnn native binding,'));
|
|
2648
|
+
console.error(chalk.yellow(' not in the CLI. Tracking at:'));
|
|
2649
|
+
console.error(chalk.white(' https://github.com/ruvnet/ruvector/issues/402'));
|
|
2650
|
+
} else {
|
|
2651
|
+
console.error(chalk.red('GNN demo failed:', msg));
|
|
2652
|
+
}
|
|
2602
2653
|
}
|
|
2603
2654
|
}
|
|
2604
2655
|
|
|
@@ -2608,18 +2659,111 @@ program
|
|
|
2608
2659
|
let graphNode;
|
|
2609
2660
|
try {
|
|
2610
2661
|
graphNode = require('@ruvector/graph-node');
|
|
2611
|
-
console.log(chalk.green(' @ruvector/graph-node is available!'));
|
|
2612
|
-
console.log(chalk.gray(' Full graph demo coming soon.'));
|
|
2613
2662
|
} catch (e) {
|
|
2614
2663
|
console.log(chalk.yellow(' @ruvector/graph-node not installed.'));
|
|
2615
2664
|
console.log(chalk.white(' Install with: npm install @ruvector/graph-node'));
|
|
2665
|
+
console.log('');
|
|
2666
|
+
return;
|
|
2667
|
+
}
|
|
2668
|
+
|
|
2669
|
+
try {
|
|
2670
|
+
// The current binding exposes a `GraphDatabase` class (not Graph /
|
|
2671
|
+
// HyperGraph / RuVectorGraph) with createNode / createEdge / query.
|
|
2672
|
+
const GraphDatabase = graphNode.GraphDatabase;
|
|
2673
|
+
if (typeof GraphDatabase !== 'function') {
|
|
2674
|
+
console.log(chalk.yellow(' @ruvector/graph-node has no GraphDatabase constructor.'));
|
|
2675
|
+
console.log(chalk.gray(` Available exports: ${Object.keys(graphNode).join(', ')}`));
|
|
2676
|
+
return;
|
|
2677
|
+
}
|
|
2678
|
+
|
|
2679
|
+
const g = new GraphDatabase();
|
|
2680
|
+
console.log(chalk.green(' ✓ GraphDatabase instance created'));
|
|
2681
|
+
|
|
2682
|
+
// createNode / createEdge take a JsNode / JsEdge object (not positional
|
|
2683
|
+
// args) and are async — see @ruvector/graph-node index.d.ts.
|
|
2684
|
+
const aId = await g.createNode({
|
|
2685
|
+
id: 'alice',
|
|
2686
|
+
embedding: new Float32Array([1, 0, 0, 0]),
|
|
2687
|
+
properties: { name: 'Alice', label: 'Person' },
|
|
2688
|
+
});
|
|
2689
|
+
const bId = await g.createNode({
|
|
2690
|
+
id: 'bob',
|
|
2691
|
+
embedding: new Float32Array([0, 1, 0, 0]),
|
|
2692
|
+
properties: { name: 'Bob', label: 'Person' },
|
|
2693
|
+
});
|
|
2694
|
+
console.log(chalk.green(` ✓ Created nodes: Alice (${aId}), Bob (${bId})`));
|
|
2695
|
+
|
|
2696
|
+
const edgeId = await g.createEdge({
|
|
2697
|
+
from: 'alice',
|
|
2698
|
+
to: 'bob',
|
|
2699
|
+
description: 'KNOWS',
|
|
2700
|
+
embedding: new Float32Array([0.5, 0.5, 0, 0]),
|
|
2701
|
+
confidence: 0.95,
|
|
2702
|
+
});
|
|
2703
|
+
console.log(chalk.green(` ✓ Created edge Alice -[:KNOWS]-> Bob (${edgeId})`));
|
|
2704
|
+
|
|
2705
|
+
const stats = g.stats();
|
|
2706
|
+
console.log(chalk.gray(` Stats: ${typeof stats === 'string' ? stats : JSON.stringify(stats)}`));
|
|
2707
|
+
|
|
2708
|
+
console.log(chalk.green('\n Graph demo complete!'));
|
|
2709
|
+
} catch (error) {
|
|
2710
|
+
// The createNode/createEdge signatures vary across binding versions
|
|
2711
|
+
// (some take (label, propsJson), some take (label, propsObject)).
|
|
2712
|
+
// Print enough context that the user can adapt without guessing.
|
|
2713
|
+
console.error(chalk.red(` Graph demo failed: ${error.message}`));
|
|
2714
|
+
const G = graphNode && graphNode.GraphDatabase;
|
|
2715
|
+
if (G) {
|
|
2716
|
+
const methods = Object.getOwnPropertyNames(G.prototype || {}).filter((m) => m !== 'constructor');
|
|
2717
|
+
console.error(chalk.gray(` GraphDatabase prototype: ${methods.join(', ')}`));
|
|
2718
|
+
}
|
|
2616
2719
|
}
|
|
2617
2720
|
console.log('');
|
|
2618
2721
|
}
|
|
2619
2722
|
|
|
2620
2723
|
if (options.benchmark) {
|
|
2621
|
-
|
|
2622
|
-
console.log(chalk.
|
|
2724
|
+
requireRuvector();
|
|
2725
|
+
console.log(chalk.yellow(' Mini Benchmark Demo\n'));
|
|
2726
|
+
|
|
2727
|
+
try {
|
|
2728
|
+
// Note: ruvector-core-linux-x64-gnu@0.1.29 (and current sister binaries)
|
|
2729
|
+
// has a regression where the `dimensions` constructor arg is ignored
|
|
2730
|
+
// and inserts are pinned to dim=4. Tracking at issue #402. Keeping the
|
|
2731
|
+
// demo at dim=4 so it completes; once the binding is rebuilt from
|
|
2732
|
+
// current source, this can scale up.
|
|
2733
|
+
const dim = 4;
|
|
2734
|
+
const n = 1000;
|
|
2735
|
+
const k = 10;
|
|
2736
|
+
const db = new VectorDB({ dimensions: dim, distanceMetric: 'cosine' });
|
|
2737
|
+
|
|
2738
|
+
console.log(chalk.cyan(` Generating ${n} random ${dim}-dim vectors...`));
|
|
2739
|
+
const t0 = Date.now();
|
|
2740
|
+
const entries = [];
|
|
2741
|
+
for (let i = 0; i < n; i++) {
|
|
2742
|
+
const v = new Float32Array(dim);
|
|
2743
|
+
for (let j = 0; j < dim; j++) v[j] = Math.random();
|
|
2744
|
+
entries.push({ id: `v${i}`, vector: v });
|
|
2745
|
+
}
|
|
2746
|
+
const insertStart = Date.now();
|
|
2747
|
+
for (const entry of entries) await db.insert(entry);
|
|
2748
|
+
const insertMs = Date.now() - insertStart;
|
|
2749
|
+
|
|
2750
|
+
const queryVec = new Float32Array(dim);
|
|
2751
|
+
for (let j = 0; j < dim; j++) queryVec[j] = Math.random();
|
|
2752
|
+
|
|
2753
|
+
const searchStart = Date.now();
|
|
2754
|
+
const iters = 100;
|
|
2755
|
+
for (let i = 0; i < iters; i++) {
|
|
2756
|
+
await db.search({ vector: queryVec, k });
|
|
2757
|
+
}
|
|
2758
|
+
const searchMs = Date.now() - searchStart;
|
|
2759
|
+
|
|
2760
|
+
console.log(chalk.green(`\n ✓ Inserted ${n} vectors in ${insertMs}ms (${(insertMs / n).toFixed(2)}ms/vec)`));
|
|
2761
|
+
console.log(chalk.green(` ✓ ${iters}× top-${k} search in ${searchMs}ms (${(searchMs / iters).toFixed(2)}ms/query)`));
|
|
2762
|
+
console.log(chalk.gray(` Wall time: ${Date.now() - t0}ms`));
|
|
2763
|
+
console.log(chalk.gray(' For deeper benchmarks: npx ruvector benchmark'));
|
|
2764
|
+
} catch (error) {
|
|
2765
|
+
console.error(chalk.red(` Benchmark demo failed: ${error.message}`));
|
|
2766
|
+
}
|
|
2623
2767
|
console.log('');
|
|
2624
2768
|
}
|
|
2625
2769
|
});
|
|
@@ -9119,10 +9263,14 @@ const optimizeCmd = program.command('optimize')
|
|
|
9119
9263
|
.action(async (opts) => {
|
|
9120
9264
|
let optimizerMod;
|
|
9121
9265
|
try {
|
|
9266
|
+
// Resolve via package.json so it works whether the optimizer ships under
|
|
9267
|
+
// src/optimizer/ or dist/optimizer/.
|
|
9122
9268
|
optimizerMod = require('../src/optimizer/index.js');
|
|
9123
9269
|
} catch (e) {
|
|
9124
|
-
console.error(chalk.
|
|
9125
|
-
console.error(chalk.
|
|
9270
|
+
console.error(chalk.yellow('\n ruvector optimize: not yet shipped in this release.\n'));
|
|
9271
|
+
console.error(chalk.gray(' The optimizer module (profiles, settings generation) is in development'));
|
|
9272
|
+
console.error(chalk.gray(' and will land in a future release. Track progress at:'));
|
|
9273
|
+
console.error(chalk.white(' https://github.com/ruvnet/ruvector/issues/401\n'));
|
|
9126
9274
|
process.exit(1);
|
|
9127
9275
|
}
|
|
9128
9276
|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DiskANN Wrapper — Vamana graph ANN for billion-scale vector search
|
|
3
|
+
*
|
|
4
|
+
* Wraps @ruvector/diskann for SSD-friendly approximate nearest neighbor search.
|
|
5
|
+
* Provides the same lazy-load pattern as other native wrappers.
|
|
6
|
+
*/
|
|
7
|
+
export declare function isDiskAnnAvailable(): boolean;
|
|
8
|
+
export interface DiskAnnConfig {
|
|
9
|
+
dim: number;
|
|
10
|
+
maxDegree?: number;
|
|
11
|
+
buildBeam?: number;
|
|
12
|
+
searchBeam?: number;
|
|
13
|
+
alpha?: number;
|
|
14
|
+
pqSubspaces?: number;
|
|
15
|
+
pqIterations?: number;
|
|
16
|
+
storagePath?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface DiskAnnSearchResult {
|
|
19
|
+
id: string;
|
|
20
|
+
distance: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* DiskANN index for large-scale approximate nearest neighbor search.
|
|
24
|
+
*
|
|
25
|
+
* Uses the Vamana graph algorithm with optional Product Quantization.
|
|
26
|
+
* Build after all inserts, then search.
|
|
27
|
+
*/
|
|
28
|
+
export declare class DiskAnnIndex {
|
|
29
|
+
private inner;
|
|
30
|
+
constructor(config: DiskAnnConfig);
|
|
31
|
+
/** Insert a vector with a string ID */
|
|
32
|
+
insert(id: string, vector: Float32Array | number[]): void;
|
|
33
|
+
/** Insert a batch of vectors (flat Float32Array: N * dim) */
|
|
34
|
+
insertBatch(ids: string[], vectors: Float32Array, dim: number): void;
|
|
35
|
+
/** Build the Vamana graph index (required before search) */
|
|
36
|
+
build(): void;
|
|
37
|
+
/** Build index asynchronously */
|
|
38
|
+
buildAsync(): Promise<void>;
|
|
39
|
+
/** Search for k nearest neighbors */
|
|
40
|
+
search(query: Float32Array | number[], k?: number): DiskAnnSearchResult[];
|
|
41
|
+
/** Search asynchronously */
|
|
42
|
+
searchAsync(query: Float32Array | number[], k?: number): Promise<DiskAnnSearchResult[]>;
|
|
43
|
+
/** Delete a vector by ID */
|
|
44
|
+
delete(id: string): boolean;
|
|
45
|
+
/** Get the number of vectors */
|
|
46
|
+
count(): number;
|
|
47
|
+
/** Save index to directory */
|
|
48
|
+
save(dir: string): void;
|
|
49
|
+
/** Load index from directory */
|
|
50
|
+
static load(dir: string): DiskAnnIndex;
|
|
51
|
+
}
|
|
52
|
+
export default DiskAnnIndex;
|
|
53
|
+
//# sourceMappingURL=diskann-wrapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diskann-wrapper.d.ts","sourceRoot":"","sources":["../../src/core/diskann-wrapper.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAqBH,wBAAgB,kBAAkB,IAAI,OAAO,CAO5C;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAM;gBAEP,MAAM,EAAE,aAAa;IAcjC,uCAAuC;IACvC,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,MAAM,EAAE,GAAG,IAAI;IAKzD,6DAA6D;IAC7D,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAIpE,4DAA4D;IAC5D,KAAK,IAAI,IAAI;IAIb,iCAAiC;IAC3B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC,qCAAqC;IACrC,MAAM,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,EAAE,EAAE,CAAC,GAAE,MAAW,GAAG,mBAAmB,EAAE;IAK7E,4BAA4B;IACtB,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,EAAE,EAAE,CAAC,GAAE,MAAW,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAKjG,4BAA4B;IAC5B,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAI3B,gCAAgC;IAChC,KAAK,IAAI,MAAM;IAIf,8BAA8B;IAC9B,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIvB,gCAAgC;IAChC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY;CAMvC;AAED,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* DiskANN Wrapper — Vamana graph ANN for billion-scale vector search
|
|
4
|
+
*
|
|
5
|
+
* Wraps @ruvector/diskann for SSD-friendly approximate nearest neighbor search.
|
|
6
|
+
* Provides the same lazy-load pattern as other native wrappers.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.DiskAnnIndex = void 0;
|
|
10
|
+
exports.isDiskAnnAvailable = isDiskAnnAvailable;
|
|
11
|
+
let diskannModule = null;
|
|
12
|
+
let loadError = null;
|
|
13
|
+
function getDiskAnnModule() {
|
|
14
|
+
if (diskannModule)
|
|
15
|
+
return diskannModule;
|
|
16
|
+
if (loadError)
|
|
17
|
+
throw loadError;
|
|
18
|
+
try {
|
|
19
|
+
diskannModule = require('@ruvector/diskann');
|
|
20
|
+
return diskannModule;
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
loadError = new Error(`@ruvector/diskann not installed: ${e.message}\n` +
|
|
24
|
+
`Install with: npm install @ruvector/diskann`);
|
|
25
|
+
throw loadError;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function isDiskAnnAvailable() {
|
|
29
|
+
try {
|
|
30
|
+
getDiskAnnModule();
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* DiskANN index for large-scale approximate nearest neighbor search.
|
|
39
|
+
*
|
|
40
|
+
* Uses the Vamana graph algorithm with optional Product Quantization.
|
|
41
|
+
* Build after all inserts, then search.
|
|
42
|
+
*/
|
|
43
|
+
class DiskAnnIndex {
|
|
44
|
+
constructor(config) {
|
|
45
|
+
const mod = getDiskAnnModule();
|
|
46
|
+
this.inner = new mod.DiskAnn({
|
|
47
|
+
dim: config.dim,
|
|
48
|
+
maxDegree: config.maxDegree ?? 64,
|
|
49
|
+
buildBeam: config.buildBeam ?? 128,
|
|
50
|
+
searchBeam: config.searchBeam ?? 64,
|
|
51
|
+
alpha: config.alpha ?? 1.2,
|
|
52
|
+
pqSubspaces: config.pqSubspaces ?? 0,
|
|
53
|
+
pqIterations: config.pqIterations ?? 10,
|
|
54
|
+
storagePath: config.storagePath,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/** Insert a vector with a string ID */
|
|
58
|
+
insert(id, vector) {
|
|
59
|
+
const v = vector instanceof Float32Array ? vector : new Float32Array(vector);
|
|
60
|
+
this.inner.insert(id, v);
|
|
61
|
+
}
|
|
62
|
+
/** Insert a batch of vectors (flat Float32Array: N * dim) */
|
|
63
|
+
insertBatch(ids, vectors, dim) {
|
|
64
|
+
this.inner.insertBatch(ids, vectors, dim);
|
|
65
|
+
}
|
|
66
|
+
/** Build the Vamana graph index (required before search) */
|
|
67
|
+
build() {
|
|
68
|
+
this.inner.build();
|
|
69
|
+
}
|
|
70
|
+
/** Build index asynchronously */
|
|
71
|
+
async buildAsync() {
|
|
72
|
+
return this.inner.buildAsync();
|
|
73
|
+
}
|
|
74
|
+
/** Search for k nearest neighbors */
|
|
75
|
+
search(query, k = 10) {
|
|
76
|
+
const q = query instanceof Float32Array ? query : new Float32Array(query);
|
|
77
|
+
return this.inner.search(q, k);
|
|
78
|
+
}
|
|
79
|
+
/** Search asynchronously */
|
|
80
|
+
async searchAsync(query, k = 10) {
|
|
81
|
+
const q = query instanceof Float32Array ? query : new Float32Array(query);
|
|
82
|
+
return this.inner.searchAsync(q, k);
|
|
83
|
+
}
|
|
84
|
+
/** Delete a vector by ID */
|
|
85
|
+
delete(id) {
|
|
86
|
+
return this.inner.delete(id);
|
|
87
|
+
}
|
|
88
|
+
/** Get the number of vectors */
|
|
89
|
+
count() {
|
|
90
|
+
return this.inner.count();
|
|
91
|
+
}
|
|
92
|
+
/** Save index to directory */
|
|
93
|
+
save(dir) {
|
|
94
|
+
this.inner.save(dir);
|
|
95
|
+
}
|
|
96
|
+
/** Load index from directory */
|
|
97
|
+
static load(dir) {
|
|
98
|
+
const mod = getDiskAnnModule();
|
|
99
|
+
const instance = new DiskAnnIndex({ dim: 1 }); // placeholder
|
|
100
|
+
instance.inner = mod.DiskAnn.load(dir);
|
|
101
|
+
return instance;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
exports.DiskAnnIndex = DiskAnnIndex;
|
|
105
|
+
exports.default = DiskAnnIndex;
|
package/dist/core/index.d.ts
CHANGED
|
@@ -26,6 +26,7 @@ export * from './adaptive-embedder';
|
|
|
26
26
|
export * from './neural-embeddings';
|
|
27
27
|
export * from './neural-perf';
|
|
28
28
|
export * from './rvf-wrapper';
|
|
29
|
+
export * from './diskann-wrapper';
|
|
29
30
|
export * from '../analysis';
|
|
30
31
|
export { default as gnnWrapper } from './gnn-wrapper';
|
|
31
32
|
export { default as attentionFallbacks } from './attention-fallbacks';
|
|
@@ -45,4 +46,5 @@ export { default as TensorCompress } from './tensor-compress';
|
|
|
45
46
|
export { default as LearningEngine } from './learning-engine';
|
|
46
47
|
export { default as AdaptiveEmbedder } from './adaptive-embedder';
|
|
47
48
|
export { default as NeuralSubstrate } from './neural-embeddings';
|
|
49
|
+
export { default as DiskAnnIndex } from './diskann-wrapper';
|
|
48
50
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/core/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAGlC,cAAc,aAAa,CAAC;AAG5B,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,cAAc,CAAC;AAGrD,OAAO,EAAE,UAAU,IAAI,SAAS,EAAE,MAAM,cAAc,CAAC;AAGvD,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/core/index.js
CHANGED
|
@@ -23,7 +23,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
23
23
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.NeuralSubstrate = exports.AdaptiveEmbedder = exports.LearningEngine = exports.TensorCompress = exports.ASTParser = exports.CodeParser = exports.RuvectorCluster = exports.CodeGraph = exports.SemanticRouter = exports.ExtendedWorkerPool = exports.ParallelIntelligence = exports.OptimizedOnnxEmbedder = exports.OnnxEmbedder = exports.IntelligenceEngine = exports.Sona = exports.agentdbFast = exports.attentionFallbacks = exports.gnnWrapper = void 0;
|
|
26
|
+
exports.DiskAnnIndex = exports.NeuralSubstrate = exports.AdaptiveEmbedder = exports.LearningEngine = exports.TensorCompress = exports.ASTParser = exports.CodeParser = exports.RuvectorCluster = exports.CodeGraph = exports.SemanticRouter = exports.ExtendedWorkerPool = exports.ParallelIntelligence = exports.OptimizedOnnxEmbedder = exports.OnnxEmbedder = exports.IntelligenceEngine = exports.Sona = exports.agentdbFast = exports.attentionFallbacks = exports.gnnWrapper = void 0;
|
|
27
27
|
__exportStar(require("./gnn-wrapper"), exports);
|
|
28
28
|
__exportStar(require("./attention-fallbacks"), exports);
|
|
29
29
|
__exportStar(require("./agentdb-fast"), exports);
|
|
@@ -46,6 +46,7 @@ __exportStar(require("./adaptive-embedder"), exports);
|
|
|
46
46
|
__exportStar(require("./neural-embeddings"), exports);
|
|
47
47
|
__exportStar(require("./neural-perf"), exports);
|
|
48
48
|
__exportStar(require("./rvf-wrapper"), exports);
|
|
49
|
+
__exportStar(require("./diskann-wrapper"), exports);
|
|
49
50
|
// Analysis module (consolidated security, complexity, patterns)
|
|
50
51
|
__exportStar(require("../analysis"), exports);
|
|
51
52
|
// Re-export default objects for convenience
|
|
@@ -87,3 +88,5 @@ var adaptive_embedder_1 = require("./adaptive-embedder");
|
|
|
87
88
|
Object.defineProperty(exports, "AdaptiveEmbedder", { enumerable: true, get: function () { return __importDefault(adaptive_embedder_1).default; } });
|
|
88
89
|
var neural_embeddings_1 = require("./neural-embeddings");
|
|
89
90
|
Object.defineProperty(exports, "NeuralSubstrate", { enumerable: true, get: function () { return __importDefault(neural_embeddings_1).default; } });
|
|
91
|
+
var diskann_wrapper_1 = require("./diskann-wrapper");
|
|
92
|
+
Object.defineProperty(exports, "DiskAnnIndex", { enumerable: true, get: function () { return __importDefault(diskann_wrapper_1).default; } });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parallel-workers.d.ts","sourceRoot":"","sources":["../../src/core/parallel-workers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAQH,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAMvD,MAAM,WAAW,gBAAgB;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAGD,YAAY,EAAE,eAAe,EAAE,CAAC;AAEhC,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,KAAK,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB;AA+BD,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,SAAS,CAKT;IACR,OAAO,CAAC,WAAW,CAAkC;IACrD,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,gBAAgB,CAAgD;IACxE,OAAO,CAAC,QAAQ,CAAuC;gBAE3C,MAAM,GAAE,gBAAqB;IAYnC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAgC3B,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,iBAAiB;
|
|
1
|
+
{"version":3,"file":"parallel-workers.d.ts","sourceRoot":"","sources":["../../src/core/parallel-workers.ts"],"names":[],"mappings":"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"}
|
|
@@ -173,9 +173,63 @@ class ExtendedWorkerPool {
|
|
|
173
173
|
});
|
|
174
174
|
|
|
175
175
|
// Worker implementations
|
|
176
|
+
|
|
177
|
+
// Hash-based embedding: deterministic, no external deps, 128-dim
|
|
178
|
+
function hashEmbed(text, dim = 128) {
|
|
179
|
+
const embedding = new Float64Array(dim);
|
|
180
|
+
const tokens = text.split(/\\s+|[{}()\\[\\];,.<>=/+\\-*&|!~^%@#]/);
|
|
181
|
+
|
|
182
|
+
for (let t = 0; t < tokens.length; t++) {
|
|
183
|
+
const token = tokens[t];
|
|
184
|
+
if (!token) continue;
|
|
185
|
+
|
|
186
|
+
// FNV-1a hash
|
|
187
|
+
let h = 0x811c9dc5;
|
|
188
|
+
for (let i = 0; i < token.length; i++) {
|
|
189
|
+
h ^= token.charCodeAt(i);
|
|
190
|
+
h = Math.imul(h, 0x01000193);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Positional weight (tokens near start matter more)
|
|
194
|
+
const posWeight = 1.0 / (1.0 + Math.log1p(t));
|
|
195
|
+
|
|
196
|
+
// Distribute across multiple dimensions using hash rotations
|
|
197
|
+
for (let d = 0; d < 4; d++) {
|
|
198
|
+
const idx = ((h >>> 0) + d * 37) % dim;
|
|
199
|
+
const sign = (h & (1 << d)) ? 1 : -1;
|
|
200
|
+
embedding[idx] += sign * posWeight;
|
|
201
|
+
h = (h >>> 7) | (h << 25); // rotate
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// L2 normalize
|
|
206
|
+
let norm = 0;
|
|
207
|
+
for (let i = 0; i < dim; i++) norm += embedding[i] * embedding[i];
|
|
208
|
+
norm = Math.sqrt(norm) || 1;
|
|
209
|
+
const result = new Array(dim);
|
|
210
|
+
for (let i = 0; i < dim; i++) result[i] = embedding[i] / norm;
|
|
211
|
+
return result;
|
|
212
|
+
}
|
|
213
|
+
|
|
176
214
|
async function speculativeEmbed(files, coEditGraph) {
|
|
177
|
-
|
|
178
|
-
return files.map(
|
|
215
|
+
const fs = require('fs');
|
|
216
|
+
return files.map(file => {
|
|
217
|
+
try {
|
|
218
|
+
if (!fs.existsSync(file)) {
|
|
219
|
+
return { file, embedding: hashEmbed(file), confidence: 0.2, timestamp: Date.now() };
|
|
220
|
+
}
|
|
221
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
222
|
+
const embedding = hashEmbed(content);
|
|
223
|
+
|
|
224
|
+
// Confidence based on file size (more content = higher confidence)
|
|
225
|
+
const lines = content.split('\\n').length;
|
|
226
|
+
const confidence = Math.min(0.95, 0.3 + (lines / 500) * 0.65);
|
|
227
|
+
|
|
228
|
+
return { file, embedding, confidence, timestamp: Date.now() };
|
|
229
|
+
} catch {
|
|
230
|
+
return { file, embedding: hashEmbed(file), confidence: 0.1, timestamp: Date.now() };
|
|
231
|
+
}
|
|
232
|
+
});
|
|
179
233
|
}
|
|
180
234
|
|
|
181
235
|
async function astAnalyze(files) {
|
|
@@ -278,26 +332,84 @@ class ExtendedWorkerPool {
|
|
|
278
332
|
return findings;
|
|
279
333
|
}
|
|
280
334
|
|
|
335
|
+
function cosineSimilarity(a, b) {
|
|
336
|
+
if (!a || !b || a.length !== b.length || a.length === 0) return 0;
|
|
337
|
+
let dot = 0, normA = 0, normB = 0;
|
|
338
|
+
for (let i = 0; i < a.length; i++) {
|
|
339
|
+
dot += a[i] * b[i];
|
|
340
|
+
normA += a[i] * a[i];
|
|
341
|
+
normB += b[i] * b[i];
|
|
342
|
+
}
|
|
343
|
+
const denom = Math.sqrt(normA) * Math.sqrt(normB);
|
|
344
|
+
return denom === 0 ? 0 : dot / denom;
|
|
345
|
+
}
|
|
346
|
+
|
|
281
347
|
async function ragRetrieve(query, chunks, topK) {
|
|
282
|
-
//
|
|
283
|
-
const
|
|
348
|
+
// If chunks have embeddings, use cosine similarity (semantic retrieval)
|
|
349
|
+
const hasEmbeddings = chunks.some(c => c.embedding && c.embedding.length > 0);
|
|
350
|
+
|
|
351
|
+
if (hasEmbeddings) {
|
|
352
|
+
const queryEmbedding = hashEmbed(query, chunks[0].embedding.length);
|
|
353
|
+
return chunks
|
|
354
|
+
.map(chunk => {
|
|
355
|
+
const semantic = chunk.embedding && chunk.embedding.length > 0
|
|
356
|
+
? cosineSimilarity(queryEmbedding, chunk.embedding)
|
|
357
|
+
: 0;
|
|
358
|
+
// Blend semantic + keyword for robustness
|
|
359
|
+
const queryTerms = query.toLowerCase().split(/\\s+/);
|
|
360
|
+
const content = chunk.content.toLowerCase();
|
|
361
|
+
const kwMatches = queryTerms.filter(t => content.includes(t)).length;
|
|
362
|
+
const keyword = queryTerms.length > 0 ? kwMatches / queryTerms.length : 0;
|
|
363
|
+
const relevance = semantic * 0.7 + keyword * 0.3;
|
|
364
|
+
return { ...chunk, relevance };
|
|
365
|
+
})
|
|
366
|
+
.sort((a, b) => b.relevance - a.relevance)
|
|
367
|
+
.slice(0, topK);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Fallback: TF-IDF-weighted keyword matching
|
|
371
|
+
const queryTerms = query.toLowerCase().split(/\\s+/).filter(Boolean);
|
|
372
|
+
const allContent = chunks.map(c => c.content.toLowerCase());
|
|
373
|
+
// IDF: log(N / df) for each query term
|
|
374
|
+
const idf = {};
|
|
375
|
+
for (const term of queryTerms) {
|
|
376
|
+
const df = allContent.filter(c => c.includes(term)).length || 1;
|
|
377
|
+
idf[term] = Math.log(allContent.length / df);
|
|
378
|
+
}
|
|
284
379
|
return chunks
|
|
285
380
|
.map(chunk => {
|
|
286
381
|
const content = chunk.content.toLowerCase();
|
|
287
|
-
const
|
|
288
|
-
|
|
382
|
+
const words = content.split(/\\s+/);
|
|
383
|
+
let score = 0;
|
|
384
|
+
for (const term of queryTerms) {
|
|
385
|
+
const tf = words.filter(w => w === term).length / (words.length || 1);
|
|
386
|
+
score += tf * (idf[term] || 1);
|
|
387
|
+
}
|
|
388
|
+
return { ...chunk, relevance: score };
|
|
289
389
|
})
|
|
290
390
|
.sort((a, b) => b.relevance - a.relevance)
|
|
291
391
|
.slice(0, topK);
|
|
292
392
|
}
|
|
293
393
|
|
|
294
394
|
async function contextRank(context, query) {
|
|
295
|
-
|
|
395
|
+
// Use TF-IDF scoring instead of raw keyword matching
|
|
396
|
+
const queryTerms = query.toLowerCase().split(/\\s+/).filter(Boolean);
|
|
397
|
+
const allContent = context.map(c => c.toLowerCase());
|
|
398
|
+
const idf = {};
|
|
399
|
+
for (const term of queryTerms) {
|
|
400
|
+
const df = allContent.filter(c => c.includes(term)).length || 1;
|
|
401
|
+
idf[term] = Math.log(allContent.length / df);
|
|
402
|
+
}
|
|
296
403
|
return context
|
|
297
404
|
.map((ctx, i) => {
|
|
298
405
|
const content = ctx.toLowerCase();
|
|
299
|
-
const
|
|
300
|
-
|
|
406
|
+
const words = content.split(/\\s+/);
|
|
407
|
+
let score = 0;
|
|
408
|
+
for (const term of queryTerms) {
|
|
409
|
+
const tf = words.filter(w => w === term).length / (words.length || 1);
|
|
410
|
+
score += tf * (idf[term] || 1);
|
|
411
|
+
}
|
|
412
|
+
return { index: i, content: ctx, relevance: score };
|
|
301
413
|
})
|
|
302
414
|
.sort((a, b) => b.relevance - a.relevance);
|
|
303
415
|
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,cAAc,SAAS,CAAC;AAGxB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAE3B,QAAA,IAAI,cAAc,EAAE,GAAG,CAAC;AA4DxB;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,QAAQ,GAAG,KAAK,GAAG,MAAM,CAEjE;AAED;;GAEG;AACH,wBAAgB,QAAQ,IAAI,OAAO,CAElC;AAED;;GAEG;AACH,wBAAgB,KAAK,IAAI,OAAO,CAE/B;AAED;;GAEG;AACH,wBAAgB,MAAM,IAAI,OAAO,CAEhC;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAMxE;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,cAAc,SAAS,CAAC;AAGxB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAE3B,QAAA,IAAI,cAAc,EAAE,GAAG,CAAC;AA4DxB;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,QAAQ,GAAG,KAAK,GAAG,MAAM,CAEjE;AAED;;GAEG;AACH,wBAAgB,QAAQ,IAAI,OAAO,CAElC;AAED;;GAEG;AACH,wBAAgB,KAAK,IAAI,OAAO,CAE/B;AAED;;GAEG;AACH,wBAAgB,MAAM,IAAI,OAAO,CAEhC;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAMxE;AA4BD;;GAEG;AACH,cAAM,eAAe;IACnB,OAAO,CAAC,EAAE,CAAM;gBAEJ,OAAO,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,GAAG,CAAA;KAAE;IAe7H;;OAEG;IACG,MAAM,CAAC,KAAK,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,YAAY,GAAG,MAAM,EAAE,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IActH;;OAEG;IACG,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,YAAY,GAAG,MAAM,EAAE,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAUtI;;OAEG;IACG,MAAM,CAAC,KAAK,EAAE;QAAE,MAAM,EAAE,YAAY,GAAG,MAAM,EAAE,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,YAAY,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;KAAE,CAAC,CAAC;IAuB1N;;OAEG;IACG,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,YAAY,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;KAAE,GAAG,IAAI,CAAC;IAW5G;;OAEG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI1C;;OAEG;IACG,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;IAI5B;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;CAGlC;AAGD,eAAO,MAAM,QAAQ,wBAAkB,CAAC;AACxC,eAAO,MAAM,QAAQ,wBAAkB,CAAC;AAGxC,eAAO,MAAM,cAAc,KAA0B,CAAC;AAGtD,eAAe,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -126,12 +126,49 @@ function getVersion() {
|
|
|
126
126
|
implementation: implementationType
|
|
127
127
|
};
|
|
128
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Normalize a user-friendly distance metric string (`"cosine"`, `"euclidean"`,
|
|
131
|
+
* etc.) to the PascalCase variant the native `JsDistanceMetric` enum accepts.
|
|
132
|
+
* Native: { Euclidean, Cosine, DotProduct, Manhattan }.
|
|
133
|
+
*/
|
|
134
|
+
function normalizeMetric(metric) {
|
|
135
|
+
if (!metric)
|
|
136
|
+
return metric;
|
|
137
|
+
const m = metric.toLowerCase().replace(/[_\s-]/g, '');
|
|
138
|
+
switch (m) {
|
|
139
|
+
case 'cosine':
|
|
140
|
+
return 'Cosine';
|
|
141
|
+
case 'euclidean':
|
|
142
|
+
case 'l2':
|
|
143
|
+
return 'Euclidean';
|
|
144
|
+
case 'dot':
|
|
145
|
+
case 'dotproduct':
|
|
146
|
+
case 'innerproduct':
|
|
147
|
+
return 'DotProduct';
|
|
148
|
+
case 'manhattan':
|
|
149
|
+
case 'l1':
|
|
150
|
+
return 'Manhattan';
|
|
151
|
+
default:
|
|
152
|
+
return metric; // pass through; native will error with the variant list.
|
|
153
|
+
}
|
|
154
|
+
}
|
|
129
155
|
/**
|
|
130
156
|
* Wrapper class that automatically handles metadata JSON conversion
|
|
131
157
|
*/
|
|
132
158
|
class VectorDBWrapper {
|
|
133
159
|
constructor(options) {
|
|
134
|
-
|
|
160
|
+
// Accept both `distanceMetric` (canonical) and `metric` (CLI shorthand).
|
|
161
|
+
// Normalize to the PascalCase enum variant the native binding expects.
|
|
162
|
+
const distanceMetric = normalizeMetric(options.distanceMetric ?? options.metric);
|
|
163
|
+
const nativeOptions = {
|
|
164
|
+
dimensions: options.dimensions,
|
|
165
|
+
storagePath: options.storagePath,
|
|
166
|
+
hnswConfig: options.hnswConfig,
|
|
167
|
+
};
|
|
168
|
+
if (distanceMetric !== undefined) {
|
|
169
|
+
nativeOptions.distanceMetric = distanceMetric;
|
|
170
|
+
}
|
|
171
|
+
this.db = new implementation.VectorDb(nativeOptions);
|
|
135
172
|
}
|
|
136
173
|
/**
|
|
137
174
|
* Insert a vector with optional metadata (objects are auto-converted to JSON)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ruvector",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "Self-learning vector database for Node.js — hybrid search, Graph RAG, FlashAttention-3,
|
|
3
|
+
"version": "0.2.25",
|
|
4
|
+
"description": "Self-learning vector database for Node.js — hybrid search, Graph RAG, FlashAttention-3, HNSW, 50+ attention mechanisms",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"bin": {
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"build": "tsc && cp src/core/onnx/pkg/package.json dist/core/onnx/pkg/",
|
|
12
|
-
"
|
|
12
|
+
"verify-dist": "node scripts/verify-dist.js",
|
|
13
|
+
"prepublishOnly": "npm run build && npm run verify-dist",
|
|
13
14
|
"test": "node test/integration.js && node test/cli-commands.js"
|
|
14
15
|
},
|
|
15
16
|
"keywords": [
|
|
@@ -47,7 +48,7 @@
|
|
|
47
48
|
"mcp",
|
|
48
49
|
"edge-computing",
|
|
49
50
|
"graph-rag",
|
|
50
|
-
"
|
|
51
|
+
"hnsw",
|
|
51
52
|
"hybrid-search",
|
|
52
53
|
"colbert",
|
|
53
54
|
"turboquant",
|
|
@@ -84,7 +85,7 @@
|
|
|
84
85
|
},
|
|
85
86
|
"devDependencies": {
|
|
86
87
|
"@types/node": "^20.10.5",
|
|
87
|
-
"typescript": "^5.
|
|
88
|
+
"typescript": "^5.9.3"
|
|
88
89
|
},
|
|
89
90
|
"files": [
|
|
90
91
|
"bin/",
|
|
@@ -95,6 +96,7 @@
|
|
|
95
96
|
"LICENSE"
|
|
96
97
|
],
|
|
97
98
|
"peerDependencies": {
|
|
99
|
+
"@ruvector/diskann": ">=0.1.0",
|
|
98
100
|
"@ruvector/pi-brain": ">=0.1.0",
|
|
99
101
|
"@ruvector/router": ">=0.1.0",
|
|
100
102
|
"@ruvector/ruvllm": ">=2.0.0"
|
|
@@ -108,6 +110,9 @@
|
|
|
108
110
|
},
|
|
109
111
|
"@ruvector/router": {
|
|
110
112
|
"optional": true
|
|
113
|
+
},
|
|
114
|
+
"@ruvector/diskann": {
|
|
115
|
+
"optional": true
|
|
111
116
|
}
|
|
112
117
|
},
|
|
113
118
|
"engines": {
|