use anyhow::Result;
use once_cell::sync::Lazy;
use regex::Regex;
use serde_json::Value;
use crate::llmtrim::gate::{GateKind, PlanEntry, Transform};
use crate::llmtrim::ir::Request;
use crate::llmtrim::provider::Provider;
pub struct HygieneStage {
pub strip_base64: bool,
pub sig_figs: Option<u32>,
pub normalize_unicode: bool,
}
impl Transform for HygieneStage {
fn name(&self) -> &str {
"hygiene"
}
fn gate_kind(&self) -> GateKind {
GateKind::InputTokens
}
fn apply(
&self,
req: &mut Request,
provider: &dyn Provider,
_plan: &mut Vec<PlanEntry>,
) -> Result<()> {
for ptr in crate::llmtrim::cache_zone::compressible_pointers(req, provider) {
let Some(s) = req.get_str(&ptr).map(str::to_string) else {
continue;
};
if let Ok(mut value) = serde_json::from_str::<Value>(&s) {
if self.strip_base64 {
scrub_base64_value(&mut value);
}
if self.normalize_unicode {
normalize_value(&mut value);
}
if let Some(sig) = self.sig_figs {
quantize_value(&mut value, sig);
}
let minified = serde_json::to_string(&value)?;
if minified != s {
req.set(&ptr, Value::String(minified));
}
} else {
let mut text = s.clone();
if self.strip_base64 {
text = scrub_base64_text(&text);
}
if self.normalize_unicode {
text = normalize_text(&text);
}
text = minify_embedded_json(&text);
if text != s {
req.set(&ptr, Value::String(text));
}
}
}
Ok(())
}
}
static DATA_URI: Lazy<Regex> =
Lazy::new(|| Regex::new(r"data:[A-Za-z0-9.+/-]+;base64,[A-Za-z0-9+/=]+").unwrap());
static BASE64_RUN: Lazy<Regex> = Lazy::new(|| Regex::new(r"[A-Za-z0-9+/]{200,}={0,2}").unwrap());
fn placeholder(n: usize) -> String {
format!("[base64 elided: {n} chars]")
}
fn scrub_base64_text(s: &str) -> String {
let s1 = DATA_URI.replace_all(s, |c: ®ex::Captures| placeholder(c[0].len()));
BASE64_RUN
.replace_all(&s1, |c: ®ex::Captures| placeholder(c[0].len()))
.into_owned()
}
fn scrub_base64_value(v: &mut Value) {
match v {
Value::String(s) => *s = scrub_base64_text(s),
Value::Array(arr) => arr.iter_mut().for_each(scrub_base64_value),
Value::Object(map) => map.values_mut().for_each(scrub_base64_value),
_ => {}
}
}
static JSON_FENCE: Lazy<Regex> =
Lazy::new(|| Regex::new(r"(?is)```json\b[^\r\n]*\r?\n(.*?)```").unwrap());
fn minify_embedded_json(text: &str) -> String {
let fenced = JSON_FENCE.replace_all(text, |caps: ®ex::Captures| {
let inner = &caps[1];
match minify_json_str(inner) {
Some(min) => format!("```json\n{min}\n```"),
None => caps[0].to_string(),
}
});
minify_balanced_spans(&fenced)
}
fn minify_json_str(s: &str) -> Option<String> {
let value: Value = serde_json::from_str(s.trim()).ok()?;
let min = serde_json::to_string(&value).ok()?;
(min.len() < s.len()).then_some(min)
}
const MAX_JSON_SCAN: usize = 256 * 1024;
fn minify_balanced_spans(text: &str) -> String {
let bytes = text.as_bytes();
let mut out = String::with_capacity(text.len());
let mut i = 0;
let mut failed_scan_budget = bytes.len().max(MAX_JSON_SCAN);
while i < bytes.len() {
if bytes[i..].starts_with(b"```") {
let after = i + 3;
let end = find_fence_close(bytes, after).unwrap_or(bytes.len());
out.push_str(&text[i..end]);
i = end;
continue;
}
if (bytes[i] == b'{' || bytes[i] == b'[')
&& failed_scan_budget > 0
&& looks_like_json_open(bytes, i)
{
let limit = (i + MAX_JSON_SCAN).min(bytes.len());
match balanced_json_end(&bytes[..limit], i) {
Some(end) => {
if let Some(min) = minify_json_str(&text[i..end]) {
out.push_str(&min);
i = end;
continue;
}
failed_scan_budget = failed_scan_budget.saturating_sub(end - i);
}
None => failed_scan_budget = failed_scan_budget.saturating_sub(limit - i),
}
}
let ch_len = text[i..].chars().next().map_or(1, char::len_utf8);
out.push_str(&text[i..i + ch_len]);
i += ch_len;
}
out
}
fn find_fence_close(bytes: &[u8], from: usize) -> Option<usize> {
let mut j = from;
while j + 3 <= bytes.len() {
if bytes[j..].starts_with(b"```") {
return Some(j + 3);
}
j += 1;
}
None
}
fn looks_like_json_open(bytes: &[u8], open: usize) -> bool {
let mut j = open + 1;
while j < bytes.len() && (bytes[j] as char).is_whitespace() {
j += 1;
}
let Some(&next) = bytes.get(j) else {
return false;
};
if bytes[open] == b'{' {
next == b'"' || next == b'}'
} else {
matches!(
next,
b'"' | b'{' | b'[' | b']' | b'-' | b't' | b'f' | b'n' | b'0'..=b'9'
)
}
}
fn balanced_json_end(bytes: &[u8], start: usize) -> Option<usize> {
let mut depth = 0i32;
let mut in_str = false;
let mut escaped = false;
let mut i = start;
while i < bytes.len() {
let b = bytes[i];
if in_str {
if escaped {
escaped = false;
} else if b == b'\\' {
escaped = true;
} else if b == b'"' {
in_str = false;
}
} else {
match b {
b'"' => in_str = true,
b'{' | b'[' => depth += 1,
b'}' | b']' => {
depth -= 1;
if depth == 0 {
return Some(i + 1);
}
if depth < 0 {
return None; }
}
_ => {}
}
}
i += 1;
}
None
}
fn normalize_text(s: &str) -> String {
use unicode_normalization::UnicodeNormalization;
s.chars()
.filter_map(|c| match c {
'\u{00A0}' | '\u{2007}' | '\u{2009}' | '\u{200A}' | '\u{202F}' => Some(' '),
'\u{200B}' | '\u{FEFF}' | '\u{2060}' | '\u{00AD}' => None,
other => Some(other),
})
.nfkc()
.collect()
}
fn normalize_value(v: &mut Value) {
match v {
Value::String(s) => *s = normalize_text(s),
Value::Array(arr) => arr.iter_mut().for_each(normalize_value),
Value::Object(map) => map.values_mut().for_each(normalize_value),
_ => {}
}
}
fn round_sig(x: f64, sig: u32) -> f64 {
if x == 0.0 || !x.is_finite() || sig == 0 {
return x;
}
let d = sig as i32 - 1 - x.abs().log10().floor() as i32;
let f = 10f64.powi(d);
(x * f).round() / f
}
fn quantize_value(v: &mut Value, sig: u32) {
match v {
Value::Number(n) if !n.is_i64() && !n.is_u64() => {
let raw = n.to_string();
if (raw.contains('.') || raw.contains('e') || raw.contains('E'))
&& let Some(x) = n.as_f64()
&& let Some(r) = serde_json::Number::from_f64(round_sig(x, sig))
{
*n = r;
}
}
Value::Array(a) => a.iter_mut().for_each(|e| quantize_value(e, sig)),
Value::Object(m) => m.values_mut().for_each(|e| quantize_value(e, sig)),
_ => {}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::llmtrim::ir::ProviderKind;
use crate::llmtrim::pipeline;
use crate::llmtrim::provider::OpenAiProvider;
use crate::llmtrim::tokenizer::counter_for;
use serde_json::json;
fn run(body: Value, stage: HygieneStage) -> (Request, bool) {
let mut req = Request::from_value(ProviderKind::OpenAi, body);
let counter = counter_for(ProviderKind::OpenAi, Some("gpt-4o")).unwrap();
let stages: Vec<Box<dyn Transform>> = vec![Box::new(stage)];
let out = pipeline::run(&mut req, &OpenAiProvider, counter.as_ref(), &stages);
let applied = out.stages[0].applied;
(req, applied)
}
#[test]
fn minifies_pretty_json_content_losslessly() {
let pretty =
serde_json::to_string_pretty(&json!({"a":1,"b":[1,2,3],"c":{"d":true}})).unwrap();
let body = json!({"model":"gpt-4o","messages":[{"role":"user","content":pretty}]});
let (req, applied) = run(
body,
HygieneStage {
strip_base64: false,
sig_figs: None,
normalize_unicode: false,
},
);
assert!(applied, "minify should reduce tokens");
let now = req.get_str("/messages/0/content").unwrap();
assert!(!now.contains("\n "), "pretty whitespace removed");
let before: Value = json!({"a":1,"b":[1,2,3],"c":{"d":true}});
assert_eq!(serde_json::from_str::<Value>(now).unwrap(), before);
}
#[test]
fn minifies_fenced_json_block_leaving_prose() {
let pretty = "{\n \"a\": 1,\n \"b\": [\n 1,\n 2\n ]\n}";
let content = format!("Here is the response:\n```json\n{pretty}\n```\nThanks!");
let body = json!({"model":"gpt-4o","messages":[{"role":"user","content":content}]});
let (req, applied) = run(
body,
HygieneStage {
strip_base64: false,
sig_figs: None,
normalize_unicode: false,
},
);
assert!(applied, "embedded fenced JSON minifies → fewer tokens");
let now = req.get_str("/messages/0/content").unwrap();
assert!(
now.contains("Here is the response:"),
"leading prose untouched"
);
assert!(now.contains("Thanks!"), "trailing prose untouched");
assert!(
now.contains(r#"{"a":1,"b":[1,2]}"#),
"JSON minified losslessly: {now}"
);
assert!(!now.contains("\n \"a\""), "pretty whitespace gone");
}
#[cfg(feature = "tiktoken")]
#[test]
fn minifies_inline_json_span_leaving_prose() {
let content = "The server returned { \"ok\" : true , \"count\" : 3 } as the body.";
let body = json!({"model":"gpt-4o","messages":[{"role":"user","content":content}]});
let (req, applied) = run(
body,
HygieneStage {
strip_base64: false,
sig_figs: None,
normalize_unicode: false,
},
);
assert!(applied, "inline JSON span minifies");
let now = req.get_str("/messages/0/content").unwrap();
assert!(
now.starts_with("The server returned "),
"prose before span intact"
);
assert!(now.ends_with(" as the body."), "prose after span intact");
assert!(
now.contains(r#"{"ok":true,"count":3}"#),
"span minified: {now}"
);
}
#[test]
fn invalid_json_braces_are_left_alone() {
let content = "Use the { placeholder } token and call foo() { return 1; } please.";
let body = json!({"model":"gpt-4o","messages":[{"role":"user","content":content}]});
let (req, applied) = run(
body,
HygieneStage {
strip_base64: false,
sig_figs: None,
normalize_unicode: false,
},
);
assert!(!applied, "no valid JSON span → nothing to minify");
assert_eq!(
req.get_str("/messages/0/content").unwrap(),
content,
"invalid-JSON braces left exactly verbatim"
);
}
#[test]
fn embedded_json_scanner_handles_braces_inside_strings() {
let content = r#"prefix {"k": "a}b\"c[d", "n": 2} suffix"#;
let out = minify_embedded_json(content);
assert!(out.starts_with("prefix "), "prose before intact: {out}");
assert!(out.ends_with(" suffix"), "prose after intact: {out}");
assert!(
out.contains(r#""a}b\"c[d""#),
"string-with-braces preserved exactly: {out}"
);
let lo = out.find('{').unwrap();
let hi = out.rfind('}').unwrap();
let v: Value = serde_json::from_str(&out[lo..=hi]).expect("still valid JSON");
assert_eq!(v["k"], json!("a}b\"c[d"));
assert_eq!(v["n"], json!(2));
}
#[test]
fn embedded_json_minify_is_lossless_on_numbers() {
let content = "data: {\"x\": 123456789012345678, \"y\": 0.1234567890123456789}";
let out = minify_embedded_json(content);
assert!(out.contains("123456789012345678"), "large int exact: {out}");
assert!(
out.contains("0.1234567890123456789"),
"long decimal exact: {out}"
);
}
#[test]
fn leaves_prose_untouched_without_base64() {
let body = json!({"model":"gpt-4o","messages":[{"role":"user","content":"just some prose, not json"}]});
let (req, applied) = run(
body,
HygieneStage {
strip_base64: false,
sig_figs: None,
normalize_unicode: false,
},
);
assert!(!applied, "prose is not JSON; nothing to minify");
assert_eq!(
req.get_str("/messages/0/content"),
Some("just some prose, not json")
);
}
#[test]
fn strips_base64_in_prose_when_enabled() {
let blob = "A".repeat(300);
let content = format!("attached blob {blob} thanks");
let body = json!({"model":"gpt-4o","messages":[{"role":"user","content":content}]});
let (req, applied) = run(
body,
HygieneStage {
strip_base64: true,
sig_figs: None,
normalize_unicode: false,
},
);
assert!(applied);
let now = req.get_str("/messages/0/content").unwrap();
assert!(now.contains("base64 elided"));
assert!(!now.contains(&"A".repeat(300)));
}
#[test]
fn strips_base64_inside_json_string_values() {
let blob = "Zm9v".repeat(60); let body = json!({"model":"gpt-4o","messages":[{"role":"user","content": serde_json::to_string(&json!({"img": blob, "name": "ok"})).unwrap()}]});
let (req, applied) = run(
body,
HygieneStage {
strip_base64: true,
sig_figs: None,
normalize_unicode: false,
},
);
assert!(applied);
let now = req.get_str("/messages/0/content").unwrap();
let v: Value = serde_json::from_str(now).expect("still valid JSON");
assert_eq!(v.get("name").and_then(Value::as_str), Some("ok"));
assert!(
v.get("img")
.and_then(Value::as_str)
.unwrap()
.contains("elided"),
"base64 value elided, JSON structure intact"
);
}
#[test]
fn base64_not_stripped_when_disabled() {
let content = format!("blob {} end", "A".repeat(300));
let body = json!({"model":"gpt-4o","messages":[{"role":"user","content":content.clone()}]});
let (req, applied) = run(
body,
HygieneStage {
strip_base64: false,
sig_figs: None,
normalize_unicode: false,
},
);
assert!(!applied, "disabled => prose untouched");
assert_eq!(req.get_str("/messages/0/content"), Some(content.as_str()));
}
#[test]
fn quantizes_floats_when_enabled() {
let inner =
serde_json::to_string(&json!({"a":8.123456789,"b":2,"c":123.456789,"name":"keep"}))
.unwrap();
let body = json!({"model":"gpt-4o","messages":[{"role":"user","content":inner}]});
let (req, applied) = run(
body,
HygieneStage {
strip_base64: false,
sig_figs: Some(3),
normalize_unicode: false,
},
);
assert!(applied, "rounding long floats cuts tokens");
let v: Value = serde_json::from_str(req.get_str("/messages/0/content").unwrap()).unwrap();
assert_eq!(v["a"], json!(8.12));
assert_eq!(v["b"], json!(2), "integers untouched");
assert_eq!(v["name"], json!("keep"), "strings untouched");
}
#[test]
fn normalize_text_strips_waste_folds_nfkc_keeps_joiners() {
let out = normalize_text("\u{FEFF}AB\u{200B}x\u{00A0}y fi 👨\u{200D}👩");
assert!(!out.contains('\u{FEFF}'), "BOM stripped");
assert!(!out.contains('\u{200B}'), "zero-width space stripped");
assert!(out.contains("AB"), "full-width folded to ASCII");
assert!(out.contains("x y"), "NBSP folded to a plain space");
assert!(out.contains("fi"), "fi ligature folded (NFKC)");
assert!(
out.contains('\u{200D}'),
"ZWJ preserved — emoji/script meaning kept (universality)"
);
}
#[test]
fn normalize_unicode_wired_through_stage_for_prose() {
let messy = "CPU load high\u{200B}\u{200B}\u{200B}".to_string();
let body = json!({"model":"gpt-4o","messages":[{"role":"user","content":messy}]});
let (req, applied) = run(
body,
HygieneStage {
strip_base64: false,
sig_figs: None,
normalize_unicode: true,
},
);
assert!(applied, "folding full-width + dropping ZWSP cuts tokens");
let now = req.get_str("/messages/0/content").unwrap();
assert!(now.starts_with("CPU") && !now.contains('\u{200B}'));
}
#[test]
fn quantize_preserves_large_integers() {
let mut v = serde_json::from_str::<Value>(r#"{"id": 12345678901234567890}"#).unwrap();
quantize_value(&mut v, 4);
assert_eq!(v["id"].to_string(), "12345678901234567890");
}
}