-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy patherrors.py
More file actions
123 lines (112 loc) · 4.41 KB
/
Copy patherrors.py
File metadata and controls
123 lines (112 loc) · 4.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import json
from dataclasses import dataclass
from mlpa.core.config import (
ERROR_CODE_BUDGET_LIMIT_EXCEEDED,
ERROR_CODE_INVALID_MODEL_NAME,
ERROR_CODE_INVALID_REQUEST,
ERROR_CODE_RATE_LIMIT_EXCEEDED,
ERROR_CODE_REQUEST_TOO_LARGE,
ERROR_CODE_UPSTREAM_RATE_LIMIT_EXCEEDED,
)
from mlpa.core.prometheus_metrics import AvailabilityReason, PrometheusRejectionReason
from mlpa.core.utils import (
is_context_window_error,
is_invalid_model_name_error,
is_invalid_request_error,
is_litellm_upstream_rate_limit,
is_rate_limit_error,
)
_REJECTION_TO_AVAILABILITY_REASON: dict[
PrometheusRejectionReason, AvailabilityReason
] = {
PrometheusRejectionReason.BUDGET_EXCEEDED: AvailabilityReason.BUDGET_EXCEEDED,
PrometheusRejectionReason.PAYLOAD_TOO_LARGE: AvailabilityReason.PAYLOAD_TOO_LARGE,
PrometheusRejectionReason.INVALID_MODEL_NAME: AvailabilityReason.INVALID_MODEL_NAME,
PrometheusRejectionReason.INVALID_REQUEST: AvailabilityReason.INVALID_REQUEST,
}
@dataclass(frozen=True)
class RejectionMatch:
reason: PrometheusRejectionReason
error_code: int
http_status: int
retry_after: str | None = None
log_message: str = ""
def availability_reason(self) -> AvailabilityReason:
# SIGNUP_CAP_EXCEEDED is recorded pre-completion, not via classify_upstream_error,
# so it is not in the mapping below.
if self.reason == PrometheusRejectionReason.RATE_LIMITED:
if self.error_code == ERROR_CODE_UPSTREAM_RATE_LIMIT_EXCEEDED:
return AvailabilityReason.RATE_LIMITED_UPSTREAM
return AvailabilityReason.RATE_LIMITED_PLATFORM
return _REJECTION_TO_AVAILABILITY_REASON[self.reason]
_RATE_LIMIT_REJECTION: dict[int, tuple[PrometheusRejectionReason, str, str]] = {
ERROR_CODE_BUDGET_LIMIT_EXCEEDED: (
PrometheusRejectionReason.BUDGET_EXCEEDED,
"86400",
"Budget limit exceeded",
),
ERROR_CODE_RATE_LIMIT_EXCEEDED: (
PrometheusRejectionReason.RATE_LIMITED,
"60",
"Rate limit exceeded",
),
ERROR_CODE_UPSTREAM_RATE_LIMIT_EXCEEDED: (
PrometheusRejectionReason.RATE_LIMITED,
"60",
"Upstream rate limit exceeded",
),
}
def _parse_rate_limit_error(error_text: str) -> int | None:
if not error_text:
return None
try:
error_data = json.loads(error_text)
if is_rate_limit_error(error_data, ["budget"]):
return ERROR_CODE_BUDGET_LIMIT_EXCEEDED
if is_rate_limit_error(error_data, ["rate"]):
return ERROR_CODE_RATE_LIMIT_EXCEEDED
except (json.JSONDecodeError, AttributeError, UnicodeDecodeError):
pass
if is_litellm_upstream_rate_limit(error_text):
return ERROR_CODE_UPSTREAM_RATE_LIMIT_EXCEEDED
return None
def classify_upstream_error(
*,
error_text: str,
status_code: int,
user: str,
) -> RejectionMatch | None:
if status_code in {400, 429}:
error_code = _parse_rate_limit_error(error_text)
if error_code is not None and error_code in _RATE_LIMIT_REJECTION:
reason, retry_after, log_prefix = _RATE_LIMIT_REJECTION[error_code]
return RejectionMatch(
reason=reason,
error_code=error_code,
http_status=429,
retry_after=retry_after,
log_message=f"{log_prefix} for user {user}: {error_text}",
)
if status_code == 413 or is_context_window_error(error_text):
return RejectionMatch(
reason=PrometheusRejectionReason.PAYLOAD_TOO_LARGE,
error_code=ERROR_CODE_REQUEST_TOO_LARGE,
http_status=413,
log_message=f"Context window exceeded for user {user}: {error_text}",
)
if status_code == 400:
if is_invalid_model_name_error(error_text):
return RejectionMatch(
reason=PrometheusRejectionReason.INVALID_MODEL_NAME,
error_code=ERROR_CODE_INVALID_MODEL_NAME,
http_status=400,
log_message=f"Invalid model name for user {user}: {error_text}",
)
if is_invalid_request_error(error_text):
return RejectionMatch(
reason=PrometheusRejectionReason.INVALID_REQUEST,
error_code=ERROR_CODE_INVALID_REQUEST,
http_status=400,
log_message=f"Invalid request for user {user}: {error_text}",
)
return None