Skip to main content

vv_agent/memory/manager/
emergency.rs

1use super::{
2    helpers::{adjust_start_for_tool_context, sanitize_empty_assistant_messages},
3    MemoryManager,
4};
5use crate::types::{Message, MessageRole};
6
7impl MemoryManager {
8    pub fn emergency_compact(&self, messages: &[Message], drop_ratio: f64) -> Vec<Message> {
9        if messages.len() <= 2 {
10            return messages.to_vec();
11        }
12
13        let (system_message, non_system) = if messages
14            .first()
15            .is_some_and(|message| message.role == MessageRole::System)
16        {
17            (messages.first().cloned(), &messages[1..])
18        } else {
19            (None, messages)
20        };
21        if non_system.is_empty() {
22            return system_message.into_iter().collect();
23        }
24
25        let keep_count = self.config.keep_recent_messages.max(1);
26        let clamped_ratio = drop_ratio.clamp(0.0, 0.95);
27        let max_droppable = non_system.len().saturating_sub(keep_count);
28        let drop_count = if max_droppable == 0 {
29            0
30        } else {
31            ((non_system.len() as f64 * clamped_ratio).floor() as usize)
32                .max(1)
33                .min(max_droppable)
34        };
35        let mut start_index = drop_count.min(non_system.len());
36        if non_system.len().saturating_sub(start_index) < keep_count {
37            start_index = non_system.len().saturating_sub(keep_count);
38        }
39        start_index = adjust_start_for_tool_context(non_system, start_index);
40
41        let mut compacted = Vec::new();
42        if let Some(system_message) = system_message {
43            compacted.push(system_message);
44        }
45        compacted.extend_from_slice(&non_system[start_index..]);
46        sanitize_empty_assistant_messages(compacted)
47    }
48}