#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ContextMode {
#[default]
Full,
Fast,
}
#[derive(Debug, Clone, Copy)]
pub struct LayerBudget {
pub fraction: f64,
}
impl LayerBudget {
pub fn tokens(&self, total: usize) -> usize {
(total as f64 * self.fraction) as usize
}
}
#[derive(Debug, Clone, Copy)]
pub struct CompactionThresholds {
pub soft: f64,
pub hard: f64,
}
impl Default for CompactionThresholds {
fn default() -> Self {
Self {
soft: 0.70,
hard: 0.95,
}
}
}
#[derive(Debug, Clone)]
pub struct MemgineConfig {
pub token_budget: usize,
pub layer1_budget: LayerBudget,
pub layer2_budget: LayerBudget,
pub layer3_budget: LayerBudget,
pub layer4_budget: LayerBudget,
pub thresholds: CompactionThresholds,
pub working_set_max: usize,
pub working_set_keep_recent: usize,
pub environment_max: usize,
pub max_skills_in_context: usize,
pub evolution_threshold: f64,
pub code_budget_weight: f64,
pub structured_budget_weight: f64,
pub conversation_keep_recent: usize,
pub compaction_batch_size: usize,
pub speculative_compaction_interval: usize,
pub response_reservation: usize,
pub context_budget_fraction: f64,
}
impl Default for MemgineConfig {
fn default() -> Self {
Self {
token_budget: 8000,
layer1_budget: LayerBudget { fraction: 0.05 },
layer2_budget: LayerBudget { fraction: 0.50 },
layer3_budget: LayerBudget { fraction: 0.30 },
layer4_budget: LayerBudget { fraction: 0.15 },
thresholds: CompactionThresholds::default(),
working_set_max: 10,
working_set_keep_recent: 3,
environment_max: 5,
max_skills_in_context: 6,
evolution_threshold: 0.6,
code_budget_weight: 1.5,
structured_budget_weight: 0.8,
conversation_keep_recent: 6,
compaction_batch_size: 8,
speculative_compaction_interval: 10,
response_reservation: 4096,
context_budget_fraction: 0.40,
}
}
}
impl MemgineConfig {
pub fn layer_tokens(&self, layer: u8) -> usize {
match layer {
1 => self.layer1_budget.tokens(self.token_budget),
2 => self.layer2_budget.tokens(self.token_budget),
3 => self.layer3_budget.tokens(self.token_budget),
4 => self.layer4_budget.tokens(self.token_budget),
_ => 0,
}
}
pub fn effective_budget(&self, model_context_window: Option<usize>) -> usize {
match model_context_window {
Some(ctx_window) if ctx_window > 0 => {
let remaining = ctx_window.saturating_sub(self.response_reservation);
let dynamic = (remaining as f64 * self.context_budget_fraction) as usize;
dynamic.max(2000).min(remaining)
}
_ => self.token_budget,
}
}
pub fn validate(&self) -> Result<(), String> {
let total = self.layer1_budget.fraction
+ self.layer2_budget.fraction
+ self.layer3_budget.fraction
+ self.layer4_budget.fraction;
if (total - 1.0).abs() > 0.01 {
return Err(format!("Layer fractions must sum to 1.0, got {}", total));
}
if self.thresholds.soft >= self.thresholds.hard {
return Err("Soft threshold must be < hard threshold".to_string());
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn effective_budget_none_uses_fixed() {
let config = MemgineConfig::default();
assert_eq!(config.effective_budget(None), 8000);
}
#[test]
fn effective_budget_large_model() {
let config = MemgineConfig::default();
let budget = config.effective_budget(Some(272_000));
assert_eq!(budget, 107_161);
}
#[test]
fn effective_budget_small_model() {
let config = MemgineConfig::default();
let budget = config.effective_budget(Some(8_000));
assert_eq!(budget, 2000);
}
#[test]
fn effective_budget_zero_window() {
let config = MemgineConfig::default();
assert_eq!(config.effective_budget(Some(0)), 8000);
}
#[test]
fn effective_budget_medium_model() {
let config = MemgineConfig::default();
let budget = config.effective_budget(Some(128_000));
assert_eq!(budget, 49_561);
}
}