Spaces:
Runtime error
Runtime error
| """ | |
| packages/shared/exceptions.py | |
| Ultron V4 — Shared Custom Exceptions | |
| ====================================== | |
| All custom exception classes used across V4 modules live here. | |
| Import pattern: | |
| from packages.shared.exceptions import AllKeysExhaustedError, SentinelKeyUnavailableError | |
| Future bug risks (pre-registered): | |
| EX1 [MED] If pool.py is imported before shared/ is on PYTHONPATH, ImportError. | |
| Fix: ensure packages/ is in sys.path at startup (main.py responsibility). | |
| EX2 [LOW] New modules may define local exceptions with same name → shadowing. | |
| Rule: always import from shared.exceptions, never redefine locally. | |
| Tool calls used writing this file: | |
| Github:push_files x1 (batch with pool.py) | |
| """ | |
| class UltronBaseError(Exception): | |
| """Base class for all Ultron V4 exceptions.""" | |
| class AllKeysExhaustedError(UltronBaseError): | |
| """Raised by KeyPool.get_key() when all keys in the general pool are tripped. | |
| Callers (task_dispatcher, llm_router) must catch this and return a 503-style | |
| response to Discord. Never swallow silently. | |
| Attributes: | |
| provider_states: dict of {provider: failure_count} for diagnostics. | |
| """ | |
| def __init__(self, provider_states: dict | None = None): | |
| self.provider_states = provider_states or {} | |
| super().__init__( | |
| f"All keys in general pool exhausted. States: {self.provider_states}" | |
| ) | |
| class SentinelKeyUnavailableError(UltronBaseError): | |
| """Raised by KeyPool.get_sentinel_key() when the Sentinel Gemini key is tripped. | |
| Sentinel unavailability is a degraded-mode event. Ultron should: | |
| 1. Log as CRITICAL | |
| 2. Write incident to Notion (when Notion MCP available in Sentinel code) | |
| 3. Continue serving user requests from general pool (Sentinel is non-user-facing) | |
| 4. Retry Sentinel key after reset_at cooldown (24hr for Gemini). | |
| Attributes: | |
| reset_at: float UNIX timestamp when the key comes out of cooldown. | |
| """ | |
| def __init__(self, reset_at: float | None = None): | |
| self.reset_at = reset_at | |
| super().__init__( | |
| f"Sentinel key unavailable. Cooldown until: {reset_at}" | |
| ) | |
| class KeyPoolConfigError(UltronBaseError): | |
| """Raised during KeyPool.__init__ if config is malformed. | |
| Fail loud at startup. Never silently skip bad config. | |
| """ | |
| class ProviderNotSupportedError(UltronBaseError): | |
| """Raised when an unrecognized provider string is encountered in llm_router.""" | |