#!/usr/bin/env python # -*- coding: utf-8 -*- """ @Time : 2023/5/12 00:30 @Author : alexanderwu @File : software_company.py """ from pathlib import Path from pydantic import BaseModel, Field from metagpt.actions import BossRequirement from metagpt.config import CONFIG from metagpt.environment import Environment from metagpt.logs import logger from metagpt.roles import Role from metagpt.schema import Message from metagpt.utils.common import NoMoneyException from metagpt.utils.utils import read_json_file, write_json_file, serialize_decorator from metagpt.const import SERDESER_PATH class Team(BaseModel): """ Team: Possesses one or more roles (agents), SOP (Standard Operating Procedures), and a platform for instant messaging, dedicated to perform any multi-agent activity, such as collaboratively writing executable code. """ environment: Environment = Field(default_factory=Environment) investment: float = Field(default=10.0) idea: str = Field(default="") class Config: arbitrary_types_allowed = True def serialize(self, stg_path: Path = None): stg_path = SERDESER_PATH.joinpath("team") if stg_path is None else stg_path team_info_path = stg_path.joinpath("team_info.json") write_json_file(team_info_path, self.dict(exclude={"environment": True})) self.environment.serialize(stg_path.joinpath("environment")) # save environment alone @classmethod def recover(cls, stg_path: Path) -> "Team": return cls.deserialize(stg_path) @classmethod def deserialize(cls, stg_path: Path) -> "Team": """ stg_path = ./storage/team """ # recover team_info team_info_path = stg_path.joinpath("team_info.json") if not team_info_path.exists(): raise FileNotFoundError("recover storage meta file `team_info.json` not exist, " "not to recover and please start a new project.") team_info: dict = read_json_file(team_info_path) # recover environment environment = Environment.deserialize(stg_path=stg_path.joinpath("environment")) team_info.update({"environment": environment}) team = Team(**team_info) return team def hire(self, roles: list[Role]): """Hire roles to cooperate""" self.environment.add_roles(roles) def invest(self, investment: float): """Invest company. raise NoMoneyException when exceed max_budget.""" self.investment = investment CONFIG.max_budget = investment logger.info(f'Investment: ${investment}.') def _check_balance(self): if CONFIG.total_cost > CONFIG.max_budget: raise NoMoneyException(CONFIG.total_cost, f'Insufficient funds: {CONFIG.max_budget}') def start_project(self, idea, send_to: str = ""): """Start a project from publishing boss requirement.""" self.idea = idea self.environment.publish_message(Message(role="Human", content=idea, cause_by=BossRequirement, send_to=send_to)) def _save(self): logger.info(self.json()) @serialize_decorator async def run(self, n_round=3): """Run company until target round or no money""" while n_round > 0: # self._save() n_round -= 1 logger.debug(f"{n_round=}") self._check_balance() await self.environment.run() return self.environment.history