hxf/backend/th_agenter/utils/exceptions.py

170 lines
4.7 KiB
Python

"""Custom exceptions and error handlers for the chat agent application."""
from typing import Any, Dict, Optional
from fastapi import HTTPException, Request
from fastapi.responses import JSONResponse
from starlette.status import (
HTTP_400_BAD_REQUEST,
HTTP_401_UNAUTHORIZED,
HTTP_403_FORBIDDEN,
HTTP_404_NOT_FOUND,
HTTP_422_UNPROCESSABLE_ENTITY,
HTTP_500_INTERNAL_SERVER_ERROR,
)
from .logger import get_logger
logger = get_logger("exceptions")
class ChatAgentException(Exception):
"""Base exception for chat agent application."""
def __init__(
self,
message: str,
status_code: int = HTTP_500_INTERNAL_SERVER_ERROR,
details: Optional[Dict[str, Any]] = None
):
self.message = message
self.status_code = status_code
self.details = details or {}
super().__init__(self.message)
class ValidationError(ChatAgentException):
"""Validation error exception."""
def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):
super().__init__(message, HTTP_422_UNPROCESSABLE_ENTITY, details)
class AuthenticationError(ChatAgentException):
"""Authentication error exception."""
def __init__(self, message: str = "Authentication failed"):
super().__init__(message, HTTP_401_UNAUTHORIZED)
class AuthorizationError(ChatAgentException):
"""Authorization error exception."""
def __init__(self, message: str = "Access denied"):
super().__init__(message, HTTP_403_FORBIDDEN)
class NotFoundError(ChatAgentException):
"""Resource not found exception."""
def __init__(self, message: str = "Resource not found"):
super().__init__(message, HTTP_404_NOT_FOUND)
class ConversationNotFoundError(NotFoundError):
"""Conversation not found exception."""
def __init__(self, conversation_id: str):
super().__init__(f"Conversation with ID {conversation_id} not found")
class UserNotFoundError(NotFoundError):
"""User not found exception."""
def __init__(self, user_id: str):
super().__init__(f"User with ID {user_id} not found")
class ChatServiceError(ChatAgentException):
"""Chat service error exception."""
def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):
super().__init__(message, HTTP_500_INTERNAL_SERVER_ERROR, details)
class OpenAIError(ChatServiceError):
"""OpenAI API error exception."""
def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):
super().__init__(f"OpenAI API error: {message}", details)
class RateLimitError(ChatAgentException):
"""Rate limit exceeded error."""
pass
class DatabaseError(ChatAgentException):
"""Database operation error exception."""
def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):
super().__init__(f"Database error: {message}", details)
# Error handlers
async def chat_agent_exception_handler(request: Request, exc: ChatAgentException) -> JSONResponse:
"""Handle ChatAgentException and its subclasses."""
logger.error(
f"ChatAgentException: {exc.message}",
extra={
"status_code": exc.status_code,
"details": exc.details,
"path": request.url.path,
"method": request.method
}
)
return JSONResponse(
status_code=exc.status_code,
content={
"error": {
"message": exc.message,
"type": exc.__class__.__name__,
"details": exc.details
}
}
)
async def http_exception_handler(request: Request, exc: HTTPException) -> JSONResponse:
"""Handle HTTPException."""
logger.warning(
f"HTTPException: {exc.detail}",
extra={
"status_code": exc.status_code,
"path": request.url.path,
"method": request.method
}
)
return JSONResponse(
status_code=exc.status_code,
content={
"error": {
"message": exc.detail,
"type": "HTTPException"
}
}
)
async def general_exception_handler(request: Request, exc: Exception) -> JSONResponse:
"""Handle general exceptions."""
logger.error(
f"Unhandled exception: {str(exc)}",
extra={
"exception_type": exc.__class__.__name__,
"path": request.url.path,
"method": request.method
},
exc_info=True
)
return JSONResponse(
status_code=HTTP_500_INTERNAL_SERVER_ERROR,
content={
"error": {
"message": "Internal server error",
"type": "InternalServerError"
}
}
)