fix(config): preserve explicit custom provider against legacy PROVIDER override
This commit is contained in:
parent
d6dca4b890
commit
9381e4451a
3 changed files with 67 additions and 4 deletions
|
|
@ -20,6 +20,19 @@ Schema export command:
|
|||
| `default_model` | `anthropic/claude-sonnet-4-6` | model routed through selected provider |
|
||||
| `default_temperature` | `0.7` | model temperature |
|
||||
|
||||
## Environment Provider Overrides
|
||||
|
||||
Provider selection can also be controlled by environment variables. Precedence is:
|
||||
|
||||
1. `ZEROCLAW_PROVIDER` (explicit override, always wins when non-empty)
|
||||
2. `PROVIDER` (legacy fallback, only applied when config provider is unset or still `openrouter`)
|
||||
3. `default_provider` in `config.toml`
|
||||
|
||||
Operational note for container users:
|
||||
|
||||
- If your `config.toml` sets an explicit custom provider like `custom:https://.../v1`, a default `PROVIDER=openrouter` from Docker/container env will no longer replace it.
|
||||
- Use `ZEROCLAW_PROVIDER` when you intentionally want runtime env to override a non-default configured provider.
|
||||
|
||||
## `[agent]`
|
||||
|
||||
| Key | Default | Purpose |
|
||||
|
|
|
|||
|
|
@ -2767,13 +2767,23 @@ impl Config {
|
|||
}
|
||||
}
|
||||
|
||||
// Provider: ZEROCLAW_PROVIDER or PROVIDER
|
||||
if let Ok(provider) =
|
||||
std::env::var("ZEROCLAW_PROVIDER").or_else(|_| std::env::var("PROVIDER"))
|
||||
{
|
||||
// Provider override precedence:
|
||||
// 1) ZEROCLAW_PROVIDER always wins when set.
|
||||
// 2) Legacy PROVIDER is only honored when config still uses the
|
||||
// default provider (openrouter) or provider is unset. This prevents
|
||||
// container defaults from overriding explicit custom providers.
|
||||
if let Ok(provider) = std::env::var("ZEROCLAW_PROVIDER") {
|
||||
if !provider.is_empty() {
|
||||
self.default_provider = Some(provider);
|
||||
}
|
||||
} else if let Ok(provider) = std::env::var("PROVIDER") {
|
||||
let should_apply_legacy_provider = self.default_provider.as_deref().map_or(
|
||||
true,
|
||||
|configured| configured.trim().eq_ignore_ascii_case("openrouter"),
|
||||
);
|
||||
if should_apply_legacy_provider && !provider.is_empty() {
|
||||
self.default_provider = Some(provider);
|
||||
}
|
||||
}
|
||||
|
||||
// Model: ZEROCLAW_MODEL or MODEL
|
||||
|
|
@ -4353,6 +4363,42 @@ default_temperature = 0.7
|
|||
std::env::remove_var("PROVIDER");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn env_override_provider_fallback_does_not_replace_non_default_provider() {
|
||||
let _env_guard = env_override_test_guard();
|
||||
let mut config = Config {
|
||||
default_provider: Some("custom:https://proxy.example.com/v1".to_string()),
|
||||
..Config::default()
|
||||
};
|
||||
|
||||
std::env::remove_var("ZEROCLAW_PROVIDER");
|
||||
std::env::set_var("PROVIDER", "openrouter");
|
||||
config.apply_env_overrides();
|
||||
assert_eq!(
|
||||
config.default_provider.as_deref(),
|
||||
Some("custom:https://proxy.example.com/v1")
|
||||
);
|
||||
|
||||
std::env::remove_var("PROVIDER");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn env_override_zero_claw_provider_overrides_non_default_provider() {
|
||||
let _env_guard = env_override_test_guard();
|
||||
let mut config = Config {
|
||||
default_provider: Some("custom:https://proxy.example.com/v1".to_string()),
|
||||
..Config::default()
|
||||
};
|
||||
|
||||
std::env::set_var("ZEROCLAW_PROVIDER", "openrouter");
|
||||
std::env::set_var("PROVIDER", "anthropic");
|
||||
config.apply_env_overrides();
|
||||
assert_eq!(config.default_provider.as_deref(), Some("openrouter"));
|
||||
|
||||
std::env::remove_var("ZEROCLAW_PROVIDER");
|
||||
std::env::remove_var("PROVIDER");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn env_override_glm_api_key_for_regional_aliases() {
|
||||
let _env_guard = env_override_test_guard();
|
||||
|
|
|
|||
|
|
@ -1194,6 +1194,8 @@ mod tests {
|
|||
idempotency_store: Arc::new(IdempotencyStore::new(Duration::from_secs(300), 1000)),
|
||||
whatsapp: None,
|
||||
whatsapp_app_secret: None,
|
||||
linq: None,
|
||||
linq_signing_secret: None,
|
||||
observer: Arc::new(crate::observability::NoopObserver),
|
||||
};
|
||||
|
||||
|
|
@ -1235,6 +1237,8 @@ mod tests {
|
|||
idempotency_store: Arc::new(IdempotencyStore::new(Duration::from_secs(300), 1000)),
|
||||
whatsapp: None,
|
||||
whatsapp_app_secret: None,
|
||||
linq: None,
|
||||
linq_signing_secret: None,
|
||||
observer,
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue