agent_proxy_rust_core/
compression.rs1#[derive(Debug, Clone, Default)]
19pub struct CompressionStats {
20 pub tokenless_pre: u64,
23 pub tokenless_post: u64,
25 pub tokenless_experimental: u64,
27
28 pub proxy_req_pre: u64,
31 pub proxy_req_post: u64,
33 pub proxy_res_pre: u64,
35 pub proxy_res_post: u64,
37
38 pub rtk_saved: u64,
41}
42
43impl CompressionStats {
44 #[must_use]
46 pub fn tokenless_saved(&self) -> u64 {
47 self.tokenless_pre.saturating_sub(self.tokenless_post)
48 }
49
50 #[must_use]
52 pub fn proxy_schema_saved(&self) -> u64 {
53 self.proxy_req_pre.saturating_sub(self.proxy_req_post)
54 }
55
56 #[must_use]
58 pub fn proxy_response_saved(&self) -> u64 {
59 self.proxy_res_pre.saturating_sub(self.proxy_res_post)
60 }
61
62 #[must_use]
64 pub fn total_saved(&self) -> u64 {
65 self.tokenless_saved()
66 + self.tokenless_experimental
67 + self.proxy_schema_saved()
68 + self.proxy_response_saved()
69 + self.rtk_saved
70 }
71}
72
73#[must_use]
78pub fn read_tokenless_stats() -> CompressionStats {
79 let Ok(value) = std::env::var("TOKENLESS_TOKENS") else {
80 return CompressionStats::default();
81 };
82 if value.is_empty() {
83 return CompressionStats::default();
84 }
85 parse_tokenless_json(&value).unwrap_or_default()
86}
87
88fn parse_tokenless_json(json: &str) -> Option<CompressionStats> {
89 #[derive(serde::Deserialize)]
90 struct TokenlessHeader {
91 pre: Option<u64>,
92 post: Option<u64>,
93 experimental: Option<u64>,
94 }
95 let h: TokenlessHeader = serde_json::from_str(json).ok()?;
96 Some(CompressionStats {
97 tokenless_pre: h.pre.unwrap_or(0),
98 tokenless_post: h.post.unwrap_or(0),
99 tokenless_experimental: h.experimental.unwrap_or(0),
100 ..Default::default()
101 })
102}
103
104#[cfg(test)]
109#[allow(clippy::unwrap_used)]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn test_default_is_zero() {
115 let s = CompressionStats::default();
116 assert_eq!(s.tokenless_pre, 0);
117 assert_eq!(s.total_saved(), 0);
118 }
119
120 #[test]
121 fn test_tokenless_saved() {
122 let s = CompressionStats {
123 tokenless_pre: 800,
124 tokenless_post: 300,
125 ..Default::default()
126 };
127 assert_eq!(s.tokenless_saved(), 500);
128 }
129
130 #[test]
131 fn test_saturating_sub_prevents_underflow() {
132 let s = CompressionStats {
133 tokenless_pre: 100,
134 tokenless_post: 200,
135 ..Default::default()
136 };
137 assert_eq!(s.tokenless_saved(), 0);
138 }
139
140 #[test]
141 fn test_total_saved_sums_all_layers() {
142 let s = CompressionStats {
143 tokenless_pre: 800,
144 tokenless_post: 300, tokenless_experimental: 150, proxy_req_pre: 300,
147 proxy_req_post: 220, proxy_res_pre: 1200,
149 proxy_res_post: 800, rtk_saved: 0,
151 };
152 assert_eq!(s.total_saved(), 1130);
154 }
155
156 #[test]
157 fn test_parse_valid_json() {
158 let stats = parse_tokenless_json(r#"{"pre":800,"post":300,"experimental":150}"#).unwrap();
159 assert_eq!(stats.tokenless_pre, 800);
160 assert_eq!(stats.tokenless_post, 300);
161 assert_eq!(stats.tokenless_experimental, 150);
162 }
163
164 #[test]
165 fn test_parse_partial_json() {
166 let stats = parse_tokenless_json(r#"{"pre":500}"#).unwrap();
167 assert_eq!(stats.tokenless_pre, 500);
168 assert_eq!(stats.tokenless_post, 0);
169 assert_eq!(stats.tokenless_experimental, 0);
170 }
171
172 #[test]
173 fn test_parse_invalid_json_returns_none() {
174 assert!(parse_tokenless_json("not json").is_none());
175 assert!(parse_tokenless_json("").is_none());
176 }
177
178 #[test]
179 fn test_parse_missing_all_fields_returns_default() {
180 let stats = parse_tokenless_json(r"{}").unwrap();
181 assert_eq!(stats.tokenless_pre, 0);
182 }
183
184 #[test]
185 fn test_proxy_schema_saved() {
186 let s = CompressionStats {
187 proxy_req_pre: 500,
188 proxy_req_post: 350,
189 ..Default::default()
190 };
191 assert_eq!(s.proxy_schema_saved(), 150);
192 }
193
194 #[test]
195 fn test_proxy_response_saved() {
196 let s = CompressionStats {
197 proxy_res_pre: 2000,
198 proxy_res_post: 1200,
199 ..Default::default()
200 };
201 assert_eq!(s.proxy_response_saved(), 800);
202 }
203}