From 493224439e47cdcf3170d495a6ec35e481404ae8 Mon Sep 17 00:00:00 2001 From: garylin2099 Date: Fri, 15 Dec 2023 18:48:43 +0800 Subject: [PATCH 1/9] version preparation --- README.md | 3 ++- config/config.yaml | 3 +++ setup.py | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b3473a12c..b0faf85c7 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,8 @@ # MetaGPT: The Multi-Agent Framework

Software Company Multi-Role Schematic (Gradually Implementing)

- +## News +- Dec 15: v0.5.0 is released! We introduce **incremental development**, facilitating agents to build up larger projects on top of their previous efforts or exisiting human codebase. We also launch a whole collection of important features, including multilingual support (experimental), multiple programming languages support (experimental), incremental development (experimental), CLI support, pip support, enhanced code review, documentation mechanism, and optimized messaging mechanism! ## Install diff --git a/config/config.yaml b/config/config.yaml index 8fd208c59..dc4c4ea5a 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -1,6 +1,9 @@ # DO NOT MODIFY THIS FILE, create a new key.yaml, define OPENAI_API_KEY. # The configuration of key.yaml has a higher priority and will not enter git +#### Project Path Setting +# WORKSPACE_PATH: "Path for placing output files" + #### if OpenAI ## The official OPENAI_API_BASE is https://api.openai.com/v1 ## If the official OPENAI_API_BASE is not available, we recommend using the [openai-forward](https://github.com/beidongjiedeguang/openai-forward). diff --git a/setup.py b/setup.py index 4dd453b3d..730fffd35 100644 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ with open(path.join(here, "requirements.txt"), encoding="utf-8") as f: setup( name="metagpt", - version="0.4.0", + version="0.5.0", description="The Multi-Role Meta Programming Framework", long_description=long_description, long_description_content_type="text/markdown", From 335a025c030db55f563e5dd21aaa0f2a7e632018 Mon Sep 17 00:00:00 2001 From: shenchucheng Date: Fri, 15 Dec 2023 19:38:48 +0800 Subject: [PATCH 2/9] fix cContextVar OPTIONS LookupError --- metagpt/config.py | 2 ++ metagpt/const.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/metagpt/config.py b/metagpt/config.py index 19bd02c87..d7f5c1249 100644 --- a/metagpt/config.py +++ b/metagpt/config.py @@ -45,9 +45,11 @@ class Config(metaclass=Singleton): default_yaml_file = METAGPT_ROOT / "config/config.yaml" def __init__(self, yaml_file=default_yaml_file): + golbal_options = OPTIONS.get() self._init_with_config_files_and_env(yaml_file) logger.debug("Config loading done.") self._update() + golbal_options.update(OPTIONS.get()) def _update(self): # logger.info("Config loading done.") diff --git a/metagpt/const.py b/metagpt/const.py index f6f64a27d..47864d134 100644 --- a/metagpt/const.py +++ b/metagpt/const.py @@ -17,7 +17,7 @@ from loguru import logger import metagpt -OPTIONS = contextvars.ContextVar("OPTIONS") +OPTIONS = contextvars.ContextVar("OPTIONS", default={}) def get_metagpt_package_root(): From 68f3865893140f93f2f38fc5591d0b9cb340c871 Mon Sep 17 00:00:00 2001 From: shenchucheng Date: Sun, 17 Dec 2023 00:21:43 +0800 Subject: [PATCH 3/9] Add UserRequirement to watch in default if the role is not set to watch --- metagpt/roles/role.py | 14 +++++++++++++- metagpt/schema.py | 4 ++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/metagpt/roles/role.py b/metagpt/roles/role.py index b07541b09..1e7ebf711 100644 --- a/metagpt/roles/role.py +++ b/metagpt/roles/role.py @@ -27,6 +27,7 @@ from pydantic import BaseModel, Field from metagpt.actions import Action, ActionOutput 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 @@ -126,7 +127,17 @@ class RoleContext(BaseModel): return self.memory.get() -class Role: +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): """Role/Agent""" def __init__(self, name="", profile="", goal="", constraints="", desc="", is_human=False): @@ -141,6 +152,7 @@ class Role: self._rc = RoleContext() self._subscription = {any_to_str(self), name} if name else {any_to_str(self)} + def _reset(self): self._states = [] self._actions = [] diff --git a/metagpt/schema.py b/metagpt/schema.py index 758149efa..5aec378e4 100644 --- a/metagpt/schema.py +++ b/metagpt/schema.py @@ -121,6 +121,10 @@ class Message(BaseModel): :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, From 355ee8faa8cf4b2edd0fbeccf2084890da780d6d Mon Sep 17 00:00:00 2001 From: shenchucheng Date: Sun, 17 Dec 2023 00:23:21 +0800 Subject: [PATCH 4/9] Set current working directory (cwd) to default project root in PyPI mode --- metagpt/const.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/metagpt/const.py b/metagpt/const.py index 47864d134..10de0ff66 100644 --- a/metagpt/const.py +++ b/metagpt/const.py @@ -23,6 +23,12 @@ OPTIONS = contextvars.ContextVar("OPTIONS", default={}) def get_metagpt_package_root(): """Get the root directory of the installed package.""" package_root = Path(metagpt.__file__).parent.parent + for i in (".git", ".project_root", ".gitignore"): + if (package_root / i).exists(): + break + else: + package_root = Path.cwd() + logger.info(f"Package root set to {str(package_root)}") return package_root From feef54ba3bcbd0d6fe7943f6e9aaf318b9cc396a Mon Sep 17 00:00:00 2001 From: garylin2099 Date: Sun, 17 Dec 2023 13:52:37 +0800 Subject: [PATCH 5/9] patch release v0.5.1 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 730fffd35..73a05eeae 100644 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ with open(path.join(here, "requirements.txt"), encoding="utf-8") as f: setup( name="metagpt", - version="0.5.0", + version="0.5.1", description="The Multi-Role Meta Programming Framework", long_description=long_description, long_description_content_type="text/markdown", From 097c6e09d2ff7b0f5487f6068ff2185801eb950e Mon Sep 17 00:00:00 2001 From: shenchucheng Date: Sun, 17 Dec 2023 14:41:59 +0800 Subject: [PATCH 6/9] add deprecated warnings for the start_project method --- metagpt/team.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/metagpt/team.py b/metagpt/team.py index a5c405f80..5ce07ef13 100644 --- a/metagpt/team.py +++ b/metagpt/team.py @@ -3,10 +3,11 @@ """ @Time : 2023/5/12 00:30 @Author : alexanderwu -@File : software_company.py +@File : team.py @Modified By: mashenquan, 2023/11/27. Add an archiving operation after completing the project, as specified in Section 2.2.3.3 of RFC 135. """ +import warnings from pydantic import BaseModel, Field from metagpt.actions import UserRequirement @@ -47,7 +48,7 @@ class Team(BaseModel): raise NoMoneyException(CONFIG.total_cost, f"Insufficient funds: {CONFIG.max_budget}") def run_project(self, idea, send_to: str = ""): - """Start a project from publishing user requirement.""" + """Run a project from publishing user requirement.""" self.idea = idea # Human requirement. @@ -55,6 +56,16 @@ class Team(BaseModel): Message(role="Human", content=idea, cause_by=UserRequirement, send_to=send_to or MESSAGE_ROUTE_TO_ALL) ) + def start_project(self, idea, send_to: str = ""): + """ + Deprecated: This method will be removed in the future. + Please use the `run_project` method instead. + """ + warnings.warn("The 'start_project' method is deprecated and will be removed in the future. " + "Please use the 'run_project' method instead.", + DeprecationWarning, stacklevel=2) + return self.run_project(idea=idea, send_to=send_to) + def _save(self): logger.info(self.json(ensure_ascii=False)) From 43e35fe929d165f6f5c36b8f683d85825fa78684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 18 Dec 2023 16:13:21 +0800 Subject: [PATCH 7/9] fixbug: recursive user requirement dead loop --- metagpt/roles/role.py | 23 ++++++----------------- metagpt/schema.py | 4 ---- tests/metagpt/test_role.py | 6 +++--- 3 files changed, 9 insertions(+), 24 deletions(-) diff --git a/metagpt/roles/role.py b/metagpt/roles/role.py index 1e7ebf711..48688ad5f 100644 --- a/metagpt/roles/role.py +++ b/metagpt/roles/role.py @@ -25,9 +25,8 @@ from typing import Iterable, Set, Type 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 @@ -127,17 +126,7 @@ class RoleContext(BaseModel): 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): @@ -149,10 +138,9 @@ class Role(metaclass=_RoleInjector): 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 = [] @@ -203,8 +191,7 @@ class Role(metaclass=_RoleInjector): """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) @@ -401,6 +388,8 @@ class Role(metaclass=_RoleInjector): 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(): diff --git a/metagpt/schema.py b/metagpt/schema.py index 5aec378e4..758149efa 100644 --- a/metagpt/schema.py +++ b/metagpt/schema.py @@ -121,10 +121,6 @@ class Message(BaseModel): :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, diff --git a/tests/metagpt/test_role.py b/tests/metagpt/test_role.py index 8fac2503c..611d321fc 100644 --- a/tests/metagpt/test_role.py +++ b/tests/metagpt/test_role.py @@ -14,11 +14,11 @@ import uuid 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): @@ -60,7 +60,7 @@ async def test_react(): 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 From a88f931fe9a93dc7d883c0a260310f9aee9942e0 Mon Sep 17 00:00:00 2001 From: garylin2099 Date: Mon, 18 Dec 2023 19:26:38 +0800 Subject: [PATCH 8/9] update version and roadmap --- docs/ROADMAP.md | 8 ++++---- setup.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index afc9ff445..3cb03f374 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -30,10 +30,10 @@ ### Tasks 4. Complete the design and implementation of module breakdown 5. Support various modes of memory: clearly distinguish between long-term and short-term memory 6. Perfect the test role, and carry out necessary interactions with humans - 7. Allowing natural communication between roles (expected v0.5.0) + 7. ~~Allowing natural communication between roles~~ (v0.5.0) 8. Implement SkillManager and the process of incremental Skill learning (experimentation done with game agents) 9. Automatically get RPM and configure it by calling the corresponding openai page, so that each key does not need to be manually configured - 10. IMPORTANT: Support incremental development (expected v0.5.0) + 10. ~~IMPORTANT: Support incremental development~~ (v0.5.0) 3. Strategies 1. Support ReAct strategy (experimentation done with game agents) 2. Support CoT strategy (experimentation done with game agents) @@ -45,8 +45,8 @@ ### Tasks 2. Implementation: Knowledge search, supporting 10+ data formats 3. Implementation: Data EDA (expected v0.6.0) 4. Implementation: Review - 5. Implementation: Add Document (expected v0.5.0) - 6. Implementation: Delete Document (expected v0.5.0) + 5. ~~Implementation~~: Add Document (v0.5.0) + 6. ~~Implementation~~: Delete Document (v0.5.0) 7. Implementation: Self-training 8. ~~Implementation: DebugError~~ (v0.2.1) 9. Implementation: Generate reliable unit tests based on YAPI diff --git a/setup.py b/setup.py index 73a05eeae..57290f4cd 100644 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ with open(path.join(here, "requirements.txt"), encoding="utf-8") as f: setup( name="metagpt", - version="0.5.1", + version="0.5.2", description="The Multi-Role Meta Programming Framework", long_description=long_description, long_description_content_type="text/markdown", From e67dbc92e42fcc9479027df6e9d00eabce20df36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 19 Dec 2023 16:37:01 +0800 Subject: [PATCH 9/9] feat: disable -- max_auto_summarize_code --- metagpt/startup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metagpt/startup.py b/metagpt/startup.py index f930c386b..e886ad2a4 100644 --- a/metagpt/startup.py +++ b/metagpt/startup.py @@ -26,7 +26,7 @@ def startup( ), reqa_file: str = typer.Option(default="", help="Specify the source file name for rewriting the quality test code."), max_auto_summarize_code: int = typer.Option( - default=-1, + default=0, help="The maximum number of times the 'SummarizeCode' action is automatically invoked, with -1 indicating unlimited. This parameter is used for debugging the workflow.", ), ):