1
- from typing import List , Sequence
1
+ from typing import Any , List , Protocol , Sequence
2
+
3
+ from agnext .chat .types import Reset , RespondNow
2
4
3
- from ...agent_components .type_routed_agent import message_handler
4
5
from ...core .agent_runtime import AgentRuntime
5
6
from ...core .cancellation_token import CancellationToken
6
7
from ..agents .base import BaseChatAgent
7
- from ..messages import ChatMessage
8
+
9
+
10
+ class Output (Protocol ):
11
+ def on_message_received (self , message : Any ) -> None : ...
12
+
13
+ def get_output (self ) -> Any : ...
14
+
15
+ def reset (self ) -> None : ...
8
16
9
17
10
18
class GroupChat (BaseChatAgent ):
@@ -15,70 +23,69 @@ def __init__(
15
23
runtime : AgentRuntime ,
16
24
agents : Sequence [BaseChatAgent ],
17
25
num_rounds : int ,
26
+ output : Output ,
18
27
) -> None :
19
28
super ().__init__ (name , description , runtime )
20
29
self ._agents = agents
21
30
self ._num_rounds = num_rounds
22
- self ._history : List [ChatMessage ] = []
31
+ self ._history : List [Any ] = []
32
+ self ._output = output
23
33
24
- @message_handler (ChatMessage )
25
- async def on_chat_message (
26
- self ,
27
- message : ChatMessage ,
28
- require_response : bool ,
29
- cancellation_token : CancellationToken ,
30
- ) -> ChatMessage | None :
31
- if message .reset :
34
+ @property
35
+ def subscriptions (self ) -> Sequence [type ]:
36
+ agent_sublists = [agent .subscriptions for agent in self ._agents ]
37
+ return [Reset , RespondNow ] + [item for sublist in agent_sublists for item in sublist ]
38
+
39
+ async def on_message (
40
+ self , message : Any , require_response : bool , cancellation_token : CancellationToken
41
+ ) -> Any | None :
42
+ if isinstance (message , Reset ):
32
43
# Reset the history.
33
44
self ._history = []
34
- if message .save_message_only :
35
- # TODO: what should we do with save_message_only messages for this pattern?
36
- return ChatMessage (body = "OK" , sender = self .name )
45
+ # TODO: reset sub-agents?
46
+
47
+ if isinstance (message , RespondNow ):
48
+ # TODO reset...
49
+ return self ._output .get_output ()
50
+
51
+ # TODO: should we do nothing here?
52
+ # Perhaps it should be saved into the message history?
53
+ if not require_response :
54
+ return None
37
55
38
56
self ._history .append (message )
39
- previous_speaker : BaseChatAgent | None = None
40
57
round = 0
41
58
42
59
while round < self ._num_rounds :
43
60
# TODO: add support for advanced speaker selection.
44
61
# Select speaker (round-robin for now).
45
62
speaker = self ._agents [round % len (self ._agents )]
46
63
47
- # Send the last message to non-speaking agents.
48
- for agent in [agent for agent in self ._agents if agent is not previous_speaker and agent is not speaker ]:
64
+ # Send the last message to all agents.
65
+ for agent in [agent for agent in self ._agents ]:
66
+ # TODO gather and await
49
67
_ = await self ._send_message (
50
- ChatMessage (
51
- body = self ._history [- 1 ].body ,
52
- sender = self ._history [- 1 ].sender ,
53
- save_message_only = True ,
54
- ),
68
+ self ._history [- 1 ],
55
69
agent ,
70
+ require_response = False ,
71
+ cancellation_token = cancellation_token ,
56
72
)
57
73
58
- # Send the last message to the speaking agent and ask to speak.
59
- if previous_speaker is not speaker :
60
- response = await self ._send_message (
61
- ChatMessage (body = self ._history [- 1 ].body , sender = self ._history [- 1 ].sender ),
62
- speaker ,
63
- )
64
- else :
65
- # The same speaker is speaking again.
66
- # TODO: should support a separate message type for request to speak only.
67
- response = await self ._send_message (
68
- ChatMessage (body = "" , sender = self .name ),
69
- speaker ,
70
- )
74
+ response = await self ._send_message (
75
+ RespondNow (),
76
+ speaker ,
77
+ require_response = True ,
78
+ cancellation_token = cancellation_token ,
79
+ )
71
80
72
81
if response is not None :
73
82
# 4. Append the response to the history.
74
83
self ._history .append (response )
75
-
76
- # 5. Update the previous speaker.
77
- previous_speaker = speaker
84
+ self ._output .on_message_received (response )
78
85
79
86
# 6. Increment the round.
80
87
round += 1
81
88
82
- # Construct the final response.
83
- response_body = " \n " . join ([ f" { message . sender } : { message . body } " for message in self ._history ] )
84
- return ChatMessage ( body = response_body , sender = self . name )
89
+ output = self . _output . get_output ()
90
+ self ._output . reset ( )
91
+ return output
0 commit comments