codex_memory/memory/
models.rs

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
9use super::math_engine::constants;
10use super::simple_consolidation::{SimpleConsolidationConfig, SimpleConsolidationEngine};
11
12#[derive(Debug, Clone)]
13pub struct SerializableVector(pub Option<Vector>);
14
15impl Serialize for SerializableVector {
16    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
17    where
18        S: serde::Serializer,
19    {
20        match &self.0 {
21            Some(v) => v.as_slice().serialize(serializer),
22            None => serializer.serialize_none(),
23        }
24    }
25}
26
27impl<'de> Deserialize<'de> for SerializableVector {
28    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
29    where
30        D: serde::Deserializer<'de>,
31    {
32        let opt_vec: Option<Vec<f32>> = Option::deserialize(deserializer)?;
33        Ok(SerializableVector(opt_vec.map(Vector::from)))
34    }
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, sqlx::Type)]
38#[sqlx(type_name = "varchar", rename_all = "lowercase")]
39pub enum MemoryTier {
40    Working,
41    Warm,
42    Cold,
43    Frozen,
44}
45
46impl FromStr for MemoryTier {
47    type Err = String;
48
49    fn from_str(s: &str) -> Result<Self, Self::Err> {
50        match s.to_lowercase().as_str() {
51            "working" => Ok(MemoryTier::Working),
52            "warm" => Ok(MemoryTier::Warm),
53            "cold" => Ok(MemoryTier::Cold),
54            "frozen" => Ok(MemoryTier::Frozen),
55            _ => Err(format!("Invalid memory tier: {s}")),
56        }
57    }
58}
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, sqlx::Type)]
61#[sqlx(type_name = "varchar", rename_all = "lowercase")]
62pub enum MemoryStatus {
63    Active,
64    Migrating,
65    Archived,
66    Deleted,
67}
68
69#[derive(Debug, Clone, FromRow)]
70pub struct Memory {
71    pub id: Uuid,
72    pub content: String,
73    pub content_hash: String,
74    pub embedding: Option<Vector>,
75    pub tier: MemoryTier,
76    pub status: MemoryStatus,
77    pub importance_score: f64,
78    pub access_count: i32,
79    pub last_accessed_at: Option<DateTime<Utc>>,
80    pub metadata: serde_json::Value,
81    pub parent_id: Option<Uuid>,
82    pub created_at: DateTime<Utc>,
83    pub updated_at: DateTime<Utc>,
84    pub expires_at: Option<DateTime<Utc>>,
85    // Consolidation fields for memory decay and strengthening
86    pub consolidation_strength: f64,
87    pub decay_rate: f64,
88    pub recall_probability: Option<f64>,
89    pub last_recall_interval: Option<PgInterval>,
90    // Three-component scoring fields
91    pub recency_score: f64,
92    pub relevance_score: f64,
93}
94
95impl Serialize for Memory {
96    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
97    where
98        S: serde::Serializer,
99    {
100        use serde::ser::SerializeStruct;
101        let mut state = serializer.serialize_struct("Memory", 21)?;
102        state.serialize_field("id", &self.id)?;
103        state.serialize_field("content", &self.content)?;
104        state.serialize_field("content_hash", &self.content_hash)?;
105        state.serialize_field("embedding", &self.embedding.as_ref().map(|v| v.as_slice()))?;
106        state.serialize_field("tier", &self.tier)?;
107        state.serialize_field("status", &self.status)?;
108        state.serialize_field("importance_score", &self.importance_score)?;
109        state.serialize_field("access_count", &self.access_count)?;
110        state.serialize_field("last_accessed_at", &self.last_accessed_at)?;
111        state.serialize_field("metadata", &self.metadata)?;
112        state.serialize_field("parent_id", &self.parent_id)?;
113        state.serialize_field("created_at", &self.created_at)?;
114        state.serialize_field("updated_at", &self.updated_at)?;
115        state.serialize_field("expires_at", &self.expires_at)?;
116        state.serialize_field("consolidation_strength", &self.consolidation_strength)?;
117        state.serialize_field("decay_rate", &self.decay_rate)?;
118        state.serialize_field("recall_probability", &self.recall_probability)?;
119        state.serialize_field(
120            "last_recall_interval",
121            &self.last_recall_interval.as_ref().map(|i| i.microseconds),
122        )?;
123        state.serialize_field("recency_score", &self.recency_score)?;
124        state.serialize_field("relevance_score", &self.relevance_score)?;
125        state.end()
126    }
127}
128
129impl<'de> Deserialize<'de> for Memory {
130    fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
131    where
132        D: serde::Deserializer<'de>,
133    {
134        // For now, we'll just return a default memory since we don't need to deserialize from JSON
135        Ok(Memory::default())
136    }
137}
138
139#[derive(Debug, Clone, FromRow)]
140pub struct MemorySummary {
141    pub id: Uuid,
142    pub summary_level: String,
143    pub summary_content: String,
144    pub summary_embedding: Option<Vector>,
145    pub start_time: DateTime<Utc>,
146    pub end_time: DateTime<Utc>,
147    pub memory_count: i32,
148    pub metadata: serde_json::Value,
149    pub created_at: DateTime<Utc>,
150    pub updated_at: DateTime<Utc>,
151}
152
153impl Serialize for MemorySummary {
154    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
155    where
156        S: serde::Serializer,
157    {
158        use serde::ser::SerializeStruct;
159        let mut state = serializer.serialize_struct("MemorySummary", 10)?;
160        state.serialize_field("id", &self.id)?;
161        state.serialize_field("summary_level", &self.summary_level)?;
162        state.serialize_field("summary_content", &self.summary_content)?;
163        state.serialize_field(
164            "summary_embedding",
165            &self.summary_embedding.as_ref().map(|v| v.as_slice()),
166        )?;
167        state.serialize_field("start_time", &self.start_time)?;
168        state.serialize_field("end_time", &self.end_time)?;
169        state.serialize_field("memory_count", &self.memory_count)?;
170        state.serialize_field("metadata", &self.metadata)?;
171        state.serialize_field("created_at", &self.created_at)?;
172        state.serialize_field("updated_at", &self.updated_at)?;
173        state.end()
174    }
175}
176
177impl<'de> Deserialize<'de> for MemorySummary {
178    fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
179    where
180        D: serde::Deserializer<'de>,
181    {
182        unimplemented!("MemorySummary deserialization not needed")
183    }
184}
185
186#[derive(Debug, Clone, FromRow)]
187pub struct MemoryCluster {
188    pub id: Uuid,
189    pub cluster_name: String,
190    pub centroid_embedding: Vector,
191    pub concept_tags: Vec<String>,
192    pub member_count: i32,
193    pub tier: MemoryTier,
194    pub metadata: serde_json::Value,
195    pub created_at: DateTime<Utc>,
196    pub updated_at: DateTime<Utc>,
197}
198
199impl Serialize for MemoryCluster {
200    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
201    where
202        S: serde::Serializer,
203    {
204        use serde::ser::SerializeStruct;
205        let mut state = serializer.serialize_struct("MemoryCluster", 9)?;
206        state.serialize_field("id", &self.id)?;
207        state.serialize_field("cluster_name", &self.cluster_name)?;
208        state.serialize_field("centroid_embedding", &self.centroid_embedding.as_slice())?;
209        state.serialize_field("concept_tags", &self.concept_tags)?;
210        state.serialize_field("member_count", &self.member_count)?;
211        state.serialize_field("tier", &self.tier)?;
212        state.serialize_field("metadata", &self.metadata)?;
213        state.serialize_field("created_at", &self.created_at)?;
214        state.serialize_field("updated_at", &self.updated_at)?;
215        state.end()
216    }
217}
218
219impl<'de> Deserialize<'de> for MemoryCluster {
220    fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
221    where
222        D: serde::Deserializer<'de>,
223    {
224        unimplemented!("MemoryCluster deserialization not needed")
225    }
226}
227
228#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
229pub struct MigrationHistoryEntry {
230    pub id: Uuid,
231    pub memory_id: Uuid,
232    pub from_tier: MemoryTier,
233    pub to_tier: MemoryTier,
234    pub migration_reason: Option<String>,
235    pub migrated_at: DateTime<Utc>,
236    pub migration_duration_ms: Option<i32>,
237    pub success: bool,
238    pub error_message: Option<String>,
239}
240
241#[derive(Debug, Clone, Serialize, Deserialize, Default)]
242pub struct CreateMemoryRequest {
243    pub content: String,
244    pub embedding: Option<Vec<f32>>,
245    pub tier: Option<MemoryTier>,
246    pub importance_score: Option<f64>,
247    pub metadata: Option<serde_json::Value>,
248    pub parent_id: Option<Uuid>,
249    pub expires_at: Option<DateTime<Utc>>,
250}
251
252#[derive(Debug, Clone, Serialize, Deserialize)]
253pub struct UpdateMemoryRequest {
254    pub content: Option<String>,
255    pub embedding: Option<Vec<f32>>,
256    pub tier: Option<MemoryTier>,
257    pub importance_score: Option<f64>,
258    pub metadata: Option<serde_json::Value>,
259    pub expires_at: Option<DateTime<Utc>>,
260}
261
262#[derive(Debug, Clone, Serialize, Deserialize, Default)]
263pub struct SearchRequest {
264    // Query options
265    pub query_text: Option<String>,
266    pub query_embedding: Option<Vec<f32>>,
267
268    // Search type configuration
269    pub search_type: Option<SearchType>,
270    pub hybrid_weights: Option<HybridWeights>,
271
272    // Filtering options
273    pub tier: Option<MemoryTier>,
274    pub date_range: Option<DateRange>,
275    pub importance_range: Option<RangeFilter<f32>>,
276    pub metadata_filters: Option<serde_json::Value>,
277    pub tags: Option<Vec<String>>,
278
279    // Result configuration
280    pub limit: Option<i32>,
281    pub offset: Option<i64>,    // For traditional pagination
282    pub cursor: Option<String>, // For cursor-based pagination
283    pub similarity_threshold: Option<f32>,
284    pub include_metadata: Option<bool>,
285    pub include_facets: Option<bool>,
286
287    // Ranking configuration
288    pub ranking_boost: Option<RankingBoost>,
289    pub explain_score: Option<bool>,
290}
291
292#[derive(Debug, Clone, Serialize, Deserialize, Hash)]
293pub enum SearchType {
294    Semantic,
295    Temporal,
296    Hybrid,
297    FullText,
298}
299
300#[derive(Debug, Clone, Serialize, Deserialize)]
301pub struct HybridWeights {
302    pub semantic_weight: f32,
303    pub temporal_weight: f32,
304    pub importance_weight: f32,
305    pub access_frequency_weight: f32,
306}
307
308#[derive(Debug, Clone, Serialize, Deserialize)]
309pub struct DateRange {
310    pub start: Option<DateTime<Utc>>,
311    pub end: Option<DateTime<Utc>>,
312}
313
314#[derive(Debug, Clone, Serialize, Deserialize)]
315pub struct RangeFilter<T> {
316    pub min: Option<T>,
317    pub max: Option<T>,
318}
319
320#[derive(Debug, Clone, Serialize, Deserialize)]
321pub struct RankingBoost {
322    pub recency_boost: Option<f32>,
323    pub importance_boost: Option<f32>,
324    pub access_frequency_boost: Option<f32>,
325    pub tier_boost: Option<std::collections::HashMap<MemoryTier, f32>>,
326}
327
328#[derive(Debug, Clone, Serialize, Deserialize)]
329pub struct SearchResult {
330    pub memory: Memory,
331    pub similarity_score: f32,
332    pub temporal_score: Option<f32>,
333    pub importance_score: f64,
334    pub access_frequency_score: Option<f32>,
335    pub combined_score: f32,
336    pub score_explanation: Option<ScoreExplanation>,
337}
338
339#[derive(Debug, Clone, Serialize, Deserialize)]
340pub struct ScoreExplanation {
341    pub semantic_contribution: f32,
342    pub temporal_contribution: f32,
343    pub importance_contribution: f32,
344    pub access_frequency_contribution: f32,
345    pub total_score: f32,
346    pub factors: Vec<String>,
347}
348
349#[derive(Debug, Clone, Serialize, Deserialize)]
350pub struct SearchResponse {
351    pub results: Vec<SearchResult>,
352    pub total_count: Option<i64>,
353    pub facets: Option<SearchFacets>,
354    pub suggestions: Option<Vec<String>>,
355    pub next_cursor: Option<String>,
356    pub execution_time_ms: u64,
357}
358
359#[derive(Debug, Clone, Serialize, Deserialize)]
360pub struct SearchFacets {
361    pub tiers: std::collections::HashMap<MemoryTier, i64>,
362    pub date_histogram: Vec<DateBucket>,
363    pub importance_ranges: Vec<ImportanceRange>,
364    pub tags: std::collections::HashMap<String, i64>,
365}
366
367#[derive(Debug, Clone, Serialize, Deserialize)]
368pub struct DateBucket {
369    pub date: DateTime<Utc>,
370    pub count: i64,
371    pub interval: String, // "day", "week", "month"
372}
373
374#[derive(Debug, Clone, Serialize, Deserialize)]
375pub struct ImportanceRange {
376    pub min: f32,
377    pub max: f32,
378    pub count: i64,
379    pub label: String,
380}
381
382impl Default for Memory {
383    fn default() -> Self {
384        Self {
385            id: Uuid::new_v4(),
386            content: String::new(),
387            content_hash: String::new(),
388            embedding: None,
389            tier: MemoryTier::Working,
390            status: MemoryStatus::Active,
391            importance_score: 0.5,
392            access_count: 0,
393            last_accessed_at: None,
394            metadata: serde_json::json!({}),
395            parent_id: None,
396            created_at: Utc::now(),
397            updated_at: Utc::now(),
398            expires_at: None,
399            consolidation_strength: 1.0,
400            decay_rate: 1.0,
401            recall_probability: None,
402            last_recall_interval: None,
403            recency_score: 0.0,
404            relevance_score: 0.0,
405        }
406    }
407}
408
409impl Memory {
410    pub fn calculate_content_hash(content: &str) -> String {
411        use sha2::{Digest, Sha256};
412        let mut hasher = Sha256::new();
413        hasher.update(content.as_bytes());
414        hex::encode(hasher.finalize())
415    }
416
417    /// Get recall count (alias for access_count)
418    pub fn recall_count(&self) -> i32 {
419        self.access_count
420    }
421
422    pub fn should_migrate(&self) -> bool {
423        // Frozen tier never migrates
424        if matches!(self.tier, MemoryTier::Frozen) {
425            return false;
426        }
427
428        let config = SimpleConsolidationConfig::default();
429        let engine = SimpleConsolidationEngine::new(config);
430
431        // Use the simple consolidation engine to calculate recall probability
432        match engine.calculate_recall_probability(self, None) {
433            Ok(recall_prob) => recall_prob < constants::COLD_MIGRATION_THRESHOLD,
434            Err(_) => {
435                // Fallback to basic heuristics if calculation fails
436                match self.tier {
437                    MemoryTier::Working => {
438                        self.importance_score < 0.3
439                            || (self.last_accessed_at.is_some()
440                                && Utc::now()
441                                    .signed_duration_since(self.last_accessed_at.unwrap())
442                                    .num_hours()
443                                    > 24)
444                    }
445                    MemoryTier::Warm => {
446                        self.importance_score < 0.1
447                            && Utc::now().signed_duration_since(self.updated_at).num_days() > 7
448                    }
449                    MemoryTier::Cold => {
450                        Utc::now().signed_duration_since(self.updated_at).num_days() > 30
451                    }
452                    MemoryTier::Frozen => false,
453                }
454            }
455        }
456    }
457
458    pub fn next_tier(&self) -> Option<MemoryTier> {
459        match self.tier {
460            MemoryTier::Working => Some(MemoryTier::Warm),
461            MemoryTier::Warm => Some(MemoryTier::Cold),
462            MemoryTier::Cold => Some(MemoryTier::Frozen),
463            MemoryTier::Frozen => None,
464        }
465    }
466
467    /// Calculate recall probability using the new math engine
468    /// This method now uses the optimized and more accurate math engine
469    /// with proper edge case handling and performance optimization.
470    pub fn calculate_recall_probability(&self) -> Option<f64> {
471        use crate::memory::math_engine::{MathEngine, MemoryParameters};
472
473        let engine = MathEngine::new();
474        let params = MemoryParameters {
475            consolidation_strength: self.consolidation_strength,
476            decay_rate: self.decay_rate,
477            last_accessed_at: self.last_accessed_at,
478            created_at: self.created_at,
479            access_count: self.access_count,
480            importance_score: self.importance_score,
481        };
482
483        match engine.calculate_recall_probability(&params) {
484            Ok(result) => Some(result.recall_probability),
485            Err(e) => {
486                tracing::warn!(
487                    "Recall probability calculation failed for memory {}: {}. Using fallback.",
488                    self.id,
489                    e
490                );
491                // Use mathematically principled fallback based on importance and consolidation
492                let fallback = (self.importance_score * self.consolidation_strength / 10.0)
493                    .min(1.0)
494                    .max(0.0);
495                Some(fallback)
496            }
497        }
498    }
499
500    /// Update consolidation strength using the new math engine
501    /// This method now uses the optimized and more accurate math engine
502    /// with proper error handling and performance optimization.
503    pub fn update_consolidation_strength(&mut self, recall_interval: PgInterval) {
504        use crate::memory::math_engine::MathEngine;
505
506        let engine = MathEngine::new();
507
508        match engine.update_consolidation_strength(self.consolidation_strength, recall_interval) {
509            Ok(result) => {
510                self.consolidation_strength = result.new_consolidation_strength;
511            }
512            Err(_) => {
513                // Fallback to simple increment if calculation fails
514                let time_hours = recall_interval.microseconds as f64 / 3_600_000_000.0;
515                let increment = time_hours.min(1.0) * 0.1; // Conservative increment
516                self.consolidation_strength = (self.consolidation_strength + increment).min(10.0);
517            }
518        }
519    }
520}
521
522// New model structs for consolidation features
523
524#[derive(Debug, Clone, FromRow)]
525pub struct MemoryConsolidationLog {
526    pub id: Uuid,
527    pub memory_id: Uuid,
528    pub event_type: String,
529    pub previous_consolidation_strength: f64,
530    pub new_consolidation_strength: f64,
531    pub previous_recall_probability: Option<f64>,
532    pub new_recall_probability: Option<f64>,
533    pub recall_interval: Option<PgInterval>,
534    pub access_context: serde_json::Value,
535    pub created_at: DateTime<Utc>,
536}
537
538impl Serialize for MemoryConsolidationLog {
539    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
540    where
541        S: serde::Serializer,
542    {
543        use serde::ser::SerializeStruct;
544        let mut state = serializer.serialize_struct("MemoryConsolidationLog", 10)?;
545        state.serialize_field("id", &self.id)?;
546        state.serialize_field("memory_id", &self.memory_id)?;
547        state.serialize_field("event_type", &self.event_type)?;
548        state.serialize_field(
549            "previous_consolidation_strength",
550            &self.previous_consolidation_strength,
551        )?;
552        state.serialize_field(
553            "new_consolidation_strength",
554            &self.new_consolidation_strength,
555        )?;
556        state.serialize_field(
557            "previous_recall_probability",
558            &self.previous_recall_probability,
559        )?;
560        state.serialize_field("new_recall_probability", &self.new_recall_probability)?;
561        state.serialize_field(
562            "recall_interval_microseconds",
563            &self.recall_interval.as_ref().map(|i| i.microseconds),
564        )?;
565        state.serialize_field("access_context", &self.access_context)?;
566        state.serialize_field("created_at", &self.created_at)?;
567        state.end()
568    }
569}
570
571#[derive(Debug, Clone, FromRow)]
572pub struct FrozenMemory {
573    pub id: Uuid,
574    pub original_memory_id: Uuid,
575    pub compressed_content: serde_json::Value, // Matches JSONB in database for compatibility, but contains BYTEA
576    pub original_metadata: Option<serde_json::Value>, // Matches database
577    pub original_content_hash: String,
578    pub original_embedding: Option<Vector>,
579    pub original_tier: MemoryTier,
580    pub freeze_reason: Option<String>,
581    pub frozen_at: DateTime<Utc>,
582    pub unfreeze_count: Option<i32>,             // Matches database
583    pub last_unfrozen_at: Option<DateTime<Utc>>, // Matches database
584    pub compression_ratio: Option<f64>,
585    pub original_size_bytes: Option<i32>,
586    pub compressed_size_bytes: Option<i32>,
587}
588
589impl Serialize for FrozenMemory {
590    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
591    where
592        S: serde::Serializer,
593    {
594        use serde::ser::SerializeStruct;
595        let mut state = serializer.serialize_struct("FrozenMemory", 13)?;
596        state.serialize_field("id", &self.id)?;
597        state.serialize_field("original_memory_id", &self.original_memory_id)?;
598        state.serialize_field("compressed_content", &self.compressed_content)?;
599        state.serialize_field("original_metadata", &self.original_metadata)?;
600        state.serialize_field("original_content_hash", &self.original_content_hash)?;
601        state.serialize_field(
602            "original_embedding",
603            &self.original_embedding.as_ref().map(|v| v.as_slice()),
604        )?;
605        state.serialize_field("original_tier", &self.original_tier)?;
606        state.serialize_field("freeze_reason", &self.freeze_reason)?;
607        state.serialize_field("frozen_at", &self.frozen_at)?;
608        state.serialize_field("unfreeze_count", &self.unfreeze_count)?;
609        state.serialize_field("last_unfrozen_at", &self.last_unfrozen_at)?;
610        state.serialize_field("compression_ratio", &self.compression_ratio)?;
611        state.serialize_field("original_size_bytes", &self.original_size_bytes)?;
612        state.serialize_field("compressed_size_bytes", &self.compressed_size_bytes)?;
613        state.end()
614    }
615}
616
617#[derive(Debug, Clone, FromRow, Serialize, Deserialize)]
618pub struct MemoryTierStatistics {
619    pub id: Uuid,
620    pub tier: MemoryTier,
621    pub total_memories: i64,
622    pub average_consolidation_strength: Option<f64>,
623    pub average_recall_probability: Option<f64>,
624    pub average_age_days: Option<f64>,
625    pub total_storage_bytes: i64,
626    pub snapshot_timestamp: DateTime<Utc>,
627}
628
629#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
630pub struct ConsolidationAnalytics {
631    pub tier: MemoryTier,
632    pub total_memories: i64,
633    pub avg_consolidation_strength: Option<f64>,
634    pub avg_recall_probability: Option<f64>,
635    pub avg_decay_rate: Option<f64>,
636    pub avg_age_days: Option<f64>,
637    pub migration_candidates: i64,
638    pub never_accessed: i64,
639    pub accessed_recently: i64,
640}
641
642#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
643pub struct ConsolidationEventSummary {
644    pub event_type: String,
645    pub event_count: i64,
646    pub avg_strength_change: Option<f64>,
647    pub avg_probability_change: Option<f64>,
648    pub avg_recall_interval_hours: Option<f64>,
649}
650
651// Request/Response structures for freezing operations
652
653#[derive(Debug, Clone, Serialize, Deserialize)]
654pub struct FreezeMemoryRequest {
655    pub memory_id: Uuid,
656    pub reason: Option<String>,
657}
658
659#[derive(Debug, Clone, Serialize, Deserialize)]
660pub struct FreezeMemoryResponse {
661    pub frozen_id: Uuid,
662    pub compression_ratio: Option<f64>,
663    pub original_tier: MemoryTier,
664    pub frozen_at: DateTime<Utc>,
665}
666
667#[derive(Debug, Clone, Serialize, Deserialize)]
668pub struct UnfreezeMemoryRequest {
669    pub frozen_id: Uuid,
670    pub target_tier: Option<MemoryTier>,
671}
672
673#[derive(Debug, Clone, Serialize, Deserialize)]
674pub struct UnfreezeMemoryResponse {
675    pub memory_id: Uuid,
676    pub retrieval_delay_seconds: i32,
677    pub restoration_tier: MemoryTier,
678    pub unfrozen_at: DateTime<Utc>,
679}
680
681// Consolidation-specific search requests
682
683#[derive(Debug, Clone, Serialize, Deserialize)]
684pub struct ConsolidationSearchRequest {
685    pub min_consolidation_strength: Option<f64>,
686    pub max_consolidation_strength: Option<f64>,
687    pub min_recall_probability: Option<f64>,
688    pub max_recall_probability: Option<f64>,
689    pub include_frozen: Option<bool>,
690    pub tier: Option<MemoryTier>,
691    pub limit: Option<i32>,
692    pub offset: Option<i64>,
693}
694
695// Batch operations for frozen memory tier
696
697#[derive(Debug, Clone, Serialize, Deserialize)]
698pub struct BatchFreezeResult {
699    pub memories_frozen: u32,
700    pub total_space_saved_bytes: u64,
701    pub average_compression_ratio: f32,
702    pub processing_time_ms: u64,
703    pub frozen_memory_ids: Vec<Uuid>,
704}
705
706#[derive(Debug, Clone, Serialize, Deserialize)]
707pub struct BatchUnfreezeResult {
708    pub memories_unfrozen: u32,
709    pub total_processing_time_ms: u64,
710    pub average_delay_seconds: f32,
711    pub unfrozen_memory_ids: Vec<Uuid>,
712}
713
714// New model structures for Migration 008: Missing Database Tables
715
716/// Session types for harvest operations
717#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, sqlx::Type)]
718#[sqlx(type_name = "varchar", rename_all = "lowercase")]
719pub enum HarvestSessionType {
720    Silent,
721    Manual,
722    Scheduled,
723    Forced,
724}
725
726/// Session status for harvest operations
727#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, sqlx::Type)]
728#[sqlx(type_name = "varchar", rename_all = "lowercase")]
729pub enum HarvestSessionStatus {
730    InProgress,
731    Completed,
732    Failed,
733    Cancelled,
734}
735
736/// Harvest session tracking for silent harvester operations
737#[derive(Debug, Clone, FromRow, Serialize, Deserialize)]
738pub struct HarvestSession {
739    pub id: Uuid,
740    pub session_type: HarvestSessionType,
741    pub trigger_reason: String,
742    pub started_at: DateTime<Utc>,
743    pub completed_at: Option<DateTime<Utc>>,
744    pub status: HarvestSessionStatus,
745
746    // Processing metrics
747    pub messages_processed: i32,
748    pub patterns_extracted: i32,
749    pub patterns_stored: i32,
750    pub duplicates_filtered: i32,
751    pub processing_time_ms: i64,
752
753    // Configuration snapshot for reproducibility
754    pub config_snapshot: serde_json::Value,
755
756    // Error handling
757    pub error_message: Option<String>,
758    pub retry_count: i32,
759
760    // Performance metrics
761    pub extraction_time_ms: i64,
762    pub deduplication_time_ms: i64,
763    pub storage_time_ms: i64,
764
765    // Resource usage tracking
766    pub memory_usage_mb: Option<f64>,
767    pub cpu_usage_percent: Option<f64>,
768
769    pub created_at: DateTime<Utc>,
770}
771
772/// Pattern types for harvest operations
773#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, sqlx::Type)]
774#[sqlx(type_name = "varchar", rename_all = "lowercase")]
775pub enum HarvestPatternType {
776    Preference,
777    Fact,
778    Decision,
779    Correction,
780    Emotion,
781    Goal,
782    Relationship,
783    Skill,
784}
785
786/// Pattern status for tracking lifecycle
787#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, sqlx::Type)]
788#[sqlx(type_name = "varchar", rename_all = "lowercase")]
789pub enum HarvestPatternStatus {
790    Extracted,
791    Stored,
792    Duplicate,
793    Rejected,
794}
795
796/// Extracted patterns before they become memories
797#[derive(Debug, Clone, FromRow, Serialize, Deserialize)]
798pub struct HarvestPattern {
799    pub id: Uuid,
800    pub harvest_session_id: Uuid,
801    pub pattern_type: HarvestPatternType,
802    pub content: String,
803    pub confidence_score: f64,
804    pub source_message_id: Option<String>,
805    pub context: Option<String>,
806    pub metadata: serde_json::Value,
807
808    // Processing status
809    pub status: HarvestPatternStatus,
810    pub memory_id: Option<Uuid>, // Links to created memory if stored
811    pub rejection_reason: Option<String>,
812
813    // Extraction metrics
814    pub extraction_confidence: Option<f64>,
815    pub similarity_to_existing: Option<f64>,
816
817    pub extracted_at: DateTime<Utc>,
818}
819
820/// Consolidation event types
821#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, sqlx::Type)]
822#[sqlx(type_name = "varchar", rename_all = "lowercase")]
823pub enum ConsolidationEventType {
824    TierMigration,
825    ImportanceUpdate,
826    AccessDecay,
827    BatchConsolidation,
828    ManualOverride,
829}
830
831/// Comprehensive tier migration and consolidation tracking
832#[derive(Debug, Clone, FromRow, Serialize, Deserialize)]
833pub struct ConsolidationEvent {
834    pub id: Uuid,
835    pub event_type: ConsolidationEventType,
836    pub memory_id: Uuid,
837
838    // Tier migration details
839    pub source_tier: Option<String>,
840    pub target_tier: Option<String>,
841    pub migration_reason: Option<String>,
842
843    // Consolidation strength tracking
844    pub old_consolidation_strength: Option<f64>,
845    pub new_consolidation_strength: Option<f64>,
846    pub strength_delta: Option<f64>,
847
848    // Recall probability tracking
849    pub old_recall_probability: Option<f64>,
850    pub new_recall_probability: Option<f64>,
851    pub probability_delta: Option<f64>,
852
853    // Performance metrics
854    pub processing_time_ms: Option<i32>,
855
856    // Context and metadata
857    pub triggered_by: Option<String>, // 'user', 'system', 'scheduler', 'background_service'
858    pub context_metadata: serde_json::Value,
859
860    pub created_at: DateTime<Utc>,
861}
862
863/// Memory access types
864#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, sqlx::Type)]
865#[sqlx(type_name = "varchar", rename_all = "lowercase")]
866pub enum MemoryAccessType {
867    Search,
868    DirectRetrieval,
869    SimilarityMatch,
870    ReflectionAnalysis,
871    ConsolidationProcess,
872}
873
874/// Detailed memory access tracking
875#[derive(Debug, Clone, FromRow, Serialize, Deserialize)]
876pub struct MemoryAccessLog {
877    pub id: Uuid,
878    pub memory_id: Uuid,
879    pub access_type: MemoryAccessType,
880
881    // Access context
882    pub session_id: Option<Uuid>, // Could reference various session types
883    pub user_context: Option<String>,
884    pub query_context: Option<String>,
885
886    // Performance metrics
887    pub retrieval_time_ms: Option<i32>,
888    pub similarity_score: Option<f64>,
889    pub ranking_position: Option<i32>,
890
891    // Impact tracking
892    pub importance_boost: f64,
893    pub access_count_increment: i32,
894
895    pub accessed_at: DateTime<Utc>,
896}
897
898/// System metrics snapshot types
899#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, sqlx::Type)]
900#[sqlx(type_name = "varchar", rename_all = "lowercase")]
901pub enum SystemMetricsSnapshotType {
902    Hourly,
903    Daily,
904    Weekly,
905    OnDemand,
906    Incident,
907}
908
909/// System performance monitoring snapshots
910#[derive(Debug, Clone, FromRow, Serialize, Deserialize)]
911pub struct SystemMetricsSnapshot {
912    pub id: Uuid,
913    pub snapshot_type: SystemMetricsSnapshotType,
914
915    // Memory tier statistics
916    pub working_memory_count: i32,
917    pub warm_memory_count: i32,
918    pub cold_memory_count: i32,
919    pub frozen_memory_count: i32,
920
921    // Storage metrics
922    pub total_storage_bytes: i64,
923    pub compressed_storage_bytes: i64,
924    pub average_compression_ratio: Option<f64>,
925
926    // Performance metrics
927    pub average_query_time_ms: Option<f64>,
928    pub p95_query_time_ms: Option<f64>,
929    pub p99_query_time_ms: Option<f64>,
930    pub slow_query_count: i32,
931
932    // Memory system health
933    pub consolidation_backlog: i32,
934    pub migration_queue_size: i32,
935    pub failed_operations_count: i32,
936
937    // Vector index performance
938    pub vector_index_size_mb: Option<f64>,
939    pub vector_search_performance: serde_json::Value,
940
941    // System resources
942    pub database_cpu_percent: Option<f64>,
943    pub database_memory_mb: Option<f64>,
944    pub connection_count: Option<i32>,
945    pub active_connections: Option<i32>,
946
947    pub recorded_at: DateTime<Utc>,
948}
949
950// Request/Response structures for new table operations
951
952#[derive(Debug, Clone, Serialize, Deserialize)]
953pub struct CreateHarvestSessionRequest {
954    pub session_type: HarvestSessionType,
955    pub trigger_reason: String,
956    pub config_snapshot: Option<serde_json::Value>,
957}
958
959#[derive(Debug, Clone, Serialize, Deserialize)]
960pub struct UpdateHarvestSessionRequest {
961    pub status: Option<HarvestSessionStatus>,
962    pub messages_processed: Option<i32>,
963    pub patterns_extracted: Option<i32>,
964    pub patterns_stored: Option<i32>,
965    pub duplicates_filtered: Option<i32>,
966    pub processing_time_ms: Option<i64>,
967    pub error_message: Option<String>,
968    pub extraction_time_ms: Option<i64>,
969    pub deduplication_time_ms: Option<i64>,
970    pub storage_time_ms: Option<i64>,
971    pub memory_usage_mb: Option<f64>,
972    pub cpu_usage_percent: Option<f64>,
973}
974
975#[derive(Debug, Clone, Serialize, Deserialize)]
976pub struct CreateHarvestPatternRequest {
977    pub harvest_session_id: Uuid,
978    pub pattern_type: HarvestPatternType,
979    pub content: String,
980    pub confidence_score: f64,
981    pub source_message_id: Option<String>,
982    pub context: Option<String>,
983    pub metadata: Option<serde_json::Value>,
984}
985
986#[derive(Debug, Clone, Serialize, Deserialize)]
987pub struct CreateConsolidationEventRequest {
988    pub event_type: ConsolidationEventType,
989    pub memory_id: Uuid,
990    pub source_tier: Option<String>,
991    pub target_tier: Option<String>,
992    pub migration_reason: Option<String>,
993    pub old_consolidation_strength: Option<f64>,
994    pub new_consolidation_strength: Option<f64>,
995    pub old_recall_probability: Option<f64>,
996    pub new_recall_probability: Option<f64>,
997    pub triggered_by: Option<String>,
998    pub context_metadata: Option<serde_json::Value>,
999}
1000
1001#[derive(Debug, Clone, Serialize, Deserialize)]
1002pub struct CreateMemoryAccessLogRequest {
1003    pub memory_id: Uuid,
1004    pub access_type: MemoryAccessType,
1005    pub session_id: Option<Uuid>,
1006    pub user_context: Option<String>,
1007    pub query_context: Option<String>,
1008    pub retrieval_time_ms: Option<i32>,
1009    pub similarity_score: Option<f64>,
1010    pub ranking_position: Option<i32>,
1011    pub importance_boost: Option<f64>,
1012    pub access_count_increment: Option<i32>,
1013}
1014
1015// Analytics structures for the new tables
1016
1017#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
1018pub struct HarvestSuccessRate {
1019    pub total_sessions: i32,
1020    pub successful_sessions: i32,
1021    pub failed_sessions: i32,
1022    pub success_rate: f64,
1023    pub average_processing_time_ms: f64,
1024}
1025
1026#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
1027pub struct TierMigrationStats {
1028    pub source_tier: String,
1029    pub target_tier: String,
1030    pub migration_count: i32,
1031    pub avg_processing_time_ms: f64,
1032    pub success_rate: f64,
1033}
1034
1035#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
1036pub struct TopHarvestPattern {
1037    pub pattern_type: HarvestPatternType,
1038    pub total_extracted: i32,
1039    pub total_stored: i32,
1040    pub avg_confidence: f64,
1041    pub success_rate: f64,
1042}