1
1
import asyncio
2
2
import logging
3
3
4
- from collections .abc import AsyncGenerator , AsyncIterator
4
+ from collections .abc import AsyncGenerator , AsyncIterator , Callable , Awaitable
5
5
6
6
from a2a .server .events import Event , EventConsumer
7
- from a2a .server .tasks .push_notification_sender import PushNotificationSender
8
7
from a2a .server .tasks .task_manager import TaskManager
9
8
from a2a .types import Message , Task , TaskState , TaskStatusUpdateEvent
10
9
@@ -28,17 +27,14 @@ class ResultAggregator:
28
27
def __init__ (
29
28
self ,
30
29
task_manager : TaskManager ,
31
- push_sender : PushNotificationSender | None = None ,
32
30
) -> None :
33
31
"""Initializes the ResultAggregator.
34
32
35
33
Args:
36
34
task_manager: The `TaskManager` instance to use for processing events
37
35
and managing the task state.
38
- push_sender: The `PushNotificationSender` instance to use for sending push notifications.
39
36
"""
40
37
self .task_manager = task_manager
41
- self .push_sender = push_sender
42
38
self ._message : Message | None = None
43
39
44
40
@property
@@ -99,7 +95,10 @@ async def consume_all(
99
95
return await self .task_manager .get_task ()
100
96
101
97
async def consume_and_break_on_interrupt (
102
- self , consumer : EventConsumer , blocking : bool = True
98
+ self ,
99
+ consumer : EventConsumer ,
100
+ blocking : bool = True ,
101
+ event_callback : Callable [[], Awaitable [None ]] | None = None
103
102
) -> tuple [Task | Message | None , bool ]:
104
103
"""Processes the event stream until completion or an interruptable state is encountered.
105
104
@@ -112,6 +111,9 @@ async def consume_and_break_on_interrupt(
112
111
consumer: The `EventConsumer` to read events from.
113
112
blocking: If `False`, the method returns as soon as a task/message
114
113
is available. If `True`, it waits for a terminal state.
114
+ event_callback: Optional async callback function to be called after each event
115
+ is processed in the background continuation.
116
+ Mainly used for push notifications currently.
115
117
116
118
Returns:
117
119
A tuple containing:
@@ -157,13 +159,15 @@ async def consume_and_break_on_interrupt(
157
159
if should_interrupt :
158
160
# Continue consuming the rest of the events in the background.
159
161
# TODO: We should track all outstanding tasks to ensure they eventually complete.
160
- asyncio .create_task (self ._continue_consuming (event_stream )) # noqa: RUF006
162
+ asyncio .create_task (self ._continue_consuming (event_stream , event_callback )) # noqa: RUF006
161
163
interrupted = True
162
164
break
163
165
return await self .task_manager .get_task (), interrupted
164
166
165
167
async def _continue_consuming (
166
- self , event_stream : AsyncIterator [Event ]
168
+ self ,
169
+ event_stream : AsyncIterator [Event ],
170
+ event_callback : Callable [[], Awaitable [None ]] | None = None
167
171
) -> None :
168
172
"""Continues processing an event stream in a background task.
169
173
@@ -172,14 +176,9 @@ async def _continue_consuming(
172
176
173
177
Args:
174
178
event_stream: The remaining `AsyncIterator` of events from the consumer.
179
+ event_callback: Optional async callback function to be called after each event is processed.
175
180
"""
176
181
async for event in event_stream :
177
182
await self .task_manager .process (event )
178
- await self ._send_push_notification_if_needed ()
179
-
180
- async def _send_push_notification_if_needed (self ) -> None :
181
- """Sends push notification if configured and task is available."""
182
- if self .push_sender :
183
- latest_task = await self .current_result
184
- if isinstance (latest_task , Task ):
185
- await self .push_sender .send_notification (latest_task )
183
+ if event_callback :
184
+ await event_callback ()
0 commit comments