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 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 billion-scale 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.
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** — Billion-scale SSD-backed ANN with <10ms latency
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
- // Create test data
762
- const nodeEmbedding = Array.from({ length: inputDim }, () => Math.random());
763
- const neighborEmbeddings = [
764
- Array.from({ length: inputDim }, () => Math.random()),
765
- Array.from({ length: inputDim }, () => Math.random())
766
- ];
767
- const edgeWeights = [0.6, 0.4];
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
- console.error(chalk.red(error.message));
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 vec = embedding.vector || embedding;
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
- console.error(chalk.red(error.message));
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
- const candidates = candidatesData.map(c => c.vector || c);
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(query, candidates, k, temperature);
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 = result.weights[i];
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
- console.error(chalk.red(error.message));
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 query = JSON.parse(options.query);
1002
+ const queryRaw = JSON.parse(options.query);
975
1003
  const keysData = JSON.parse(fs.readFileSync(options.keys, 'utf8'));
976
- const keys = keysData.map(k => k.vector || k);
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
- const queryMat = [query];
993
- const output = attn.forward(queryMat, keys, values);
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(query.length, numHeads, headDim);
1002
- const queryMat = [query];
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(query.length);
1009
- const queryMat = [query];
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(query.length, curvature);
1017
- const queryMat = [query];
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(query.length);
1024
- const queryMat = [query];
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 # Semantic routing'));
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-router-core)')
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 npm package for router is in development.'));
1762
- console.log(chalk.gray(' Rust crate available: cargo add ruvector-router-core'));
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, metric: 'cosine' });
2568
+ const db = new VectorDB({ dimensions: 4, distanceMetric: 'cosine' });
2538
2569
 
2539
2570
  spinner.text = 'Inserting vectors...';
2540
- db.insert('vec1', [1.0, 0.0, 0.0, 0.0], { label: 'x-axis' });
2541
- db.insert('vec2', [0.0, 1.0, 0.0, 0.0], { label: 'y-axis' });
2542
- db.insert('vec3', [0.0, 0.0, 1.0, 0.0], { label: 'z-axis' });
2543
- db.insert('vec4', [0.7, 0.7, 0.0, 0.0], { label: 'xy-diagonal' });
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
- const queryVec = [1.0, 0.5, 0.3, 0.1];
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
- console.log(chalk.cyan(' Query:'), JSON.stringify(queryVec));
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
- console.log(chalk.gray(` ${i + 1}. Index ${idx} (attention: ${result.attention_weights[i].toFixed(4)})`));
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
- console.error(chalk.red('GNN demo failed:', error.message));
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
- console.log(chalk.yellow(' Redirecting to benchmark command...\n'));
2622
- console.log(chalk.white(' Run: npx ruvector benchmark'));
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.red('Error: Failed to load optimizer module.'));
9125
- console.error(chalk.dim(` ${e.message}`));
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;
@@ -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
@@ -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;AAG9B,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"}
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"}
@@ -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":"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"}
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
- // Pre-compute embeddings for likely next files
178
- return files.map(f => ({ file: f, embedding: [], confidence: 0.5 }));
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
- // Simple keyword-based retrieval (would use embeddings in production)
283
- const queryTerms = query.toLowerCase().split(/\\s+/);
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 matches = queryTerms.filter(term => content.includes(term)).length;
288
- return { ...chunk, relevance: matches / queryTerms.length };
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
- const queryTerms = query.toLowerCase().split(/\\s+/);
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 matches = queryTerms.filter(term => content.includes(term)).length;
300
- return { index: i, content: ctx, relevance: matches / queryTerms.length };
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
@@ -45,6 +45,7 @@ declare class VectorDBWrapper {
45
45
  dimensions: number;
46
46
  storagePath?: string;
47
47
  distanceMetric?: string;
48
+ metric?: string;
48
49
  hnswConfig?: any;
49
50
  });
50
51
  /**
@@ -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;AAED;;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,UAAU,CAAC,EAAE,GAAG,CAAA;KAAE;IAI5G;;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"}
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
- this.db = new implementation.VectorDb(options);
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.22",
4
- "description": "Self-learning vector database for Node.js — hybrid search, Graph RAG, FlashAttention-3, DiskANN, 50+ attention mechanisms",
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
- "prepublishOnly": "npm run build",
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
- "diskann",
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.3.3"
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": {