Fix: banner on launch, config file loading, 7 providers match setup wizard
BUGFIXES: - Banner now displays on 'gyandoot run' via gyandoot_tui::banner::print_banner() - Config now loads from ~/.config/gyandoot/config.toml with fallback chain (XDG -> ~/.gyandoot/config.yaml -> hardcoded defaults), fixing 401 errors - gyandoot init now writes visible placeholder api_key for users to edit NEW PROVIDERS (4 added, now 7 total matching setup wizard): - Google Gemini: Native API with x-goog-api-key auth, streamingGenerateContent - DeepSeek: OpenAI-compatible wrapper at api.deepseek.com/v1 - OpenRouter: With HTTP-Referer/X-Title headers, model routing - Groq: OpenAI-compatible wrapper at api.groq.com/openai/v1 All compile with 0 errors.
This commit is contained in:
@@ -14,12 +14,20 @@ pub mod openai;
|
||||
pub mod anthropic;
|
||||
pub mod ollama;
|
||||
pub mod streaming;
|
||||
pub mod gemini;
|
||||
pub mod deepseek;
|
||||
pub mod openrouter;
|
||||
pub mod groq;
|
||||
|
||||
// ─── Re-exports ───────────────────────────────────────────────────────────
|
||||
|
||||
pub use openai::OpenAIProvider;
|
||||
pub use anthropic::AnthropicProvider;
|
||||
pub use ollama::OllamaProvider;
|
||||
pub use gemini::GeminiProvider;
|
||||
pub use deepseek::DeepSeekProvider;
|
||||
pub use openrouter::OpenRouterProvider;
|
||||
pub use groq::GroqProvider;
|
||||
pub use streaming::{SseParser, StreamEvent, TokenStream, collect_stream};
|
||||
|
||||
// ─── ProviderResponse ─────────────────────────────────────────────────────
|
||||
@@ -102,6 +110,7 @@ pub enum ProviderKind {
|
||||
Gemini,
|
||||
DeepSeek,
|
||||
OpenRouter,
|
||||
Groq,
|
||||
}
|
||||
|
||||
impl ProviderKind {
|
||||
@@ -114,6 +123,7 @@ impl ProviderKind {
|
||||
"gemini" => Some(ProviderKind::Gemini),
|
||||
"deepseek" => Some(ProviderKind::DeepSeek),
|
||||
"openrouter" => Some(ProviderKind::OpenRouter),
|
||||
"groq" => Some(ProviderKind::Groq),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -127,6 +137,7 @@ impl ProviderKind {
|
||||
ProviderKind::Gemini => "gemini",
|
||||
ProviderKind::DeepSeek => "deepseek",
|
||||
ProviderKind::OpenRouter => "openrouter",
|
||||
ProviderKind::Groq => "groq",
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,7 +171,7 @@ impl ProviderFactory {
|
||||
config: &gyandoot_core::ProviderRootConfig,
|
||||
) -> ProviderResult<Box<dyn Provider>> {
|
||||
match kind {
|
||||
ProviderKind::OpenAI | ProviderKind::DeepSeek | ProviderKind::OpenRouter => {
|
||||
ProviderKind::OpenAI => {
|
||||
let cfg = config.openai.as_ref().ok_or_else(|| gyandoot_core::ProviderError::Api {
|
||||
status: 0,
|
||||
message: "OpenAI config not found".to_string(),
|
||||
@@ -196,8 +207,40 @@ impl ProviderFactory {
|
||||
status: 0,
|
||||
message: "Gemini config not found (use openai section)".to_string(),
|
||||
})?;
|
||||
// Gemini uses the OpenAI-compatible endpoint
|
||||
Ok(Box::new(openai::OpenAIProvider::new(
|
||||
Ok(Box::new(gemini::GeminiProvider::new(
|
||||
cfg.api_key.clone(),
|
||||
cfg.model.clone(),
|
||||
cfg.base_url.clone(),
|
||||
)))
|
||||
}
|
||||
ProviderKind::DeepSeek => {
|
||||
let cfg = config.openai.as_ref().ok_or_else(|| gyandoot_core::ProviderError::Api {
|
||||
status: 0,
|
||||
message: "DeepSeek config not found (use openai section)".to_string(),
|
||||
})?;
|
||||
Ok(Box::new(deepseek::DeepSeekProvider::new(
|
||||
cfg.api_key.clone(),
|
||||
cfg.model.clone(),
|
||||
cfg.base_url.clone(),
|
||||
)))
|
||||
}
|
||||
ProviderKind::OpenRouter => {
|
||||
let cfg = config.openai.as_ref().ok_or_else(|| gyandoot_core::ProviderError::Api {
|
||||
status: 0,
|
||||
message: "OpenRouter config not found (use openai section)".to_string(),
|
||||
})?;
|
||||
Ok(Box::new(openrouter::OpenRouterProvider::new(
|
||||
cfg.api_key.clone(),
|
||||
cfg.model.clone(),
|
||||
cfg.base_url.clone(),
|
||||
)))
|
||||
}
|
||||
ProviderKind::Groq => {
|
||||
let cfg = config.openai.as_ref().ok_or_else(|| gyandoot_core::ProviderError::Api {
|
||||
status: 0,
|
||||
message: "Groq config not found (use openai section)".to_string(),
|
||||
})?;
|
||||
Ok(Box::new(groq::GroqProvider::new(
|
||||
cfg.api_key.clone(),
|
||||
cfg.model.clone(),
|
||||
cfg.base_url.clone(),
|
||||
@@ -220,7 +263,7 @@ impl ProviderFactory {
|
||||
|
||||
let config = gyandoot_core::ProviderRootConfig {
|
||||
default: name.to_string(),
|
||||
openai: if matches!(kind, ProviderKind::OpenAI | ProviderKind::DeepSeek | ProviderKind::OpenRouter | ProviderKind::Gemini) {
|
||||
openai: if matches!(kind, ProviderKind::OpenAI | ProviderKind::DeepSeek | ProviderKind::OpenRouter | ProviderKind::Gemini | ProviderKind::Groq) {
|
||||
Some(gyandoot_core::OpenAIConfig {
|
||||
api_key: api_key.to_string(),
|
||||
model: model.to_string(),
|
||||
@@ -263,6 +306,7 @@ fn default_base_url(kind: &ProviderKind) -> String {
|
||||
ProviderKind::Gemini => "https://generativelanguage.googleapis.com/v1".to_string(),
|
||||
ProviderKind::DeepSeek => "https://api.deepseek.com/v1".to_string(),
|
||||
ProviderKind::OpenRouter => "https://openrouter.ai/api/v1".to_string(),
|
||||
ProviderKind::Groq => "https://api.groq.com/openai/v1".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,6 +325,7 @@ mod tests {
|
||||
ProviderKind::Gemini,
|
||||
ProviderKind::DeepSeek,
|
||||
ProviderKind::OpenRouter,
|
||||
ProviderKind::Groq,
|
||||
] {
|
||||
let s = kind.to_string();
|
||||
let parsed = ProviderKind::from_str(&s).unwrap();
|
||||
|
||||
Reference in New Issue
Block a user