# --- Raw Dictionary Models for Alexa Skill Error Responses --- from typing import List, Optional, Literal, Any, Dict import uuid # --- General Errors (Alexa Namespace, v3.0 Payload) --- def build_alexa_error_response( request_message_id: Optional[str], error_type: Literal[ "ACCOUNT_PROBLEM", "EXPIRED_AUTHORIZATION_CREDENTIAL", "INTERNAL_ERROR", "INVALID_AUTHORIZATION_CREDENTIAL", "INVALID_DIRECTIVE", "RATE_LIMIT_EXCEEDED", ], message: str, ) -> Dict[str, Any]: """Builds a general Alexa ErrorResponse dictionary.""" response = { "header": { "messageId": request_message_id or str(uuid.uuid4()), "namespace": "Alexa", "name": "ErrorResponse", "payloadVersion": "3.0" }, "payload": { "type": error_type, "message": message } } return response # --- Media-Specific Errors (Alexa.Media Namespace, v1.0 Payload) --- def build_media_error_response( request_message_id: Optional[str], error_type: Literal[ "CONTENT_FILTERED", "INSUFFICIENT_USER_SUBSCRIPTION", "INVALID_ITEM", "ITEM_NOT_FOUND", "CRITERIA_NOT_FOUND", "CONTENT_NOT_FOUND", "GEOGRAPHICAL_RESTRICTION_ERROR", "DEVICE_LIMIT_REACHED", "USER_CONTEXT_MISMATCH", ], message: Optional[str] = None, subtypes: Optional[ List[ Literal["EXPLICIT_LANGUAGE_FILTER", "NO_FOLLOWED_CONTENT", "NO_NEW_CONTENT"] ] ] = None, ) -> Dict[str, Any]: """Builds an Alexa.Media ErrorResponse dictionary.""" payload = { "type": error_type, } if message: payload["message"] = message if subtypes: payload["subtypes"] = subtypes response = { "header": { "messageId": request_message_id or str(uuid.uuid4()), "namespace": "Alexa.Media", "name": "ErrorResponse", "payloadVersion": "1.0" }, "payload": payload } return response # --- Audio-Specific Errors (Alexa.Audio Namespace, v1.0 Payload) --- def build_audio_error_response( request_message_id: Optional[str], message: Optional[str] = None, retry_period: Optional[Literal["HOURLY", "DAILY", "UNKNOWN"]] = None, ) -> Dict[str, Any]: """Builds an Alexa.Audio ErrorResponse dictionary (for SKIP_LIMIT_REACHED).""" payload = { "type": "SKIP_LIMIT_REACHED", } if message: payload["message"] = message if retry_period: payload["retryPeriod"] = retry_period response = { "header": { "messageId": request_message_id or str(uuid.uuid4()), "namespace": "Alexa.Audio", "name": "ErrorResponse", "payloadVersion": "1.0" }, "payload": payload } return response # --- Example Custom Exceptions (Good Practice) --- class SkillError(Exception): """Base class for skill-specific errors.""" def __init__( self, message="An error occurred in the skill.", error_code=None, subtypes=None, retry_period=None, ): super().__init__(message) self.message = message self.error_code = error_code self.subtypes = subtypes self.retry_period = retry_period class AuthorizationError(SkillError): """Errors related to user authentication or authorization.""" pass class AccountProblemError(SkillError): """Errors related to the user's service account status.""" pass class ContentNotFoundError(SkillError): """Errors when requested content/item/criteria cannot be found.""" pass class ContentFilteredError(SkillError): """Errors when content is filtered (e.g., ELF).""" def __init__(self, message="Content filtered.", subtypes=None): super().__init__( message, error_code="CONTENT_FILTERED", subtypes=subtypes, ) class InvalidRequestError(SkillError): """Errors for malformed or unsupported requests.""" pass class RateLimitError(SkillError): """Errors when user exceeds rate limits.""" pass class DeviceLimitError(SkillError): """Errors when device streaming limit is reached.""" pass class GeoRestrictionError(SkillError): """Errors due to geographical restrictions.""" pass class SkipLimitError(SkillError): """Errors when skip limit is reached.""" pass class UserContextMismatchError(SkillError): """Error for Reinitiate context mismatch.""" pass