2454c83e82
- vector.rs: replace flat O(n) scan with instant-distance HNSW for stores >= 100 nodes; flat scan retained as fallback for small graphs; dirty-flag persistence in sled triggers index rebuild only when nodes are added - consolidation.rs: Episodic → Semantic promotion based on activation_count and salience_floor thresholds; global decay pass after each cycle; ConsolidationConfig + ConsolidationReport types; 8 tests - migration.rs: reads Neuron SQLite (memory_nodes, knowledge_entries, graph_edges) and writes to Engram sled; placeholder unit-vector embeddings with TODO for ONNX; 5 tests including full in-memory DB roundtrip - crates/engram-migrate: CLI binary (engram-migrate --sqlite / --output) - crates/engram-jni: JNI cdylib exposing open/close/put_node/get_node/ activate/search_embedding/touch/decay/node_count/edge_count via Java_ai_neuron_engram_EngramDb_* entry points; 6 tests - bindings/kotlin: EngramDb.kt (AutoCloseable JNI wrapper), EngramNode, EngramEdge, ActivatedNode, EngramTypes; build.gradle.kts; settings.gradle.kts - bindings/typescript: engram-wasm crate (wasm-bindgen, serde-wasm-bindgen); WasmEngramDb with in-memory backend (sled not available in WASM); TypeScript wrapper (index.ts, types.ts, package.json, tsconfig.json) - bindings/go: engram.go (CGo wrapper), engram.h (C header), engram_test.go (4 tests covering open/close/put_node/get_node/node_count/decay); go.mod - engram-core: wasm feature gate for in-memory backend; mem_storage.rs; activation.activate_mem for WASM path; Node::with_id helper; salience.rs doctest fixed (text block) - examples/basic.rs: consolidation section added - examples/migrate.rs: migration API demonstration Build: cargo build --workspace -- zero warnings, zero errors Tests: 38 pass (25 engram-core + 7 engram-ffi + 6 engram-jni)
131 lines
2.7 KiB
Go
131 lines
2.7 KiB
Go
// Package engram basic test.
|
|
//
|
|
// NOTE: This test requires the FFI shared library to be compiled first:
|
|
//
|
|
// cargo build --package engram-ffi --release
|
|
//
|
|
// Then run:
|
|
//
|
|
// DYLD_LIBRARY_PATH=../../target/release go test ./...
|
|
// # or on Linux:
|
|
// LD_LIBRARY_PATH=../../target/release go test ./...
|
|
package engram
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
// TestOpenClose verifies that a database can be opened and closed without errors.
|
|
func TestOpenClose(t *testing.T) {
|
|
dir := t.TempDir()
|
|
db, err := Open(filepath.Join(dir, "test-engram"))
|
|
if err != nil {
|
|
t.Fatalf("Open: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
n, err := db.NodeCount()
|
|
if err != nil {
|
|
t.Fatalf("NodeCount: %v", err)
|
|
}
|
|
if n != 0 {
|
|
t.Errorf("expected 0 nodes, got %d", n)
|
|
}
|
|
}
|
|
|
|
// TestPutGetNode verifies node storage and retrieval roundtrip.
|
|
func TestPutGetNode(t *testing.T) {
|
|
dir := t.TempDir()
|
|
db, err := Open(filepath.Join(dir, "test-engram"))
|
|
if err != nil {
|
|
t.Fatalf("Open: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
input := &NodeInput{
|
|
Content: "Spreading activation is the core retrieval mechanism",
|
|
NodeType: "Concept",
|
|
Tier: "Semantic",
|
|
Importance: 0.9,
|
|
Embedding: []float32{0.1, 0.2, 0.3, 0.4},
|
|
}
|
|
|
|
id, err := db.PutNode(input)
|
|
if err != nil {
|
|
t.Fatalf("PutNode: %v", err)
|
|
}
|
|
if id == "" {
|
|
t.Fatal("expected non-empty UUID")
|
|
}
|
|
|
|
node, err := db.GetNode(id)
|
|
if err != nil {
|
|
t.Fatalf("GetNode: %v", err)
|
|
}
|
|
if node == nil {
|
|
t.Fatal("expected node, got nil")
|
|
}
|
|
if node.Content != input.Content {
|
|
t.Errorf("content mismatch: got %q, want %q", node.Content, input.Content)
|
|
}
|
|
}
|
|
|
|
// TestNodeCount verifies node count increments.
|
|
func TestNodeCount(t *testing.T) {
|
|
dir := t.TempDir()
|
|
db, err := Open(filepath.Join(dir, "test-engram"))
|
|
if err != nil {
|
|
t.Fatalf("Open: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
for i := 0; i < 3; i++ {
|
|
_, err := db.PutNode(&NodeInput{
|
|
Content: "node content",
|
|
Embedding: []float32{float32(i), 0.0, 0.0},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("PutNode[%d]: %v", i, err)
|
|
}
|
|
}
|
|
|
|
n, err := db.NodeCount()
|
|
if err != nil {
|
|
t.Fatalf("NodeCount: %v", err)
|
|
}
|
|
if n != 3 {
|
|
t.Errorf("expected 3 nodes, got %d", n)
|
|
}
|
|
}
|
|
|
|
// TestDecay verifies salience decay runs without error.
|
|
func TestDecay(t *testing.T) {
|
|
dir := t.TempDir()
|
|
db, err := Open(filepath.Join(dir, "test-engram"))
|
|
if err != nil {
|
|
t.Fatalf("Open: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
_, err = db.PutNode(&NodeInput{
|
|
Content: "test node",
|
|
Embedding: []float32{1.0, 0.0},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("PutNode: %v", err)
|
|
}
|
|
|
|
updated, err := db.Decay(0.95)
|
|
if err != nil {
|
|
t.Fatalf("Decay: %v", err)
|
|
}
|
|
if updated == 0 {
|
|
t.Error("expected at least one node to be decayed")
|
|
}
|
|
}
|
|
|
|
// ensure test file exists (compile guard)
|
|
var _ = os.DevNull
|