Files
Aether/_deprecated_py_src/services/usage/error_classifier.py

71 lines
2.0 KiB
Python
Raw Normal View History

"""Error classification helpers for Usage records."""
from __future__ import annotations
from src.core.enums import ErrorCategory
_STATUS_CODE_MAP: dict[int, ErrorCategory] = {
400: ErrorCategory.INVALID_REQUEST,
401: ErrorCategory.AUTH,
403: ErrorCategory.AUTH,
404: ErrorCategory.NOT_FOUND,
408: ErrorCategory.TIMEOUT,
429: ErrorCategory.RATE_LIMIT,
500: ErrorCategory.SERVER_ERROR,
502: ErrorCategory.SERVER_ERROR,
503: ErrorCategory.SERVER_ERROR,
504: ErrorCategory.TIMEOUT,
}
_CONTEXT_LENGTH_PATTERNS = (
"context_length_exceeded",
"maximum context length",
"too many tokens",
"input is too long",
)
_CONTENT_FILTER_PATTERNS = (
"content_filter",
"content_policy",
"safety_block",
"blocked by content",
)
_NETWORK_PATTERNS = ("connection", "network", "dns", "socket")
def classify_error(
status_code: int | None,
error_message: str | None,
status: str | None = None,
) -> ErrorCategory:
"""Map provider errors to ErrorCategory."""
if status and status.lower() == "cancelled":
return ErrorCategory.CANCELLED
if status_code is not None:
mapped = _STATUS_CODE_MAP.get(status_code)
if mapped:
return mapped
if error_message:
msg_lower = error_message.lower()
if any(p in msg_lower for p in _CONTEXT_LENGTH_PATTERNS):
return ErrorCategory.CONTEXT_LENGTH
if any(p in msg_lower for p in _CONTENT_FILTER_PATTERNS):
return ErrorCategory.CONTENT_FILTER
if "rate limit" in msg_lower or "rate_limit" in msg_lower:
return ErrorCategory.RATE_LIMIT
if "timeout" in msg_lower or "timed out" in msg_lower:
return ErrorCategory.TIMEOUT
if any(p in msg_lower for p in _NETWORK_PATTERNS):
return ErrorCategory.NETWORK
if status_code is not None:
if status_code >= 500:
return ErrorCategory.SERVER_ERROR
if status_code >= 400:
return ErrorCategory.INVALID_REQUEST
return ErrorCategory.UNKNOWN