1212# limitations under the License.
1313# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
1414
15+ import ast
1516import json
1617import re
1718
1819
20+ def _parse_dict (text : str ) -> dict | None :
21+ """Parse a dict string (JSON double-quotes or Python single-quotes)."""
22+ for loader in (json .loads , ast .literal_eval ):
23+ try :
24+ result = loader (text )
25+ if isinstance (result , dict ):
26+ return result
27+ except Exception : # nosec B112
28+ continue
29+ return None
30+
31+
32+ def _extract_from_dict (d : dict ) -> tuple [str | None , str | None , dict ]:
33+ """Pull message / code / error_obj from an OpenAI-shaped dict."""
34+ err = d .get ("error" ) or d
35+ if not isinstance (err , dict ):
36+ return None , None , {}
37+ error_obj = {
38+ "message" : err .get ("message" ),
39+ "type" : err .get ("type" ),
40+ "param" : err .get ("param" ),
41+ "code" : err .get ("code" ),
42+ }
43+ return err .get ("message" ), err .get ("code" ), error_obj
44+
45+
1946def normalize_error_to_openai_format (
2047 exception : Exception ,
2148) -> tuple [str , str | None , dict | None ]:
@@ -29,76 +56,50 @@ def normalize_error_to_openai_format(
2956 tuple: (message, error_code, error_object)
3057 """
3158 raw_msg = str (exception )
32- error_obj = None
33- error_code = None
34- message = raw_msg
3559
36- # Match "Error code: <code> - {json}"
60+ # 1) Structured attributes (OpenAI SDK exceptions expose .body)
61+ body = getattr (exception , "body" , None )
62+ if isinstance (body , dict ):
63+ msg , code , obj = _extract_from_dict (body )
64+ if msg :
65+ return msg , code , obj
66+
67+ # 2) Parse "Error code: <status> - {dict}" from str(exception)
3768 m = re .search (r"Error code:\s*(\d+)\s*-\s*(\{.*\})" , raw_msg , re .DOTALL )
3869 if m :
39- error_code = m .group (1 )
40- try :
41- parsed = json .loads (m .group (2 ))
42- err = parsed .get ("error" ) or parsed
43- if isinstance (err , dict ):
44- error_obj = {
45- "message" : err .get ("message" ),
46- "type" : err .get ("type" ),
47- "param" : err .get ("param" ),
48- "code" : err .get ("code" ),
49- }
50- if err .get ("message" ):
51- message = err .get ("message" )
52- if err .get ("code" ):
53- error_code = err .get ("code" )
54- except Exception :
55- pass
70+ parsed = _parse_dict (m .group (2 ))
71+ if parsed :
72+ msg , code , obj = _extract_from_dict (parsed )
73+ if msg :
74+ return msg , code or m .group (1 ), obj
5675
57- # Heuristics if not parsed
58- if error_obj is None :
59- lower = raw_msg .lower ()
60- if (
61- "invalid_api_key" in lower
62- or "incorrect api key" in lower
63- or "unauthorized" in lower
64- or " 401" in lower
65- ):
66- error_code = "invalid_api_key"
67- message = "Invalid key. Validation failed."
68- error_obj = {
69- "message" : message ,
70- "type" : "invalid_request_error" ,
71- "param" : None ,
72- "code" : "invalid_api_key" ,
73- }
74- elif (
75- "model_not_found" in lower
76- or "does not exist" in lower
77- or " 404" in lower
78- ):
79- error_code = "model_not_found"
80- message = "Invalid model name. Validation failed."
81- error_obj = {
82- "message" : message ,
83- "type" : "invalid_request_error" ,
84- "param" : None ,
85- "code" : "model_not_found" ,
86- }
87- elif (
88- "insufficient_quota" in lower
89- or "quota" in lower
90- or " 429" in lower
91- ):
92- error_code = "insufficient_quota"
93- message = (
94- "You exceeded your current quota, "
95- "please check your plan and billing details."
96- )
97- error_obj = {
98- "message" : message ,
99- "type" : "insufficient_quota" ,
100- "param" : None ,
101- "code" : "insufficient_quota" ,
102- }
76+ # 3) Keyword heuristics — classify the error but preserve original text
77+ lower = raw_msg .lower ()
78+ if (
79+ "invalid_api_key" in lower
80+ or "incorrect api key" in lower
81+ or "unauthorized" in lower
82+ or " 401" in lower
83+ ):
84+ code = "invalid_api_key"
85+ elif (
86+ "model_not_found" in lower
87+ or "does not exist" in lower
88+ or " 404" in lower
89+ ):
90+ code = "model_not_found"
91+ elif "insufficient_quota" in lower or "quota" in lower or " 429" in lower :
92+ code = "insufficient_quota"
93+ else :
94+ return raw_msg , None , None
10395
104- return message , error_code , error_obj
96+ return (
97+ raw_msg ,
98+ code ,
99+ {
100+ "message" : raw_msg ,
101+ "type" : "invalid_request_error" ,
102+ "param" : None ,
103+ "code" : code ,
104+ },
105+ )
0 commit comments