Skip to content

Commit 477598a

Browse files
afourneysonichiekzhu
authored
Groupchat send introductions (#961)
* Allow the GroupChatManager to send introductions. * Fixed function name. * Added test cases for sending introductions. * Trying to sort out why remote pytest is failing. * Fixed broken plugin behavior. * Update autogen/agentchat/groupchat.py Co-authored-by: Chi Wang <[email protected]> * Updated as per Chi's suggestions. --------- Co-authored-by: Chi Wang <[email protected]> Co-authored-by: Eric Zhu <[email protected]>
1 parent fb2b412 commit 477598a

File tree

2 files changed

+139
-2
lines changed

2 files changed

+139
-2
lines changed

autogen/agentchat/groupchat.py

+33-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ class GroupChat:
5858
Must be supplied if `allowed_or_disallowed_speaker_transitions` is not None.
5959
- enable_clear_history: enable possibility to clear history of messages for agents manually by providing
6060
"clear history" phrase in user prompt. This is experimental feature.
61-
See description of `GroupChatManager.clear_agents_history` function for more info.
61+
See description of GroupChatManager.clear_agents_history function for more info.
62+
- send_introductions: send a round of introductions at the start of the group chat, so agents know who they can speak to (default: False)
6263
"""
6364

6465
agents: List[Agent]
@@ -71,6 +72,7 @@ class GroupChat:
7172
allowed_or_disallowed_speaker_transitions: Optional[Dict] = None
7273
speaker_transitions_type: Optional[str] = None
7374
enable_clear_history: Optional[bool] = False
75+
send_introductions: Optional[bool] = False
7476

7577
_VALID_SPEAKER_SELECTION_METHODS = ["auto", "manual", "random", "round_robin"]
7678
_VALID_SPEAKER_TRANSITIONS_TYPE = ["allowed", "disallowed", None]
@@ -229,6 +231,16 @@ def select_speaker_prompt(self, agents: Optional[List[Agent]] = None) -> str:
229231
agents = self.agents
230232
return f"Read the above conversation. Then select the next role from {[agent.name for agent in agents]} to play. Only return the role."
231233

234+
def introductions_msg(self, agents: Optional[List[Agent]] = None) -> str:
235+
"""Return the system message for selecting the next speaker. This is always the *first* message in the context."""
236+
if agents is None:
237+
agents = self.agents
238+
239+
return f"""Hello everyone. We have assembled a great team today to answer questions and solve tasks. In attendance are:
240+
241+
{self._participant_roles(agents)}
242+
"""
243+
232244
def manual_select_speaker(self, agents: Optional[List[Agent]] = None) -> Union[Agent, None]:
233245
"""Manually select the next speaker."""
234246
if agents is None:
@@ -535,6 +547,16 @@ def run_chat(
535547
message = messages[-1]
536548
speaker = sender
537549
groupchat = config
550+
send_introductions = getattr(groupchat, "send_introductions", False)
551+
552+
if send_introductions:
553+
# Broadcast the intro
554+
intro = groupchat.introductions_msg()
555+
for agent in groupchat.agents:
556+
self.send(intro, agent, request_reply=False, silent=True)
557+
# NOTE: We do not also append to groupchat.messages,
558+
# since groupchat handles its own introductions
559+
538560
if self.client_cache is not None:
539561
for a in groupchat.agents:
540562
a.previous_cache = a.client_cache
@@ -598,6 +620,16 @@ async def a_run_chat(
598620
message = messages[-1]
599621
speaker = sender
600622
groupchat = config
623+
send_introductions = getattr(groupchat, "send_introductions", False)
624+
625+
if send_introductions:
626+
# Broadcast the intro
627+
intro = groupchat.introductions_msg()
628+
for agent in groupchat.agents:
629+
self.a_send(intro, agent, request_reply=False, silent=True)
630+
# NOTE: We do not also append to groupchat.messages,
631+
# since groupchat handles its own introductions
632+
601633
if self.client_cache is not None:
602634
for a in groupchat.agents:
603635
a.previous_cache = a.client_cache

test/agentchat/test_groupchat.py

+106-1
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,110 @@ def test_next_agent():
448448
assert groupchat.next_agent(agent4, [agent1, agent2, agent3]) == agent1
449449

450450

451+
def test_send_intros():
452+
agent1 = autogen.ConversableAgent(
453+
"alice",
454+
description="The first agent.",
455+
max_consecutive_auto_reply=10,
456+
human_input_mode="NEVER",
457+
llm_config=False,
458+
default_auto_reply="This is alice speaking. TERMINATE",
459+
)
460+
agent2 = autogen.ConversableAgent(
461+
"bob",
462+
description="The second agent.",
463+
max_consecutive_auto_reply=10,
464+
human_input_mode="NEVER",
465+
llm_config=False,
466+
default_auto_reply="This is bob speaking. TERMINATE",
467+
)
468+
agent3 = autogen.ConversableAgent(
469+
"sam",
470+
description="The third agent.",
471+
max_consecutive_auto_reply=10,
472+
human_input_mode="NEVER",
473+
llm_config=False,
474+
default_auto_reply="This is sam speaking. TERMINATE",
475+
)
476+
agent4 = autogen.ConversableAgent(
477+
"sally",
478+
description="The fourth agent.",
479+
max_consecutive_auto_reply=10,
480+
human_input_mode="NEVER",
481+
llm_config=False,
482+
default_auto_reply="This is sally speaking. TERMINATE",
483+
)
484+
485+
# Test empty is_termination_msg function
486+
groupchat = autogen.GroupChat(
487+
agents=[agent1, agent2, agent3],
488+
messages=[],
489+
speaker_selection_method="round_robin",
490+
max_round=10,
491+
send_introductions=True,
492+
)
493+
494+
intro = groupchat.introductions_msg()
495+
assert "The first agent." in intro
496+
assert "The second agent." in intro
497+
assert "The third agent." in intro
498+
assert "The fourth agent." not in intro
499+
500+
intro = groupchat.introductions_msg([agent1, agent2, agent4])
501+
assert "The first agent." in intro
502+
assert "The second agent." in intro
503+
assert "The third agent." not in intro
504+
assert "The fourth agent." in intro
505+
506+
groupchat = autogen.GroupChat(
507+
agents=[agent1, agent2, agent3],
508+
messages=[],
509+
speaker_selection_method="round_robin",
510+
max_round=10,
511+
send_introductions=True,
512+
)
513+
514+
group_chat_manager = autogen.GroupChatManager(
515+
groupchat=groupchat,
516+
llm_config=False,
517+
is_termination_msg=lambda x: x.get("content", "").rstrip().find("TERMINATE") >= 0,
518+
)
519+
520+
group_chat_manager.initiate_chat(group_chat_manager, message="The initiating message.")
521+
for a in [agent1, agent2, agent3]:
522+
messages = agent1.chat_messages[group_chat_manager]
523+
assert len(messages) == 3
524+
assert "The first agent." in messages[0]["content"]
525+
assert "The second agent." in messages[0]["content"]
526+
assert "The third agent." in messages[0]["content"]
527+
assert "The initiating message." == messages[1]["content"]
528+
assert messages[2]["content"] == agent1._default_auto_reply
529+
530+
# Reset and start again
531+
agent1.reset()
532+
agent2.reset()
533+
agent3.reset()
534+
agent4.reset()
535+
536+
# Check the default (no introductions)
537+
groupchat2 = autogen.GroupChat(
538+
agents=[agent1, agent2, agent3], messages=[], speaker_selection_method="round_robin", max_round=10
539+
)
540+
541+
group_chat_manager2 = autogen.GroupChatManager(
542+
groupchat=groupchat2,
543+
llm_config=False,
544+
is_termination_msg=lambda x: x.get("content", "").rstrip().find("TERMINATE") >= 0,
545+
)
546+
547+
group_chat_manager2.initiate_chat(group_chat_manager2, message="The initiating message.")
548+
for a in [agent1, agent2, agent3]:
549+
messages = agent1.chat_messages[group_chat_manager2]
550+
assert len(messages) == 2
551+
assert "The initiating message." == messages[0]["content"]
552+
assert messages[1]["content"] == agent1._default_auto_reply
553+
554+
451555
def test_selection_helpers():
452556
agent1 = autogen.ConversableAgent(
453557
"alice",
@@ -814,6 +918,7 @@ def chat(gc_manager: autogen.GroupChatManager):
814918
# test_agent_mentions()
815919
# test_termination()
816920
# test_next_agent()
921+
test_send_intros()
817922
# test_invalid_allow_repeat_speaker()
818923
# test_graceful_exit_before_max_round()
819-
test_clear_agents_history()
924+
# test_clear_agents_history()

0 commit comments

Comments
 (0)