semantic_memory/types.rs
1use crate::error::MemoryError;
2use serde::{Deserialize, Serialize};
3
4/// Role of a message in a conversation.
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
6#[serde(rename_all = "lowercase")]
7pub enum Role {
8 /// System prompt / instructions.
9 System,
10 /// User message.
11 User,
12 /// Assistant (LLM) response.
13 Assistant,
14 /// Tool call result.
15 Tool,
16}
17
18impl Role {
19 /// Convert to the string stored in SQLite.
20 pub fn as_str(&self) -> &'static str {
21 match self {
22 Role::System => "system",
23 Role::User => "user",
24 Role::Assistant => "assistant",
25 Role::Tool => "tool",
26 }
27 }
28
29 /// Parse from the string stored in SQLite.
30 pub fn from_str_value(s: &str) -> Option<Self> {
31 match s {
32 "system" => Some(Role::System),
33 "user" => Some(Role::User),
34 "assistant" => Some(Role::Assistant),
35 "tool" => Some(Role::Tool),
36 _ => None,
37 }
38 }
39}
40
41impl std::fmt::Display for Role {
42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43 f.write_str(self.as_str())
44 }
45}
46
47impl std::str::FromStr for Role {
48 type Err = MemoryError;
49
50 fn from_str(s: &str) -> Result<Self, Self::Err> {
51 Self::from_str_value(s).ok_or_else(|| MemoryError::Other(format!("Unknown role: '{}'", s)))
52 }
53}
54
55/// Indicates whether a search result came from a fact, document chunk, or message.
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57pub enum SearchSourceType {
58 /// Result is from the facts table.
59 Facts,
60 /// Result is from the chunks table.
61 Chunks,
62 /// Result is from the messages table.
63 Messages,
64}
65
66/// A conversation session.
67#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct Session {
69 /// UUID v4.
70 pub id: String,
71 /// Channel identifier (e.g. "repl", "telegram").
72 pub channel: String,
73 /// ISO 8601 timestamp.
74 pub created_at: String,
75 /// ISO 8601 timestamp.
76 pub updated_at: String,
77 /// Optional JSON metadata.
78 pub metadata: Option<serde_json::Value>,
79 /// Number of messages (populated on list queries).
80 pub message_count: u32,
81}
82
83/// A single message within a session.
84#[derive(Debug, Clone, Serialize, Deserialize)]
85pub struct Message {
86 /// Auto-increment ID.
87 pub id: i64,
88 /// Session this message belongs to.
89 pub session_id: String,
90 /// Role of the speaker.
91 pub role: Role,
92 /// Message text.
93 pub content: String,
94 /// Estimated token count (caller-provided).
95 pub token_count: Option<u32>,
96 /// ISO 8601 timestamp.
97 pub created_at: String,
98 /// Optional JSON metadata.
99 pub metadata: Option<serde_json::Value>,
100}
101
102/// A discrete fact in the knowledge store.
103#[derive(Debug, Clone, Serialize, Deserialize)]
104pub struct Fact {
105 /// UUID v4.
106 pub id: String,
107 /// Categorization namespace.
108 pub namespace: String,
109 /// The fact text.
110 pub content: String,
111 /// Where this fact came from.
112 pub source: Option<String>,
113 /// ISO 8601 timestamp.
114 pub created_at: String,
115 /// ISO 8601 timestamp.
116 pub updated_at: String,
117 /// Optional JSON metadata.
118 pub metadata: Option<serde_json::Value>,
119}
120
121/// A source document that has been chunked and embedded.
122#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct Document {
124 /// UUID v4.
125 pub id: String,
126 /// Document title.
127 pub title: String,
128 /// File path, URL, or identifier.
129 pub source_path: Option<String>,
130 /// Categorization namespace.
131 pub namespace: String,
132 /// ISO 8601 timestamp.
133 pub created_at: String,
134 /// Optional JSON metadata.
135 pub metadata: Option<serde_json::Value>,
136 /// Number of chunks (populated on list queries).
137 pub chunk_count: u32,
138}
139
140/// A chunk produced by the text splitter.
141#[derive(Debug, Clone, Serialize, Deserialize)]
142pub struct TextChunk {
143 /// Position in the original document (0-based).
144 pub index: usize,
145 /// The chunk text.
146 pub content: String,
147 /// Rough token estimate (chars / 4).
148 pub token_count_estimate: usize,
149}
150
151/// A single search result.
152#[derive(Debug, Clone, Serialize, Deserialize)]
153pub struct SearchResult {
154 /// The matched text content.
155 pub content: String,
156
157 /// Where this result came from.
158 pub source: SearchSource,
159
160 /// Combined RRF score. Higher = more relevant.
161 pub score: f64,
162
163 /// BM25 rank (1-based) if this result appeared in BM25 results.
164 pub bm25_rank: Option<usize>,
165
166 /// Vector rank (1-based) if this result appeared in vector results.
167 pub vector_rank: Option<usize>,
168
169 /// Cosine similarity score if computed.
170 pub cosine_similarity: Option<f64>,
171}
172
173/// Source information for a search result.
174#[derive(Debug, Clone, Serialize, Deserialize)]
175pub enum SearchSource {
176 /// Result came from the facts table.
177 Fact {
178 /// Fact UUID.
179 fact_id: String,
180 /// Fact namespace.
181 namespace: String,
182 },
183 /// Result came from a document chunk.
184 Chunk {
185 /// Chunk UUID.
186 chunk_id: String,
187 /// Parent document UUID.
188 document_id: String,
189 /// Parent document title.
190 document_title: String,
191 /// Position within the document (0-based).
192 chunk_index: usize,
193 },
194 /// Result came from a conversation message.
195 Message {
196 /// Message auto-increment ID.
197 message_id: i64,
198 /// Session UUID.
199 session_id: String,
200 /// Message role (user, assistant, etc.).
201 role: String,
202 },
203}
204
205/// Database statistics.
206#[derive(Debug, Clone, Serialize, Deserialize)]
207pub struct MemoryStats {
208 /// Total number of facts.
209 pub total_facts: u64,
210 /// Total number of documents.
211 pub total_documents: u64,
212 /// Total number of chunks across all documents.
213 pub total_chunks: u64,
214 /// Total number of conversation sessions.
215 pub total_sessions: u64,
216 /// Total number of messages across all sessions.
217 pub total_messages: u64,
218 /// Database file size in bytes.
219 pub database_size_bytes: u64,
220 /// Currently configured embedding model.
221 pub embedding_model: Option<String>,
222 /// Currently configured embedding dimensions.
223 pub embedding_dimensions: Option<usize>,
224}