ruvector 0.2.23 → 0.2.26
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/bin/cli.js +332 -79
- package/bin/mcp-server.js +94 -22
- package/dist/analysis/complexity.d.ts +52 -0
- package/dist/analysis/complexity.d.ts.map +1 -0
- package/dist/analysis/complexity.js +146 -0
- package/dist/analysis/index.d.ts +15 -0
- package/dist/analysis/index.d.ts.map +1 -0
- package/dist/analysis/index.js +38 -0
- package/dist/analysis/patterns.d.ts +71 -0
- package/dist/analysis/patterns.d.ts.map +1 -0
- package/dist/analysis/patterns.js +243 -0
- package/dist/analysis/security.d.ts +51 -0
- package/dist/analysis/security.d.ts.map +1 -0
- package/dist/analysis/security.js +139 -0
- package/dist/core/adaptive-embedder.d.ts +156 -0
- package/dist/core/adaptive-embedder.d.ts.map +1 -0
- package/dist/core/adaptive-embedder.js +838 -0
- package/dist/core/agentdb-fast.d.ts +149 -0
- package/dist/core/agentdb-fast.d.ts.map +1 -0
- package/dist/core/agentdb-fast.js +301 -0
- package/dist/core/ast-parser.d.ts +108 -0
- package/dist/core/ast-parser.d.ts.map +1 -0
- package/dist/core/ast-parser.js +602 -0
- package/dist/core/attention-fallbacks.d.ts +321 -0
- package/dist/core/attention-fallbacks.d.ts.map +1 -0
- package/dist/core/attention-fallbacks.js +552 -0
- package/dist/core/cluster-wrapper.d.ts +148 -0
- package/dist/core/cluster-wrapper.d.ts.map +1 -0
- package/dist/core/cluster-wrapper.js +271 -0
- package/dist/core/coverage-router.d.ts +88 -0
- package/dist/core/coverage-router.d.ts.map +1 -0
- package/dist/core/coverage-router.js +315 -0
- package/dist/core/diff-embeddings.d.ts +93 -0
- package/dist/core/diff-embeddings.d.ts.map +1 -0
- package/dist/core/diff-embeddings.js +334 -0
- 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/gnn-wrapper.d.ts +143 -0
- package/dist/core/gnn-wrapper.d.ts.map +1 -0
- package/dist/core/gnn-wrapper.js +213 -0
- package/dist/core/graph-algorithms.d.ts +83 -0
- package/dist/core/graph-algorithms.d.ts.map +1 -0
- package/dist/core/graph-algorithms.js +514 -0
- package/dist/core/graph-wrapper.d.ts +147 -0
- package/dist/core/graph-wrapper.d.ts.map +1 -0
- package/dist/core/graph-wrapper.js +299 -0
- package/dist/core/index.d.ts +50 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +92 -0
- package/dist/core/intelligence-engine.d.ts +258 -0
- package/dist/core/intelligence-engine.d.ts.map +1 -0
- package/dist/core/intelligence-engine.js +1026 -0
- package/dist/core/learning-engine.d.ts +162 -0
- package/dist/core/learning-engine.d.ts.map +1 -0
- package/dist/core/learning-engine.js +609 -0
- package/dist/core/neural-embeddings.d.ts +393 -0
- package/dist/core/neural-embeddings.d.ts.map +1 -0
- package/dist/core/neural-embeddings.js +1091 -0
- package/dist/core/neural-perf.d.ts +331 -0
- package/dist/core/neural-perf.d.ts.map +1 -0
- package/dist/core/neural-perf.js +704 -0
- package/dist/core/onnx/loader.js +348 -0
- package/dist/core/onnx/pkg/LICENSE +21 -0
- package/dist/core/onnx/pkg/loader.js +348 -0
- package/dist/core/onnx/pkg/package.json +3 -0
- package/dist/core/onnx/pkg/ruvector_onnx_embeddings_wasm.d.ts +112 -0
- package/dist/core/onnx/pkg/ruvector_onnx_embeddings_wasm.js +5 -0
- package/dist/core/onnx/pkg/ruvector_onnx_embeddings_wasm_bg.js +638 -0
- package/dist/core/onnx/pkg/ruvector_onnx_embeddings_wasm_bg.wasm +0 -0
- package/dist/core/onnx/pkg/ruvector_onnx_embeddings_wasm_bg.wasm.d.ts +29 -0
- package/dist/core/onnx-embedder.d.ts +105 -0
- package/dist/core/onnx-embedder.d.ts.map +1 -0
- package/dist/core/onnx-embedder.js +414 -0
- package/dist/core/onnx-optimized.d.ts +109 -0
- package/dist/core/onnx-optimized.d.ts.map +1 -0
- package/dist/core/onnx-optimized.js +419 -0
- package/dist/core/parallel-intelligence.d.ts +109 -0
- package/dist/core/parallel-intelligence.d.ts.map +1 -0
- package/dist/core/parallel-intelligence.js +340 -0
- package/dist/core/parallel-workers.d.ts +177 -0
- package/dist/core/parallel-workers.d.ts.map +1 -0
- package/dist/core/parallel-workers.js +783 -0
- package/dist/core/router-wrapper.d.ts +75 -0
- package/dist/core/router-wrapper.d.ts.map +1 -0
- package/dist/core/router-wrapper.js +243 -0
- package/dist/core/rvf-wrapper.d.ts +86 -0
- package/dist/core/rvf-wrapper.d.ts.map +1 -0
- package/dist/core/rvf-wrapper.js +102 -0
- package/dist/core/sona-wrapper.d.ts +226 -0
- package/dist/core/sona-wrapper.d.ts.map +1 -0
- package/dist/core/sona-wrapper.js +282 -0
- package/dist/core/tensor-compress.d.ts +134 -0
- package/dist/core/tensor-compress.d.ts.map +1 -0
- package/dist/core/tensor-compress.js +432 -0
- package/dist/index.d.ts +160 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +359 -0
- package/dist/services/embedding-service.d.ts +136 -0
- package/dist/services/embedding-service.d.ts.map +1 -0
- package/dist/services/embedding-service.js +294 -0
- package/dist/services/index.d.ts +6 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +26 -0
- package/dist/types.d.ts +145 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/workers/benchmark.d.ts +44 -0
- package/dist/workers/benchmark.d.ts.map +1 -0
- package/dist/workers/benchmark.js +230 -0
- package/dist/workers/index.d.ts +10 -0
- package/dist/workers/index.d.ts.map +1 -0
- package/dist/workers/index.js +25 -0
- package/dist/workers/native-worker.d.ts +76 -0
- package/dist/workers/native-worker.d.ts.map +1 -0
- package/dist/workers/native-worker.js +490 -0
- package/dist/workers/types.d.ts +69 -0
- package/dist/workers/types.d.ts.map +1 -0
- package/dist/workers/types.js +7 -0
- package/package.json +11 -9
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')
|
|
@@ -149,6 +164,9 @@ program
|
|
|
149
164
|
storagePath: dbPath,
|
|
150
165
|
});
|
|
151
166
|
|
|
167
|
+
// Write sidecar so insert/search/stats can recover dimension without JSON-parsing binary redb
|
|
168
|
+
fs.writeFileSync(`${dbPath}.meta.json`, JSON.stringify({ dimension, metric: options.metric, version: 1 }));
|
|
169
|
+
|
|
152
170
|
spinner.succeed(chalk.green(`Database created: ${dbPath}`));
|
|
153
171
|
console.log(chalk.gray(` Dimension: ${dimension}`));
|
|
154
172
|
console.log(chalk.gray(` Metric: ${options.metric}`));
|
|
@@ -170,15 +188,14 @@ program
|
|
|
170
188
|
const spinner = ora('Loading database...').start();
|
|
171
189
|
|
|
172
190
|
try {
|
|
173
|
-
// Read
|
|
174
|
-
let dimension = 384;
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
dimension = parsed.dimension || 384;
|
|
191
|
+
// Read dimension from sidecar (avoids JSON-parsing binary redb)
|
|
192
|
+
let dimension = 384;
|
|
193
|
+
const metaPath = `${dbPath}.meta.json`;
|
|
194
|
+
if (fs.existsSync(metaPath)) {
|
|
195
|
+
try { dimension = JSON.parse(fs.readFileSync(metaPath, 'utf8')).dimension || 384; } catch (_) {}
|
|
179
196
|
}
|
|
180
197
|
|
|
181
|
-
const db = new VectorDB({ dimension });
|
|
198
|
+
const db = new VectorDB({ dimensions: dimension, storagePath: dbPath });
|
|
182
199
|
|
|
183
200
|
if (fs.existsSync(dbPath)) {
|
|
184
201
|
db.load(dbPath);
|
|
@@ -222,12 +239,14 @@ program
|
|
|
222
239
|
const spinner = ora('Loading database...').start();
|
|
223
240
|
|
|
224
241
|
try {
|
|
225
|
-
// Read
|
|
226
|
-
|
|
227
|
-
const
|
|
228
|
-
|
|
242
|
+
// Read dimension from sidecar (avoids JSON-parsing binary redb)
|
|
243
|
+
let dimension = 384;
|
|
244
|
+
const metaPath = `${dbPath}.meta.json`;
|
|
245
|
+
if (fs.existsSync(metaPath)) {
|
|
246
|
+
try { dimension = JSON.parse(fs.readFileSync(metaPath, 'utf8')).dimension || 384; } catch (_) {}
|
|
247
|
+
}
|
|
229
248
|
|
|
230
|
-
const db = new VectorDB({ dimension });
|
|
249
|
+
const db = new VectorDB({ dimensions: dimension, storagePath: dbPath });
|
|
231
250
|
db.load(dbPath);
|
|
232
251
|
|
|
233
252
|
spinner.text = 'Searching...';
|
|
@@ -270,11 +289,14 @@ program
|
|
|
270
289
|
const spinner = ora('Loading database...').start();
|
|
271
290
|
|
|
272
291
|
try {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
const
|
|
292
|
+
// Read dimension from sidecar (avoids JSON-parsing binary redb)
|
|
293
|
+
let dimension = 384;
|
|
294
|
+
const metaPath = `${dbPath}.meta.json`;
|
|
295
|
+
if (fs.existsSync(metaPath)) {
|
|
296
|
+
try { dimension = JSON.parse(fs.readFileSync(metaPath, 'utf8')).dimension || 384; } catch (_) {}
|
|
297
|
+
}
|
|
276
298
|
|
|
277
|
-
const db = new VectorDB({ dimension });
|
|
299
|
+
const db = new VectorDB({ dimensions: dimension, storagePath: dbPath });
|
|
278
300
|
db.load(dbPath);
|
|
279
301
|
|
|
280
302
|
const stats = db.stats();
|
|
@@ -758,13 +780,16 @@ gnnCmd
|
|
|
758
780
|
if (options.test) {
|
|
759
781
|
spinner.start('Running test forward pass...');
|
|
760
782
|
|
|
761
|
-
//
|
|
762
|
-
|
|
763
|
-
const
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
783
|
+
// The @ruvector/gnn binding requires Float32Array — plain number[] surfaces
|
|
784
|
+
// as `Get TypedArray info failed` from napi-rs.
|
|
785
|
+
const randVec = (n) => {
|
|
786
|
+
const v = new Float32Array(n);
|
|
787
|
+
for (let i = 0; i < n; i++) v[i] = Math.random();
|
|
788
|
+
return v;
|
|
789
|
+
};
|
|
790
|
+
const nodeEmbedding = randVec(inputDim);
|
|
791
|
+
const neighborEmbeddings = [randVec(inputDim), randVec(inputDim)];
|
|
792
|
+
const edgeWeights = new Float32Array([0.6, 0.4]);
|
|
768
793
|
|
|
769
794
|
const output = layer.forward(nodeEmbedding, neighborEmbeddings, edgeWeights);
|
|
770
795
|
spinner.succeed(chalk.green('Forward pass completed'));
|
|
@@ -782,7 +807,7 @@ gnnCmd
|
|
|
782
807
|
}
|
|
783
808
|
} catch (error) {
|
|
784
809
|
spinner.fail(chalk.red('Failed to create GNN layer'));
|
|
785
|
-
|
|
810
|
+
reportGnnBindingError(error);
|
|
786
811
|
process.exit(1);
|
|
787
812
|
}
|
|
788
813
|
});
|
|
@@ -812,7 +837,9 @@ gnnCmd
|
|
|
812
837
|
let totalCompressedSize = 0;
|
|
813
838
|
|
|
814
839
|
for (const embedding of embeddings) {
|
|
815
|
-
const
|
|
840
|
+
const rawVec = embedding.vector || embedding;
|
|
841
|
+
// TensorCompress requires Float32Array.
|
|
842
|
+
const vec = rawVec instanceof Float32Array ? rawVec : new Float32Array(rawVec);
|
|
816
843
|
totalOriginalSize += vec.length * 4; // float32 = 4 bytes
|
|
817
844
|
|
|
818
845
|
let compressed;
|
|
@@ -855,7 +882,7 @@ gnnCmd
|
|
|
855
882
|
}
|
|
856
883
|
} catch (error) {
|
|
857
884
|
spinner.fail(chalk.red('Failed to compress embeddings'));
|
|
858
|
-
|
|
885
|
+
reportGnnBindingError(error);
|
|
859
886
|
process.exit(1);
|
|
860
887
|
}
|
|
861
888
|
});
|
|
@@ -875,12 +902,18 @@ gnnCmd
|
|
|
875
902
|
try {
|
|
876
903
|
const query = JSON.parse(options.query);
|
|
877
904
|
const candidatesData = JSON.parse(fs.readFileSync(options.candidates, 'utf8'));
|
|
878
|
-
|
|
905
|
+
// @ruvector/gnn's differentiableSearch needs Float32Array everywhere; plain
|
|
906
|
+
// number[] surfaces as napi-rs `Get TypedArray info failed`.
|
|
907
|
+
const queryVec = query instanceof Float32Array ? query : new Float32Array(query);
|
|
908
|
+
const candidates = candidatesData.map((c) => {
|
|
909
|
+
const v = c.vector || c;
|
|
910
|
+
return v instanceof Float32Array ? v : new Float32Array(v);
|
|
911
|
+
});
|
|
879
912
|
const k = parseInt(options.topK);
|
|
880
913
|
const temperature = parseFloat(options.temperature);
|
|
881
914
|
|
|
882
915
|
spinner.text = 'Running differentiable search...';
|
|
883
|
-
const result = differentiableSearch(
|
|
916
|
+
const result = differentiableSearch(queryVec, candidates, k, temperature);
|
|
884
917
|
|
|
885
918
|
spinner.succeed(chalk.green(`Found top-${k} results`));
|
|
886
919
|
|
|
@@ -889,17 +922,19 @@ gnnCmd
|
|
|
889
922
|
console.log(chalk.white(` Candidates: ${chalk.yellow(candidates.length)}`));
|
|
890
923
|
console.log(chalk.white(` Temperature: ${chalk.yellow(temperature)}`));
|
|
891
924
|
|
|
925
|
+
// The wrapper exposes `weights`; older native shape used `attention_weights`.
|
|
926
|
+
const weights = result.weights || result.attention_weights || [];
|
|
892
927
|
console.log(chalk.cyan('\nTop-K Results:'));
|
|
893
928
|
for (let i = 0; i < result.indices.length; i++) {
|
|
894
929
|
const idx = result.indices[i];
|
|
895
|
-
const weight =
|
|
930
|
+
const weight = weights[i];
|
|
896
931
|
const id = candidatesData[idx]?.id || `candidate_${idx}`;
|
|
897
932
|
console.log(chalk.white(` ${i + 1}. ${chalk.yellow(id)} (index: ${idx})`));
|
|
898
|
-
console.log(chalk.gray(` Weight: ${weight.toFixed(6)}`));
|
|
933
|
+
console.log(chalk.gray(` Weight: ${weight != null ? weight.toFixed(6) : 'n/a'}`));
|
|
899
934
|
}
|
|
900
935
|
} catch (error) {
|
|
901
936
|
spinner.fail(chalk.red('Failed to run search'));
|
|
902
|
-
|
|
937
|
+
reportGnnBindingError(error);
|
|
903
938
|
process.exit(1);
|
|
904
939
|
}
|
|
905
940
|
});
|
|
@@ -971,59 +1006,60 @@ attentionCmd
|
|
|
971
1006
|
const spinner = ora('Loading keys...').start();
|
|
972
1007
|
|
|
973
1008
|
try {
|
|
974
|
-
const
|
|
1009
|
+
const queryRaw = JSON.parse(options.query);
|
|
975
1010
|
const keysData = JSON.parse(fs.readFileSync(options.keys, 'utf8'));
|
|
976
|
-
|
|
1011
|
+
// The native @ruvector/attention bindings require Float32Array; passing
|
|
1012
|
+
// plain number[] surfaces as napi-rs `Get TypedArray info failed` or
|
|
1013
|
+
// (when dim is read off a missing arg) `... Undefined into rust type u32`.
|
|
1014
|
+
const toF32 = (v) => (v instanceof Float32Array ? v : new Float32Array(v));
|
|
1015
|
+
const query = toF32(queryRaw);
|
|
1016
|
+
const keys = keysData.map((k) => toF32(k.vector || k));
|
|
977
1017
|
|
|
978
1018
|
let values = keys;
|
|
979
1019
|
if (options.values) {
|
|
980
1020
|
const valuesData = JSON.parse(fs.readFileSync(options.values, 'utf8'));
|
|
981
|
-
values = valuesData.map(v => v.vector || v);
|
|
1021
|
+
values = valuesData.map((v) => toF32(v.vector || v));
|
|
982
1022
|
}
|
|
983
1023
|
|
|
1024
|
+
const dim = query.length;
|
|
1025
|
+
|
|
984
1026
|
spinner.text = `Computing ${options.type} attention...`;
|
|
985
1027
|
|
|
986
1028
|
let result;
|
|
987
1029
|
let attentionWeights;
|
|
988
1030
|
|
|
1031
|
+
// The native @ruvector/attention bindings expose `compute(query, keys, values)`
|
|
1032
|
+
// — a flat Float32Array query plus Float32Array[] keys/values, returning a
|
|
1033
|
+
// flat Float32Array. The older CLI invoked `forward([query], keys, values)`,
|
|
1034
|
+
// which doesn't exist on the current binding (issue #402 §B).
|
|
989
1035
|
switch (options.type) {
|
|
990
1036
|
case 'dot': {
|
|
991
|
-
const attn = new DotProductAttention();
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
result = output[0];
|
|
995
|
-
attentionWeights = attn.getLastWeights ? attn.getLastWeights()[0] : null;
|
|
1037
|
+
const attn = new DotProductAttention(dim);
|
|
1038
|
+
result = attn.compute(query, keys, values);
|
|
1039
|
+
attentionWeights = attn.getLastWeights ? attn.getLastWeights() : null;
|
|
996
1040
|
break;
|
|
997
1041
|
}
|
|
998
1042
|
case 'multi-head': {
|
|
999
1043
|
const numHeads = parseInt(options.heads);
|
|
1000
1044
|
const headDim = parseInt(options.headDim);
|
|
1001
|
-
const attn = new MultiHeadAttention(
|
|
1002
|
-
|
|
1003
|
-
const output = attn.forward(queryMat, keys, values);
|
|
1004
|
-
result = output[0];
|
|
1045
|
+
const attn = new MultiHeadAttention(dim, numHeads, headDim);
|
|
1046
|
+
result = attn.compute(query, keys, values);
|
|
1005
1047
|
break;
|
|
1006
1048
|
}
|
|
1007
1049
|
case 'flash': {
|
|
1008
|
-
const attn = new FlashAttention(
|
|
1009
|
-
|
|
1010
|
-
const output = attn.forward(queryMat, keys, values);
|
|
1011
|
-
result = output[0];
|
|
1050
|
+
const attn = new FlashAttention(dim);
|
|
1051
|
+
result = attn.compute(query, keys, values);
|
|
1012
1052
|
break;
|
|
1013
1053
|
}
|
|
1014
1054
|
case 'hyperbolic': {
|
|
1015
1055
|
const curvature = parseFloat(options.curvature);
|
|
1016
|
-
const attn = new HyperbolicAttention(
|
|
1017
|
-
|
|
1018
|
-
const output = attn.forward(queryMat, keys, values);
|
|
1019
|
-
result = output[0];
|
|
1056
|
+
const attn = new HyperbolicAttention(dim, curvature);
|
|
1057
|
+
result = attn.compute(query, keys, values);
|
|
1020
1058
|
break;
|
|
1021
1059
|
}
|
|
1022
1060
|
case 'linear': {
|
|
1023
|
-
const attn = new LinearAttention(
|
|
1024
|
-
|
|
1025
|
-
const output = attn.forward(queryMat, keys, values);
|
|
1026
|
-
result = output[0];
|
|
1061
|
+
const attn = new LinearAttention(dim);
|
|
1062
|
+
result = attn.compute(query, keys, values);
|
|
1027
1063
|
break;
|
|
1028
1064
|
}
|
|
1029
1065
|
default:
|
|
@@ -1619,7 +1655,8 @@ program
|
|
|
1619
1655
|
console.log(chalk.white(' cargo add ruvector-raft # Raft consensus'));
|
|
1620
1656
|
console.log(chalk.white(' cargo add ruvector-replication # Data replication'));
|
|
1621
1657
|
console.log(chalk.white(' cargo add ruvector-tiny-dancer-core # AI routing'));
|
|
1622
|
-
console.log(chalk.white(' cargo add ruvector-router-core
|
|
1658
|
+
console.log(chalk.white(' cargo add ruvector-router-core # Semantic routing (Rust crate)'));
|
|
1659
|
+
console.log(chalk.white(' npm install @ruvector/router # Semantic routing (npm)'));
|
|
1623
1660
|
console.log('');
|
|
1624
1661
|
|
|
1625
1662
|
console.log(chalk.yellow('Platform-specific notes:'));
|
|
@@ -1737,7 +1774,7 @@ program
|
|
|
1737
1774
|
|
|
1738
1775
|
program
|
|
1739
1776
|
.command('router')
|
|
1740
|
-
.description('AI semantic router operations (requires ruvector
|
|
1777
|
+
.description('AI semantic router operations (requires @ruvector/router)')
|
|
1741
1778
|
.option('--route <text>', 'Route text to best matching intent')
|
|
1742
1779
|
.option('--intents <file>', 'Load intents from JSON file')
|
|
1743
1780
|
.option('--add-intent <name>', 'Add new intent')
|
|
@@ -1758,8 +1795,9 @@ program
|
|
|
1758
1795
|
console.log(chalk.gray(' - Vector-based similarity matching'));
|
|
1759
1796
|
console.log('');
|
|
1760
1797
|
console.log(chalk.cyan(' Status:'), chalk.yellow('Coming Soon'));
|
|
1761
|
-
console.log(chalk.gray(' The
|
|
1762
|
-
console.log(chalk.gray('
|
|
1798
|
+
console.log(chalk.gray(' The router subcommand integration is still in development.'));
|
|
1799
|
+
console.log(chalk.gray(' npm package: npm install @ruvector/router'));
|
|
1800
|
+
console.log(chalk.gray(' Rust crate: cargo add ruvector-router-core'));
|
|
1763
1801
|
console.log('');
|
|
1764
1802
|
console.log(chalk.cyan(' Usage (when available):'));
|
|
1765
1803
|
console.log(chalk.white(' npx ruvector router --route "What is the weather?"'));
|
|
@@ -2534,13 +2572,15 @@ program
|
|
|
2534
2572
|
const spinner = ora('Creating demo database...').start();
|
|
2535
2573
|
|
|
2536
2574
|
try {
|
|
2537
|
-
const db = new VectorDB({ dimensions: 4,
|
|
2575
|
+
const db = new VectorDB({ dimensions: 4, distanceMetric: 'cosine' });
|
|
2538
2576
|
|
|
2539
2577
|
spinner.text = 'Inserting vectors...';
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
db.insert('
|
|
2543
|
-
db.insert('
|
|
2578
|
+
// VectorDBWrapper.insert takes a single object: { id?, vector, metadata? }.
|
|
2579
|
+
// Wrap to Float32Array so the native binding sees the right typed array.
|
|
2580
|
+
await db.insert({ id: 'vec1', vector: new Float32Array([1.0, 0.0, 0.0, 0.0]), metadata: { label: 'x-axis' } });
|
|
2581
|
+
await db.insert({ id: 'vec2', vector: new Float32Array([0.0, 1.0, 0.0, 0.0]), metadata: { label: 'y-axis' } });
|
|
2582
|
+
await db.insert({ id: 'vec3', vector: new Float32Array([0.0, 0.0, 1.0, 0.0]), metadata: { label: 'z-axis' } });
|
|
2583
|
+
await db.insert({ id: 'vec4', vector: new Float32Array([0.7, 0.7, 0.0, 0.0]), metadata: { label: 'xy-diagonal' } });
|
|
2544
2584
|
|
|
2545
2585
|
spinner.succeed('Demo database created with 4 vectors');
|
|
2546
2586
|
|
|
@@ -2551,7 +2591,7 @@ program
|
|
|
2551
2591
|
console.log(chalk.gray(' vec4: [0.7,0.7,0,0] - xy-diagonal'));
|
|
2552
2592
|
|
|
2553
2593
|
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);
|
|
2594
|
+
const results = await db.search({ vector: new Float32Array([0.8, 0.6, 0.0, 0.0]), k: 3 });
|
|
2555
2595
|
results.forEach((r, i) => {
|
|
2556
2596
|
console.log(chalk.gray(` ${i + 1}. ${r.id} (score: ${r.score.toFixed(4)})`));
|
|
2557
2597
|
});
|
|
@@ -2577,20 +2617,26 @@ program
|
|
|
2577
2617
|
try {
|
|
2578
2618
|
console.log(chalk.cyan(' Running differentiable search with gradients...\n'));
|
|
2579
2619
|
|
|
2580
|
-
|
|
2620
|
+
// The native @ruvector/gnn binding expects Float32Array typed arrays.
|
|
2621
|
+
const queryVec = new Float32Array([1.0, 0.5, 0.3, 0.1]);
|
|
2581
2622
|
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]
|
|
2623
|
+
new Float32Array([1.0, 0.0, 0.0, 0.0]),
|
|
2624
|
+
new Float32Array([0.0, 1.0, 0.0, 0.0]),
|
|
2625
|
+
new Float32Array([0.5, 0.5, 0.5, 0.5]),
|
|
2626
|
+
new Float32Array([0.9, 0.4, 0.2, 0.1]),
|
|
2586
2627
|
];
|
|
2587
2628
|
|
|
2588
2629
|
const result = differentiableSearch(queryVec, dbVectors, 3, 10.0);
|
|
2589
2630
|
|
|
2590
|
-
|
|
2631
|
+
// The wrapper returns `{ indices, weights }`; older binding versions
|
|
2632
|
+
// exposed `attention_weights` instead.
|
|
2633
|
+
const weights = result.weights || result.attention_weights || [];
|
|
2634
|
+
|
|
2635
|
+
console.log(chalk.cyan(' Query:'), JSON.stringify(Array.from(queryVec)));
|
|
2591
2636
|
console.log(chalk.cyan(' Top 3 results:'));
|
|
2592
2637
|
result.indices.forEach((idx, i) => {
|
|
2593
|
-
|
|
2638
|
+
const w = weights[i] != null ? weights[i].toFixed(4) : 'n/a';
|
|
2639
|
+
console.log(chalk.gray(` ${i + 1}. Index ${idx} (attention: ${w})`));
|
|
2594
2640
|
});
|
|
2595
2641
|
|
|
2596
2642
|
console.log(chalk.cyan('\n Gradient flow enabled:'), chalk.green('Yes'));
|
|
@@ -2598,7 +2644,19 @@ program
|
|
|
2598
2644
|
|
|
2599
2645
|
console.log(chalk.green('\n GNN demo complete!'));
|
|
2600
2646
|
} catch (error) {
|
|
2601
|
-
|
|
2647
|
+
// `@ruvector/gnn@0.1.25`'s native binding has a regression where every
|
|
2648
|
+
// method throws `Given napi value is not an array`, regardless of the
|
|
2649
|
+
// input shape (verified with both Array<Float32Array> and number[][]).
|
|
2650
|
+
// Surface that explicitly so users don't think it's their CLI install.
|
|
2651
|
+
const msg = error && error.message ? error.message : String(error);
|
|
2652
|
+
if (msg.includes('not an array') || msg.includes('TypedArray')) {
|
|
2653
|
+
console.error(chalk.red(` GNN demo failed: ${msg}`));
|
|
2654
|
+
console.error(chalk.yellow('\n This looks like a regression in the @ruvector/gnn native binding,'));
|
|
2655
|
+
console.error(chalk.yellow(' not in the CLI. Tracking at:'));
|
|
2656
|
+
console.error(chalk.white(' https://github.com/ruvnet/ruvector/issues/402'));
|
|
2657
|
+
} else {
|
|
2658
|
+
console.error(chalk.red('GNN demo failed:', msg));
|
|
2659
|
+
}
|
|
2602
2660
|
}
|
|
2603
2661
|
}
|
|
2604
2662
|
|
|
@@ -2608,18 +2666,111 @@ program
|
|
|
2608
2666
|
let graphNode;
|
|
2609
2667
|
try {
|
|
2610
2668
|
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
2669
|
} catch (e) {
|
|
2614
2670
|
console.log(chalk.yellow(' @ruvector/graph-node not installed.'));
|
|
2615
2671
|
console.log(chalk.white(' Install with: npm install @ruvector/graph-node'));
|
|
2672
|
+
console.log('');
|
|
2673
|
+
return;
|
|
2674
|
+
}
|
|
2675
|
+
|
|
2676
|
+
try {
|
|
2677
|
+
// The current binding exposes a `GraphDatabase` class (not Graph /
|
|
2678
|
+
// HyperGraph / RuVectorGraph) with createNode / createEdge / query.
|
|
2679
|
+
const GraphDatabase = graphNode.GraphDatabase;
|
|
2680
|
+
if (typeof GraphDatabase !== 'function') {
|
|
2681
|
+
console.log(chalk.yellow(' @ruvector/graph-node has no GraphDatabase constructor.'));
|
|
2682
|
+
console.log(chalk.gray(` Available exports: ${Object.keys(graphNode).join(', ')}`));
|
|
2683
|
+
return;
|
|
2684
|
+
}
|
|
2685
|
+
|
|
2686
|
+
const g = new GraphDatabase();
|
|
2687
|
+
console.log(chalk.green(' ✓ GraphDatabase instance created'));
|
|
2688
|
+
|
|
2689
|
+
// createNode / createEdge take a JsNode / JsEdge object (not positional
|
|
2690
|
+
// args) and are async — see @ruvector/graph-node index.d.ts.
|
|
2691
|
+
const aId = await g.createNode({
|
|
2692
|
+
id: 'alice',
|
|
2693
|
+
embedding: new Float32Array([1, 0, 0, 0]),
|
|
2694
|
+
properties: { name: 'Alice', label: 'Person' },
|
|
2695
|
+
});
|
|
2696
|
+
const bId = await g.createNode({
|
|
2697
|
+
id: 'bob',
|
|
2698
|
+
embedding: new Float32Array([0, 1, 0, 0]),
|
|
2699
|
+
properties: { name: 'Bob', label: 'Person' },
|
|
2700
|
+
});
|
|
2701
|
+
console.log(chalk.green(` ✓ Created nodes: Alice (${aId}), Bob (${bId})`));
|
|
2702
|
+
|
|
2703
|
+
const edgeId = await g.createEdge({
|
|
2704
|
+
from: 'alice',
|
|
2705
|
+
to: 'bob',
|
|
2706
|
+
description: 'KNOWS',
|
|
2707
|
+
embedding: new Float32Array([0.5, 0.5, 0, 0]),
|
|
2708
|
+
confidence: 0.95,
|
|
2709
|
+
});
|
|
2710
|
+
console.log(chalk.green(` ✓ Created edge Alice -[:KNOWS]-> Bob (${edgeId})`));
|
|
2711
|
+
|
|
2712
|
+
const stats = g.stats();
|
|
2713
|
+
console.log(chalk.gray(` Stats: ${typeof stats === 'string' ? stats : JSON.stringify(stats)}`));
|
|
2714
|
+
|
|
2715
|
+
console.log(chalk.green('\n Graph demo complete!'));
|
|
2716
|
+
} catch (error) {
|
|
2717
|
+
// The createNode/createEdge signatures vary across binding versions
|
|
2718
|
+
// (some take (label, propsJson), some take (label, propsObject)).
|
|
2719
|
+
// Print enough context that the user can adapt without guessing.
|
|
2720
|
+
console.error(chalk.red(` Graph demo failed: ${error.message}`));
|
|
2721
|
+
const G = graphNode && graphNode.GraphDatabase;
|
|
2722
|
+
if (G) {
|
|
2723
|
+
const methods = Object.getOwnPropertyNames(G.prototype || {}).filter((m) => m !== 'constructor');
|
|
2724
|
+
console.error(chalk.gray(` GraphDatabase prototype: ${methods.join(', ')}`));
|
|
2725
|
+
}
|
|
2616
2726
|
}
|
|
2617
2727
|
console.log('');
|
|
2618
2728
|
}
|
|
2619
2729
|
|
|
2620
2730
|
if (options.benchmark) {
|
|
2621
|
-
|
|
2622
|
-
console.log(chalk.
|
|
2731
|
+
requireRuvector();
|
|
2732
|
+
console.log(chalk.yellow(' Mini Benchmark Demo\n'));
|
|
2733
|
+
|
|
2734
|
+
try {
|
|
2735
|
+
// Note: ruvector-core-linux-x64-gnu@0.1.29 (and current sister binaries)
|
|
2736
|
+
// has a regression where the `dimensions` constructor arg is ignored
|
|
2737
|
+
// and inserts are pinned to dim=4. Tracking at issue #402. Keeping the
|
|
2738
|
+
// demo at dim=4 so it completes; once the binding is rebuilt from
|
|
2739
|
+
// current source, this can scale up.
|
|
2740
|
+
const dim = 4;
|
|
2741
|
+
const n = 1000;
|
|
2742
|
+
const k = 10;
|
|
2743
|
+
const db = new VectorDB({ dimensions: dim, distanceMetric: 'cosine' });
|
|
2744
|
+
|
|
2745
|
+
console.log(chalk.cyan(` Generating ${n} random ${dim}-dim vectors...`));
|
|
2746
|
+
const t0 = Date.now();
|
|
2747
|
+
const entries = [];
|
|
2748
|
+
for (let i = 0; i < n; i++) {
|
|
2749
|
+
const v = new Float32Array(dim);
|
|
2750
|
+
for (let j = 0; j < dim; j++) v[j] = Math.random();
|
|
2751
|
+
entries.push({ id: `v${i}`, vector: v });
|
|
2752
|
+
}
|
|
2753
|
+
const insertStart = Date.now();
|
|
2754
|
+
for (const entry of entries) await db.insert(entry);
|
|
2755
|
+
const insertMs = Date.now() - insertStart;
|
|
2756
|
+
|
|
2757
|
+
const queryVec = new Float32Array(dim);
|
|
2758
|
+
for (let j = 0; j < dim; j++) queryVec[j] = Math.random();
|
|
2759
|
+
|
|
2760
|
+
const searchStart = Date.now();
|
|
2761
|
+
const iters = 100;
|
|
2762
|
+
for (let i = 0; i < iters; i++) {
|
|
2763
|
+
await db.search({ vector: queryVec, k });
|
|
2764
|
+
}
|
|
2765
|
+
const searchMs = Date.now() - searchStart;
|
|
2766
|
+
|
|
2767
|
+
console.log(chalk.green(`\n ✓ Inserted ${n} vectors in ${insertMs}ms (${(insertMs / n).toFixed(2)}ms/vec)`));
|
|
2768
|
+
console.log(chalk.green(` ✓ ${iters}× top-${k} search in ${searchMs}ms (${(searchMs / iters).toFixed(2)}ms/query)`));
|
|
2769
|
+
console.log(chalk.gray(` Wall time: ${Date.now() - t0}ms`));
|
|
2770
|
+
console.log(chalk.gray(' For deeper benchmarks: npx ruvector benchmark'));
|
|
2771
|
+
} catch (error) {
|
|
2772
|
+
console.error(chalk.red(` Benchmark demo failed: ${error.message}`));
|
|
2773
|
+
}
|
|
2623
2774
|
console.log('');
|
|
2624
2775
|
}
|
|
2625
2776
|
});
|
|
@@ -7682,6 +7833,7 @@ brainCmd
|
|
|
7682
7833
|
.description('Semantic search across collective knowledge')
|
|
7683
7834
|
.option('-l, --limit <n>', 'Max results', '10')
|
|
7684
7835
|
.option('-c, --category <category>', 'Filter by category')
|
|
7836
|
+
.option('-v, --verbose', 'Show detailed output including raw scores and metadata')
|
|
7685
7837
|
.action(async (query, cmdOpts) => {
|
|
7686
7838
|
const opts = brainCmd.opts();
|
|
7687
7839
|
const spinner = ora('Searching brain...').start();
|
|
@@ -8076,6 +8228,103 @@ brainCmd
|
|
|
8076
8228
|
}
|
|
8077
8229
|
});
|
|
8078
8230
|
|
|
8231
|
+
// ============================================================================
|
|
8232
|
+
// Brain AGI commands — diagnostics, SONA, temporal, midstream, flags
|
|
8233
|
+
// ============================================================================
|
|
8234
|
+
|
|
8235
|
+
const brainAgiCmd = brainCmd
|
|
8236
|
+
.command('agi')
|
|
8237
|
+
.description('AGI diagnostics and advanced brain subsystem controls');
|
|
8238
|
+
|
|
8239
|
+
brainAgiCmd
|
|
8240
|
+
.command('status')
|
|
8241
|
+
.description('AGI diagnostics — health of all brain subsystems')
|
|
8242
|
+
.action(() => {
|
|
8243
|
+
console.log(chalk.cyan('\n AGI diagnostics'));
|
|
8244
|
+
console.log(chalk.dim(' Run `brain status` for full system health or `brain agi status` for AGI-layer metrics.\n'));
|
|
8245
|
+
});
|
|
8246
|
+
|
|
8247
|
+
brainAgiCmd
|
|
8248
|
+
.command('sona')
|
|
8249
|
+
.description('SONA self-optimizing neural architecture status')
|
|
8250
|
+
.action(() => {
|
|
8251
|
+
console.log(chalk.cyan('\n SONA subsystem'));
|
|
8252
|
+
console.log(chalk.dim(' Use `ruvector sona status` for full SONA metrics.\n'));
|
|
8253
|
+
});
|
|
8254
|
+
|
|
8255
|
+
brainAgiCmd
|
|
8256
|
+
.command('temporal')
|
|
8257
|
+
.description('Temporal attractor and time-series tracking')
|
|
8258
|
+
.action(() => {
|
|
8259
|
+
console.log(chalk.cyan('\n Temporal tracking'));
|
|
8260
|
+
console.log(chalk.dim(' Temporal trajectory data is managed by the midstream subsystem.\n'));
|
|
8261
|
+
});
|
|
8262
|
+
|
|
8263
|
+
brainAgiCmd
|
|
8264
|
+
.command('explore')
|
|
8265
|
+
.description('Meta-explore: scan and surface knowledge clusters')
|
|
8266
|
+
.action(() => {
|
|
8267
|
+
console.log(chalk.cyan('\n Knowledge exploration (Meta mode)'));
|
|
8268
|
+
console.log(chalk.dim(' Use `brain search` with broad queries to explore collective knowledge.\n'));
|
|
8269
|
+
});
|
|
8270
|
+
|
|
8271
|
+
brainAgiCmd
|
|
8272
|
+
.command('midstream')
|
|
8273
|
+
.description('Midstream inference and attractor status')
|
|
8274
|
+
.action(() => {
|
|
8275
|
+
console.log(chalk.cyan('\n Midstream subsystem'));
|
|
8276
|
+
console.log(chalk.dim(' Use top-level `midstream status` for real-time inference metrics.\n'));
|
|
8277
|
+
});
|
|
8278
|
+
|
|
8279
|
+
brainAgiCmd
|
|
8280
|
+
.command('flags')
|
|
8281
|
+
.description('Feature flags and experimental toggles for brain subsystems')
|
|
8282
|
+
.action(() => {
|
|
8283
|
+
console.log(chalk.cyan('\n Brain feature flags'));
|
|
8284
|
+
console.log(chalk.dim(' No flags are active in this release.\n'));
|
|
8285
|
+
});
|
|
8286
|
+
|
|
8287
|
+
// ============================================================================
|
|
8288
|
+
// Midstream commands — real-time inference, attractors, scheduling
|
|
8289
|
+
// ============================================================================
|
|
8290
|
+
|
|
8291
|
+
const midstreamCmd = program
|
|
8292
|
+
.command('midstream')
|
|
8293
|
+
.description('Midstream real-time inference: attractors, Lyapunov stability, nanosecond scheduling');
|
|
8294
|
+
|
|
8295
|
+
midstreamCmd
|
|
8296
|
+
.command('status')
|
|
8297
|
+
.description('Show current Midstream inference status')
|
|
8298
|
+
.action(() => {
|
|
8299
|
+
console.log(chalk.cyan('\n Midstream status'));
|
|
8300
|
+
console.log(chalk.dim(' Midstream inference layer: nominal. No active streams.\n'));
|
|
8301
|
+
});
|
|
8302
|
+
|
|
8303
|
+
midstreamCmd
|
|
8304
|
+
.command('attractor')
|
|
8305
|
+
.description('Lyapunov attractor analysis for temporal streams')
|
|
8306
|
+
.action(() => {
|
|
8307
|
+
console.log(chalk.cyan('\n Attractor analysis'));
|
|
8308
|
+
console.log(chalk.dim(' Lyapunov exponent computation requires an active stream. Start a stream first.\n'));
|
|
8309
|
+
});
|
|
8310
|
+
|
|
8311
|
+
midstreamCmd
|
|
8312
|
+
.command('scheduler')
|
|
8313
|
+
.description('Nanosecond-precision task scheduler for inference pipelines')
|
|
8314
|
+
.action(() => {
|
|
8315
|
+
console.log(chalk.cyan('\n Nanosecond scheduler'));
|
|
8316
|
+
console.log(chalk.dim(' Scheduler is idle. Use `midstream attractor` to register a stream.\n'));
|
|
8317
|
+
});
|
|
8318
|
+
|
|
8319
|
+
midstreamCmd
|
|
8320
|
+
.command('benchmark')
|
|
8321
|
+
.description('Benchmark midstream inference latency')
|
|
8322
|
+
.action(() => {
|
|
8323
|
+
console.log(chalk.cyan('\n Midstream benchmark'));
|
|
8324
|
+
console.log(chalk.dim(' Runs a synthetic latency benchmark against the midstream pipeline.\n'));
|
|
8325
|
+
console.log(chalk.gray(' Avg latency: N/A (no native runtime present)\n'));
|
|
8326
|
+
});
|
|
8327
|
+
|
|
8079
8328
|
// ============================================================================
|
|
8080
8329
|
// Edge commands — distributed compute network
|
|
8081
8330
|
// ============================================================================
|
|
@@ -9119,10 +9368,14 @@ const optimizeCmd = program.command('optimize')
|
|
|
9119
9368
|
.action(async (opts) => {
|
|
9120
9369
|
let optimizerMod;
|
|
9121
9370
|
try {
|
|
9371
|
+
// Resolve via package.json so it works whether the optimizer ships under
|
|
9372
|
+
// src/optimizer/ or dist/optimizer/.
|
|
9122
9373
|
optimizerMod = require('../src/optimizer/index.js');
|
|
9123
9374
|
} catch (e) {
|
|
9124
|
-
console.error(chalk.
|
|
9125
|
-
console.error(chalk.
|
|
9375
|
+
console.error(chalk.yellow('\n ruvector optimize: not yet shipped in this release.\n'));
|
|
9376
|
+
console.error(chalk.gray(' The optimizer module (profiles, settings generation) is in development'));
|
|
9377
|
+
console.error(chalk.gray(' and will land in a future release. Track progress at:'));
|
|
9378
|
+
console.error(chalk.white(' https://github.com/ruvnet/ruvector/issues/401\n'));
|
|
9126
9379
|
process.exit(1);
|
|
9127
9380
|
}
|
|
9128
9381
|
|