MetaGPT icon indicating copy to clipboard operation
MetaGPT copied to clipboard

Possible bug with the Role Memory

Open nkrj01 opened this issue 1 year ago • 2 comments

Bug description When I put two agents (AgentA and AgentB) in an environment, AgentB is automatically picks up the published message of AgentA even though _watch function is not set to AgentAAction.

AgentAAction: take a string and publish one letter at a time AgentBAction: given any string simple add the word "Add"

There is no LLM functionality here.

Code is shown below:

Defining AgentA

from metagpt.actions import Action, UserRequirement from metagpt.roles import Role from metagpt.logs import logger from metagpt.schema import Message

class AgentAAction(Action): name: str = "AgentAAction"

async def run(self, task: str):
    sub_task = [letter for letter in task]
    return sub_task

class AgentA(Role): name: str = "AgentA" profile: str = "AgentA"

def __init__(self, **kwargs):
    super().__init__(**kwargs)
    self.set_actions([AgentAAction])
    self._watch({UserRequirement})

async def _act(self) -> None:
    logger.info(f"{self._setting}: to do {self.rc.todo}({self.rc.todo.name}) {type(self.rc)}")
    todo = self.rc.todo  # todo will be SimpleWriteCode()

    task = self.get_memories(k=1)[0]  # find the most recent messages
    sub_tasks = await todo.run(task.content)
    
    for i in sub_tasks:
       msg = Message(content=i, role=self.profile, cause_by=type(todo))
       self.rc.env.publish_message(msg)

Defining AgentB

class AgentBAction(Action): name: str = "AgentBAction"

async def run(self, sub_task: str):
    final_output = sub_task + "Add"
    return final_output

class AgentB(Role): name: str = "AgentB" profile: str = "AgentB"

def __init__(self, **kwargs):
    super().__init__(**kwargs)
    self.set_actions([AgentBAction])
    self._watch({UserRequirement}) ## Note!! Not watching AgentAAction

async def _act(self) -> Message:
    logger.info(f"{self._setting}: to do {self.rc.todo}({self.rc.todo.name}) {type(self.rc)}")
    todo = self.rc.todo  # todo will be AgentBAction

    sub_tasks = self.rc.history  # find all the messages
    print(sub_tasks)
    
    for i in sub_tasks:
        final_output = await todo.run(i.content)
        final_output = Message(content=final_output, role=self.profile, cause_by=type(todo))
        self.rc.env.publish_message(final_output)
        self.rc.memory.add(final_output)

from metagpt.context import Context import asyncio from metagpt.environment import Environment

agentA = AgentA() agentB = AgentB() context = Context() # Load config2.yaml env = Environment(context=context) env.add_roles([agentA, agentB]) env.publish_message(Message(content='APPLE', send_to=AgentA)) env.publish_message(Message(content='CAT', send_to=AgentB)) # Send the user's message to Agent A to start the process. await env.run()

print all the messages in the memory of agentB

for index, memory in enumerate(agentB.get_memories(k=0)): print(f'{index}: {memory}')

Output: 0: user: CAT 1: AgentA: A 2: AgentA: P 3: AgentA: P 4: AgentA: L 5: AgentA: E 6: AgentB: CATAdd 7: AgentB: AAdd 8: AgentB: PAdd 9: AgentB: PAdd 10: AgentB: LAdd 11: AgentB: EAdd

Ideally the output should just be: 0: user: CAT 1: user: CATadd

Bug solved method

Environment information

Windows 12

  • LLM type and model name: NA
  • System version:
  • Python version: 3.11
  • MetaGPT version or branch: 0.8
  • packages version:
  • installation method: using pip

Screenshots or logs

nkrj01 avatar May 27 '24 23:05 nkrj01

looks like message is still observed even if cause_by is set to type(todo). Can @iorisa check this?

garylin2099 avatar May 28 '24 06:05 garylin2099

I think in current implementation of publish_message does not take care of role watch actions.

As in metagpt/environment/base_env.py#L187

for role, addrs in self.member_addrs.items():
    if is_send_to(message, addrs):
        role.put_message(message)
        found = True

It should be

for role, addrs in self.member_addrs.items():
    if is_send_to(message, addrs) and role.is_watch(message.cause_by):
        role.put_message(message)
        found = True

Create this pull request: https://github.com/geekan/MetaGPT/pull/1314

PS: I am a bit new, I don't know if it will break other examples or not.

Kaushal-26 avatar May 31 '24 15:05 Kaushal-26

I think in current implementation of publish_message does not take care of role watch actions.

As in metagpt/environment/base_env.py#L187

for role, addrs in self.member_addrs.items():
    if is_send_to(message, addrs):
        role.put_message(message)
        found = True

It should be

for role, addrs in self.member_addrs.items():
    if is_send_to(message, addrs) and role.is_watch(message.cause_by):
        role.put_message(message)
        found = True

Create this pull request: #1314

PS: I am a bit new, I don't know if it will break other examples or not.

The use of is_send_to(message, addrs) only is for the purpose of sending messages to the agents who want to know what's happening and the agents responsible for auditing, log processing, debuging, and experience generation, as these agents need to receive all messages.

iorisa avatar Oct 11 '24 03:10 iorisa

I noticed that you have closed the PR, so I will go ahead and close this issue as well. If you have any questions, feel free to reopen this issue or create a new one to continue asking.

iorisa avatar Oct 11 '24 03:10 iorisa