Merge branch 'dev' into dev_incremental

This commit is contained in:
mannaandpoem 2024-01-23 09:39:43 +08:00
commit 32f9fbb46b
24 changed files with 75 additions and 48 deletions

View file

@ -182,7 +182,7 @@ class WriteCodeReview(Action):
format_example=format_example,
)
len1 = len(iterative_code) if iterative_code else 0
len2 = len(self.context.code_doc.content) if self.context.code_doc.content else 0
len2 = len(self.i_context.code_doc.content) if self.i_context.code_doc.content else 0
logger.info(
f"Code review and rewrite {self.i_context.code_doc.filename}: {i + 1}/{k} | len(iterative_code)={len1}, "
f"len(self.i_context.code_doc.content)={len2}"

View file

@ -38,6 +38,7 @@ class CLIParams(BaseModel):
if self.project_path:
self.inc = True
self.project_name = self.project_name or Path(self.project_path).name
return self
class Config(CLIParams, YamlModel):

View file

@ -95,7 +95,3 @@ class Context(BaseModel):
if llm.cost_manager is None:
llm.cost_manager = self.cost_manager
return llm
# Global context, not in Env
CONTEXT = Context()

View file

@ -10,7 +10,7 @@ from typing import Optional
from pydantic import BaseModel, ConfigDict, Field
from metagpt.config2 import Config
from metagpt.context import CONTEXT, Context
from metagpt.context import Context
from metagpt.provider.base_llm import BaseLLM
@ -34,7 +34,7 @@ class ContextMixin(BaseModel):
def __init__(
self,
context: Optional[Context] = CONTEXT,
context: Optional[Context] = None,
config: Optional[Config] = None,
llm: Optional[BaseLLM] = None,
**kwargs,
@ -81,7 +81,7 @@ class ContextMixin(BaseModel):
"""Role context: role context > context"""
if self.private_context:
return self.private_context
return CONTEXT
return Context()
@context.setter
def context(self, context: Context) -> None:

View file

@ -13,7 +13,7 @@ import aiofiles
import yaml
from pydantic import BaseModel, Field
from metagpt.context import CONTEXT, Context
from metagpt.context import Context
class Example(BaseModel):
@ -73,14 +73,15 @@ class SkillsDeclaration(BaseModel):
skill_data = yaml.safe_load(data)
return SkillsDeclaration(**skill_data)
def get_skill_list(self, entity_name: str = "Assistant", context: Context = CONTEXT) -> Dict:
def get_skill_list(self, entity_name: str = "Assistant", context: Context = None) -> Dict:
"""Return the skill name based on the skill description."""
entity = self.entities.get(entity_name)
if not entity:
return {}
# List of skills that the agent chooses to activate.
agent_skills = context.kwargs.agent_skills
ctx = context or Context()
agent_skills = ctx.kwargs.agent_skills
if not agent_skills:
return {}

View file

@ -8,12 +8,13 @@
from typing import Optional
from metagpt.configs.llm_config import LLMConfig
from metagpt.context import CONTEXT
from metagpt.context import Context
from metagpt.provider.base_llm import BaseLLM
def LLM(llm_config: Optional[LLMConfig] = None) -> BaseLLM:
def LLM(llm_config: Optional[LLMConfig] = None, context: Context = None) -> BaseLLM:
"""get the default llm provider if name is None"""
ctx = context or Context()
if llm_config is not None:
CONTEXT.llm_with_cost_manager_from_llm_config(llm_config)
return CONTEXT.llm()
ctx.llm_with_cost_manager_from_llm_config(llm_config)
return ctx.llm()

View file

@ -22,7 +22,6 @@ from pydantic import Field
from metagpt.actions.skill_action import ArgumentsParingAction, SkillAction
from metagpt.actions.talk_action import TalkAction
from metagpt.context import CONTEXT
from metagpt.learn.skill_loader import SkillsDeclaration
from metagpt.logs import logger
from metagpt.memory.brain_memory import BrainMemory
@ -48,7 +47,7 @@ class Assistant(Role):
def __init__(self, **kwargs):
super().__init__(**kwargs)
language = kwargs.get("language") or self.context.kwargs.language or CONTEXT.kwargs.language
language = kwargs.get("language") or self.context.kwargs.language
self.constraints = self.constraints.format(language=language)
async def think(self) -> bool:

View file

@ -8,6 +8,7 @@ import typer
from metagpt.config2 import config
from metagpt.const import CONFIG_ROOT, METAGPT_ROOT
from metagpt.context import Context
app = typer.Typer(add_completion=False, pretty_exceptions_show_locals=False)
@ -37,9 +38,10 @@ def generate_repo(
from metagpt.team import Team
config.update_via_cli(project_path, project_name, inc, reqa_file, max_auto_summarize_code)
ctx = Context(config=config)
if not recover_path:
company = Team()
company = Team(context=ctx)
company.hire(
[
ProductManager(),
@ -58,7 +60,7 @@ def generate_repo(
if not stg_path.exists() or not str(stg_path).endswith("team"):
raise FileNotFoundError(f"{recover_path} not exists or not endswith `team`")
company = Team.deserialize(stg_path=stg_path)
company = Team.deserialize(stg_path=stg_path, context=ctx)
idea = company.idea
company.invest(investment)

View file

@ -10,12 +10,13 @@
import warnings
from pathlib import Path
from typing import Any
from typing import Any, Optional
from pydantic import BaseModel, ConfigDict, Field
from metagpt.actions import UserRequirement
from metagpt.const import MESSAGE_ROUTE_TO_ALL, SERDESER_PATH
from metagpt.context import Context
from metagpt.environment import Environment
from metagpt.logs import logger
from metagpt.roles import Role
@ -36,12 +37,17 @@ class Team(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True)
env: Environment = Field(default_factory=Environment)
env: Optional[Environment] = None
investment: float = Field(default=10.0)
idea: str = Field(default="")
def __init__(self, **data: Any):
def __init__(self, context: Context = None, **data: Any):
super(Team, self).__init__(**data)
ctx = context or Context()
if not self.env:
self.env = Environment(context=ctx)
else:
self.env.context = ctx # The `env` object is allocated by deserialization
if "roles" in data:
self.hire(data["roles"])
if "env_desc" in data:
@ -54,7 +60,7 @@ class Team(BaseModel):
write_json_file(team_info_path, self.model_dump())
@classmethod
def deserialize(cls, stg_path: Path) -> "Team":
def deserialize(cls, stg_path: Path, context: Context = None) -> "Team":
"""stg_path = ./storage/team"""
# recover team_info
team_info_path = stg_path.joinpath("team.json")
@ -64,7 +70,8 @@ class Team(BaseModel):
)
team_info: dict = read_json_file(team_info_path)
team = Team(**team_info)
ctx = context or Context()
team = Team(**team_info, context=ctx)
return team
def hire(self, roles: list[Role]):

View file

@ -28,7 +28,7 @@ from typing import Any, List, Tuple, Union
import aiofiles
import loguru
from pydantic_core import to_jsonable_python
from tenacity import RetryCallState, _utils
from tenacity import RetryCallState, RetryError, _utils
from metagpt.const import MESSAGE_ROUTE_TO_ALL
from metagpt.logs import logger
@ -505,7 +505,7 @@ def role_raise_decorator(func):
self.rc.memory.delete(self.latest_observed_msg)
# raise again to make it captured outside
raise Exception(format_trackback_info(limit=None))
except Exception:
except Exception as e:
if self.latest_observed_msg:
logger.warning(
"There is a exception in role's execution, in order to resume, "
@ -514,6 +514,12 @@ def role_raise_decorator(func):
# remove role newest observed msg to make it observed again
self.rc.memory.delete(self.latest_observed_msg)
# raise again to make it captured outside
if isinstance(e, RetryError):
last_error = e.last_attempt._exception
name = any_to_str(last_error)
if re.match(r"^openai\.", name) or re.match(r"^httpx\.", name):
raise last_error
raise Exception(format_trackback_info(limit=None))
return wrapper