Skip to content

Commit

Permalink
patch release v0.5.2: fix user requirement dead loop in startup
Browse files Browse the repository at this point in the history
fixbug: recursive user requirement dead loop
  • Loading branch information
garylin2099 authored Dec 18, 2023
2 parents e43aaec + 43e35fe commit fa727c4
Show file tree
Hide file tree
Showing 3 changed files with 9 additions and 24 deletions.
23 changes: 6 additions & 17 deletions metagpt/roles/role.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@

from pydantic import BaseModel, Field

from metagpt.actions import Action, ActionOutput
from metagpt.actions import Action, ActionOutput, UserRequirement
from metagpt.actions.action_node import ActionNode
from metagpt.actions.add_requirement import UserRequirement
from metagpt.llm import LLM, HumanProvider
from metagpt.logs import logger
from metagpt.memory import Memory
Expand Down Expand Up @@ -127,17 +126,7 @@ def history(self) -> list[Message]:
return self.memory.get()


class _RoleInjector(type):
def __call__(cls, *args, **kwargs):
instance = super().__call__(*args, **kwargs)

if not instance._rc.watch:
instance._watch([UserRequirement])

return instance


class Role(metaclass=_RoleInjector):
class Role:
"""Role/Agent"""

def __init__(self, name="", profile="", goal="", constraints="", desc="", is_human=False):
Expand All @@ -149,10 +138,9 @@ def __init__(self, name="", profile="", goal="", constraints="", desc="", is_hum
self._states = []
self._actions = []
self._role_id = str(self._setting)
self._rc = RoleContext()
self._rc = RoleContext(watch={any_to_str(UserRequirement)})
self._subscription = {any_to_str(self), name} if name else {any_to_str(self)}


def _reset(self):
self._states = []
self._actions = []
Expand Down Expand Up @@ -203,8 +191,7 @@ def _watch(self, actions: Iterable[Type[Action]]):
"""Watch Actions of interest. Role will select Messages caused by these Actions from its personal message
buffer during _observe.
"""
tags = {any_to_str(t) for t in actions}
self._rc.watch.update(tags)
self._rc.watch = {any_to_str(t) for t in actions}
# check RoleContext after adding watch actions
self._rc.check(self._role_id)

Expand Down Expand Up @@ -401,6 +388,8 @@ async def run(self, with_message=None):
msg = with_message
elif isinstance(with_message, list):
msg = Message("\n".join(with_message))
if not msg.cause_by:
msg.cause_by = UserRequirement
self.put_message(msg)

if not await self._observe():
Expand Down
4 changes: 0 additions & 4 deletions metagpt/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,6 @@ def __init__(
:param send_to: Specifies the target recipient or consumer for message delivery in the environment.
:param role: Message meta info tells who sent this message.
"""
if not cause_by:
from metagpt.actions import UserRequirement
cause_by = UserRequirement

super().__init__(
id=uuid.uuid4().hex,
content=content,
Expand Down
6 changes: 3 additions & 3 deletions tests/metagpt/test_role.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
import pytest
from pydantic import BaseModel

from metagpt.actions import Action, ActionOutput
from metagpt.actions import Action, ActionOutput, UserRequirement
from metagpt.environment import Environment
from metagpt.roles import Role
from metagpt.schema import Message
from metagpt.utils.common import get_class_name
from metagpt.utils.common import any_to_str, get_class_name


class MockAction(Action):
Expand Down Expand Up @@ -60,7 +60,7 @@ class Input(BaseModel):
name=seed.name, profile=seed.profile, goal=seed.goal, constraints=seed.constraints, desc=seed.desc
)
role.subscribe({seed.subscription})
assert role._rc.watch == set({})
assert role._rc.watch == {any_to_str(UserRequirement)}
assert role.name == seed.name
assert role.profile == seed.profile
assert role._setting.goal == seed.goal
Expand Down

0 comments on commit fa727c4

Please sign in to comment.