From 155efdf9f325dfcd24e98159b9fcf8534c07267a Mon Sep 17 00:00:00 2001 From: KimiSwitch Dev Date: Wed, 8 Jul 2026 14:25:05 +0800 Subject: [PATCH] feat: keep provider records on switch, only mark active; filter on save --- src-tauri/src/kimi_code_io.rs | 19 +++++++++++++++++++ src-tauri/src/models.rs | 3 +++ src-tauri/src/pi_io.rs | 1 + src/App.tsx | 22 ++++++---------------- src/components/ProviderList.tsx | 5 +---- src/types/index.ts | 2 ++ 6 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src-tauri/src/kimi_code_io.rs b/src-tauri/src/kimi_code_io.rs index 4ff2e55..23f2b92 100644 --- a/src-tauri/src/kimi_code_io.rs +++ b/src-tauri/src/kimi_code_io.rs @@ -124,6 +124,7 @@ pub fn kimi_code_to_config(value: &TomlValue) -> Config { official_url: None, managed, enabled, + active: true, raw_other, }, ); @@ -225,8 +226,15 @@ pub fn config_to_kimi_code(config: &Config, existing: Option<&TomlValue>) -> Tom .unwrap_or(TomlValue::String("".to_string())), ); + let is_kimi_native = |p: &Provider| p.managed; + let mut providers_table = Table::new(); for (name, provider) in &config.providers { + // Skip inactive custom providers when writing to Kimi Code config. + // Kimi native (managed) providers are always preserved. + if !is_kimi_native(provider) && !provider.active { + continue; + } let mut pt = Table::new(); pt.insert("type".to_string(), TomlValue::String(provider.provider_type.as_str().to_string())); if let Some(base_url) = provider.base_url.clone().filter(|s| !s.is_empty()) { @@ -261,8 +269,19 @@ pub fn config_to_kimi_code(config: &Config, existing: Option<&TomlValue>) -> Tom } root.insert("providers".to_string(), TomlValue::Table(providers_table)); + // Collect provider names that survived the filter above. + let active_provider_names: std::collections::HashSet<&str> = config + .providers + .values() + .filter(|p| is_kimi_native(p) || p.active) + .map(|p| p.name.as_str()) + .collect(); + let mut models_table = Table::new(); for (alias, model) in &config.models { + if !active_provider_names.contains(model.provider.as_str()) { + continue; + } let mut mt = Table::new(); mt.insert("provider".to_string(), TomlValue::String(model.provider.clone())); mt.insert("model".to_string(), TomlValue::String(model.model.clone())); diff --git a/src-tauri/src/models.rs b/src-tauri/src/models.rs index d626820..ed9cc98 100644 --- a/src-tauri/src/models.rs +++ b/src-tauri/src/models.rs @@ -83,6 +83,8 @@ pub struct Provider { pub managed: bool, #[serde(default = "default_true")] pub enabled: bool, + #[serde(default)] + pub active: bool, #[serde(default, skip_serializing_if = "Value::is_null")] pub raw_other: Value, } @@ -98,6 +100,7 @@ impl PartialEq for Provider { && self.official_url == other.official_url && self.managed == other.managed && self.enabled == other.enabled + && self.active == other.active && self.raw_other == other.raw_other } } diff --git a/src-tauri/src/pi_io.rs b/src-tauri/src/pi_io.rs index 1769b11..6c7a5be 100644 --- a/src-tauri/src/pi_io.rs +++ b/src-tauri/src/pi_io.rs @@ -201,6 +201,7 @@ pub fn pi_file_to_config(file: &PiModelsFile) -> Config { official_url: None, managed: false, enabled: pi_provider.enabled, + active: true, raw_other: pi_provider.extra.clone(), }; diff --git a/src/App.tsx b/src/App.tsx index a015e31..7e51bbd 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -194,37 +194,27 @@ export default function App() { const handleSwitchProvider = (name: string) => { updateConfig((cfg) => { const target = cfg.providers[name]; - if (!target) return cfg; + if (!target || target.managed) return cfg; const isKimiNative = (p: Provider) => p.managed === true; - // Keep Kimi native (managed) providers and the selected provider only. + // Mark the selected provider as active and deactivate other custom providers. + // Kimi native providers are left untouched. No provider/model records are deleted. const providers: Record = {}; for (const [key, p] of Object.entries(cfg.providers)) { - if (isKimiNative(p)) { - providers[key] = p; - } - } - providers[name] = { ...target, enabled: true }; - - // Drop models whose provider was removed. - const models: Record = {}; - for (const [key, m] of Object.entries(cfg.models)) { - if (providers[m.provider]) { - models[key] = m; - } + providers[key] = { ...p, active: isKimiNative(p) ? undefined : key === name }; } // Set default model to the first model of the selected provider. let default_model: string | null = null; - for (const [key, m] of Object.entries(models)) { + for (const [key, m] of Object.entries(cfg.models)) { if (m.provider === name) { default_model = key; break; } } - return { ...cfg, providers, models, default_model }; + return { ...cfg, providers, default_model }; }); }; diff --git a/src/components/ProviderList.tsx b/src/components/ProviderList.tsx index d4b6ec9..40c8d72 100644 --- a/src/components/ProviderList.tsx +++ b/src/components/ProviderList.tsx @@ -93,10 +93,7 @@ export function ProviderList({ ? models[defaultModel]?.display_name || defaultModel : null; const isKimiNative = provider.managed === true; - const isActive = - !isKimiNative && - defaultModel !== null && - models[defaultModel]?.provider === provider.name; + const isActive = !isKimiNative && provider.active === true; return (