diff --git a/crates/rhema-claw/src/backends.rs b/crates/rhema-claw/src/backends.rs index 2d3272e..a3270f8 100644 --- a/crates/rhema-claw/src/backends.rs +++ b/crates/rhema-claw/src/backends.rs @@ -360,6 +360,12 @@ pub struct ProviderParams { /// (OpenAI-compatible, Z.ai, OpenCode). #[serde(default, skip_serializing_if = "Option::is_none")] pub url: Option, + /// The request shape an `openai` kind speaks, when the config + /// chose one: `chat` or `responses`. Unset lets the registry's + /// route rule decide. Writable in the config file today; the login + /// forms do not ask for it yet. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub api: Option, } /// Every kind a runtime login can construct, ascending: the addable @@ -438,16 +444,31 @@ pub fn construct(kind: &str, params: &ProviderParams) -> Result build(kind, params.api_key.as_deref(), Some(&llama_url), None), + "llama-cpp" => build( + kind, + params.api_key.as_deref(), + Some(&llama_url), + None, + None, + ), // The route-bearing kinds take an optional stored override; the - // rest keep their adapter's default. + // rest keep their adapter's default. Only the `openai` kind + // reads the stored request shape — the one whose dialect its + // route cannot imply. "openai" | "zai" | "opencode" => build( kind, Some(require_key(kind, params)?.as_str()), None, params.url.as_deref(), + params.api.as_deref(), + ), + _ => build( + kind, + Some(require_key(kind, params)?.as_str()), + None, + None, + None, ), - _ => build(kind, Some(require_key(kind, params)?.as_str()), None, None), } .map_err(|err| match err { rhema_provider_registry::BuildError::Unknown(kind) => BackendError::UnknownKind(kind), @@ -559,12 +580,14 @@ pub fn discover( kind: kind.to_owned(), api_key: None, url: Some(stored.llama_cpp_url()), + api: None, } } else if let Some(api_key) = env_key(kind) { ProviderParams { kind: kind.to_owned(), api_key: Some(api_key), url: stored_route(kind), + api: None, } } else if stored_of_kind { // The stored instance of the kind wins over the profile @@ -582,6 +605,7 @@ pub fn discover( kind: kind.to_owned(), api_key, url: stored_route(kind), + api: None, } }; let has_creds = match kind { @@ -733,6 +757,7 @@ mod tests { kind: kind.to_owned(), api_key: api_key.map(str::to_owned), url: url.map(str::to_owned), + api: None, } } @@ -853,6 +878,7 @@ mod tests { api_key: None, secret_ref: Some("ref-1".into()), base_url: None, + api: None, }, ); let store = rhema_config::secrets::VolatileSecretStore::new(); @@ -961,6 +987,7 @@ mod tests { api_key: Some("pg".into()), secret_ref: None, base_url: None, + api: None, }, ); profile diff --git a/crates/rhema-claw/src/http.rs b/crates/rhema-claw/src/http.rs index 7b97e54..d293f28 100644 --- a/crates/rhema-claw/src/http.rs +++ b/crates/rhema-claw/src/http.rs @@ -2094,6 +2094,7 @@ async fn providers_set_credentials( kind: kind.clone(), api_key: blank_is_absent(body["api_key"].as_str()), url: blank_is_absent(body["url"].as_str()), + api: None, }; let mut backend = crate::backends::construct(&kind, ¶ms).map_err(bad_request)?; backend.id = id.to_owned();