Skip to content

Add option to change the base_url of openai provider#58

Open
kiwnix wants to merge 5 commits into
jnsahaj:mainfrom
kiwnix:implement-baseurl
Open

Add option to change the base_url of openai provider#58
kiwnix wants to merge 5 commits into
jnsahaj:mainfrom
kiwnix:implement-baseurl

Conversation

@kiwnix

@kiwnix kiwnix commented May 31, 2025

Copy link
Copy Markdown

This PR Adds an option to change the openai base URL (for use in proxys or local llm with OpenAI-style API support).

The cli option is -u
The env is LUMEN_BASE_URL

Sorry i'm not proficient in rust so not sure about correct coding conventions or style.

Summary by CodeRabbit

  • New Features
    • Added support for a Custom OpenAI provider with its own default model (gpt-5-mini) and env var for credentials.
    • New CLI option -u / --base-url and corresponding environment variable to specify a custom API base URL.
    • Base URL is applied when using the Custom OpenAI provider.
  • Bug Fixes / Validation
    • Prevents setting a base URL for non-custom providers to avoid misconfiguration.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented May 31, 2025

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Added an optional base_url CLI/config field, propagated it into provider initialization; introduced ProviderType::Customopenai, updated provider registry, and enforced that base_url may only be used with the Customopenai provider.

Changes

Cohort / File(s) Summary
CLI & Config
src/config/cli.rs, src/config/configuration.rs
Added pub base_url: Option<String> to Cli and LumenConfig; added default_base_url() to read LUMEN_BASE_URL; merged CLI/config base_url in LumenConfig::build.
Provider Registry
src/config/providers.rs
Added Custom OpenAI entry (id: "customopenai", provider_type: ProviderType::Customopenai, env_key: "CUSTOMOPENAI_API_KEY", default_model: "gpt-5-mini").
Provider Initialization & Routing
src/provider/mod.rs
LumenProvider::new gained base_url: Option<String> parameter; added ProviderType::Customopenai; CustomProviderConfig.endpoint changed from &'static str to String; endpoint construction now uses Endpoint::from_owned(...); validation ensures base_url only allowed for Customopenai.
Integration (call site)
src/main.rs
Updated call to provider::LumenProvider::new(...) to pass config.base_url as the fourth argument.

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant CLI
  participant Config
  participant Main
  participant Provider
  participant ExternalAPI

  User->>CLI: run with optional `-u/--base-url`
  CLI->>Config: build(cli)
  Config->>Main: return LumenConfig (includes base_url)
  Main->>Provider: LumenProvider::new(provider, api_key, model, base_url)
  Provider->>Provider: validate base_url for Customopenai
  Provider->>ExternalAPI: construct endpoint (owned String) and connect
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • jnsahaj

Poem

🐰 I hopped through flags and config lines,
A base URL tucked where sunlight shines,
From CLI to provider I carried the clue,
Custom routes now wake and new,
✨ — a rabbit's small update, true

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding a CLI option to customize the base URL for OpenAI-compatible providers, with implementation supporting the new Customopenai provider variant.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🔭 Outside diff range comments (1)
src/provider/mod.rs (1)

75-111: 💡 Verification agent

🧩 Analysis chain

Consider extending base_url support to other applicable providers.

While the OpenAI implementation is correct, other providers like Ollama (which often runs locally) and OpenRouter (which provides multiple endpoints) could also benefit from configurable base URLs. This would make the feature more comprehensive and the API more consistent.

Consider extending base_url support to providers that could benefit from it:

            ProviderType::Ollama => {
                let model = model.ok_or(LumenError::MissingModel("Ollama".to_string()))?;
-                let config = OllamaConfig::new(model);
+                let config = OllamaConfig::new(model, base_url);
                let provider = LumenProvider::Ollama(Box::new(OllamaProvider::new(client, config)));
                Ok(provider)
            }

Let me check which other providers could benefit from configurable base URLs:


🏁 Script executed:

#!/bin/bash
# Check the constructor signatures of other provider configs to see if they support base_url
fd -e rs . src/provider/ --exec grep -l "Config::new" {} \; | xargs grep -A 5 "pub fn new"

Length of output: 277


#!/bin/bash
# List each provider config file and its `new` constructor signature
grep -R -lE 'struct [A-Za-z0-9]+Config' src/provider | while read -r file; do
  echo "File: $file"
  grep -R -n 'pub fn new' "$file"
  echo
done

Extend base_url support to all providers

Currently only the OpenAI provider respects a custom base_url. To keep the API consistent, add base_url: Option<String> to each provider’s config and pass it through in src/provider/mod.rs.

Providers to update:

  • PhindConfig::new(model)
  • GroqConfig::new(api_key, model)
  • ClaudeConfig::new(api_key, model)
  • OllamaConfig::new(model)
  • OpenRouterConfig::new(api_key, model)
  • DeepSeekConfig::new(api_key, model)

