diff --git a/nanobot/providers/openai_compat_provider.py b/nanobot/providers/openai_compat_provider.py index 83fbd7fb3..4dea2d5fc 100644 --- a/nanobot/providers/openai_compat_provider.py +++ b/nanobot/providers/openai_compat_provider.py @@ -798,7 +798,13 @@ class OpenAICompatProvider(LLMProvider): "error_should_retry": should_retry, } - def _handle_error(self, e: Exception) -> LLMResponse: + @staticmethod + def _handle_error( + e: Exception, + *, + spec: ProviderSpec | None = None, + api_base: str | None = None, + ) -> LLMResponse: body = ( getattr(e, "doc", None) or getattr(e, "body", None) @@ -807,12 +813,11 @@ class OpenAICompatProvider(LLMProvider): body_text = body if isinstance(body, str) else str(body) if body is not None else "" msg = f"Error: {body_text.strip()[:500]}" if body_text.strip() else f"Error calling LLM: {e}" - spec = self._spec text = f"{body_text} {e}".lower() if spec and spec.is_local and ("502" in text or "connection" in text or "refused" in text): msg += ( "\nHint: this is a local model endpoint. Check that the local server is reachable at " - f"{self.api_base or spec.default_api_base}, and if you are using a proxy/tunnel, make sure it " + f"{api_base or spec.default_api_base}, and if you are using a proxy/tunnel, make sure it " "can reach your local Ollama/vLLM service instead of routing localhost through the remote host." ) @@ -859,7 +864,7 @@ class OpenAICompatProvider(LLMProvider): ) return self._parse(await self._client.chat.completions.create(**kwargs)) except Exception as e: - return self._handle_error(e) + return self._handle_error(e, spec=self._spec, api_base=self.api_base) async def chat_stream( self, @@ -942,7 +947,7 @@ class OpenAICompatProvider(LLMProvider): error_kind="timeout", ) except Exception as e: - return self._handle_error(e) + return self._handle_error(e, spec=self._spec, api_base=self.api_base) def get_default_model(self) -> str: return self.default_model diff --git a/tests/providers/test_custom_provider.py b/tests/providers/test_custom_provider.py index 33c5d027a..85314dc79 100644 --- a/tests/providers/test_custom_provider.py +++ b/tests/providers/test_custom_provider.py @@ -61,7 +61,11 @@ def test_local_provider_502_error_includes_reachability_hint() -> None: with patch("nanobot.providers.openai_compat_provider.AsyncOpenAI"): provider = OpenAICompatProvider(api_base="http://localhost:11434/v1", spec=spec) - result = provider._handle_error(Exception("Error code: 502")) + result = provider._handle_error( + Exception("Error code: 502"), + spec=spec, + api_base="http://localhost:11434/v1", + ) assert result.finish_reason == "error" assert "local model endpoint" in result.content