Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion autogen/agentchat/groupchat.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ class GroupChat:
Must be supplied if `allowed_or_disallowed_speaker_transitions` is not None.
- enable_clear_history: enable possibility to clear history of messages for agents manually by providing
"clear history" phrase in user prompt. This is experimental feature.
See description of `GroupChatManager.clear_agents_history` function for more info.
See description of GroupChatManager.clear_agents_history function for more info.
- send_introductions: send a round of introductions at the start of the group chat, so agents know who they can speak to (default: False)
"""

agents: List[Agent]
Expand All @@ -71,6 +72,7 @@ class GroupChat:
allowed_or_disallowed_speaker_transitions: Optional[Dict] = None
speaker_transitions_type: Optional[str] = None
enable_clear_history: Optional[bool] = False
send_introductions: Optional[bool] = False

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

def introductions_msg(self, agents: Optional[List[Agent]] = None) -> str:
"""Return the system message for selecting the next speaker. This is always the *first* message in the context."""
if agents is None:
agents = self.agents

return f"""Hello everyone. We have assembled a great team today to answer questions and solve tasks. In attendance are:

{self._participant_roles(agents)}
"""

def manual_select_speaker(self, agents: Optional[List[Agent]] = None) -> Union[Agent, None]:
"""Manually select the next speaker."""
if agents is None:
Expand Down Expand Up @@ -529,6 +541,16 @@ def run_chat(
message = messages[-1]
speaker = sender
groupchat = config
send_introductions = getattr(groupchat, "send_introductions", False)

if send_introductions:
# Broadcast the intro
intro = groupchat.introductions_msg()
for agent in groupchat.agents:
self.send(intro, agent, request_reply=False, silent=True)
# NOTE: We do not also append to groupchat.messages,
# since groupchat handles its own introductions

if self.client_cache is not None:
for a in groupchat.agents:
a.previous_cache = a.client_cache
Expand Down Expand Up @@ -592,6 +614,16 @@ async def a_run_chat(
message = messages[-1]
speaker = sender
groupchat = config
send_introductions = getattr(groupchat, "send_introductions", False)

if send_introductions:
# Broadcast the intro
intro = groupchat.introductions_msg()
for agent in groupchat.agents:
self.a_send(intro, agent, request_reply=False, silent=True)
# NOTE: We do not also append to groupchat.messages,
# since groupchat handles its own introductions

if self.client_cache is not None:
for a in groupchat.agents:
a.previous_cache = a.client_cache
Expand Down
107 changes: 106 additions & 1 deletion test/agentchat/test_groupchat.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,110 @@ def test_next_agent():
assert groupchat.next_agent(agent4, [agent1, agent2, agent3]) == agent1


def test_send_intros():
agent1 = autogen.ConversableAgent(
"alice",
description="The first agent.",
max_consecutive_auto_reply=10,
human_input_mode="NEVER",
llm_config=False,
default_auto_reply="This is alice speaking. TERMINATE",
)
agent2 = autogen.ConversableAgent(
"bob",
description="The second agent.",
max_consecutive_auto_reply=10,
human_input_mode="NEVER",
llm_config=False,
default_auto_reply="This is bob speaking. TERMINATE",
)
agent3 = autogen.ConversableAgent(
"sam",
description="The third agent.",
max_consecutive_auto_reply=10,
human_input_mode="NEVER",
llm_config=False,
default_auto_reply="This is sam speaking. TERMINATE",
)
agent4 = autogen.ConversableAgent(
"sally",
description="The fourth agent.",
max_consecutive_auto_reply=10,
human_input_mode="NEVER",
llm_config=False,
default_auto_reply="This is sally speaking. TERMINATE",
)

# Test empty is_termination_msg function
groupchat = autogen.GroupChat(
agents=[agent1, agent2, agent3],
messages=[],
speaker_selection_method="round_robin",
max_round=10,
send_introductions=True,
)

intro = groupchat.introductions_msg()
assert "The first agent." in intro
assert "The second agent." in intro
assert "The third agent." in intro
assert "The fourth agent." not in intro

intro = groupchat.introductions_msg([agent1, agent2, agent4])
assert "The first agent." in intro
assert "The second agent." in intro
assert "The third agent." not in intro
assert "The fourth agent." in intro

groupchat = autogen.GroupChat(
agents=[agent1, agent2, agent3],
messages=[],
speaker_selection_method="round_robin",
max_round=10,
send_introductions=True,
)

group_chat_manager = autogen.GroupChatManager(
groupchat=groupchat,
llm_config=False,
is_termination_msg=lambda x: x.get("content", "").rstrip().find("TERMINATE") >= 0,
)

group_chat_manager.initiate_chat(group_chat_manager, message="The initiating message.")
for a in [agent1, agent2, agent3]:
messages = agent1.chat_messages[group_chat_manager]
assert len(messages) == 3
assert "The first agent." in messages[0]["content"]
assert "The second agent." in messages[0]["content"]
assert "The third agent." in messages[0]["content"]
assert "The initiating message." == messages[1]["content"]
assert messages[2]["content"] == agent1._default_auto_reply

# Reset and start again
agent1.reset()
agent2.reset()
agent3.reset()
agent4.reset()

# Check the default (no introductions)
groupchat2 = autogen.GroupChat(
agents=[agent1, agent2, agent3], messages=[], speaker_selection_method="round_robin", max_round=10
)

group_chat_manager2 = autogen.GroupChatManager(
groupchat=groupchat2,
llm_config=False,
is_termination_msg=lambda x: x.get("content", "").rstrip().find("TERMINATE") >= 0,
)

group_chat_manager2.initiate_chat(group_chat_manager2, message="The initiating message.")
for a in [agent1, agent2, agent3]:
messages = agent1.chat_messages[group_chat_manager2]
assert len(messages) == 2
assert "The initiating message." == messages[0]["content"]
assert messages[1]["content"] == agent1._default_auto_reply


def test_selection_helpers():
agent1 = autogen.ConversableAgent(
"alice",
Expand Down Expand Up @@ -814,6 +918,7 @@ def chat(gc_manager: autogen.GroupChatManager):
# test_agent_mentions()
# test_termination()
# test_next_agent()
test_send_intros()
# test_invalid_allow_repeat_speaker()
# test_graceful_exit_before_max_round()
test_clear_agents_history()
# test_clear_agents_history()