14
14
MessageContext ,
15
15
)
16
16
from autogen_core .components import ClosureAgent , TypeSubscription
17
+ from autogen_core .components ._closure_agent import ClosureContext
17
18
18
19
from ... import EVENT_LOGGER_NAME
19
20
from ...base import ChatAgent , TaskResult , Team , TerminationCondition
@@ -139,8 +140,7 @@ async def _init(self, runtime: AgentRuntime) -> None:
139
140
)
140
141
141
142
async def collect_output_messages (
142
- _runtime : AgentRuntime ,
143
- id : AgentId ,
143
+ _runtime : ClosureContext ,
144
144
message : GroupChatStart | GroupChatMessage | GroupChatTermination ,
145
145
ctx : MessageContext ,
146
146
) -> None :
@@ -150,7 +150,7 @@ async def collect_output_messages(
150
150
return
151
151
await self ._output_message_queue .put (message .message )
152
152
153
- await ClosureAgent .register (
153
+ await ClosureAgent .register_closure (
154
154
runtime ,
155
155
type = self ._collector_agent_type ,
156
156
closure = collect_output_messages ,
@@ -170,6 +170,13 @@ async def run(
170
170
:meth:`run_stream` to run the team and then returns the final result.
171
171
Once the team is stopped, the termination condition is reset.
172
172
173
+ Args:
174
+ task (str | ChatMessage | None): The task to run the team with.
175
+ cancellation_token (CancellationToken | None): The cancellation token to kill the task immediately.
176
+ Setting the cancellation token potentially put the team in an inconsistent state,
177
+ and it may not reset the termination condition.
178
+ To gracefully stop the team, use :class:`~autogen_agentchat.task.ExternalTermination` instead.
179
+
173
180
Example using the :class:`~autogen_agentchat.teams.RoundRobinGroupChat` team:
174
181
175
182
@@ -198,6 +205,47 @@ async def main() -> None:
198
205
print(result)
199
206
200
207
208
+ asyncio.run(main())
209
+
210
+
211
+ Example using the :class:`~autogen_core.base.CancellationToken` to cancel the task:
212
+
213
+ .. code-block:: python
214
+
215
+ import asyncio
216
+ from autogen_agentchat.agents import AssistantAgent
217
+ from autogen_agentchat.task import MaxMessageTermination
218
+ from autogen_agentchat.teams import RoundRobinGroupChat
219
+ from autogen_core.base import CancellationToken
220
+ from autogen_ext.models import OpenAIChatCompletionClient
221
+
222
+
223
+ async def main() -> None:
224
+ model_client = OpenAIChatCompletionClient(model="gpt-4o")
225
+
226
+ agent1 = AssistantAgent("Assistant1", model_client=model_client)
227
+ agent2 = AssistantAgent("Assistant2", model_client=model_client)
228
+ termination = MaxMessageTermination(3)
229
+ team = RoundRobinGroupChat([agent1, agent2], termination_condition=termination)
230
+
231
+ cancellation_token = CancellationToken()
232
+
233
+ # Create a task to run the team in the background.
234
+ run_task = asyncio.create_task(
235
+ team.run(
236
+ task="Count from 1 to 10, respond one at a time.",
237
+ cancellation_token=cancellation_token,
238
+ )
239
+ )
240
+
241
+ # Wait for 1 second and then cancel the task.
242
+ await asyncio.sleep(1)
243
+ cancellation_token.cancel()
244
+
245
+ # This will raise a cancellation error.
246
+ await run_task
247
+
248
+
201
249
asyncio.run(main())
202
250
"""
203
251
result : TaskResult | None = None
@@ -221,6 +269,13 @@ async def run_stream(
221
269
of the type :class:`TaskResult` as the last item in the stream. Once the
222
270
team is stopped, the termination condition is reset.
223
271
272
+ Args:
273
+ task (str | ChatMessage | None): The task to run the team with.
274
+ cancellation_token (CancellationToken | None): The cancellation token to kill the task immediately.
275
+ Setting the cancellation token potentially put the team in an inconsistent state,
276
+ and it may not reset the termination condition.
277
+ To gracefully stop the team, use :class:`~autogen_agentchat.task.ExternalTermination` instead.
278
+
224
279
Example using the :class:`~autogen_agentchat.teams.RoundRobinGroupChat` team:
225
280
226
281
.. code-block:: python
@@ -251,7 +306,52 @@ async def main() -> None:
251
306
252
307
253
308
asyncio.run(main())
309
+
310
+
311
+ Example using the :class:`~autogen_core.base.CancellationToken` to cancel the task:
312
+
313
+ .. code-block:: python
314
+
315
+ import asyncio
316
+ from autogen_agentchat.agents import AssistantAgent
317
+ from autogen_agentchat.task import MaxMessageTermination, Console
318
+ from autogen_agentchat.teams import RoundRobinGroupChat
319
+ from autogen_core.base import CancellationToken
320
+ from autogen_ext.models import OpenAIChatCompletionClient
321
+
322
+
323
+ async def main() -> None:
324
+ model_client = OpenAIChatCompletionClient(model="gpt-4o")
325
+
326
+ agent1 = AssistantAgent("Assistant1", model_client=model_client)
327
+ agent2 = AssistantAgent("Assistant2", model_client=model_client)
328
+ termination = MaxMessageTermination(3)
329
+ team = RoundRobinGroupChat([agent1, agent2], termination_condition=termination)
330
+
331
+ cancellation_token = CancellationToken()
332
+
333
+ # Create a task to run the team in the background.
334
+ run_task = asyncio.create_task(
335
+ Console(
336
+ team.run_stream(
337
+ task="Count from 1 to 10, respond one at a time.",
338
+ cancellation_token=cancellation_token,
339
+ )
340
+ )
341
+ )
342
+
343
+ # Wait for 1 second and then cancel the task.
344
+ await asyncio.sleep(1)
345
+ cancellation_token.cancel()
346
+
347
+ # This will raise a cancellation error.
348
+ await run_task
349
+
350
+
351
+ asyncio.run(main())
352
+
254
353
"""
354
+
255
355
# Create the first chat message if the task is a string or a chat message.
256
356
first_chat_message : ChatMessage | None = None
257
357
if task is None :
@@ -288,12 +388,17 @@ async def stop_runtime() -> None:
288
388
await self ._runtime .send_message (
289
389
GroupChatStart (message = first_chat_message ),
290
390
recipient = AgentId (type = self ._group_chat_manager_topic_type , key = self ._team_id ),
391
+ cancellation_token = cancellation_token ,
291
392
)
292
393
# Collect the output messages in order.
293
394
output_messages : List [AgentMessage ] = []
294
395
# Yield the messsages until the queue is empty.
295
396
while True :
296
- message = await self ._output_message_queue .get ()
397
+ message_future = asyncio .ensure_future (self ._output_message_queue .get ())
398
+ if cancellation_token is not None :
399
+ cancellation_token .link_future (message_future )
400
+ # Wait for the next message, this will raise an exception if the task is cancelled.
401
+ message = await message_future
297
402
if message is None :
298
403
break
299
404
yield message
0 commit comments