refactor(config): the provider registry owns the default models
The per-provider fallback ids were spelled in three crates that had
already drifted. claw's resolved_model carried a stale match that
answered deepseek, copilot, and zai with google's fallback while its
own backends.rs knew better; acp and the headless one-shot still used
the copy-pasted google default for openrouter, which claw's module doc
records as deliberately replaced by openrouter/auto — a router
deserves its own router id. Keeping three tables honest was a
comment-level contract ("the same defaults the headless one-shot
uses"), and the comments lied.
ProviderInfo gains default_model, every row fills it, and
rhema_config::default_model(name) answers with google's default for
an unknown spelling, the same fallback every caller hand-rolled. The
acp resolve, claw's backends and resolved_model, and the headless
one-shot read the registry now; the three copies are gone. claw's
resolved_model test pins the arms that had silently dropped off.
Behavior changes, both toward the recorded decisions: the headless
openrouter fallback becomes openrouter/auto, and claw's deepseek,
copilot, and zai fallbacks become their real ids instead of google's.
This commit is contained in:
1 parent
df4cf87a20
commit
c3188af8bc
2 files changed
+25
-33
No files matched your search
@@ -17,9 +17,11 @@
|
||||
//! file, persisted in the settings store, changeable over `/v1/providers`
|
||||
//! — the chart pins nothing.
|
||||
//!
|
||||
//! The per-kind default models are fallbacks only, in one place here:
|
||||
//! openrouter's `openrouter/auto` deliberately replaces the old
|
||||
//! copy-pasted google default — a router deserves its own router id.
|
||||
//! The per-kind default models are fallbacks only, owned by
|
||||
//! rhema-config's provider registry (`PROVIDERS`): one table, every
|
||||
//! frontend. openrouter's `openrouter/auto` deliberately replaces the
|
||||
//! old copy-pasted google default — a router deserves its own router
|
||||
//! id — and that decision now lives in the row, not in this crate.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::future::Future;
|
||||
@@ -63,22 +65,6 @@ pub enum BackendError {
|
||||
MissingKey(String),
|
||||
}
|
||||
|
||||
/// The default model per backend kind, when neither the operator nor the
|
||||
/// settings store names one.
|
||||
pub fn default_model_for(kind: &str) -> &'static str {
|
||||
match kind {
|
||||
"llama-cpp" => "local",
|
||||
"anthropic" => "claude-sonnet-4-5",
|
||||
"openai" => "gpt-5",
|
||||
"openrouter" => "openrouter/auto",
|
||||
"deepseek" => "deepseek-chat",
|
||||
// The Coding Plan's flagship, as Z.ai's own client spells it.
|
||||
"zai" => "GLM-5.3",
|
||||
"copilot" => "gpt-4.1",
|
||||
_ => "gemini-3.8-flash",
|
||||
}
|
||||
}
|
||||
|
||||
/// The listing of a card-backed backend, boxed for the registry; a
|
||||
/// backend without one (the mock, llama's raw id list) carries `None`.
|
||||
pub type ModelListing = Pin<Box<dyn Future<Output = Result<Vec<ModelCard>, ProviderError>> + Send>>;
|
||||
@@ -526,7 +512,7 @@ pub fn construct(kind: &str, params: &ProviderParams) -> Result<Backend, Backend
|
||||
}
|
||||
_ => return Err(BackendError::UnknownKind(kind.to_owned())),
|
||||
};
|
||||
let default_model = default_model_for(kind).to_owned();
|
||||
let default_model = rhema_config::default_model(kind).to_owned();
|
||||
let provider = Arc::new(provider);
|
||||
Ok(Backend {
|
||||
id: kind.to_owned(),
|
||||
@@ -707,7 +693,7 @@ mod tests {
|
||||
id: kind.to_owned(),
|
||||
kind: kind.to_owned(),
|
||||
provider: Arc::new(Stub),
|
||||
default_model: default_model_for(kind).to_owned(),
|
||||
default_model: rhema_config::default_model(kind).to_owned(),
|
||||
list_models: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,20 +289,13 @@ impl ClawConfig {
|
||||
}
|
||||
|
||||
/// The model identifier the handler runs: the config's, or the
|
||||
/// provider's headless default (the same fallbacks the rhema
|
||||
/// frontend's one-shot uses). An unknown provider string reads as
|
||||
/// google here; the binary rejects it when it resolves the backend.
|
||||
/// provider registry's default. An unknown provider string reads
|
||||
/// as google here; the binary rejects it when it resolves the
|
||||
/// backend.
|
||||
pub fn resolved_model(&self) -> String {
|
||||
self.model.clone().unwrap_or_else(|| {
|
||||
match self.provider.as_deref().unwrap_or("google") {
|
||||
"llama-cpp" => "local",
|
||||
"anthropic" => "claude-sonnet-4-5",
|
||||
"openai" => "gpt-5",
|
||||
// The Coding Plan's flagship, as Z.ai's own client spells it.
|
||||
"zai" => "GLM-5.3",
|
||||
_ => "gemini-3.8-flash",
|
||||
}
|
||||
.to_owned()
|
||||
let provider = self.provider.as_deref().unwrap_or("google");
|
||||
rhema_config::default_model(provider).to_owned()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -577,6 +570,19 @@ ingest_token: door-key
|
||||
"claude-sonnet-4-5"
|
||||
);
|
||||
assert_eq!(config(Some("openai"), None).resolved_model(), "gpt-5");
|
||||
// The arms the old inline match dropped: the registry answers
|
||||
// for the whole fleet, so a provider cannot silently read as
|
||||
// google's default.
|
||||
assert_eq!(
|
||||
config(Some("deepseek"), None).resolved_model(),
|
||||
"deepseek-chat"
|
||||
);
|
||||
assert_eq!(config(Some("copilot"), None).resolved_model(), "gpt-4.1");
|
||||
assert_eq!(
|
||||
config(Some("openrouter"), None).resolved_model(),
|
||||
"openrouter/auto"
|
||||
);
|
||||
assert_eq!(config(Some("zai"), None).resolved_model(), "GLM-5.3");
|
||||
// An explicit model always wins, whatever the provider.
|
||||
assert_eq!(
|
||||
config(Some("openrouter"), Some("x/y")).resolved_model(),
|
||||
|
||||
Reference in new issue
Block a user