Skip to main content

llm_kernel/graph/
mod.rs

1//! AI agent memory graph — SQLite/PostgreSQL-backed long-term memory with FTS5
2//! search, smart recall, and graph-structured relevance boosting.
3//!
4//! The module is tuned for agent *memory*: nodes carry importance and decaying
5//! recency/access signals, and are recalled by composite scoring (recency +
6//! importance + access + FTS + graph boost), with CSR algorithms ([`algo`])
7//! surfacing structurally central memories. The niche is comparable to
8//! **Zep / Mem0 / Letta**, but local-first and vault-based rather than a hosted
9//! service.
10//!
11//! From v0.19 the trait also serves **general directed-graph workloads** —
12//! citation networks, document backlinks, dependency graphs — via batch edge
13//! writes ([`GraphBackend::append_edges`]), directional / relation-filtered
14//! lookups ([`GraphBackend::edges_for_node_dir`],
15//! [`GraphBackend::neighbors_weighted`]), and filtered BFS
16//! ([`GraphBackend::related_nodes_filtered`]); [`EdgeDirection`] selects
17//! out / in / both. For pure topology with no memory semantics, `petgraph` or
18//! a graph database remains a better fit.
19//!
20//! Provides a complete knowledge graph layer on top of SQLite:
21//!
22//! - **Types**: [`GraphNode`], [`GraphEdge`], [`ScoredNode`], [`GraphStats`]
23//! - **Schema**: [`init_graph_schema`] — creates tables, FTS5, indexes
24//! - **CRUD**: node/edge insert, read, update, delete
25//! - **Search**: FTS5 full-text search and dynamic filtering
26//! - **Recall**: [`smart_recall`] — composite scoring with recency, importance, access, FTS, graph boost
27//! - **Traversal**: [`graph_neighbors`] (1-hop), [`related_nodes`] (BFS via recursive CTE)
28//! - **Algorithms**: pure-Rust CSR algorithms in [`algo`] — [`pagerank()`], [`connected_components()`], [`label_propagation()`], [`dijkstra()`], [`jaccard_similarity()`]
29//! - **Lifecycle**: [`decay_importance`], [`tag_stale_nodes`], [`compute_stats`]
30//!
31//! All functions take `&rusqlite::Connection` — no hardcoded paths.
32//!
33//! ```no_run
34//! use rusqlite::Connection;
35//! use llm_kernel::graph::{init_graph_schema, upsert_node, smart_recall, GraphNode};
36//!
37//! let conn = Connection::open_in_memory().unwrap();
38//! init_graph_schema(&conn).unwrap();
39//!
40//! upsert_node(&conn, &GraphNode {
41//!     id: "rust-ownership".into(),
42//!     node_type: "concept".into(),
43//!     title: "Rust Ownership Model".into(),
44//!     body: "Ownership, borrowing, and lifetimes...".into(),
45//!     tags: vec!["rust".into(), "memory-safety".into()],
46//!     projects: vec!["my-project".into()],
47//!     agents: vec![],
48//!     created: "2026-01-01T00:00:00Z".into(),
49//!     updated: "2026-01-01T00:00:00Z".into(),
50//!     importance: 0.8,
51//!     access_count: 0,
52//!     accessed_at: String::new(),
53//!     ..Default::default()
54//! }).unwrap();
55//!
56//! let results = smart_recall(&conn, Some("my-project"), Some("ownership"), 5).unwrap();
57//! for scored in &results {
58//!     println!("{:.2} — {}", scored.score, scored.node.title);
59//! }
60//! ```
61
62pub mod algo;
63pub mod backend;
64pub mod dedup;
65pub mod lifecycle;
66pub mod recall;
67pub mod schema;
68pub mod search;
69pub mod store;
70pub mod traversal;
71pub mod types;
72
73/// CJK-aware graph search (Rust-side segmentation; no schema change).
74#[cfg(feature = "graph-cjk")]
75pub mod cjk;
76
77/// PostgreSQL `GraphBackend` (feature `graph-pg`).
78#[cfg(feature = "graph-pg")]
79pub mod pg;
80
81/// Async PostgreSQL graph backend over `sqlx::PgPool` (feature `graph-pg-sqlx`) —
82/// for consumers (e.g. klr) that own an async pool and need transaction sharing.
83#[cfg(feature = "graph-pg-sqlx")]
84pub mod sqlx_pg;
85
86#[cfg(feature = "graph-async")]
87pub mod async_graph;
88
89#[cfg(feature = "graph-pool")]
90pub mod async_pool;
91#[cfg(feature = "graph-pool")]
92pub use async_pool::AsyncPoolGraph;
93
94// Re-export primary types and functions
95pub use algo::{
96    CsrGraph, LABEL_PROPAGATION_ITERS, PAGERANK_DAMPING, PAGERANK_EPS, PAGERANK_ITERS,
97    SHORTEST_PATH_W_MIN, adamic_adar, common_neighbors, connected_components, dijkstra,
98    jaccard_similarity, label_propagation, label_propagation_default, link_prediction, pagerank,
99    pagerank_default, pagerank_scores, shortest_path, shortest_path_ids,
100};
101pub use backend::{GraphBackend, SqliteGraph};
102pub use dedup::{find_duplicate, upsert_node_dedup};
103pub use lifecycle::{
104    compute_stats, count_expired_nodes, decay_importance, mark_verified, tag_stale_nodes,
105    touch_node, touch_nodes,
106};
107pub use recall::{RecallOptions, smart_recall, smart_recall_with};
108pub use schema::{GRAPH_SCHEMA_VERSION, init_graph_schema, migrate_graph, schema_version};
109pub use search::{
110    NodeOrder, NodeQuery, query_nodes, query_nodes_ex, search_nodes, search_nodes_hybrid,
111};
112pub use store::{
113    append_edge, delete_edge, delete_node, read_edges, read_node, read_nodes, upsert_node,
114};
115pub use traversal::{build_graph, graph_neighbors, related_nodes};
116pub use types::{
117    EdgeDirection, Graph, GraphEdge, GraphNode, GraphNodeSummary, GraphStats, ScoredNode,
118    validate_uuid,
119};
120
121#[cfg(feature = "graph-cjk")]
122pub use cjk::{search_nodes_cjk, segment_cjk};
123
124#[cfg(feature = "graph-pg")]
125pub use pg::PgGraph;
126
127#[cfg(feature = "graph-pg-sqlx")]
128pub use sqlx_pg::SqlxPgGraph;