ai_agent/services/context_collapse/
mod.rs1pub mod operations;
7pub mod persist;
8
9pub use operations::*;
10pub use persist::*;
11
12#[derive(Debug, Clone, Default)]
14pub struct ContextCollapseStats {
15 pub collapsed_spans: usize,
16 pub staged_spans: usize,
17 pub health: ContextCollapseHealth,
18}
19
20#[derive(Debug, Clone, Default)]
22pub struct ContextCollapseHealth {
23 pub total_errors: usize,
24 pub total_empty_spawns: usize,
25 pub empty_spawn_warning_emitted: bool,
26}
27
28static STATS: std::sync::LazyLock<std::sync::Mutex<ContextCollapseStats>> =
30 std::sync::LazyLock::new(|| std::sync::Mutex::new(ContextCollapseStats::default()));
31
32pub fn is_context_collapse_enabled() -> bool {
36 false
39}
40
41pub fn reset_context_collapse() {
43 let mut stats = STATS.lock().unwrap();
44 *stats = ContextCollapseStats::default();
45}
46
47pub fn apply_collapses_if_needed<T>(messages: T) -> ContextCollapseApplyResult<T>
50where
51 T: Clone,
52{
53 ContextCollapseApplyResult {
56 messages,
57 changed: false,
58 }
59}
60
61pub fn is_withheld_prompt_too_long() -> bool {
63 false
64}
65
66pub fn recover_from_overflow<T>(messages: T) -> T
68where
69 T: Clone,
70{
71 messages
73}
74
75#[derive(Debug, Clone)]
77pub struct ContextCollapseApplyResult<T> {
78 pub messages: T,
79 pub changed: bool,
80}
81
82pub fn get_stats() -> ContextCollapseStats {
84 STATS.lock().unwrap().clone()
85}
86
87pub fn increment_collapsed_spans() {
89 let mut stats = STATS.lock().unwrap();
90 stats.collapsed_spans += 1;
91}
92
93pub fn increment_staged_spans() {
95 let mut stats = STATS.lock().unwrap();
96 stats.staged_spans += 1;
97}
98
99pub fn record_error() {
101 let mut stats = STATS.lock().unwrap();
102 stats.health.total_errors += 1;
103}
104
105pub fn record_empty_spawn() {
107 let mut stats = STATS.lock().unwrap();
108 stats.health.total_empty_spawns += 1;
109}
110
111pub fn emit_empty_spawn_warning() {
113 let mut stats = STATS.lock().unwrap();
114 stats.health.empty_spawn_warning_emitted = true;
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120
121 #[test]
122 fn test_is_context_collapse_enabled() {
123 assert!(!is_context_collapse_enabled());
125 }
126
127 #[test]
128 fn test_get_stats_default() {
129 let stats = get_stats();
130 assert_eq!(stats.collapsed_spans, 0);
131 assert_eq!(stats.staged_spans, 0);
132 assert_eq!(stats.health.total_errors, 0);
133 assert_eq!(stats.health.total_empty_spawns, 0);
134 assert!(!stats.health.empty_spawn_warning_emitted);
135 }
136
137 #[test]
138 fn test_increment_collapsed_spans() {
139 increment_collapsed_spans();
140 let stats = get_stats();
141 assert_eq!(stats.collapsed_spans, 1);
142 reset_context_collapse();
144 }
145
146 #[test]
147 fn test_apply_collapses_if_needed_no_change() {
148 let messages = vec![1, 2, 3];
149 let result = apply_collapses_if_needed(messages.clone());
150 assert!(!result.changed);
151 assert_eq!(result.messages, messages);
152 }
153
154 #[test]
155 fn test_recover_from_overflow() {
156 let messages = vec![1, 2, 3];
157 let result = recover_from_overflow(messages.clone());
158 assert_eq!(result, messages);
159 }
160}