Spaces:
Runtime error
Runtime error
""" | |
Error handling utilities for the AI agent project. | |
""" | |
import functools | |
import time | |
import logging | |
from typing import Callable, Dict, Any, TypeVar, Optional | |
# Type variables for function signature | |
F = TypeVar('F', bound=Callable[..., Any]) | |
T = TypeVar('T') | |
class ToolExecutionError(Exception): | |
"""Exception raised when a tool execution fails.""" | |
def __init__(self, tool_name: str, message: str): | |
self.tool_name = tool_name | |
self.message = message | |
super().__init__(f"Error executing {tool_name}: {message}") | |
def log_exceptions(func: F) -> F: | |
""" | |
Decorator to log exceptions raised by functions. | |
Args: | |
func: Function to decorate | |
Returns: | |
Decorated function | |
""" | |
def wrapper(*args, **kwargs): | |
try: | |
return func(*args, **kwargs) | |
except Exception as e: | |
# Get the logger for the module where the function is defined | |
logger = logging.getLogger(func.__module__) | |
logger.error(f"Exception in {func.__name__}: {e}") | |
# Re-raise the exception | |
raise | |
return wrapper | |
def retry(tries: int = 3, delay: float = 1, backoff: float = 2, logger_func: Callable = print) -> Callable: | |
""" | |
Retry decorator with exponential backoff. | |
Args: | |
tries: Number of times to try before giving up | |
delay: Initial delay between retries in seconds | |
backoff: Backoff multiplier | |
logger_func: Function to use for logging | |
Returns: | |
Decorator function | |
""" | |
def decorator(func): | |
def wrapper(*args, **kwargs): | |
mtries, mdelay = tries, delay | |
while mtries > 0: | |
try: | |
return func(*args, **kwargs) | |
except Exception as e: | |
msg = f"{func.__name__} - Retrying in {mdelay}s... ({mtries-1} tries left). Error: {e}" | |
if logger_func: | |
logger_func(msg) | |
time.sleep(mdelay) | |
mtries -= 1 | |
mdelay *= backoff | |
# If we get here, we've exhausted all retries | |
return func(*args, **kwargs) | |
return wrapper | |
return decorator | |
class FallbackRegistry: | |
"""Registry for tool fallbacks.""" | |
_fallbacks = {} | |
def register_fallback(cls, tool_name: str, fallback_func: Callable) -> None: | |
""" | |
Register a fallback function for a tool. | |
Args: | |
tool_name: Name of the tool | |
fallback_func: Fallback function to use | |
""" | |
cls._fallbacks[tool_name] = fallback_func | |
def get_fallback(cls, tool_name: str) -> Optional[Callable]: | |
""" | |
Get the fallback function for a tool. | |
Args: | |
tool_name: Name of the tool | |
Returns: | |
Fallback function or None if not found | |
""" | |
return cls._fallbacks.get(tool_name) |