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 <wang.chi@microsoft.com>

* Updated as per Chi's suggestions.

---------

Co-authored-by: Chi Wang <wang.chi@microsoft.com>
Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
This commit is contained in:
afourney 2024-02-24 08:50:46 -08:00 committed by GitHub
parent fb2b412c4a
commit 477598afff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 139 additions and 2 deletions

View File

@ -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]
@ -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]
@ -229,6 +231,16 @@ Then select the next role from {[agent.name for agent in agents]} to play. Only
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:
@ -535,6 +547,16 @@ class GroupChatManager(ConversableAgent):
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
@ -598,6 +620,16 @@ class GroupChatManager(ConversableAgent):
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

View File

@ -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",
@ -814,6 +918,7 @@ if __name__ == "__main__":
# 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()