class NaviError(Exception):
"""Base exception for all navi errors."""
class SessionNotFound(NaviError):
def __init__(self, session_id: str):
super().__init__(f"Session not found: {session_id}")
self.session_id = session_id
class ProfileNotFound(NaviError):
def __init__(self, profile_id: str):
super().__init__(f"Profile not found: {profile_id}")
self.profile_id = profile_id
class ToolNotFound(NaviError):
def __init__(self, tool_name: str):
super().__init__(f"Tool not found: {tool_name}")
self.tool_name = tool_name
class ToolExecutionError(NaviError):
def __init__(self, tool_name: str, reason: str):
super().__init__(f"Tool '{tool_name}' failed: {reason}")
self.tool_name = tool_name
class LLMBackendError(NaviError):
pass
class LLMConnectionError(LLMBackendError):
"""Server unreachable — connection refused, timeout, network error."""
class LLMModelNotFoundError(LLMBackendError):
"""Model not found on this server."""
class LLMQuotaExceededError(LLMBackendError):
"""The provider accepted the request and refused it for quota/rate reasons.
Ollama Cloud answers 429 when the plan's limits are spent for the window.
It used to arrive as a plain ``LLMBackendError``, which the fallback loop
did not catch — so hitting the limit ended the turn instead of moving to
the backup host, the exact case the backup exists for.
"""
def __init__(self, message: str, retry_after: float | None = None):
super().__init__(message)
self.retry_after = retry_after
class LLMAuthError(LLMBackendError):
"""401/403 — the target rejected our credentials.
Not the same as a bad request: retrying with the same key is pointless,
but the key can be rotated in the environment, so the target is probed
again (slowly) rather than disabled for the process lifetime.
"""
class LLMServerUnavailableError(LLMBackendError):
"""5xx from the target — the host is up but cannot serve right now."""
class MaxIterationsReached(NaviError):
def __init__(self, limit: int):
super().__init__(f"Agent reached max iterations limit ({limit})")
self.limit = limit
class ContextTooLargeError(NaviError):
"""Raised when the estimated context size would exceed the model's safe window."""
class NothingToCompactError(NaviError):
"""Raised when a forced /compact has nothing to summarize (context too small)."""