1use chrono::{DateTime, Utc};
2use pgvector::Vector;
3use serde::{Deserialize, Serialize};
4use sqlx::postgres::types::PgInterval;
5use sqlx::FromRow;
6use std::str::FromStr;
7use uuid::Uuid;
8
9#[derive(Debug, Clone)]
10pub struct SerializableVector(pub Option<Vector>);
11
12impl Serialize for SerializableVector {
13 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
14 where
15 S: serde::Serializer,
16 {
17 match &self.0 {
18 Some(v) => v.as_slice().serialize(serializer),
19 None => serializer.serialize_none(),
20 }
21 }
22}
23
24impl<'de> Deserialize<'de> for SerializableVector {
25 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
26 where
27 D: serde::Deserializer<'de>,
28 {
29 let opt_vec: Option<Vec<f32>> = Option::deserialize(deserializer)?;
30 Ok(SerializableVector(opt_vec.map(Vector::from)))
31 }
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, sqlx::Type)]
35#[sqlx(type_name = "varchar", rename_all = "lowercase")]
36pub enum MemoryTier {
37 Working,
38 Warm,
39 Cold,
40 Frozen,
41}
42
43impl FromStr for MemoryTier {
44 type Err = String;
45
46 fn from_str(s: &str) -> Result<Self, Self::Err> {
47 match s.to_lowercase().as_str() {
48 "working" => Ok(MemoryTier::Working),
49 "warm" => Ok(MemoryTier::Warm),
50 "cold" => Ok(MemoryTier::Cold),
51 "frozen" => Ok(MemoryTier::Frozen),
52 _ => Err(format!("Invalid memory tier: {s}")),
53 }
54 }
55}
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, sqlx::Type)]
58#[sqlx(type_name = "varchar", rename_all = "lowercase")]
59pub enum MemoryStatus {
60 Active,
61 Migrating,
62 Archived,
63 Deleted,
64}
65
66#[derive(Debug, Clone, FromRow)]
67pub struct Memory {
68 pub id: Uuid,
69 pub content: String,
70 pub content_hash: String,
71 pub embedding: Option<Vector>,
72 pub tier: MemoryTier,
73 pub status: MemoryStatus,
74 pub importance_score: f64,
75 pub access_count: i32,
76 pub last_accessed_at: Option<DateTime<Utc>>,
77 pub metadata: serde_json::Value,
78 pub parent_id: Option<Uuid>,
79 pub created_at: DateTime<Utc>,
80 pub updated_at: DateTime<Utc>,
81 pub expires_at: Option<DateTime<Utc>>,
82 pub consolidation_strength: f64,
84 pub decay_rate: f64,
85 pub recall_probability: Option<f64>,
86 pub last_recall_interval: Option<PgInterval>,
87 pub recency_score: f64,
89 pub relevance_score: f64,
90}
91
92impl Serialize for Memory {
93 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
94 where
95 S: serde::Serializer,
96 {
97 use serde::ser::SerializeStruct;
98 let mut state = serializer.serialize_struct("Memory", 21)?;
99 state.serialize_field("id", &self.id)?;
100 state.serialize_field("content", &self.content)?;
101 state.serialize_field("content_hash", &self.content_hash)?;
102 state.serialize_field("embedding", &self.embedding.as_ref().map(|v| v.as_slice()))?;
103 state.serialize_field("tier", &self.tier)?;
104 state.serialize_field("status", &self.status)?;
105 state.serialize_field("importance_score", &self.importance_score)?;
106 state.serialize_field("access_count", &self.access_count)?;
107 state.serialize_field("last_accessed_at", &self.last_accessed_at)?;
108 state.serialize_field("metadata", &self.metadata)?;
109 state.serialize_field("parent_id", &self.parent_id)?;
110 state.serialize_field("created_at", &self.created_at)?;
111 state.serialize_field("updated_at", &self.updated_at)?;
112 state.serialize_field("expires_at", &self.expires_at)?;
113 state.serialize_field("consolidation_strength", &self.consolidation_strength)?;
114 state.serialize_field("decay_rate", &self.decay_rate)?;
115 state.serialize_field("recall_probability", &self.recall_probability)?;
116 state.serialize_field(
117 "last_recall_interval",
118 &self.last_recall_interval.as_ref().map(|i| i.microseconds),
119 )?;
120 state.serialize_field("recency_score", &self.recency_score)?;
121 state.serialize_field("relevance_score", &self.relevance_score)?;
122 state.end()
123 }
124}
125
126impl<'de> Deserialize<'de> for Memory {
127 fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
128 where
129 D: serde::Deserializer<'de>,
130 {
131 Ok(Memory::default())
133 }
134}
135
136#[derive(Debug, Clone, FromRow)]
137pub struct MemorySummary {
138 pub id: Uuid,
139 pub summary_level: String,
140 pub summary_content: String,
141 pub summary_embedding: Option<Vector>,
142 pub start_time: DateTime<Utc>,
143 pub end_time: DateTime<Utc>,
144 pub memory_count: i32,
145 pub metadata: serde_json::Value,
146 pub created_at: DateTime<Utc>,
147 pub updated_at: DateTime<Utc>,
148}
149
150impl Serialize for MemorySummary {
151 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
152 where
153 S: serde::Serializer,
154 {
155 use serde::ser::SerializeStruct;
156 let mut state = serializer.serialize_struct("MemorySummary", 10)?;
157 state.serialize_field("id", &self.id)?;
158 state.serialize_field("summary_level", &self.summary_level)?;
159 state.serialize_field("summary_content", &self.summary_content)?;
160 state.serialize_field(
161 "summary_embedding",
162 &self.summary_embedding.as_ref().map(|v| v.as_slice()),
163 )?;
164 state.serialize_field("start_time", &self.start_time)?;
165 state.serialize_field("end_time", &self.end_time)?;
166 state.serialize_field("memory_count", &self.memory_count)?;
167 state.serialize_field("metadata", &self.metadata)?;
168 state.serialize_field("created_at", &self.created_at)?;
169 state.serialize_field("updated_at", &self.updated_at)?;
170 state.end()
171 }
172}
173
174impl<'de> Deserialize<'de> for MemorySummary {
175 fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
176 where
177 D: serde::Deserializer<'de>,
178 {
179 unimplemented!("MemorySummary deserialization not needed")
180 }
181}
182
183#[derive(Debug, Clone, FromRow)]
184pub struct MemoryCluster {
185 pub id: Uuid,
186 pub cluster_name: String,
187 pub centroid_embedding: Vector,
188 pub concept_tags: Vec<String>,
189 pub member_count: i32,
190 pub tier: MemoryTier,
191 pub metadata: serde_json::Value,
192 pub created_at: DateTime<Utc>,
193 pub updated_at: DateTime<Utc>,
194}
195
196impl Serialize for MemoryCluster {
197 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
198 where
199 S: serde::Serializer,
200 {
201 use serde::ser::SerializeStruct;
202 let mut state = serializer.serialize_struct("MemoryCluster", 9)?;
203 state.serialize_field("id", &self.id)?;
204 state.serialize_field("cluster_name", &self.cluster_name)?;
205 state.serialize_field("centroid_embedding", &self.centroid_embedding.as_slice())?;
206 state.serialize_field("concept_tags", &self.concept_tags)?;
207 state.serialize_field("member_count", &self.member_count)?;
208 state.serialize_field("tier", &self.tier)?;
209 state.serialize_field("metadata", &self.metadata)?;
210 state.serialize_field("created_at", &self.created_at)?;
211 state.serialize_field("updated_at", &self.updated_at)?;
212 state.end()
213 }
214}
215
216impl<'de> Deserialize<'de> for MemoryCluster {
217 fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
218 where
219 D: serde::Deserializer<'de>,
220 {
221 unimplemented!("MemoryCluster deserialization not needed")
222 }
223}
224
225#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
226pub struct MigrationHistoryEntry {
227 pub id: Uuid,
228 pub memory_id: Uuid,
229 pub from_tier: MemoryTier,
230 pub to_tier: MemoryTier,
231 pub migration_reason: Option<String>,
232 pub migrated_at: DateTime<Utc>,
233 pub migration_duration_ms: Option<i32>,
234 pub success: bool,
235 pub error_message: Option<String>,
236}
237
238#[derive(Debug, Clone, Serialize, Deserialize)]
239pub struct CreateMemoryRequest {
240 pub content: String,
241 pub embedding: Option<Vec<f32>>,
242 pub tier: Option<MemoryTier>,
243 pub importance_score: Option<f64>,
244 pub metadata: Option<serde_json::Value>,
245 pub parent_id: Option<Uuid>,
246 pub expires_at: Option<DateTime<Utc>>,
247}
248
249#[derive(Debug, Clone, Serialize, Deserialize)]
250pub struct UpdateMemoryRequest {
251 pub content: Option<String>,
252 pub embedding: Option<Vec<f32>>,
253 pub tier: Option<MemoryTier>,
254 pub importance_score: Option<f64>,
255 pub metadata: Option<serde_json::Value>,
256 pub expires_at: Option<DateTime<Utc>>,
257}
258
259#[derive(Debug, Clone, Serialize, Deserialize, Default)]
260pub struct SearchRequest {
261 pub query_text: Option<String>,
263 pub query_embedding: Option<Vec<f32>>,
264
265 pub search_type: Option<SearchType>,
267 pub hybrid_weights: Option<HybridWeights>,
268
269 pub tier: Option<MemoryTier>,
271 pub date_range: Option<DateRange>,
272 pub importance_range: Option<RangeFilter<f32>>,
273 pub metadata_filters: Option<serde_json::Value>,
274 pub tags: Option<Vec<String>>,
275
276 pub limit: Option<i32>,
278 pub offset: Option<i64>, pub cursor: Option<String>, pub similarity_threshold: Option<f32>,
281 pub include_metadata: Option<bool>,
282 pub include_facets: Option<bool>,
283
284 pub ranking_boost: Option<RankingBoost>,
286 pub explain_score: Option<bool>,
287}
288
289#[derive(Debug, Clone, Serialize, Deserialize)]
290pub enum SearchType {
291 Semantic,
292 Temporal,
293 Hybrid,
294 FullText,
295}
296
297#[derive(Debug, Clone, Serialize, Deserialize)]
298pub struct HybridWeights {
299 pub semantic_weight: f32,
300 pub temporal_weight: f32,
301 pub importance_weight: f32,
302 pub access_frequency_weight: f32,
303}
304
305#[derive(Debug, Clone, Serialize, Deserialize)]
306pub struct DateRange {
307 pub start: Option<DateTime<Utc>>,
308 pub end: Option<DateTime<Utc>>,
309}
310
311#[derive(Debug, Clone, Serialize, Deserialize)]
312pub struct RangeFilter<T> {
313 pub min: Option<T>,
314 pub max: Option<T>,
315}
316
317#[derive(Debug, Clone, Serialize, Deserialize)]
318pub struct RankingBoost {
319 pub recency_boost: Option<f32>,
320 pub importance_boost: Option<f32>,
321 pub access_frequency_boost: Option<f32>,
322 pub tier_boost: Option<std::collections::HashMap<MemoryTier, f32>>,
323}
324
325#[derive(Debug, Clone, Serialize, Deserialize)]
326pub struct SearchResult {
327 pub memory: Memory,
328 pub similarity_score: f32,
329 pub temporal_score: Option<f32>,
330 pub importance_score: f64,
331 pub access_frequency_score: Option<f32>,
332 pub combined_score: f32,
333 pub score_explanation: Option<ScoreExplanation>,
334}
335
336#[derive(Debug, Clone, Serialize, Deserialize)]
337pub struct ScoreExplanation {
338 pub semantic_contribution: f32,
339 pub temporal_contribution: f32,
340 pub importance_contribution: f32,
341 pub access_frequency_contribution: f32,
342 pub total_score: f32,
343 pub factors: Vec<String>,
344}
345
346#[derive(Debug, Clone, Serialize, Deserialize)]
347pub struct SearchResponse {
348 pub results: Vec<SearchResult>,
349 pub total_count: Option<i64>,
350 pub facets: Option<SearchFacets>,
351 pub suggestions: Option<Vec<String>>,
352 pub next_cursor: Option<String>,
353 pub execution_time_ms: u64,
354}
355
356#[derive(Debug, Clone, Serialize, Deserialize)]
357pub struct SearchFacets {
358 pub tiers: std::collections::HashMap<MemoryTier, i64>,
359 pub date_histogram: Vec<DateBucket>,
360 pub importance_ranges: Vec<ImportanceRange>,
361 pub tags: std::collections::HashMap<String, i64>,
362}
363
364#[derive(Debug, Clone, Serialize, Deserialize)]
365pub struct DateBucket {
366 pub date: DateTime<Utc>,
367 pub count: i64,
368 pub interval: String, }
370
371#[derive(Debug, Clone, Serialize, Deserialize)]
372pub struct ImportanceRange {
373 pub min: f32,
374 pub max: f32,
375 pub count: i64,
376 pub label: String,
377}
378
379impl Default for Memory {
380 fn default() -> Self {
381 Self {
382 id: Uuid::new_v4(),
383 content: String::new(),
384 content_hash: String::new(),
385 embedding: None,
386 tier: MemoryTier::Working,
387 status: MemoryStatus::Active,
388 importance_score: 0.5,
389 access_count: 0,
390 last_accessed_at: None,
391 metadata: serde_json::json!({}),
392 parent_id: None,
393 created_at: Utc::now(),
394 updated_at: Utc::now(),
395 expires_at: None,
396 consolidation_strength: 1.0,
397 decay_rate: 1.0,
398 recall_probability: None,
399 last_recall_interval: None,
400 recency_score: 0.0,
401 relevance_score: 0.0,
402 }
403 }
404}
405
406impl Memory {
407 pub fn calculate_content_hash(content: &str) -> String {
408 use sha2::{Digest, Sha256};
409 let mut hasher = Sha256::new();
410 hasher.update(content.as_bytes());
411 hex::encode(hasher.finalize())
412 }
413
414 pub fn recall_count(&self) -> i32 {
416 self.access_count
417 }
418
419 pub fn should_migrate(&self) -> bool {
420 use crate::memory::simple_consolidation::{
421 SimpleConsolidationConfig, SimpleConsolidationEngine,
422 };
423
424 let config = SimpleConsolidationConfig::default();
425 let engine = SimpleConsolidationEngine::new(config);
426
427 match engine.calculate_recall_probability(self, None) {
429 Ok(recall_prob) => recall_prob < 0.86, Err(_) => {
431 match self.tier {
433 MemoryTier::Working => {
434 self.importance_score < 0.3
435 || (self.last_accessed_at.is_some()
436 && Utc::now()
437 .signed_duration_since(self.last_accessed_at.unwrap())
438 .num_hours()
439 > 24)
440 }
441 MemoryTier::Warm => {
442 self.importance_score < 0.1
443 && Utc::now().signed_duration_since(self.updated_at).num_days() > 7
444 }
445 MemoryTier::Cold => {
446 Utc::now().signed_duration_since(self.updated_at).num_days() > 30
447 }
448 MemoryTier::Frozen => false,
449 }
450 }
451 }
452 }
453
454 pub fn next_tier(&self) -> Option<MemoryTier> {
455 match self.tier {
456 MemoryTier::Working => Some(MemoryTier::Warm),
457 MemoryTier::Warm => Some(MemoryTier::Cold),
458 MemoryTier::Cold => Some(MemoryTier::Frozen),
459 MemoryTier::Frozen => None,
460 }
461 }
462
463 pub fn calculate_recall_probability(&self) -> Option<f64> {
467 use crate::memory::math_engine::{MathEngine, MemoryParameters};
468
469 let engine = MathEngine::new();
470 let params = MemoryParameters {
471 consolidation_strength: self.consolidation_strength,
472 decay_rate: self.decay_rate,
473 last_accessed_at: self.last_accessed_at,
474 created_at: self.created_at,
475 access_count: self.access_count,
476 importance_score: self.importance_score,
477 };
478
479 match engine.calculate_recall_probability(¶ms) {
480 Ok(result) => Some(result.recall_probability),
481 Err(e) => {
482 tracing::warn!(
483 "Recall probability calculation failed for memory {}: {}. Using fallback.",
484 self.id,
485 e
486 );
487 let fallback = (self.importance_score * self.consolidation_strength / 10.0)
489 .min(1.0)
490 .max(0.0);
491 Some(fallback)
492 }
493 }
494 }
495
496 pub fn update_consolidation_strength(&mut self, recall_interval: PgInterval) {
500 use crate::memory::math_engine::MathEngine;
501
502 let engine = MathEngine::new();
503
504 match engine.update_consolidation_strength(self.consolidation_strength, recall_interval) {
505 Ok(result) => {
506 self.consolidation_strength = result.new_consolidation_strength;
507 }
508 Err(_) => {
509 let time_hours = recall_interval.microseconds as f64 / 3_600_000_000.0;
511 let increment = time_hours.min(1.0) * 0.1; self.consolidation_strength = (self.consolidation_strength + increment).min(10.0);
513 }
514 }
515 }
516}
517
518#[derive(Debug, Clone, FromRow)]
521pub struct MemoryConsolidationLog {
522 pub id: Uuid,
523 pub memory_id: Uuid,
524 pub event_type: String,
525 pub previous_consolidation_strength: f64,
526 pub new_consolidation_strength: f64,
527 pub previous_recall_probability: Option<f64>,
528 pub new_recall_probability: Option<f64>,
529 pub recall_interval: Option<PgInterval>,
530 pub access_context: serde_json::Value,
531 pub created_at: DateTime<Utc>,
532}
533
534impl Serialize for MemoryConsolidationLog {
535 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
536 where
537 S: serde::Serializer,
538 {
539 use serde::ser::SerializeStruct;
540 let mut state = serializer.serialize_struct("MemoryConsolidationLog", 10)?;
541 state.serialize_field("id", &self.id)?;
542 state.serialize_field("memory_id", &self.memory_id)?;
543 state.serialize_field("event_type", &self.event_type)?;
544 state.serialize_field(
545 "previous_consolidation_strength",
546 &self.previous_consolidation_strength,
547 )?;
548 state.serialize_field(
549 "new_consolidation_strength",
550 &self.new_consolidation_strength,
551 )?;
552 state.serialize_field(
553 "previous_recall_probability",
554 &self.previous_recall_probability,
555 )?;
556 state.serialize_field("new_recall_probability", &self.new_recall_probability)?;
557 state.serialize_field(
558 "recall_interval_microseconds",
559 &self.recall_interval.as_ref().map(|i| i.microseconds),
560 )?;
561 state.serialize_field("access_context", &self.access_context)?;
562 state.serialize_field("created_at", &self.created_at)?;
563 state.end()
564 }
565}
566
567#[derive(Debug, Clone, FromRow)]
568pub struct FrozenMemory {
569 pub id: Uuid,
570 pub original_memory_id: Uuid,
571 pub compressed_content: serde_json::Value, pub original_metadata: Option<serde_json::Value>, pub freeze_reason: Option<String>,
574 pub frozen_at: DateTime<Utc>,
575 pub unfreeze_count: Option<i32>, pub last_unfrozen_at: Option<DateTime<Utc>>, pub compression_ratio: Option<f64>,
578}
579
580impl Serialize for FrozenMemory {
581 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
582 where
583 S: serde::Serializer,
584 {
585 use serde::ser::SerializeStruct;
586 let mut state = serializer.serialize_struct("FrozenMemory", 9)?;
587 state.serialize_field("id", &self.id)?;
588 state.serialize_field("original_memory_id", &self.original_memory_id)?;
589 state.serialize_field("compressed_content", &self.compressed_content)?;
590 state.serialize_field("original_metadata", &self.original_metadata)?;
591 state.serialize_field("freeze_reason", &self.freeze_reason)?;
592 state.serialize_field("frozen_at", &self.frozen_at)?;
593 state.serialize_field("unfreeze_count", &self.unfreeze_count)?;
594 state.serialize_field("last_unfrozen_at", &self.last_unfrozen_at)?;
595 state.serialize_field("compression_ratio", &self.compression_ratio)?;
596 state.end()
597 }
598}
599
600#[derive(Debug, Clone, FromRow, Serialize, Deserialize)]
601pub struct MemoryTierStatistics {
602 pub id: Uuid,
603 pub tier: MemoryTier,
604 pub total_memories: i64,
605 pub average_consolidation_strength: Option<f64>,
606 pub average_recall_probability: Option<f64>,
607 pub average_age_days: Option<f64>,
608 pub total_storage_bytes: i64,
609 pub snapshot_timestamp: DateTime<Utc>,
610}
611
612#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
613pub struct ConsolidationAnalytics {
614 pub tier: MemoryTier,
615 pub total_memories: i64,
616 pub avg_consolidation_strength: Option<f64>,
617 pub avg_recall_probability: Option<f64>,
618 pub avg_decay_rate: Option<f64>,
619 pub avg_age_days: Option<f64>,
620 pub migration_candidates: i64,
621 pub never_accessed: i64,
622 pub accessed_recently: i64,
623}
624
625#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
626pub struct ConsolidationEventSummary {
627 pub event_type: String,
628 pub event_count: i64,
629 pub avg_strength_change: Option<f64>,
630 pub avg_probability_change: Option<f64>,
631 pub avg_recall_interval_hours: Option<f64>,
632}
633
634#[derive(Debug, Clone, Serialize, Deserialize)]
637pub struct FreezeMemoryRequest {
638 pub memory_id: Uuid,
639 pub reason: Option<String>,
640}
641
642#[derive(Debug, Clone, Serialize, Deserialize)]
643pub struct FreezeMemoryResponse {
644 pub frozen_id: Uuid,
645 pub compression_ratio: Option<f64>,
646 pub original_tier: MemoryTier,
647 pub frozen_at: DateTime<Utc>,
648}
649
650#[derive(Debug, Clone, Serialize, Deserialize)]
651pub struct UnfreezeMemoryRequest {
652 pub frozen_id: Uuid,
653 pub target_tier: Option<MemoryTier>,
654}
655
656#[derive(Debug, Clone, Serialize, Deserialize)]
657pub struct UnfreezeMemoryResponse {
658 pub memory_id: Uuid,
659 pub retrieval_delay_seconds: i32,
660 pub restoration_tier: MemoryTier,
661 pub unfrozen_at: DateTime<Utc>,
662}
663
664#[derive(Debug, Clone, Serialize, Deserialize)]
667pub struct ConsolidationSearchRequest {
668 pub min_consolidation_strength: Option<f64>,
669 pub max_consolidation_strength: Option<f64>,
670 pub min_recall_probability: Option<f64>,
671 pub max_recall_probability: Option<f64>,
672 pub include_frozen: Option<bool>,
673 pub tier: Option<MemoryTier>,
674 pub limit: Option<i32>,
675 pub offset: Option<i64>,
676}