Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/config/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ pub struct Cli {
#[arg(value_enum, long = "vcs")]
pub vcs: Option<VcsOverride>,

#[arg(short = 'u', long = "base-url")]
pub base_url: Option<String>,

#[command(subcommand)]
pub command: Commands,
}
Expand All @@ -50,6 +53,7 @@ pub enum ProviderType {
Gemini,
Xai,
Vercel,
Customopenai
}

impl FromStr for ProviderType {
Expand All @@ -67,6 +71,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)),
}
}
Expand Down
10 changes: 10 additions & 0 deletions src/config/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ pub struct LumenConfig {
#[serde(default = "default_api_key")]
pub api_key: Option<String>,

#[serde(default = "default_base_url")]
pub base_url: Option<String>,

#[serde(default = "default_draft_config")]
pub draft: DraftConfig,

Expand Down Expand Up @@ -82,6 +85,10 @@ fn default_api_key() -> Option<String> {
std::env::var("LUMEN_API_KEY").ok()
}

fn default_base_url() -> Option<String> {
std::env::var("LUMEN_BASE_URL").ok()
}

fn deserialize_commit_types<'de, D>(deserializer: D) -> Result<String, D::Error>
where
D: Deserializer<'de>,
Expand Down Expand Up @@ -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,
})
Expand Down Expand Up @@ -151,6 +160,7 @@ impl Default for LumenConfig {
api_key: default_api_key(),
draft: default_draft_config(),
theme: None,
base_url: default_base_url(),
}
}
}
7 changes: 7 additions & 0 deletions src/config/providers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,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 {
Expand Down
3 changes: 2 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(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
Expand Down
37 changes: 30 additions & 7 deletions src/provider/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand All @@ -46,28 +46,51 @@ impl LumenProvider {
provider_type: ProviderType,
api_key: Option<String>,
model: Option<String>,
base_url: Option<String>,
) -> Result<Self, LumenError> {
Comment on lines +49 to 50

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.

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

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.


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

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.

_ => unreachable!(),
};

Expand All @@ -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()),

@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

auth: AuthData::from_env(auth_env_key),
model: ModelIden::new(adapter_kind, model.model_name),
})
Expand Down