fix(api): model claude selalu pakai Opus dari settings.json, bukan deepseek
TUI turn.rs & daemon handler.rs ambil model langsung dari settings.model (tersimpan 'deepseek-v4-flash-free' di ~/.local/share/zesdex/settings.json) padahal provider sudah 'claude'. - feat(domain): resolve_effective_model() — saat provider claude, model diambil dari app_config provider claude (default_model=claude-opus-4-8 hasil deteksi ~/.claude/settings.json), menang atas settings.model basi. Provider non-claude tetap hormati settings.model user. - fix(tui): turn.rs pakai resolve_effective_model (bukan settings.model) - fix(daemon): handler.rs run_turn + compaction pakai resolve_effective_model - fix(data): ~/.local/share/zesdex/settings.json model deepseek -> claude-opus-4-8 - test: 3 unit test resolve_effective_model
This commit is contained in:
@@ -23,6 +23,8 @@ use std::collections::HashMap;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::app_config::AppConfig;
|
||||
|
||||
/// Controls how much network access the agent is permitted during a session.
|
||||
///
|
||||
/// ## Variants
|
||||
@@ -112,3 +114,86 @@ impl Default for Settings {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pick the effective model name for the main agent.
|
||||
///
|
||||
/// When `settings.provider` is `"claude"` (auto-detected from
|
||||
/// `~/.claude/settings.json`), the provider's `default_model` (or the
|
||||
/// app-level `default_model`) wins over a possibly-stale persisted
|
||||
/// `settings.model`. Otherwise the user's explicit `settings.model` is used.
|
||||
///
|
||||
/// Why: the user's custom Claude endpoint (URL + API key from
|
||||
/// `~/.claude/settings.json`) implies Opus as the model; a stale
|
||||
/// `settings.json` (e.g. "deepseek-v4-flash-free") must not override it.
|
||||
pub fn resolve_effective_model(settings: &Settings, app_config: &AppConfig) -> String {
|
||||
if settings.provider == "claude" {
|
||||
if let Some(m) = app_config
|
||||
.providers
|
||||
.get("claude")
|
||||
.and_then(|p| p.default_model.clone())
|
||||
{
|
||||
return m;
|
||||
}
|
||||
return app_config.default_model.clone();
|
||||
}
|
||||
settings.model.clone()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::cms::app_config::AppConfig;
|
||||
|
||||
fn claude_app_config() -> AppConfig {
|
||||
let mut cfg = AppConfig::default();
|
||||
cfg.providers.insert(
|
||||
"claude".to_string(),
|
||||
crate::cms::ProviderConfig {
|
||||
api_base: "https://9router.example/v1".to_string(),
|
||||
api_key_env: Some("ANTHROPIC_API_KEY".to_string()),
|
||||
default_model: Some("claude-opus-4-8".to_string()),
|
||||
default_api_key: Some("sk-test".to_string()),
|
||||
},
|
||||
);
|
||||
cfg.default_provider = "claude".to_string();
|
||||
cfg.default_model = "claude-opus-4-8".to_string();
|
||||
cfg
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn claude_provider_uses_opus_model_over_stale_settings_model() {
|
||||
let settings = Settings {
|
||||
provider: "claude".to_string(),
|
||||
model: "deepseek-v4-flash-free".to_string(), // stale persisted
|
||||
..Settings::default()
|
||||
};
|
||||
|
||||
let model = resolve_effective_model(&settings, &claude_app_config());
|
||||
assert_eq!(model, "claude-opus-4-8");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn non_claude_provider_uses_settings_model() {
|
||||
let settings = Settings {
|
||||
provider: "zen".to_string(),
|
||||
model: "my-model".to_string(),
|
||||
..Settings::default()
|
||||
};
|
||||
|
||||
let model = resolve_effective_model(&settings, &AppConfig::default());
|
||||
assert_eq!(model, "my-model");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn claude_falls_back_to_app_default() {
|
||||
let settings = Settings {
|
||||
provider: "claude".to_string(),
|
||||
model: String::new(),
|
||||
..Settings::default()
|
||||
};
|
||||
|
||||
let cfg = AppConfig::default();
|
||||
let model = resolve_effective_model(&settings, &cfg);
|
||||
assert_eq!(model, cfg.default_model);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user