fix(tui): persist provider switches to config

This commit is contained in:
xyuai
2026-06-04 06:19:32 +08:00
committed by Hunter Bown
parent 260ee737b0
commit dba332e8d5
2 changed files with 82 additions and 19 deletions
+31 -19
View File
@@ -5363,33 +5363,45 @@ async fn switch_provider(
})
.await;
app.add_message(HistoryCell::System {
content: format!(
"Provider switched: {} → {}\nModel: {} → {}\nEndpoint: {}",
previous_provider.as_str(),
target.as_str(),
previous_model,
new_model,
new_endpoint
),
});
app.status_message = Some(format!(
"Provider: {} via {}",
target.as_str(),
new_endpoint
));
let persist_warning = (|| -> anyhow::Result<()> {
commands::persist_root_string_key(app.config_path.as_deref(), "provider", target.as_str())?;
// Persist the provider choice so it survives restarts.
if let Ok(mut settings) = crate::settings::Settings::load() {
let mut settings = crate::settings::Settings::load()?;
settings.default_provider = Some(target.as_str().to_string());
if model_override.is_some() {
settings.set_model_for_provider(target.as_str(), &new_model);
if matches!(target, ApiProvider::Deepseek | ApiProvider::DeepseekCN) {
let _ = settings.set("default_model", &new_model);
settings.set("default_model", &new_model)?;
}
}
let _ = settings.save();
settings.save()?;
Ok(())
})()
.err()
.map(|err| format!("Provider selection was not fully persisted: {err}"));
let mut switch_summary = format!(
"Provider switched: {} → {}",
previous_provider.as_str(),
target.as_str(),
);
switch_summary.push(char::from(10));
switch_summary.push_str(&format!("Model: {}{}", previous_model, new_model));
switch_summary.push(char::from(10));
switch_summary.push_str(&format!("Endpoint: {}", new_endpoint));
if let Some(ref warning) = persist_warning {
switch_summary.push(char::from(10));
switch_summary.push_str(warning);
}
app.add_message(HistoryCell::System {
content: switch_summary,
});
let mut status_message = format!("Provider: {} via {}", target.as_str(), new_endpoint);
if persist_warning.is_some() {
status_message.push_str(" (not fully persisted)");
}
app.status_message = Some(status_message);
}
fn root_base_url_belongs_to_non_deepseek_provider(base_url: &str) -> bool {
+51
View File
@@ -2237,6 +2237,57 @@ async fn provider_switch_to_deepseek_drops_stale_xiaomi_root_base_url() {
assert_eq!(config.base_url, None);
}
#[tokio::test]
async fn provider_switch_persists_provider_to_config_for_restart() {
let _home = SettingsHomeGuard::new();
let tmp = TempDir::new().expect("config tempdir");
let config_path = tmp.path().join("config.toml");
std::fs::write(
&config_path,
r#"provider = "arcee"
[providers.xiaomi_mimo]
base_url = "https://token-plan-sgp.xiaomimimo.com/v1"
model = "mimo-v2.5-pro"
api_key = "mimo-key"
[providers.arcee]
api_key = "arcee-key"
"#,
)
.expect("write config");
let mut app = create_test_app();
app.api_provider = ApiProvider::Arcee;
app.model = "auto".to_string();
app.config_path = Some(config_path.clone());
let mut engine = mock_engine_handle();
let mut config = Config::load(Some(config_path.clone()), None).expect("load config");
switch_provider(
&mut app,
&mut engine.handle,
&mut config,
ApiProvider::XiaomiMimo,
None,
)
.await;
assert_eq!(app.api_provider, ApiProvider::XiaomiMimo);
assert_eq!(config.provider.as_deref(), Some("xiaomi-mimo"));
let reloaded = Config::load(Some(config_path.clone()), None).expect("reload config");
assert_eq!(reloaded.api_provider(), ApiProvider::XiaomiMimo);
assert_eq!(
reloaded.deepseek_base_url(),
"https://token-plan-sgp.xiaomimimo.com/v1"
);
let settings = crate::settings::Settings::load().expect("load settings");
assert_eq!(settings.default_provider.as_deref(), Some("xiaomi-mimo"));
}
#[tokio::test]
async fn provider_switch_model_override_updates_target_provider_model_slot() {
let _home = SettingsHomeGuard::new();