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
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    // Consolidation fields for memory decay and strengthening
83    pub consolidation_strength: f64,
84    pub decay_rate: f64,
85    pub recall_probability: Option<f64>,
86    pub last_recall_interval: Option<PgInterval>,
87    // Three-component scoring fields
88    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        // For now, we'll just return a default memory since we don't need to deserialize from JSON
132        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    // Query options
262    pub query_text: Option<String>,
263    pub query_embedding: Option<Vec<f32>>,
264
265    // Search type configuration
266    pub search_type: Option<SearchType>,
267    pub hybrid_weights: Option<HybridWeights>,
268
269    // Filtering options
270    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    // Result configuration
277    pub limit: Option<i32>,
278    pub offset: Option<i64>,    // For traditional pagination
279    pub cursor: Option<String>, // For cursor-based pagination
280    pub similarity_threshold: Option<f32>,
281    pub include_metadata: Option<bool>,
282    pub include_facets: Option<bool>,
283
284    // Ranking configuration
285    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, // "day", "week", "month"
369}
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    /// Get recall count (alias for access_count)
415    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        // Frozen tier never migrates
425        if matches!(self.tier, MemoryTier::Frozen) {
426            return false;
427        }
428
429        let config = SimpleConsolidationConfig::default();
430        let engine = SimpleConsolidationEngine::new(config);
431
432        // Use the simple consolidation engine to calculate recall probability
433        match engine.calculate_recall_probability(self, None) {
434            Ok(recall_prob) => recall_prob < 0.86, // Story 2 threshold
435            Err(_) => {
436                // Fallback to basic heuristics if calculation fails
437                match self.tier {
438                    MemoryTier::Working => {
439                        self.importance_score < 0.3
440                            || (self.last_accessed_at.is_some()
441                                && Utc::now()
442                                    .signed_duration_since(self.last_accessed_at.unwrap())
443                                    .num_hours()
444                                    > 24)
445                    }
446                    MemoryTier::Warm => {
447                        self.importance_score < 0.1
448                            && Utc::now().signed_duration_since(self.updated_at).num_days() > 7
449                    }
450                    MemoryTier::Cold => {
451                        Utc::now().signed_duration_since(self.updated_at).num_days() > 30
452                    }
453                    MemoryTier::Frozen => false,
454                }
455            }
456        }
457    }
458
459    pub fn next_tier(&self) -> Option<MemoryTier> {
460        match self.tier {
461            MemoryTier::Working => Some(MemoryTier::Warm),
462            MemoryTier::Warm => Some(MemoryTier::Cold),
463            MemoryTier::Cold => Some(MemoryTier::Frozen),
464            MemoryTier::Frozen => None,
465        }
466    }
467
468    /// Calculate recall probability using the new math engine
469    /// This method now uses the optimized and more accurate math engine
470    /// with proper edge case handling and performance optimization.
471    pub fn calculate_recall_probability(&self) -> Option<f64> {
472        use crate::memory::math_engine::{MathEngine, MemoryParameters};
473
474        let engine = MathEngine::new();
475        let params = MemoryParameters {
476            consolidation_strength: self.consolidation_strength,
477            decay_rate: self.decay_rate,
478            last_accessed_at: self.last_accessed_at,
479            created_at: self.created_at,
480            access_count: self.access_count,
481            importance_score: self.importance_score,
482        };
483
484        match engine.calculate_recall_probability(&params) {
485            Ok(result) => Some(result.recall_probability),
486            Err(e) => {
487                tracing::warn!(
488                    "Recall probability calculation failed for memory {}: {}. Using fallback.",
489                    self.id,
490                    e
491                );
492                // Use mathematically principled fallback based on importance and consolidation
493                let fallback = (self.importance_score * self.consolidation_strength / 10.0)
494                    .min(1.0)
495                    .max(0.0);
496                Some(fallback)
497            }
498        }
499    }
500
501    /// Update consolidation strength using the new math engine
502    /// This method now uses the optimized and more accurate math engine
503    /// with proper error handling and performance optimization.
504    pub fn update_consolidation_strength(&mut self, recall_interval: PgInterval) {
505        use crate::memory::math_engine::MathEngine;
506
507        let engine = MathEngine::new();
508
509        match engine.update_consolidation_strength(self.consolidation_strength, recall_interval) {
510            Ok(result) => {
511                self.consolidation_strength = result.new_consolidation_strength;
512            }
513            Err(_) => {
514                // Fallback to simple increment if calculation fails
515                let time_hours = recall_interval.microseconds as f64 / 3_600_000_000.0;
516                let increment = time_hours.min(1.0) * 0.1; // Conservative increment
517                self.consolidation_strength = (self.consolidation_strength + increment).min(10.0);
518            }
519        }
520    }
521}
522
523// New model structs for consolidation features
524
525#[derive(Debug, Clone, FromRow)]
526pub struct MemoryConsolidationLog {
527    pub id: Uuid,
528    pub memory_id: Uuid,
529    pub event_type: String,
530    pub previous_consolidation_strength: f64,
531    pub new_consolidation_strength: f64,
532    pub previous_recall_probability: Option<f64>,
533    pub new_recall_probability: Option<f64>,
534    pub recall_interval: Option<PgInterval>,
535    pub access_context: serde_json::Value,
536    pub created_at: DateTime<Utc>,
537}
538
539impl Serialize for MemoryConsolidationLog {
540    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
541    where
542        S: serde::Serializer,
543    {
544        use serde::ser::SerializeStruct;
545        let mut state = serializer.serialize_struct("MemoryConsolidationLog", 10)?;
546        state.serialize_field("id", &self.id)?;
547        state.serialize_field("memory_id", &self.memory_id)?;
548        state.serialize_field("event_type", &self.event_type)?;
549        state.serialize_field(
550            "previous_consolidation_strength",
551            &self.previous_consolidation_strength,
552        )?;
553        state.serialize_field(
554            "new_consolidation_strength",
555            &self.new_consolidation_strength,
556        )?;
557        state.serialize_field(
558            "previous_recall_probability",
559            &self.previous_recall_probability,
560        )?;
561        state.serialize_field("new_recall_probability", &self.new_recall_probability)?;
562        state.serialize_field(
563            "recall_interval_microseconds",
564            &self.recall_interval.as_ref().map(|i| i.microseconds),
565        )?;
566        state.serialize_field("access_context", &self.access_context)?;
567        state.serialize_field("created_at", &self.created_at)?;
568        state.end()
569    }
570}
571
572#[derive(Debug, Clone, FromRow)]
573pub struct FrozenMemory {
574    pub id: Uuid,
575    pub original_memory_id: Uuid,
576    pub compressed_content: serde_json::Value, // Matches JSONB in database
577    pub original_metadata: Option<serde_json::Value>, // Matches database
578    pub freeze_reason: Option<String>,
579    pub frozen_at: DateTime<Utc>,
580    pub unfreeze_count: Option<i32>,             // Matches database
581    pub last_unfrozen_at: Option<DateTime<Utc>>, // Matches database
582    pub compression_ratio: Option<f64>,
583}
584
585impl Serialize for FrozenMemory {
586    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
587    where
588        S: serde::Serializer,
589    {
590        use serde::ser::SerializeStruct;
591        let mut state = serializer.serialize_struct("FrozenMemory", 9)?;
592        state.serialize_field("id", &self.id)?;
593        state.serialize_field("original_memory_id", &self.original_memory_id)?;
594        state.serialize_field("compressed_content", &self.compressed_content)?;
595        state.serialize_field("original_metadata", &self.original_metadata)?;
596        state.serialize_field("freeze_reason", &self.freeze_reason)?;
597        state.serialize_field("frozen_at", &self.frozen_at)?;
598        state.serialize_field("unfreeze_count", &self.unfreeze_count)?;
599        state.serialize_field("last_unfrozen_at", &self.last_unfrozen_at)?;
600        state.serialize_field("compression_ratio", &self.compression_ratio)?;
601        state.end()
602    }
603}
604
605#[derive(Debug, Clone, FromRow, Serialize, Deserialize)]
606pub struct MemoryTierStatistics {
607    pub id: Uuid,
608    pub tier: MemoryTier,
609    pub total_memories: i64,
610    pub average_consolidation_strength: Option<f64>,
611    pub average_recall_probability: Option<f64>,
612    pub average_age_days: Option<f64>,
613    pub total_storage_bytes: i64,
614    pub snapshot_timestamp: DateTime<Utc>,
615}
616
617#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
618pub struct ConsolidationAnalytics {
619    pub tier: MemoryTier,
620    pub total_memories: i64,
621    pub avg_consolidation_strength: Option<f64>,
622    pub avg_recall_probability: Option<f64>,
623    pub avg_decay_rate: Option<f64>,
624    pub avg_age_days: Option<f64>,
625    pub migration_candidates: i64,
626    pub never_accessed: i64,
627    pub accessed_recently: i64,
628}
629
630#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
631pub struct ConsolidationEventSummary {
632    pub event_type: String,
633    pub event_count: i64,
634    pub avg_strength_change: Option<f64>,
635    pub avg_probability_change: Option<f64>,
636    pub avg_recall_interval_hours: Option<f64>,
637}
638
639// Request/Response structures for freezing operations
640
641#[derive(Debug, Clone, Serialize, Deserialize)]
642pub struct FreezeMemoryRequest {
643    pub memory_id: Uuid,
644    pub reason: Option<String>,
645}
646
647#[derive(Debug, Clone, Serialize, Deserialize)]
648pub struct FreezeMemoryResponse {
649    pub frozen_id: Uuid,
650    pub compression_ratio: Option<f64>,
651    pub original_tier: MemoryTier,
652    pub frozen_at: DateTime<Utc>,
653}
654
655#[derive(Debug, Clone, Serialize, Deserialize)]
656pub struct UnfreezeMemoryRequest {
657    pub frozen_id: Uuid,
658    pub target_tier: Option<MemoryTier>,
659}
660
661#[derive(Debug, Clone, Serialize, Deserialize)]
662pub struct UnfreezeMemoryResponse {
663    pub memory_id: Uuid,
664    pub retrieval_delay_seconds: i32,
665    pub restoration_tier: MemoryTier,
666    pub unfrozen_at: DateTime<Utc>,
667}
668
669// Consolidation-specific search requests
670
671#[derive(Debug, Clone, Serialize, Deserialize)]
672pub struct ConsolidationSearchRequest {
673    pub min_consolidation_strength: Option<f64>,
674    pub max_consolidation_strength: Option<f64>,
675    pub min_recall_probability: Option<f64>,
676    pub max_recall_probability: Option<f64>,
677    pub include_frozen: Option<bool>,
678    pub tier: Option<MemoryTier>,
679    pub limit: Option<i32>,
680    pub offset: Option<i64>,
681}