// graph.el — Graph operations subsystem. // // Neuron's storage backend is Engram — a graph database where every entity // (Memory, Knowledge, BacklogItem, etc.) is a node and every relationship // is a typed edge. This subsystem exposes the raw graph API for operations // that span entity types or need structural graph information. // // WHY expose graph ops directly? // High-level tools like search_memories or retrieve_knowledge hide the graph // structure. But some questions are inherently graph-shaped: // "What entities are connected to this decision?" // "How deep is the dependency chain for this backlog item?" // "Are these two memories causally related?" // // Graph ops answer these questions without the overhead of entity-typed // queries. They're the escape hatch when you need to see the whole picture. // // link_entities is a @manager because it mutates the graph topology. // All reads are @accessor. from types import { GraphNode, SearchResult, NeuronError, } // ── Public API ──────────────────────────────────────────────────────────────── // inspect_graph — get a node and its immediate connections. // // entity_type: "Memory" | "Knowledge" | "BacklogItem" | "Context" | "Artifact" | ... // entity_id: the UUID or string ID of the entity. // // Returns the node and its edges formatted as "relation:target_id" strings. // Use this to understand what a node is connected to before traversing deeper. @accessor fn inspect_graph(entity_type: String, entity_id: String) -> Result { let node = native_graph_inspect(entity_type, entity_id)? Ok(node) } // traverse_graph — walk the graph from a starting node up to depth hops. // // depth=1 returns immediate neighbors only (equivalent to inspect_graph). // depth=2 returns neighbors of neighbors, etc. // Default depth is 2 — deep enough for most dependency chains. // // Returns all visited nodes, not just leaves. This gives the caller the // full subgraph around the starting node. @accessor fn traverse_graph(entity_id: String, depth: Int) -> Result<[GraphNode], NeuronError> { let effective_depth = if depth == 0 { 2 } else { depth } let nodes = native_graph_traverse(entity_id, effective_depth)? Ok(nodes) } // link_entities — create a typed edge between two graph nodes. // // relation examples: "supersedes", "depends_on", "caused_by", "related_to", // "implements", "references", "blocks" // // Edges are directional: source --relation--> target. // Use causal links for reasoning chains, dependency links for work items, // supersedes links for knowledge evolution. @manager fn link_entities( source_id: String, target_id: String, relation: String, ) -> Result { native_graph_link(source_id, target_id, relation)? native_emit("graph.linked", {"source": source_id, "target": target_id, "relation": relation}) // Return the source node with its updated edges. let source_node = native_graph_inspect("", source_id)? Ok(source_node) } // search_graph — semantic search across all node types in the graph. // // Unlike type-specific search (search_memories, search_knowledge), this // searches the entire graph regardless of entity type. Useful for // cross-cutting queries: "what's related to authentication across all // memories, knowledge, and backlog items?" @accessor fn search_graph(query: String) -> Result<[SearchResult], NeuronError> { let results = native_semantic_search(query, "", 20)? Ok(results) } // rebuild_graph — trigger a full graph index rebuild. // // Used after bulk imports or when the semantic index drifts out of sync. // This is an expensive operation — avoid in normal sessions. // It's sealed because it modifies the graph infrastructure, not just data. @manager fn rebuild_graph() -> Result { sealed { native_emit("graph.rebuild_requested", {}) Ok("graph rebuild initiated") } } // pin_node — mark a graph node as pinned (exempt from compaction). // // Pinned nodes survive graph compaction even when their activation scores // drop below the compaction threshold. Use for foundational knowledge nodes // that must never be evicted. @manager fn pin_node(entity_id: String, entity_type: String) -> Result { sealed { // Pinning is implemented as a special self-referential "pinned" edge. native_graph_link(entity_id, entity_id, "pinned")? native_emit("graph.node_pinned", {"id": entity_id, "type": entity_type}) let node = native_graph_inspect(entity_type, entity_id)? Ok(node) } }