Example diff in src/provider/mod.rs:

 ProviderType::Ollama => {
     let model = model.ok_or(LumenError::MissingModel("Ollama".to_string()))?;
-    let config = OllamaConfig::new(model);
+    let config = OllamaConfig::new(model, base_url.clone());
     let provider = LumenProvider::Ollama(Box::new(OllamaProvider::new(client, config)));
     Ok(provider)
 }

Repeat the same pattern for Phind, Groq, Claude, OpenRouter, and DeepSeek—updating each Config::new signature and constructor call to accept and forward base_url.

🧹 Nitpick comments (4)
src/config/cli.rs (1)

24-25: Consider adding provider-specific documentation to the help text.

The implementation is correct, but the help text should clarify that this option currently only affects the OpenAI provider to set user expectations properly.

Consider updating the help documentation:

-    #[arg(short = 'u', long = "base-url")]
+    #[arg(short = 'u', long = "base-url", help = "Custom base URL for OpenAI provider")]
src/main.rs (1)

36-36: Consider adding URL validation for the base_url parameter.

The implementation correctly passes the base_url to the provider constructor. However, consider validating that the base_url is a properly formatted URL before initialization to provide better error messages to users.

Consider adding URL validation:

// Before line 35, add validation if base_url is present
if let Some(ref url) = config.base_url {
    if url.parse::<reqwest::Url>().is_err() {
        return Err(LumenError::InvalidArguments(
            format!("Invalid base URL format: {}", url)
        ));
    }
}
src/provider/mod.rs (1)

66-66: Consider documenting that base_url only affects OpenAI provider.

The method signature accepts base_url for all provider types, but the parameter is currently only used by the OpenAI provider. Consider adding documentation to clarify this limitation.

Add documentation to the method:

