ai_agent/services/compact/
compact.rs1use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
11#[serde(rename_all = "lowercase")]
12pub enum CompactDirection {
13 Head,
15 Tail,
17 #[default]
19 Smart,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct CompactResult {
25 pub success: bool,
27 pub messages_removed: usize,
29 pub tokens_before: u64,
31 pub tokens_after: u64,
33 pub direction: CompactDirection,
35 pub error: Option<String>,
37}
38
39#[derive(Debug, Clone, Default)]
41pub struct CompactOptions {
42 pub max_tokens: Option<u64>,
44 pub direction: CompactDirection,
46 pub create_boundary: bool,
48 pub system_prompt: Option<String>,
50}
51
52pub async fn compact_messages(
54 _messages: &[impl AsRef<dyn std::any::Any>],
55 options: CompactOptions,
56) -> Result<CompactResult, String> {
57 Ok(CompactResult {
65 success: true,
66 messages_removed: 0,
67 tokens_before: 0,
68 tokens_after: 0,
69 direction: options.direction,
70 error: None,
71 })
72}
73
74pub fn get_recommended_direction(
76 message_count: usize,
77 total_tokens: u64,
78 max_tokens: u64,
79) -> CompactDirection {
80 if total_tokens <= max_tokens {
81 return CompactDirection::Smart;
82 }
83
84 if message_count > 10 {
87 CompactDirection::Head
88 } else {
89 CompactDirection::Smart
90 }
91}
92
93pub fn calculate_messages_to_remove(
95 current_tokens: u64,
96 target_tokens: u64,
97 avg_tokens_per_message: u64,
98) -> usize {
99 if current_tokens <= target_tokens {
100 return 0;
101 }
102
103 let tokens_to_remove = current_tokens - target_tokens;
104 (tokens_to_remove / avg_tokens_per_message) as usize
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn test_compact_direction_default() {
113 let options = CompactOptions::default();
114 assert_eq!(options.direction, CompactDirection::Smart);
115 }
116
117 #[test]
118 fn test_get_recommended_direction_no_compact() {
119 let dir = get_recommended_direction(5, 1000, 2000);
120 assert_eq!(dir, CompactDirection::Smart);
121 }
122
123 #[test]
124 fn test_calculate_messages_to_remove() {
125 let count = calculate_messages_to_remove(5000, 2000, 500);
126 assert_eq!(count, 6);
127 }
128
129 #[test]
130 fn test_calculate_messages_to_remove_no_need() {
131 let count = calculate_messages_to_remove(1000, 2000, 500);
132 assert_eq!(count, 0);
133 }
134}