77import httpx
88from a2a .types import TaskState
99
10+ from ..error_taxonomy import (
11+ extract_upstream_error_detail as _extract_upstream_error_detail ,
12+ )
13+ from ..error_taxonomy import (
14+ resolve_upstream_http_error_profile as _resolve_upstream_error_profile ,
15+ )
1016from ..opencode_upstream_client import UpstreamContractError
1117
1218
@@ -18,13 +24,6 @@ class _StreamTerminalSignal:
1824 upstream_status : int | None = None
1925
2026
21- @dataclass (frozen = True )
22- class _UpstreamErrorProfile :
23- error_type : str
24- state : TaskState
25- default_message : str
26-
27-
2827@dataclass (frozen = True )
2928class _UpstreamInBandError :
3029 error_type : str
@@ -33,81 +32,6 @@ class _UpstreamInBandError:
3332 upstream_status : int | None = None
3433
3534
36- _UPSTREAM_HTTP_ERROR_PROFILE_BY_STATUS : dict [int , _UpstreamErrorProfile ] = {
37- 400 : _UpstreamErrorProfile (
38- "UPSTREAM_BAD_REQUEST" ,
39- TaskState .failed ,
40- "OpenCode rejected the request due to invalid input" ,
41- ),
42- 401 : _UpstreamErrorProfile (
43- "UPSTREAM_UNAUTHORIZED" ,
44- TaskState .auth_required ,
45- "OpenCode rejected the request due to authentication failure" ,
46- ),
47- 403 : _UpstreamErrorProfile (
48- "UPSTREAM_PERMISSION_DENIED" ,
49- TaskState .failed ,
50- "OpenCode rejected the request due to insufficient permissions" ,
51- ),
52- 404 : _UpstreamErrorProfile (
53- "UPSTREAM_RESOURCE_NOT_FOUND" ,
54- TaskState .failed ,
55- "OpenCode rejected the request because the target resource was not found" ,
56- ),
57- 429 : _UpstreamErrorProfile (
58- "UPSTREAM_QUOTA_EXCEEDED" ,
59- TaskState .failed ,
60- "OpenCode rejected the request due to quota limits" ,
61- ),
62- }
63-
64-
65- def _resolve_upstream_error_profile (status : int ) -> _UpstreamErrorProfile :
66- if status in _UPSTREAM_HTTP_ERROR_PROFILE_BY_STATUS :
67- return _UPSTREAM_HTTP_ERROR_PROFILE_BY_STATUS [status ]
68- if 400 <= status < 500 :
69- return _UpstreamErrorProfile (
70- "UPSTREAM_CLIENT_ERROR" ,
71- TaskState .failed ,
72- f"OpenCode rejected the request with client error { status } " ,
73- )
74- if status >= 500 :
75- return _UpstreamErrorProfile (
76- "UPSTREAM_SERVER_ERROR" ,
77- TaskState .failed ,
78- f"OpenCode rejected the request with server error { status } " ,
79- )
80- return _UpstreamErrorProfile (
81- "UPSTREAM_HTTP_ERROR" ,
82- TaskState .failed ,
83- f"OpenCode rejected the request with HTTP status { status } " ,
84- )
85-
86-
87- def _extract_upstream_error_detail (response : httpx .Response | None ) -> str | None :
88- if response is None :
89- return None
90-
91- payload = None
92- try :
93- payload = response .json ()
94- except Exception :
95- payload = None
96-
97- if isinstance (payload , dict ):
98- for key in ("detail" , "error" , "message" ):
99- value = payload .get (key )
100- if isinstance (value , str ):
101- value = value .strip ()
102- if value :
103- return value
104-
105- text = response .text .strip ()
106- if text :
107- return text [:512 ]
108- return None
109-
110-
11135def _format_upstream_error (
11236 exc : httpx .HTTPStatusError , * , request : str
11337) -> tuple [str , TaskState , str ]:
0 commit comments