const MODEL_FILE: &str = ".lh_model";
pub(crate) const DEFAULT_MODEL: &str = crate::types::DEFAULT_MODEL;
#[cfg(not(feature = "local"))]
pub(crate) const MODELS: &[(&str, &str)] = &[
(crate::types::DEFAULT_MODEL, "Gemini"),
(crate::backends::anthropic::DEFAULT_MODEL, "Claude Haiku"),
(crate::backends::anthropic::SONNET_MODEL, "Claude Sonnet"),
(crate::backends::anthropic::OPUS_MODEL, "Claude Opus"),
];
#[cfg(feature = "local")]
pub(crate) const MODELS: &[(&str, &str)] = &[
(crate::types::DEFAULT_MODEL, "Gemini"),
(crate::backends::anthropic::DEFAULT_MODEL, "Claude Haiku"),
(crate::backends::anthropic::SONNET_MODEL, "Claude Sonnet"),
(crate::backends::anthropic::OPUS_MODEL, "Claude Opus"),
("gemma-3-270m", "Local (Gemma)"),
];
pub(crate) fn is_anthropic(model: &str) -> bool {
model.starts_with("claude-")
}
pub(crate) fn is_local(model: &str) -> bool {
model.starts_with("gemma-")
}
pub(crate) fn session_thinking_ceiling(model: &str) -> Option<crate::types::ThinkingLevel> {
use crate::types::ThinkingLevel;
if is_local(model) {
None
} else if is_anthropic(model) {
if model.contains("haiku") {
Some(ThinkingLevel::Medium)
} else {
Some(ThinkingLevel::High)
}
} else {
Some(ThinkingLevel::High)
}
}
pub(crate) fn describe(model: &str) -> String {
let label = MODELS
.iter()
.find(|(id, _)| *id == model)
.map(|(_, label)| *label)
.unwrap_or(model);
let backend = if is_anthropic(model) {
"the Anthropic backend"
} else if is_local(model) {
"the local in-browser Gemma backend (no network)"
} else {
"the Gemini backend"
};
format!("{label} ({model}) via {backend}")
}
pub(crate) async fn load() -> String {
let fs = super::shared_opfs();
let chosen = fs
.read(MODEL_FILE)
.await
.ok()
.and_then(|bytes| String::from_utf8(bytes).ok())
.map(|s| s.trim().to_string())
.unwrap_or_default();
if MODELS.iter().any(|(id, _)| *id == chosen) {
chosen
} else {
DEFAULT_MODEL.to_string()
}
}
pub(crate) async fn save(model: &str) {
if !MODELS.iter().any(|(id, _)| *id == model) {
return;
}
let fs = super::shared_opfs();
if let Err(err) = fs.write_atomic(MODEL_FILE, model.as_bytes()).await {
web_sys::console::warn_1(&wasm_bindgen::JsValue::from_str(&format!(
"model save: {err}"
)));
}
}