-
Notifications
You must be signed in to change notification settings - Fork 138
Add option to change the base_url of openai provider #58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
97cf8f1
b1d271c
2089ea8
6ef7fa5
11ee42b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -36,7 +36,7 @@ pub struct LumenProvider { | |||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| /// Provider configuration for custom endpoint providers (OpenCode Zen, OpenRouter, Vercel) | ||||||||||||||||||||||||||||||||||||||||||||||
| struct CustomProviderConfig { | ||||||||||||||||||||||||||||||||||||||||||||||
| endpoint: &'static str, | ||||||||||||||||||||||||||||||||||||||||||||||
| endpoint: String, | ||||||||||||||||||||||||||||||||||||||||||||||
| env_key: &'static str, | ||||||||||||||||||||||||||||||||||||||||||||||
| adapter_kind: AdapterKind, | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -46,28 +46,51 @@ impl LumenProvider { | |||||||||||||||||||||||||||||||||||||||||||||
| provider_type: ProviderType, | ||||||||||||||||||||||||||||||||||||||||||||||
| api_key: Option<String>, | ||||||||||||||||||||||||||||||||||||||||||||||
| model: Option<String>, | ||||||||||||||||||||||||||||||||||||||||||||||
| base_url: Option<String>, | ||||||||||||||||||||||||||||||||||||||||||||||
| ) -> Result<Self, LumenError> { | ||||||||||||||||||||||||||||||||||||||||||||||
| 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(), | ||||||||||||||||||||||||||||||||||||||||||||||
| )); | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+51
to
+60
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, let's look at the actual code in src/provider/mod.rs around lines 51-60
head -70 src/provider/mod.rs | tail -40Repository: jnsahaj/lumen Length of output: 1493 🏁 Script executed: # Check dependencies in Cargo.toml to see if reqwest is available
cat Cargo.toml | grep -A 30 "\[dependencies\]"Repository: jnsahaj/lumen Length of output: 902 🏁 Script executed: # Search for how base_url is used throughout the codebase
rg -n "base_url" --type rustRepository: jnsahaj/lumen Length of output: 865 🏁 Script executed: # Look for genai library usage and Endpoint initialization
rg -n "genai\|Endpoint" --type rust -C 3Repository: jnsahaj/lumen Length of output: 39 🏁 Script executed: # Let's see more context around line 79 where base_url is used
sed -n '75,95p' src/provider/mod.rsRepository: jnsahaj/lumen Length of output: 979 🏁 Script executed: # Search for endpoint usage and how it flows through the code
rg -n "endpoint" --type rust src/provider/mod.rs -C 2Repository: jnsahaj/lumen Length of output: 2338 🏁 Script executed: # Check if there's URL validation elsewhere in the codebase
rg -n "Url::parse|parse.*url" --type rust -iRepository: jnsahaj/lumen Length of output: 118 🏁 Script executed: # Look at the full new() function to understand the flow
sed -n '47,100p' src/provider/mod.rsRepository: jnsahaj/lumen Length of output: 2496 🏁 Script executed: # Search for how Endpoint is handled and used
rg -n "Endpoint::|from_owned|http" --type rust -C 2 | head -50Repository: jnsahaj/lumen Length of output: 2936 🏁 Script executed: # Check if there's any error handling around the ServiceTargetResolver usage
rg -n "ServiceTargetResolver|ServiceTarget" --type rust -A 3 | head -80Repository: jnsahaj/lumen Length of output: 1474 🏁 Script executed: # Look at the command diff module that mentions URL parsing
sed -n '40,50p' src/command/diff/mod.rsRepository: jnsahaj/lumen Length of output: 630 🏁 Script executed: # Search for any HTTP request code that might fail on malformed URLs
rg -n "http|request|client\.post|client\.get" --type rust | head -20Repository: jnsahaj/lumen Length of output: 885 Add URL validation for base_url when using CustomOpenAI provider. The code currently accepts Consider adding validation using Suggested validation ProviderType::Customopenai => {
let endpoint = base_url.ok_or_else(|| {
LumenError::ConfigurationError("A Custom URL is required on CustomOpenAI provider".to_string())
})?;
+
+ // Validate URL format
+ reqwest::Url::parse(&endpoint).map_err(|e| {
+ LumenError::ConfigurationError(format!("Invalid base URL: {}", e))
+ })?;
CustomProviderConfig {
endpoint,
env_key: defaults.env_key,
adapter_kind: AdapterKind::OpenAI,
}
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| let (backend, provider_name) = match provider_type { | ||||||||||||||||||||||||||||||||||||||||||||||
| // Custom endpoint providers (OpenCode Zen, OpenRouter, Vercel) - use ServiceTargetResolver | ||||||||||||||||||||||||||||||||||||||||||||||
| ProviderType::OpencodeZen | ProviderType::Openrouter | ProviderType::Vercel => { | ||||||||||||||||||||||||||||||||||||||||||||||
| // Custom endpoint providers (OpenCode Zen, OpenRouter, Vercel, Customopenai) - use ServiceTargetResolver | ||||||||||||||||||||||||||||||||||||||||||||||
| ProviderType::OpencodeZen | ProviderType::Openrouter | ProviderType::Vercel | ProviderType::Customopenai => { | ||||||||||||||||||||||||||||||||||||||||||||||
| 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, | ||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||
| 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/", | ||||||||||||||||||||||||||||||||||||||||||||||
| 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, | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+83
to
+93
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, verify if CUSTOMOPENAI_API_KEY is defined
rg -n "CUSTOMOPENAI_API_KEY" src/Repository: jnsahaj/lumen Length of output: 124 🏁 Script executed: # Check the context of lines 83-93 in src/provider/mod.rs
sed -n '75,100p' src/provider/mod.rsRepository: jnsahaj/lumen Length of output: 1298 🏁 Script executed: # Look for defaults definition and how env_key is set
rg -n "defaults\." src/provider/mod.rs | head -20Repository: jnsahaj/lumen Length of output: 707 🏁 Script executed: # Search for env_key configuration in providers.rs
rg -n "env_key" src/config/providers.rs -B 2 -A 2Repository: jnsahaj/lumen Length of output: 1932 Improve error message wording. The environment variable configuration is correctly set up with 📝 Suggested error message improvement- LumenError::ConfigurationError("A Custom URL is required on CustomOpenAI provider".to_string())
+ LumenError::ConfigurationError("A custom base URL is required for the CustomOpenAI provider".to_string())📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||
| _ => unreachable!(), | ||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -87,7 +110,7 @@ impl LumenProvider { | |||||||||||||||||||||||||||||||||||||||||||||
| move |service_target: ServiceTarget| -> Result<ServiceTarget, genai::resolver::Error> { | ||||||||||||||||||||||||||||||||||||||||||||||
| let ServiceTarget { model, .. } = service_target; | ||||||||||||||||||||||||||||||||||||||||||||||
| Ok(ServiceTarget { | ||||||||||||||||||||||||||||||||||||||||||||||
| endpoint: Endpoint::from_static(endpoint), | ||||||||||||||||||||||||||||||||||||||||||||||
| endpoint: Endpoint::from_owned(endpoint.clone()), | ||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cd /tmp && find . -name "Cargo.toml" -type f 2>/dev/null | head -5Repository: jnsahaj/lumen Length of output: 39 🏁 Script executed: cat Cargo.toml | grep -A 5 "genai"Repository: jnsahaj/lumen Length of output: 187 🏁 Script executed: rg "Endpoint::from_owned|Endpoint::from_static" --type rustRepository: jnsahaj/lumen Length of output: 154 🌐 Web query:
💡 Result: I couldn't find an Endpoint::from_owned in genai v0.4.0 (or in the genai v0.4.x docs/source). The genai docs and repo (v0.4.x) list Client, ClientConfig, ServiceTarget/ModelIden, etc., but no Endpoint::from_owned symbol. See the genai docs and repo here: [1][2]. Do you mean a different crate or symbol (e.g., an Endpoint type from another crate) or would you like me to search the genai repo source for a similarly named constructor? Sources:
🏁 Script executed: rg "use.*Endpoint|from genai" src/provider/mod.rs -B 5 -A 5Repository: jnsahaj/lumen Length of output: 427 🏁 Script executed: rg "struct Endpoint|impl Endpoint" --type rustRepository: jnsahaj/lumen Length of output: 39 🏁 Script executed: head -30 src/provider/mod.rsRepository: jnsahaj/lumen Length of output: 955 🏁 Script executed: sed -n '100,120p' src/provider/mod.rsRepository: jnsahaj/lumen Length of output: 980 🌐 Web query:
💡 Result: Do you mean the genai crate's "Endpoint" (ServiceTarget/ServiceTargetResolver) type and its methods, or the available provider API endpoints (chat, embed, images, etc.) exposed by genai v0.4.0? 🌐 Web query:
💡 Result: The genai v0.4 docs and examples use Endpoint::from_static(...) when you build a ServiceTarget inside a ServiceTargetResolver (example: examples/c06-target-resolver.rs). [1][2] Note: genai’s example uses an Endpoint type with from_static; some other crates (e.g., xai-grpc-client) provide similar constructors (from_static and from_shared / from_owned-style APIs) on their Endpoint types — check the specific Endpoint implementation you’re using if you need a from_owned/from_shared variant. [3] Sources:
🌐 Web query:
💡 Result: The rust-genai v0.4.x release lets you override endpoint/auth via a ServiceTargetResolver (see README) — example usage is in examples/c06-target-resolver.rs. See: [1], [2]. Sources: Citations:
🏁 Script executed: # Check if there's any documentation or comments about Endpoint in the repo
rg "Endpoint" src/provider/mod.rs -B 3 -A 3Repository: jnsahaj/lumen Length of output: 769 🏁 Script executed: # Look for any previous usage or version history comments
git log --oneline -n 20 src/provider/mod.rs 2>/dev/null || echo "Git history not available"Repository: jnsahaj/lumen Length of output: 128 🏁 Script executed: sed -n '90,115p' src/provider/mod.rsRepository: jnsahaj/lumen Length of output: 1219 🏁 Script executed: rg "config.endpoint" src/ -B 5 -A 5 --type rust | head -40Repository: jnsahaj/lumen Length of output: 815 🌐 Web query:
💡 Result: If you mean tonic::transport::Endpoint::from_static, its signature takes a &'static str (not String): pub fn from_static(s: &'static str) -> Self. [1] For the genai crate (v0.4.x) there isn't a genai::Endpoint::from_static in the public docs — genai uses its own ServiceTarget/Client types; check genai docs for the exact types you’re working with. [2] Sources:
🏁 Script executed: # Try to find what methods Endpoint actually has
python3 << 'EOF'
import urllib.request
import json
# Check docs.rs API for genai 0.4.0 Endpoint
try:
response = urllib.request.urlopen('https://docs.rs/genai/0.4.0/genai/resolver/struct.Endpoint.json')
data = json.loads(response.read().decode())
# Print methods if available
if 'docs' in str(data):
print(json.dumps(data, indent=2)[:1000])
except Exception as e:
print(f"Could not fetch: {e}")
EOFRepository: jnsahaj/lumen Length of output: 143 🌐 Web query:
💡 Result: In genai v0.4.0 (Go package) the resolver Endpoint type is a simple struct added in v0.4.0: type Endpoint struct { It represents an endpoint where models are deployed and has no receiver methods defined on it (just the two fields). [1] Sources:
The genai v0.4.0 resolver module provides only 🤖 Prompt for AI Agents
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It builds ok for me. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: Length of output: 1118 🌐 Web query: 💡 Result: There is no Endpoint::from_owned in genai v0.4.4. Use Endpoint::from_static (or other Endpoint constructors shown in the resolver docs/examples) — see the genai example that uses Endpoint::from_static. [1][2] Sources:
🏁 Script executed: Length of output: 11163 @kiwnix You're absolutely right, and I apologize for the incorrect review comment. I've verified the genai v0.4.4 source code, and pub fn from_owned(url: impl Into<Arc<str>>) -> Self {
Endpoint {
inner: EndpointInner::Owned(url.into()),
}
}Your implementation using Sorry for the confusion! 🧬 Code Graph Analysis ResultsFilename: src/command/mod.rs (lines 43-45) Filename: src/ai_prompt.rs (lines 18-97)
Filename: src/ai_prompt.rs (lines 99-149)
Filename: src/ai_prompt.rs (lines 151-170)
|
||||||||||||||||||||||||||||||||||||||||||||||
| auth: AuthData::from_env(auth_env_key), | ||||||||||||||||||||||||||||||||||||||||||||||
| model: ModelIden::new(adapter_kind, model.model_name), | ||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clarify base_url handling for non-Custom providers.
Currently,
base_urlis only validated and used whenProviderType::Customopenaiis selected. If a user mistakenly passesbase_urlvia CLI or environment variable while using a different provider (e.g., OpenAI, Groq), it will be silently ignored. This could cause confusion.Consider either:
base_urlis provided for non-custom providers, orbase_urlis provided but ignored.Also applies to: 67-77
🤖 Prompt for AI Agents