fix(ruvector-cli): real demo + binding-drift fixes for v0.2.25 (#400, #402)#404
Merged
fix(ruvector-cli): real demo + binding-drift fixes for v0.2.25 (#400, #402)#404
Conversation
…402) Follow-up to #403. Addresses the runtime-side issues from #400 (`ruvector demo` modes) and #402 §A/§B (VectorDB CRUD + GNN/attention typed-array errors) that needed binding-surface investigation. ## Changes ### `VectorDBWrapper`: normalize distance metric (§A root cause) `@ruvector/core`'s `JsDistanceMetric` enum is PascalCase (`Euclidean | Cosine | DotProduct | Manhattan`), but every CLI call site passes lowercase shorthand (`'cosine'`, `'euclidean'`, `'dot'`). The native binding rejects lowercase with: value `"cosine"` does not match any variant of enum `JsDistanceMetric` on JsDbOptions.distanceMetric Add a `normalizeMetric()` helper in `src/index.ts` that maps both casing *and* common aliases (`l2`, `dot`, `dotproduct`, `innerproduct`, `l1`) to the enum variant. Also accept `metric` as a constructor alias for `distanceMetric` so the CLI's existing `{metric: ...}` shape works without changing every call site. ### `demo --basic`: realign with current `VectorDb` API (§A surface) Old code: db.insert('vec1', [1.0, 0.0, 0.0, 0.0], { label: 'x-axis' }); const r = db.search([0.8, 0.6, 0, 0], 3); Current `VectorDBWrapper` (and the underlying `@ruvector/core` binding) takes a single object: await db.insert({ id: 'vec1', vector: new Float32Array([...]), metadata: { label: 'x-axis' } }); const r = await db.search({ vector: new Float32Array([...]), k: 3 }); Updated all four insert calls + the search call accordingly. Verified locally — vec4 (closest to [0.8, 0.6]) is correctly returned first. ### `demo --gnn`: Float32Array + binding-bug surfaceability Two issues: 1. CLI passed plain `number[]`; binding requires `Float32Array`. Fixed. 2. `@ruvector/gnn-linux-x64-gnu@0.1.25` has a published-binding regression where every method (`differentiableSearch`, `RuvectorLayer.forward`, `TensorCompress.compress`) throws `Given napi value is not an array` regardless of input shape — verified with both `Array<Float32Array>` and `number[][]`. This is a binary-side bug, not fixable from the CLI. Added `reportGnnBindingError()` helper that detects the error pattern and surfaces a pointer at #402 so users don't waste time debugging their own install. Wired it into all three GNN command error handlers (`gnn layer --test`, `gnn compress`, `gnn search`) and the demo. Also fixed `result.attention_weights` → `result.weights` (the wrapper shape; `attention_weights` was the older binding shape) with a fallback that handles both. ### `demo --graph`: real round-trip via `GraphDatabase` Was a stub printing "Full graph demo coming soon". `@ruvector/graph-node` exposes a `GraphDatabase` class with `createNode({ id, embedding, properties })`, `createEdge({ from, to, description, embedding, confidence })`, and `stats()` — all async. Implemented a tiny Alice -[:KNOWS]-> Bob round-trip using the actual API surface. ### `demo --benchmark`: real inline benchmark (with workaround) Was redirecting to `npx ruvector benchmark`. Implemented an inline 1000-vector / 100-query mini-benchmark. Pinned to `dim=4` because `ruvector-core-linux-x64-gnu@0.1.29` has a regression where the `dimensions` constructor arg is ignored — every `VectorDb` instance reports `expected 4` regardless of what's passed (verified by constructing fresh instances with various dims). Tracked at #402. Once that binding is rebuilt, `dim` can scale up. ### `attention compute`: align with current `compute()` surface (§B) The CLI's old switch invoked `attn.forward([query], keys, values)`, but every current `@ruvector/attention` class exposes `compute(query, keys, values)` instead — `forward` doesn't exist. Also the query must be a flat `Float32Array`, not `[query]` matrix. Reproduces the user's `Failed to convert napi value Undefined into rust type u32` and `Get TypedArray info failed` errors directly. Replaced all five branches (`dot | multi-head | flash | hyperbolic | linear`) with the correct `compute()` invocation + Float32Array conversion. Verified locally: $ node bin/cli.js attention compute -q "[1,0,0,0]" -k keys.json -t dot ✔ Attention computed (dot) Output: [0.6225, 0.3775, 0, 0...] ### `gnn layer --test` / `gnn compress` / `gnn search`: typed-array conversion All three commands previously passed plain `number[]` where the binding needs `Float32Array`. Converted at the call sites + added the `reportGnnBindingError` hook so users see the upstream pointer when they hit the binding-side regression. ## Verification ``` $ node bin/cli.js demo --basic Searching for nearest to [0.8, 0.6, 0, 0]: 1. vec4 (score: 0.0101) ✓ correct nearest 2. vec1 (score: 0.2000) 3. vec2 (score: 0.4000) Demo complete! $ node bin/cli.js demo --gnn GNN demo failed: Given napi value is not an array Note: this is a known regression in the @ruvector/gnn native binding… #402 $ node bin/cli.js demo --graph ✓ GraphDatabase instance created ✓ Created nodes: Alice (alice), Bob (bob) ✓ Created edge Alice -[:KNOWS]-> Bob (uuid) Graph demo complete! $ node bin/cli.js demo --benchmark ✓ Inserted 1000 vectors in 126ms (0.13ms/vec) ✓ 100× top-10 search in 51ms (0.51ms/query) $ node bin/cli.js attention compute -q "[1,0,0,0]" -k keys.json -t dot ✔ Attention computed (dot) $ npm run verify-dist verify-dist: 13 dist path(s) present. ``` Version bumped 0.2.24 → 0.2.25. ## Out of scope (binding-side rebuilds needed) - `@ruvector/gnn` published bindings throw on every call (binding bug). - `@ruvector/core` published bindings ignore `dimensions` constructor arg (binding bug). Both need a rebuild from current source — the Rust source in this repo shows correct independent state, but the published `.node` files have the regression. Rebuild and republish are tracked separately.
This was referenced Apr 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #403. Fixes the runtime-side issues from #400 (
ruvector demomodes) and #402 §A/§B (VectorDB CRUD + GNN/attention typed-array errors) — the bits that needed binding-surface investigation.Changes
VectorDBWrapper: normalize distance metric (§A root cause)Native
JsDistanceMetricenum is PascalCase (Cosine | Euclidean | DotProduct | Manhattan); CLI passes lowercase shorthand. AddednormalizeMetric()insrc/index.tsthat maps casing + common aliases (l2,dot,dotproduct,innerproduct,l1) and acceptsmetricas a constructor alias fordistanceMetric.demo --basic: realign with current API (§A surface)Old:
db.insert('vec1', [1.0, 0.0, 0.0, 0.0], { label: ... })(positional).Now:
await db.insert({ id, vector: new Float32Array(...), metadata: {...} })— matching the wrapper's actual signature.demo --gnn: typed-array fix + binding-bug surfaceFloat32Arrayeverywhere; handle bothresult.weights(wrapper) andresult.attention_weights(older shape).@ruvector/gnn@0.1.25has a published-binding regression where every method throwsGiven napi value is not an arrayregardless of input shape. AddedreportGnnBindingError()helper that detects the pattern and points at ruvector@0.2.23: data-plane broken — VectorDB CRUD, GNN, attention, embed, rvf, benchmark all fail #402.demo --graph: real round-trip viaGraphDatabaseWas "coming soon" stub. Implemented Alice -[:KNOWS]-> Bob using
createNode({id, embedding, properties})/createEdge({from, to, description, embedding, confidence}).demo --benchmark: real inline benchmarkWas a redirect to
ruvector benchmark. Implemented 1000-insert / 100-query mini-bench. Pinned todim=4becauseruvector-core@0.1.29has a regression that ignores thedimensionsconstructor arg — once the binding is rebuilt,dimcan scale up.attention compute: align with current API (§B)CLI invoked
attn.forward([query], keys, values). Current@ruvector/attentionclasses exposecompute(query, keys, values)—forwarddoesn't exist. Replaced all five branches; query must be flatFloat32Array, not[query]. Reproduces and fixes user'sUndefined into rust type u32/Get TypedArray info failederrors.gnn layer --test/compress/search: typed-array conversionAll three previously passed
number[]where the binding needsFloat32Array. Converted at call sites + wiredreportGnnBindingErrorso users see the upstream pointer when they hit the binding-side regression.Verification
Version bumped 0.2.24 → 0.2.25.
Out of scope (binding-side rebuilds tracked separately)
Two published native bindings have regressions that the CLI can detect but not fix:
@ruvector/gnn@0.1.25(and platform pkgs)Given napi value is not an arrayruvector-core@0.1.29(and platform pkgs)dimensionsarg ignored, all inserts pinned to dim=4The Rust source in this repo shows correct behavior — the published
.nodeartifacts are stale. Rebuild + republish is tracked at #402.Closes #400 (demo modes runtime). Partially addresses #402 (§A/§B CLI-side fixed; binding-side rebuilds tracked).