Skip to content

Commit 041f0f5

Browse files
authored
feat: implement missing push notifications related methods (#711)
Covers bullets 1-4 from #702.
1 parent f0d4669 commit 041f0f5

File tree

14 files changed

+699
-19
lines changed

14 files changed

+699
-19
lines changed

src/a2a/client/base_client.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@
1818
AgentCard,
1919
CancelTaskRequest,
2020
CreateTaskPushNotificationConfigRequest,
21+
DeleteTaskPushNotificationConfigRequest,
2122
GetTaskPushNotificationConfigRequest,
2223
GetTaskRequest,
24+
ListTaskPushNotificationConfigsRequest,
25+
ListTaskPushNotificationConfigsResponse,
2326
ListTasksRequest,
2427
ListTasksResponse,
2528
Message,
@@ -247,6 +250,45 @@ async def get_task_callback(
247250
request, context=context, extensions=extensions
248251
)
249252

253+
async def list_task_callback(
254+
self,
255+
request: ListTaskPushNotificationConfigsRequest,
256+
*,
257+
context: ClientCallContext | None = None,
258+
extensions: list[str] | None = None,
259+
) -> ListTaskPushNotificationConfigsResponse:
260+
"""Lists push notification configurations for a specific task.
261+
262+
Args:
263+
request: The `ListTaskPushNotificationConfigsRequest` object specifying the request.
264+
context: The client call context.
265+
extensions: List of extensions to be activated.
266+
267+
Returns:
268+
A `ListTaskPushNotificationConfigsResponse` object.
269+
"""
270+
return await self._transport.list_task_callback(
271+
request, context=context, extensions=extensions
272+
)
273+
274+
async def delete_task_callback(
275+
self,
276+
request: DeleteTaskPushNotificationConfigRequest,
277+
*,
278+
context: ClientCallContext | None = None,
279+
extensions: list[str] | None = None,
280+
) -> None:
281+
"""Deletes the push notification configuration for a specific task.
282+
283+
Args:
284+
request: The `DeleteTaskPushNotificationConfigRequest` object specifying the request.
285+
context: The client call context.
286+
extensions: List of extensions to be activated.
287+
"""
288+
await self._transport.delete_task_callback(
289+
request, context=context, extensions=extensions
290+
)
291+
250292
async def subscribe(
251293
self,
252294
request: SubscribeToTaskRequest,

src/a2a/client/client.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@
1313
AgentCard,
1414
CancelTaskRequest,
1515
CreateTaskPushNotificationConfigRequest,
16+
DeleteTaskPushNotificationConfigRequest,
1617
GetTaskPushNotificationConfigRequest,
1718
GetTaskRequest,
19+
ListTaskPushNotificationConfigsRequest,
20+
ListTaskPushNotificationConfigsResponse,
1821
ListTasksRequest,
1922
ListTasksResponse,
2023
Message,
@@ -177,6 +180,26 @@ async def get_task_callback(
177180
) -> TaskPushNotificationConfig:
178181
"""Retrieves the push notification configuration for a specific task."""
179182

183+
@abstractmethod
184+
async def list_task_callback(
185+
self,
186+
request: ListTaskPushNotificationConfigsRequest,
187+
*,
188+
context: ClientCallContext | None = None,
189+
extensions: list[str] | None = None,
190+
) -> ListTaskPushNotificationConfigsResponse:
191+
"""Lists push notification configurations for a specific task."""
192+
193+
@abstractmethod
194+
async def delete_task_callback(
195+
self,
196+
request: DeleteTaskPushNotificationConfigRequest,
197+
*,
198+
context: ClientCallContext | None = None,
199+
extensions: list[str] | None = None,
200+
) -> None:
201+
"""Deletes the push notification configuration for a specific task."""
202+
180203
@abstractmethod
181204
async def subscribe(
182205
self,

src/a2a/client/transports/base.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@
99
AgentCard,
1010
CancelTaskRequest,
1111
CreateTaskPushNotificationConfigRequest,
12+
DeleteTaskPushNotificationConfigRequest,
1213
GetTaskPushNotificationConfigRequest,
1314
GetTaskRequest,
15+
ListTaskPushNotificationConfigsRequest,
16+
ListTaskPushNotificationConfigsResponse,
1417
ListTasksRequest,
1518
ListTasksResponse,
1619
SendMessageRequest,
@@ -110,6 +113,26 @@ async def get_task_callback(
110113
) -> TaskPushNotificationConfig:
111114
"""Retrieves the push notification configuration for a specific task."""
112115

116+
@abstractmethod
117+
async def list_task_callback(
118+
self,
119+
request: ListTaskPushNotificationConfigsRequest,
120+
*,
121+
context: ClientCallContext | None = None,
122+
extensions: list[str] | None = None,
123+
) -> ListTaskPushNotificationConfigsResponse:
124+
"""Lists push notification configurations for a specific task."""
125+
126+
@abstractmethod
127+
async def delete_task_callback(
128+
self,
129+
request: DeleteTaskPushNotificationConfigRequest,
130+
*,
131+
context: ClientCallContext | None = None,
132+
extensions: list[str] | None = None,
133+
) -> None:
134+
"""Deletes the push notification configuration for a specific task."""
135+
113136
@abstractmethod
114137
async def subscribe(
115138
self,

src/a2a/client/transports/grpc.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,11 @@
2323
AgentCard,
2424
CancelTaskRequest,
2525
CreateTaskPushNotificationConfigRequest,
26+
DeleteTaskPushNotificationConfigRequest,
2627
GetTaskPushNotificationConfigRequest,
2728
GetTaskRequest,
29+
ListTaskPushNotificationConfigsRequest,
30+
ListTaskPushNotificationConfigsResponse,
2831
ListTasksRequest,
2932
ListTasksResponse,
3033
SendMessageRequest,
@@ -198,6 +201,32 @@ async def get_task_callback(
198201
metadata=self._get_grpc_metadata(extensions),
199202
)
200203

204+
async def list_task_callback(
205+
self,
206+
request: ListTaskPushNotificationConfigsRequest,
207+
*,
208+
context: ClientCallContext | None = None,
209+
extensions: list[str] | None = None,
210+
) -> ListTaskPushNotificationConfigsResponse:
211+
"""Lists push notification configurations for a specific task."""
212+
return await self.stub.ListTaskPushNotificationConfigs(
213+
request,
214+
metadata=self._get_grpc_metadata(extensions),
215+
)
216+
217+
async def delete_task_callback(
218+
self,
219+
request: DeleteTaskPushNotificationConfigRequest,
220+
*,
221+
context: ClientCallContext | None = None,
222+
extensions: list[str] | None = None,
223+
) -> None:
224+
"""Deletes the push notification configuration for a specific task."""
225+
await self.stub.DeleteTaskPushNotificationConfig(
226+
request,
227+
metadata=self._get_grpc_metadata(extensions),
228+
)
229+
201230
async def get_extended_agent_card(
202231
self,
203232
*,

src/a2a/client/transports/jsonrpc.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,12 @@
2424
AgentCard,
2525
CancelTaskRequest,
2626
CreateTaskPushNotificationConfigRequest,
27+
DeleteTaskPushNotificationConfigRequest,
2728
GetExtendedAgentCardRequest,
2829
GetTaskPushNotificationConfigRequest,
2930
GetTaskRequest,
31+
ListTaskPushNotificationConfigsRequest,
32+
ListTaskPushNotificationConfigsResponse,
3033
ListTasksRequest,
3134
ListTasksResponse,
3235
SendMessageRequest,
@@ -364,6 +367,69 @@ async def get_task_callback(
364367
)
365368
return response
366369

370+
async def list_task_callback(
371+
self,
372+
request: ListTaskPushNotificationConfigsRequest,
373+
*,
374+
context: ClientCallContext | None = None,
375+
extensions: list[str] | None = None,
376+
) -> ListTaskPushNotificationConfigsResponse:
377+
"""Lists push notification configurations for a specific task."""
378+
rpc_request = JSONRPC20Request(
379+
method='ListTaskPushNotificationConfigs',
380+
params=json_format.MessageToDict(request),
381+
_id=str(uuid4()),
382+
)
383+
modified_kwargs = update_extension_header(
384+
self._get_http_args(context),
385+
extensions if extensions is not None else self.extensions,
386+
)
387+
payload, modified_kwargs = await self._apply_interceptors(
388+
'ListTaskPushNotificationConfigs',
389+
cast('dict[str, Any]', rpc_request.data),
390+
modified_kwargs,
391+
context,
392+
)
393+
response_data = await self._send_request(payload, modified_kwargs)
394+
json_rpc_response = JSONRPC20Response(**response_data)
395+
if json_rpc_response.error:
396+
raise A2AClientJSONRPCError(json_rpc_response.error)
397+
response: ListTaskPushNotificationConfigsResponse = (
398+
json_format.ParseDict(
399+
json_rpc_response.result,
400+
ListTaskPushNotificationConfigsResponse(),
401+
)
402+
)
403+
return response
404+
405+
async def delete_task_callback(
406+
self,
407+
request: DeleteTaskPushNotificationConfigRequest,
408+
*,
409+
context: ClientCallContext | None = None,
410+
extensions: list[str] | None = None,
411+
) -> None:
412+
"""Deletes the push notification configuration for a specific task."""
413+
rpc_request = JSONRPC20Request(
414+
method='DeleteTaskPushNotificationConfig',
415+
params=json_format.MessageToDict(request),
416+
_id=str(uuid4()),
417+
)
418+
modified_kwargs = update_extension_header(
419+
self._get_http_args(context),
420+
extensions if extensions is not None else self.extensions,
421+
)
422+
payload, modified_kwargs = await self._apply_interceptors(
423+
'DeleteTaskPushNotificationConfig',
424+
cast('dict[str, Any]', rpc_request.data),
425+
modified_kwargs,
426+
context,
427+
)
428+
response_data = await self._send_request(payload, modified_kwargs)
429+
json_rpc_response = JSONRPC20Response(**response_data)
430+
if json_rpc_response.error:
431+
raise A2AClientJSONRPCError(json_rpc_response.error)
432+
367433
async def subscribe(
368434
self,
369435
request: SubscribeToTaskRequest,

src/a2a/client/transports/rest.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@
2222
AgentCard,
2323
CancelTaskRequest,
2424
CreateTaskPushNotificationConfigRequest,
25+
DeleteTaskPushNotificationConfigRequest,
2526
GetTaskPushNotificationConfigRequest,
2627
GetTaskRequest,
28+
ListTaskPushNotificationConfigsRequest,
29+
ListTaskPushNotificationConfigsResponse,
2730
ListTasksRequest,
2831
ListTasksResponse,
2932
SendMessageRequest,
@@ -199,6 +202,21 @@ async def _send_get_request(
199202
)
200203
)
201204

205+
async def _send_delete_request(
206+
self,
207+
target: str,
208+
query_params: dict[str, Any],
209+
http_kwargs: dict[str, Any] | None = None,
210+
) -> dict[str, Any]:
211+
return await self._send_request(
212+
self.httpx_client.build_request(
213+
'DELETE',
214+
f'{self.url}{target}',
215+
params=query_params,
216+
**(http_kwargs or {}),
217+
)
218+
)
219+
202220
async def get_task(
203221
self,
204222
request: GetTaskRequest,
@@ -338,6 +356,64 @@ async def get_task_callback(
338356
)
339357
return response
340358

359+
async def list_task_callback(
360+
self,
361+
request: ListTaskPushNotificationConfigsRequest,
362+
*,
363+
context: ClientCallContext | None = None,
364+
extensions: list[str] | None = None,
365+
) -> ListTaskPushNotificationConfigsResponse:
366+
"""Lists push notification configurations for a specific task."""
367+
params = MessageToDict(request)
368+
modified_kwargs = update_extension_header(
369+
self._get_http_args(context),
370+
extensions if extensions is not None else self.extensions,
371+
)
372+
params, modified_kwargs = await self._apply_interceptors(
373+
params,
374+
modified_kwargs,
375+
context,
376+
)
377+
if 'task_id' in params:
378+
del params['task_id']
379+
response_data = await self._send_get_request(
380+
f'/v1/tasks/{request.task_id}/pushNotificationConfigs',
381+
params,
382+
modified_kwargs,
383+
)
384+
response: ListTaskPushNotificationConfigsResponse = ParseDict(
385+
response_data, ListTaskPushNotificationConfigsResponse()
386+
)
387+
return response
388+
389+
async def delete_task_callback(
390+
self,
391+
request: DeleteTaskPushNotificationConfigRequest,
392+
*,
393+
context: ClientCallContext | None = None,
394+
extensions: list[str] | None = None,
395+
) -> None:
396+
"""Deletes the push notification configuration for a specific task."""
397+
params = MessageToDict(request)
398+
modified_kwargs = update_extension_header(
399+
self._get_http_args(context),
400+
extensions if extensions is not None else self.extensions,
401+
)
402+
params, modified_kwargs = await self._apply_interceptors(
403+
params,
404+
modified_kwargs,
405+
context,
406+
)
407+
if 'id' in params:
408+
del params['id']
409+
if 'task_id' in params:
410+
del params['task_id']
411+
await self._send_delete_request(
412+
f'/v1/tasks/{request.task_id}/pushNotificationConfigs/{request.id}',
413+
params,
414+
modified_kwargs,
415+
)
416+
341417
async def subscribe(
342418
self,
343419
request: SubscribeToTaskRequest,

src/a2a/server/apps/rest/rest_adapter.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,12 @@ def routes(self) -> dict[tuple[str, str], Callable[[Request], Any]]:
234234
): functools.partial(
235235
self._handle_request, self.handler.get_push_notification
236236
),
237+
(
238+
'/v1/tasks/{id}/pushNotificationConfigs/{push_id}',
239+
'DELETE',
240+
): functools.partial(
241+
self._handle_request, self.handler.delete_push_notification
242+
),
237243
(
238244
'/v1/tasks/{id}/pushNotificationConfigs',
239245
'POST',

0 commit comments

Comments
 (0)