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 4 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
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,10 +119,10 @@ 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_auto_reply([Agent, None], ConversableAgent.generate_oai_reply)
self.register_auto_reply([Agent, None], ConversableAgent.generate_code_execution_reply)
self.register_auto_reply([Agent, None], ConversableAgent.generate_function_call_reply)
self.register_auto_reply([Agent, None], ConversableAgent.check_termination_and_human_reply)

def register_auto_reply(
self,
Expand Down Expand Up @@ -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
6 changes: 3 additions & 3 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 @@ -38,7 +38,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 @@ -62,7 +62,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 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_auto_reply`)[conversable_agent#register_auto_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
6 changes: 3 additions & 3 deletions notebook/autogen_agentchat_chess.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,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_auto_reply(autogen.ConversableAgent, BoardAgent._generate_board_reply)\n",
" self.board = board\n",
" self.correct_move_messages = defaultdict(list)\n",
"\n",
Expand Down Expand Up @@ -261,7 +261,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 Expand Up @@ -1009,7 +1009,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.16"
"version": "3.9.17"
},
"orig_nbformat": 4
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
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 = 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_auto_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"))
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")
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"
assert agent1.last_message(agent)["content"] == "hello conversable agent"
agent.register_auto_reply(
lambda sender: sender.name.startswith("a"), lambda recipient, messages, sender, config: (True, "hello a")
)
Expand All @@ -41,8 +41,8 @@ def test_trigger():


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)
10 changes: 5 additions & 5 deletions test/autogen/agentchat/test_groupchat.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@


def test_chat_manager():
agent1 = autogen.ResponsiveAgent(
agent1 = autogen.ConversableAgent(
"alice",
max_consecutive_auto_reply=2,
human_input_mode="NEVER",
llm_config=False,
default_auto_reply="This is alice sepaking.",
)
agent2 = autogen.ResponsiveAgent(
agent2 = autogen.ConversableAgent(
"bob",
max_consecutive_auto_reply=2,
human_input_mode="NEVER",
Expand All @@ -33,22 +33,22 @@ def test_chat_manager():

def test_plugin():
# Give another Agent class ability to manage group chat
agent1 = autogen.ResponsiveAgent(
agent1 = autogen.ConversableAgent(
"alice",
max_consecutive_auto_reply=2,
human_input_mode="NEVER",
llm_config=False,
default_auto_reply="This is alice sepaking.",
)
agent2 = autogen.ResponsiveAgent(
agent2 = autogen.ConversableAgent(
"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)
group_chat_manager = autogen.ResponsiveAgent(name="deputy_manager", llm_config=False)
group_chat_manager = autogen.ConversableAgent(name="deputy_manager", llm_config=False)
group_chat_manager.register_auto_reply(
autogen.Agent,
reply_func=autogen.GroupChatManager.run_chat,
Expand Down
4 changes: 2 additions & 2 deletions website/docs/Use-Cases/Autogen.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ The package is under active development with more features upcoming.

### Basic Concept

We have designed a generic `ResponsiveAgent` class for Agents that are capable of conversing with each other through the exchange of messages to jointly finish a task. An agent can communicate with other agents and perform actions. Different agents can differ in what actions they perform after receiving messages. Two representative subclasses are `AssistantAgent` and `UserProxyAgent`.
We have designed a generic `ConversableAgent` class for Agents that are capable of conversing with each other through the exchange of messages to jointly finish a task. An agent can communicate with other agents and perform actions. Different agents can differ in what actions they perform after receiving messages. Two representative subclasses are `AssistantAgent` and `UserProxyAgent`.

- `AssistantAgent`. Designed to act as an assistant by responding to user requests. It could write Python code (in a Python coding block) for a user to execute when a message (typically a description of a task that needs to be solved) is received. Under the hood, the Python code is written by LLM (e.g., GPT-4). It can also receive the execution results and suggest code with bug fix. Its behavior can be altered by passing a new system message. The LLM [inference](#enhanced-inference) configuration can be configured via `llm_config`.
- `UserProxyAgent`. Serves as a proxy for the human user. Upon receiving a message, the UserProxyAgent will either solicit the human user's input or prepare an automatically generated reply. The chosen action depends on the settings of the `human_input_mode` and `max_consecutive_auto_reply` when the `UserProxyAgent` instance is constructed, and whether a human user input is available.
By default, the automatically generated reply is crafted based on automatic code execution. The `UserProxyAgent` triggers code execution automatically when it detects an executable code block in the received message and no human user input is provided. Code execution can be disabled by setting `code_execution_config` to False. LLM-based response is disabled by default. It can be enabled by setting `llm_config` to a dict corresponding to the [inference](#enhanced-inference) configuration.
When `llm_config` is set to a dict, `UserProxyAgent` can generate replies using an LLM when code execution is not performed.

The auto-reply capability of `ResponsiveAgent` allows for more autonomous multi-agent communication while retaining the possibility of human intervention.
The auto-reply capability of `ConversableAgent` allows for more autonomous multi-agent communication while retaining the possibility of human intervention.
One can also easily extend it by registering auto_reply functions with the `register_auto_reply()` method.

### Basic Example
Expand Down
Loading