🐛 Fix Ollama auth + config format
Fixes:
1. Added to (config.rs)
2. Rewrote with dual-mode logic:
- OpenAI-compatible mode (api_key set OR non-localhost URL):
uses /chat/completions + Bearer auth
- Native mode: uses /api/chat (no auth)
3. Updated in agent_loop.rs to pass api_key
4. Updated to pass api_key
5. Added in main.rs — parses
flat format AND canonical format
6. Added dependency to root Cargo.toml
The
o
|
- - - - - - .---. - - - - - -
- - - - - - - - - [ ^ ^ ] - - - - - - - - -
- - - - - - - | ___ | - - - - - - -
`-----'
____ __ __ ___ _ _ ____ ___ ___ _____
/ ___|\ \ / / / _ \ | \ | || _ \ / _ \ / _ \|_ _|
| | _ \ V / / /_\ \| \| || | | | | | | | | | | |
| |_| | | | | _ || |\ || |_| | |_| | |_| | | |
\____/ |_| |_| |_||_| \_||____/ \___/ \___/ |_|
o - - - - - - - knowledge. delivered. - - - - - - - o
╔══════════════════════════════════════════════╗
║ ज्ञानदूत GyanDoot — Setup Wizard ║
╚══════════════════════════════════════════════╝
Configure your AI provider in 4 simple steps
This wizard will help you configure GyanDoot to connect
to your preferred LLM provider. You can re-run this anytime.
Select a provider:
────────────────────────────────────────────────────────────
1. Alibaba (Qwen) (alibaba)
2. Anthropic (anthropic)
3. Azure OpenAI (azure)
4. Amazon Bedrock (bedrock)
5. DeepSeek (deepseek)
6. Google Gemini (gemini)
7. Groq (groq)
8. HuggingFace (huggingface)
9. Kilocode (kilocode)
10. MiniMax (minimax)
11. Novita AI (novita)
12. Ollama (Local or Cloud) (ollama)
13. OpenAI (openai)
14. OpenRouter (openrouter)
15. StepFun (stepfun)
16. Together AI (together)
17. xAI / Grok (xai)
18. Xiaomi (MiLM) (xiaomi)
19. ZAI (01.AI / Yi) (zai)
20. Custom / Other
Enter number (1-20): wizard writes (singular) but
the config loader only parsed (plural). Now both
formats work. Ollama cloud endpoints (ollama.com/v1) get proper
Bearer auth with the API key from the setup wizard.
This commit is contained in:
88
src/main.rs
88
src/main.rs
@@ -207,11 +207,8 @@ fn load_agent_config() -> gyandoot_core::config::AgentConfig {
|
||||
if let Some(home) = dirs::home_dir() {
|
||||
let explicit_path = home.join(".config").join("gyandoot").join("config.toml");
|
||||
if explicit_path.exists() {
|
||||
match gyandoot_core::config::ConfigLoader::from_file(&explicit_path) {
|
||||
Ok(gyandoot_cfg) => {
|
||||
tracing::info!("Loaded config from {}", explicit_path.display());
|
||||
return gyandoot_core::config::AgentConfig::from(gyandoot_cfg);
|
||||
}
|
||||
match load_and_convert_config(&explicit_path) {
|
||||
Ok(cfg) => return cfg,
|
||||
Err(e) => tracing::warn!("Failed to parse {}: {}", explicit_path.display(), e),
|
||||
}
|
||||
}
|
||||
@@ -221,11 +218,8 @@ fn load_agent_config() -> gyandoot_core::config::AgentConfig {
|
||||
if let Some(cfg_dir) = dirs::config_dir() {
|
||||
let xdg_path = cfg_dir.join("gyandoot").join("config.toml");
|
||||
if xdg_path.exists() {
|
||||
match gyandoot_core::config::ConfigLoader::from_file(&xdg_path) {
|
||||
Ok(gyandoot_cfg) => {
|
||||
tracing::info!("Loaded config from {}", xdg_path.display());
|
||||
return gyandoot_core::config::AgentConfig::from(gyandoot_cfg);
|
||||
}
|
||||
match load_and_convert_config(&xdg_path) {
|
||||
Ok(cfg) => return cfg,
|
||||
Err(e) => tracing::warn!("Failed to parse {}: {}", xdg_path.display(), e),
|
||||
}
|
||||
}
|
||||
@@ -250,11 +244,83 @@ fn load_agent_config() -> gyandoot_core::config::AgentConfig {
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Fallback to hardcoded defaults
|
||||
// 4. Fallback to hardcoded defaults
|
||||
tracing::warn!("No config file found; using default configuration (API keys will be empty)");
|
||||
gyandoot_core::config::AgentConfig::default()
|
||||
}
|
||||
|
||||
/// Load a TOML config file, converting `[provider]` (singular, flat format
|
||||
/// written by `gyandoot setup`) to the canonical `[providers]` format.
|
||||
fn load_and_convert_config(path: &std::path::Path) -> Result<gyandoot_core::config::AgentConfig, Box<dyn std::error::Error>> {
|
||||
let content = std::fs::read_to_string(path)?;
|
||||
|
||||
// Try parsing as canonical GyandootConfig first
|
||||
if let Ok(gyandoot_cfg) = toml::from_str::<gyandoot_core::config::GyandootConfig>(&content) {
|
||||
tracing::info!("Loaded config from {}", path.display());
|
||||
return Ok(gyandoot_core::config::AgentConfig::from(gyandoot_cfg));
|
||||
}
|
||||
|
||||
// Fallback: parse flat `[provider]` format and convert to canonical
|
||||
#[derive(serde::Deserialize)]
|
||||
struct FlatConfig {
|
||||
provider: FlatProvider,
|
||||
agent: Option<FlatAgent>,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
struct FlatProvider {
|
||||
kind: String,
|
||||
base_url: String,
|
||||
api_key: Option<String>,
|
||||
model: String,
|
||||
temperature: Option<f64>,
|
||||
max_tokens: Option<u32>,
|
||||
#[serde(default)]
|
||||
merge_system: bool,
|
||||
#[serde(default)]
|
||||
no_tools: bool,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
struct FlatAgent {
|
||||
name: Option<String>,
|
||||
}
|
||||
|
||||
let flat: FlatConfig = toml::from_str(&content)?;
|
||||
tracing::info!("Loaded config from {} (converted from flat [provider] format)", path.display());
|
||||
|
||||
// Build canonical GyandootConfig from flat data
|
||||
let provider_name = flat.provider.kind.to_lowercase();
|
||||
let mut providers_map = std::collections::HashMap::new();
|
||||
let mut provider_table = toml::map::Map::new();
|
||||
provider_table.insert("model".to_string(), toml::Value::String(flat.provider.model.clone()));
|
||||
provider_table.insert("base_url".to_string(), toml::Value::String(flat.provider.base_url));
|
||||
if let Some(key) = &flat.provider.api_key {
|
||||
provider_table.insert("api_key".to_string(), toml::Value::String(key.clone()));
|
||||
}
|
||||
providers_map.insert(provider_name.clone(), toml::Value::Table(provider_table));
|
||||
|
||||
let gyandoot_cfg = gyandoot_core::config::GyandootConfig {
|
||||
agent: gyandoot_core::config::AgentSection {
|
||||
name: flat.agent.and_then(|a| a.name).unwrap_or_else(|| "gyandoot".to_string()),
|
||||
model: flat.provider.model.clone(),
|
||||
max_tokens: flat.provider.max_tokens.unwrap_or(4096) as usize,
|
||||
temperature: flat.provider.temperature.unwrap_or(0.7),
|
||||
system_prompt: String::new(),
|
||||
},
|
||||
providers: gyandoot_core::config::ProvidersSection {
|
||||
default: provider_name,
|
||||
providers: providers_map,
|
||||
},
|
||||
platform: gyandoot_core::config::PlatformSection::default(),
|
||||
memory: gyandoot_core::config::MemorySection::default(),
|
||||
gateway: gyandoot_core::config::GatewaySection::default(),
|
||||
browser: gyandoot_core::config::BrowserSection::default(),
|
||||
};
|
||||
|
||||
Ok(gyandoot_core::config::AgentConfig::from(gyandoot_cfg))
|
||||
}
|
||||
|
||||
/// Start the gateway server for multi-platform sessions
|
||||
async fn cmd_serve(profile_name: &str, host: &str, port: u16) -> anyhow::Result<()> {
|
||||
tracing::info!(
|
||||
|
||||
Reference in New Issue
Block a user