use std::fmt;
use std::str::FromStr;
pub const DEFAULT_MAX_OUTPUT_BYTES: usize = 64 * 1024;
pub const DEFAULT_MAX_DEDUP_ENTRIES_PER_SESSION: usize = 128;
pub const DEFAULT_MAX_DEDUP_SESSIONS: usize = 64;
pub const LZW_DICTIONARY_HEADER: &str = "[Forge LZW Dictionary]";
pub const REPAIR_DICTIONARY_HEADER: &str = "[Forge RePair Dictionary]";
pub const DICTIONARY_MAX_DICT_SIZE: usize = 20;
pub const DICTIONARY_MAX_INPUT_BYTES: usize = 50_000;
pub const DICTIONARY_MIN_OCCURRENCES: usize = 3;
pub const DICTIONARY_MIN_NET_SAVINGS_BYTES: usize = 32;
pub const DICTIONARY_MIN_ENTRY_SAVINGS_BYTES: usize = 16;
pub const DICTIONARY_MIN_NET_SAVINGS_PERCENT: usize = 3;
pub fn is_dictionary_compressed_output(output: &str) -> bool {
output.starts_with(LZW_DICTIONARY_HEADER) || output.starts_with(REPAIR_DICTIONARY_HEADER)
}
pub fn dictionary_has_meaningful_savings(original_len: usize, savings: usize) -> bool {
savings >= DICTIONARY_MIN_NET_SAVINGS_BYTES
&& savings.saturating_mul(100) / original_len.max(1) >= DICTIONARY_MIN_NET_SAVINGS_PERCENT
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
pub enum ToolOutputCompressionMode {
Disabled,
Safe,
#[default]
Standard,
Aggressive,
}
impl ToolOutputCompressionMode {
pub fn as_str(self) -> &'static str {
match self {
Self::Disabled => "disabled",
Self::Safe => "safe",
Self::Standard => "standard",
Self::Aggressive => "aggressive",
}
}
pub fn enabled(self) -> bool {
self != Self::Disabled
}
}
impl fmt::Display for ToolOutputCompressionMode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl FromStr for ToolOutputCompressionMode {
type Err = String;
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value.trim().to_ascii_lowercase().as_str() {
"disabled" | "off" | "false" | "none" => Ok(Self::Disabled),
"safe" => Ok(Self::Safe),
"standard" | "on" | "true" => Ok(Self::Standard),
"aggressive" => Ok(Self::Aggressive),
other => Err(format!(
"tool output compression must be disabled, safe, standard, or aggressive, got '{other}'"
)),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ToolOutputCompressionMethod {
#[default]
Lzw,
Repair,
Auto,
}
impl ToolOutputCompressionMethod {
pub fn as_str(self) -> &'static str {
match self {
Self::Lzw => "lzw",
Self::Repair => "repair",
Self::Auto => "auto",
}
}
}
impl fmt::Display for ToolOutputCompressionMethod {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl FromStr for ToolOutputCompressionMethod {
type Err = String;
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value.trim().to_ascii_lowercase().as_str() {
"lzw" => Ok(Self::Lzw),
"repair" | "re-pair" => Ok(Self::Repair),
"auto" => Ok(Self::Auto),
other => Err(format!(
"tool output compression method must be lzw, repair, or auto, got '{other}'"
)),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ToolOutputCompressionConfig {
pub mode: ToolOutputCompressionMode,
pub method: ToolOutputCompressionMethod,
pub redact_secrets: bool,
pub enable_dedup: bool,
pub enable_memo: bool,
pub session_id: Option<String>,
pub max_output_bytes: usize,
pub max_dedup_entries_per_session: usize,
pub max_dedup_sessions: usize,
}
impl Default for ToolOutputCompressionConfig {
fn default() -> Self {
Self {
mode: ToolOutputCompressionMode::Standard,
method: ToolOutputCompressionMethod::Lzw,
redact_secrets: true,
enable_dedup: true,
enable_memo: true,
session_id: None,
max_output_bytes: DEFAULT_MAX_OUTPUT_BYTES,
max_dedup_entries_per_session: DEFAULT_MAX_DEDUP_ENTRIES_PER_SESSION,
max_dedup_sessions: DEFAULT_MAX_DEDUP_SESSIONS,
}
}
}
impl ToolOutputCompressionConfig {
pub fn disabled() -> Self {
Self {
mode: ToolOutputCompressionMode::Disabled,
..Self::default()
}
}
pub fn from_mode(mode: ToolOutputCompressionMode) -> Self {
Self {
mode,
..Self::default()
}
}
pub fn enabled(&self) -> bool {
self.mode.enabled()
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct ToolOutputCompressionResult {
pub output: String,
pub before_tokens: i64,
pub after_tokens: i64,
pub saved_tokens: i64,
pub saved_pct: i64,
pub canonical_tool: String,
pub family: String,
pub mode: ToolOutputCompressionMode,
pub redacted: bool,
pub capped: bool,
pub deduped: bool,
pub memo_reused: bool,
pub memo_changed: bool,
pub strategies: Vec<String>,
}