fix(config): accept vercel and openrouter as provider_interface values (#915)

The Python CLI (#902) and the JSON schema both allow `vercel` and
`openrouter` as `provider_interface`, and `hermesllm::ProviderId` knows
how to dispatch them — but `crates/common::LlmProviderType` was never
extended to deserialize them. As a result, `planoai up` with no user
config (which synthesizes both providers via `cli/planoai/defaults.py`)
caused brightstaff to crash on startup with:

    unknown variant `vercel`, expected one of `anthropic`, ..., `digitalocean`

Add the missing enum variants and Display arms, plus a regression test
that asserts both round-trip through serde and resolve through
`to_provider_id()` (the exact path that previously panicked at parse).
This commit is contained in:
Musa 2026-04-24 16:32:00 -07:00 committed by GitHub
parent 92f82a9c68
commit 2954ae258f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -396,6 +396,10 @@ pub enum LlmProviderType {
ChatGPT,
#[serde(rename = "digitalocean")]
DigitalOcean,
#[serde(rename = "vercel")]
Vercel,
#[serde(rename = "openrouter")]
OpenRouter,
}
impl Display for LlmProviderType {
@ -419,6 +423,8 @@ impl Display for LlmProviderType {
LlmProviderType::Plano => write!(f, "plano"),
LlmProviderType::ChatGPT => write!(f, "chatgpt"),
LlmProviderType::DigitalOcean => write!(f, "digitalocean"),
LlmProviderType::Vercel => write!(f, "vercel"),
LlmProviderType::OpenRouter => write!(f, "openrouter"),
}
}
}
@ -757,6 +763,26 @@ mod test {
assert!(!model_ids.contains(&"plano-orchestrator".to_string()));
}
#[test]
fn test_llm_provider_type_vercel_and_openrouter_roundtrip() {
// Regression: brightstaff used to reject `provider_interface: vercel`
// (and `openrouter`) because these variants were missing from
// `LlmProviderType`, causing `planoai up` with the synthesized default
// config to crash on startup.
for (yaml_value, expected) in [
("vercel", LlmProviderType::Vercel),
("openrouter", LlmProviderType::OpenRouter),
] {
let parsed: LlmProviderType =
serde_yaml::from_str(yaml_value).expect("variant should deserialize");
assert_eq!(parsed, expected);
assert_eq!(parsed.to_string(), yaml_value);
// to_provider_id() bridges into hermesllm; both providers must be
// recognized there as well or this panics.
let _ = parsed.to_provider_id();
}
}
#[test]
fn test_overrides_disable_signals_default_none() {
let overrides = super::Overrides::default();