import inspect import json import logging from functools import wraps import httpx from mem0.exceptions import ( NetworkError, create_exception_from_response, ) logger = logging.getLogger(__name__) class APIError(Exception): """Exception raised for errors in the API. Deprecated: Use specific exception classes from mem0.exceptions instead. This class is maintained for backward compatibility. """ pass def _handle_http_error(e): logger.error(f"HTTP error occurred: {e}") response_text = "" error_details = {} debug_info = { "status_code": e.response.status_code, "url": str(e.request.url), "method": e.request.method, } try: response_text = e.response.text if e.response.headers.get("content-type", "").startswith("application/json"): error_data = json.loads(response_text) if isinstance(error_data, dict): error_details = error_data response_text = error_data.get("detail", response_text) except (json.JSONDecodeError, AttributeError): pass if e.response.status_code == 429: retry_after = e.response.headers.get("Retry-After") if retry_after: try: debug_info["retry_after"] = int(retry_after) except ValueError: pass for header in ["X-RateLimit-Limit", "X-RateLimit-Remaining", "X-RateLimit-Reset"]: value = e.response.headers.get(header) if value: debug_info[header.lower().replace("-", "_")] = value raise create_exception_from_response( status_code=e.response.status_code, response_text=response_text, details=error_details, debug_info=debug_info, ) def _handle_request_error(e): logger.error(f"Request error occurred: {e}") if isinstance(e, httpx.TimeoutException): raise NetworkError( message=f"Request timed out: {str(e)}", error_code="NET_TIMEOUT", suggestion="Please check your internet connection and try again", debug_info={"error_type": "timeout", "original_error": str(e)}, ) elif isinstance(e, httpx.ConnectError): raise NetworkError( message=f"Connection failed: {str(e)}", error_code="NET_CONNECT", suggestion="Please check your internet connection and try again", debug_info={"error_type": "connection", "original_error": str(e)}, ) else: raise NetworkError( message=f"Network request failed: {str(e)}", error_code="NET_GENERIC", suggestion="Please check your internet connection and try again", debug_info={"error_type": "request", "original_error": str(e)}, ) def api_error_handler(func): """Decorator to handle API errors consistently. This decorator catches HTTP and request errors and converts them to appropriate structured exception classes with detailed error information. Supports both sync and async functions. """ if inspect.iscoroutinefunction(func): @wraps(func) async def async_wrapper(*args, **kwargs): try: return await func(*args, **kwargs) except httpx.HTTPStatusError as e: _handle_http_error(e) raise except httpx.RequestError as e: _handle_request_error(e) raise return async_wrapper else: @wraps(func) def wrapper(*args, **kwargs): try: return func(*args, **kwargs) except httpx.HTTPStatusError as e: _handle_http_error(e) raise except httpx.RequestError as e: _handle_request_error(e) raise return wrapper