use std::path::{Path, PathBuf};
pub const DEFAULT_PROVIDER: &str = "openai";
pub const DEFAULT_OPENAI_BASE_URL: &str = "http://localhost:11434/v1";
pub const DEFAULT_OPENAI_MODEL: &str = "kimi-k2.6:cloud";
pub const DEFAULT_MAGI_MELCHIOR: &str = "qwen3.5:397b-cloud";
pub const DEFAULT_MAGI_BALTHASAR: &str = "gpt-oss:120b-cloud";
pub const DEFAULT_MAGI_CASPAR: &str = "deepseek-v4-pro:cloud";
pub const DEFAULT_ANTHROPIC_MODEL: &str = "claude-sonnet-4-6";
pub fn no_config_notice() -> String {
format!(
"No magi.toml — using Ollama defaults ({base}, {model}, \
Melchior: {mel}, Balthasar: {bal}, Caspar: {cas}). Copy \
magi.toml.example to customize, or set provider=\"anthropic\" \
for Anthropic.",
base = DEFAULT_OPENAI_BASE_URL,
model = DEFAULT_OPENAI_MODEL,
mel = DEFAULT_MAGI_MELCHIOR,
bal = DEFAULT_MAGI_BALTHASAR,
cas = DEFAULT_MAGI_CASPAR,
)
}
pub fn render_default_magi_toml() -> String {
format!(
"# Generated by magi-rs --init-config / /init-config — built-in Ollama-first defaults.\n\
# Edit to customize, or set provider = \"anthropic\" to use Anthropic instead.\n\
provider = \"{provider}\"\n\n\
[openai]\n\
base_url = \"{base}\"\n\
model = \"{model}\"\n\n\
[magi]\n\
melchior_model = \"{mel}\"\n\
balthasar_model = \"{bal}\"\n\
caspar_model = \"{cas}\"\n",
provider = DEFAULT_PROVIDER,
base = DEFAULT_OPENAI_BASE_URL,
model = DEFAULT_OPENAI_MODEL,
mel = DEFAULT_MAGI_MELCHIOR,
bal = DEFAULT_MAGI_BALTHASAR,
cas = DEFAULT_MAGI_CASPAR,
)
}
pub fn write_default_config(dir: &Path) -> anyhow::Result<PathBuf> {
let path = dir.join("magi.toml");
match std::fs::OpenOptions::new()
.write(true)
.create_new(true)
.open(&path)
{
Ok(mut f) => {
use std::io::Write;
f.write_all(render_default_magi_toml().as_bytes())?;
Ok(path)
}
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => anyhow::bail!(
"{} already exists — refusing to overwrite (edit it manually or delete it first)",
path.display()
),
Err(e) => Err(anyhow::anyhow!("failed to write {}: {e}", path.display())),
}
}
pub fn should_emit_default_notice(provider_kind: &str, magi_toml_exists: bool) -> bool {
provider_kind == "openai" && !magi_toml_exists
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_constants_are_the_ollama_first_profile() {
assert_eq!(DEFAULT_PROVIDER, "openai");
assert_eq!(DEFAULT_OPENAI_BASE_URL, "http://localhost:11434/v1");
assert_eq!(DEFAULT_OPENAI_MODEL, "kimi-k2.6:cloud");
assert_eq!(DEFAULT_MAGI_MELCHIOR, "qwen3.5:397b-cloud");
assert_eq!(DEFAULT_MAGI_BALTHASAR, "gpt-oss:120b-cloud");
assert_eq!(DEFAULT_MAGI_CASPAR, "deepseek-v4-pro:cloud");
assert_eq!(DEFAULT_ANTHROPIC_MODEL, "claude-sonnet-4-6");
}
#[test]
fn test_should_emit_default_notice_only_for_openai_without_file() {
assert!(should_emit_default_notice("openai", false));
assert!(!should_emit_default_notice("openai", true)); assert!(!should_emit_default_notice("anthropic", false)); assert!(!should_emit_default_notice("anthropic", true));
}
#[test]
fn test_no_config_notice_interpolates_all_defaults() {
let n = no_config_notice();
assert!(n.contains(DEFAULT_OPENAI_BASE_URL));
assert!(n.contains(DEFAULT_OPENAI_MODEL));
assert!(n.contains(DEFAULT_MAGI_MELCHIOR));
assert!(n.contains(DEFAULT_MAGI_BALTHASAR));
assert!(n.contains(DEFAULT_MAGI_CASPAR));
}
#[test]
fn test_render_default_magi_toml_interpolates_and_parses() {
let s = render_default_magi_toml();
assert!(s.contains(DEFAULT_OPENAI_BASE_URL));
assert!(s.contains(DEFAULT_OPENAI_MODEL));
assert!(s.contains(DEFAULT_MAGI_MELCHIOR));
assert!(s.contains(DEFAULT_MAGI_BALTHASAR));
assert!(s.contains(DEFAULT_MAGI_CASPAR));
let parsed = crate::config::MagiConfig::from_toml_str(&s).unwrap();
assert_eq!(parsed.provider.as_deref(), Some("openai"));
assert_eq!(
parsed.magi.melchior_model.as_deref(),
Some(DEFAULT_MAGI_MELCHIOR)
);
}
#[test]
fn test_write_default_config_writes_when_absent() {
let dir = tempfile::tempdir().unwrap();
let path = write_default_config(dir.path()).unwrap();
assert_eq!(path, dir.path().join("magi.toml"));
assert!(path.exists());
let body = std::fs::read_to_string(&path).unwrap();
assert!(body.contains(DEFAULT_OPENAI_MODEL));
}
#[test]
fn test_write_default_config_refuses_to_overwrite() {
let dir = tempfile::tempdir().unwrap();
std::fs::write(dir.path().join("magi.toml"), "provider = \"anthropic\"").unwrap();
let err = write_default_config(dir.path()).unwrap_err();
assert!(err.to_string().contains("magi.toml"));
let body = std::fs::read_to_string(dir.path().join("magi.toml")).unwrap();
assert_eq!(body, "provider = \"anthropic\"");
}
}