use std::path::PathBuf;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum TuneSource {
#[default]
Empirical,
OllamaShow,
Manual,
Community,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TuningProfile {
pub model: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub context_window: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub safe_context: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub mid_loop_trim_threshold: Option<usize>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub max_tool_rounds: Option<usize>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub estimate_ratio: Option<f32>,
#[serde(default)]
pub tune_source: TuneSource,
#[serde(default = "default_confidence")]
pub confidence: String,
#[serde(default)]
pub data_points: u32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub notes: Option<String>,
}
fn default_confidence() -> String {
"none".to_string()
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FormatMeta {
pub version: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub generated_by: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub generated_at: Option<String>,
}
impl Default for FormatMeta {
fn default() -> Self {
Self {
version: "1".to_string(),
generated_by: None,
generated_at: None,
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct CommunityTunings {
#[serde(default)]
pub format: FormatMeta,
#[serde(default)]
pub profiles: Vec<TuningProfile>,
}
pub fn community_tunings_path() -> Option<PathBuf> {
crate::config::Config::user_config_path().map(|p| p.with_file_name("community-tunings.toml"))
}
pub fn load_community_tunings() -> CommunityTunings {
let Some(path) = community_tunings_path() else {
return CommunityTunings::default();
};
let Ok(data) = std::fs::read_to_string(&path) else {
return CommunityTunings::default();
};
toml::from_str(&data).unwrap_or_default()
}
pub fn save_community_tunings(tunings: &CommunityTunings) -> std::io::Result<()> {
let path = community_tunings_path()
.ok_or_else(|| std::io::Error::other("cannot determine ~/.newt path"))?;
let data = toml::to_string_pretty(tunings).map_err(|e| std::io::Error::other(e.to_string()))?;
std::fs::write(path, data)
}
impl CommunityTunings {
pub fn find(&self, model: &str) -> Option<&TuningProfile> {
self.profiles.iter().find(|p| p.model == model)
}
pub fn merge(&mut self, other: Self) {
for incoming in other.profiles {
if let Some(existing) = self.profiles.iter_mut().find(|p| p.model == incoming.model) {
if confidence_rank(&incoming.confidence) >= confidence_rank(&existing.confidence) {
*existing = incoming;
}
} else {
self.profiles.push(incoming);
}
}
}
}
fn confidence_rank(c: &str) -> u8 {
match c {
"high" => 3,
"medium" => 2,
"low" => 1,
_ => 0,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn community_tunings_roundtrips_toml() {
let mut ct = CommunityTunings::default();
ct.format.version = "1".to_string();
ct.format.generated_by = Some("newt/0.6.6".to_string());
ct.profiles.push(TuningProfile {
model: "nemotron3:33b".to_string(),
context_window: Some(32768),
safe_context: Some(24576),
mid_loop_trim_threshold: Some(12),
max_tool_rounds: Some(20),
estimate_ratio: Some(1.29),
tune_source: TuneSource::Empirical,
confidence: "high".to_string(),
data_points: 15,
notes: Some("confirmed safe".to_string()),
});
let serialized = toml::to_string_pretty(&ct).unwrap();
let back: CommunityTunings = toml::from_str(&serialized).unwrap();
assert_eq!(back.profiles.len(), 1);
assert_eq!(back.profiles[0].model, "nemotron3:33b");
assert_eq!(back.profiles[0].safe_context, Some(24576));
assert_eq!(back.profiles[0].confidence, "high");
assert_eq!(back.profiles[0].estimate_ratio, Some(1.29));
}
#[test]
fn estimate_ratio_is_optional_in_v1_files() {
let toml_text = r#"
[format]
version = "1"
[[profiles]]
model = "old:7b"
safe_context = 4096
confidence = "low"
"#;
let ct: CommunityTunings = toml::from_str(toml_text).unwrap();
assert_eq!(ct.format.version, "1");
assert_eq!(ct.profiles[0].estimate_ratio, None);
let out = toml::to_string_pretty(&ct).unwrap();
assert!(!out.contains("estimate_ratio"), "{out}");
}
#[test]
fn community_tunings_find_returns_correct_profile() {
let ct = CommunityTunings {
profiles: vec![
TuningProfile {
model: "a:7b".to_string(),
context_window: None,
safe_context: None,
mid_loop_trim_threshold: None,
max_tool_rounds: None,
estimate_ratio: None,
tune_source: TuneSource::Manual,
confidence: "medium".to_string(),
data_points: 0,
notes: None,
},
TuningProfile {
model: "b:13b".to_string(),
context_window: Some(8192),
safe_context: Some(6553),
mid_loop_trim_threshold: None,
max_tool_rounds: None,
estimate_ratio: None,
tune_source: TuneSource::OllamaShow,
confidence: "low".to_string(),
data_points: 1,
notes: None,
},
],
..CommunityTunings::default()
};
assert!(ct.find("a:7b").is_some());
assert_eq!(ct.find("b:13b").unwrap().context_window, Some(8192));
assert!(ct.find("c:30b").is_none());
}
#[test]
fn merge_replaces_lower_confidence_with_higher() {
let mut base = CommunityTunings {
profiles: vec![TuningProfile {
model: "m:7b".to_string(),
safe_context: Some(4096),
confidence: "low".to_string(),
context_window: None,
mid_loop_trim_threshold: None,
max_tool_rounds: None,
estimate_ratio: None,
tune_source: TuneSource::Community,
data_points: 1,
notes: None,
}],
..CommunityTunings::default()
};
let incoming = CommunityTunings {
profiles: vec![TuningProfile {
model: "m:7b".to_string(),
safe_context: Some(8192),
confidence: "high".to_string(),
context_window: None,
mid_loop_trim_threshold: None,
max_tool_rounds: None,
estimate_ratio: None,
tune_source: TuneSource::Empirical,
data_points: 10,
notes: None,
}],
..CommunityTunings::default()
};
base.merge(incoming);
assert_eq!(base.profiles.len(), 1);
assert_eq!(base.profiles[0].safe_context, Some(8192));
assert_eq!(base.profiles[0].data_points, 10);
}
#[test]
fn merge_does_not_replace_higher_confidence_with_lower() {
let mut base = CommunityTunings {
profiles: vec![TuningProfile {
model: "m:7b".to_string(),
safe_context: Some(8192),
confidence: "high".to_string(),
context_window: None,
mid_loop_trim_threshold: None,
max_tool_rounds: None,
estimate_ratio: None,
tune_source: TuneSource::Empirical,
data_points: 10,
notes: None,
}],
..CommunityTunings::default()
};
let incoming = CommunityTunings {
profiles: vec![TuningProfile {
model: "m:7b".to_string(),
safe_context: Some(2048),
confidence: "low".to_string(),
context_window: None,
mid_loop_trim_threshold: None,
max_tool_rounds: None,
estimate_ratio: None,
tune_source: TuneSource::Community,
data_points: 1,
notes: None,
}],
..CommunityTunings::default()
};
base.merge(incoming);
assert_eq!(base.profiles[0].safe_context, Some(8192));
assert_eq!(base.profiles[0].data_points, 10);
}
#[test]
fn confidence_rank_orders_correctly() {
assert!(confidence_rank("high") > confidence_rank("medium"));
assert!(confidence_rank("medium") > confidence_rank("low"));
assert!(confidence_rank("low") > confidence_rank("none"));
assert_eq!(confidence_rank("none"), 0);
}
#[test]
fn empty_document_parses_without_error() {
let ct: CommunityTunings = toml::from_str("").unwrap();
assert!(ct.profiles.is_empty());
}
}