ForcePilot/backend/package/yuxi/channels/sdk/error_classifier.py
Kris f8a985aad8 feat(channels): 新增会话路由、错误分类与聊天能力支持
1. 新增ChannelStreamingProtocol协议的打字指示器、消息编辑支持和 fallback 发送方法
2. 重构SDK导入顺序,调整normalizer和retry的导入位置
3. 新增错误分类模块,实现异常类型归类逻辑
4. 新增SessionRouter抽象基类,实现基础会话路由逻辑
5. 增强重试SDK,添加总超时、熔断和指标回调支持
2026-05-13 16:20:54 +08:00

53 lines
1.5 KiB
Python

from __future__ import annotations
from enum import StrEnum
from yuxi.channels.exceptions import (
ChannelAuthenticationError,
ChannelException,
ChannelNotConnectedError,
ChannelRateLimitError,
ChannelTimeoutError,
MessageTooLargeError,
TokenExpiredError,
)
class ErrorCategory(StrEnum):
TRANSIENT = "transient"
PERMANENT = "permanent"
RATE_LIMIT = "rate_limit"
AUTH_EXPIRED = "auth_expired"
CIRCUIT_OPEN = "circuit_open"
TIMEOUT = "timeout"
_ERROR_CATEGORY_MAP: dict[type[Exception], ErrorCategory] = {
ChannelNotConnectedError: ErrorCategory.TRANSIENT,
ChannelRateLimitError: ErrorCategory.RATE_LIMIT,
TokenExpiredError: ErrorCategory.AUTH_EXPIRED,
ChannelAuthenticationError: ErrorCategory.PERMANENT,
ChannelTimeoutError: ErrorCategory.TIMEOUT,
MessageTooLargeError: ErrorCategory.PERMANENT,
TimeoutError: ErrorCategory.TIMEOUT,
}
def classify_error(error: Exception) -> ErrorCategory:
error_type = type(error)
if error_type in _ERROR_CATEGORY_MAP:
return _ERROR_CATEGORY_MAP[error_type]
try:
from yuxi.channels.infra.circuit_breaker import CircuitBreakerOpenError
if isinstance(error, CircuitBreakerOpenError):
return ErrorCategory.CIRCUIT_OPEN
except ImportError:
pass
if isinstance(error, ChannelException):
return ErrorCategory.TRANSIENT if error.retryable else ErrorCategory.PERMANENT
return ErrorCategory.TRANSIENT