feat(hermes): bind per-provider models to top-level model: on switch

Hermes custom_providers entries now carry an ordered models array
(id / context_length / max_tokens) plus suggestedDefaults. The backend
serializes the array to the YAML dict shape Hermes expects on write and
inverts it on read, preserving insertion order via the preserve_order
feature on serde_json.

When a user switches providers, switch_normal calls apply_switch_defaults
so the top-level model.default / model.provider follow the selected
provider's first model. Previously switching a Hermes provider only
shuffled custom_providers[] and left Hermes pointing at whatever
model.provider was set before.

Seven existing Hermes presets now ship with a curated models list so
switching lands on a working default without a detour through the
Model panel.
This commit is contained in:
Jason
2026-04-18 22:08:23 +08:00
parent 63aa310576
commit f935bac633
3 changed files with 560 additions and 4 deletions
+19
View File
@@ -1523,6 +1523,25 @@ impl ProviderService {
// Sync to live (write_gemini_live handles security flag internally for Gemini)
write_live_with_common_config(state.db.as_ref(), &app_type, provider)?;
// Hermes is additive, so "switching" doesn't overwrite a live config file
// — we instead update the top-level `model:` section to point at this
// provider's first declared model. Without this, clicking "switch" would
// only shuffle entries in custom_providers[] while Hermes keeps using
// whatever `model.provider` was set before.
if matches!(app_type, AppType::Hermes) {
if let Err(e) =
crate::hermes_config::apply_switch_defaults(&provider.id, &provider.settings_config)
{
log::warn!(
"Failed to update Hermes model defaults after switching to '{}': {e}",
provider.id
);
result
.warnings
.push(format!("hermes_model_defaults_failed:{}", provider.id));
}
}
// For additive-mode providers that were DB-only (live_config_managed == Some(false)),
// flip the flag to true now that the provider has been successfully written to the live
// file. This ensures sync_all_providers_to_live() will include it on future syncs.