Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename Responsive -> Conversable #1202

Merged
merged 12 commits into from
Sep 12, 2023
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
4 changes: 2 additions & 2 deletions flaml/autogen/agentchat/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from .agent import Agent
from .responsive_agent import ResponsiveAgent
from .conversable_agent import ConversableAgent
from .assistant_agent import AssistantAgent
from .user_proxy_agent import UserProxyAgent
from .groupchat import GroupChat, GroupChatManager

__all__ = [
"Agent",
"ResponsiveAgent",
"ConversableAgent",
"AssistantAgent",
"UserProxyAgent",
"GroupChat",
Expand Down
8 changes: 4 additions & 4 deletions flaml/autogen/agentchat/assistant_agent.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from .responsive_agent import ResponsiveAgent
from .conversable_agent import ConversableAgent
from typing import Callable, Dict, Optional, Union


class AssistantAgent(ResponsiveAgent):
class AssistantAgent(ConversableAgent):
"""(In preview) Assistant agent, designed to solve a task with LLM.

AssistantAgent is a subclass of ResponsiveAgent configured with a default system message.
AssistantAgent is a subclass of ConversableAgent configured with a default system message.
The default system message is designed to solve a task with LLM,
including suggesting python code blocks and debugging.
`human_input_mode` is default to "NEVER"
Expand Down Expand Up @@ -52,7 +52,7 @@ def __init__(
default to None (no limit provided, class attribute MAX_CONSECUTIVE_AUTO_REPLY will be used as the limit in this case).
The limit only plays a role when human_input_mode is not "ALWAYS".
**kwargs (dict): Please refer to other kwargs in
[ResponsiveAgent](responsive_agent#__init__).
[ConversableAgent](conversable_agent#__init__).
"""
super().__init__(
name,
Expand Down
2 changes: 1 addition & 1 deletion flaml/autogen/agentchat/contrib/math_user_proxy_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ def __init__(
default_auto_reply=default_auto_reply,
**kwargs,
)
self.register_auto_reply([Agent, None], MathUserProxyAgent._generate_math_reply, 1)
self.register_reply([Agent, None], MathUserProxyAgent._generate_math_reply, 1)
# fixed var
self._max_invalid_q_per_step = max_invalid_q_per_step

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class RetrieveAssistantAgent(AssistantAgent):

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.register_auto_reply(Agent, RetrieveAssistantAgent._generate_retrieve_assistant_reply)
self.register_reply(Agent, RetrieveAssistantAgent._generate_retrieve_assistant_reply)

def _generate_retrieve_assistant_reply(
self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ def __init__(
self._ipython = get_ipython()
self._doc_idx = -1 # the index of the current used doc
self._results = {} # the results of the current query
self.register_auto_reply(Agent, RetrieveUserProxyAgent._generate_retrieve_user_reply)
self.register_reply(Agent, RetrieveUserProxyAgent._generate_retrieve_user_reply)

@staticmethod
def get_max_tokens(model="gpt-3.5-turbo"):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ def colored(x, *args, **kwargs):
return x


class ResponsiveAgent(Agent):
"""(Experimental) A class for generic responsive agents which can be configured as assistant or user proxy.
class ConversableAgent(Agent):
"""(In preview) A class for generic conversable agents which can be configured as assistant or user proxy.

After receiving each message, the agent will send a reply to the sender unless the msg is a termination msg.
For example, AssistantAgent and UserProxyAgent are subclasses of ResponsiveAgent,
For example, AssistantAgent and UserProxyAgent are subclasses of this class,
configured with different default settings.

To modify auto reply, override `generate_reply` method.
Expand Down Expand Up @@ -119,12 +119,12 @@ def __init__(
self._default_auto_reply = default_auto_reply
self._reply_func_list = []
self.reply_at_receive = defaultdict(bool)
self.register_auto_reply([Agent, None], ResponsiveAgent.generate_oai_reply)
self.register_auto_reply([Agent, None], ResponsiveAgent.generate_code_execution_reply)
self.register_auto_reply([Agent, None], ResponsiveAgent.generate_function_call_reply)
self.register_auto_reply([Agent, None], ResponsiveAgent.check_termination_and_human_reply)
self.register_reply([Agent, None], ConversableAgent.generate_oai_reply)
self.register_reply([Agent, None], ConversableAgent.generate_code_execution_reply)
self.register_reply([Agent, None], ConversableAgent.generate_function_call_reply)
self.register_reply([Agent, None], ConversableAgent.check_termination_and_human_reply)

def register_auto_reply(
def register_reply(
self,
trigger: Union[Type[Agent], str, Agent, Callable[[Agent], bool], List],
reply_func: Callable,
Expand All @@ -151,7 +151,7 @@ def register_auto_reply(
The function takes a recipient agent, a list of messages, a sender agent and a config as input and returns a reply message.
```python
def reply_func(
recipient: ResponsiveAgent,
recipient: ConversableAgent,
messages: Optional[List[Dict]] = None,
sender: Optional[Agent] = None,
config: Optional[Any] = None,
Expand Down Expand Up @@ -499,7 +499,7 @@ def _prepare_chat(self, recipient, clear_history):

def initiate_chat(
self,
recipient: "ResponsiveAgent",
recipient: "ConversableAgent",
clear_history: Optional[bool] = True,
silent: Optional[bool] = False,
**context,
Expand All @@ -522,7 +522,7 @@ def initiate_chat(

async def a_initiate_chat(
self,
recipient: "ResponsiveAgent",
recipient: "ConversableAgent",
clear_history: Optional[bool] = True,
silent: Optional[bool] = False,
**context,
Expand Down Expand Up @@ -610,8 +610,8 @@ def generate_code_execution_reply(
return False, None
if messages is None:
messages = self._oai_messages[sender]
last_n_messages = min(len(messages), code_execution_config.pop("last_n_messages", 1))
for i in range(last_n_messages):
last_n_messages = code_execution_config.pop("last_n_messages", 1)
for i in range(min(len(messages), last_n_messages)):
message = messages[-(i + 1)]
code_blocks = extract_code(message["content"])
if len(code_blocks) == 1 and code_blocks[0][0] == UNKNOWN:
Expand Down
8 changes: 4 additions & 4 deletions flaml/autogen/agentchat/groupchat.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import sys
from typing import Dict, List, Optional, Union
from .agent import Agent
from .responsive_agent import ResponsiveAgent
from .conversable_agent import ConversableAgent


@dataclass
Expand Down Expand Up @@ -39,7 +39,7 @@ def select_speaker_msg(self):
Read the following conversation.
Then select the next role from {self.agent_names} to play. Only return the role."""

def select_speaker(self, last_speaker: Agent, selector: ResponsiveAgent):
def select_speaker(self, last_speaker: Agent, selector: ConversableAgent):
"""Select the next speaker."""
selector.update_system_message(self.select_speaker_msg())
final, name = selector.generate_oai_reply(
Expand All @@ -63,7 +63,7 @@ def _participant_roles(self):
return "\n".join([f"{agent.name}: {agent.system_message}" for agent in self.agents])


class GroupChatManager(ResponsiveAgent):
class GroupChatManager(ConversableAgent):
"""(In preview) A chat manager agent that can manage a group chat of multiple agents."""

def __init__(
Expand All @@ -84,7 +84,7 @@ def __init__(
system_message=system_message,
**kwargs,
)
self.register_auto_reply(Agent, GroupChatManager.run_chat, config=groupchat, reset_config=GroupChat.reset)
self.register_reply(Agent, GroupChatManager.run_chat, config=groupchat, reset_config=GroupChat.reset)
# self._random = random.Random(seed)

def run_chat(
Expand Down
8 changes: 4 additions & 4 deletions flaml/autogen/agentchat/user_proxy_agent.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
from .responsive_agent import ResponsiveAgent
from .conversable_agent import ConversableAgent
from typing import Callable, Dict, Optional, Union


class UserProxyAgent(ResponsiveAgent):
class UserProxyAgent(ConversableAgent):
"""(In preview) A proxy agent for the user, that can execute code and provide feedback to the other agents.

UserProxyAgent is a subclass of ResponsiveAgent configured with `human_input_mode` to ALWAYS
UserProxyAgent is a subclass of ConversableAgent configured with `human_input_mode` to ALWAYS
and `llm_config` to False. By default, the agent will prompt for human input every time a message is received.
Code execution is enabled by default. LLM-based auto reply is disabled by default.
To modify auto reply, register a method with (`register_auto_reply`)[responsive_agent#register_auto_reply].
To modify auto reply, register a method with (`register_reply`)[conversable_agent#register_reply].
To modify the way to get human input, override `get_human_input` method.
To modify the way to execute code blocks, single code block, or function call, override `execute_code_blocks`,
`run_code`, and `execute_function` methods respectively.
Expand Down
2 changes: 1 addition & 1 deletion flaml/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "2.0.3"
__version__ = "2.1.0"
10 changes: 5 additions & 5 deletions notebook/autogen_agentchat_chess.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"outputs": [],
"source": [
"%%capture --no-stderr\n",
"# %pip install flaml[autogen]~=2.0.0\n",
"# %pip install flaml[autogen]~=2.1.0\n",
"%pip install chess -U"
]
},
Expand Down Expand Up @@ -158,7 +158,7 @@
" llm_config={\"temperature\": 0.0, \"config_list\": config_list_gpt4},\n",
" max_consecutive_auto_reply=10,\n",
" )\n",
" self.register_auto_reply(autogen.ResponsiveAgent, BoardAgent._generate_board_reply)\n",
" self.register_reply(autogen.ConversableAgent, BoardAgent._generate_board_reply)\n",
" self.board = board\n",
" self.correct_move_messages = defaultdict(list)\n",
"\n",
Expand Down Expand Up @@ -226,8 +226,8 @@
" max_consecutive_auto_reply=max_turns,\n",
" **kwargs,\n",
" )\n",
" self.register_auto_reply(BoardAgent, ChessPlayerAgent._generate_reply_for_board, config=board_agent.board)\n",
" self.register_auto_reply(ChessPlayerAgent, ChessPlayerAgent._generate_reply_for_player, config=board_agent)\n",
" self.register_reply(BoardAgent, ChessPlayerAgent._generate_reply_for_board, config=board_agent.board)\n",
" self.register_reply(ChessPlayerAgent, ChessPlayerAgent._generate_reply_for_player, config=board_agent)\n",
" self.update_max_consecutive_auto_reply(board_agent.max_consecutive_auto_reply(), board_agent)\n",
"\n",
" def _generate_reply_for_board(\n",
Expand Down Expand Up @@ -262,7 +262,7 @@
" return True, None\n",
" # converse with the board until a legal move is made or max allowed retries.\n",
" # change silent to False to see that conversation.\n",
" self.initiate_chat(board_agent, clear_history=False, message=message, silent=True)\n",
" self.initiate_chat(board_agent, clear_history=False, message=message, silent=self.human_input_mode == \"NEVER\")\n",
" # last message sent by the board agent\n",
" last_message = self._oai_messages[board_agent][-1]\n",
" if last_message[\"role\"] == \"assistant\":\n",
Expand Down
4 changes: 2 additions & 2 deletions notebook/autogen_agentchat_stream.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
},
"outputs": [],
"source": [
"# %pip install flaml[autogen]~=2.0.0"
"# %pip install flaml[autogen]~=2.1.0"
]
},
{
Expand Down Expand Up @@ -258,7 +258,7 @@
" )\n",
" return False, None\n",
"\n",
"user_proxy.register_auto_reply(autogen.AssistantAgent, add_data_reply, 1, config={\"news_stream\": data})"
"user_proxy.register_reply(autogen.AssistantAgent, add_data_reply, 1, config={\"news_stream\": data})"
]
},
{
Expand Down
2 changes: 1 addition & 1 deletion test/autogen/agentchat/test_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ async def add_data_reply(recipient, messages, sender, config):
)
return False, None

user_proxy.register_auto_reply(autogen.AssistantAgent, add_data_reply, 1, config={"news_stream": data})
user_proxy.register_reply(autogen.AssistantAgent, add_data_reply, 1, config={"news_stream": data})

await user_proxy.a_initiate_chat(
assistant,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,48 +1,48 @@
import pytest
from flaml.autogen.agentchat import ResponsiveAgent
from flaml.autogen.agentchat import ConversableAgent


def test_trigger():
agent = ResponsiveAgent("a0", max_consecutive_auto_reply=0, llm_config=False, human_input_mode="NEVER")
agent1 = ResponsiveAgent("a1", max_consecutive_auto_reply=0, human_input_mode="NEVER")
agent.register_auto_reply(agent1, lambda recipient, messages, sender, config: (True, "hello"))
agent = ConversableAgent("a0", max_consecutive_auto_reply=0, llm_config=False, human_input_mode="NEVER")
agent1 = ConversableAgent("a1", max_consecutive_auto_reply=0, human_input_mode="NEVER")
agent.register_reply(agent1, lambda recipient, messages, sender, config: (True, "hello"))
agent1.initiate_chat(agent, message="hi")
assert agent1.last_message(agent)["content"] == "hello"
agent.register_auto_reply("a1", lambda recipient, messages, sender, config: (True, "hello a1"))
agent.register_reply("a1", lambda recipient, messages, sender, config: (True, "hello a1"))
agent1.initiate_chat(agent, message="hi")
assert agent1.last_message(agent)["content"] == "hello a1"
agent.register_auto_reply(
ResponsiveAgent, lambda recipient, messages, sender, config: (True, "hello responsive agent")
agent.register_reply(
ConversableAgent, lambda recipient, messages, sender, config: (True, "hello conversable agent")
)
agent1.initiate_chat(agent, message="hi")
assert agent1.last_message(agent)["content"] == "hello responsive agent"
agent.register_auto_reply(
assert agent1.last_message(agent)["content"] == "hello conversable agent"
agent.register_reply(
lambda sender: sender.name.startswith("a"), lambda recipient, messages, sender, config: (True, "hello a")
)
agent1.initiate_chat(agent, message="hi")
assert agent1.last_message(agent)["content"] == "hello a"
agent.register_auto_reply(
agent.register_reply(
lambda sender: sender.name.startswith("b"), lambda recipient, messages, sender, config: (True, "hello b")
)
agent1.initiate_chat(agent, message="hi")
assert agent1.last_message(agent)["content"] == "hello a"
agent.register_auto_reply(
agent.register_reply(
["agent2", agent1], lambda recipient, messages, sender, config: (True, "hello agent2 or agent1")
)
agent1.initiate_chat(agent, message="hi")
assert agent1.last_message(agent)["content"] == "hello agent2 or agent1"
agent.register_auto_reply(
agent.register_reply(
["agent2", "agent3"], lambda recipient, messages, sender, config: (True, "hello agent2 or agent3")
)
agent1.initiate_chat(agent, message="hi")
assert agent1.last_message(agent)["content"] == "hello agent2 or agent1"
pytest.raises(ValueError, agent.register_auto_reply, 1, lambda recipient, messages, sender, config: (True, "hi"))
pytest.raises(ValueError, agent.register_reply, 1, lambda recipient, messages, sender, config: (True, "hi"))
pytest.raises(ValueError, agent._match_trigger, 1, agent1)


def test_context():
agent = ResponsiveAgent("a0", max_consecutive_auto_reply=0, llm_config=False, human_input_mode="NEVER")
agent1 = ResponsiveAgent("a1", max_consecutive_auto_reply=0, human_input_mode="NEVER")
agent = ConversableAgent("a0", max_consecutive_auto_reply=0, llm_config=False, human_input_mode="NEVER")
agent1 = ConversableAgent("a1", max_consecutive_auto_reply=0, human_input_mode="NEVER")
agent1.send(
{
"content": "hello {name}",
Expand Down Expand Up @@ -77,8 +77,8 @@ def test_context():


def test_max_consecutive_auto_reply():
agent = ResponsiveAgent("a0", max_consecutive_auto_reply=2, llm_config=False, human_input_mode="NEVER")
agent1 = ResponsiveAgent("a1", max_consecutive_auto_reply=0, human_input_mode="NEVER")
agent = ConversableAgent("a0", max_consecutive_auto_reply=2, llm_config=False, human_input_mode="NEVER")
agent1 = ConversableAgent("a1", max_consecutive_auto_reply=0, human_input_mode="NEVER")
assert agent.max_consecutive_auto_reply() == agent.max_consecutive_auto_reply(agent1) == 2
agent.update_max_consecutive_auto_reply(1)
assert agent.max_consecutive_auto_reply() == agent.max_consecutive_auto_reply(agent1) == 1
Expand All @@ -105,9 +105,9 @@ def test_max_consecutive_auto_reply():
assert agent1.reply_at_receive[agent] is False and agent.reply_at_receive[agent1] is True


def test_responsive_agent():
dummy_agent_1 = ResponsiveAgent(name="dummy_agent_1", human_input_mode="ALWAYS")
dummy_agent_2 = ResponsiveAgent(name="dummy_agent_2", human_input_mode="TERMINATE")
def test_conversable_agent():
dummy_agent_1 = ConversableAgent(name="dummy_agent_1", human_input_mode="ALWAYS")
dummy_agent_2 = ConversableAgent(name="dummy_agent_2", human_input_mode="TERMINATE")

# monkeypatch.setattr(sys, "stdin", StringIO("exit"))
dummy_agent_1.receive("hello", dummy_agent_2) # receive a str
Expand Down Expand Up @@ -159,7 +159,7 @@ def add_num(num_to_be_added):
given_num = 10
return num_to_be_added + given_num

dummy_agent_2 = ResponsiveAgent(name="user_proxy", human_input_mode="TERMINATE", function_map={"add_num": add_num})
dummy_agent_2 = ConversableAgent(name="user_proxy", human_input_mode="TERMINATE", function_map={"add_num": add_num})
messsages = [{"function_call": {"name": "add_num", "arguments": '{ "num_to_be_added": 5 }'}, "role": "assistant"}]

# when sender is None, messages is provided
Expand All @@ -168,7 +168,7 @@ def add_num(num_to_be_added):
), "generate_reply not working when sender is None"

# when sender is provided, messages is None
dummy_agent_1 = ResponsiveAgent(name="dummy_agent_1", human_input_mode="ALWAYS")
dummy_agent_1 = ConversableAgent(name="dummy_agent_1", human_input_mode="ALWAYS")
dummy_agent_2._oai_messages[dummy_agent_1] = messsages
assert (
dummy_agent_2.generate_reply(messages=None, sender=dummy_agent_1)["content"] == "15"
Expand All @@ -179,4 +179,4 @@ def add_num(num_to_be_added):
test_trigger()
# test_context()
# test_max_consecutive_auto_reply()
# test_responsive_agent(pytest.monkeypatch)
# test_conversable_agent(pytest.monkeypatch)
Loading
Loading