microsoft / autogen

A programming framework for agentic AI 🤖
https://microsoft.github.io/autogen/
Creative Commons Attribution 4.0 International
30.97k stars 4.52k forks source link

Getting messages from the "agent" to the "groupchat manager": #3279

Closed sujan-sarker closed 1 month ago

sujan-sarker commented 1 month ago

Describe the issue

Hi, I am working on a project using the group chat manager to manage chats among multiple agents. We register a reply function to get sender, receiver, and message content whenever an agent sends a reply. However, it turned out that it only works for chat managers rather than for individual agents. Do you have any solution for that? I found the same problem in the following issue but couldn't find any solution. https://github.com/microsoft/autogen/discussions/1050

Steps to reproduce

No response

Screenshots and logs

No response

Additional Information

No response

wenngong commented 1 month ago

@sujan-sarker Could you please post the example codes to reproduce you problem?

sujan-sarker commented 1 month ago

Hi Wenngong, I appreciate your reply. The following is the code I was running. I want the print_and_store_messages function to be called whenever any of the agents sends a message. However, it only works for the chat manager; that is, it only prints message information when the chat manager sends it.

from autogen import ConversableAgent, GroupChat, GroupChatManager

LLM configuration

llm_config = {"model": "gpt-4-turbo"} task = "Proxy: Cooperative storytelling with two virtual NAO robots and one human."

message_log = ""

Callback function to print and store messages

def print_and_store_messages(recipient, messages, sender, config): global message_log if "callback" in config and config["callback"] is not None: callback = config["callback"] callback(sender, recipient, messages[-1])

# Print the message immediately
print(f"Sender: {sender.name} | Recipient: {recipient.name} | Message: {messages[-1].get('content')}")

return False, None  # Required to ensure the agent communication flow continues

Function to start the server and manage chat

def start_server(): global message_log

# Define the roles and system messages for each agent
proxy_agent = ConversableAgent(
    name="ProxyAgent",
    system_message=(
        "You are the proxy agent representing the human participant. "
        "Start the story and interact with the  other agents (agent1 and agent2)"
        "Your contributions should be concise and keep the story progressing quickly. "

        "Focus on setting the scene and resolving the story efficiently."
    ),
    llm_config=llm_config,
    human_input_mode="ALWAYS",
)

agent1 = ConversableAgent(
    name="Agent1",
    system_message=(
        "You are a storytelling agent . "
        "Contribute to the story with creative ideas and interact with the ProxyAgent and Agent2. "
        "Make sure to say your name first before any content
        "Say who you want to go next at the end, agent 2 or proxy agent"

        "Keep your contributions brief and to the point. "
        "Focus on adding plot twists or character actions, and help resolve the story quickly."
    ),
    llm_config=llm_config,
)

agent2 = ConversableAgent(
    name="Agent2",
    system_message=(
        "You are a storytelling agent. "
        "Your role is to add humor or unexpected elements to the story. "
        "Interact with ProxyAgent and Agent1, keeping your contributions short. "
        "Make sure to say your name first before any content."
        "Aim to add closure to the story swiftly, ensuring it's entertaining and engaging."
    ),
    llm_config=llm_config,
)

proxy_agent.register_reply(
    [ConversableAgent, None],
    reply_func=print_and_store_messages,
    config={"callback": None},
)

agent1.register_reply(
    [ConversableAgent, None],
    reply_func=print_and_store_messages,
    config={"callback": None},
)

agent2.register_reply(
    [ConversableAgent, None],
    reply_func=print_and_store_messages,
    config={"callback": None},
)

# Setup the group chat
groupchat = GroupChat(
    agents=[proxy_agent, agent1, agent2],
    messages=[],
    max_round=6,
    allowed_or_disallowed_speaker_transitions={
        proxy_agent: [agent1, agent2],
        robot1: [proxy_agent, agent2],
        robot2: [proxy_agent, agent1],
    },
    speaker_transitions_type="allowed",
)

# Manager to manage the group chat
manager = GroupChatManager(
    groupchat=groupchat, llm_config=llm_config
)

try:
    # while True:
    # Start the conversation
    groupchat_result = proxy_agent.initiate_chat(
        manager,
        message=task,
    )
finally:
    pass

if name == 'main': start_server()

thinkall commented 1 month ago

Hi @sujan-sarker , with your code, the print_and_store_messages will be called each time any agent send a message.

I want the print_and_store_messages function to be called whenever any of the agents sends a message.

I've verified it in the agentchat_groupchat.ipynb by adding such a print message function to the agents. image

sujan-sarker commented 1 month ago

Hi @thinkall This also works for me. However, the problem is that when user_proxy or other agents send a message to the chat_manager, we cannot invoke this message for that. For example, I want something like that, Sender: User_proxy receiver: chat_manger ...... that is, when any agent sends a message to chat_manager, the callback function should be invoked, and it should be received at that time. Can you please check this part.

