909c1577f1
- crates/ → engrams/ (Rust engrams live here) - bindings/ → receptors/ (cross-language access points into the graph) - Cargo.toml workspace paths updated
198 lines
6.1 KiB
Go
198 lines
6.1 KiB
Go
// Package engram provides Go bindings for the Engram memory substrate via CGo.
|
|
//
|
|
// Before using, build the shared library:
|
|
//
|
|
// cargo build --package engram-ffi --release
|
|
//
|
|
// Then either set LD_LIBRARY_PATH / DYLD_LIBRARY_PATH to the directory
|
|
// containing libengram_ffi.so/.dylib, or copy the library to a standard path.
|
|
//
|
|
// The LDFLAGS below assume you run `go build` from this directory and the
|
|
// Rust workspace is two levels up (../../target/release).
|
|
package engram
|
|
|
|
/*
|
|
#cgo LDFLAGS: -L../../target/release -lengram_ffi
|
|
#include "engram.h"
|
|
#include <stdlib.h>
|
|
*/
|
|
import "C"
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"unsafe"
|
|
)
|
|
|
|
// ── Types ─────────────────────────────────────────────────────────────────────
|
|
|
|
// DB is a handle to an open Engram database.
|
|
type DB struct {
|
|
ptr *C.EngramHandle
|
|
}
|
|
|
|
// Node mirrors the Rust Node struct.
|
|
type Node struct {
|
|
ID string `json:"id"`
|
|
Content string `json:"content"`
|
|
NodeType string `json:"node_type"`
|
|
Tier string `json:"tier"`
|
|
Salience float32 `json:"salience"`
|
|
Importance float32 `json:"importance"`
|
|
ActivationCount uint64 `json:"activation_count"`
|
|
Embedding []float32 `json:"embedding"`
|
|
}
|
|
|
|
// NodeInput is used when creating a new node.
|
|
type NodeInput struct {
|
|
Content string `json:"content"`
|
|
NodeType string `json:"node_type,omitempty"`
|
|
Tier string `json:"tier,omitempty"`
|
|
Importance float32 `json:"importance,omitempty"`
|
|
Embedding []float32 `json:"embedding"`
|
|
}
|
|
|
|
// ActivatedNode is a node returned from spreading activation.
|
|
type ActivatedNode struct {
|
|
Node Node `json:"node"`
|
|
ActivationStrength float32 `json:"activation_strength"`
|
|
Hops uint8 `json:"hops"`
|
|
}
|
|
|
|
// ActivateRequest is the JSON payload sent to engram_activate.
|
|
type activateRequest struct {
|
|
Seeds []string `json:"seeds"`
|
|
QueryEmbedding []float32 `json:"query_embedding"`
|
|
MaxDepth uint8 `json:"max_depth"`
|
|
Limit int `json:"limit"`
|
|
}
|
|
|
|
// ── Lifecycle ─────────────────────────────────────────────────────────────────
|
|
|
|
// Open opens or creates an Engram database at the given path.
|
|
func Open(path string) (*DB, error) {
|
|
cpath := C.CString(path)
|
|
defer C.free(unsafe.Pointer(cpath))
|
|
|
|
ptr := C.engram_open(cpath)
|
|
if ptr == nil {
|
|
return nil, fmt.Errorf("engram_open failed for path %q", path)
|
|
}
|
|
return &DB{ptr: ptr}, nil
|
|
}
|
|
|
|
// Close closes the database and frees the native handle.
|
|
func (db *DB) Close() {
|
|
if db.ptr != nil {
|
|
C.engram_close(db.ptr)
|
|
db.ptr = nil
|
|
}
|
|
}
|
|
|
|
// ── Statistics ────────────────────────────────────────────────────────────────
|
|
|
|
// NodeCount returns the total number of nodes.
|
|
func (db *DB) NodeCount() (uint64, error) {
|
|
n := C.engram_node_count(db.ptr)
|
|
if n < 0 {
|
|
return 0, errors.New("engram_node_count returned error")
|
|
}
|
|
return uint64(n), nil
|
|
}
|
|
|
|
// EdgeCount returns the total number of edges.
|
|
func (db *DB) EdgeCount() (uint64, error) {
|
|
n := C.engram_edge_count(db.ptr)
|
|
if n < 0 {
|
|
return 0, errors.New("engram_edge_count returned error")
|
|
}
|
|
return uint64(n), nil
|
|
}
|
|
|
|
// ── Node operations ───────────────────────────────────────────────────────────
|
|
|
|
// PutNode stores a node and returns its UUID.
|
|
func (db *DB) PutNode(node *NodeInput) (string, error) {
|
|
jsonBytes, err := json.Marshal(node)
|
|
if err != nil {
|
|
return "", fmt.Errorf("marshal node: %w", err)
|
|
}
|
|
|
|
cjson := C.CString(string(jsonBytes))
|
|
defer C.free(unsafe.Pointer(cjson))
|
|
|
|
result := C.engram_put_node(db.ptr, cjson)
|
|
if result == nil {
|
|
return "", errors.New("engram_put_node returned null")
|
|
}
|
|
defer C.engram_free_string(result)
|
|
|
|
return C.GoString(result), nil
|
|
}
|
|
|
|
// GetNode retrieves a node by UUID. Returns nil if not found.
|
|
func (db *DB) GetNode(id string) (*Node, error) {
|
|
cid := C.CString(id)
|
|
defer C.free(unsafe.Pointer(cid))
|
|
|
|
result := C.engram_get_node(db.ptr, cid)
|
|
if result == nil {
|
|
return nil, nil
|
|
}
|
|
defer C.engram_free_string(result)
|
|
|
|
var node Node
|
|
if err := json.Unmarshal([]byte(C.GoString(result)), &node); err != nil {
|
|
return nil, fmt.Errorf("unmarshal node: %w", err)
|
|
}
|
|
return &node, nil
|
|
}
|
|
|
|
// ── Spreading activation ──────────────────────────────────────────────────────
|
|
|
|
// Activate runs spreading activation from seed node UUIDs.
|
|
func (db *DB) Activate(
|
|
seeds []string,
|
|
queryEmbedding []float32,
|
|
maxDepth uint8,
|
|
limit int,
|
|
) ([]*ActivatedNode, error) {
|
|
req := activateRequest{
|
|
Seeds: seeds,
|
|
QueryEmbedding: queryEmbedding,
|
|
MaxDepth: maxDepth,
|
|
Limit: limit,
|
|
}
|
|
jsonBytes, err := json.Marshal(req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("marshal activate request: %w", err)
|
|
}
|
|
|
|
cjson := C.CString(string(jsonBytes))
|
|
defer C.free(unsafe.Pointer(cjson))
|
|
|
|
result := C.engram_activate(db.ptr, cjson)
|
|
if result == nil {
|
|
return nil, errors.New("engram_activate returned null")
|
|
}
|
|
defer C.engram_free_string(result)
|
|
|
|
var nodes []*ActivatedNode
|
|
if err := json.Unmarshal([]byte(C.GoString(result)), &nodes); err != nil {
|
|
return nil, fmt.Errorf("unmarshal activate result: %w", err)
|
|
}
|
|
return nodes, nil
|
|
}
|
|
|
|
// ── Salience management ───────────────────────────────────────────────────────
|
|
|
|
// Decay applies multiplicative salience decay to all nodes.
|
|
// factor should be in (0.0, 1.0). Returns the number of nodes updated.
|
|
func (db *DB) Decay(factor float32) (uint64, error) {
|
|
n := C.engram_decay(db.ptr, C.float(factor))
|
|
if n < 0 {
|
|
return 0, errors.New("engram_decay returned error")
|
|
}
|
|
return uint64(n), nil
|
|
}
|