Skip to content

Commit 86b9783

Browse files
committed
WIP: implement missing push notifications APIs
1 parent b306e44 commit 86b9783

13 files changed

Lines changed: 701 additions & 13 deletions

File tree

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+
ListTaskPushNotificationConfigRequest,
25+
ListTaskPushNotificationConfigResponse,
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: ListTaskPushNotificationConfigRequest,
256+
*,
257+
context: ClientCallContext | None = None,
258+
extensions: list[str] | None = None,
259+
) -> ListTaskPushNotificationConfigResponse:
260+
"""Lists push notification configurations for a specific task.
261+
262+
Args:
263+
request: The `ListTaskPushNotificationConfigRequest` object specifying the request.
264+
context: The client call context.
265+
extensions: List of extensions to be activated.
266+
267+
Returns:
268+
A `ListTaskPushNotificationConfigResponse` 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+
ListTaskPushNotificationConfigRequest,
20+
ListTaskPushNotificationConfigResponse,
1821
ListTasksRequest,
1922
ListTasksResponse,
2023
Message,
@@ -175,6 +178,26 @@ async def get_task_callback(
175178
) -> TaskPushNotificationConfig:
176179
"""Retrieves the push notification configuration for a specific task."""
177180

181+
@abstractmethod
182+
async def list_task_callback(
183+
self,
184+
request: ListTaskPushNotificationConfigRequest,
185+
*,
186+
context: ClientCallContext | None = None,
187+
extensions: list[str] | None = None,
188+
) -> ListTaskPushNotificationConfigResponse:
189+
"""Lists push notification configurations for a specific task."""
190+
191+
@abstractmethod
192+
async def delete_task_callback(
193+
self,
194+
request: DeleteTaskPushNotificationConfigRequest,
195+
*,
196+
context: ClientCallContext | None = None,
197+
extensions: list[str] | None = None,
198+
) -> None:
199+
"""Deletes the push notification configuration for a specific task."""
200+
178201
@abstractmethod
179202
async def subscribe(
180203
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+
ListTaskPushNotificationConfigRequest,
16+
ListTaskPushNotificationConfigResponse,
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: ListTaskPushNotificationConfigRequest,
120+
*,
121+
context: ClientCallContext | None = None,
122+
extensions: list[str] | None = None,
123+
) -> ListTaskPushNotificationConfigResponse:
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+
ListTaskPushNotificationConfigRequest,
30+
ListTaskPushNotificationConfigResponse,
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: ListTaskPushNotificationConfigRequest,
207+
*,
208+
context: ClientCallContext | None = None,
209+
extensions: list[str] | None = None,
210+
) -> ListTaskPushNotificationConfigResponse:
211+
"""Lists push notification configurations for a specific task."""
212+
return await self.stub.ListTaskPushNotificationConfig(
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
@@ -25,9 +25,12 @@
2525
AgentCard,
2626
CancelTaskRequest,
2727
CreateTaskPushNotificationConfigRequest,
28+
DeleteTaskPushNotificationConfigRequest,
2829
GetExtendedAgentCardRequest,
2930
GetTaskPushNotificationConfigRequest,
3031
GetTaskRequest,
32+
ListTaskPushNotificationConfigRequest,
33+
ListTaskPushNotificationConfigResponse,
3134
ListTasksRequest,
3235
ListTasksResponse,
3336
SendMessageRequest,
@@ -378,6 +381,69 @@ async def get_task_callback(
378381
)
379382
return response
380383

384+
async def list_task_callback(
385+
self,
386+
request: ListTaskPushNotificationConfigRequest,
387+
*,
388+
context: ClientCallContext | None = None,
389+
extensions: list[str] | None = None,
390+
) -> ListTaskPushNotificationConfigResponse:
391+
"""Lists push notification configurations for a specific task."""
392+
rpc_request = JSONRPC20Request(
393+
method='ListTaskPushNotificationConfig',
394+
params=json_format.MessageToDict(request),
395+
_id=str(uuid4()),
396+
)
397+
modified_kwargs = update_extension_header(
398+
self._get_http_args(context),
399+
extensions if extensions is not None else self.extensions,
400+
)
401+
payload, modified_kwargs = await self._apply_interceptors(
402+
'ListTaskPushNotificationConfig',
403+
cast('dict[str, Any]', rpc_request.data),
404+
modified_kwargs,
405+
context,
406+
)
407+
response_data = await self._send_request(payload, modified_kwargs)
408+
json_rpc_response = JSONRPC20Response(**response_data)
409+
if json_rpc_response.error:
410+
raise A2AClientJSONRPCError(json_rpc_response.error)
411+
response: ListTaskPushNotificationConfigResponse = (
412+
json_format.ParseDict(
413+
json_rpc_response.result,
414+
ListTaskPushNotificationConfigResponse(),
415+
)
416+
)
417+
return response
418+
419+
async def delete_task_callback(
420+
self,
421+
request: DeleteTaskPushNotificationConfigRequest,
422+
*,
423+
context: ClientCallContext | None = None,
424+
extensions: list[str] | None = None,
425+
) -> None:
426+
"""Deletes the push notification configuration for a specific task."""
427+
rpc_request = JSONRPC20Request(
428+
method='DeleteTaskPushNotificationConfig',
429+
params=json_format.MessageToDict(request),
430+
_id=str(uuid4()),
431+
)
432+
modified_kwargs = update_extension_header(
433+
self._get_http_args(context),
434+
extensions if extensions is not None else self.extensions,
435+
)
436+
payload, modified_kwargs = await self._apply_interceptors(
437+
'DeleteTaskPushNotificationConfig',
438+
cast('dict[str, Any]', rpc_request.data),
439+
modified_kwargs,
440+
context,
441+
)
442+
response_data = await self._send_request(payload, modified_kwargs)
443+
json_rpc_response = JSONRPC20Response(**response_data)
444+
if json_rpc_response.error:
445+
raise A2AClientJSONRPCError(json_rpc_response.error)
446+
381447
async def subscribe(
382448
self,
383449
request: SubscribeToTaskRequest,

src/a2a/client/transports/rest.py

Lines changed: 76 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+
ListTaskPushNotificationConfigRequest,
30+
ListTaskPushNotificationConfigResponse,
2831
ListTasksRequest,
2932
ListTasksResponse,
3033
SendMessageRequest,
@@ -224,6 +227,21 @@ async def _send_get_request(
224227
)
225228
)
226229

230+
async def _send_delete_request(
231+
self,
232+
target: str,
233+
query_params: dict[str, Any],
234+
http_kwargs: dict[str, Any] | None = None,
235+
) -> dict[str, Any]:
236+
return await self._send_request(
237+
self.httpx_client.build_request(
238+
'DELETE',
239+
f'{self.url}{target}',
240+
params=query_params,
241+
**(http_kwargs or {}),
242+
)
243+
)
244+
227245
async def get_task(
228246
self,
229247
request: GetTaskRequest,
@@ -363,6 +381,64 @@ async def get_task_callback(
363381
)
364382
return response
365383

384+
async def list_task_callback(
385+
self,
386+
request: ListTaskPushNotificationConfigRequest,
387+
*,
388+
context: ClientCallContext | None = None,
389+
extensions: list[str] | None = None,
390+
) -> ListTaskPushNotificationConfigResponse:
391+
"""Lists push notification configurations for a specific task."""
392+
params = MessageToDict(request)
393+
modified_kwargs = update_extension_header(
394+
self._get_http_args(context),
395+
extensions if extensions is not None else self.extensions,
396+
)
397+
params, modified_kwargs = await self._apply_interceptors(
398+
params,
399+
modified_kwargs,
400+
context,
401+
)
402+
if 'task_id' in params:
403+
del params['task_id']
404+
response_data = await self._send_get_request(
405+
f'/v1/tasks/{request.task_id}/pushNotificationConfigs',
406+
params,
407+
modified_kwargs,
408+
)
409+
response: ListTaskPushNotificationConfigResponse = ParseDict(
410+
response_data, ListTaskPushNotificationConfigResponse()
411+
)
412+
return response
413+
414+
async def delete_task_callback(
415+
self,
416+
request: DeleteTaskPushNotificationConfigRequest,
417+
*,
418+
context: ClientCallContext | None = None,
419+
extensions: list[str] | None = None,
420+
) -> None:
421+
"""Deletes the push notification configuration for a specific task."""
422+
params = MessageToDict(request)
423+
modified_kwargs = update_extension_header(
424+
self._get_http_args(context),
425+
extensions if extensions is not None else self.extensions,
426+
)
427+
params, modified_kwargs = await self._apply_interceptors(
428+
params,
429+
modified_kwargs,
430+
context,
431+
)
432+
if 'id' in params:
433+
del params['id']
434+
if 'task_id' in params:
435+
del params['task_id']
436+
await self._send_delete_request(
437+
f'/v1/tasks/{request.task_id}/pushNotificationConfigs/{request.id}',
438+
params,
439+
modified_kwargs,
440+
)
441+
366442
async def subscribe(
367443
self,
368444
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)