Skip to content

Commit 0f40985

Browse files
0xrinegadeclaude
andcommitted
feat(ai): Add automatic Ollama fallback when osvm.ai is unavailable
- Add fallback mechanism to AiService that tries local Ollama when primary osvm.ai endpoint fails or times out - Preserve system prompt when falling back (critical for agentic behavior) - Add user notification in chat UI: "⚡ Using local AI (model) - primary service unavailable" - Add `did_use_fallback()` and `get_fallback_model()` public methods for UI integration - Use atomic flag for thread-safe fallback state tracking - Default fallback model: qwen3-coder:30b (configurable via OLLAMA_MODEL env) - Reduced retry attempts from 4 to 2 for faster fallback response This fixes the chat hanging forever when osvm.ai is down by automatically switching to local Ollama while preserving the full system prompt for proper agentic execution. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent fcf5d71 commit 0f40985

File tree

2 files changed

+28
-1
lines changed

2 files changed

+28
-1
lines changed

src/services/ai_service.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ pub struct AiService {
7777
/// Fallback to Ollama if primary API fails
7878
fallback_url: Option<String>,
7979
fallback_model: Option<String>,
80+
/// Track if last request used fallback (for UI notification)
81+
last_used_fallback: std::sync::Arc<std::sync::atomic::AtomicBool>,
8082
}
8183

8284
impl AiService {
@@ -257,9 +259,20 @@ impl AiService {
257259
conversation_history: std::sync::Arc::new(std::sync::Mutex::new(Vec::new())),
258260
fallback_url,
259261
fallback_model,
262+
last_used_fallback: std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)),
260263
}
261264
}
262265

266+
/// Check if the last AI request used fallback (and reset the flag)
267+
pub fn did_use_fallback(&self) -> bool {
268+
self.last_used_fallback.swap(false, std::sync::atomic::Ordering::SeqCst)
269+
}
270+
271+
/// Get the fallback model name if available
272+
pub fn get_fallback_model(&self) -> Option<&str> {
273+
self.fallback_model.as_deref()
274+
}
275+
263276
/// Add a message to the conversation history
264277
pub fn add_to_history(&self, role: &str, content: &str) {
265278
if let Ok(mut history) = self.conversation_history.lock() {
@@ -574,7 +587,9 @@ impl AiService {
574587

575588
// Check if Ollama is available before trying
576589
if self.is_ollama_available().await {
577-
debug_print!("🔄 Falling back to local Ollama (system prompt preserved)");
590+
// Set fallback flag for UI notification
591+
self.last_used_fallback.store(true, std::sync::atomic::Ordering::SeqCst);
592+
log::info!("AI fallback: using local Ollama instead of osvm.ai");
578593

579594
// Use Ollama with the SAME system prompt
580595
match self.query_ollama_fallback(question, system_prompt.clone(), debug_mode).await {

src/utils/agent_chat_v2/agent/execution.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,18 @@ impl AdvancedChatState {
143143
// Determine if any MCP servers/tools are configured
144144
let no_configured_tools = available_tools.is_empty();
145145

146+
// Check if AI service used Ollama fallback and notify user
147+
if self.ai_service.did_use_fallback() {
148+
let fallback_model = self.ai_service.get_fallback_model().unwrap_or("local model");
149+
let _ = self.add_message_to_session(
150+
session_id,
151+
ChatMessage::System(format!(
152+
"⚡ Using local AI ({}) - primary service unavailable",
153+
fallback_model
154+
)),
155+
);
156+
}
157+
146158
match tool_plan_result {
147159
Err(_) => {
148160
warn!("AI planning timed out");

0 commit comments

Comments
 (0)