1use rusqlite::{Connection, OptionalExtension, params};
2use serde::{Deserialize, Serialize};
3use thiserror::Error;
4
5use crate::schema;
6
7#[derive(Error, Debug)]
9pub enum StorageError {
10 #[error("Database error: {0}")]
11 Database(#[from] rusqlite::Error),
12
13 #[error("Serialization error: {0}")]
14 Serialization(#[from] serde_json::Error),
15
16 #[error("Not found: {0}")]
17 NotFound(String),
18
19 #[error("Invalid data: {0}")]
20 InvalidData(String),
21}
22
23pub type Result<T> = std::result::Result<T, StorageError>;
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct StoredMemory {
28 pub id: String,
29 pub content: String,
30 pub tier: i32,
31 pub importance: f64,
32 pub embedding_blob: Option<Vec<u8>>,
33 pub created_at: i64,
34 pub last_accessed: i64,
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct StoredSkill {
40 pub id: String,
41 pub name: String,
42 pub description: String,
43 pub trigger_pattern: String,
44 pub success_count: i32,
45 pub last_used: Option<i64>,
46 pub created_at: i64,
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct StoredArchitecture {
52 pub id: String,
53 pub name: String,
54 pub paradigm: String,
55 pub substrate: String,
56 pub fitness_json: String,
57 pub lineage_json: String,
58 pub created_at: i64,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
63pub struct StoredIntelligence {
64 pub id: String,
65 pub name: String,
66 pub arch_id: String,
67 pub maturity: f64,
68 pub capabilities_json: String,
69 pub memories_json: String,
70 pub state_json: String,
71 pub created_at: i64,
72 pub updated_at: i64,
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
77pub struct StoredVector {
78 pub id: String,
79 pub memory_id: String,
80 pub dimensions: i32,
81 pub data_blob: Vec<u8>,
82}
83
84#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct StoredReflexionEpisode {
87 pub id: String,
88 pub memory_id: String,
89 pub trigger: String,
90 pub context: String,
91 pub action: String,
92 pub outcome: String,
93 pub created_at: i64,
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct StoredCausalEdge {
99 pub id: String,
100 pub from_memory: String,
101 pub to_memory: String,
102 pub weight: f64,
103 pub edge_type: String,
104 pub created_at: i64,
105}
106
107pub struct OmegaStore {
109 conn: Connection,
110}
111
112impl OmegaStore {
113 pub fn new(path: &str) -> Result<Self> {
121 let conn = Connection::open(path)?;
122
123 conn.execute("PRAGMA foreign_keys = ON;", [])?;
125
126 for schema_sql in schema::ALL_SCHEMAS {
128 conn.execute(schema_sql, [])?;
129 }
130
131 Ok(Self { conn })
132 }
133
134 pub fn new_in_memory() -> Result<Self> {
136 let conn = Connection::open_in_memory()?;
137 conn.execute("PRAGMA foreign_keys = ON;", [])?;
138
139 for schema_sql in schema::ALL_SCHEMAS {
140 conn.execute(schema_sql, [])?;
141 }
142
143 Ok(Self { conn })
144 }
145
146 pub fn store_memory(&self, memory: &StoredMemory) -> Result<()> {
150 self.conn.execute(
151 "INSERT OR REPLACE INTO memories
152 (id, content, tier, importance, embedding_blob, created_at, last_accessed)
153 VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
154 params![
155 &memory.id,
156 &memory.content,
157 memory.tier,
158 memory.importance,
159 &memory.embedding_blob,
160 memory.created_at,
161 memory.last_accessed,
162 ],
163 )?;
164 Ok(())
165 }
166
167 pub fn get_memory(&self, id: &str) -> Result<StoredMemory> {
169 let memory = self.conn.query_row(
170 "SELECT id, content, tier, importance, embedding_blob, created_at, last_accessed
171 FROM memories WHERE id = ?1",
172 params![id],
173 |row| {
174 Ok(StoredMemory {
175 id: row.get(0)?,
176 content: row.get(1)?,
177 tier: row.get(2)?,
178 importance: row.get(3)?,
179 embedding_blob: row.get(4)?,
180 created_at: row.get(5)?,
181 last_accessed: row.get(6)?,
182 })
183 },
184 ).optional()?
185 .ok_or_else(|| StorageError::NotFound(format!("Memory not found: {}", id)))?;
186
187 Ok(memory)
188 }
189
190 pub fn query_memories_by_tier(&self, tier: i32) -> Result<Vec<StoredMemory>> {
192 let mut stmt = self.conn.prepare(
193 "SELECT id, content, tier, importance, embedding_blob, created_at, last_accessed
194 FROM memories WHERE tier = ?1 ORDER BY importance DESC"
195 )?;
196
197 let memories = stmt.query_map(params![tier], |row| {
198 Ok(StoredMemory {
199 id: row.get(0)?,
200 content: row.get(1)?,
201 tier: row.get(2)?,
202 importance: row.get(3)?,
203 embedding_blob: row.get(4)?,
204 created_at: row.get(5)?,
205 last_accessed: row.get(6)?,
206 })
207 })?
208 .collect::<std::result::Result<Vec<_>, _>>()?;
209
210 Ok(memories)
211 }
212
213 pub fn update_memory_access(&self, id: &str, timestamp: i64) -> Result<()> {
215 let rows = self.conn.execute(
216 "UPDATE memories SET last_accessed = ?1 WHERE id = ?2",
217 params![timestamp, id],
218 )?;
219
220 if rows == 0 {
221 return Err(StorageError::NotFound(format!("Memory not found: {}", id)));
222 }
223
224 Ok(())
225 }
226
227 pub fn store_skill(&self, skill: &StoredSkill) -> Result<()> {
231 self.conn.execute(
232 "INSERT OR REPLACE INTO skills
233 (id, name, description, trigger_pattern, success_count, last_used, created_at)
234 VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
235 params![
236 &skill.id,
237 &skill.name,
238 &skill.description,
239 &skill.trigger_pattern,
240 skill.success_count,
241 skill.last_used,
242 skill.created_at,
243 ],
244 )?;
245 Ok(())
246 }
247
248 pub fn get_skill(&self, id: &str) -> Result<StoredSkill> {
250 let skill = self.conn.query_row(
251 "SELECT id, name, description, trigger_pattern, success_count, last_used, created_at
252 FROM skills WHERE id = ?1",
253 params![id],
254 |row| {
255 Ok(StoredSkill {
256 id: row.get(0)?,
257 name: row.get(1)?,
258 description: row.get(2)?,
259 trigger_pattern: row.get(3)?,
260 success_count: row.get(4)?,
261 last_used: row.get(5)?,
262 created_at: row.get(6)?,
263 })
264 },
265 ).optional()?
266 .ok_or_else(|| StorageError::NotFound(format!("Skill not found: {}", id)))?;
267
268 Ok(skill)
269 }
270
271 pub fn get_skills_by_pattern(&self, pattern: &str) -> Result<Vec<StoredSkill>> {
273 let mut stmt = self.conn.prepare(
274 "SELECT id, name, description, trigger_pattern, success_count, last_used, created_at
275 FROM skills WHERE trigger_pattern LIKE ?1 ORDER BY success_count DESC"
276 )?;
277
278 let pattern_query = format!("%{}%", pattern);
279 let skills = stmt.query_map(params![pattern_query], |row| {
280 Ok(StoredSkill {
281 id: row.get(0)?,
282 name: row.get(1)?,
283 description: row.get(2)?,
284 trigger_pattern: row.get(3)?,
285 success_count: row.get(4)?,
286 last_used: row.get(5)?,
287 created_at: row.get(6)?,
288 })
289 })?
290 .collect::<std::result::Result<Vec<_>, _>>()?;
291
292 Ok(skills)
293 }
294
295 pub fn increment_skill_success(&self, id: &str, timestamp: i64) -> Result<()> {
297 let rows = self.conn.execute(
298 "UPDATE skills SET success_count = success_count + 1, last_used = ?1 WHERE id = ?2",
299 params![timestamp, id],
300 )?;
301
302 if rows == 0 {
303 return Err(StorageError::NotFound(format!("Skill not found: {}", id)));
304 }
305
306 Ok(())
307 }
308
309 pub fn store_architecture(&self, arch: &StoredArchitecture) -> Result<()> {
313 self.conn.execute(
314 "INSERT OR REPLACE INTO architectures
315 (id, name, paradigm, substrate, fitness_json, lineage_json, created_at)
316 VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
317 params![
318 &arch.id,
319 &arch.name,
320 &arch.paradigm,
321 &arch.substrate,
322 &arch.fitness_json,
323 &arch.lineage_json,
324 arch.created_at,
325 ],
326 )?;
327 Ok(())
328 }
329
330 pub fn get_architecture(&self, id: &str) -> Result<StoredArchitecture> {
332 let arch = self.conn.query_row(
333 "SELECT id, name, paradigm, substrate, fitness_json, lineage_json, created_at
334 FROM architectures WHERE id = ?1",
335 params![id],
336 |row| {
337 Ok(StoredArchitecture {
338 id: row.get(0)?,
339 name: row.get(1)?,
340 paradigm: row.get(2)?,
341 substrate: row.get(3)?,
342 fitness_json: row.get(4)?,
343 lineage_json: row.get(5)?,
344 created_at: row.get(6)?,
345 })
346 },
347 ).optional()?
348 .ok_or_else(|| StorageError::NotFound(format!("Architecture not found: {}", id)))?;
349
350 Ok(arch)
351 }
352
353 pub fn get_architectures_by_paradigm(&self, paradigm: &str) -> Result<Vec<StoredArchitecture>> {
355 let mut stmt = self.conn.prepare(
356 "SELECT id, name, paradigm, substrate, fitness_json, lineage_json, created_at
357 FROM architectures WHERE paradigm = ?1 ORDER BY created_at DESC"
358 )?;
359
360 let archs = stmt.query_map(params![paradigm], |row| {
361 Ok(StoredArchitecture {
362 id: row.get(0)?,
363 name: row.get(1)?,
364 paradigm: row.get(2)?,
365 substrate: row.get(3)?,
366 fitness_json: row.get(4)?,
367 lineage_json: row.get(5)?,
368 created_at: row.get(6)?,
369 })
370 })?
371 .collect::<std::result::Result<Vec<_>, _>>()?;
372
373 Ok(archs)
374 }
375
376 pub fn store_intelligence(&self, intel: &StoredIntelligence) -> Result<()> {
380 self.conn.execute(
381 "INSERT OR REPLACE INTO intelligences
382 (id, name, arch_id, maturity, capabilities_json, memories_json, state_json, created_at, updated_at)
383 VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)",
384 params![
385 &intel.id,
386 &intel.name,
387 &intel.arch_id,
388 intel.maturity,
389 &intel.capabilities_json,
390 &intel.memories_json,
391 &intel.state_json,
392 intel.created_at,
393 intel.updated_at,
394 ],
395 )?;
396 Ok(())
397 }
398
399 pub fn get_intelligence(&self, id: &str) -> Result<StoredIntelligence> {
401 let intel = self.conn.query_row(
402 "SELECT id, name, arch_id, maturity, capabilities_json, memories_json, state_json, created_at, updated_at
403 FROM intelligences WHERE id = ?1",
404 params![id],
405 |row| {
406 Ok(StoredIntelligence {
407 id: row.get(0)?,
408 name: row.get(1)?,
409 arch_id: row.get(2)?,
410 maturity: row.get(3)?,
411 capabilities_json: row.get(4)?,
412 memories_json: row.get(5)?,
413 state_json: row.get(6)?,
414 created_at: row.get(7)?,
415 updated_at: row.get(8)?,
416 })
417 },
418 ).optional()?
419 .ok_or_else(|| StorageError::NotFound(format!("Intelligence not found: {}", id)))?;
420
421 Ok(intel)
422 }
423
424 pub fn get_intelligences_by_arch(&self, arch_id: &str) -> Result<Vec<StoredIntelligence>> {
426 let mut stmt = self.conn.prepare(
427 "SELECT id, name, arch_id, maturity, capabilities_json, memories_json, state_json, created_at, updated_at
428 FROM intelligences WHERE arch_id = ?1 ORDER BY maturity DESC"
429 )?;
430
431 let intels = stmt.query_map(params![arch_id], |row| {
432 Ok(StoredIntelligence {
433 id: row.get(0)?,
434 name: row.get(1)?,
435 arch_id: row.get(2)?,
436 maturity: row.get(3)?,
437 capabilities_json: row.get(4)?,
438 memories_json: row.get(5)?,
439 state_json: row.get(6)?,
440 created_at: row.get(7)?,
441 updated_at: row.get(8)?,
442 })
443 })?
444 .collect::<std::result::Result<Vec<_>, _>>()?;
445
446 Ok(intels)
447 }
448
449 pub fn store_vector(&self, vector: &StoredVector) -> Result<()> {
453 self.conn.execute(
454 "INSERT OR REPLACE INTO vectors (id, memory_id, dimensions, data_blob)
455 VALUES (?1, ?2, ?3, ?4)",
456 params![
457 &vector.id,
458 &vector.memory_id,
459 vector.dimensions,
460 &vector.data_blob,
461 ],
462 )?;
463 Ok(())
464 }
465
466 pub fn get_vector_by_memory(&self, memory_id: &str) -> Result<StoredVector> {
468 let vector = self.conn.query_row(
469 "SELECT id, memory_id, dimensions, data_blob FROM vectors WHERE memory_id = ?1",
470 params![memory_id],
471 |row| {
472 Ok(StoredVector {
473 id: row.get(0)?,
474 memory_id: row.get(1)?,
475 dimensions: row.get(2)?,
476 data_blob: row.get(3)?,
477 })
478 },
479 ).optional()?
480 .ok_or_else(|| StorageError::NotFound(format!("Vector not found for memory: {}", memory_id)))?;
481
482 Ok(vector)
483 }
484
485 pub fn store_reflexion(&self, episode: &StoredReflexionEpisode) -> Result<()> {
489 self.conn.execute(
490 "INSERT OR REPLACE INTO reflexion_episodes
491 (id, memory_id, trigger, context, action, outcome, created_at)
492 VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
493 params![
494 &episode.id,
495 &episode.memory_id,
496 &episode.trigger,
497 &episode.context,
498 &episode.action,
499 &episode.outcome,
500 episode.created_at,
501 ],
502 )?;
503 Ok(())
504 }
505
506 pub fn get_reflexions_by_memory(&self, memory_id: &str) -> Result<Vec<StoredReflexionEpisode>> {
508 let mut stmt = self.conn.prepare(
509 "SELECT id, memory_id, trigger, context, action, outcome, created_at
510 FROM reflexion_episodes WHERE memory_id = ?1 ORDER BY created_at DESC"
511 )?;
512
513 let episodes = stmt.query_map(params![memory_id], |row| {
514 Ok(StoredReflexionEpisode {
515 id: row.get(0)?,
516 memory_id: row.get(1)?,
517 trigger: row.get(2)?,
518 context: row.get(3)?,
519 action: row.get(4)?,
520 outcome: row.get(5)?,
521 created_at: row.get(6)?,
522 })
523 })?
524 .collect::<std::result::Result<Vec<_>, _>>()?;
525
526 Ok(episodes)
527 }
528
529 pub fn store_causal_edge(&self, edge: &StoredCausalEdge) -> Result<()> {
533 self.conn.execute(
534 "INSERT OR REPLACE INTO causal_edges
535 (id, from_memory, to_memory, weight, edge_type, created_at)
536 VALUES (?1, ?2, ?3, ?4, ?5, ?6)",
537 params![
538 &edge.id,
539 &edge.from_memory,
540 &edge.to_memory,
541 edge.weight,
542 &edge.edge_type,
543 edge.created_at,
544 ],
545 )?;
546 Ok(())
547 }
548
549 pub fn get_causal_edges_from(&self, memory_id: &str) -> Result<Vec<StoredCausalEdge>> {
551 let mut stmt = self.conn.prepare(
552 "SELECT id, from_memory, to_memory, weight, edge_type, created_at
553 FROM causal_edges WHERE from_memory = ?1 ORDER BY weight DESC"
554 )?;
555
556 let edges = stmt.query_map(params![memory_id], |row| {
557 Ok(StoredCausalEdge {
558 id: row.get(0)?,
559 from_memory: row.get(1)?,
560 to_memory: row.get(2)?,
561 weight: row.get(3)?,
562 edge_type: row.get(4)?,
563 created_at: row.get(5)?,
564 })
565 })?
566 .collect::<std::result::Result<Vec<_>, _>>()?;
567
568 Ok(edges)
569 }
570
571 pub fn backup(&self, backup_path: &str) -> Result<()> {
575 let mut backup_conn = Connection::open(backup_path)?;
576 let backup = rusqlite::backup::Backup::new(&self.conn, &mut backup_conn)?;
577 backup.run_to_completion(5, std::time::Duration::from_millis(250), None)?;
578 Ok(())
579 }
580
581 pub fn get_statistics(&self) -> Result<DatabaseStatistics> {
583 let memory_count: i64 = self.conn.query_row(
584 "SELECT COUNT(*) FROM memories",
585 [],
586 |row| row.get(0),
587 )?;
588
589 let skill_count: i64 = self.conn.query_row(
590 "SELECT COUNT(*) FROM skills",
591 [],
592 |row| row.get(0),
593 )?;
594
595 let architecture_count: i64 = self.conn.query_row(
596 "SELECT COUNT(*) FROM architectures",
597 [],
598 |row| row.get(0),
599 )?;
600
601 let intelligence_count: i64 = self.conn.query_row(
602 "SELECT COUNT(*) FROM intelligences",
603 [],
604 |row| row.get(0),
605 )?;
606
607 let causal_edge_count: i64 = self.conn.query_row(
608 "SELECT COUNT(*) FROM causal_edges",
609 [],
610 |row| row.get(0),
611 )?;
612
613 Ok(DatabaseStatistics {
614 memory_count,
615 skill_count,
616 architecture_count,
617 intelligence_count,
618 causal_edge_count,
619 })
620 }
621}
622
623#[derive(Debug, Clone, Serialize, Deserialize)]
625pub struct DatabaseStatistics {
626 pub memory_count: i64,
627 pub skill_count: i64,
628 pub architecture_count: i64,
629 pub intelligence_count: i64,
630 pub causal_edge_count: i64,
631}