lean_ctx/core/context_kernel/
adaptive_hook.rs1use super::adaptive_bridge::KernelCompressionAdvice;
4
5#[derive(Debug, Clone, Copy, serde::Serialize)]
7pub struct CompressionAdvice {
8 pub should_reduce: bool,
10 pub bounce_rate: f64,
12 pub advice: KernelCompressionAdvice,
14}
15
16impl CompressionAdvice {
17 fn maintain() -> Self {
18 Self {
19 should_reduce: false,
20 bounce_rate: 0.0,
21 advice: KernelCompressionAdvice::Maintain,
22 }
23 }
24
25 fn from_rate(bounce_rate: f64) -> Self {
26 let advice = super::adaptive_bridge::compression_advice(bounce_rate);
27 Self {
28 should_reduce: advice == KernelCompressionAdvice::Reduce,
29 bounce_rate,
30 advice,
31 }
32 }
33}
34
35pub fn update_from_bounce_tracker() {
37 if !super::kernel_config::is_enabled() {
38 return;
39 }
40 let tracker = crate::core::bounce_tracker::global()
41 .lock()
42 .unwrap_or_else(std::sync::PoisonError::into_inner);
43 let total_bounces = tracker.total_bounces();
44 let _total_wasted_tokens = tracker.total_wasted_tokens();
45 let denominator = total_bounces.saturating_add(100).max(1);
46 let rate = total_bounces as f64 / denominator as f64;
47 drop(tracker);
48 super::adaptive_bridge::update_bounce_signal(rate);
49}
50
51#[must_use]
53pub fn advice_for_path(path: &str) -> CompressionAdvice {
54 if !super::kernel_config::is_enabled() {
55 return CompressionAdvice::maintain();
56 }
57 let tracker = crate::core::bounce_tracker::global()
58 .lock()
59 .unwrap_or_else(std::sync::PoisonError::into_inner);
60 tracker
61 .bounce_rate_for_extension(path)
62 .map_or_else(CompressionAdvice::maintain, CompressionAdvice::from_rate)
63}
64
65#[must_use]
67pub fn global_advice() -> CompressionAdvice {
68 CompressionAdvice::from_rate(super::adaptive_bridge::current_bounce_rate())
69}
70
71pub fn reset() {
73 super::adaptive_bridge::reset();
74}
75
76#[cfg(test)]
77mod tests {
78 use super::{advice_for_path, update_from_bounce_tracker};
79 use crate::core::context_kernel::{adaptive_bridge, kernel_config};
80
81 fn setup() -> std::sync::MutexGuard<'static, ()> {
82 let guard = kernel_config::KERNEL_TEST_LOCK
83 .lock()
84 .unwrap_or_else(std::sync::PoisonError::into_inner);
85 kernel_config::reset_features();
86 adaptive_bridge::reset();
87 let mut tracker = crate::core::bounce_tracker::global()
88 .lock()
89 .unwrap_or_else(std::sync::PoisonError::into_inner);
90 *tracker = crate::core::bounce_tracker::BounceTracker::new();
91 drop(tracker);
92 guard
93 }
94
95 #[test]
96 fn update_feeds_bridge() {
97 let _guard = setup();
98 crate::core::bounce_tracker::global()
99 .lock()
100 .unwrap_or_else(std::sync::PoisonError::into_inner)
101 .record_expansion(None, 20);
102 update_from_bounce_tracker();
103 assert!(adaptive_bridge::current_bounce_rate() > 0.0);
104 }
105
106 #[test]
107 fn advice_for_unknown_path() {
108 let _guard = setup();
109 assert_eq!(
110 advice_for_path("unknown.rs").advice,
111 adaptive_bridge::KernelCompressionAdvice::Maintain
112 );
113 }
114
115 #[test]
116 fn disabled_kernel_noop() {
117 let _guard = setup();
118 let mut features = kernel_config::features();
119 features.enabled = false;
120 kernel_config::update_features(features);
121 update_from_bounce_tracker();
122 assert_eq!(
123 advice_for_path("disabled.rs").advice,
124 adaptive_bridge::KernelCompressionAdvice::Maintain
125 );
126 }
127}