-
Notifications
You must be signed in to change notification settings - Fork 340
Description
Summary
The NAPI bindings in @ruvector/attention and @ruvector/gnn packages are failing with type conversion errors when called from TypeScript/JavaScript. The error message indicates that Rust is receiving Object types when it expects primitive types like f64.
Error Message:
Failed to convert napi value Object into rust type f64
Affected Functions
@ruvector/gnn Package
1. hierarchicalForward()
- Error: "Failed to convert napi value Object into rust type f64"
- Location: Called from
RuVectorLearning.enhanceHierarchical()in AgentDB - Current binding signature (
crates/ruvector-gnn-node/src/lib.rs:364-368):
#[napi]
pub fn hierarchical_forward(
query: Vec<f64>,
layer_embeddings: Vec<Vec<Vec<f64>>>,
gnn_layers_json: Vec<String>,
) -> Result<Vec<f64>>- Parameters being passed from JS:
hierarchicalForward(
Array.from(query), // Array<number> from Float32Array
layerEmbeddings.map(layer => // Array<Array<Array<number>>>
layer.map(e => Array.from(e))
),
[layerJson] // Array<string> - JSON serialized layer
)@ruvector/attention Package
2. Attention Mechanisms
All attention mechanisms use Float32Array which works correctly, but there may be edge cases with type coercion:
multiHeadAttention()- UsesFloat32ArraycorrectlyflashAttention()- UsesFloat32ArraycorrectlylinearAttention()- UsesFloat32ArraycorrectlyhyperbolicAttention()- UsesFloat32ArraycorrectlymoeAttention()- UsesFloat32Arraycorrectly
Current binding signature (npm/node_modules/@ruvector/attention/src/attention.rs:145-161):
#[napi]
pub fn compute(
&self,
query: Float32Array,
keys: Vec<Float32Array>,
values: Vec<Float32Array>,
) -> Result<Float32Array>Root Cause Analysis
The issue appears to be in the NAPI-RS bindings where:
-
Array Type Mismatch: The
hierarchicalForwardfunction expectsVec<f64>but JavaScript'sArray.from(Float32Array)produces anArray<number>which NAPI-RS may interpret asObjectrather thanVec<f64>. -
Nested Array Handling: The deeply nested array structure
Array<Array<Array<number>>>forlayerEmbeddingsmay not be properly converted through the NAPI boundary when usingVec<Vec<Vec<f64>>>. -
Type Coercion Path: NAPI-RS attempts to convert JS arrays to Rust
Vec<f64>, but when the array contains objects or the nesting is complex, it may fail to recognize the proper conversion path.
Expected Behavior
The NAPI bindings should:
- Accept standard JavaScript types (
Array,number,Float32Array) - Properly convert nested array structures
- Handle JSON strings or require pre-parsed objects (with clear documentation)
- Provide clear type errors when incorrect types are passed
Current Workaround
AgentDB has implemented graceful fallback that returns the original query when NAPI calls fail:
try {
const result = this.hierarchicalForward(
Array.from(query),
layerEmbeddings.map(layer => layer.map(e => Array.from(e))),
[layerJson]
);
return new Float32Array(result);
} catch (error) {
console.warn(`[RuVectorLearning] Hierarchical enhancement failed: ${(error as Error).message}`);
return query; // Fallback to original query
}Reproduction Steps
- Install
@ruvector/gnnpackage - Create a
RuvectorLayerand serialize to JSON:
const layer = new RuvectorLayer(128, 256, 4, 0.1);
const layerJson = layer.toJson();- Call
hierarchicalForward()with array parameters:
const query = Array.from(new Float32Array([1.0, 2.0, 3.0, ...]));
const layerEmbeddings = [[[1.0, 2.0], [3.0, 4.0]]];
const result = hierarchicalForward(query, layerEmbeddings, [layerJson]);- Observe NAPI type conversion error
Environment
- Node.js: v18+
- TypeScript: 5.7.2
- Platform: Linux (also affects macOS/Windows)
- Package Versions:
@ruvector/gnn: Latest@ruvector/attention: v0.1.1ruvector: v0.1.24
Suggested Fixes
Option 1: Accept Multiple Input Types via Either
Use NAPI-RS Either to accept both Float32Array and Vec<f64>:
use napi::Either;
#[napi]
pub fn hierarchical_forward(
query: Either<Float32Array, Vec<f64>>,
layer_embeddings: Vec<Vec<Vec<f64>>>,
gnn_layers_json: Vec<String>,
) -> Result<Vec<f64>> {
let query_vec: Vec<f32> = match query {
Either::A(arr) => arr.to_vec(),
Either::B(vec) => vec.iter().map(|&x| x as f32).collect(),
};
// ...
}Option 2: Use Float32Array Consistently
Change the signature to use Float32Array like the attention mechanisms:
#[napi]
pub fn hierarchical_forward(
query: Float32Array,
layer_embeddings: Vec<Vec<Float32Array>>, // Flatten one level
gnn_layers_json: Vec<String>,
) -> Result<Float32Array>Option 3: Add TypeScript Wrapper with Validation
Provide a TypeScript wrapper that validates and converts types:
// Export from @ruvector/gnn
export function prepareHierarchicalInput(
query: Float32Array | number[],
embeddings: Float32Array[][] | number[][][]
): PreparedInput {
return {
query: query instanceof Float32Array ? query : new Float32Array(query),
embeddings: embeddings.map(layer =>
layer.map(e => e instanceof Float32Array ? e : new Float32Array(e))
)
};
}Option 4: Improve Error Messages
Add runtime type checking with clear error messages:
#[napi]
pub fn hierarchical_forward(
query: JsUnknown,
layer_embeddings: JsUnknown,
gnn_layers_json: Vec<String>,
) -> Result<Vec<f64>> {
// Validate query type
let query_vec = extract_number_array(query)
.map_err(|_| Error::new(
Status::InvalidArg,
"query must be Array<number> or Float32Array"
))?;
// ...
}Additional Context
- The errors only occur when optional dependencies are installed
- When
@ruvector/gnnor@ruvector/attentionare not installed, AgentDB gracefully falls back to JavaScript implementations which work correctly - This confirms the issue is specifically in the NAPI bindings, not the calling code
- The attention mechanisms in
@ruvector/attentionuseFloat32Arraydirectly and work correctly
Impact
- Severity: Medium - Features degrade gracefully but advanced attention/GNN features are unavailable
- Workaround: Available (fallback to JS implementations)
- Affected Users: Anyone using the NAPI bindings in Node.js environments
Related Files
crates/ruvector-gnn-node/src/lib.rs:364-396-hierarchical_forwardimplementationnpm/node_modules/@ruvector/attention/src/attention.rs- Attention mechanism bindings (reference for workingFloat32Arrayusage)npm/node_modules/@ruvector/gnn/src/lib.rs- Published GNN bindings
Labels
bug, napi-rs, type-conversion, gnn, attention