Skip to main content

matrixcode_core/memory/
config.rs

1//! Memory system constants and configuration.
2
3use serde::{Deserialize, Serialize};
4
5// ============================================================================
6// Constants
7// ============================================================================
8
9/// Maximum importance score ceiling (entries cannot exceed this).
10pub const MAX_IMPORTANCE_CEILING: f64 = 100.0;
11
12/// Minimum content length for similarity check (to avoid short words matching everything).
13pub const MIN_SIMILARITY_LENGTH: usize = 10;
14
15/// Similarity threshold for considering entries as duplicates (0.0-1.0).
16/// Lowered to 0.6 to better detect semantic duplicates (same pattern/type).
17/// Examples that should match: "项目技术栈: Node.js" vs "项目技术栈: Rust"
18pub const SIMILARITY_THRESHOLD: f64 = 0.6;
19
20/// Similarity threshold for merging similar memories (0.0-1.0).
21/// Lower than duplicate threshold to allow semantic merging.
22pub const MERGE_SIMILARITY_THRESHOLD: f64 = 0.7;
23
24/// Minimum content length for memory detection (to avoid capturing too generic content).
25/// Increased to 20 to filter out short fragments.
26pub const MIN_MEMORY_CONTENT_LENGTH: usize = 20;
27
28/// Maximum entries to return from detection (to avoid overwhelming).
29pub const MAX_DETECTED_ENTRIES: usize = 5;
30
31/// Maximum length for memory content before truncation.
32pub const MAX_MEMORY_CONTENT_LENGTH: usize = 200;
33
34/// Maximum length for display (shorter for terminal readability).
35pub const MAX_DISPLAY_LENGTH: usize = 60;
36
37/// Topic overlap threshold for conflict detection.
38pub const CONFLICT_OVERLAY_THRESHOLD: f64 = 0.5;
39
40/// Lower topic overlap threshold when change signal is present.
41pub const CONFLICT_OVERLAY_THRESHOLD_WITH_SIGNAL: f64 = 0.3;
42
43/// Importance threshold for displaying star marker (⭐).
44pub const IMPORTANCE_STAR_THRESHOLD: f64 = 80.0;
45
46/// Weight for relevance in contextual summary (relevance vs importance trade-off).
47pub const CONTEXT_RELEVANCE_WEIGHT: f64 = 0.6;
48
49/// Weight for importance in contextual summary (1.0 - CONTEXT_RELEVANCE_WEIGHT).
50pub const CONTEXT_IMPORTANCE_WEIGHT: f64 = 0.4;
51
52/// Default model for cost-effective memory extraction.
53pub const DEFAULT_MEMORY_EXTRACTOR_MODEL: &str = "claude-3-5-haiku-20241022";
54
55/// Default fast model for AI memory extraction.
56pub const DEFAULT_FAST_MODEL: &str = "claude-3-5-haiku-20241022";
57
58/// Default importance scores by category.
59/// Lower values allow for gradual importance growth through references.
60pub const DEFAULT_IMPORTANCE_DECISION: f64 = 75.0;
61pub const DEFAULT_IMPORTANCE_SOLUTION: f64 = 70.0;
62pub const DEFAULT_IMPORTANCE_PREF: f64 = 65.0;
63pub const DEFAULT_IMPORTANCE_FINDING: f64 = 55.0;
64pub const DEFAULT_IMPORTANCE_TECH: f64 = 45.0;
65pub const DEFAULT_IMPORTANCE_STRUCTURE: f64 = 35.0;
66
67/// AI memory detection mode.
68/// Controls whether AI is used for memory category detection.
69#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
70pub enum AiDetectionMode {
71    /// Hybrid mode: rule-based detection, AI enriches when confidence is low (default).
72    #[default]
73    Auto,
74    /// Always use AI for memory detection (more accurate but slower).
75    Always,
76    /// Never use AI, only rule-based detection (fastest).
77    Never,
78}
79
80impl AiDetectionMode {
81    /// Parse from environment variable string.
82    pub fn from_env() -> Self {
83        match std::env::var("MEMORY_AI_DETECTION")
84            .unwrap_or_default()
85            .to_lowercase()
86            .as_str()
87        {
88            "always" | "true" | "1" => AiDetectionMode::Always,
89            "never" | "false" | "0" => AiDetectionMode::Never,
90            "auto" | "" => AiDetectionMode::Auto,
91            other => {
92                log::warn!(
93                    "Unknown MEMORY_AI_DETECTION value: '{}', using 'auto'",
94                    other
95                );
96                AiDetectionMode::Auto
97            }
98        }
99    }
100
101    /// Whether AI detection should be used.
102    pub fn should_use_ai(&self) -> bool {
103        match self {
104            AiDetectionMode::Always => true,
105            AiDetectionMode::Never => false,
106            AiDetectionMode::Auto => false, // Default to rule-based for speed
107        }
108    }
109
110    /// Whether AI detection should be used for given text length.
111    /// Longer texts benefit more from AI detection.
112    pub fn should_use_ai_for_text(&self, text_len: usize) -> bool {
113        match self {
114            AiDetectionMode::Always => true,
115            AiDetectionMode::Never => false,
116            AiDetectionMode::Auto => text_len > 500,
117        }
118    }
119}
120
121// ============================================================================
122// Memory Configuration
123// ============================================================================
124
125/// Configuration for the memory system.
126#[derive(Debug, Clone, Serialize, Deserialize)]
127pub struct MemoryConfig {
128    /// Maximum number of entries to keep.
129    pub max_entries: usize,
130    /// Minimum importance threshold to keep.
131    pub min_importance: f64,
132    /// Whether auto accumulation is enabled.
133    pub enabled: bool,
134    /// Days before time decay starts.
135    pub decay_start_days: i64,
136    /// Decay rate per period (0.0-1.0).
137    pub decay_rate: f64,
138    /// Importance increment per reference.
139    pub reference_increment: f64,
140    /// Maximum importance ceiling.
141    pub max_importance_ceiling: f64,
142}
143
144impl Default for MemoryConfig {
145    fn default() -> Self {
146        Self {
147            max_entries: 100,
148            min_importance: 30.0,
149            enabled: true,
150            decay_start_days: 30,
151            decay_rate: 0.5,
152            reference_increment: 1.0,
153            max_importance_ceiling: MAX_IMPORTANCE_CEILING,
154        }
155    }
156}
157
158impl MemoryConfig {
159    /// Create a new config with custom max entries.
160    pub fn with_max_entries(max: usize) -> Self {
161        Self {
162            max_entries: max,
163            ..Self::default()
164        }
165    }
166
167    /// Create a minimal config for low-memory environments.
168    pub fn minimal() -> Self {
169        Self {
170            max_entries: 50,
171            min_importance: 50.0,
172            enabled: true,
173            decay_start_days: 14,
174            decay_rate: 0.6,
175            reference_increment: 1.0,
176            max_importance_ceiling: MAX_IMPORTANCE_CEILING,
177        }
178    }
179
180    /// Create a config for long-term archival.
181    pub fn archival() -> Self {
182        Self {
183            max_entries: 500,
184            min_importance: 20.0,
185            enabled: true,
186            decay_start_days: 90,
187            decay_rate: 0.3,
188            reference_increment: 3.0,
189            max_importance_ceiling: MAX_IMPORTANCE_CEILING,
190        }
191    }
192}