From 97cf8f1e9ed68a327728950bba57fd3acd578145 Mon Sep 17 00:00:00 2001 From: Eduardo Garcia Cebollero Date: Sat, 31 May 2025 02:42:55 -0600 Subject: [PATCH 1/4] Add option to change the base_url of openai provider --- src/config/cli.rs | 3 +++ src/config/configuration.rs | 10 ++++++++++ src/main.rs | 3 ++- src/provider/mod.rs | 10 +++++++++- 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/config/cli.rs b/src/config/cli.rs index c205ab41..26771618 100644 --- a/src/config/cli.rs +++ b/src/config/cli.rs @@ -34,6 +34,9 @@ pub struct Cli { #[arg(value_enum, long = "vcs")] pub vcs: Option, + #[arg(short = 'u', long = "base-url")] + pub base_url: Option, + #[command(subcommand)] pub command: Commands, } diff --git a/src/config/configuration.rs b/src/config/configuration.rs index 7b30cb64..73b706f4 100644 --- a/src/config/configuration.rs +++ b/src/config/configuration.rs @@ -24,6 +24,9 @@ pub struct LumenConfig { #[serde(default = "default_api_key")] pub api_key: Option, + #[serde(default = "default_base_url")] + pub base_url: Option, + #[serde(default = "default_draft_config")] pub draft: DraftConfig, @@ -82,6 +85,10 @@ fn default_api_key() -> Option { std::env::var("LUMEN_API_KEY").ok() } +fn default_base_url() -> Option { + std::env::var("LUMEN_BASE_URL").ok() +} + fn deserialize_commit_types<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, @@ -119,11 +126,13 @@ impl LumenConfig { let provider = cli.provider.as_ref().cloned().unwrap_or(config.provider); let api_key = cli.api_key.clone().or(config.api_key); let model = cli.model.clone().or(config.model); + let base_url = cli.base_url.clone().or(config.base_url); Ok(LumenConfig { provider, model, api_key, + base_url, draft: config.draft, theme: config.theme, }) @@ -151,6 +160,7 @@ impl Default for LumenConfig { api_key: default_api_key(), draft: default_draft_config(), theme: None, + base_url: default_base_url(), } } } diff --git a/src/main.rs b/src/main.rs index e9ba7f38..46f1dcbf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,7 +34,8 @@ async fn run() -> Result<(), LumenError> { Err(e) => return Err(e), }; - let provider = provider::LumenProvider::new(config.provider, config.api_key, config.model)?; + let provider = + provider::LumenProvider::new(client, config.provider, config.api_key, config.model, config.base_url)?; let command = command::LumenCommand::new(provider); // Get VCS backend based on CLI override or auto-detection diff --git a/src/provider/mod.rs b/src/provider/mod.rs index 9f7da0aa..7dd310fb 100644 --- a/src/provider/mod.rs +++ b/src/provider/mod.rs @@ -46,6 +46,7 @@ impl LumenProvider { provider_type: ProviderType, api_key: Option, model: Option, + base_url: Option, ) -> Result { let (backend, provider_name) = match provider_type { // Custom endpoint providers (OpenRouter, Vercel) - use ServiceTargetResolver @@ -63,6 +64,14 @@ impl LumenProvider { env_key: defaults.env_key, adapter_kind: AdapterKind::OpenAI, }, + ProviderType::OpenAI => CustomProviderConfig { + // Trailing slash is required for URL joining to work correctly + endpoint: base_url + .as_deref() + .unwrap_or("https://api.openai.com/v1/"), + env_key: defaults.env_key, + adapter_kind: AdapterKind::OpenAI, + }, _ => unreachable!(), }; @@ -100,7 +109,6 @@ impl LumenProvider { }, defaults.display_name.to_string(), ) - } // Native genai providers _ => { let defaults = ProviderInfo::for_provider(provider_type); From b1d271caf36092e97482217e9eb872c6facd6dd8 Mon Sep 17 00:00:00 2001 From: Eduardo Garcia Cebollero Date: Thu, 8 Jan 2026 17:58:27 +0100 Subject: [PATCH 2/4] Update the custom provider to the new api structure --- src/config/cli.rs | 2 ++ src/config/providers.rs | 7 +++++++ src/main.rs | 2 +- src/provider/mod.rs | 30 +++++++++++++++++------------- 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/config/cli.rs b/src/config/cli.rs index 26771618..3760806b 100644 --- a/src/config/cli.rs +++ b/src/config/cli.rs @@ -52,6 +52,7 @@ pub enum ProviderType { Gemini, Xai, Vercel, + Customopenai } impl FromStr for ProviderType { @@ -68,6 +69,7 @@ impl FromStr for ProviderType { "gemini" => Ok(ProviderType::Gemini), "xai" => Ok(ProviderType::Xai), "vercel" => Ok(ProviderType::Vercel), + "customopenai" => Ok(ProviderType::Customopenai), _ => Err(format!("Unknown provider: {}", s)), } } diff --git a/src/config/providers.rs b/src/config/providers.rs index ee8ff201..6326a1b3 100644 --- a/src/config/providers.rs +++ b/src/config/providers.rs @@ -80,6 +80,13 @@ pub const ALL_PROVIDERS: &[ProviderInfo] = &[ default_model: "anthropic/claude-sonnet-4.5", env_key: "VERCEL_API_KEY", }, + ProviderInfo { + id: "customopenai", + provider_type: ProviderType::Customopenai, + display_name: "Custom OpenAI", + default_model: "gpt-5-mini", + env_key: "CUSTOMOPENAI_API_KEY", + }, ]; impl ProviderInfo { diff --git a/src/main.rs b/src/main.rs index 46f1dcbf..e9e3e5d7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,7 +35,7 @@ async fn run() -> Result<(), LumenError> { }; let provider = - provider::LumenProvider::new(client, config.provider, config.api_key, config.model, config.base_url)?; + provider::LumenProvider::new(config.provider, config.api_key, config.model, config.base_url)?; let command = command::LumenCommand::new(provider); // Get VCS backend based on CLI override or auto-detection diff --git a/src/provider/mod.rs b/src/provider/mod.rs index 7dd310fb..1a71db6c 100644 --- a/src/provider/mod.rs +++ b/src/provider/mod.rs @@ -36,7 +36,7 @@ pub struct LumenProvider { /// Provider configuration for custom endpoint providers (OpenRouter, Vercel) struct CustomProviderConfig { - endpoint: &'static str, + endpoint: String, env_key: &'static str, adapter_kind: AdapterKind, } @@ -50,28 +50,31 @@ impl LumenProvider { ) -> Result { let (backend, provider_name) = match provider_type { // Custom endpoint providers (OpenRouter, Vercel) - use ServiceTargetResolver - ProviderType::Openrouter | ProviderType::Vercel => { + ProviderType::Openrouter | ProviderType::Vercel | ProviderType::Customopenai => { let defaults = ProviderInfo::for_provider(provider_type); let config = match provider_type { ProviderType::Openrouter => CustomProviderConfig { - endpoint: "https://openrouter.ai/api/v1/", + endpoint: "https://openrouter.ai/api/v1/".to_string(), env_key: defaults.env_key, adapter_kind: AdapterKind::OpenAI, }, ProviderType::Vercel => CustomProviderConfig { // Trailing slash is required for URL joining to work correctly - endpoint: "https://ai-gateway.vercel.sh/v1/", - env_key: defaults.env_key, - adapter_kind: AdapterKind::OpenAI, - }, - ProviderType::OpenAI => CustomProviderConfig { - // Trailing slash is required for URL joining to work correctly - endpoint: base_url - .as_deref() - .unwrap_or("https://api.openai.com/v1/"), + endpoint: "https://ai-gateway.vercel.sh/v1/".to_string(), env_key: defaults.env_key, adapter_kind: AdapterKind::OpenAI, }, + ProviderType::Customopenai => { + let endpoint = base_url.ok_or_else(|| { + LumenError::ConfigurationError("A Custom URL is required on CustomOpenAI provider".to_string()) + })?; + + CustomProviderConfig { + endpoint, + env_key: defaults.env_key, + adapter_kind: AdapterKind::OpenAI, + } + } _ => unreachable!(), }; @@ -91,7 +94,7 @@ impl LumenProvider { move |service_target: ServiceTarget| -> Result { let ServiceTarget { model, .. } = service_target; Ok(ServiceTarget { - endpoint: Endpoint::from_static(endpoint), + endpoint: Endpoint::from_owned(endpoint.clone()), auth: AuthData::from_env(auth_env_key), model: ModelIden::new(adapter_kind, model.model_name), }) @@ -109,6 +112,7 @@ impl LumenProvider { }, defaults.display_name.to_string(), ) + } // Native genai providers _ => { let defaults = ProviderInfo::for_provider(provider_type); From 2089ea85f936ce3498cd803ba006775b80d0cd75 Mon Sep 17 00:00:00 2001 From: Eduardo Garcia Cebollero Date: Thu, 8 Jan 2026 18:05:14 +0100 Subject: [PATCH 3/4] fix: only accept custom base url if using customopenai provider --- src/provider/mod.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/provider/mod.rs b/src/provider/mod.rs index 1a71db6c..e98123ec 100644 --- a/src/provider/mod.rs +++ b/src/provider/mod.rs @@ -48,6 +48,17 @@ impl LumenProvider { model: Option, base_url: Option, ) -> Result { + if (base_url.is_some()) + && !matches!( + provider_type, + ProviderType::Customopenai + ) + { + return Err(LumenError::ConfigurationError( + "Base URL can only be set for CustomOpenAI provider".to_string(), + )); + } + let (backend, provider_name) = match provider_type { // Custom endpoint providers (OpenRouter, Vercel) - use ServiceTargetResolver ProviderType::Openrouter | ProviderType::Vercel | ProviderType::Customopenai => { From 11ee42b8306ec37ac2e919b72fcb4957ca25d17a Mon Sep 17 00:00:00 2001 From: Eduardo Garcia Cebollero Date: Sun, 11 Jan 2026 00:07:04 +0100 Subject: [PATCH 4/4] fix: fix compilation for OpencodeZen --- src/provider/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/provider/mod.rs b/src/provider/mod.rs index 2545a57d..32fe17f4 100644 --- a/src/provider/mod.rs +++ b/src/provider/mod.rs @@ -65,7 +65,7 @@ impl LumenProvider { let defaults = ProviderInfo::for_provider(provider_type); let config = match provider_type { ProviderType::OpencodeZen => CustomProviderConfig { - endpoint: "https://opencode.ai/zen/v1/", + endpoint: "https://opencode.ai/zen/v1/".to_string(), env_key: defaults.env_key, adapter_kind: AdapterKind::OpenAI, },