diff --git a/codex-rs/common/src/oss.rs b/codex-rs/common/src/oss.rs index a579f72373..249cc0c45c 100644 --- a/codex-rs/common/src/oss.rs +++ b/codex-rs/common/src/oss.rs @@ -14,6 +14,24 @@ pub fn get_default_model_for_oss_provider(provider_id: &str) -> Option<&'static } } +/// Detect whether the selected Ollama instance supports the responses API and, if not, downgrade +/// to the chat completions wire API. This should run whenever the Ollama provider is selected, +/// even when `--oss` is not in use, so older servers remain compatible. +pub async fn detect_ollama_wire_api_if_needed(config: &mut Config) { + if config.model_provider_id != OLLAMA_OSS_PROVIDER_ID + || config.model_provider.wire_api != WireApi::Responses + { + return; + } + + match codex_ollama::detect_wire_api(&config.model_provider).await { + Ok(Some(detection)) if detection.wire_api == WireApi::Chat => { + config.model_provider.wire_api = WireApi::Chat; + } + Ok(_) | Err(_) => {} + } +} + /// Ensures the specified OSS provider is ready (models downloaded, service reachable). pub async fn ensure_oss_provider_ready( provider_id: &str, @@ -26,14 +44,7 @@ pub async fn ensure_oss_provider_ready( .map_err(|e| std::io::Error::other(format!("OSS setup failed: {e}")))?; } OLLAMA_OSS_PROVIDER_ID => { - if config.model_provider.wire_api == WireApi::Responses { - match codex_ollama::detect_wire_api(&config.model_provider).await { - Ok(Some(detection)) if detection.wire_api == WireApi::Chat => { - config.model_provider.wire_api = WireApi::Chat; - } - Ok(_) | Err(_) => {} - } - } + detect_ollama_wire_api_if_needed(config).await; codex_ollama::ensure_oss_ready(config) .await diff --git a/codex-rs/exec/src/lib.rs b/codex-rs/exec/src/lib.rs index 5998920a7e..86589315d4 100644 --- a/codex-rs/exec/src/lib.rs +++ b/codex-rs/exec/src/lib.rs @@ -13,6 +13,7 @@ pub mod exec_events; pub use cli::Cli; pub use cli::Command; pub use cli::ReviewArgs; +use codex_common::oss::detect_ollama_wire_api_if_needed; use codex_common::oss::ensure_oss_provider_ready; use codex_common::oss::get_default_model_for_oss_provider; use codex_core::AuthManager; @@ -204,6 +205,10 @@ pub async fn run_main(cli: Cli, codex_linux_sandbox_exe: Option) -> any let mut config = Config::load_with_cli_overrides(cli_kv_overrides, overrides).await?; + if !oss { + detect_ollama_wire_api_if_needed(&mut config).await; + } + if let Err(err) = enforce_login_restrictions(&config).await { eprintln!("{err}"); std::process::exit(1); diff --git a/codex-rs/ollama/src/lib.rs b/codex-rs/ollama/src/lib.rs index 3412921b8c..f719ed7977 100644 --- a/codex-rs/ollama/src/lib.rs +++ b/codex-rs/ollama/src/lib.rs @@ -94,7 +94,10 @@ mod tests { #[test] fn test_wire_api_for_version_dev_zero_keeps_responses() { - assert_eq!(wire_api_for_version(&Version::new(0, 0, 0)), WireApi::Responses); + assert_eq!( + wire_api_for_version(&Version::new(0, 0, 0)), + WireApi::Responses + ); } #[test] @@ -104,7 +107,13 @@ mod tests { #[test] fn test_wire_api_for_version_at_or_after_cutoff_is_responses() { - assert_eq!(wire_api_for_version(&Version::new(0, 13, 4)), WireApi::Responses); - assert_eq!(wire_api_for_version(&Version::new(0, 14, 0)), WireApi::Responses); + assert_eq!( + wire_api_for_version(&Version::new(0, 13, 4)), + WireApi::Responses + ); + assert_eq!( + wire_api_for_version(&Version::new(0, 14, 0)), + WireApi::Responses + ); } } diff --git a/codex-rs/tui/src/lib.rs b/codex-rs/tui/src/lib.rs index bb2daa8844..2765ab5bb3 100644 --- a/codex-rs/tui/src/lib.rs +++ b/codex-rs/tui/src/lib.rs @@ -7,6 +7,7 @@ use additional_dirs::add_dir_warning_message; use app::App; pub use app::AppExitInfo; use codex_app_server_protocol::AuthMode; +use codex_common::oss::detect_ollama_wire_api_if_needed; use codex_common::oss::ensure_oss_provider_ready; use codex_common::oss::get_default_model_for_oss_provider; use codex_core::AuthManager; @@ -553,7 +554,10 @@ async fn load_config_or_exit( ) -> Config { #[allow(clippy::print_stderr)] match Config::load_with_cli_overrides(cli_kv_overrides, overrides).await { - Ok(config) => config, + Ok(mut config) => { + detect_ollama_wire_api_if_needed(&mut config).await; + config + } Err(err) => { eprintln!("Error loading configuration: {err}"); std::process::exit(1); diff --git a/codex-rs/tui2/src/lib.rs b/codex-rs/tui2/src/lib.rs index de2a7204e2..cd5743129f 100644 --- a/codex-rs/tui2/src/lib.rs +++ b/codex-rs/tui2/src/lib.rs @@ -7,6 +7,7 @@ use additional_dirs::add_dir_warning_message; use app::App; pub use app::AppExitInfo; use codex_app_server_protocol::AuthMode; +use codex_common::oss::detect_ollama_wire_api_if_needed; use codex_common::oss::ensure_oss_provider_ready; use codex_common::oss::get_default_model_for_oss_provider; use codex_core::AuthManager; @@ -574,7 +575,10 @@ async fn load_config_or_exit( ) -> Config { #[allow(clippy::print_stderr)] match Config::load_with_cli_overrides(cli_kv_overrides, overrides).await { - Ok(config) => config, + Ok(mut config) => { + detect_ollama_wire_api_if_needed(&mut config).await; + config + } Err(err) => { eprintln!("Error loading configuration: {err}"); std::process::exit(1);