from __future__ import annotations from enum import StrEnum class FeishuErrorCategory(StrEnum): RATE_LIMIT = "rate_limit" AUTH = "auth" TRANSIENT = "transient" PERMANENT = "permanent" NOT_FOUND = "not_found" VALIDATION = "validation" class FeishuError(Exception): def __init__(self, message: str, *, code: int = 0, category: str = "transient"): super().__init__(message) self.code = code self.category = category class FeishuAuthError(FeishuError): def __init__(self, message: str, *, code: int = 0): super().__init__(message, code=code, category="auth") class FeishuRateLimitError(FeishuError): def __init__(self, message: str = "Rate limited", *, code: int = 99991400): super().__init__(message, code=code, category="rate_limit") class FeishuConnectionError(FeishuError): def __init__(self, message: str, *, code: int = 0): super().__init__(message, code=code, category="transient") def classify_feishu_error(code: int, msg: str = "") -> FeishuError: if code in (99991400,): return FeishuRateLimitError(msg or "Rate limited", code=code) if code in (99991403,): return FeishuRateLimitError(msg or "Quota exceeded", code=code) if code in (99991663, 99991664, 99991665): return FeishuAuthError(msg or "Authentication failed", code=code) if code in (230011, 231003): return FeishuError(msg or "Reply target not found", code=code, category="transient") if code in (0,): return FeishuError(msg, code=code, category="transient") return FeishuError(msg or f"Feishu API error {code}", code=code, category="permanent") RETRYABLE_CODES = frozenset({ 99991400, 99991403, 230011, 231003, }) AUTH_ERROR_CODES = frozenset({ 99991663, 99991664, 99991665, })