use std::collections::HashMap;
use std::fs;
use std::path::Path;
use serde::Deserialize;
pub struct LlmApiConfig {
pub auth_token: String,
pub base_url: String,
pub haiku_model: String,
}
#[derive(Deserialize, Default)]
struct SettingsFile {
#[serde(default)]
env: Option<HashMap<String, String>>,
}
const DEFAULT_HAIKU: &str = "deepseek-v4-flash";
pub fn load_api_config(claude_dir: &Path) -> LlmApiConfig {
let settings_path = claude_dir.join("settings.json");
let env = fs::read_to_string(&settings_path)
.ok()
.and_then(|content| serde_json::from_str::<SettingsFile>(&content).ok())
.and_then(|s| s.env)
.unwrap_or_default();
let auth_token = env
.get("ANTHROPIC_AUTH_TOKEN")
.cloned()
.unwrap_or_default();
let base_url = env
.get("ANTHROPIC_BASE_URL")
.cloned()
.unwrap_or_else(|| "https://api.anthropic.com".to_string());
let haiku_model = env
.get("ANTHROPIC_DEFAULT_HAIKU_MODEL")
.cloned()
.filter(|m| !m.is_empty())
.unwrap_or_else(|| DEFAULT_HAIKU.to_string());
LlmApiConfig {
auth_token,
base_url,
haiku_model,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_load_api_config_defaults() {
let cfg = load_api_config(Path::new("/nonexistent/path"));
assert!(!cfg.haiku_model.is_empty());
}
#[test]
fn test_load_api_config_from_file() {
let tmp = std::env::temp_dir().join("__llm_test_settings");
let _ = std::fs::remove_dir_all(&tmp);
std::fs::create_dir_all(&tmp).unwrap();
let settings = tmp.join("settings.json");
std::fs::write(&settings, r#"{
"env": {
"ANTHROPIC_AUTH_TOKEN": "test-token",
"ANTHROPIC_BASE_URL": "https://test.api.com",
"ANTHROPIC_DEFAULT_HAIKU_MODEL": "test-haiku-model"
}
}"#).unwrap();
let cfg = load_api_config(&tmp);
assert_eq!(cfg.auth_token, "test-token");
assert_eq!(cfg.base_url, "https://test.api.com");
assert_eq!(cfg.haiku_model, "test-haiku-model");
let _ = std::fs::remove_dir_all(&tmp);
}
}