diff --git a/navi/core/registry.py b/navi/core/registry.py index 4cb3940..99f6820 100644 --- a/navi/core/registry.py +++ b/navi/core/registry.py @@ -116,6 +116,11 @@ from navi.llm.ollama import OllamaBackend from navi.llm.fallback import FallbackOllamaBackend from navi.llm.openai_backend import OpenAIBackend + ollama_http_timeout = max( + settings.ollama_request_timeout, + settings.llm_complete_timeout, + settings.llm_stream_first_chunk_timeout, + ) # Ollama backend (primary) if settings.ollama_backends_file: @@ -126,6 +131,7 @@ model=settings.ollama_default_model, host=settings.ollama_host, api_key=settings.ollama_api_key, + timeout=ollama_http_timeout, ))) # OpenAI backend (if configured) diff --git a/navi/llm/fallback.py b/navi/llm/fallback.py index 163d87f..9bb8106 100644 --- a/navi/llm/fallback.py +++ b/navi/llm/fallback.py @@ -79,9 +79,14 @@ def _get_client(self, server: ServerEntry) -> OllamaBackend: from navi.config import settings if server.host not in self._clients: + ollama_http_timeout = max( + settings.ollama_request_timeout, + settings.llm_complete_timeout, + settings.llm_stream_first_chunk_timeout, + ) self._clients[server.host] = OllamaBackend( model="", host=server.host, api_key=server.api_key, - timeout=settings.ollama_request_timeout, + timeout=ollama_http_timeout, ) return self._clients[server.host] diff --git a/navi/llm/ollama.py b/navi/llm/ollama.py index aa5db4c..5e0146c 100644 --- a/navi/llm/ollama.py +++ b/navi/llm/ollama.py @@ -71,7 +71,10 @@ return LLMModelNotFoundError(str(e)) return LLMBackendError(str(e)) # Catch httpx / socket connection failures by message + err_type = type(e).__name__.lower() err_str = str(e).lower() + if "timeout" in err_type: + return LLMConnectionError(str(e) or type(e).__name__) if any(kw in err_str for kw in ("connect", "connection refused", "name or service not known", "network", "timeout", "unreachable", "nodename")): return LLMConnectionError(str(e)) diff --git a/tests/unit/llm/test_ollama.py b/tests/unit/llm/test_ollama.py new file mode 100644 index 0000000..10d6b00 --- /dev/null +++ b/tests/unit/llm/test_ollama.py @@ -0,0 +1,19 @@ +"""Unit tests for Ollama backend helpers.""" + +import httpx + +from navi.exceptions import LLMConnectionError +from navi.llm.ollama import _classify_error + + +def test_classify_read_timeout_as_connection_error(): + err = _classify_error(httpx.ReadTimeout("timed out")) + + assert isinstance(err, LLMConnectionError) + + +def test_classify_empty_timeout_message_as_connection_error(): + err = _classify_error(httpx.ReadTimeout("")) + + assert isinstance(err, LLMConnectionError) + assert str(err) == "ReadTimeout"