Skip to main content

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}