thinkall commented 1 month ago

Sender: User_proxy receiver: chat_manger ......

Hi @sujan-sarker , any message chat_manager sends out is actually received from another agent. That to say, you can invoke the callbacks when "Sender: chat_manager receiver: coder ...".

Say agent A send a message to chat_manager, you want to call the callback, but you can't, because in a group chat, you never see the receiver to be chat_manager. However, chat_manager will send this message to the next agent B, so you can call the callback function when B receives the message. The message and the callback function will be exactly the same.

Would this work for you?

sujan-sarker commented 1 month ago

Hi, I highly appreciate your answer. I have two questions.

  1. Is there any way to invoke the callback whenever an agent sends the message to the chat manager in group chat ?
  2. I actually need the sender information. For example, say agent A sends a message and the chat manager forwards it to agent B. Using the code I can invoke the callback when the chat manager sends the message of A to agent B. So callback prints, sender: chat manager and receiver: B. How can I get the original sender information (i.e., A)?

On Tue, Aug 6, 2024, 10:36 PM Li Jiang @.***> wrote:

Sender: User_proxy receiver: chat_manger ......

Hi @sujan-sarker https://github.com/sujan-sarker , any message chat_manager sends out is actually received from another agent. That to say, you can invoke the callbacks when "Sender: chat_manager receiver: coder ...".

Say agent A send a message to chat_manager, you want to call the callback, but you can't, because in a group chat, you never see the receiver to be chat_manager. However, chat_manager will send this message to the next agent B, so you can call the callback function when B receives the message. The message and the callback function will be exactly the same.

Would this work for you?

— Reply to this email directly, view it on GitHub https://github.com/microsoft/autogen/issues/3279#issuecomment-2272505453, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABX7ZJTOQZD3G4IA6U2325DZQGB4PAVCNFSM6AAAAABL33QCESVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENZSGUYDKNBVGM . You are receiving this because you were mentioned.Message ID: @.***>

thinkall commented 1 month ago

Hi, I highly appreciate your answer. I have two questions. 1. Is there any way to invoke the callback whenever an agent sends the message to the chat manager in group chat ? 2. I actually need the sender information. For example, say agent A sends a message and the chat manager forwards it to agent B. Using the code I can invoke the callback when the chat manager sends the message of A to agent B. So callback prints, sender: chat manager and receiver: B. How can I get the original sender information (i.e., A)? … On Tue, Aug 6, 2024, 10:36 PM Li Jiang @.> wrote: Sender: User_proxy receiver: chat_manger ...... Hi @sujan-sarker https://github.com/sujan-sarker , any message chat_manager sends out is actually received from another agent. That to say, you can invoke the callbacks when "Sender: chat_manager receiver: coder ...". Say agent A send a message to chat_manager, you want to call the callback, but you can't, because in a group chat, you never see the receiver to be chat_manager. However, chat_manager will send this message to the next agent B, so you can call the callback function when B receives the message. The message and the callback function will be exactly the same. Would this work for you? — Reply to this email directly, view it on GitHub <#3279 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABX7ZJTOQZD3G4IA6U2325DZQGB4PAVCNFSM6AAAAABL33QCESVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENZSGUYDKNBVGM . You are receiving this because you were mentioned.Message ID: @.>

All the history messages are stored in groupchat, below function could give you the real sender info.

def print_and_store_messages(recipient, messages, sender, config):
    # Print the message immediately
    print(f"Sender: {sender.name} | Recipient: {recipient.name} | Message: {messages[-1].get('content')}")
    print(f"Real Sender: {sender.groupchat.messages[-1].get("name", sender.name)}")
    return False, None  # Required to ensure the agent communication flow continues
thinkall commented 1 month ago

Hi @sujan-sarker , could you please help check if #3318 makes it easier for you to access the real sender? With the PR, you can access the real sender with:

def print_and_store_messages(recipient, messages, sender, config):
    # Print the message immediately
    print(f"Sender: {sender.name} | Recipient: {recipient.name} | Message: {messages[-1].get('content')}")
    print(f"Real Sender: {sender.last_speaker.name}")
    return False, None  # Required to ensure the agent communication flow continues
JinMizar commented 1 month ago

Hi @sujan-sarker , could you please help check if #3318 makes it easier for you to access the real sender? With the PR, you can access the real sender with:

def print_and_store_messages(recipient, messages, sender, config):
    # Print the message immediately
    print(f"Sender: {sender.name} | Recipient: {recipient.name} | Message: {messages[-1].get('content')}")
    print(f"Real Sender: {sender.last_speaker.name}")
    return False, None  # Required to ensure the agent communication flow continues

Hi @thinkall , I am working on a similar project that needs to access the last message sender. The last_speaker attribute didn't exist. Is it due to the change hasn't been made yet?

image

thinkall commented 1 month ago

Hi @JinMizar , the PR is not merged yet.