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

Fix Role not fully defined error debugger #833

Merged
Merged
Show file tree
Hide file tree
Changes from all 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
27 changes: 19 additions & 8 deletions metagpt/environment/base_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import asyncio
from enum import Enum
from typing import Any, Iterable, Optional, Set, Union
from typing import TYPE_CHECKING, Any, Iterable, Optional, Set, Union

from pydantic import BaseModel, ConfigDict, Field, SerializeAsAny, model_validator

Expand All @@ -15,10 +15,12 @@
WriteAPIRegistry,
)
from metagpt.logs import logger
from metagpt.roles.role import Role
from metagpt.schema import Message
from metagpt.utils.common import get_function_schema, is_coroutine_func, is_send_to

if TYPE_CHECKING:
from metagpt.roles.role import Role # noqa: F401


class EnvType(Enum):
ANDROID = "Android"
Expand Down Expand Up @@ -101,8 +103,8 @@ class Environment(ExtEnv):
model_config = ConfigDict(arbitrary_types_allowed=True)

desc: str = Field(default="") # 环境描述
roles: dict[str, SerializeAsAny[Role]] = Field(default_factory=dict, validate_default=True)
member_addrs: dict[Role, Set] = Field(default_factory=dict, exclude=True)
roles: dict[str, SerializeAsAny["Role"]] = Field(default_factory=dict, validate_default=True)
member_addrs: dict["Role", Set] = Field(default_factory=dict, exclude=True)
history: str = "" # For debug
context: Context = Field(default_factory=Context, exclude=True)

Expand All @@ -111,15 +113,15 @@ def init_roles(self):
self.add_roles(self.roles.values())
return self

def add_role(self, role: Role):
def add_role(self, role: "Role"):
"""增加一个在当前环境的角色
Add a role in the current environment
"""
self.roles[role.profile] = role
role.set_env(self)
role.context = self.context

def add_roles(self, roles: Iterable[Role]):
def add_roles(self, roles: Iterable["Role"]):
"""增加一批在当前环境的角色
Add a batch of characters in the current environment
"""
Expand Down Expand Up @@ -165,13 +167,13 @@ async def run(self, k=1):
await asyncio.gather(*futures)
logger.debug(f"is idle: {self.is_idle}")

def get_roles(self) -> dict[str, Role]:
def get_roles(self) -> dict[str, "Role"]:
"""获得环境内的所有角色
Process all Role runs at once
"""
return self.roles

def get_role(self, name: str) -> Role:
def get_role(self, name: str) -> "Role":
"""获得环境内的指定角色
get all the environment roles
"""
Expand Down Expand Up @@ -199,3 +201,12 @@ def set_addresses(self, obj, addresses):
def archive(self, auto_archive=True):
if auto_archive and self.context.git_repo:
self.context.git_repo.archive()

@classmethod
def model_rebuild(cls, **kwargs):
from metagpt.roles.role import Role # noqa: F401

super().model_rebuild(**kwargs)


Environment.model_rebuild()
24 changes: 14 additions & 10 deletions metagpt/roles/role.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from __future__ import annotations

from enum import Enum
from typing import Iterable, Optional, Set, Type, Union
from typing import TYPE_CHECKING, Iterable, Optional, Set, Type, Union

from pydantic import BaseModel, ConfigDict, Field, SerializeAsAny, model_validator

Expand All @@ -39,6 +39,10 @@
from metagpt.utils.project_repo import ProjectRepo
from metagpt.utils.repair_llm_raw_output import extract_state_value_from_output

if TYPE_CHECKING:
from metagpt.environment import Environment # noqa: F401


PREFIX_TEMPLATE = """You are a {profile}, named {name}, your goal is {goal}. """
CONSTRAINT_TEMPLATE = "the constraint is {constraints}. "

Expand Down Expand Up @@ -117,6 +121,12 @@ def important_memory(self) -> list[Message]:
def history(self) -> list[Message]:
return self.memory.get()

@classmethod
def model_rebuild(cls, **kwargs):
from metagpt.environment.base_env import Environment # noqa: F401

super().model_rebuild(**kwargs)


class Role(SerializationMixin, ContextMixin, BaseModel):
"""Role/Agent"""
Expand Down Expand Up @@ -155,7 +165,6 @@ def validate_role_extra(self):
return self

def _process_role_extra(self):
self.pydantic_rebuild_model()
kwargs = self.model_extra or {}

if self.is_human:
Expand All @@ -168,14 +177,6 @@ def _process_role_extra(self):
if self.latest_observed_msg:
self.recovered = True

@staticmethod
def pydantic_rebuild_model():
"""Rebuild model to avoid `RecursionError: maximum recursion depth exceeded in comparison`"""
from metagpt.environment import Environment

Environment
Role.model_rebuild()

@property
def todo(self) -> Action:
"""Get action to do"""
Expand Down Expand Up @@ -559,3 +560,6 @@ def action_description(self) -> str:
if self.actions:
return any_to_name(self.actions[0])
return ""


RoleContext.model_rebuild()
Loading