Skip to main content

vv_agent/memory/
microcompact.rs

1use serde::{de::Error as _, Deserialize, Deserializer, Serialize};
2
3#[derive(Debug, Clone, Copy, PartialEq, Serialize)]
4pub struct MicrocompactionPolicy {
5    pub trigger_ratio: f64,
6    pub target_ratio: f64,
7    pub keep_recent_cycles: u32,
8    pub min_result_chars: u32,
9}
10
11#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
12#[error("microcompaction_policy_invalid: {message}")]
13pub struct MicrocompactionPolicyError {
14    message: String,
15}
16
17#[derive(Deserialize)]
18#[serde(deny_unknown_fields)]
19struct MicrocompactionPolicyWire {
20    trigger_ratio: f64,
21    target_ratio: f64,
22    keep_recent_cycles: u32,
23    min_result_chars: u32,
24}
25
26impl Default for MicrocompactionPolicy {
27    fn default() -> Self {
28        Self {
29            trigger_ratio: 0.75,
30            target_ratio: 0.60,
31            keep_recent_cycles: 3,
32            min_result_chars: 500,
33        }
34    }
35}
36
37impl<'de> Deserialize<'de> for MicrocompactionPolicy {
38    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
39    where
40        D: Deserializer<'de>,
41    {
42        let wire = MicrocompactionPolicyWire::deserialize(deserializer)?;
43        let policy = Self {
44            trigger_ratio: wire.trigger_ratio,
45            target_ratio: wire.target_ratio,
46            keep_recent_cycles: wire.keep_recent_cycles,
47            min_result_chars: wire.min_result_chars,
48        };
49        policy.validate().map_err(D::Error::custom)?;
50        Ok(policy)
51    }
52}
53
54impl MicrocompactionPolicy {
55    pub fn new(
56        trigger_ratio: f64,
57        target_ratio: f64,
58        keep_recent_cycles: u32,
59        min_result_chars: u32,
60    ) -> Result<Self, MicrocompactionPolicyError> {
61        let policy = Self {
62            trigger_ratio,
63            target_ratio,
64            keep_recent_cycles,
65            min_result_chars,
66        };
67        policy.validate()?;
68        Ok(policy)
69    }
70
71    pub fn validate(&self) -> Result<(), MicrocompactionPolicyError> {
72        if !self.trigger_ratio.is_finite()
73            || !self.target_ratio.is_finite()
74            || self.target_ratio <= 0.0
75            || self.target_ratio >= self.trigger_ratio
76            || self.trigger_ratio > 1.0
77        {
78            return Err(MicrocompactionPolicyError {
79                message: "expected 0 < target_ratio < trigger_ratio <= 1".to_string(),
80            });
81        }
82        if self.min_result_chars == 0 {
83            return Err(MicrocompactionPolicyError {
84                message: "min_result_chars must be at least 1".to_string(),
85            });
86        }
87        Ok(())
88    }
89}