use serde_json::Value;
use trusty_mpm_core::compress::{CompressionLevel, compress_output};
pub type ToolOverrides = std::collections::HashMap<String, CompressionLevel>;
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, utoipa::ToSchema)]
pub struct OptimizerConfig {
pub default_level: CompressionLevel,
pub tool_overrides: ToolOverrides,
pub suppress_redundant_reads: bool,
}
impl Default for OptimizerConfig {
fn default() -> Self {
Self {
default_level: CompressionLevel::Trim,
tool_overrides: ToolOverrides::new(),
suppress_redundant_reads: true,
}
}
}
#[derive(Debug, serde::Deserialize)]
struct OptimizerToml {
#[serde(default)]
default: OptimizerTomlDefault,
#[serde(default)]
tools: std::collections::HashMap<String, TomlLevel>,
}
#[derive(Debug, Clone, Copy)]
struct TomlLevel(CompressionLevel);
impl<'de> serde::Deserialize<'de> for TomlLevel {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
de_level(deserializer).map(TomlLevel)
}
}
#[derive(Debug, serde::Deserialize)]
struct OptimizerTomlDefault {
#[serde(default = "default_trim", deserialize_with = "de_level")]
level: CompressionLevel,
}
impl Default for OptimizerTomlDefault {
fn default() -> Self {
Self {
level: CompressionLevel::Trim,
}
}
}
fn default_trim() -> CompressionLevel {
CompressionLevel::Trim
}
fn de_level<'de, D>(deserializer: D) -> Result<CompressionLevel, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::Deserialize;
let raw = String::deserialize(deserializer)?;
let lowered = raw.to_ascii_lowercase();
CompressionLevel::deserialize(serde::de::value::StrDeserializer::<D::Error>::new(&lowered))
}
impl OptimizerConfig {
pub fn level_for(&self, tool: &str) -> CompressionLevel {
self.tool_overrides
.get(tool)
.copied()
.unwrap_or(self.default_level)
}
pub fn load_from_file(path: &std::path::Path) -> anyhow::Result<Self> {
let raw = match std::fs::read_to_string(path) {
Ok(raw) => raw,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
return Ok(Self::default());
}
Err(e) => return Err(e.into()),
};
let parsed: OptimizerToml = toml::from_str(&raw)?;
let tool_overrides = parsed
.tools
.into_iter()
.map(|(tool, level)| (tool, level.0))
.collect();
Ok(Self {
default_level: parsed.default.level,
tool_overrides,
suppress_redundant_reads: true,
})
}
}
pub fn optimize_tool_output(
config: &OptimizerConfig,
tool_name: &str,
payload: &mut Value,
) -> trusty_mpm_core::compress::CompressionStats {
let level = config.level_for(tool_name);
if level == CompressionLevel::Off {
return Default::default();
}
if let Some(output) = payload.get("output").and_then(Value::as_str) {
let (compressed, stats) = compress_output(output, level);
payload["output"] = Value::String(compressed);
stats
} else {
Default::default()
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
use trusty_mpm_core::compress::TRIM_THRESHOLD_BYTES;
fn big_output() -> String {
(0..500)
.map(|i| format!("line {i} with some padding content"))
.collect::<Vec<_>>()
.join("\n")
}
#[test]
fn optimize_rewrites_large_output_at_trim_level() {
let cfg = OptimizerConfig::default(); let original = big_output();
assert!(original.len() > TRIM_THRESHOLD_BYTES);
let mut payload = json!({ "tool": "Bash", "output": original.clone() });
let stats = optimize_tool_output(&cfg, "Bash", &mut payload);
assert!(stats.saved_bytes() > 0);
let rewritten = payload["output"].as_str().unwrap();
assert!(rewritten.len() < original.len());
}
#[test]
fn optimize_skips_small_output_at_trim_level() {
let cfg = OptimizerConfig::default();
let mut payload = json!({ "tool": "Bash", "output": "tiny output" });
let stats = optimize_tool_output(&cfg, "Bash", &mut payload);
assert_eq!(stats.saved_bytes(), 0);
assert_eq!(payload["output"], "tiny output");
}
#[test]
fn optimize_uses_tool_override() {
let mut overrides = ToolOverrides::new();
overrides.insert("Bash".into(), CompressionLevel::Caveman);
let cfg = OptimizerConfig {
tool_overrides: overrides,
..OptimizerConfig::default()
};
assert_eq!(cfg.level_for("Read"), CompressionLevel::Trim);
assert_eq!(cfg.level_for("Bash"), CompressionLevel::Caveman);
let mut payload = json!({ "tool": "Bash", "output": "small" });
optimize_tool_output(&cfg, "Bash", &mut payload);
assert!(payload["output"].as_str().unwrap().contains("suppressed"));
}
#[test]
fn optimize_off_level_is_passthrough() {
let cfg = OptimizerConfig {
default_level: CompressionLevel::Off,
..OptimizerConfig::default()
};
let original = big_output();
let mut payload = json!({ "tool": "Bash", "output": original.clone() });
let stats = optimize_tool_output(&cfg, "Bash", &mut payload);
assert_eq!(stats.saved_bytes(), 0);
assert_eq!(payload["output"], original);
}
#[test]
fn optimize_caveman_always_replaces() {
let cfg = OptimizerConfig {
default_level: CompressionLevel::Caveman,
..OptimizerConfig::default()
};
let mut payload = json!({ "tool": "Read", "output": "x" });
optimize_tool_output(&cfg, "Read", &mut payload);
assert!(payload["output"].as_str().unwrap().contains("suppressed"));
}
#[test]
fn optimize_missing_output_field_is_noop() {
let cfg = OptimizerConfig::default();
let mut payload = json!({ "tool": "Bash" });
let stats = optimize_tool_output(&cfg, "Bash", &mut payload);
assert_eq!(stats.saved_bytes(), 0);
}
#[test]
fn config_loads_from_toml_file() {
use std::io::Write;
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("optimizer.toml");
let mut file = std::fs::File::create(&path).unwrap();
writeln!(
file,
"[default]\nlevel = \"Caveman\"\n\n[tools]\nRead = \"Off\""
)
.unwrap();
let cfg = OptimizerConfig::load_from_file(&path).unwrap();
assert_eq!(cfg.default_level, CompressionLevel::Caveman);
assert_eq!(cfg.level_for("Read"), CompressionLevel::Off);
assert_eq!(cfg.level_for("Bash"), CompressionLevel::Caveman);
}
#[test]
fn config_missing_file_is_default() {
let dir = tempfile::tempdir().unwrap();
let cfg = OptimizerConfig::load_from_file(&dir.path().join("absent.toml")).unwrap();
assert_eq!(cfg.default_level, OptimizerConfig::default().default_level);
}
}