impl LumenProvider {
+    /// Creates a new LumenProvider instance.
+    /// Note: base_url parameter currently only affects OpenAI provider.
    pub fn new(
src/config/configuration.rs (1)

27-28: LGTM! Consider adding URL validation.

The field follows the established pattern for optional configuration fields. Consider adding URL validation to ensure the provided base_url is well-formed.

You could add validation in the build method:

        let base_url = cli.base_url.clone().or(config.base_url);
+        
+        // Validate base_url if provided
+        if let Some(ref url) = base_url {
+            if url::Url::parse(url).is_err() {
+                return Err(LumenError::InvalidConfiguration(
+                    format!("Invalid base_url: {}", url)
+                ));
+            }
+        }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c9ae97a and 622c659.

📒 Files selected for processing (5)
  • src/config/cli.rs (1 hunks)
  • src/config/configuration.rs (4 hunks)
  • src/main.rs (1 hunks)
  • src/provider/mod.rs (1 hunks)
  • src/provider/openai.rs (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/provider/mod.rs (1)
src/provider/openai.rs (2)
  • new (15-21)
  • new (30-32)
🔇 Additional comments (5)
src/provider/openai.rs (1)

15-21: LGTM! Clean implementation with appropriate fallback.

The implementation correctly handles the optional base_url parameter while maintaining backward compatibility with the default OpenAI endpoint. The use of unwrap_or_else with a closure is appropriate here.

src/provider/mod.rs (1)

69-74: LGTM! OpenAI provider correctly receives the base_url parameter.

The implementation properly passes the base_url parameter to the OpenAI configuration, enabling custom endpoint support for OpenAI-compatible APIs.

src/config/configuration.rs (3)

85-87: LGTM! Environment variable naming is consistent.

The function follows the same pattern as other default functions and uses appropriate environment variable naming that aligns with the existing LUMEN_* convention.


126-126: LGTM! CLI override logic is correct.

The precedence logic correctly implements CLI args > config file > environment variable, which matches the expected behavior and is consistent with other configuration fields.


132-132: LGTM! Struct field integration is complete.

The base_url field is correctly included in both the build method result and the Default implementation, ensuring consistency across all configuration paths.

Also applies to: 158-158

@jnsahaj

jnsahaj commented Jan 6, 2026

Copy link
Copy Markdown
Owner

Hi, I know it's been a while but I like your change! Do you want to look at the conflicts?

@kiwnix kiwnix force-pushed the implement-baseurl branch from 622c659 to 69fd560 Compare January 8, 2026 15:43

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/provider/mod.rs (1)

51-119: Unresolved merge conflict markers must be resolved.

The code contains Git merge conflict markers (<<<<<<< HEAD, |||||||, =======, >>>>>>>) which will cause compilation failure.

Key observations about the conflict:

  • HEAD branch: Contains OpenRouter/Vercel custom provider logic using ServiceTargetResolver
  • Merged branch: Contains OpenAI-specific path using OpenAIConfig, OpenAIProvider, and LumenProvider::OpenAI enum variant

The merged branch references types (OpenAIConfig, OpenAIProvider, LumenProvider::OpenAI, client) that don't align with the current ProviderBackend enum structure in HEAD. You'll need to:

  1. Resolve the conflict by integrating both the OpenRouter/Vercel logic and the OpenAI base_url support
  2. Decide whether to use the ProviderBackend::GenAI pattern or introduce a separate OpenAI variant
  3. Ensure the base_url parameter is utilized for OpenAI provider configuration
🤖 Fix all issues with AI agents
In @src/config/configuration.rs:
- Around line 162-167: Resolve the leftover merge conflict markers in the
Default implementation in configuration.rs by removing the conflict noise
(<<<<<<<, =======, >>>>>>>) and returning both fields: set theme: None and
base_url: default_base_url() inside the Default::default() (or impl Default for
Configuration) so the struct initializes with both the theme and base_url fields
present; keep the call to default_base_url() as the value for base_url.

In @src/main.rs:
- Around line 37-45: Resolve the merge conflict by removing the conflict markers
and the undefined `client` reference; call LumenProvider::new with the correct
parameters from `config` to match its signature
(provider::LumenProvider::new(config.provider, config.api_key, config.model,
config.base_url)?), ensuring you reference the existing `config` struct fields
and the LumenProvider::new function rather than a non-existent `client`.

In @src/provider/openai.rs:
- Around line 1-5: Add the missing AIProvider trait and the two missing
ProviderError variants so the OpenAI implementation compiles: define an
AIProvider trait whose async method signatures match the impl in openai.rs (add
the same function names, argument types and return Result<..., ProviderError>
used in that impl), and extend the existing ProviderError enum by adding
UnexpectedResponse and APIError variants (use suitable payloads, e.g.,
UnexpectedResponse(String) and APIError(String) or boxed error types) so
references to ProviderError::UnexpectedResponse and ProviderError::APIError
resolve.
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 622c659 and 69fd560.

📒 Files selected for processing (5)
  • src/config/cli.rs
  • src/config/configuration.rs
  • src/main.rs
  • src/provider/mod.rs
  • src/provider/openai.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/config/cli.rs
🧰 Additional context used
🧬 Code graph analysis (1)
src/provider/mod.rs (1)
src/provider/openai.rs (2)
  • new (15-21)
  • new (30-32)
🔇 Additional comments (6)
src/provider/mod.rs (1)

49-49: LGTM on the new parameter.

The base_url parameter is correctly added to the function signature.

src/config/configuration.rs (3)

27-29: LGTM on the new field.

The base_url field is correctly added with appropriate serde attribute for environment variable fallback.


88-90: LGTM on the helper function.

The default_base_url() function follows the same pattern as other default functions (default_model, default_api_key).


129-135: LGTM on the configuration merging logic.

The base_url is correctly merged with CLI taking precedence over config file, consistent with other options.

src/provider/openai.rs (2)

7-22: LGTM on OpenAIConfig implementation.

The configuration struct correctly handles optional model and base_url with sensible defaults. The default model gpt-4o-mini and default endpoint are appropriate.


89-97: LGTM on AIProvider trait implementation.

The trait implementation correctly delegates to the internal complete method and exposes the model name.

Comment thread src/config/configuration.rs Outdated
Comment thread src/main.rs Outdated
Comment thread src/provider/openai.rs Outdated
Comment thread src/provider/openai.rs Outdated
@kiwnix kiwnix force-pushed the implement-baseurl branch from 69fd560 to b1d271c Compare January 8, 2026 16:58
@kiwnix

kiwnix commented Jan 8, 2026

Copy link
Copy Markdown
Author

I updated the code to adapt to the new implementation structure

The env var to set the api key is CUSTOMOPENAI_API_KEY, for example the parameters for GLM-4.7 on z.ai will be: -p customopenai -m glm-4.7 -u https://api.z.ai/api/coding/paas/v4/

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @src/provider/mod.rs:
- Around line 49-50: The code currently only validates and uses base_url when
ProviderType::Customopenai is selected, which silently ignores a provided
base_url for other providers; update the provider initialization (the function
handling base_url in src/provider/mod.rs that returns Result<Self, LumenError>)
to check if base_url.is_some() while the selected provider is not
ProviderType::Customopenai and either return a clear error (preferred) or emit a
warning log indicating base_url will be ignored; apply the same check/behavior
in the other initialization branch around the logic at the region covering lines
67-77 so users aren’t confused when passing base_url for non-custom providers.
🧹 Nitpick comments (3)
src/config/providers.rs (1)

83-89: Consider a more generic default model name or add documentation about model configuration.

The default model "gpt-5-mini" is OpenAI-specific and will likely be invalid for most custom endpoints (e.g., local LLMs, other OpenAI-compatible providers). Users will need to explicitly set the model via CLI or config, but there's no indication of this requirement.

Consider either:

  1. Using a more generic placeholder like "default" or "gpt-3.5-turbo" (more widely supported), or
  2. Adding a comment or documentation noting that users must configure the model when using custom endpoints.
src/provider/mod.rs (2)

69-69: Minor grammar improvement in error message.

The phrase "required on CustomOpenAI provider" sounds slightly off.

✏️ Suggested improvement
-                            LumenError::ConfigurationError("A Custom URL is required on CustomOpenAI provider".to_string())
+                            LumenError::ConfigurationError("A custom URL is required for the CustomOpenAI provider".to_string())

56-77: Consider refactoring to reduce code duplication.

The three match arms for Openrouter, Vercel, and Customopenai follow a very similar structure. Consider extracting the common logic into a helper function or using a more data-driven approach.

♻️ Example refactor approach
// Helper function to create config
fn get_custom_provider_config(
    provider_type: ProviderType,
    base_url: Option<String>,
    defaults: &ProviderInfo,
) -> Result<CustomProviderConfig, LumenError> {
    let endpoint = match provider_type {
        ProviderType::Openrouter => "https://openrouter.ai/api/v1/".to_string(),
        ProviderType::Vercel => "https://ai-gateway.vercel.sh/v1/".to_string(),
        ProviderType::Customopenai => base_url.ok_or_else(|| {
            LumenError::ConfigurationError(
                "A custom URL is required for the CustomOpenAI provider".to_string()
            )
        })?,
        _ => unreachable!(),
    };

    Ok(CustomProviderConfig {
        endpoint,
        env_key: defaults.env_key,
        adapter_kind: AdapterKind::OpenAI,
    })
}

// Then in the match arm:
let config = get_custom_provider_config(provider_type, base_url, defaults)?;
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 69fd560 and b1d271c.

📒 Files selected for processing (5)
  • src/config/cli.rs
  • src/config/configuration.rs
  • src/config/providers.rs
  • src/main.rs
  • src/provider/mod.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/main.rs
  • src/config/cli.rs
🧰 Additional context used
🧬 Code graph analysis (1)
src/provider/mod.rs (1)
src/config/providers.rs (1)
  • for_provider (94-99)
🔇 Additional comments (2)
src/config/configuration.rs (1)

27-28: LGTM! Clean implementation following existing patterns.

The base_url field integration follows the same pattern as other config fields (api_key, model), with proper precedence handling (CLI > config file > environment variable) and serde defaults.

Also applies to: 88-90, 129-129, 135-135, 163-163

src/provider/mod.rs (1)

97-97: Consider the performance impact of cloning endpoint on every service target resolution.

The endpoint.clone() is called each time the resolver callback is invoked. While this is a real operation, in practice the cost is likely negligible compared to network I/O for API calls. However, if profiling reveals this as a bottleneck in high-frequency scenarios, consider using Arc<String> to avoid the clone overhead.

Comment thread src/provider/mod.rs
Comment on lines +49 to 50
base_url: Option<String>,
) -> Result<Self, LumenError> {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Clarify base_url handling for non-Custom providers.

Currently, base_url is only validated and used when ProviderType::Customopenai is selected. If a user mistakenly passes base_url via CLI or environment variable while using a different provider (e.g., OpenAI, Groq), it will be silently ignored. This could cause confusion.

Consider either:

  1. Adding validation to return an error if base_url is provided for non-custom providers, or
  2. Adding a warning log when base_url is provided but ignored.

Also applies to: 67-77

🤖 Prompt for AI Agents
In @src/provider/mod.rs around lines 49 - 50, The code currently only validates
and uses base_url when ProviderType::Customopenai is selected, which silently
ignores a provided base_url for other providers; update the provider
initialization (the function handling base_url in src/provider/mod.rs that
returns Result<Self, LumenError>) to check if base_url.is_some() while the
selected provider is not ProviderType::Customopenai and either return a clear
error (preferred) or emit a warning log indicating base_url will be ignored;
apply the same check/behavior in the other initialization branch around the
logic at the region covering lines 67-77 so users aren’t confused when passing
base_url for non-custom providers.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @src/provider/mod.rs:
- Around line 51-60: The check that rejects base_url for non-CustomOpenAI
providers needs an additional early validation step: when provider_type is
ProviderType::Customopenai and base_url.is_some(), attempt to parse the base_url
with reqwest::Url::parse() and if parsing fails return
LumenError::ConfigurationError with a clear message including the parse error;
update the branch around the existing base_url/is_some() check (the same block
referencing ProviderType::Customopenai and LumenError::ConfigurationError) to
perform this parse and error handling before proceeding.
- Line 108: The code calls Endpoint::from_owned (which doesn't exist in genai
0.4.0); replace it with Endpoint::from_static and supply a &'static str instead
of an owned String—either use a compile-time &'static str for the endpoint or
convert the owned String to a &'static str (e.g., leak it with
Box::leak(endpoint.into_boxed_str())) before calling
Endpoint::from_static(endpoint_static) where the variable referenced is the same
endpoint used in Endpoint::from_owned.
🧹 Nitpick comments (2)
src/provider/mod.rs (2)

78-88: Consider handling trailing slashes for consistency.

The code comment on line 73 notes that Vercel requires a trailing slash for URL joining. However, the custom base_url doesn't enforce or normalize trailing slashes, which could lead to URL joining issues depending on how the genai library constructs request paths.

Consider normalizing the endpoint URL to ensure consistent behavior.

♻️ Proposed trailing slash normalization
                    ProviderType::Customopenai => {
-                        let endpoint = base_url.ok_or_else(|| {
+                        let mut endpoint = base_url.ok_or_else(|| {
                            LumenError::ConfigurationError("A Custom URL is required on CustomOpenAI provider".to_string())
                        })?;
+                        
+                        // Ensure trailing slash for consistent URL joining
+                        if !endpoint.ends_with('/') {
+                            endpoint.push('/');
+                        }

                        CustomProviderConfig {
                            endpoint,
                            env_key: defaults.env_key,
                            adapter_kind: AdapterKind::OpenAI,
                        }
                    }

79-81: Optional: Improve error message wording.

The error message "A Custom URL is required on CustomOpenAI provider" could be clearer.

♻️ Suggested improvement
-                            LumenError::ConfigurationError("A Custom URL is required on CustomOpenAI provider".to_string())
+                            LumenError::ConfigurationError("Base URL is required when using the CustomOpenAI provider".to_string())
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b1d271c and 2089ea8.

📒 Files selected for processing (1)
  • src/provider/mod.rs
🔇 Additional comments (1)
src/provider/mod.rs (1)

39-39: LGTM!

The type change from &'static str to String is necessary and correct for supporting dynamic endpoints from configuration.

Comment thread src/provider/mod.rs
Comment on lines +51 to +60
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(),
));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 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 -40

Repository: 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 rust

Repository: jnsahaj/lumen

Length of output: 865


🏁 Script executed:

# Look for genai library usage and Endpoint initialization
rg -n "genai\|Endpoint" --type rust -C 3

Repository: 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.rs

Repository: 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 2

Repository: 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 -i

Repository: 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.rs

Repository: 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 -50

Repository: 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 -80

Repository: 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.rs

Repository: 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 -20

Repository: jnsahaj/lumen

Length of output: 885


Add URL validation for base_url when using CustomOpenAI provider.

The code currently accepts base_url as any string without validating its format. While the genai library will eventually validate it, providing early validation would improve the user experience by surfacing format errors immediately rather than during the HTTP request.

Consider adding validation using reqwest::Url::parse():

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,
                        }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In @src/provider/mod.rs around lines 51 - 60, The check that rejects base_url
for non-CustomOpenAI providers needs an additional early validation step: when
provider_type is ProviderType::Customopenai and base_url.is_some(), attempt to
parse the base_url with reqwest::Url::parse() and if parsing fails return
LumenError::ConfigurationError with a clear message including the parse error;
update the branch around the existing base_url/is_some() check (the same block
referencing ProviderType::Customopenai and LumenError::ConfigurationError) to
perform this parse and error handling before proceeding.

Comment thread src/provider/mod.rs
let ServiceTarget { model, .. } = service_target;
Ok(ServiceTarget {
endpoint: Endpoint::from_static(endpoint),
endpoint: Endpoint::from_owned(endpoint.clone()),

@coderabbitai coderabbitai Bot Jan 8, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

cd /tmp && find . -name "Cargo.toml" -type f 2>/dev/null | head -5

Repository: 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 rust

Repository: jnsahaj/lumen

Length of output: 154


🌐 Web query:

genai crate Rust Endpoint::from_owned version 0.4.0

💡 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 5

Repository: jnsahaj/lumen

Length of output: 427


🏁 Script executed:

rg "struct Endpoint|impl Endpoint" --type rust

Repository: jnsahaj/lumen

Length of output: 39


🏁 Script executed:

head -30 src/provider/mod.rs

Repository: jnsahaj/lumen

Length of output: 955


🏁 Script executed:

sed -n '100,120p' src/provider/mod.rs

Repository: jnsahaj/lumen

Length of output: 980


🌐 Web query:

genai rust crate 0.4.0 Endpoint API methods available

💡 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:

site:docs.rs genai 0.4 Endpoint from_static from_owned resolver

💡 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:

  • genai crate docs and examples (ServiceTargetResolver example). [1]
  • genai crate module index. [2]
  • xai-grpc-client Endpoint (from_static / from_shared). [3]

🌐 Web query:

genai rust resolver Endpoint methods 0.4.0 site:github.com/jeremychone/rust-genai

💡 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:
[1] jeremychone/rust-genai README (v0.4.x notes). (github.com)
[2] examples/c06-target-resolver.rs (custom endpoint/auth resolver example). (github.com)

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 3

Repository: 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.rs

Repository: jnsahaj/lumen

Length of output: 1219


🏁 Script executed:

rg "config.endpoint" src/ -B 5 -A 5 --type rust | head -40

Repository: jnsahaj/lumen

Length of output: 815


🌐 Web query:

genai 0.4.0 Endpoint::from_static signature &str string

💡 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}")
EOF

Repository: jnsahaj/lumen

Length of output: 143


🌐 Web query:

genai 0.4.0 resolver module Endpoint type definition methods

💡 Result:

In genai v0.4.0 (Go package) the resolver Endpoint type is a simple struct added in v0.4.0:

type Endpoint struct {
Name string json:"name,omitempty"
DeployedModelID string json:"deployedModelId,omitempty"
}

It represents an endpoint where models are deployed and has no receiver methods defined on it (just the two fields). [1]

Sources:
[1] google.golang.org/genai (Endpoint type, added in v0.4.0).


Endpoint::from_owned does not exist in genai 0.4.0 and will cause a compilation error.

The genai v0.4.0 resolver module provides only Endpoint::from_static, not from_owned. This change references a non-existent method and will prevent the code from compiling. Additionally, from_static expects a &'static str, not an owned String, which may require a different approach for dynamic endpoint configuration.

🤖 Prompt for AI Agents
In @src/provider/mod.rs at line 108, The code calls Endpoint::from_owned (which
doesn't exist in genai 0.4.0); replace it with Endpoint::from_static and supply
a &'static str instead of an owned String—either use a compile-time &'static str
for the endpoint or convert the owned String to a &'static str (e.g., leak it
with Box::leak(endpoint.into_boxed_str())) before calling
Endpoint::from_static(endpoint_static) where the variable referenced is the same
endpoint used in Endpoint::from_owned.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It builds ok for me.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# Check the exact genai version being used
echo "=== Cargo.toml genai dependency ==="
cat Cargo.toml | grep -A 2 "genai"

echo -e "\n=== Cargo.lock genai version ==="
cat Cargo.lock | grep -A 5 "name = \"genai\"" | head -10

echo -e "\n=== Check if from_owned is used anywhere ==="
rg "from_owned" --type rust -C 2

echo -e "\n=== Check genai resolver imports ==="
rg "use genai::resolver" --type rust -A 3

Length of output: 1118


🌐 Web query:

genai rust crate 0.4.4 Endpoint from_owned method

💡 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:

  • genai example using Endpoint::from_static. [1]
  • genai crate docs (resolver/ServiceTarget/Client docs). [2]

🏁 Script executed:

#!/bin/bash

# Clone and check the genai repository directly to see if from_owned exists
cd /tmp
rm -rf rust-genai 2>/dev/null
git clone --depth 1 --branch v0.4.4 https://github.com/jeremychone/rust-genai.git 2>&1 || \
git clone --depth 1 https://github.com/jeremychone/rust-genai.git 2>&1

cd rust-genai

echo "=== Searching for from_owned in genai source ==="
rg "from_owned" -A 3 -B 3

echo -e "\n=== Searching for Endpoint implementation ==="
rg "impl.*Endpoint" -A 10

echo -e "\n=== Check Endpoint struct definition ==="
rg "struct Endpoint|pub fn from_" src/ -A 3

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 Endpoint::from_owned does exist. It's defined in the resolver module and accepts anything that implements Into<Arc<str>>, which makes it perfect for your use case with dynamic endpoints.

pub fn from_owned(url: impl Into<Arc<str>>) -> Self {
    Endpoint {
        inner: EndpointInner::Owned(url.into()),
    }
}

Your implementation using Endpoint::from_owned(endpoint.clone()) is correct and will compile successfully. My initial analysis was based on incomplete information. The change from from_static to from_owned is the right approach for supporting dynamic base URLs.

Sorry for the confusion!


🧬 Code Graph Analysis Results

Filename: src/command/mod.rs (lines 43-45)

pub fn new(provider: LumenProvider) -> Self {
        LumenCommand { provider }
    }

Filename: src/ai_prompt.rs (lines 18-97)
Summary:

  • Function: build_explain_prompt(command: &ExplainCommand) -> Result<Self, AIPromptError>
  • Parameters:
    • command: &ExplainCommand
  • Returns:
    • Ok(AIPrompt) containing system_prompt and user_prompt configured to explain Git changes concisely
    • Err(AIPromptError) on error
  • Key behavior:
    • Builds a system_prompt describing the assistant role for explaining changes concisely
    • Constructs user_prompt based on command.git_entity (Commit or Diff) with appropriate content
    • Uses formatting to present change context and a focused explanation
  • Error handling:
    • Propagates AIPromptError on failure
  • Important implementation details:
    • For Commit, includes commit message and diffs
    • For Diff, includes Changes diff block
    • Keeps prompts concise with markdown formatting

Filename: src/ai_prompt.rs (lines 99-149)
Summary:

  • Function: build_draft_prompt(command: &DraftCommand) -> Result<Self, AIPromptError>
  • Parameters:
    • command: &DraftCommand
  • Returns:
    • Ok(AIPrompt) for drafting a commit message
    • Err(AIPromptError) if not a working-tree diff
  • Key behavior:
    • Validates that the command.git_entity is a Diff::WorkingTree
    • Sets system_prompt describing a commit message generator with rules (present tense, concise, format: type(scope): message)
    • Builds a user_prompt requesting a concise git commit message for the given diff, with a character limit and a type chosen from a JSON mapping
  • Error handling:
    • Returns AIPromptError if draft is not applicable to the provided diff
  • Important implementation details:
    • May include optional context in the prompt
    • Enforces strict output format to be directly usable as a commit message

Filename: src/ai_prompt.rs (lines 151-170)
Summary:

  • Function: build_operate_prompt(query: &str) -> Result<Self, AIPromptError>
  • Parameters:
    • query: &str
  • Returns:
    • Ok(AIPrompt) containing system_prompt and user_prompt for generating a Git command
    • Err(AIPromptError) on error
  • Key behavior:
    • System prompt defines role as a Git assistant that provides commands with explanations
    • User prompt asks to generate a Git command for the given query, including a command tag, explanation, and a warning for destructive commands
  • Error handling:
    • Propagates AIPromptError on failure
  • Important implementation details:
    • Prefixes any destructive commands with a warning field
    • Intended to produce structured output suitable for execution and explanation

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/provider/mod.rs (1)

66-71: Fix type mismatch: missing .to_string() for OpencodeZen endpoint.

The endpoint field in CustomProviderConfig is now of type String (line 39), but line 68 assigns a string literal without converting it. This will cause a compilation error.

🐛 Proposed fix
                    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,
                    },
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2089ea8 and 6ef7fa5.

📒 Files selected for processing (3)
  • src/config/cli.rs
  • src/config/providers.rs
  • src/provider/mod.rs
🔇 Additional comments (8)
src/config/cli.rs (3)

37-38: LGTM!

The CLI argument for base URL is properly defined with appropriate short and long flags. This integrates cleanly with the existing CLI structure.


56-56: LGTM!

The Customopenai variant is properly added to the ProviderType enum, maintaining consistency with the existing provider types.


74-74: LGTM!

The string-to-enum mapping for "customopenai" is correctly implemented in the FromStr trait, following the pattern of existing providers.

src/provider/mod.rs (4)

39-39: LGTM!

Changing the endpoint field to String enables dynamic base URL configuration for custom providers. This is necessary to support the custom OpenAI provider feature.


49-60: LGTM!

The validation ensures that base_url can only be provided when using the Customopenai provider. This prevents misuse and provides a clear error message when users attempt to set a base URL for standard providers.


83-93: LGTM!

The Customopenai provider correctly requires a base URL and returns a clear error if it's missing. The implementation properly constructs the CustomProviderConfig with the provided endpoint.


113-113: LGTM!

The change from Endpoint::from_static to Endpoint::from_owned with clone() is necessary since endpoints are now owned String values rather than static string slices. This aligns with the dynamic base URL feature.

src/config/providers.rs (1)

90-96: No changes needed. The default model "gpt-5-mini" is a valid OpenAI model announced in August 2025 and remains available through 2026.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/provider/mod.rs (1)

109-118: Performance concern: endpoint cloned on every request.

The resolver closure clones endpoint (a String) each time it's invoked, which happens for every API request through the ServiceTargetResolver. This is inefficient for frequently-used providers.

♻️ Use Arc to avoid repeated cloning

At line 106, wrap endpoint in Arc before the closure:

-                let endpoint = config.endpoint;
+                let endpoint = std::sync::Arc::new(config.endpoint);
                 let adapter_kind = config.adapter_kind;

