11import logging
22
33from collections .abc import AsyncGenerator , Callable
4+ from functools import wraps
5+ from typing import Any , NoReturn
6+
7+ import a2a .utils .errors
8+
9+ from a2a .client .errors import A2AClientError
410
511
612try :
4349logger = logging .getLogger (__name__ )
4450
4551
52+ def _map_grpc_error (e : grpc .aio .AioRpcError ) -> NoReturn :
53+ details = e .details ()
54+ if isinstance (details , str ) and ': ' in details :
55+ error_type_name , error_message = details .split (': ' , 1 )
56+ exception_cls = getattr (a2a .utils .errors , error_type_name , None )
57+ if (
58+ exception_cls
59+ and isinstance (exception_cls , type )
60+ and issubclass (exception_cls , a2a .utils .errors .A2AError )
61+ ):
62+ raise exception_cls (error_message ) from e
63+ raise A2AClientError (f'gRPC Error { e .code ().name } : { e .details ()} ' ) from e
64+
65+ def _handle_grpc_exception (func : Callable [..., Any ]) -> Callable [..., Any ]:
66+ @wraps (func )
67+ async def wrapper (* args : Any , ** kwargs : Any ) -> Any :
68+ try :
69+ return await func (* args , ** kwargs )
70+ except grpc .aio .AioRpcError as e :
71+ _map_grpc_error (e )
72+ return wrapper
73+
74+ def _handle_grpc_stream_exception (func : Callable [..., Any ]) -> Callable [..., Any ]:
75+ @wraps (func )
76+ async def wrapper (* args : Any , ** kwargs : Any ) -> Any :
77+ try :
78+ async for item in func (* args , ** kwargs ):
79+ yield item
80+ except grpc .aio .AioRpcError as e :
81+ _map_grpc_error (e )
82+ return wrapper
83+
84+
4685@trace_class (kind = SpanKind .CLIENT )
4786class GrpcTransport (ClientTransport ):
4887 """A gRPC transport for the A2A client."""
@@ -87,6 +126,7 @@ def create(
87126 raise ValueError ('grpc_channel_factory is required when using gRPC' )
88127 return cls (config .grpc_channel_factory (url ), card , config .extensions )
89128
129+ @_handle_grpc_exception
90130 async def send_message (
91131 self ,
92132 request : SendMessageRequest ,
@@ -100,6 +140,7 @@ async def send_message(
100140 metadata = self ._get_grpc_metadata (extensions ),
101141 )
102142
143+ @_handle_grpc_stream_exception
103144 async def send_message_streaming (
104145 self ,
105146 request : SendMessageRequest ,
@@ -118,6 +159,7 @@ async def send_message_streaming(
118159 break
119160 yield response
120161
162+ @_handle_grpc_stream_exception
121163 async def subscribe (
122164 self ,
123165 request : SubscribeToTaskRequest ,
@@ -136,6 +178,7 @@ async def subscribe(
136178 break
137179 yield response
138180
181+ @_handle_grpc_exception
139182 async def get_task (
140183 self ,
141184 request : GetTaskRequest ,
@@ -149,6 +192,7 @@ async def get_task(
149192 metadata = self ._get_grpc_metadata (extensions ),
150193 )
151194
195+ @_handle_grpc_exception
152196 async def list_tasks (
153197 self ,
154198 request : ListTasksRequest ,
@@ -162,6 +206,7 @@ async def list_tasks(
162206 metadata = self ._get_grpc_metadata (extensions ),
163207 )
164208
209+ @_handle_grpc_exception
165210 async def cancel_task (
166211 self ,
167212 request : CancelTaskRequest ,
@@ -175,6 +220,7 @@ async def cancel_task(
175220 metadata = self ._get_grpc_metadata (extensions ),
176221 )
177222
223+ @_handle_grpc_exception
178224 async def create_task_push_notification_config (
179225 self ,
180226 request : CreateTaskPushNotificationConfigRequest ,
@@ -188,6 +234,7 @@ async def create_task_push_notification_config(
188234 metadata = self ._get_grpc_metadata (extensions ),
189235 )
190236
237+ @_handle_grpc_exception
191238 async def get_task_push_notification_config (
192239 self ,
193240 request : GetTaskPushNotificationConfigRequest ,
@@ -201,6 +248,7 @@ async def get_task_push_notification_config(
201248 metadata = self ._get_grpc_metadata (extensions ),
202249 )
203250
251+ @_handle_grpc_exception
204252 async def list_task_push_notification_configs (
205253 self ,
206254 request : ListTaskPushNotificationConfigsRequest ,
@@ -214,6 +262,7 @@ async def list_task_push_notification_configs(
214262 metadata = self ._get_grpc_metadata (extensions ),
215263 )
216264
265+ @_handle_grpc_exception
217266 async def delete_task_push_notification_config (
218267 self ,
219268 request : DeleteTaskPushNotificationConfigRequest ,
@@ -227,6 +276,7 @@ async def delete_task_push_notification_config(
227276 metadata = self ._get_grpc_metadata (extensions ),
228277 )
229278
279+ @_handle_grpc_exception
230280 async def get_extended_agent_card (
231281 self ,
232282 * ,
0 commit comments