diff --git a/Cargo.lock b/Cargo.lock index 49104b22d2..de6b99c01c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -835,6 +835,7 @@ dependencies = [ "serde_json", "serde_yaml", "sha2 0.11.0", + "temp-env", "tempfile", "tokio", "tracing", @@ -2177,7 +2178,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccc2776f0c61eca1ca32528f85548abd1a4be8fb53d1b21c013e4f18da1e7090" dependencies = [ "data-encoding", - "syn 1.0.109", + "syn 2.0.117", ] [[package]] @@ -8714,6 +8715,15 @@ dependencies = [ "xattr", ] +[[package]] +name = "temp-env" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96374855068f47402c3121c6eed88d29cb1de8f3ab27090e273e420bdabcf050" +dependencies = [ + "parking_lot", +] + [[package]] name = "tempfile" version = "3.27.0" diff --git a/crates/buzz-agent/Cargo.toml b/crates/buzz-agent/Cargo.toml index 7889ad34a7..0fa69a222d 100644 --- a/crates/buzz-agent/Cargo.toml +++ b/crates/buzz-agent/Cargo.toml @@ -55,3 +55,4 @@ hex = { workspace = true } serde = { workspace = true } sha2 = { workspace = true } tempfile = "3" +temp-env = "0.3" diff --git a/crates/buzz-agent/src/config.rs b/crates/buzz-agent/src/config.rs index a0e64f1a9d..852e06051b 100644 --- a/crates/buzz-agent/src/config.rs +++ b/crates/buzz-agent/src/config.rs @@ -791,7 +791,9 @@ impl Config { env("OPENAI_COMPAT_MODEL").as_deref(), ) .ok_or_else(|| "config: OPENAI_COMPAT_MODEL required".to_string())?, - env_or("OPENAI_COMPAT_BASE_URL", "https://api.openai.com/v1"), + env("OPENAI_COMPAT_BASE_URL") + .or_else(|| env("OPENAI_BASE_URL")) + .unwrap_or_else(|| "https://api.openai.com/v1".into()), parse_openai_api(env("OPENAI_COMPAT_API").as_deref())?, ), Provider::Databricks | Provider::DatabricksV2 => ( @@ -2751,4 +2753,67 @@ mod tests { let err = resolve_provider(Some("openrouter"), None, None, None).unwrap_err(); assert!(err.contains("OPENROUTER_API_KEY")); } + + #[test] + fn base_url_prefers_compat_over_generic() { + temp_env::with_vars( + [ + ("BUZZ_AGENT_PROVIDER", Some("openai")), + ("OPENAI_COMPAT_API_KEY", Some("sk-test")), + ("OPENAI_COMPAT_MODEL", Some("gpt-4")), + ("OPENAI_COMPAT_BASE_URL", Some("https://custom-openai.local/v1")), + ("OPENAI_BASE_URL", Some("https://generic-openai.local/v1")), + ], + || { + let config = Config::from_env().unwrap(); + assert_eq!( + config.base_url, + "https://custom-openai.local/v1", + "specific OPENAI_COMPAT_BASE_URL should win over generic OPENAI_BASE_URL" + ); + }, + ); + } + + #[test] + fn base_url_falls_back_to_generic_when_compat_unset() { + temp_env::with_vars( + [ + ("BUZZ_AGENT_PROVIDER", Some("openai")), + ("OPENAI_COMPAT_API_KEY", Some("sk-test")), + ("OPENAI_COMPAT_MODEL", Some("gpt-4")), + ("OPENAI_COMPAT_BASE_URL", None), + ("OPENAI_BASE_URL", Some("https://generic-openai.local/v1")), + ], + || { + let config = Config::from_env().unwrap(); + assert_eq!( + config.base_url, + "https://generic-openai.local/v1", + "OPENAI_BASE_URL should be used when OPENAI_COMPAT_BASE_URL is unset" + ); + }, + ); + } + + #[test] + fn base_url_defaults_when_none_set() { + temp_env::with_vars( + [ + ("BUZZ_AGENT_PROVIDER", Some("openai")), + ("OPENAI_COMPAT_API_KEY", Some("sk-test")), + ("OPENAI_COMPAT_MODEL", Some("gpt-4")), + ("OPENAI_COMPAT_BASE_URL", None), + ("OPENAI_BASE_URL", None), + ], + || { + let config = Config::from_env().unwrap(); + assert_eq!( + config.base_url, + "https://api.openai.com/v1", + "should default when neither env var is set" + ); + }, + ); + } }