                 let target_resolver = ServiceTargetResolver::from_resolver_fn(
                     move |service_target: ServiceTarget| -> Result<ServiceTarget, genai::resolver::Error> {
                         let ServiceTarget { model, .. } = service_target;
                         Ok(ServiceTarget {
-                            endpoint: Endpoint::from_owned(endpoint.clone()),
+                            endpoint: Endpoint::from_owned((*endpoint).clone()),
                             auth: AuthData::from_env(auth_env_key),
                             model: ModelIden::new(adapter_kind, model.model_name),
                         })
                     },
                 );

Arc::clone() (inside the move) is a cheap operation (just incrementing a refcount), while String::clone() allocates new memory. Since Endpoint::from_owned accepts impl Into<Arc<str>>, the Arc-wrapped String will be efficiently converted.

🤖 Fix all issues with AI agents
In @src/provider/mod.rs:
- Around line 83-93: The error thrown when base_url is missing in the
ProviderType::Customopenai arm uses awkward wording; update the
LumenError::ConfigurationError message to clearly state that a custom endpoint
URL is required for the CustomOpenAI provider (e.g. "A custom endpoint URL is
required for the CustomOpenAI provider" or similar), keeping the existing
base_url check and construction of CustomProviderConfig (endpoint,
defaults.env_key, AdapterKind::OpenAI) unchanged.
🧹 Nitpick comments (2)
src/provider/mod.rs (2)

39-39: Consider performance: keep static endpoints for non-dynamic providers.

The change from &'static str to String forces all providers to allocate owned strings, even those with static endpoints (OpencodeZen, Openrouter, Vercel). Only Customopenai requires a dynamic endpoint.

♻️ Proposed optimization using enum
 struct CustomProviderConfig {
-    endpoint: String,
+    endpoint: EndpointSource,
     env_key: &'static str,
     adapter_kind: AdapterKind,
 }
+
+enum EndpointSource {
+    Static(&'static str),
+    Dynamic(String),
+}

Then in the resolver closure (around line 113), match on the endpoint source:

endpoint: match &endpoint {
    EndpointSource::Static(s) => Endpoint::from_static(s),
    EndpointSource::Dynamic(s) => Endpoint::from_owned(s.clone()),
},

This avoids unnecessary allocations for static endpoints.


51-60: Consider simplifying the validation logic.

The validation correctly enforces that base_url is only used with Customopenai, but the double negative (!matches!) reduces readability.

♻️ Optional: More direct validation
-        if (base_url.is_some())
-            && !matches!(
-                provider_type,
-                ProviderType::Customopenai
-            )
-        {
+        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(),
             ));
         }

Or, if you prefer positive logic:

-        if (base_url.is_some())
-            && !matches!(
-                provider_type,
-                ProviderType::Customopenai
-            )
-        {
+        if let Some(_) = base_url {
+            if !matches!(provider_type, ProviderType::Customopenai) {
                 return Err(LumenError::ConfigurationError(
                     "Base URL can only be set for CustomOpenAI provider".to_string(),
                 ));
+            }
         }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6ef7fa5 and 11ee42b.

📒 Files selected for processing (1)
  • src/provider/mod.rs
🧰 Additional context used
🧬 Code graph analysis (1)
src/provider/mod.rs (1)
src/config/providers.rs (1)
  • for_provider (101-106)
🔇 Additional comments (3)
src/provider/mod.rs (3)

49-49: LGTM: New parameter properly integrated.

The base_url parameter is correctly added and used throughout the function for validation and the Customopenai provider initialization.


64-64: LGTM: Customopenai correctly added to custom endpoint providers.

The match pattern properly includes the new provider type alongside other custom endpoint providers.


68-82: These conversions follow from the endpoint type change.

The .to_string() calls on lines 68, 73, and 79 are necessary given the type change at line 39. See the earlier comment about optimizing the endpoint field type to avoid these allocations.

Comment thread src/provider/mod.rs
Comment on lines +83 to +93
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,
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 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.rs

Repository: 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 -20

Repository: 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 2

Repository: jnsahaj/lumen

Length of output: 1932


Improve error message wording.

The environment variable configuration is correctly set up with CUSTOMOPENAI_API_KEY in the provider defaults. The only issue is the error message phrasing.

📝 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

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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,
}
}
ProviderType::Customopenai => {
let endpoint = base_url.ok_or_else(|| {
LumenError::ConfigurationError("A custom base URL is required for the CustomOpenAI provider".to_string())
})?;
CustomProviderConfig {
endpoint,
env_key: defaults.env_key,
adapter_kind: AdapterKind::OpenAI,
}
}
🤖 Prompt for AI Agents
In @src/provider/mod.rs around lines 83 - 93, The error thrown when base_url is
missing in the ProviderType::Customopenai arm uses awkward wording; update the
LumenError::ConfigurationError message to clearly state that a custom endpoint
URL is required for the CustomOpenAI provider (e.g. "A custom endpoint URL is
required for the CustomOpenAI provider" or similar), keeping the existing
base_url check and construction of CustomProviderConfig (endpoint,
defaults.env_key, AdapterKind::OpenAI) unchanged.

@y-cg y-cg mentioned this pull request Jan 16, 2026
@nosignleft

Copy link
Copy Markdown

@jnsahaj is this OK to merge?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants