2024-02-28 17:11:08 -08:00
#!/usr/bin/env python3 -m pytest
2023-11-17 21:56:11 +08:00
import builtins
2024-05-11 08:56:25 +10:00
import io
2023-11-16 18:30:24 -08:00
import json
2024-05-11 08:56:25 +10:00
import logging
2024-03-09 16:15:19 +01:00
from typing import Any , Dict , List , Optional
2024-05-14 03:46:01 -03:00
from unittest import TestCase , mock
2024-03-09 16:15:19 +01:00
import pytest
2024-05-14 03:46:01 -03:00
from test_assistant_agent import KEY_LOC , OAI_CONFIG_LIST
2024-03-09 16:15:19 +01:00
import autogen
2024-05-11 08:56:25 +10:00
from autogen import Agent , AssistantAgent , GroupChat , GroupChatManager
2024-08-26 13:47:48 +10:00
from autogen . agentchat . contrib . capabilities import transform_messages , transforms
2024-03-09 16:15:19 +01:00
from autogen . exception_utils import AgentNameConflict , UndefinedNextAgent
2023-08-03 02:17:20 -07:00
2023-10-19 07:43:36 -07:00
def test_func_call_groupchat ( ) :
agent1 = autogen . ConversableAgent (
" alice " ,
human_input_mode = " NEVER " ,
llm_config = False ,
2023-11-17 21:56:11 +08:00
default_auto_reply = " This is alice speaking. " ,
2023-10-19 07:43:36 -07:00
)
agent2 = autogen . ConversableAgent (
" bob " ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is bob speaking. " ,
function_map = { " test_func " : lambda x : x } ,
)
groupchat = autogen . GroupChat ( agents = [ agent1 , agent2 ] , messages = [ ] , max_round = 3 )
group_chat_manager = autogen . GroupChatManager ( groupchat = groupchat , llm_config = False )
agent2 . initiate_chat ( group_chat_manager , message = { " function_call " : { " name " : " test_func " , " arguments " : ' { " x " : 1} ' } } )
assert len ( groupchat . messages ) == 3
assert (
groupchat . messages [ - 2 ] [ " role " ] == " function "
and groupchat . messages [ - 2 ] [ " name " ] == " test_func "
and groupchat . messages [ - 2 ] [ " content " ] == " 1 "
)
assert groupchat . messages [ - 1 ] [ " name " ] == " alice "
agent3 = autogen . ConversableAgent (
" carol " ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is carol speaking. " ,
function_map = { " test_func " : lambda x : x + 1 } ,
)
groupchat = autogen . GroupChat ( agents = [ agent1 , agent2 , agent3 ] , messages = [ ] , max_round = 3 )
group_chat_manager = autogen . GroupChatManager ( groupchat = groupchat , llm_config = False )
agent3 . initiate_chat ( group_chat_manager , message = { " function_call " : { " name " : " test_func " , " arguments " : ' { " x " : 1} ' } } )
assert (
groupchat . messages [ - 2 ] [ " role " ] == " function "
and groupchat . messages [ - 2 ] [ " name " ] == " test_func "
and groupchat . messages [ - 2 ] [ " content " ] == " 1 "
)
assert groupchat . messages [ - 1 ] [ " name " ] == " carol "
agent2 . initiate_chat ( group_chat_manager , message = { " function_call " : { " name " : " func " , " arguments " : ' { " x " : 1} ' } } )
2023-08-03 02:17:20 -07:00
def test_chat_manager ( ) :
2023-09-11 17:07:35 -07:00
agent1 = autogen . ConversableAgent (
2023-08-03 02:17:20 -07:00
" alice " ,
max_consecutive_auto_reply = 2 ,
human_input_mode = " NEVER " ,
llm_config = False ,
2023-11-17 21:56:11 +08:00
default_auto_reply = " This is alice speaking. " ,
2023-08-03 02:17:20 -07:00
)
2023-09-11 17:07:35 -07:00
agent2 = autogen . ConversableAgent (
2023-08-03 02:17:20 -07:00
" bob " ,
max_consecutive_auto_reply = 2 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is bob speaking. " ,
)
2023-08-07 11:41:58 -07:00
groupchat = autogen . GroupChat ( agents = [ agent1 , agent2 ] , messages = [ ] , max_round = 2 )
group_chat_manager = autogen . GroupChatManager ( groupchat = groupchat , llm_config = False )
2023-08-04 07:26:58 -07:00
agent1 . initiate_chat ( group_chat_manager , message = " hello " )
2023-08-03 02:17:20 -07:00
2023-08-04 07:26:58 -07:00
assert len ( agent1 . chat_messages [ group_chat_manager ] ) == 2
2023-08-07 11:41:58 -07:00
assert len ( groupchat . messages ) == 2
2023-08-03 02:17:20 -07:00
group_chat_manager . reset ( )
2023-08-07 11:41:58 -07:00
assert len ( groupchat . messages ) == 0
2023-08-03 02:17:20 -07:00
agent1 . reset ( )
agent2 . reset ( )
2023-08-04 07:26:58 -07:00
agent2 . initiate_chat ( group_chat_manager , message = " hello " )
2023-08-07 11:41:58 -07:00
assert len ( groupchat . messages ) == 2
2023-10-19 07:43:36 -07:00
with pytest . raises ( ValueError ) :
agent2 . initiate_chat ( group_chat_manager , message = { " function_call " : { " name " : " func " , " arguments " : ' { " x " : 1} ' } } )
2023-08-07 11:41:58 -07:00
2023-11-17 21:56:11 +08:00
def _test_selection_method ( method : str ) :
agent1 = autogen . ConversableAgent (
" alice " ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is alice speaking. " ,
)
agent2 = autogen . ConversableAgent (
" bob " ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is bob speaking. " ,
)
agent3 = autogen . ConversableAgent (
" charlie " ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is charlie speaking. " ,
)
groupchat = autogen . GroupChat (
agents = [ agent1 , agent2 , agent3 ] ,
messages = [ ] ,
max_round = 6 ,
speaker_selection_method = method ,
allow_repeat_speaker = False if method == " manual " else True ,
)
group_chat_manager = autogen . GroupChatManager ( groupchat = groupchat , llm_config = False )
if method == " round_robin " :
agent1 . initiate_chat ( group_chat_manager , message = " This is alice speaking. " )
assert len ( agent1 . chat_messages [ group_chat_manager ] ) == 6
assert len ( groupchat . messages ) == 6
assert [ msg [ " content " ] for msg in agent1 . chat_messages [ group_chat_manager ] ] == [
" This is alice speaking. " ,
" This is bob speaking. " ,
" This is charlie speaking. " ,
] * 2
elif method == " auto " :
agent1 . initiate_chat ( group_chat_manager , message = " This is alice speaking. " )
assert len ( agent1 . chat_messages [ group_chat_manager ] ) == 6
assert len ( groupchat . messages ) == 6
elif method == " random " :
agent1 . initiate_chat ( group_chat_manager , message = " This is alice speaking. " )
assert len ( agent1 . chat_messages [ group_chat_manager ] ) == 6
assert len ( groupchat . messages ) == 6
elif method == " manual " :
for user_input in [ " " , " q " , " x " , " 1 " , " 10 " ] :
with mock . patch . object ( builtins , " input " , lambda _ : user_input ) :
group_chat_manager . reset ( )
agent1 . reset ( )
agent2 . reset ( )
agent3 . reset ( )
agent1 . initiate_chat ( group_chat_manager , message = " This is alice speaking. " )
if user_input == " 1 " :
assert len ( agent1 . chat_messages [ group_chat_manager ] ) == 6
assert len ( groupchat . messages ) == 6
assert [ msg [ " content " ] for msg in agent1 . chat_messages [ group_chat_manager ] ] == [
" This is alice speaking. " ,
" This is bob speaking. " ,
" This is alice speaking. " ,
" This is bob speaking. " ,
" This is alice speaking. " ,
" This is bob speaking. " ,
]
else :
assert len ( agent1 . chat_messages [ group_chat_manager ] ) == 6
assert len ( groupchat . messages ) == 6
elif method == " wrong " :
with pytest . raises ( ValueError ) :
agent1 . initiate_chat ( group_chat_manager , message = " This is alice speaking. " )
def test_speaker_selection_method ( ) :
for method in [ " auto " , " round_robin " , " random " , " manual " , " wrong " , " RounD_roBin " ] :
_test_selection_method ( method )
def _test_n_agents_less_than_3 ( method ) :
agent1 = autogen . ConversableAgent (
" alice " ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is alice speaking. " ,
)
agent2 = autogen . ConversableAgent (
" bob " ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is bob speaking. " ,
)
# test two agents
groupchat = autogen . GroupChat (
agents = [ agent1 , agent2 ] ,
messages = [ ] ,
max_round = 6 ,
speaker_selection_method = method ,
2023-12-17 19:51:39 -08:00
allow_repeat_speaker = [ agent1 , agent2 ] if method == " random " else False ,
2023-11-17 21:56:11 +08:00
)
group_chat_manager = autogen . GroupChatManager ( groupchat = groupchat , llm_config = False )
agent1 . initiate_chat ( group_chat_manager , message = " This is alice speaking. " )
assert len ( agent1 . chat_messages [ group_chat_manager ] ) == 6
assert len ( groupchat . messages ) == 6
if method != " random " or method . lower ( ) == " round_robin " :
assert [ msg [ " content " ] for msg in agent1 . chat_messages [ group_chat_manager ] ] == [
" This is alice speaking. " ,
" This is bob speaking. " ,
] * 3
# test zero agent
with pytest . raises ( ValueError ) :
2024-02-06 14:13:18 +11:00
groupchat = autogen . GroupChat (
agents = [ ] , messages = [ ] , max_round = 6 , speaker_selection_method = " round_robin " , allow_repeat_speaker = False
)
2023-11-17 21:56:11 +08:00
group_chat_manager = autogen . GroupChatManager ( groupchat = groupchat , llm_config = False )
agent1 . initiate_chat ( group_chat_manager , message = " This is alice speaking. " )
2024-01-14 10:24:05 -08:00
def test_invalid_allow_repeat_speaker ( ) :
agent1 = autogen . ConversableAgent (
" alice " ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is alice speaking. " ,
)
agent2 = autogen . ConversableAgent (
" bob " ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is bob speaking. " ,
)
# test invalid allow_repeat_speaker
with pytest . raises ( ValueError ) as e :
2024-02-05 23:18:13 -08:00
autogen . GroupChat (
agents = [ agent1 , agent2 ] ,
messages = [ ] ,
max_round = 6 ,
speaker_selection_method = " round_robin " ,
allow_repeat_speaker = { } ,
)
2024-01-14 10:24:05 -08:00
assert str ( e . value ) == " GroupChat allow_repeat_speaker should be a bool or a list of Agents. " , e . value
2023-11-17 21:56:11 +08:00
def test_n_agents_less_than_3 ( ) :
for method in [ " auto " , " round_robin " , " random " , " RounD_roBin " ] :
_test_n_agents_less_than_3 ( method )
2023-08-07 11:41:58 -07:00
def test_plugin ( ) :
# Give another Agent class ability to manage group chat
2023-09-11 17:07:35 -07:00
agent1 = autogen . ConversableAgent (
2023-08-07 11:41:58 -07:00
" alice " ,
max_consecutive_auto_reply = 2 ,
human_input_mode = " NEVER " ,
llm_config = False ,
2023-11-17 21:56:11 +08:00
default_auto_reply = " This is alice speaking. " ,
2023-08-07 11:41:58 -07:00
)
2023-09-11 17:07:35 -07:00
agent2 = autogen . ConversableAgent (
2023-08-07 11:41:58 -07:00
" bob " ,
max_consecutive_auto_reply = 2 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is bob speaking. " ,
)
groupchat = autogen . GroupChat ( agents = [ agent1 , agent2 ] , messages = [ ] , max_round = 2 )
2023-09-11 17:07:35 -07:00
group_chat_manager = autogen . ConversableAgent ( name = " deputy_manager " , llm_config = False )
group_chat_manager . register_reply (
2023-08-07 11:41:58 -07:00
autogen . Agent ,
reply_func = autogen . GroupChatManager . run_chat ,
2023-08-14 00:09:45 -07:00
config = groupchat ,
reset_config = autogen . GroupChat . reset ,
2023-08-07 11:41:58 -07:00
)
agent1 . initiate_chat ( group_chat_manager , message = " hello " )
assert len ( agent1 . chat_messages [ group_chat_manager ] ) == 2
assert len ( groupchat . messages ) == 2
2023-08-03 02:17:20 -07:00
2023-11-16 18:30:24 -08:00
def test_agent_mentions ( ) :
agent1 = autogen . ConversableAgent (
" alice " ,
max_consecutive_auto_reply = 2 ,
human_input_mode = " NEVER " ,
llm_config = False ,
2023-11-29 12:43:57 -08:00
default_auto_reply = " This is alice speaking. " ,
2023-11-16 18:30:24 -08:00
)
agent2 = autogen . ConversableAgent (
" bob " ,
max_consecutive_auto_reply = 2 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is bob speaking. " ,
)
agent3 = autogen . ConversableAgent (
" sam " ,
max_consecutive_auto_reply = 2 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is sam speaking. " ,
)
groupchat = autogen . GroupChat ( agents = [ agent1 , agent2 , agent3 ] , messages = [ ] , max_round = 2 )
# Basic counting
assert json . dumps ( groupchat . _mentioned_agents ( " " , [ agent1 , agent2 , agent3 ] ) , sort_keys = True ) == " {} "
assert json . dumps ( groupchat . _mentioned_agents ( " alice " , [ agent1 , agent2 , agent3 ] ) , sort_keys = True ) == ' { " alice " : 1} '
assert (
json . dumps ( groupchat . _mentioned_agents ( " alice bob alice " , [ agent1 , agent2 , agent3 ] ) , sort_keys = True )
== ' { " alice " : 2, " bob " : 1} '
)
assert (
json . dumps ( groupchat . _mentioned_agents ( " alice bob alice sam " , [ agent1 , agent2 , agent3 ] ) , sort_keys = True )
== ' { " alice " : 2, " bob " : 1, " sam " : 1} '
)
assert (
json . dumps ( groupchat . _mentioned_agents ( " alice bob alice sam robert " , [ agent1 , agent2 , agent3 ] ) , sort_keys = True )
== ' { " alice " : 2, " bob " : 1, " sam " : 1} '
)
# Substring
assert (
json . dumps ( groupchat . _mentioned_agents ( " sam samantha basam asami " , [ agent1 , agent2 , agent3 ] ) , sort_keys = True )
== ' { " sam " : 1} '
)
# Word boundaries
assert (
json . dumps ( groupchat . _mentioned_agents ( " alice! .alice. .alice " , [ agent1 , agent2 , agent3 ] ) , sort_keys = True )
== ' { " alice " : 3} '
)
# Special characters in agent names
agent4 = autogen . ConversableAgent (
" .* " ,
max_consecutive_auto_reply = 2 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " Match everything. " ,
)
groupchat = autogen . GroupChat ( agents = [ agent1 , agent2 , agent3 , agent4 ] , messages = [ ] , max_round = 2 )
assert (
json . dumps (
groupchat . _mentioned_agents ( " alice bob alice sam robert .* " , [ agent1 , agent2 , agent3 , agent4 ] ) ,
sort_keys = True ,
)
== ' { " .* " : 1, " alice " : 2, " bob " : 1, " sam " : 1} '
)
2023-11-29 12:43:57 -08:00
def test_termination ( ) :
agent1 = autogen . ConversableAgent (
" alice " ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is alice speaking. " ,
)
agent2 = autogen . ConversableAgent (
" bob " ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is bob speaking. " ,
)
agent3 = autogen . ConversableAgent (
" sam " ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is sam speaking. TERMINATE " ,
)
# Test empty is_termination_msg function
groupchat = autogen . GroupChat (
agents = [ agent1 , agent2 , agent3 ] , messages = [ ] , speaker_selection_method = " round_robin " , max_round = 10
)
group_chat_manager = autogen . GroupChatManager ( groupchat = groupchat , llm_config = False , is_termination_msg = None )
agent1 . initiate_chat ( group_chat_manager , message = " ' None ' is_termination_msg function. " )
assert len ( groupchat . messages ) == 10
# Test user-provided is_termination_msg function
agent1 . reset ( )
agent2 . reset ( )
agent3 . reset ( )
groupchat = autogen . GroupChat (
agents = [ agent1 , agent2 , agent3 ] , messages = [ ] , speaker_selection_method = " round_robin " , max_round = 10
)
group_chat_manager = autogen . GroupChatManager (
groupchat = groupchat ,
llm_config = False ,
is_termination_msg = lambda x : x . get ( " content " , " " ) . rstrip ( ) . find ( " TERMINATE " ) > = 0 ,
)
agent1 . initiate_chat ( group_chat_manager , message = " User-provided is_termination_msg function. " )
assert len ( groupchat . messages ) == 3
2023-12-08 07:39:27 -08:00
def test_next_agent ( ) :
2024-03-09 16:15:19 +01:00
def create_agent ( name : str ) - > autogen . ConversableAgent :
return autogen . ConversableAgent (
name ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = f " This is { name } speaking. " ,
)
agent1 = create_agent ( " alice " )
agent2 = create_agent ( " bob " )
agent3 = create_agent ( " sam " )
agent4 = create_agent ( " sally " )
agent5 = create_agent ( " samantha " )
agent6 = create_agent ( " robert " )
2023-12-08 07:39:27 -08:00
# Test empty is_termination_msg function
groupchat = autogen . GroupChat (
agents = [ agent1 , agent2 , agent3 ] , messages = [ ] , speaker_selection_method = " round_robin " , max_round = 10
)
assert groupchat . next_agent ( agent1 , [ agent1 , agent2 , agent3 ] ) == agent2
assert groupchat . next_agent ( agent2 , [ agent1 , agent2 , agent3 ] ) == agent3
assert groupchat . next_agent ( agent3 , [ agent1 , agent2 , agent3 ] ) == agent1
2023-12-24 04:23:06 -08:00
assert groupchat . next_agent ( agent1 ) == agent2
assert groupchat . next_agent ( agent2 ) == agent3
assert groupchat . next_agent ( agent3 ) == agent1
2023-12-08 07:39:27 -08:00
assert groupchat . next_agent ( agent1 , [ agent1 , agent3 ] ) == agent3
assert groupchat . next_agent ( agent3 , [ agent1 , agent3 ] ) == agent1
assert groupchat . next_agent ( agent2 , [ agent1 , agent3 ] ) == agent3
assert groupchat . next_agent ( agent4 , [ agent1 , agent3 ] ) == agent1
assert groupchat . next_agent ( agent4 , [ agent1 , agent2 , agent3 ] ) == agent1
2024-03-09 16:15:19 +01:00
with pytest . raises ( UndefinedNextAgent ) :
groupchat . next_agent ( agent4 , [ agent5 , agent6 ] )
2023-12-08 07:39:27 -08:00
2024-02-24 08:50:46 -08:00
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
2023-12-24 04:23:06 -08:00
def test_selection_helpers ( ) :
agent1 = autogen . ConversableAgent (
" alice " ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is alice speaking. " ,
description = " Alice is an AI agent. " ,
)
agent2 = autogen . ConversableAgent (
" bob " ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
description = " Bob is an AI agent. " ,
)
agent3 = autogen . ConversableAgent (
" sam " ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is sam speaking. " ,
system_message = " Sam is an AI agent. " ,
)
# Test empty is_termination_msg function
groupchat = autogen . GroupChat (
agents = [ agent1 , agent2 , agent3 ] , messages = [ ] , speaker_selection_method = " round_robin " , max_round = 10
)
select_speaker_msg = groupchat . select_speaker_msg ( )
select_speaker_prompt = groupchat . select_speaker_prompt ( )
assert " Alice is an AI agent. " in select_speaker_msg
assert " Bob is an AI agent. " in select_speaker_msg
assert " Sam is an AI agent. " in select_speaker_msg
assert str ( [ " Alice " , " Bob " , " Sam " ] ) . lower ( ) in select_speaker_prompt . lower ( )
with mock . patch . object ( builtins , " input " , lambda _ : " 1 " ) :
groupchat . manual_select_speaker ( )
2024-02-06 14:13:18 +11:00
def test_init_default_parameters ( ) :
2024-02-09 20:52:16 -08:00
agents = [ autogen . ConversableAgent ( name = f " Agent { i } " , llm_config = False ) for i in range ( 3 ) ]
2024-02-06 14:13:18 +11:00
group_chat = GroupChat ( agents = agents , messages = [ ] , max_round = 3 )
for agent in agents :
assert set ( [ a . name for a in group_chat . allowed_speaker_transitions_dict [ agent ] ] ) == set (
[ a . name for a in agents ]
)
def test_graph_parameters ( ) :
2024-02-09 20:52:16 -08:00
agents = [ autogen . ConversableAgent ( name = f " Agent { i } " , llm_config = False ) for i in range ( 3 ) ]
2024-02-06 14:13:18 +11:00
with pytest . raises ( ValueError ) :
GroupChat (
agents = agents ,
messages = [ ] ,
max_round = 3 ,
2024-02-05 23:18:13 -08:00
allowed_or_disallowed_speaker_transitions = { agents [ 0 ] : [ agents [ 1 ] ] , agents [ 1 ] : [ agents [ 2 ] ] } ,
)
with pytest . raises ( ValueError ) :
GroupChat (
agents = agents ,
messages = [ ] ,
max_round = 3 ,
allow_repeat_speaker = False , # should be None
2024-02-06 14:13:18 +11:00
allowed_or_disallowed_speaker_transitions = { agents [ 0 ] : [ agents [ 1 ] ] , agents [ 1 ] : [ agents [ 2 ] ] } ,
)
2024-02-05 23:18:13 -08:00
with pytest . raises ( ValueError ) :
2024-02-06 14:13:18 +11:00
GroupChat (
agents = agents ,
messages = [ ] ,
max_round = 3 ,
allow_repeat_speaker = None ,
allowed_or_disallowed_speaker_transitions = { agents [ 0 ] : [ agents [ 1 ] ] , agents [ 1 ] : [ agents [ 2 ] ] } ,
speaker_transitions_type = " a " ,
)
group_chat = GroupChat (
agents = agents ,
messages = [ ] ,
max_round = 3 ,
allowed_or_disallowed_speaker_transitions = { agents [ 0 ] : [ agents [ 1 ] ] , agents [ 1 ] : [ agents [ 2 ] ] } ,
speaker_transitions_type = " allowed " ,
)
assert " Agent0 " in group_chat . agent_names
def test_graceful_exit_before_max_round ( ) :
agent1 = autogen . ConversableAgent (
" alice " ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is alice speaking. " ,
)
agent2 = autogen . ConversableAgent (
" bob " ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is bob speaking. " ,
)
agent3 = autogen . ConversableAgent (
" sam " ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
2024-03-06 21:28:22 -05:00
default_auto_reply = " This is sam speaking. " ,
2024-02-06 14:13:18 +11:00
)
# This speaker_transitions limits the transition to be only from agent1 to agent2, and from agent2 to agent3 and end.
allowed_or_disallowed_speaker_transitions = { agent1 : [ agent2 ] , agent2 : [ agent3 ] }
# Test empty is_termination_msg function
groupchat = autogen . GroupChat (
agents = [ agent1 , agent2 , agent3 ] ,
messages = [ ] ,
speaker_selection_method = " round_robin " ,
max_round = 10 ,
allow_repeat_speaker = None ,
allowed_or_disallowed_speaker_transitions = allowed_or_disallowed_speaker_transitions ,
speaker_transitions_type = " allowed " ,
)
group_chat_manager = autogen . GroupChatManager ( groupchat = groupchat , llm_config = False , is_termination_msg = None )
2024-03-06 21:28:22 -05:00
agent1 . initiate_chat ( group_chat_manager , message = " " )
2024-02-06 14:13:18 +11:00
# Note that 3 is much lower than 10 (max_round), so the conversation should end before 10 rounds.
assert len ( groupchat . messages ) == 3
2024-01-27 20:14:03 +01:00
def test_clear_agents_history ( ) :
agent1 = autogen . ConversableAgent (
" alice " ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is alice speaking. " ,
)
agent2 = autogen . ConversableAgent (
" bob " ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is bob speaking. " ,
)
agent3 = autogen . ConversableAgent (
" sam " ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " ALWAYS " ,
llm_config = False ,
)
groupchat = autogen . GroupChat ( agents = [ agent1 , agent2 , agent3 ] , messages = [ ] , max_round = 3 , enable_clear_history = True )
group_chat_manager = autogen . GroupChatManager ( groupchat = groupchat , llm_config = False )
# testing pure "clear history" statement
with mock . patch . object ( builtins , " input " , lambda _ : " clear history. How you doing? " ) :
2024-02-07 12:17:05 -05:00
res = agent1 . initiate_chat ( group_chat_manager , message = " hello " , summary_method = " last_msg " )
2024-01-27 20:14:03 +01:00
agent1_history = list ( agent1 . _oai_messages . values ( ) ) [ 0 ]
agent2_history = list ( agent2 . _oai_messages . values ( ) ) [ 0 ]
assert agent1_history == [ { " content " : " How you doing? " , " name " : " sam " , " role " : " user " } ]
assert agent2_history == [ { " content " : " How you doing? " , " name " : " sam " , " role " : " user " } ]
assert groupchat . messages == [ { " content " : " How you doing? " , " name " : " sam " , " role " : " user " } ]
2024-02-07 12:17:05 -05:00
print ( " Chat summary " , res . summary )
print ( " Chat cost " , res . cost )
print ( " Chat history " , res . chat_history )
2024-01-27 20:14:03 +01:00
# testing clear history for defined agent
with mock . patch . object ( builtins , " input " , lambda _ : " clear history bob. How you doing? " ) :
agent1 . initiate_chat ( group_chat_manager , message = " hello " )
agent1_history = list ( agent1 . _oai_messages . values ( ) ) [ 0 ]
agent2_history = list ( agent2 . _oai_messages . values ( ) ) [ 0 ]
assert agent1_history == [
2024-08-20 14:08:26 +10:00
{ " content " : " hello " , " role " : " assistant " , " name " : " alice " } ,
2024-01-27 20:14:03 +01:00
{ " content " : " This is bob speaking. " , " name " : " bob " , " role " : " user " } ,
{ " content " : " How you doing? " , " name " : " sam " , " role " : " user " } ,
]
assert agent2_history == [ { " content " : " How you doing? " , " name " : " sam " , " role " : " user " } ]
assert groupchat . messages == [
{ " content " : " hello " , " role " : " user " , " name " : " alice " } ,
{ " content " : " This is bob speaking. " , " name " : " bob " , " role " : " user " } ,
{ " content " : " How you doing? " , " name " : " sam " , " role " : " user " } ,
]
# testing clear history with defined nr of messages to preserve
with mock . patch . object ( builtins , " input " , lambda _ : " clear history 1. How you doing? " ) :
agent1 . initiate_chat ( group_chat_manager , message = " hello " )
agent1_history = list ( agent1 . _oai_messages . values ( ) ) [ 0 ]
agent2_history = list ( agent2 . _oai_messages . values ( ) ) [ 0 ]
assert agent1_history == [
{ " content " : " This is bob speaking. " , " name " : " bob " , " role " : " user " } ,
{ " content " : " How you doing? " , " name " : " sam " , " role " : " user " } ,
]
assert agent2_history == [
2024-08-20 14:08:26 +10:00
{ " content " : " This is bob speaking. " , " role " : " assistant " , " name " : " bob " } ,
2024-01-27 20:14:03 +01:00
{ " content " : " How you doing? " , " name " : " sam " , " role " : " user " } ,
]
assert groupchat . messages == [
{ " content " : " This is bob speaking. " , " role " : " user " , " name " : " bob " } ,
{ " content " : " How you doing? " , " role " : " user " , " name " : " sam " } ,
]
# testing clear history with defined agent and nr of messages to preserve
with mock . patch . object ( builtins , " input " , lambda _ : " clear history bob 1. How you doing? " ) :
agent1 . initiate_chat ( group_chat_manager , message = " hello " )
agent1_history = list ( agent1 . _oai_messages . values ( ) ) [ 0 ]
agent2_history = list ( agent2 . _oai_messages . values ( ) ) [ 0 ]
assert agent1_history == [
2024-08-20 14:08:26 +10:00
{ " content " : " hello " , " role " : " assistant " , " name " : " alice " } ,
2024-01-27 20:14:03 +01:00
{ " content " : " This is bob speaking. " , " name " : " bob " , " role " : " user " } ,
{ " content " : " How you doing? " , " name " : " sam " , " role " : " user " } ,
]
assert agent2_history == [
2024-08-20 14:08:26 +10:00
{ " content " : " This is bob speaking. " , " role " : " assistant " , " name " : " bob " } ,
2024-01-27 20:14:03 +01:00
{ " content " : " How you doing? " , " name " : " sam " , " role " : " user " } ,
]
assert groupchat . messages == [
{ " content " : " hello " , " name " : " alice " , " role " : " user " } ,
{ " content " : " This is bob speaking. " , " name " : " bob " , " role " : " user " } ,
{ " content " : " How you doing? " , " name " : " sam " , " role " : " user " } ,
]
2024-03-02 19:03:52 +01:00
# testing saving tool_call message when clear history going to remove it leaving only tool_response message
agent1 . reset ( )
agent2 . reset ( )
agent3 . reset ( )
# we want to broadcast the message only in the preparation.
groupchat = autogen . GroupChat ( agents = [ agent1 , agent2 , agent3 ] , messages = [ ] , max_round = 1 , enable_clear_history = True )
group_chat_manager = autogen . GroupChatManager ( groupchat = groupchat , llm_config = False )
# We want to trigger the broadcast of group chat manager, which requires `request_reply` to be set to True.
agent1 . send ( " dummy message " , group_chat_manager , request_reply = True )
agent1 . send (
{
" content " : None ,
" role " : " assistant " ,
" function_call " : None ,
" tool_calls " : [
{ " id " : " call_test_id " , " function " : { " arguments " : " " , " name " : " test_tool " } , " type " : " function " }
] ,
} ,
group_chat_manager ,
request_reply = True ,
)
agent1 . send (
{
" role " : " tool " ,
" tool_responses " : [ { " tool_call_id " : " call_emulated " , " role " : " tool " , " content " : " example tool response " } ] ,
" content " : " example tool response " ,
} ,
group_chat_manager ,
request_reply = True ,
)
# increase max_round to 3
groupchat . max_round = 3
group_chat_manager = autogen . GroupChatManager ( groupchat = groupchat , llm_config = False )
with mock . patch . object ( builtins , " input " , lambda _ : " clear history alice 1. How you doing? " ) :
agent1 . initiate_chat ( group_chat_manager , message = " hello " , clear_history = False )
agent1_history = list ( agent1 . _oai_messages . values ( ) ) [ 0 ]
assert agent1_history == [
{
" tool_calls " : [
{ " id " : " call_test_id " , " function " : { " arguments " : " " , " name " : " test_tool " } , " type " : " function " } ,
] ,
" content " : None ,
" role " : " assistant " ,
} ,
{
" content " : " example tool response " ,
" tool_responses " : [ { " tool_call_id " : " call_emulated " , " role " : " tool " , " content " : " example tool response " } ] ,
" role " : " tool " ,
2024-08-20 14:08:26 +10:00
" name " : " alice " ,
2024-03-02 19:03:52 +01:00
} ,
]
# testing clear history called from tool response
agent1 . reset ( )
agent2 . reset ( )
agent3 . reset ( )
agent2 = autogen . ConversableAgent (
" bob " ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = {
" role " : " tool " ,
" tool_responses " : [ { " tool_call_id " : " call_emulated " , " role " : " tool " , " content " : " USER INTERRUPTED " } ] ,
" content " : " Clear history. How you doing? " ,
} ,
)
groupchat = autogen . GroupChat ( agents = [ agent1 , agent2 , agent3 ] , messages = [ ] , max_round = 1 , enable_clear_history = True )
group_chat_manager = autogen . GroupChatManager ( groupchat = groupchat , llm_config = False )
agent1 . send ( " dummy message " , group_chat_manager , request_reply = True )
agent1 . send (
{
" content " : None ,
" role " : " assistant " ,
" function_call " : None ,
" tool_calls " : [
{ " id " : " call_test_id " , " function " : { " arguments " : " " , " name " : " test_tool " } , " type " : " function " }
] ,
} ,
group_chat_manager ,
request_reply = True ,
)
groupchat . max_round = 2
group_chat_manager = autogen . GroupChatManager ( groupchat = groupchat , llm_config = False )
agent1 . initiate_chat ( group_chat_manager , message = " hello " )
agent1_history = list ( agent1 . _oai_messages . values ( ) ) [ 0 ]
assert agent1_history == [
{
" tool_calls " : [
{ " id " : " call_test_id " , " function " : { " arguments " : " " , " name " : " test_tool " } , " type " : " function " } ,
] ,
" content " : None ,
" role " : " assistant " ,
} ,
]
2024-01-27 20:14:03 +01:00
2024-02-15 19:33:59 +01:00
def test_get_agent_by_name ( ) :
def agent ( name : str ) - > autogen . ConversableAgent :
return autogen . ConversableAgent (
name = name ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
)
def team ( members : List [ autogen . Agent ] , name : str ) - > autogen . Agent :
gc = autogen . GroupChat ( agents = members , messages = [ ] )
return autogen . GroupChatManager ( groupchat = gc , name = name , llm_config = False )
team_member1 = agent ( " team1_member1 " )
team_member2 = agent ( " team1_member2 " )
team_dup_member1 = agent ( " team1_member1 " )
team_dup_member2 = agent ( " team1_member2 " )
user = agent ( " user " )
team1 = team ( [ team_member1 , team_member2 ] , " team1 " )
team1_duplicate = team ( [ team_dup_member1 , team_dup_member2 ] , " team1 " )
gc = autogen . GroupChat ( agents = [ user , team1 , team1_duplicate ] , messages = [ ] )
# Testing default arguments
assert gc . agent_by_name ( " user " ) == user
assert gc . agent_by_name ( " team1 " ) == team1 or gc . agent_by_name ( " team1 " ) == team1_duplicate
# Testing recursive search
assert gc . agent_by_name ( " user " , recursive = True ) == user
assert (
gc . agent_by_name ( " team1_member1 " , recursive = True ) == team_member1
or gc . agent_by_name ( " team1_member1 " , recursive = True ) == team_dup_member1
)
# Get agent that does not exist
assert gc . agent_by_name ( " team2 " ) is None
assert gc . agent_by_name ( " team2 " , recursive = True ) is None
assert gc . agent_by_name ( " team2 " , raise_on_name_conflict = True ) is None
assert gc . agent_by_name ( " team2 " , recursive = True , raise_on_name_conflict = True ) is None
# Testing naming conflict
with pytest . raises ( AgentNameConflict ) :
gc . agent_by_name ( " team1 " , raise_on_name_conflict = True )
# Testing name conflict with recursive search
with pytest . raises ( AgentNameConflict ) :
gc . agent_by_name ( " team1_member1 " , recursive = True , raise_on_name_conflict = True )
def test_get_nested_agents_in_groupchat ( ) :
def agent ( name : str ) - > autogen . ConversableAgent :
return autogen . ConversableAgent (
name = name ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
)
def team ( name : str ) - > autogen . ConversableAgent :
member1 = agent ( f " member1_ { name } " )
member2 = agent ( f " member2_ { name } " )
gc = autogen . GroupChat ( agents = [ member1 , member2 ] , messages = [ ] )
return autogen . GroupChatManager ( groupchat = gc , name = name , llm_config = False )
user = agent ( " user " )
team1 = team ( " team1 " )
team2 = team ( " team2 " )
gc = autogen . GroupChat ( agents = [ user , team1 , team2 ] , messages = [ ] )
agents = gc . nested_agents ( )
assert len ( agents ) == 7
def test_nested_teams_chat ( ) :
""" Tests chat capabilities of nested teams """
team1_msg = { " content " : " Hello from team 1 " }
team2_msg = { " content " : " Hello from team 2 " }
def agent ( name : str , auto_reply : Optional [ Dict [ str , Any ] ] = None ) - > autogen . ConversableAgent :
return autogen . ConversableAgent (
name = name ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = auto_reply ,
)
def team ( name : str , auto_reply : Optional [ Dict [ str , Any ] ] = None ) - > autogen . ConversableAgent :
member1 = agent ( f " member1_ { name } " , auto_reply = auto_reply )
member2 = agent ( f " member2_ { name } " , auto_reply = auto_reply )
gc = autogen . GroupChat ( agents = [ member1 , member2 ] , messages = [ ] )
return autogen . GroupChatManager ( groupchat = gc , name = name , llm_config = False )
def chat ( gc_manager : autogen . GroupChatManager ) :
team1_member1 = gc_manager . groupchat . agent_by_name ( " member1_team1 " , recursive = True )
team2_member2 = gc_manager . groupchat . agent_by_name ( " member2_team2 " , recursive = True )
assert team1_member1 is not None
assert team2_member2 is not None
team1_member1 . send ( team1_msg , team2_member2 , request_reply = True )
user = agent ( " user " )
team1 = team ( " team1 " , auto_reply = team1_msg )
team2 = team ( " team2 " , auto_reply = team2_msg )
gc = autogen . GroupChat ( agents = [ user , team1 , team2 ] , messages = [ ] )
gc_manager = autogen . GroupChatManager ( groupchat = gc , llm_config = False )
chat ( gc_manager )
team1_member1 = gc . agent_by_name ( " member1_team1 " , recursive = True )
team2_member2 = gc . agent_by_name ( " member2_team2 " , recursive = True )
assert team1_member1 and team2_member2
msg = team1_member1 . chat_messages [ team2_member2 ] [ 0 ]
reply = team1_member1 . chat_messages [ team2_member2 ] [ 1 ]
assert msg [ " content " ] == team1_msg [ " content " ]
assert reply [ " content " ] == team2_msg [ " content " ]
2024-03-06 21:28:22 -05:00
def test_custom_speaker_selection ( ) :
a1 = autogen . UserProxyAgent (
name = " a1 " ,
default_auto_reply = " This is a1 speaking. " ,
human_input_mode = " NEVER " ,
code_execution_config = { } ,
)
a2 = autogen . UserProxyAgent (
name = " a2 " ,
default_auto_reply = " This is a2 speaking. " ,
human_input_mode = " NEVER " ,
code_execution_config = { } ,
)
a3 = autogen . UserProxyAgent (
name = " a3 " ,
default_auto_reply = " TERMINATE " ,
human_input_mode = " NEVER " ,
code_execution_config = { } ,
)
def custom_speaker_selection_func ( last_speaker : Agent , groupchat : GroupChat ) - > Agent :
""" Define a customized speaker selection function.
A recommended way is to define a transition for each speaker using the groupchat allowed_or_disallowed_speaker_transitions parameter .
"""
if last_speaker is a1 :
return a2
elif last_speaker is a2 :
return a3
groupchat = autogen . GroupChat (
agents = [ a1 , a2 , a3 ] ,
messages = [ ] ,
max_round = 20 ,
speaker_selection_method = custom_speaker_selection_func ,
)
manager = autogen . GroupChatManager ( groupchat = groupchat , llm_config = False )
result = a1 . initiate_chat ( manager , message = " Hello, this is a1 speaking. " )
assert len ( result . chat_history ) == 3
def test_custom_speaker_selection_with_transition_graph ( ) :
"""
In this test , although speaker_selection_method is defined , the speaker transitions are also defined .
There are 26 agents here , a to z .
The speaker transitions are defined such that the agents can transition to the next alphabet .
In addition , because we want the transition order to be a , u , t , o , g , e , n , we also define the speaker transitions for these agents .
The speaker_selection_method is defined to return the next agent in the expected sequence .
"""
# For loop that creates UserProxyAgent with names from a to z
agents = [
autogen . UserProxyAgent (
name = chr ( 97 + i ) ,
default_auto_reply = f " My name is { chr ( 97 + i ) } " ,
human_input_mode = " NEVER " ,
code_execution_config = { } ,
)
for i in range ( 26 )
]
# Initiate allowed speaker transitions
allowed_or_disallowed_speaker_transitions = { }
# Each agent can transition to the next alphabet as a baseline
# Key is Agent, value is a list of Agents that the key Agent can transition to
for i in range ( 25 ) :
allowed_or_disallowed_speaker_transitions [ agents [ i ] ] = [ agents [ i + 1 ] ]
# The test is to make sure that the agent sequence is a,u,t,o,g,e,n, so we need to add those transitions
expected_sequence = [ " a " , " u " , " t " , " o " , " g " , " e " , " n " ]
current_agent = None
previous_agent = None
for char in expected_sequence :
# convert char to i so that we can use chr(97+i)
current_agent = agents [ ord ( char ) - 97 ]
if previous_agent is not None :
# Add transition
allowed_or_disallowed_speaker_transitions [ previous_agent ] . append ( current_agent )
previous_agent = current_agent
def custom_speaker_selection_func ( last_speaker : Agent , groupchat : GroupChat ) - > Optional [ Agent ] :
"""
Define a customized speaker selection function .
"""
expected_sequence = [ " a " , " u " , " t " , " o " , " g " , " e " , " n " ]
last_speaker_char = last_speaker . name
# Find the index of last_speaker_char in the expected_sequence
last_speaker_index = expected_sequence . index ( last_speaker_char )
# Return the next agent in the expected sequence
if last_speaker_index == len ( expected_sequence ) - 1 :
return None # terminate the conversation
else :
next_agent = agents [ ord ( expected_sequence [ last_speaker_index + 1 ] ) - 97 ]
return next_agent
groupchat = autogen . GroupChat (
agents = agents ,
messages = [ ] ,
max_round = 20 ,
speaker_selection_method = custom_speaker_selection_func ,
allowed_or_disallowed_speaker_transitions = allowed_or_disallowed_speaker_transitions ,
speaker_transitions_type = " allowed " ,
)
manager = autogen . GroupChatManager ( groupchat = groupchat , llm_config = False )
results = agents [ 0 ] . initiate_chat ( manager , message = " My name is a " )
actual_sequence = [ ]
# Append to actual_sequence using results.chat_history[idx]['content'][-1]
for idx in range ( len ( results . chat_history ) ) :
actual_sequence . append ( results . chat_history [ idx ] [ " content " ] [ - 1 ] ) # append the last character of the content
assert expected_sequence == actual_sequence
def test_custom_speaker_selection_overrides_transition_graph ( ) :
"""
In this test , team A engineer can transition to team A executor and team B engineer , but team B engineer cannot transition to team A executor .
The expected behaviour is that the custom speaker selection function will override the constraints of the graph .
"""
# For loop that creates UserProxyAgent with names from a to z
agents = [
autogen . UserProxyAgent (
name = " teamA_engineer " ,
default_auto_reply = " My name is teamA_engineer " ,
human_input_mode = " NEVER " ,
code_execution_config = { } ,
) ,
autogen . UserProxyAgent (
name = " teamA_executor " ,
default_auto_reply = " My name is teamA_executor " ,
human_input_mode = " NEVER " ,
code_execution_config = { } ,
) ,
autogen . UserProxyAgent (
name = " teamB_engineer " ,
default_auto_reply = " My name is teamB_engineer " ,
human_input_mode = " NEVER " ,
code_execution_config = { } ,
) ,
]
allowed_or_disallowed_speaker_transitions = { }
# teamA_engineer can transition to teamA_executor and teamB_engineer
# teamB_engineer can transition to no one
allowed_or_disallowed_speaker_transitions [ agents [ 0 ] ] = [ agents [ 1 ] , agents [ 2 ] ]
def custom_speaker_selection_func ( last_speaker : Agent , groupchat : GroupChat ) - > Optional [ Agent ] :
if last_speaker . name == " teamA_engineer " :
return agents [ 2 ] # Goto teamB_engineer
elif last_speaker . name == " teamB_engineer " :
return agents [ 1 ] # Goto teamA_executor and contradict the graph
groupchat = autogen . GroupChat (
agents = agents ,
messages = [ ] ,
max_round = 20 ,
speaker_selection_method = custom_speaker_selection_func ,
allowed_or_disallowed_speaker_transitions = allowed_or_disallowed_speaker_transitions ,
speaker_transitions_type = " allowed " ,
)
manager = autogen . GroupChatManager ( groupchat = groupchat , llm_config = False )
results = agents [ 0 ] . initiate_chat ( manager , message = " My name is teamA_engineer " )
speakers = [ ]
for idx in range ( len ( results . chat_history ) ) :
speakers . append ( results . chat_history [ idx ] . get ( " name " ) )
assert " teamA_executor " in speakers
2024-04-01 09:54:17 +11:00
def test_role_for_select_speaker_messages ( ) :
agent1 = autogen . ConversableAgent (
" alice " ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is alice speaking. " ,
)
agent2 = autogen . ConversableAgent (
" bob " ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is bob speaking. " ,
)
groupchat = autogen . GroupChat (
agents = [ agent1 , agent2 ] ,
messages = [ { " role " : " user " , " content " : " Let ' s have a chat! " } ] ,
max_round = 3 ,
2024-04-30 14:16:08 +10:00
role_for_select_speaker_messages = " system " ,
2024-04-01 09:54:17 +11:00
)
2024-04-30 14:16:08 +10:00
# Replicate the _auto_select_speaker nested chat.
# Agent for checking the response from the speaker_select_agent
checking_agent = autogen . ConversableAgent ( " checking_agent " )
# Agent for selecting a single agent name from the response
speaker_selection_agent = autogen . ConversableAgent (
" speaker_selection_agent " ,
llm_config = None ,
human_input_mode = " NEVER " , # Suppresses some extra terminal outputs, outputs will be handled by select_speaker_auto_verbose
)
# The role_for_select_speaker_message is put into the initiate_chat of the nested two-way chat
# into a message attribute called 'override_role'. This is evaluated in Conversable Agent's _append_oai_message function
# e.g.: message={'content':self.select_speaker_prompt(agents),'override_role':self.role_for_select_speaker_messages},
message = { " content " : " A prompt goes here. " , " override_role " : groupchat . role_for_select_speaker_messages }
2024-08-20 14:08:26 +10:00
checking_agent . _append_oai_message ( message , " assistant " , speaker_selection_agent , is_sending = True )
2024-04-01 09:54:17 +11:00
# Test default is "system"
2024-04-30 14:16:08 +10:00
assert len ( checking_agent . chat_messages ) == 1
assert checking_agent . chat_messages [ speaker_selection_agent ] [ - 1 ] [ " role " ] == " system "
2024-04-01 09:54:17 +11:00
# Test as "user"
groupchat . role_for_select_speaker_messages = " user "
2024-04-30 14:16:08 +10:00
message = { " content " : " A prompt goes here. " , " override_role " : groupchat . role_for_select_speaker_messages }
2024-08-20 14:08:26 +10:00
checking_agent . _append_oai_message ( message , " assistant " , speaker_selection_agent , is_sending = True )
2024-04-01 09:54:17 +11:00
2024-04-30 14:16:08 +10:00
assert len ( checking_agent . chat_messages ) == 1
assert checking_agent . chat_messages [ speaker_selection_agent ] [ - 1 ] [ " role " ] == " user "
2024-04-01 09:54:17 +11:00
# Test as something unusual
groupchat . role_for_select_speaker_messages = " SockS "
2024-04-30 14:16:08 +10:00
message = { " content " : " A prompt goes here. " , " override_role " : groupchat . role_for_select_speaker_messages }
2024-08-20 14:08:26 +10:00
checking_agent . _append_oai_message ( message , " assistant " , speaker_selection_agent , is_sending = True )
2024-04-01 09:54:17 +11:00
2024-04-30 14:16:08 +10:00
assert len ( checking_agent . chat_messages ) == 1
assert checking_agent . chat_messages [ speaker_selection_agent ] [ - 1 ] [ " role " ] == " SockS "
2024-04-01 09:54:17 +11:00
# Test empty string and None isn't accepted
# Test with empty strings
with pytest . raises ( ValueError ) as e :
groupchat = autogen . GroupChat (
agents = [ agent1 , agent2 ] ,
messages = [ { " role " : " user " , " content " : " Let ' s have a chat! " } ] ,
max_round = 3 ,
role_for_select_speaker_messages = " " ,
)
assert " role_for_select_speaker_messages cannot be empty or None. " in str ( e . value )
with pytest . raises ( ValueError ) as e :
groupchat = autogen . GroupChat (
agents = [ agent1 , agent2 ] ,
messages = [ { " role " : " user " , " content " : " Let ' s have a chat! " } ] ,
max_round = 3 ,
role_for_select_speaker_messages = None ,
)
assert " role_for_select_speaker_messages cannot be empty or None. " in str ( e . value )
2024-04-02 00:49:13 +11:00
def test_select_speaker_message_and_prompt_templates ( ) :
"""
In this test , two agents are part of a group chat which has customized select speaker message and select speaker prompt templates . Both valid and empty string values will be used .
The expected behaviour is that the customized speaker selection message and prompts will override the default values or throw exceptions if empty .
"""
agent1 = autogen . ConversableAgent (
" Alice " ,
description = " A wonderful employee named Alice. " ,
human_input_mode = " NEVER " ,
llm_config = False ,
)
agent2 = autogen . ConversableAgent (
" Bob " ,
description = " An amazing employee named Bob. " ,
human_input_mode = " NEVER " ,
llm_config = False ,
)
# Customised message, this is always the first message in the context
custom_msg = """ You are the CEO of a niche organisation creating small software tools for the healthcare sector with a small team of specialists. Call them in sequence.
The job roles and responsibilities are :
{ roles }
You must select only from { agentlist } . """
# Customised prompt, this is always the last message in the context
custom_prompt = """ Read the above conversation.
Then select the next job role from { agentlist } to take action .
RETURN ONLY THE NAME OF THE NEXT ROLE . """
# Test empty is_termination_msg function
groupchat = autogen . GroupChat (
agents = [ agent1 , agent2 ] ,
messages = [ ] ,
speaker_selection_method = " auto " ,
max_round = 10 ,
select_speaker_message_template = custom_msg ,
select_speaker_prompt_template = custom_prompt ,
)
# Test with valid strings, checking for the correct string and roles / agentlist to be included
assert groupchat . select_speaker_msg ( ) == custom_msg . replace (
" {roles} " , " Alice: A wonderful employee named Alice. \n Bob: An amazing employee named Bob. "
) . replace ( " {agentlist} " , " [ ' Alice ' , ' Bob ' ] " )
assert groupchat . select_speaker_prompt ( ) == custom_prompt . replace ( " {agentlist} " , " [ ' Alice ' , ' Bob ' ] " )
# Test with empty strings
with pytest . raises ( ValueError , match = " select_speaker_message_template cannot be empty or None. " ) :
groupchat = autogen . GroupChat (
agents = [ agent1 , agent2 ] ,
messages = [ ] ,
speaker_selection_method = " auto " ,
max_round = 10 ,
select_speaker_message_template = " " ,
select_speaker_prompt_template = " Not empty. " ,
)
2024-05-23 05:55:26 +10:00
# Will not throw an exception, prompt can be empty/None (empty is converted to None)
groupchat = autogen . GroupChat (
agents = [ agent1 , agent2 ] ,
messages = [ ] ,
speaker_selection_method = " auto " ,
max_round = 10 ,
select_speaker_message_template = " Not empty. " ,
select_speaker_prompt_template = " " ,
)
assert groupchat . select_speaker_prompt_template is None
2024-04-02 00:49:13 +11:00
# Test with None
with pytest . raises ( ValueError , match = " select_speaker_message_template cannot be empty or None. " ) :
groupchat = autogen . GroupChat (
agents = [ agent1 , agent2 ] ,
messages = [ ] ,
speaker_selection_method = " auto " ,
max_round = 10 ,
select_speaker_message_template = None ,
select_speaker_prompt_template = " Not empty. " ,
)
2024-05-23 05:55:26 +10:00
# Will not throw an exception, prompt can be empty/None (empty is converted to None)
groupchat = autogen . GroupChat (
agents = [ agent1 , agent2 ] ,
messages = [ ] ,
speaker_selection_method = " auto " ,
max_round = 10 ,
select_speaker_message_template = " Not empty. " ,
select_speaker_prompt_template = None ,
)
assert groupchat . select_speaker_prompt_template is None
2024-04-02 00:49:13 +11:00
2024-04-04 09:57:41 +11:00
def test_speaker_selection_agent_name_match ( ) :
"""
In this test a group chat , with auto speaker selection , the speaker name match
function is tested against the extended name match regex .
"""
user_proxy = autogen . UserProxyAgent (
name = " User_proxy " ,
system_message = " A human admin. " ,
code_execution_config = False ,
human_input_mode = " NEVER " ,
)
storywriter = autogen . AssistantAgent (
name = " Story_writer " ,
system_message = " An ideas person. " ,
llm_config = None ,
)
pm = autogen . AssistantAgent (
name = " Product_manager " ,
system_message = " Great in evaluating story ideas. " ,
llm_config = None ,
)
all_agents = [ user_proxy , storywriter , pm ]
groupchat = autogen . GroupChat ( agents = all_agents , messages = [ ] , max_round = 8 , speaker_selection_method = " auto " )
# Test exact match (unchanged outcome)
result = groupchat . _mentioned_agents ( agents = all_agents , message_content = " Story_writer " )
assert result == { " Story_writer " : 1 }
# Test match with extra text (unchanged outcome)
result = groupchat . _mentioned_agents (
agents = all_agents ,
message_content = " ' Story_writer. \n \n Here are three story ideas for Grade 3 kids: \n \n 1. **The Adventure of the Magic Garden:** A you... " ,
)
assert result == { " Story_writer " : 1 }
# Test match with escaped underscore (new outcome)
result = groupchat . _mentioned_agents ( agents = all_agents , message_content = " Story \\ _writer " )
assert result == { " Story_writer " : 1 }
# Test match with space (new outcome)
result = groupchat . _mentioned_agents ( agents = all_agents , message_content = " Story writer " )
assert result == { " Story_writer " : 1 }
# Test match with different casing (unchanged outcome)
result = groupchat . _mentioned_agents ( agents = all_agents , message_content = " Story_Writer " )
assert result == { }
# Test match with invalid name (unchanged outcome)
result = groupchat . _mentioned_agents ( agents = all_agents , message_content = " NoName_Person " )
assert result == { }
# Test match with no name (unchanged outcome)
result = groupchat . _mentioned_agents ( agents = all_agents , message_content = " " )
assert result == { }
# Test match with multiple agents and exact matches (unchanged outcome)
result = groupchat . _mentioned_agents (
agents = all_agents , message_content = " Story_writer will follow the Product_manager. "
)
assert result == { " Story_writer " : 1 , " Product_manager " : 1 }
# Test match with multiple agents and escaped underscores (new outcome)
result = groupchat . _mentioned_agents (
agents = all_agents , message_content = " Story \\ _writer will follow the Product \\ _manager. "
)
assert result == { " Story_writer " : 1 , " Product_manager " : 1 }
# Test match with multiple agents and escaped underscores (new outcome)
result = groupchat . _mentioned_agents (
agents = all_agents , message_content = " Story \\ _writer will follow the Product \\ _manager. "
)
assert result == { " Story_writer " : 1 , " Product_manager " : 1 }
# Test match with multiple agents and spaces (new outcome)
result = groupchat . _mentioned_agents (
agents = all_agents , message_content = " Story writer will follow the Product manager. "
)
assert result == { " Story_writer " : 1 , " Product_manager " : 1 }
# Test match with multiple agents and escaped underscores and spaces mixed (new outcome)
result = groupchat . _mentioned_agents (
agents = all_agents , message_content = " Story writer will follow the Product \\ _manager. "
)
assert result == { " Story_writer " : 1 , " Product_manager " : 1 }
# Test match with multiple agents and incorrect casing (unchanged outcome)
result = groupchat . _mentioned_agents (
agents = all_agents , message_content = " Story Writer will follow the product \\ _manager. "
)
assert result == { }
2024-05-14 03:46:01 -03:00
def test_role_for_reflection_summary ( ) :
llm_config = { " config_list " : [ { " model " : " mock " , " api_key " : " mock " } ] }
agent1 = autogen . ConversableAgent (
" alice " ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is alice speaking. " ,
)
agent2 = autogen . ConversableAgent (
" bob " ,
max_consecutive_auto_reply = 10 ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is bob speaking. " ,
)
groupchat = autogen . GroupChat (
agents = [ agent1 , agent2 ] , messages = [ ] , max_round = 3 , speaker_selection_method = " round_robin "
)
group_chat_manager = autogen . GroupChatManager ( groupchat = groupchat , llm_config = llm_config )
role_name = " user "
with mock . patch . object (
autogen . ConversableAgent , " _generate_oai_reply_from_client "
) as mock_generate_oai_reply_from_client :
mock_generate_oai_reply_from_client . return_value = " Mocked summary "
agent1 . initiate_chat (
group_chat_manager ,
max_turns = 2 ,
message = " hello " ,
summary_method = " reflection_with_llm " ,
summary_args = { " summary_role " : role_name } ,
)
mock_generate_oai_reply_from_client . assert_called_once ( )
args , kwargs = mock_generate_oai_reply_from_client . call_args
assert kwargs [ " messages " ] [ - 1 ] [ " role " ] == role_name
2024-04-30 14:16:08 +10:00
def test_speaker_selection_auto_process_result ( ) :
"""
Tests the return result of the 2 - agent chat used for speaker selection for the auto method .
The last message of the messages passed in will contain a pass or fail .
If passed , the message will contain the name of the correct agent and that agent will be returned .
If failed , the message will contain the reason for failure for the last attempt and the next
agent in the sequence will be returned .
"""
cmo = autogen . ConversableAgent (
name = " Chief_Marketing_Officer " ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is alice speaking. " ,
)
pm = autogen . ConversableAgent (
name = " Product_Manager " ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is bob speaking. " ,
function_map = { " test_func " : lambda x : x } ,
)
agent_list = [ cmo , pm ]
groupchat = autogen . GroupChat ( agents = agent_list , messages = [ ] , max_round = 3 )
chat_result = autogen . ChatResult (
chat_id = None ,
chat_history = [
{
" content " : " Let ' s get this meeting started. First the Product_Manager will create 3 new product ideas. " ,
" name " : " Chairperson " ,
" role " : " assistant " ,
} ,
{ " content " : " You are an expert at finding the next speaker. " , " role " : " assistant " } ,
{ " content " : " Product_Manager " , " role " : " user " } ,
{ " content " : " UPDATED_BELOW " , " role " : " user " } ,
] ,
)
### Agent selected successfully
chat_result . chat_history [ 3 ] [ " content " ] = " [AGENT SELECTED]Product_Manager "
# Product_Manager should be returned
assert groupchat . _process_speaker_selection_result ( chat_result , cmo , agent_list ) == pm
### Agent not selected successfully
chat_result . chat_history [ 3 ] [
" content "
] = " [AGENT SELECTION FAILED]Select speaker attempt #3 of 3 failed as it did not include any agent names. "
# The next speaker in the list will be selected, which will be the Product_Manager (as the last speaker is the Chief_Marketing_Officer)
assert groupchat . _process_speaker_selection_result ( chat_result , cmo , agent_list ) == pm
### Invalid result messages, will return the next agent
chat_result . chat_history [ 3 ] [ " content " ] = " This text should not be here. "
# The next speaker in the list will be selected, which will be the Chief_Marketing_Officer (as the last speaker is the Product_Maanger)
assert groupchat . _process_speaker_selection_result ( chat_result , pm , agent_list ) == cmo
def test_speaker_selection_validate_speaker_name ( ) :
"""
Tests the speaker name validation function used to evaluate the return result of the LLM
during speaker selection in ' auto ' mode .
Function : _validate_speaker_name
If a single agent name is returned by the LLM , it will add a relevant message to the chat messages and return True , None
If multiple agent names are returned and there are attempts left , it will return a message to be used to prompt the LLM to try again
If multiple agent names are return and there are no attempts left , it will add a relevant message to the chat messages and return True , None
If no agent names are returned and there are attempts left , it will return a message to be used to prompt the LLM to try again
If no agent names are returned and there are no attempts left , it will add a relevant message to the chat messages and return True , None
When returning a message , it will include the ' override_role ' key and value to support the GroupChat role_for_select_speaker_messages attribute
"""
# Group Chat setup
cmo = autogen . ConversableAgent (
name = " Chief_Marketing_Officer " ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is alice speaking. " ,
)
pm = autogen . ConversableAgent (
name = " Product_Manager " ,
human_input_mode = " NEVER " ,
llm_config = False ,
default_auto_reply = " This is bob speaking. " ,
function_map = { " test_func " : lambda x : x } ,
)
agent_list = [ cmo , pm ]
agent_list_string = f " { [ agent . name for agent in agent_list ] } "
groupchat = autogen . GroupChat ( agents = agent_list , messages = [ ] , max_round = 3 )
# Speaker Selection 2-agent chat setup
# Agent for selecting a single agent name from the response
speaker_selection_agent = autogen . ConversableAgent (
" speaker_selection_agent " ,
)
# Agent for checking the response from the speaker_select_agent
checking_agent = autogen . ConversableAgent ( " checking_agent " )
# Select speaker messages
select_speaker_messages = [
{
" content " : " Let ' s get this meeting started. First the Product_Manager will create 3 new product ideas. " ,
" name " : " Chairperson " ,
" role " : " assistant " ,
} ,
{ " content " : " You are an expert at finding the next speaker. " , " role " : " assistant " } ,
{ " content " : " UPDATED_BELOW " , " role " : " user " } ,
]
### Single agent name returned
attempts_left = 2
attempt = 1
select_speaker_messages [ - 1 ] [ " content " ] = " Product_Manager is the next to speak "
result = groupchat . _validate_speaker_name (
recipient = checking_agent ,
messages = select_speaker_messages ,
sender = speaker_selection_agent ,
config = None ,
attempts_left = attempts_left ,
attempt = attempt ,
agents = agent_list ,
)
assert result == ( True , None )
assert select_speaker_messages [ - 1 ] [ " content " ] == " [AGENT SELECTED]Product_Manager "
select_speaker_messages . pop ( - 1 ) # Remove the last message before the next test
### Multiple agent names returned with attempts left
attempts_left = 2
attempt = 1
select_speaker_messages [ - 1 ] [ " content " ] = " Product_Manager must speak after the Chief_Marketing_Officer "
result = groupchat . _validate_speaker_name (
recipient = checking_agent ,
messages = select_speaker_messages ,
sender = speaker_selection_agent ,
config = None ,
attempts_left = attempts_left ,
attempt = attempt ,
agents = agent_list ,
)
assert result == (
True ,
{
" content " : groupchat . select_speaker_auto_multiple_template . format ( agentlist = agent_list_string ) ,
2024-08-20 14:08:26 +10:00
" name " : " checking_agent " ,
2024-04-30 14:16:08 +10:00
" override_role " : groupchat . role_for_select_speaker_messages ,
} ,
)
### Multiple agent names returned with no attempts left
attempts_left = 0
attempt = 1
select_speaker_messages [ - 1 ] [ " content " ] = " Product_Manager must speak after the Chief_Marketing_Officer "
result = groupchat . _validate_speaker_name (
recipient = checking_agent ,
messages = select_speaker_messages ,
sender = speaker_selection_agent ,
config = None ,
attempts_left = attempts_left ,
attempt = attempt ,
agents = agent_list ,
)
assert result == ( True , None )
assert (
select_speaker_messages [ - 1 ] [ " content " ]
== f " [AGENT SELECTION FAILED]Select speaker attempt # { attempt } of { attempt + attempts_left } failed as it returned multiple names. "
)
select_speaker_messages . pop ( - 1 ) # Remove the last message before the next test
### No agent names returned with attempts left
attempts_left = 3
attempt = 2
select_speaker_messages [ - 1 ] [ " content " ] = " The PM must speak after the CMO "
result = groupchat . _validate_speaker_name (
recipient = checking_agent ,
messages = select_speaker_messages ,
sender = speaker_selection_agent ,
config = None ,
attempts_left = attempts_left ,
attempt = attempt ,
agents = agent_list ,
)
assert result == (
True ,
{
" content " : groupchat . select_speaker_auto_none_template . format ( agentlist = agent_list_string ) ,
2024-08-20 14:08:26 +10:00
" name " : " checking_agent " ,
2024-04-30 14:16:08 +10:00
" override_role " : groupchat . role_for_select_speaker_messages ,
} ,
)
### Multiple agents returned with no attempts left
attempts_left = 0
attempt = 3
select_speaker_messages [ - 1 ] [ " content " ] = " The PM must speak after the CMO "
result = groupchat . _validate_speaker_name (
recipient = checking_agent ,
messages = select_speaker_messages ,
sender = speaker_selection_agent ,
config = None ,
attempts_left = attempts_left ,
attempt = attempt ,
agents = agent_list ,
)
assert result == ( True , None )
assert (
select_speaker_messages [ - 1 ] [ " content " ]
== f " [AGENT SELECTION FAILED]Select speaker attempt # { attempt } of { attempt + attempts_left } failed as it did not include any agent names. "
)
def test_select_speaker_auto_messages ( ) :
"""
In this test , two agents are part of a group chat which has customized select speaker " auto " multiple and no - name prompt messages . Both valid and empty string values will be used .
The expected behaviour is that the customized speaker selection " auto " messages will override the default values or throw exceptions if empty .
"""
agent1 = autogen . ConversableAgent (
" Alice " ,
description = " A wonderful employee named Alice. " ,
human_input_mode = " NEVER " ,
llm_config = False ,
)
agent2 = autogen . ConversableAgent (
" Bob " ,
description = " An amazing employee named Bob. " ,
human_input_mode = " NEVER " ,
llm_config = False ,
)
# Customised message for select speaker auto method where multiple agent names are returned
custom_multiple_names_msg = " You mentioned multiple names but we need just one. Select the best one. A reminder that the options are {agentlist} . "
# Customised message for select speaker auto method where no agent names are returned
custom_no_names_msg = " You forgot to select a single names and we need one, and only one. Select the best one. A reminder that the options are {agentlist} . "
# Test empty is_termination_msg function
groupchat = autogen . GroupChat (
agents = [ agent1 , agent2 ] ,
messages = [ ] ,
speaker_selection_method = " auto " ,
max_round = 10 ,
select_speaker_auto_multiple_template = custom_multiple_names_msg ,
select_speaker_auto_none_template = custom_no_names_msg ,
)
# Test using the _validate_speaker_name function, checking for the correct string and agentlist to be included
agents = [ agent1 , agent2 ]
messages = [ { " content " : " Alice and Bob should both speak. " , " name " : " speaker_selector " , " role " : " user " } ]
assert groupchat . _validate_speaker_name ( None , messages , None , None , 1 , 1 , agents ) == (
True ,
{
" content " : custom_multiple_names_msg . replace ( " {agentlist} " , " [ ' Alice ' , ' Bob ' ] " ) ,
2024-08-20 14:08:26 +10:00
" name " : " checking_agent " ,
2024-04-30 14:16:08 +10:00
" override_role " : groupchat . role_for_select_speaker_messages ,
} ,
)
messages = [ { " content " : " Fred should both speak. " , " name " : " speaker_selector " , " role " : " user " } ]
assert groupchat . _validate_speaker_name ( None , messages , None , None , 1 , 1 , agents ) == (
True ,
{
" content " : custom_no_names_msg . replace ( " {agentlist} " , " [ ' Alice ' , ' Bob ' ] " ) ,
2024-08-20 14:08:26 +10:00
" name " : " checking_agent " ,
2024-04-30 14:16:08 +10:00
" override_role " : groupchat . role_for_select_speaker_messages ,
} ,
)
# Test with empty strings
with pytest . raises ( ValueError , match = " select_speaker_auto_multiple_template cannot be empty or None. " ) :
groupchat = autogen . GroupChat (
agents = [ agent1 , agent2 ] ,
messages = [ ] ,
speaker_selection_method = " auto " ,
max_round = 10 ,
select_speaker_auto_multiple_template = " " ,
)
with pytest . raises ( ValueError , match = " select_speaker_auto_none_template cannot be empty or None. " ) :
groupchat = autogen . GroupChat (
agents = [ agent1 , agent2 ] ,
messages = [ ] ,
speaker_selection_method = " auto " ,
max_round = 10 ,
select_speaker_auto_none_template = " " ,
)
# Test with None
with pytest . raises ( ValueError , match = " select_speaker_auto_multiple_template cannot be empty or None. " ) :
groupchat = autogen . GroupChat (
agents = [ agent1 , agent2 ] ,
messages = [ ] ,
speaker_selection_method = " auto " ,
max_round = 10 ,
select_speaker_auto_multiple_template = None ,
)
with pytest . raises ( ValueError , match = " select_speaker_auto_none_template cannot be empty or None. " ) :
groupchat = autogen . GroupChat (
agents = [ agent1 , agent2 ] ,
messages = [ ] ,
speaker_selection_method = " auto " ,
max_round = 10 ,
select_speaker_auto_none_template = None ,
)
2024-05-11 08:56:25 +10:00
def test_manager_messages_to_string ( ) :
""" In this test we test the conversion of messages to a JSON string """
messages = [
{
" content " : " You are an expert at finding the next speaker. " ,
" role " : " system " ,
} ,
{
" content " : " Let ' s get this meeting started. First the Product_Manager will create 3 new product ideas. " ,
" name " : " Chairperson " ,
" role " : " assistant " ,
} ,
]
groupchat = GroupChat ( messages = messages , agents = [ ] )
manager = GroupChatManager ( groupchat )
# Convert the messages List[Dict] to a JSON string
converted_string = manager . messages_to_string ( messages )
# The conversion should match the original messages
assert json . loads ( converted_string ) == messages
def test_manager_messages_from_string ( ) :
""" In this test we test the conversion of a JSON string of messages to a messages List[Dict] """
messages_str = r """ [ { " content " : " You are an expert at finding the next speaker. " , " role " : " system " }, { " content " : " Let ' s get this meeting started. First the Product_Manager will create 3 new product ideas. " , " name " : " Chairperson " , " role " : " assistant " }] """
groupchat = GroupChat ( messages = [ ] , agents = [ ] )
manager = GroupChatManager ( groupchat )
# Convert the messages List[Dict] to a JSON string
messages = manager . messages_from_string ( messages_str )
# The conversion should match the original messages
assert messages_str == json . dumps ( messages )
def test_manager_resume_functions ( ) :
""" Tests functions within the resume chat functionality """
# Setup
coder = AssistantAgent ( name = " Coder " , llm_config = None )
groupchat = GroupChat ( messages = [ ] , agents = [ coder ] )
manager = GroupChatManager ( groupchat )
# Tests that messages are indeed passed in
with pytest . raises ( Exception ) :
manager . _valid_resume_messages ( messages = [ ] )
# Tests that the messages passed in match the agents of the group chat
messages = [
{
" content " : " You are an expert at finding the next speaker. " ,
" role " : " system " ,
} ,
{
" content " : " Let ' s get this meeting started. First the Product_Manager will create 3 new product ideas. " ,
" name " : " Chairperson " ,
" role " : " assistant " ,
} ,
]
# Chairperson does not exist as an agent
with pytest . raises ( Exception ) :
manager . _valid_resume_messages ( messages )
messages = [
{
" content " : " You are an expert at finding the next speaker. " ,
" role " : " system " ,
} ,
{
" content " : " Let ' s get this meeting started. First the Product_Manager will create 3 new product ideas. " ,
" name " : " Coder " ,
" role " : " assistant " ,
} ,
]
# Coder does exist as an agent, no error
manager . _valid_resume_messages ( messages )
# Tests termination message replacement
final_msg = (
" Let ' s get this meeting started. First the Product_Manager will create 3 new product ideas. TERMINATE this. "
)
messages = [
{
" content " : " You are an expert at finding the next speaker. " ,
" role " : " system " ,
} ,
{
" content " : final_msg ,
" name " : " Coder " ,
" role " : " assistant " ,
} ,
]
manager . _process_resume_termination ( remove_termination_string = " TERMINATE " , messages = messages )
# TERMINATE should be removed
assert messages [ - 1 ] [ " content " ] == final_msg . replace ( " TERMINATE " , " " )
2024-06-07 03:25:55 +05:30
# Tests termination message replacement with function
def termination_func ( x : str ) - > str :
if " APPROVED " in x :
x = x . replace ( " APPROVED " , " " )
else :
x = x . replace ( " TERMINATE " , " " )
return x
final_msg1 = " Product_Manager has created 3 new product ideas. APPROVED "
messages1 = [
{
" content " : " You are an expert at finding the next speaker. " ,
" role " : " system " ,
} ,
{
" content " : final_msg1 ,
" name " : " Coder " ,
" role " : " assistant " ,
} ,
]
manager . _process_resume_termination ( remove_termination_string = termination_func , messages = messages1 )
# APPROVED should be removed
assert messages1 [ - 1 ] [ " content " ] == final_msg1 . replace ( " APPROVED " , " " )
final_msg2 = " Idea has been approved. TERMINATE "
messages2 = [
{
" content " : " You are an expert at finding the next speaker. " ,
" role " : " system " ,
} ,
{
" content " : final_msg2 ,
" name " : " Coder " ,
" role " : " assistant " ,
} ,
]
manager . _process_resume_termination ( remove_termination_string = termination_func , messages = messages2 )
# TERMINATE should be removed, "approved" should still be present as the termination_func only replaces upper-cased "APPROVED".
assert messages2 [ - 1 ] [ " content " ] == final_msg2 . replace ( " TERMINATE " , " " )
assert " approved " in messages2 [ - 1 ] [ " content " ]
2024-05-11 08:56:25 +10:00
# Check if the termination string doesn't exist there's no replacing of content
final_msg = (
" Let ' s get this meeting started. First the Product_Manager will create 3 new product ideas. TERMINATE this. "
)
messages = [
{
" content " : " You are an expert at finding the next speaker. " ,
" role " : " system " ,
} ,
{
" content " : final_msg ,
" name " : " Coder " ,
" role " : " assistant " ,
} ,
]
manager . _process_resume_termination ( remove_termination_string = " THE-END " , messages = messages )
# It should not be changed
assert messages [ - 1 ] [ " content " ] == final_msg
# Test that it warns that the termination condition would match
manager . _is_termination_msg = lambda x : x . get ( " content " , " " ) . find ( " TERMINATE " ) > = 0
# Attach a handler to the logger so we can check the log output
log_stream = io . StringIO ( )
handler = logging . StreamHandler ( log_stream )
logger = logging . getLogger ( ) # Get the root logger
logger . addHandler ( handler )
# We should get a warning that TERMINATE is still in the messages
manager . _process_resume_termination ( remove_termination_string = " THE-END " , messages = messages )
# Get the logged output and check that the warning was provided.
log_output = log_stream . getvalue ( )
assert " WARNING: Last message meets termination criteria and this may terminate the chat. " in log_output
def test_manager_resume_returns ( ) :
""" Tests the return resume chat functionality """
# Test the return agent and message is correct
coder = AssistantAgent ( name = " Coder " , llm_config = None )
groupchat = GroupChat ( messages = [ ] , agents = [ coder ] )
manager = GroupChatManager ( groupchat )
messages = [
{
" content " : " You are an expert at coding. " ,
" role " : " system " ,
} ,
{
" content " : " Let ' s get coding, should I use Python? " ,
" name " : " Coder " ,
" role " : " assistant " ,
} ,
]
return_agent , return_message = manager . resume ( messages = messages )
assert return_agent == coder
assert return_message == messages [ - 1 ]
# Test when no agent provided, the manager will be returned
messages = [ { " content " : " You are an expert at coding. " , " role " : " system " , " name " : " chat_manager " } ]
return_agent , return_message = manager . resume ( messages = messages )
assert return_agent == manager
assert return_message == messages [ - 1 ]
def test_manager_resume_messages ( ) :
""" Tests that the messages passed into resume are the correct format """
coder = AssistantAgent ( name = " Coder " , llm_config = None )
groupchat = GroupChat ( messages = [ ] , agents = [ coder ] )
manager = GroupChatManager ( groupchat )
messages = 1
# Only acceptable messages types are JSON str and List[Dict]
# Try a number
with pytest . raises ( Exception ) :
return_agent , return_message = manager . resume ( messages = messages )
# Try an empty string
with pytest . raises ( Exception ) :
return_agent , return_message = manager . resume ( messages = " " )
# Try a message starter string, which isn't valid
with pytest . raises ( Exception ) :
return_agent , return_message = manager . resume ( messages = " Let ' s get this conversation started. " )
2024-08-26 13:47:48 +10:00
def test_select_speaker_transform_messages ( ) :
""" Tests adding transform messages to a GroupChat for speaker selection when in ' auto ' mode """
# Test adding a TransformMessages to a group chat
test_add_transforms = transform_messages . TransformMessages (
transforms = [
transforms . MessageHistoryLimiter ( max_messages = 10 ) ,
transforms . MessageTokenLimiter ( max_tokens = 3000 , max_tokens_per_message = 500 , min_tokens = 300 ) ,
]
)
coder = AssistantAgent ( name = " Coder " , llm_config = None )
groupchat = GroupChat ( messages = [ ] , agents = [ coder ] , select_speaker_transform_messages = test_add_transforms )
# Ensure the transform have been added to the GroupChat
assert groupchat . _speaker_selection_transforms == test_add_transforms
# Attempt to add a non MessageTransforms object, such as a list of transforms
with pytest . raises ( ValueError , match = " select_speaker_transform_messages must be None or MessageTransforms. " ) :
groupchat = GroupChat (
messages = [ ] ,
agents = [ coder ] ,
select_speaker_transform_messages = [ transforms . MessageHistoryLimiter ( max_messages = 10 ) ] ,
)
# Ensure if we don't pass any transforms in, none are on the GroupChat
groupchat_missing = GroupChat ( messages = [ ] , agents = [ coder ] )
assert groupchat_missing . _speaker_selection_transforms is None
# Ensure we can pass in None
groupchat_none = GroupChat (
messages = [ ] ,
agents = [ coder ] ,
select_speaker_transform_messages = None ,
)
assert groupchat_none . _speaker_selection_transforms is None
2023-08-03 02:17:20 -07:00
if __name__ == " __main__ " :
2023-11-17 21:56:11 +08:00
# test_func_call_groupchat()
2023-08-03 02:17:20 -07:00
# test_broadcast()
2023-11-17 21:56:11 +08:00
# test_chat_manager()
2023-10-19 07:43:36 -07:00
# test_plugin()
2024-01-14 10:24:05 -08:00
# test_speaker_selection_method()
2023-11-29 12:43:57 -08:00
# test_n_agents_less_than_3()
2023-11-16 18:30:24 -08:00
# test_agent_mentions()
2023-12-08 07:39:27 -08:00
# test_termination()
2024-01-14 10:24:05 -08:00
# test_next_agent()
2024-03-06 21:28:22 -05:00
# test_send_intros()
2024-01-27 20:14:03 +01:00
# test_invalid_allow_repeat_speaker()
2024-02-06 14:13:18 +11:00
# test_graceful_exit_before_max_round()
2024-02-24 08:50:46 -08:00
# test_clear_agents_history()
2024-04-01 09:54:17 +11:00
# test_custom_speaker_selection_overrides_transition_graph()
2024-04-02 00:49:13 +11:00
# test_role_for_select_speaker_messages()
2024-06-07 03:25:55 +05:30
# test_select_speaker_message_and_prompt_templates()
2024-04-30 14:16:08 +10:00
# test_speaker_selection_agent_name_match()
2024-05-14 03:46:01 -03:00
# test_role_for_reflection_summary()
# test_speaker_selection_auto_process_result()
# test_speaker_selection_validate_speaker_name()
# test_select_speaker_auto_messages()
2024-05-11 08:56:25 +10:00
# test_select_speaker_auto_messages()
2024-05-14 03:46:01 -03:00
# test_manager_messages_to_string()
# test_manager_messages_from_string()
2024-06-07 03:25:55 +05:30
test_manager_resume_functions ( )
2024-05-14 03:46:01 -03:00
# test_manager_resume_returns()
# test_manager_resume_messages()
2024-08-26 13:47:48 +10:00
# test_select_speaker_transform_messages()
2024-05-14 03:46:01 -03:00
pass