nexus_memory_vectors/
lib.rs1pub mod database;
39pub mod graph;
40pub mod search;
41
42#[allow(deprecated)]
43pub use database::{
44 batch_cosine_similarity, cosine_similarity, dot_product, euclidean_distance, normalize_vector,
45 top_k_similar, VectorDatabase, VectorDatabaseStats, VectorSearchResult, DEFAULT_SEARCH_LIMIT,
46 DEFAULT_SIMILARITY_THRESHOLD,
47};
48pub use graph::{GraphNode, GraphNode as Node, GraphTree, NodeType, TreeNode, TreeStats};
49pub use search::{SearchOptions, SearchResult, SemanticSearch};
50
51use serde::{Deserialize, Serialize};
52
53pub type Result<T> = std::result::Result<T, nexus_core::NexusError>;
55
56pub const EMBEDDING_DIMENSION: usize = 384;
58
59pub type Embedding = Vec<f32>;
61
62#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct VectorEntry {
65 pub id: i64,
67
68 pub embedding: Embedding,
70
71 pub category: String,
73
74 pub memory_lane_type: Option<String>,
76
77 pub namespace_id: i64,
79
80 pub created_at: chrono::DateTime<chrono::Utc>,
82}
83
84impl VectorEntry {
85 pub fn new(id: i64, embedding: Embedding, category: String, namespace_id: i64) -> Self {
87 Self {
88 id,
89 embedding,
90 category,
91 memory_lane_type: None,
92 namespace_id,
93 created_at: chrono::Utc::now(),
94 }
95 }
96
97 pub fn with_memory_lane_type(mut self, memory_lane_type: impl Into<String>) -> Self {
99 self.memory_lane_type = Some(memory_lane_type.into());
100 self
101 }
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct SearchLatency {
107 pub total_ms: u64,
109
110 pub vector_comparison_ms: u64,
112
113 pub graph_traversal_ms: Option<u64>,
115}
116
117impl SearchLatency {
118 pub fn meets_target(&self) -> bool {
120 self.total_ms < 10
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127
128 #[test]
129 fn test_vector_entry_new() {
130 let embedding = vec![0.1; EMBEDDING_DIMENSION];
131 let entry = VectorEntry::new(1, embedding.clone(), "general".to_string(), 1);
132
133 assert_eq!(entry.id, 1);
134 assert_eq!(entry.embedding, embedding);
135 assert_eq!(entry.category, "general");
136 assert_eq!(entry.namespace_id, 1);
137 assert!(entry.memory_lane_type.is_none());
138 }
139
140 #[test]
141 fn test_vector_entry_with_memory_lane_type() {
142 let embedding = vec![0.1; EMBEDDING_DIMENSION];
143 let entry = VectorEntry::new(1, embedding, "general".to_string(), 1)
144 .with_memory_lane_type("correction");
145
146 assert_eq!(entry.memory_lane_type, Some("correction".to_string()));
147 }
148
149 #[test]
150 fn test_search_latency_meets_target() {
151 let good = SearchLatency {
152 total_ms: 5,
153 vector_comparison_ms: 3,
154 graph_traversal_ms: Some(1),
155 };
156 assert!(good.meets_target());
157
158 let bad = SearchLatency {
159 total_ms: 15,
160 vector_comparison_ms: 10,
161 graph_traversal_ms: Some(4),
162 };
163 assert!(!bad.meets_target());
164 }
165}