main
py 100 lines 2.79 KB
Raw
1 from __future__ import annotations
2
3 import re
4
5
6 MAX_DETAIL_CHARS = 500
7
8
9 def friendly_error_message(exception: BaseException) -> str:
10 summary = _error_summary(exception)
11 category = _classify_error(exception, summary)
12
13 if category == "auth":
14 return (
15 "**Agent Zero hit a provider setup issue.**\n\n"
16 "The model provider rejected the request because an API key or credential is missing, invalid, or unauthorized.\n\n"
17 f"Details: `{summary}`\n\n"
18 "Please check the model/API key settings, then send the message again."
19 )
20
21 if category == "rate_limit":
22 return (
23 "**Agent Zero was rate limited by the model provider.**\n\n"
24 "The provider is asking us to slow down before trying again.\n\n"
25 f"Details: `{summary}`"
26 )
27
28 if category == "timeout":
29 return (
30 "**Agent Zero did not get a response in time.**\n\n"
31 "The provider or tool call timed out before the agent could finish this request.\n\n"
32 f"Details: `{summary}`"
33 )
34
35 if category == "provider":
36 return (
37 "**Agent Zero could not complete the model request.**\n\n"
38 "The model provider returned an error before the agent could finish.\n\n"
39 f"Details: `{summary}`"
40 )
41
42 return (
43 "**Agent Zero ran into an error while working on this.**\n\n"
44 f"Details: `{summary}`"
45 )
46
47
48 def _classify_error(exception: BaseException, summary: str) -> str:
49 text = f"{type(exception).__name__} {summary}".lower()
50
51 if any(
52 marker in text
53 for marker in (
54 "api key",
55 "api_key",
56 "apikey",
57 "auth",
58 "credential",
59 "unauthorized",
60 "forbidden",
61 "invalid key",
62 "missing key",
63 "permission denied",
64 "401",
65 "403",
66 )
67 ):
68 return "auth"
69
70 if any(marker in text for marker in ("rate limit", "ratelimit", "too many requests", "429")):
71 return "rate_limit"
72
73 if any(marker in text for marker in ("timeout", "timed out", "deadline", "read timed out")):
74 return "timeout"
75
76 if any(
77 marker in text
78 for marker in (
79 "litellm",
80 "openai",
81 "anthropic",
82 "model",
83 "provider",
84 "badrequest",
85 "service unavailable",
86 "overloaded",
87 "503",
88 )
89 ):
90 return "provider"
91
92 return "generic"
93
94
95 def _error_summary(exception: BaseException) -> str:
96 text = str(exception).strip() or type(exception).__name__
97 text = re.sub(r"\s+", " ", text)
98 if len(text) > MAX_DETAIL_CHARS:
99 text = f"{text[: MAX_DETAIL_CHARS - 3].rstrip()}..."
100 return text