diff --git a/metagpt/environment/mgx/mgx_env.py b/metagpt/environment/mgx/mgx_env.py index 53690f7d7..9ad8f5e7f 100644 --- a/metagpt/environment/mgx/mgx_env.py +++ b/metagpt/environment/mgx/mgx_env.py @@ -8,7 +8,7 @@ from metagpt.actions import ( WriteTest, ) from metagpt.actions.summarize_code import SummarizeCode -from metagpt.const import AGENT, IMAGES, TEAMLEADER_NAME +from metagpt.const import AGENT, IMAGES, MESSAGE_ROUTE_TO_ALL, TEAMLEADER_NAME from metagpt.environment.base_env import Environment from metagpt.logs import get_human_input from metagpt.roles import Architect, ProductManager, ProjectManager, Role @@ -24,7 +24,12 @@ class MGXEnv(Environment, SerializationMixin): direct_chat_roles: set[str] = set() # record direct chat: @role_name + is_public_chat: bool = True + def _publish_message(self, message: Message, peekable: bool = True) -> bool: + if self.is_public_chat: + message.send_to.add(MESSAGE_ROUTE_TO_ALL) + message = self.move_message_info_to_content(message) return super().publish_message(message, peekable) def publish_message(self, message: Message, user_defined_recipient: str = "", publicer: str = "") -> bool: @@ -81,9 +86,8 @@ class MGXEnv(Environment, SerializationMixin): else: # every regular message goes through team leader - message = self.move_message_info_to_content(message) message.send_to.add(tl.name) - tl.put_message(message) + self._publish_message(message) self.history.add(message) @@ -122,9 +126,11 @@ class MGXEnv(Environment, SerializationMixin): if converted_msg.role not in ["system", "user", "assistant"]: converted_msg.role = "assistant" sent_from = converted_msg.metadata[AGENT] if AGENT in converted_msg.metadata else converted_msg.sent_from - converted_msg.content = ( - f"[Message] from {sent_from or 'User'} to {converted_msg.send_to}: {converted_msg.content}" - ) + if converted_msg.send_to == {MESSAGE_ROUTE_TO_ALL}: + send_to = TEAMLEADER_NAME + else: + send_to = ", ".join({role for role in converted_msg.send_to if role != MESSAGE_ROUTE_TO_ALL}) + converted_msg.content = f"[Message] from {sent_from or 'User'} to {send_to}: {converted_msg.content}" return converted_msg def attach_images(self, message: Message) -> Message: diff --git a/metagpt/roles/di/role_zero.py b/metagpt/roles/di/role_zero.py index c284db702..7e09481b1 100644 --- a/metagpt/roles/di/role_zero.py +++ b/metagpt/roles/di/role_zero.py @@ -93,6 +93,7 @@ class RoleZero(Role): experience_retriever: Annotated[ExpRetriever, Field(exclude=True)] = DummyExpRetriever() # Others + observe_all_msg_from_buffer: bool = True command_rsp: str = "" # the raw string containing the commands commands: list[dict] = [] # commands to be executed memory_k: int = 200 # number of memories (messages) to use as historical context diff --git a/metagpt/roles/role.py b/metagpt/roles/role.py index 5d1050464..f2ab60c4d 100644 --- a/metagpt/roles/role.py +++ b/metagpt/roles/role.py @@ -154,6 +154,7 @@ class Role(BaseRole, SerializationMixin, ContextMixin, BaseModel): # builtin variables recovered: bool = False # to tag if a recovered role latest_observed_msg: Optional[Message] = None # record the latest observed message when interrupted + observe_all_msg_from_buffer: bool = False # whether to save all msgs from buffer to memory for role's awareness __hash__ = object.__hash__ # support Role as hashable type in `Environment.members` @@ -171,7 +172,7 @@ class Role(BaseRole, SerializationMixin, ContextMixin, BaseModel): self._check_actions() self.llm.system_prompt = self._get_prefix() self.llm.cost_manager = self.context.cost_manager - self._watch(kwargs.pop("watch", [UserRequirement])) + self._watch(kwargs.pop("watch", [])) if self.latest_observed_msg: self.recovered = True @@ -396,7 +397,12 @@ class Role(BaseRole, SerializationMixin, ContextMixin, BaseModel): self.rc.news = [ n for n in news if (n.cause_by in self.rc.watch or self.name in n.send_to) and n not in old_messages ] - self.rc.memory.add_batch(self.rc.news) # only save messages of interest into memory + if self.observe_all_msg_from_buffer: + # save all new messages from the buffer into memory, the role may not react to them but can be aware of them + self.rc.memory.add_batch(news) + else: + # only save messages of interest into memory + self.rc.memory.add_batch(self.rc.news) self.latest_observed_msg = self.rc.news[-1] if self.rc.news else None # record the latest observed msg # Design Rules: