From 74db24508c8c589b76655685dc3f271900e0b395 Mon Sep 17 00:00:00 2001 From: voidking Date: Mon, 8 Jan 2024 17:27:02 +0800 Subject: [PATCH 01/18] bugfix: if unittest failed, results still need to upload to codecov --- .github/workflows/unittest.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/unittest.yaml b/.github/workflows/unittest.yaml index df4a71d69..d2202ae52 100644 --- a/.github/workflows/unittest.yaml +++ b/.github/workflows/unittest.yaml @@ -4,10 +4,7 @@ on: workflow_dispatch: pull_request_target: push: - branches: - - 'main' - - 'dev' - - '*-release' + branches: - '*-debugger' jobs: @@ -79,3 +76,4 @@ jobs: uses: codecov/codecov-action@v3 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + if: ${{ always() }} From 6cde039f7f29daadc0719901d729b7557269fac3 Mon Sep 17 00:00:00 2001 From: kkdev163 Date: Mon, 8 Jan 2024 17:45:44 +0800 Subject: [PATCH 02/18] fixbug: role init with is_human=True was not work --- metagpt/roles/role.py | 3 +++ tests/metagpt/roles/test_role.py | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/metagpt/roles/role.py b/metagpt/roles/role.py index 3bcd600fc..71f6ec8f5 100644 --- a/metagpt/roles/role.py +++ b/metagpt/roles/role.py @@ -166,6 +166,9 @@ class Role(SerializationMixin, is_polymorphic_base=True): Role.model_rebuild() super().__init__(**data) + if data.get("is_human"): + self.llm = HumanProvider() + self.llm.system_prompt = self._get_prefix() self._watch(data.get("watch") or [UserRequirement]) diff --git a/tests/metagpt/roles/test_role.py b/tests/metagpt/roles/test_role.py index b3b54455e..151608b6b 100644 --- a/tests/metagpt/roles/test_role.py +++ b/tests/metagpt/roles/test_role.py @@ -4,6 +4,7 @@ import pytest from metagpt.roles.role import Role +from metagpt.llm import HumanProvider def test_role_desc(): @@ -11,6 +12,9 @@ def test_role_desc(): assert role.profile == "Sales" assert role.desc == "Best Seller" +def test_role_human(): + role = Role(is_human=True) + assert isinstance(role.llm, HumanProvider) if __name__ == "__main__": pytest.main([__file__, "-s"]) From 360f5dcd1b69b5cd16e7d6dd6839bdf9b63f6a24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 8 Jan 2024 18:02:24 +0800 Subject: [PATCH 03/18] refactor: unit test --- tests/metagpt/utils/test_redis.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/tests/metagpt/utils/test_redis.py b/tests/metagpt/utils/test_redis.py index d499418ac..140c04f6b 100644 --- a/tests/metagpt/utils/test_redis.py +++ b/tests/metagpt/utils/test_redis.py @@ -5,8 +5,8 @@ @Author : mashenquan @File : test_redis.py """ +from unittest.mock import AsyncMock -import mock import pytest from metagpt.config import CONFIG @@ -14,20 +14,16 @@ from metagpt.utils.redis import Redis async def async_mock_from_url(*args, **kwargs): - mock_client = mock.AsyncMock() + mock_client = AsyncMock() mock_client.set.return_value = None mock_client.get.side_effect = [b"test", b""] return mock_client @pytest.mark.asyncio -@mock.patch("aioredis.from_url", return_value=async_mock_from_url()) -async def test_redis(mock_from_url): +async def test_redis(mocker): # Mock - # mock_client = mock.AsyncMock() - # mock_client.set.return_value=None - # mock_client.get.side_effect = [b'test', b''] - # mock_from_url.return_value = mock_client + mocker.patch("aioredis.from_url", return_value=async_mock_from_url()) # Prerequisites CONFIG.REDIS_HOST = "MOCK_REDIS_HOST" From bd2b1950eba09883790facbcb3b01b5b75cbd4c7 Mon Sep 17 00:00:00 2001 From: kkdev163 Date: Mon, 8 Jan 2024 22:29:17 +0800 Subject: [PATCH 04/18] optimize: access to is_human --- metagpt/roles/role.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metagpt/roles/role.py b/metagpt/roles/role.py index 71f6ec8f5..b234a846f 100644 --- a/metagpt/roles/role.py +++ b/metagpt/roles/role.py @@ -166,7 +166,7 @@ class Role(SerializationMixin, is_polymorphic_base=True): Role.model_rebuild() super().__init__(**data) - if data.get("is_human"): + if self.is_human: self.llm = HumanProvider() self.llm.system_prompt = self._get_prefix() From 032f9214b2e6de1142a036994cc4f00fe21c4fcf Mon Sep 17 00:00:00 2001 From: yzlin Date: Tue, 9 Jan 2024 10:30:57 +0800 Subject: [PATCH 05/18] rename workflow --- .github/workflows/unittest.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unittest.yaml b/.github/workflows/unittest.yaml index bdb080767..2b81b9b6c 100644 --- a/.github/workflows/unittest.yaml +++ b/.github/workflows/unittest.yaml @@ -1,4 +1,4 @@ -name: Python application test +name: Unit Tests on: workflow_dispatch: From 82a5eec72707dee44174eae8f8ff1490a6819ecd Mon Sep 17 00:00:00 2001 From: kkdev163 Date: Tue, 9 Jan 2024 12:01:57 +0800 Subject: [PATCH 06/18] fix(test_role): format error --- tests/metagpt/roles/test_role.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/metagpt/roles/test_role.py b/tests/metagpt/roles/test_role.py index 151608b6b..bef71f9a5 100644 --- a/tests/metagpt/roles/test_role.py +++ b/tests/metagpt/roles/test_role.py @@ -3,8 +3,8 @@ # @Desc : unittest of Role import pytest -from metagpt.roles.role import Role from metagpt.llm import HumanProvider +from metagpt.roles.role import Role def test_role_desc(): @@ -12,9 +12,11 @@ def test_role_desc(): assert role.profile == "Sales" assert role.desc == "Best Seller" + def test_role_human(): role = Role(is_human=True) assert isinstance(role.llm, HumanProvider) + if __name__ == "__main__": pytest.main([__file__, "-s"]) From 683306dc10b31810d00ff9158f52334a0a18e2fd Mon Sep 17 00:00:00 2001 From: voidking Date: Tue, 9 Jan 2024 16:12:32 +0800 Subject: [PATCH 07/18] feat: build and upload python package --- .github/workflows/build-package.yaml | 34 ++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/workflows/build-package.yaml diff --git a/.github/workflows/build-package.yaml b/.github/workflows/build-package.yaml new file mode 100644 index 000000000..7f4fee53e --- /dev/null +++ b/.github/workflows/build-package.yaml @@ -0,0 +1,34 @@ +name: Build and upload python package + +on: + release: + types: [created] + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.9' + cache: 'pip' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install -e. + pip install setuptools wheel twine + - name: Set package version + run: | + export VERSION="${GITHUB_REF#refs/tags/v}" + sed -i "s/version=.*/version=\"${VERSION}\",/" setup.py + - name: Build and publish + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} + run: | + python setup.py bdist_wheel sdist + twine upload dist/* \ No newline at end of file From 17479a23608a36a7d67f22f3d9f25d1046f24d3f Mon Sep 17 00:00:00 2001 From: better629 Date: Wed, 10 Jan 2024 11:26:23 +0800 Subject: [PATCH 08/18] fix system_prompt param that llm not support from issue 725 --- metagpt/provider/base_llm.py | 4 +++- tests/mock/mock_llm.py | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/metagpt/provider/base_llm.py b/metagpt/provider/base_llm.py index 52dd96b1a..d23d162c8 100644 --- a/metagpt/provider/base_llm.py +++ b/metagpt/provider/base_llm.py @@ -43,7 +43,9 @@ class BaseLLM(ABC): if system_msgs: message = self._system_msgs(system_msgs) else: - message = [self._default_system_msg()] if self.use_system_prompt else [] + message = [self._default_system_msg()] + if not self.use_system_prompt: + message = [] if format_msgs: message.extend(format_msgs) message.append(self._user_msg(msg)) diff --git a/tests/mock/mock_llm.py b/tests/mock/mock_llm.py index 6e7a1cdd5..35e0e9ee9 100644 --- a/tests/mock/mock_llm.py +++ b/tests/mock/mock_llm.py @@ -41,7 +41,9 @@ class MockLLM(OpenAILLM): if system_msgs: message = self._system_msgs(system_msgs) else: - message = [self._default_system_msg()] if self.use_system_prompt else [] + message = [self._default_system_msg()] + if not self.use_system_prompt: + message = [] if format_msgs: message.extend(format_msgs) message.append(self._user_msg(msg)) From 5f6b509ac857bf7a57b0848346d18486c5772036 Mon Sep 17 00:00:00 2001 From: geekan Date: Thu, 11 Jan 2024 19:10:27 +0800 Subject: [PATCH 09/18] refine code --- examples/example.pkl | Bin 624 -> 624 bytes tests/data/rsp_cache.json | 5 ++++- tests/metagpt/test_config.py | 10 +++++----- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/examples/example.pkl b/examples/example.pkl index caa0cbd31ec5615c929d03bbc05aae73a25f6446..eac758f441110e558dea4e507ba67aa3c3b53eb0 100644 GIT binary patch delta 86 zcmWN_%ME}a3;@uWFp2S6V}H=@;spYX;S44&;0kWyD2$-*_(mAv+-KpqAvfrp9i%n^ mXGHMIxo2gI_#ErBBvExO4!KkUNkySF5n!|aHyaUM?{t3~tQYP8 delta 86 zcmWN^!3}^g2mrvCIEnF#0Yss@_$e(N!x>Cmz!luYQ5-?K#D6_C{$ ncvt`?7R!jL%e_zCn3zla0m6kqTotU*3}F~jYO2h1KHc>JL)jQ| diff --git a/tests/data/rsp_cache.json b/tests/data/rsp_cache.json index 422bb5a25..32c8f850a 100644 --- a/tests/data/rsp_cache.json +++ b/tests/data/rsp_cache.json @@ -186,5 +186,8 @@ "You are a python code to Mermaid Sequence Diagram translator in function detail#SYSTEM_MSG_END#```python\n#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nfrom __future__ import annotations\n\nimport asyncio\nimport json\nfrom concurrent import futures\nfrom typing import Optional\nfrom urllib.parse import urlparse\n\nimport httplib2\nfrom pydantic import BaseModel, ConfigDict, Field, field_validator\n\nfrom metagpt.config2 import config\nfrom metagpt.logs import logger\n\ntry:\n from googleapiclient.discovery import build\n from googleapiclient.errors import HttpError\nexcept ImportError:\n raise ImportError(\n \"To use this module, you should have the `google-api-python-client` Python package installed. \"\n \"You can install it by running the command: `pip install -e.[search-google]`\"\n )\n\n\nclass GoogleAPIWrapper(BaseModel):\n model_config = ConfigDict(arbitrary_types_allowed=True)\n\n google_api_key: Optional[str] = Field(default=None, validate_default=True)\n google_cse_id: Optional[str] = Field(default=None, validate_default=True)\n loop: Optional[asyncio.AbstractEventLoop] = None\n executor: Optional[futures.Executor] = None\n\n @field_validator(\"google_api_key\", mode=\"before\")\n @classmethod\n def check_google_api_key(cls, val: str):\n val = val or config.search.api_key\n if not val:\n raise ValueError(\n \"To use, make sure you provide the google_api_key when constructing an object. Alternatively, \"\n \"ensure that the environment variable GOOGLE_API_KEY is set with your API key. You can obtain \"\n \"an API key from https://console.cloud.google.com/apis/credentials.\"\n )\n return val\n\n @field_validator(\"google_cse_id\", mode=\"before\")\n @classmethod\n def check_google_cse_id(cls, val: str):\n val = val or config.search.cse_id\n if not val:\n raise ValueError(\n \"To use, make sure you provide the google_cse_id when constructing an object. Alternatively, \"\n \"ensure that the environment variable GOOGLE_CSE_ID is set with your API key. You can obtain \"\n \"an API key from https://programmablesearchengine.google.com/controlpanel/create.\"\n )\n return val\n\n @property\n def google_api_client(self):\n build_kwargs = {\"developerKey\": self.google_api_key}\n if config.proxy:\n parse_result = urlparse(config.proxy)\n proxy_type = parse_result.scheme\n if proxy_type == \"https\":\n proxy_type = \"http\"\n build_kwargs[\"http\"] = httplib2.Http(\n proxy_info=httplib2.ProxyInfo(\n getattr(httplib2.socks, f\"PROXY_TYPE_{proxy_type.upper()}\"),\n parse_result.hostname,\n parse_result.port,\n ),\n )\n service = build(\"customsearch\", \"v1\", **build_kwargs)\n return service.cse()\n\n async def run(\n self,\n query: str,\n max_results: int = 8,\n as_string: bool = True,\n focus: list[str] | None = None,\n ) -> str | list[dict]:\n \"\"\"Return the results of a Google search using the official Google API.\n\n Args:\n query: The search query.\n max_results: The number of results to return.\n as_string: A boolean flag to determine the return type of the results. If True, the function will\n return a formatted string with the search results. If False, it will return a list of dictionaries\n containing detailed information about each search result.\n focus: Specific information to be focused on from each search result.\n\n Returns:\n The results of the search.\n \"\"\"\n loop = self.loop or asyncio.get_event_loop()\n future = loop.run_in_executor(\n self.executor, self.google_api_client.list(q=query, num=max_results, cx=self.google_cse_id).execute\n )\n try:\n result = await future\n # Extract the search result items from the response\n search_results = result.get(\"items\", [])\n\n except HttpError as e:\n # Handle errors in the API call\n logger.exception(f\"fail to search {query} for {e}\")\n search_results = []\n\n focus = focus or [\"snippet\", \"link\", \"title\"]\n details = [{i: j for i, j in item_dict.items() if i in focus} for item_dict in search_results]\n # Return the list of search result URLs\n if as_string:\n return safe_google_results(details)\n\n return details\n\n\ndef safe_google_results(results: str | list) -> str:\n \"\"\"Return the results of a google search in a safe format.\n\n Args:\n results: The search results.\n\n Returns:\n The results of the search.\n \"\"\"\n if isinstance(results, list):\n safe_message = json.dumps([result for result in results])\n else:\n safe_message = results.encode(\"utf-8\", \"ignore\").decode(\"utf-8\")\n return safe_message\n\n\nif __name__ == \"__main__\":\n import fire\n\n fire.Fire(GoogleAPIWrapper().run)\n\n```\n\n---\nTranslate the code above into Mermaid Sequence Diagram.": "```mermaid\nsequenceDiagram\n participant BaseModel\n participant httplib2\n participant asyncio\n participant futures\n participant urlparse\n participant json\n participant config\n participant logger\n participant googleapiclient.discovery\n participant googleapiclient.errors\n participant fire\n\n BaseModel->>ConfigDict: model_config\n BaseModel->>Optional: google_api_key\n BaseModel->>Optional: google_cse_id\n BaseModel->>Optional: loop\n BaseModel->>Optional: executor\n BaseModel->>googleapiclient.discovery: check_google_api_key\n BaseModel->>googleapiclient.discovery: check_google_cse_id\n BaseModel->>googleapiclient.discovery: google_api_client\n BaseModel->>asyncio: run\n asyncio->>futures: run_in_executor\n futures->>googleapiclient.discovery: list\n googleapiclient.discovery->>googleapiclient.discovery: execute\n googleapiclient.discovery-->>futures: result\n futures-->>asyncio: result\n asyncio-->>BaseModel: result\n BaseModel-->>BaseModel: safe_google_results\n BaseModel-->>BaseModel: run\n BaseModel-->>fire: run\n```", "\n## context\n\n### Project Name\n20240111154819\n\n### Original Requirements\n['开发一个基于大语言模型与私有知识库的搜索引擎,希望可以基于大语言模型进行搜索总结']\n\n### Search Information\n-\n\n\n-----\n\n## format example\n[CONTENT]\n{\n \"Language\": \"en_us\",\n \"Programming Language\": \"Python\",\n \"Original Requirements\": \"Create a 2048 game\",\n \"Product Goals\": [\n \"Create an engaging user experience\",\n \"Improve accessibility, be responsive\",\n \"More beautiful UI\"\n ],\n \"User Stories\": [\n \"As a player, I want to be able to choose difficulty levels\",\n \"As a player, I want to see my score after each game\",\n \"As a player, I want to get restart button when I lose\",\n \"As a player, I want to see beautiful UI that make me feel good\",\n \"As a player, I want to play game via mobile phone\"\n ],\n \"Competitive Analysis\": [\n \"2048 Game A: Simple interface, lacks responsive features\",\n \"play2048.co: Beautiful and responsive UI with my best score shown\",\n \"2048game.com: Responsive UI with my best score shown, but many ads\"\n ],\n \"Competitive Quadrant Chart\": \"quadrantChart\\n title \\\"Reach and engagement of campaigns\\\"\\n x-axis \\\"Low Reach\\\" --> \\\"High Reach\\\"\\n y-axis \\\"Low Engagement\\\" --> \\\"High Engagement\\\"\\n quadrant-1 \\\"We should expand\\\"\\n quadrant-2 \\\"Need to promote\\\"\\n quadrant-3 \\\"Re-evaluate\\\"\\n quadrant-4 \\\"May be improved\\\"\\n \\\"Campaign A\\\": [0.3, 0.6]\\n \\\"Campaign B\\\": [0.45, 0.23]\\n \\\"Campaign C\\\": [0.57, 0.69]\\n \\\"Campaign D\\\": [0.78, 0.34]\\n \\\"Campaign E\\\": [0.40, 0.34]\\n \\\"Campaign F\\\": [0.35, 0.78]\\n \\\"Our Target Product\\\": [0.5, 0.6]\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [\n [\n \"P0\",\n \"The main code ...\"\n ],\n [\n \"P0\",\n \"The game algorithm ...\"\n ]\n ],\n \"UI Design draft\": \"Basic function description with a simple style and layout.\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- Language: # Provide the language used in the project, typically matching the user's requirement language.\n- Programming Language: # Python/JavaScript or other mainstream programming language.\n- Original Requirements: # Place the original user's requirements here.\n- Product Goals: typing.List[str] # Provide up to three clear, orthogonal product goals.\n- User Stories: typing.List[str] # Provide up to 3 to 5 scenario-based user stories.\n- Competitive Analysis: typing.List[str] # Provide 5 to 7 competitive products.\n- Competitive Quadrant Chart: # Use mermaid quadrantChart syntax. Distribute scores evenly between 0 and 1\n- Requirement Analysis: # Provide a detailed analysis of the requirements.\n- Requirement Pool: typing.List[typing.List[str]] # List down the top-5 requirements with their priority (P0, P1, P2).\n- UI Design draft: # Provide a simple description of UI elements, functions, style, and layout.\n- Anything UNCLEAR: # Mention any aspects of the project that are unclear and try to clarify them.\n\n\n## constraint\nLanguage: Please use the same language as Human INPUT.\nFormat: output wrapped inside [CONTENT][/CONTENT] like format example, nothing else.\n\n## action\nFollow instructions of nodes, generate output and make sure it follows the format example.\n": "[CONTENT]\n{\n \"Language\": \"zh_cn\",\n \"Programming Language\": \"Python\",\n \"Original Requirements\": \"开发一个基于大语言模型与私有知识库的搜索引擎,希望可以基于大语言模型进行搜索总结\",\n \"Product Goals\": [],\n \"User Stories\": [],\n \"Competitive Analysis\": [],\n \"Competitive Quadrant Chart\": \"\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [],\n \"UI Design draft\": \"\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]", "\n## context\n\n### Project Name\n20240111154819\n\n### Original Requirements\n['']\n\n### Search Information\n-\n\n\n-----\n\n## format example\n[CONTENT]\n{\n \"Language\": \"en_us\",\n \"Programming Language\": \"Python\",\n \"Original Requirements\": \"Create a 2048 game\",\n \"Product Goals\": [\n \"Create an engaging user experience\",\n \"Improve accessibility, be responsive\",\n \"More beautiful UI\"\n ],\n \"User Stories\": [\n \"As a player, I want to be able to choose difficulty levels\",\n \"As a player, I want to see my score after each game\",\n \"As a player, I want to get restart button when I lose\",\n \"As a player, I want to see beautiful UI that make me feel good\",\n \"As a player, I want to play game via mobile phone\"\n ],\n \"Competitive Analysis\": [\n \"2048 Game A: Simple interface, lacks responsive features\",\n \"play2048.co: Beautiful and responsive UI with my best score shown\",\n \"2048game.com: Responsive UI with my best score shown, but many ads\"\n ],\n \"Competitive Quadrant Chart\": \"quadrantChart\\n title \\\"Reach and engagement of campaigns\\\"\\n x-axis \\\"Low Reach\\\" --> \\\"High Reach\\\"\\n y-axis \\\"Low Engagement\\\" --> \\\"High Engagement\\\"\\n quadrant-1 \\\"We should expand\\\"\\n quadrant-2 \\\"Need to promote\\\"\\n quadrant-3 \\\"Re-evaluate\\\"\\n quadrant-4 \\\"May be improved\\\"\\n \\\"Campaign A\\\": [0.3, 0.6]\\n \\\"Campaign B\\\": [0.45, 0.23]\\n \\\"Campaign C\\\": [0.57, 0.69]\\n \\\"Campaign D\\\": [0.78, 0.34]\\n \\\"Campaign E\\\": [0.40, 0.34]\\n \\\"Campaign F\\\": [0.35, 0.78]\\n \\\"Our Target Product\\\": [0.5, 0.6]\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [\n [\n \"P0\",\n \"The main code ...\"\n ],\n [\n \"P0\",\n \"The game algorithm ...\"\n ]\n ],\n \"UI Design draft\": \"Basic function description with a simple style and layout.\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- Language: # Provide the language used in the project, typically matching the user's requirement language.\n- Programming Language: # Python/JavaScript or other mainstream programming language.\n- Original Requirements: # Place the original user's requirements here.\n- Product Goals: typing.List[str] # Provide up to three clear, orthogonal product goals.\n- User Stories: typing.List[str] # Provide up to 3 to 5 scenario-based user stories.\n- Competitive Analysis: typing.List[str] # Provide 5 to 7 competitive products.\n- Competitive Quadrant Chart: # Use mermaid quadrantChart syntax. Distribute scores evenly between 0 and 1\n- Requirement Analysis: # Provide a detailed analysis of the requirements.\n- Requirement Pool: typing.List[typing.List[str]] # List down the top-5 requirements with their priority (P0, P1, P2).\n- UI Design draft: # Provide a simple description of UI elements, functions, style, and layout.\n- Anything UNCLEAR: # Mention any aspects of the project that are unclear and try to clarify them.\n\n\n## constraint\nLanguage: Please use the same language as Human INPUT.\nFormat: output wrapped inside [CONTENT][/CONTENT] like format example, nothing else.\n\n## action\nFollow instructions of nodes, generate output and make sure it follows the format example.\n": "[CONTENT]\n{\n \"Language\": \"en_us\",\n \"Programming Language\": \"Python\",\n \"Original Requirements\": \"\",\n \"Product Goals\": [],\n \"User Stories\": [],\n \"Competitive Analysis\": [],\n \"Competitive Quadrant Chart\": \"\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [],\n \"UI Design draft\": \"\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]", - "\n## context\n\n### Project Name\n20240111180901\n\n### Original Requirements\n['需要一个基于LLM做总结的搜索引擎']\n\n### Search Information\n-\n\n\n-----\n\n## format example\n[CONTENT]\n{\n \"Language\": \"en_us\",\n \"Programming Language\": \"Python\",\n \"Original Requirements\": \"Create a 2048 game\",\n \"Product Goals\": [\n \"Create an engaging user experience\",\n \"Improve accessibility, be responsive\",\n \"More beautiful UI\"\n ],\n \"User Stories\": [\n \"As a player, I want to be able to choose difficulty levels\",\n \"As a player, I want to see my score after each game\",\n \"As a player, I want to get restart button when I lose\",\n \"As a player, I want to see beautiful UI that make me feel good\",\n \"As a player, I want to play game via mobile phone\"\n ],\n \"Competitive Analysis\": [\n \"2048 Game A: Simple interface, lacks responsive features\",\n \"play2048.co: Beautiful and responsive UI with my best score shown\",\n \"2048game.com: Responsive UI with my best score shown, but many ads\"\n ],\n \"Competitive Quadrant Chart\": \"quadrantChart\\n title \\\"Reach and engagement of campaigns\\\"\\n x-axis \\\"Low Reach\\\" --> \\\"High Reach\\\"\\n y-axis \\\"Low Engagement\\\" --> \\\"High Engagement\\\"\\n quadrant-1 \\\"We should expand\\\"\\n quadrant-2 \\\"Need to promote\\\"\\n quadrant-3 \\\"Re-evaluate\\\"\\n quadrant-4 \\\"May be improved\\\"\\n \\\"Campaign A\\\": [0.3, 0.6]\\n \\\"Campaign B\\\": [0.45, 0.23]\\n \\\"Campaign C\\\": [0.57, 0.69]\\n \\\"Campaign D\\\": [0.78, 0.34]\\n \\\"Campaign E\\\": [0.40, 0.34]\\n \\\"Campaign F\\\": [0.35, 0.78]\\n \\\"Our Target Product\\\": [0.5, 0.6]\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [\n [\n \"P0\",\n \"The main code ...\"\n ],\n [\n \"P0\",\n \"The game algorithm ...\"\n ]\n ],\n \"UI Design draft\": \"Basic function description with a simple style and layout.\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- Language: # Provide the language used in the project, typically matching the user's requirement language.\n- Programming Language: # Python/JavaScript or other mainstream programming language.\n- Original Requirements: # Place the original user's requirements here.\n- Product Goals: typing.List[str] # Provide up to three clear, orthogonal product goals.\n- User Stories: typing.List[str] # Provide up to 3 to 5 scenario-based user stories.\n- Competitive Analysis: typing.List[str] # Provide 5 to 7 competitive products.\n- Competitive Quadrant Chart: # Use mermaid quadrantChart syntax. Distribute scores evenly between 0 and 1\n- Requirement Analysis: # Provide a detailed analysis of the requirements.\n- Requirement Pool: typing.List[typing.List[str]] # List down the top-5 requirements with their priority (P0, P1, P2).\n- UI Design draft: # Provide a simple description of UI elements, functions, style, and layout.\n- Anything UNCLEAR: # Mention any aspects of the project that are unclear and try to clarify them.\n\n\n## constraint\nLanguage: Please use the same language as Human INPUT.\nFormat: output wrapped inside [CONTENT][/CONTENT] like format example, nothing else.\n\n## action\nFollow instructions of nodes, generate output and make sure it follows the format example.\n": "[CONTENT]\n{\n \"Language\": \"zh_cn\",\n \"Programming Language\": \"LLM\",\n \"Original Requirements\": \"需要一个基于LLM做总结的搜索引擎\",\n \"Product Goals\": [],\n \"User Stories\": [],\n \"Competitive Analysis\": [],\n \"Competitive Quadrant Chart\": \"\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [],\n \"UI Design draft\": \"\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]" + "\n## context\n\n### Project Name\n20240111180901\n\n### Original Requirements\n['需要一个基于LLM做总结的搜索引擎']\n\n### Search Information\n-\n\n\n-----\n\n## format example\n[CONTENT]\n{\n \"Language\": \"en_us\",\n \"Programming Language\": \"Python\",\n \"Original Requirements\": \"Create a 2048 game\",\n \"Product Goals\": [\n \"Create an engaging user experience\",\n \"Improve accessibility, be responsive\",\n \"More beautiful UI\"\n ],\n \"User Stories\": [\n \"As a player, I want to be able to choose difficulty levels\",\n \"As a player, I want to see my score after each game\",\n \"As a player, I want to get restart button when I lose\",\n \"As a player, I want to see beautiful UI that make me feel good\",\n \"As a player, I want to play game via mobile phone\"\n ],\n \"Competitive Analysis\": [\n \"2048 Game A: Simple interface, lacks responsive features\",\n \"play2048.co: Beautiful and responsive UI with my best score shown\",\n \"2048game.com: Responsive UI with my best score shown, but many ads\"\n ],\n \"Competitive Quadrant Chart\": \"quadrantChart\\n title \\\"Reach and engagement of campaigns\\\"\\n x-axis \\\"Low Reach\\\" --> \\\"High Reach\\\"\\n y-axis \\\"Low Engagement\\\" --> \\\"High Engagement\\\"\\n quadrant-1 \\\"We should expand\\\"\\n quadrant-2 \\\"Need to promote\\\"\\n quadrant-3 \\\"Re-evaluate\\\"\\n quadrant-4 \\\"May be improved\\\"\\n \\\"Campaign A\\\": [0.3, 0.6]\\n \\\"Campaign B\\\": [0.45, 0.23]\\n \\\"Campaign C\\\": [0.57, 0.69]\\n \\\"Campaign D\\\": [0.78, 0.34]\\n \\\"Campaign E\\\": [0.40, 0.34]\\n \\\"Campaign F\\\": [0.35, 0.78]\\n \\\"Our Target Product\\\": [0.5, 0.6]\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [\n [\n \"P0\",\n \"The main code ...\"\n ],\n [\n \"P0\",\n \"The game algorithm ...\"\n ]\n ],\n \"UI Design draft\": \"Basic function description with a simple style and layout.\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- Language: # Provide the language used in the project, typically matching the user's requirement language.\n- Programming Language: # Python/JavaScript or other mainstream programming language.\n- Original Requirements: # Place the original user's requirements here.\n- Product Goals: typing.List[str] # Provide up to three clear, orthogonal product goals.\n- User Stories: typing.List[str] # Provide up to 3 to 5 scenario-based user stories.\n- Competitive Analysis: typing.List[str] # Provide 5 to 7 competitive products.\n- Competitive Quadrant Chart: # Use mermaid quadrantChart syntax. Distribute scores evenly between 0 and 1\n- Requirement Analysis: # Provide a detailed analysis of the requirements.\n- Requirement Pool: typing.List[typing.List[str]] # List down the top-5 requirements with their priority (P0, P1, P2).\n- UI Design draft: # Provide a simple description of UI elements, functions, style, and layout.\n- Anything UNCLEAR: # Mention any aspects of the project that are unclear and try to clarify them.\n\n\n## constraint\nLanguage: Please use the same language as Human INPUT.\nFormat: output wrapped inside [CONTENT][/CONTENT] like format example, nothing else.\n\n## action\nFollow instructions of nodes, generate output and make sure it follows the format example.\n": "[CONTENT]\n{\n \"Language\": \"zh_cn\",\n \"Programming Language\": \"LLM\",\n \"Original Requirements\": \"需要一个基于LLM做总结的搜索引擎\",\n \"Product Goals\": [],\n \"User Stories\": [],\n \"Competitive Analysis\": [],\n \"Competitive Quadrant Chart\": \"\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [],\n \"UI Design draft\": \"\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]", + "\n## context\n\n### Project Name\n20240111181214\n\n### Original Requirements\n['需要一个基于LLM做总结的搜索引擎']\n\n### Search Information\n-\n\n\n-----\n\n## format example\n[CONTENT]\n{\n \"Language\": \"en_us\",\n \"Programming Language\": \"Python\",\n \"Original Requirements\": \"Create a 2048 game\",\n \"Product Goals\": [\n \"Create an engaging user experience\",\n \"Improve accessibility, be responsive\",\n \"More beautiful UI\"\n ],\n \"User Stories\": [\n \"As a player, I want to be able to choose difficulty levels\",\n \"As a player, I want to see my score after each game\",\n \"As a player, I want to get restart button when I lose\",\n \"As a player, I want to see beautiful UI that make me feel good\",\n \"As a player, I want to play game via mobile phone\"\n ],\n \"Competitive Analysis\": [\n \"2048 Game A: Simple interface, lacks responsive features\",\n \"play2048.co: Beautiful and responsive UI with my best score shown\",\n \"2048game.com: Responsive UI with my best score shown, but many ads\"\n ],\n \"Competitive Quadrant Chart\": \"quadrantChart\\n title \\\"Reach and engagement of campaigns\\\"\\n x-axis \\\"Low Reach\\\" --> \\\"High Reach\\\"\\n y-axis \\\"Low Engagement\\\" --> \\\"High Engagement\\\"\\n quadrant-1 \\\"We should expand\\\"\\n quadrant-2 \\\"Need to promote\\\"\\n quadrant-3 \\\"Re-evaluate\\\"\\n quadrant-4 \\\"May be improved\\\"\\n \\\"Campaign A\\\": [0.3, 0.6]\\n \\\"Campaign B\\\": [0.45, 0.23]\\n \\\"Campaign C\\\": [0.57, 0.69]\\n \\\"Campaign D\\\": [0.78, 0.34]\\n \\\"Campaign E\\\": [0.40, 0.34]\\n \\\"Campaign F\\\": [0.35, 0.78]\\n \\\"Our Target Product\\\": [0.5, 0.6]\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [\n [\n \"P0\",\n \"The main code ...\"\n ],\n [\n \"P0\",\n \"The game algorithm ...\"\n ]\n ],\n \"UI Design draft\": \"Basic function description with a simple style and layout.\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- Language: # Provide the language used in the project, typically matching the user's requirement language.\n- Programming Language: # Python/JavaScript or other mainstream programming language.\n- Original Requirements: # Place the original user's requirements here.\n- Product Goals: typing.List[str] # Provide up to three clear, orthogonal product goals.\n- User Stories: typing.List[str] # Provide up to 3 to 5 scenario-based user stories.\n- Competitive Analysis: typing.List[str] # Provide 5 to 7 competitive products.\n- Competitive Quadrant Chart: # Use mermaid quadrantChart syntax. Distribute scores evenly between 0 and 1\n- Requirement Analysis: # Provide a detailed analysis of the requirements.\n- Requirement Pool: typing.List[typing.List[str]] # List down the top-5 requirements with their priority (P0, P1, P2).\n- UI Design draft: # Provide a simple description of UI elements, functions, style, and layout.\n- Anything UNCLEAR: # Mention any aspects of the project that are unclear and try to clarify them.\n\n\n## constraint\nLanguage: Please use the same language as Human INPUT.\nFormat: output wrapped inside [CONTENT][/CONTENT] like format example, nothing else.\n\n## action\nFollow instructions of nodes, generate output and make sure it follows the format example.\n": "[CONTENT]\n{\n \"Language\": \"zh_cn\",\n \"Programming Language\": \"LLM\",\n \"Original Requirements\": \"需要一个基于LLM做总结的搜索引擎\",\n \"Product Goals\": [],\n \"User Stories\": [],\n \"Competitive Analysis\": [],\n \"Competitive Quadrant Chart\": \"\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [],\n \"UI Design draft\": \"\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]", + "\n## context\n\n### Project Name\n20240111181426\n\n### Original Requirements\n['开发一个基于大语言模型与私有知识库的搜索引擎,希望可以基于大语言模型进行搜索总结']\n\n### Search Information\n-\n\n\n-----\n\n## format example\n[CONTENT]\n{\n \"Language\": \"en_us\",\n \"Programming Language\": \"Python\",\n \"Original Requirements\": \"Create a 2048 game\",\n \"Product Goals\": [\n \"Create an engaging user experience\",\n \"Improve accessibility, be responsive\",\n \"More beautiful UI\"\n ],\n \"User Stories\": [\n \"As a player, I want to be able to choose difficulty levels\",\n \"As a player, I want to see my score after each game\",\n \"As a player, I want to get restart button when I lose\",\n \"As a player, I want to see beautiful UI that make me feel good\",\n \"As a player, I want to play game via mobile phone\"\n ],\n \"Competitive Analysis\": [\n \"2048 Game A: Simple interface, lacks responsive features\",\n \"play2048.co: Beautiful and responsive UI with my best score shown\",\n \"2048game.com: Responsive UI with my best score shown, but many ads\"\n ],\n \"Competitive Quadrant Chart\": \"quadrantChart\\n title \\\"Reach and engagement of campaigns\\\"\\n x-axis \\\"Low Reach\\\" --> \\\"High Reach\\\"\\n y-axis \\\"Low Engagement\\\" --> \\\"High Engagement\\\"\\n quadrant-1 \\\"We should expand\\\"\\n quadrant-2 \\\"Need to promote\\\"\\n quadrant-3 \\\"Re-evaluate\\\"\\n quadrant-4 \\\"May be improved\\\"\\n \\\"Campaign A\\\": [0.3, 0.6]\\n \\\"Campaign B\\\": [0.45, 0.23]\\n \\\"Campaign C\\\": [0.57, 0.69]\\n \\\"Campaign D\\\": [0.78, 0.34]\\n \\\"Campaign E\\\": [0.40, 0.34]\\n \\\"Campaign F\\\": [0.35, 0.78]\\n \\\"Our Target Product\\\": [0.5, 0.6]\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [\n [\n \"P0\",\n \"The main code ...\"\n ],\n [\n \"P0\",\n \"The game algorithm ...\"\n ]\n ],\n \"UI Design draft\": \"Basic function description with a simple style and layout.\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- Language: # Provide the language used in the project, typically matching the user's requirement language.\n- Programming Language: # Python/JavaScript or other mainstream programming language.\n- Original Requirements: # Place the original user's requirements here.\n- Product Goals: typing.List[str] # Provide up to three clear, orthogonal product goals.\n- User Stories: typing.List[str] # Provide up to 3 to 5 scenario-based user stories.\n- Competitive Analysis: typing.List[str] # Provide 5 to 7 competitive products.\n- Competitive Quadrant Chart: # Use mermaid quadrantChart syntax. Distribute scores evenly between 0 and 1\n- Requirement Analysis: # Provide a detailed analysis of the requirements.\n- Requirement Pool: typing.List[typing.List[str]] # List down the top-5 requirements with their priority (P0, P1, P2).\n- UI Design draft: # Provide a simple description of UI elements, functions, style, and layout.\n- Anything UNCLEAR: # Mention any aspects of the project that are unclear and try to clarify them.\n\n\n## constraint\nLanguage: Please use the same language as Human INPUT.\nFormat: output wrapped inside [CONTENT][/CONTENT] like format example, nothing else.\n\n## action\nFollow instructions of nodes, generate output and make sure it follows the format example.\n": "[CONTENT]\n{\n \"Language\": \"zh_cn\",\n \"Programming Language\": \"Python\",\n \"Original Requirements\": \"开发一个基于大语言模型与私有知识库的搜索引擎,希望可以基于大语言模型进行搜索总结\",\n \"Product Goals\": [\n \"提供高效的搜索功能\",\n \"整合私有知识库\",\n \"生成准确的搜索总结\"\n ],\n \"User Stories\": [\n \"作为用户,我希望能够快速找到所需信息\",\n \"作为用户,我希望搜索结果能够涵盖私有知识库内容\",\n \"作为用户,我希望搜索总结能够准确反映所需信息\"\n ],\n \"Competitive Analysis\": [\n \"搜索引擎A:搜索速度快,但不支持私有知识库整合\",\n \"搜索引擎B:支持私有知识库整合,但搜索总结不够准确\",\n \"搜索引擎C:准确的搜索总结,但不支持私有知识库整合\"\n ],\n \"Competitive Quadrant Chart\": \"quadrantChart\\n title \\\"搜索引擎比较\\\"\\n x-axis \\\"低速度\\\" --> \\\"高速度\\\"\\n y-axis \\\"低准确性\\\" --> \\\"高准确性\\\"\\n quadrant-1 \\\"速度快,准确性低\\\"\\n quadrant-2 \\\"速度慢,准确性低\\\"\\n quadrant-3 \\\"速度慢,准确性高\\\"\\n quadrant-4 \\\"速度快,准确性高\\\"\\n \\\"搜索引擎A\\\": [0.8, 0.3]\\n \\\"搜索引擎B\\\": [0.4, 0.2]\\n \\\"搜索引擎C\\\": [0.2, 0.9]\\n \\\"我们的目标产品\\\": [0.7, 0.8]\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [\n [\n \"P0\",\n \"基于大语言模型的搜索功能\"\n ],\n [\n \"P0\",\n \"私有知识库整合\"\n ],\n [\n \"P1\",\n \"搜索总结生成\"\n ]\n ],\n \"UI Design draft\": \"简洁的搜索界面,包含私有知识库搜索选项。\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]", + "\n## context\n\n### Project Name\n20240111181426\n\n### Original Requirements\n['']\n\n### Search Information\n-\n\n\n-----\n\n## format example\n[CONTENT]\n{\n \"Language\": \"en_us\",\n \"Programming Language\": \"Python\",\n \"Original Requirements\": \"Create a 2048 game\",\n \"Product Goals\": [\n \"Create an engaging user experience\",\n \"Improve accessibility, be responsive\",\n \"More beautiful UI\"\n ],\n \"User Stories\": [\n \"As a player, I want to be able to choose difficulty levels\",\n \"As a player, I want to see my score after each game\",\n \"As a player, I want to get restart button when I lose\",\n \"As a player, I want to see beautiful UI that make me feel good\",\n \"As a player, I want to play game via mobile phone\"\n ],\n \"Competitive Analysis\": [\n \"2048 Game A: Simple interface, lacks responsive features\",\n \"play2048.co: Beautiful and responsive UI with my best score shown\",\n \"2048game.com: Responsive UI with my best score shown, but many ads\"\n ],\n \"Competitive Quadrant Chart\": \"quadrantChart\\n title \\\"Reach and engagement of campaigns\\\"\\n x-axis \\\"Low Reach\\\" --> \\\"High Reach\\\"\\n y-axis \\\"Low Engagement\\\" --> \\\"High Engagement\\\"\\n quadrant-1 \\\"We should expand\\\"\\n quadrant-2 \\\"Need to promote\\\"\\n quadrant-3 \\\"Re-evaluate\\\"\\n quadrant-4 \\\"May be improved\\\"\\n \\\"Campaign A\\\": [0.3, 0.6]\\n \\\"Campaign B\\\": [0.45, 0.23]\\n \\\"Campaign C\\\": [0.57, 0.69]\\n \\\"Campaign D\\\": [0.78, 0.34]\\n \\\"Campaign E\\\": [0.40, 0.34]\\n \\\"Campaign F\\\": [0.35, 0.78]\\n \\\"Our Target Product\\\": [0.5, 0.6]\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [\n [\n \"P0\",\n \"The main code ...\"\n ],\n [\n \"P0\",\n \"The game algorithm ...\"\n ]\n ],\n \"UI Design draft\": \"Basic function description with a simple style and layout.\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- Language: # Provide the language used in the project, typically matching the user's requirement language.\n- Programming Language: # Python/JavaScript or other mainstream programming language.\n- Original Requirements: # Place the original user's requirements here.\n- Product Goals: typing.List[str] # Provide up to three clear, orthogonal product goals.\n- User Stories: typing.List[str] # Provide up to 3 to 5 scenario-based user stories.\n- Competitive Analysis: typing.List[str] # Provide 5 to 7 competitive products.\n- Competitive Quadrant Chart: # Use mermaid quadrantChart syntax. Distribute scores evenly between 0 and 1\n- Requirement Analysis: # Provide a detailed analysis of the requirements.\n- Requirement Pool: typing.List[typing.List[str]] # List down the top-5 requirements with their priority (P0, P1, P2).\n- UI Design draft: # Provide a simple description of UI elements, functions, style, and layout.\n- Anything UNCLEAR: # Mention any aspects of the project that are unclear and try to clarify them.\n\n\n## constraint\nLanguage: Please use the same language as Human INPUT.\nFormat: output wrapped inside [CONTENT][/CONTENT] like format example, nothing else.\n\n## action\nFollow instructions of nodes, generate output and make sure it follows the format example.\n": "[CONTENT]\n{\n \"Language\": \"en_us\",\n \"Programming Language\": \"Python\",\n \"Original Requirements\": \"\",\n \"Product Goals\": [],\n \"User Stories\": [],\n \"Competitive Analysis\": [],\n \"Competitive Quadrant Chart\": \"quadrantChart\\n title \\\"Reach and engagement of campaigns\\\"\\n x-axis \\\"Low Reach\\\" --> \\\"High Reach\\\"\\n y-axis \\\"Low Engagement\\\" --> \\\"High Engagement\\\"\\n quadrant-1 \\\"We should expand\\\"\\n quadrant-2 \\\"Need to promote\\\"\\n quadrant-3 \\\"Re-evaluate\\\"\\n quadrant-4 \\\"May be improved\\\"\\n \\\"Campaign A\\\": [0.3, 0.6]\\n \\\"Campaign B\\\": [0.45, 0.23]\\n \\\"Campaign C\\\": [0.57, 0.69]\\n \\\"Campaign D\\\": [0.78, 0.34]\\n \\\"Campaign E\\\": [0.40, 0.34]\\n \\\"Campaign F\\\": [0.35, 0.78]\\n \\\"Our Target Product\\\": [0.5, 0.6]\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [],\n \"UI Design draft\": \"Basic function description with a simple style and layout.\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]" } \ No newline at end of file diff --git a/tests/metagpt/test_config.py b/tests/metagpt/test_config.py index 29f473c1f..0785079fe 100644 --- a/tests/metagpt/test_config.py +++ b/tests/metagpt/test_config.py @@ -66,13 +66,13 @@ def test_config_mixin_3(): i = Config(llm=mock_llm_config) j = Config(llm=mock_llm_config_proxy) obj = ModelY(config=i) - assert obj.private_config == i - assert obj.private_config.llm == mock_llm_config + assert obj.config == i + assert obj.config.llm == mock_llm_config obj.set_config(j) # obj already has a config, so it will not be set - assert obj.private_config == i - assert obj.private_config.llm == mock_llm_config + assert obj.config == i + assert obj.config.llm == mock_llm_config assert obj.a == "a" assert obj.b == "b" @@ -80,4 +80,4 @@ def test_config_mixin_3(): assert obj.d == "d" print(obj.__dict__.keys()) - assert "_config" in obj.__dict__.keys() + assert "private_config" in obj.__dict__.keys() From da87e6aa8c63888996c335bf9102054900c9196f Mon Sep 17 00:00:00 2001 From: geekan Date: Thu, 11 Jan 2024 19:16:55 +0800 Subject: [PATCH 10/18] Update ROADMAP.md --- docs/ROADMAP.md | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index d3f7ea408..9bc62f849 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -9,24 +9,22 @@ ### Short-term Objective 1. Become the multi-agent framework with the highest ROI. 2. Support fully automatic implementation of medium-sized projects (around 2000 lines of code). -3. Implement most identified tasks, reaching version 0.5. +3. Implement most identified tasks, reaching version 1.0. ### Tasks -To reach version v0.5, approximately 70% of the following tasks need to be completed. - 1. Usability 1. ~~Release v0.01 pip package to try to solve issues like npm installation (though not necessarily successfully)~~ (v0.3.0) - 2. Support for overall save and recovery of software companies + 2. ~~Support for overall save and recovery of software companies~~ (v0.6.0) 3. ~~Support human confirmation and modification during the process~~ (v0.3.0) New: Support human confirmation and modification with fewer constrainsts and a more user-friendly interface 4. Support process caching: Consider carefully whether to add server caching mechanism 5. ~~Resolve occasional failure to follow instruction under current prompts, causing code parsing errors, through stricter system prompts~~ (v0.4.0, with function call) 6. Write documentation, describing the current features and usage at all levels (ongoing, continuously adding contents to [documentation site](https://docs.deepwisdom.ai/main/en/guide/get_started/introduction.html)) 7. ~~Support Docker~~ 2. Features - 1. Support a more standard and stable parser (need to analyze the format that the current LLM is better at) - 2. ~~Establish a separate output queue, differentiated from the message queue~~ - 3. Attempt to atomize all role work, but this may significantly increase token overhead + 1. ~~Support a more standard and stable parser (need to analyze the format that the current LLM is better at)~~ (v0.5.0) + 2. ~~Establish a separate output queue, differentiated from the message queue~~ (v0.5.0) + 3. ~~Attempt to atomize all role work, but this may significantly increase token overhead~~ (v0.5.0) 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 @@ -43,10 +41,10 @@ ### Tasks 4. Actions 1. ~~Implementation: Search~~ (v0.2.1) 2. Implementation: Knowledge search, supporting 10+ data formats - 3. Implementation: Data EDA (expected v0.6.0) - 4. Implementation: Review - 5. ~~Implementation~~: Add Document (v0.5.0) - 6. ~~Implementation~~: Delete Document (v0.5.0) + 3. Implementation: Data EDA (expected v0.7.0) + 4. Implementation: Review & Revise (expected v0.7.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 @@ -64,23 +62,23 @@ ### Tasks 3. ~~Support Playwright apis~~ 7. Roles 1. Perfect the action pool/skill pool for each role - 2. Red Book blogger - 3. E-commerce seller - 4. Data analyst (expected v0.6.0) - 5. News observer - 6. ~~Institutional researcher~~ (v0.2.1) + 2. E-commerce seller + 3. Data analyst (expected v0.7.0) + 4. News observer + 5. ~~Institutional researcher~~ (v0.2.1) 8. Evaluation 1. Support an evaluation on a game dataset (experimentation done with game agents) 2. Reproduce papers, implement full skill acquisition for a single game role, achieving SOTA results (experimentation done with game agents) - 3. Support an evaluation on a math dataset (expected v0.6.0) + 3. Support an evaluation on a math dataset (expected v0.7.0) 4. Reproduce papers, achieving SOTA results for current mathematical problem solving process 9. LLM 1. Support Claude underlying API 2. ~~Support Azure asynchronous API~~ 3. Support streaming version of all APIs 4. ~~Make gpt-3.5-turbo available (HARD)~~ + 5. Support 10. Other - 1. Clean up existing unused code + 1. ~~Clean up existing unused code~~ 2. Unify all code styles and establish contribution standards - 3. Multi-language support - 4. Multi-programming-language support + 3. ~~Multi-language support~~ + 4. ~~Multi-programming-language support~~ From 5596e7e217f03706703179bb0f6a326e05a24627 Mon Sep 17 00:00:00 2001 From: geekan Date: Thu, 11 Jan 2024 19:21:09 +0800 Subject: [PATCH 11/18] add comment --- metagpt/context_mixin.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/metagpt/context_mixin.py b/metagpt/context_mixin.py index c83400669..94c2dcd37 100644 --- a/metagpt/context_mixin.py +++ b/metagpt/context_mixin.py @@ -19,6 +19,11 @@ class ContextMixin(BaseModel): model_config = ConfigDict(arbitrary_types_allowed=True) + # Pydantic has bug on _private_attr when using inheritance, so we use private_* instead + # - https://github.com/pydantic/pydantic/issues/7142 + # - https://github.com/pydantic/pydantic/issues/7083 + # - https://github.com/pydantic/pydantic/issues/7091 + # Env/Role/Action will use this context as private context, or use self.context as public context private_context: Optional[Context] = Field(default=None, exclude=True) # Env/Role/Action will use this config as private config, or use self.context.config as public config From 45f5b02475ef0e7ea37ce4953b7411912a68c035 Mon Sep 17 00:00:00 2001 From: geekan Date: Thu, 11 Jan 2024 19:32:29 +0800 Subject: [PATCH 12/18] refine code --- tests/metagpt/provider/mock_llm_config.py | 1 + tests/metagpt/test_config.py | 61 +-------------- tests/metagpt/test_context_mixin.py | 93 +++++++++++++++++++++++ 3 files changed, 95 insertions(+), 60 deletions(-) create mode 100644 tests/metagpt/test_context_mixin.py diff --git a/tests/metagpt/provider/mock_llm_config.py b/tests/metagpt/provider/mock_llm_config.py index 0f28ab54d..e2f626a6a 100644 --- a/tests/metagpt/provider/mock_llm_config.py +++ b/tests/metagpt/provider/mock_llm_config.py @@ -39,5 +39,6 @@ mock_llm_config_zhipu = LLMConfig( llm_type="zhipu", api_key="mock_api_key.zhipu", base_url="mock_base_url", + model="mock_zhipu_model", proxy="http://localhost:8080", ) diff --git a/tests/metagpt/test_config.py b/tests/metagpt/test_config.py index 0785079fe..7ce5765cf 100644 --- a/tests/metagpt/test_config.py +++ b/tests/metagpt/test_config.py @@ -5,15 +5,10 @@ @Author : alexanderwu @File : test_config.py """ -from pydantic import BaseModel from metagpt.config2 import Config from metagpt.configs.llm_config import LLMType -from metagpt.context_mixin import ContextMixin -from tests.metagpt.provider.mock_llm_config import ( - mock_llm_config, - mock_llm_config_proxy, -) +from tests.metagpt.provider.mock_llm_config import mock_llm_config def test_config_1(): @@ -27,57 +22,3 @@ def test_config_from_dict(): cfg = Config(llm=mock_llm_config) assert cfg assert cfg.llm.api_key == "mock_api_key" - - -class ModelX(ContextMixin, BaseModel): - a: str = "a" - b: str = "b" - - -class WTFMixin(BaseModel): - c: str = "c" - d: str = "d" - - -class ModelY(WTFMixin, ModelX): - pass - - -def test_config_mixin_1(): - new_model = ModelX() - assert new_model.a == "a" - assert new_model.b == "b" - - -def test_config_mixin_2(): - i = Config(llm=mock_llm_config) - j = Config(llm=mock_llm_config_proxy) - obj = ModelX(config=i) - assert obj.config == i - assert obj.config.llm == mock_llm_config - - obj.set_config(j) - # obj already has a config, so it will not be set - assert obj.config == i - - -def test_config_mixin_3(): - """Test config mixin with multiple inheritance""" - i = Config(llm=mock_llm_config) - j = Config(llm=mock_llm_config_proxy) - obj = ModelY(config=i) - assert obj.config == i - assert obj.config.llm == mock_llm_config - - obj.set_config(j) - # obj already has a config, so it will not be set - assert obj.config == i - assert obj.config.llm == mock_llm_config - - assert obj.a == "a" - assert obj.b == "b" - assert obj.c == "c" - assert obj.d == "d" - - print(obj.__dict__.keys()) - assert "private_config" in obj.__dict__.keys() diff --git a/tests/metagpt/test_context_mixin.py b/tests/metagpt/test_context_mixin.py new file mode 100644 index 000000000..4f261f4e9 --- /dev/null +++ b/tests/metagpt/test_context_mixin.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +@Time : 2024/1/11 19:24 +@Author : alexanderwu +@File : test_context_mixin.py +""" +from pydantic import BaseModel + +from metagpt.config2 import Config +from metagpt.context_mixin import ContextMixin +from tests.metagpt.provider.mock_llm_config import ( + mock_llm_config, + mock_llm_config_proxy, + mock_llm_config_zhipu, +) + + +class ModelX(ContextMixin, BaseModel): + a: str = "a" + b: str = "b" + + +class WTFMixin(BaseModel): + c: str = "c" + d: str = "d" + + +class ModelY(WTFMixin, ModelX): + pass + + +def test_config_mixin_1(): + new_model = ModelX() + assert new_model.a == "a" + assert new_model.b == "b" + + +def test_config_mixin_2(): + i = Config(llm=mock_llm_config) + j = Config(llm=mock_llm_config_proxy) + obj = ModelX(config=i) + assert obj.config == i + assert obj.config.llm == mock_llm_config + + obj.set_config(j) + # obj already has a config, so it will not be set + assert obj.config == i + + +def test_config_mixin_3_multi_inheritance_not_override_config(): + """Test config mixin with multiple inheritance""" + i = Config(llm=mock_llm_config) + j = Config(llm=mock_llm_config_proxy) + obj = ModelY(config=i) + assert obj.config == i + assert obj.config.llm == mock_llm_config + + obj.set_config(j) + # obj already has a config, so it will not be set + assert obj.config == i + assert obj.config.llm == mock_llm_config + + assert obj.a == "a" + assert obj.b == "b" + assert obj.c == "c" + assert obj.d == "d" + + print(obj.__dict__.keys()) + assert "private_config" in obj.__dict__.keys() + + +def test_config_mixin_4_multi_inheritance_override_config(): + """Test config mixin with multiple inheritance""" + i = Config(llm=mock_llm_config) + j = Config(llm=mock_llm_config_zhipu) + obj = ModelY(config=i) + assert obj.config == i + assert obj.config.llm == mock_llm_config + + obj.set_config(j, override=True) + # obj already has a config, so it will not be set + assert obj.config == j + assert obj.config.llm == mock_llm_config_zhipu + + assert obj.a == "a" + assert obj.b == "b" + assert obj.c == "c" + assert obj.d == "d" + + print(obj.__dict__.keys()) + assert "private_config" in obj.__dict__.keys() + assert obj.llm.model == "mock_zhipu_model" From b9b268ad8b516b9eb861983d86b8d74353e06a1a Mon Sep 17 00:00:00 2001 From: geekan Date: Thu, 11 Jan 2024 19:51:09 +0800 Subject: [PATCH 13/18] fix comment --- tests/metagpt/test_context_mixin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/metagpt/test_context_mixin.py b/tests/metagpt/test_context_mixin.py index 4f261f4e9..2c237b2ec 100644 --- a/tests/metagpt/test_context_mixin.py +++ b/tests/metagpt/test_context_mixin.py @@ -79,7 +79,7 @@ def test_config_mixin_4_multi_inheritance_override_config(): assert obj.config.llm == mock_llm_config obj.set_config(j, override=True) - # obj already has a config, so it will not be set + # override obj.config assert obj.config == j assert obj.config.llm == mock_llm_config_zhipu From f59449d5d20d675d6f1fb3eb41986f582138bfa8 Mon Sep 17 00:00:00 2001 From: geekan Date: Thu, 11 Jan 2024 20:51:27 +0800 Subject: [PATCH 14/18] support spark --- metagpt/llm.py | 8 ++++--- metagpt/roles/engineer.py | 2 +- metagpt/roles/role.py | 9 ++++---- tests/metagpt/provider/test_spark_api.py | 10 ++++++++ tests/metagpt/test_context_mixin.py | 29 ++++++++++++++++++++++++ 5 files changed, 50 insertions(+), 8 deletions(-) diff --git a/metagpt/llm.py b/metagpt/llm.py index 4c9993441..30ced25d2 100644 --- a/metagpt/llm.py +++ b/metagpt/llm.py @@ -5,13 +5,15 @@ @Author : alexanderwu @File : llm.py """ +from typing import Optional - +from metagpt.configs.llm_config import LLMConfig from metagpt.context import CONTEXT from metagpt.provider.base_llm import BaseLLM -def LLM() -> BaseLLM: +def LLM(llm_config: Optional[LLMConfig] = None) -> BaseLLM: """get the default llm provider if name is None""" - # context.use_llm(name=name, provider=provider) + if llm_config is not None: + CONTEXT.llm_with_cost_manager_from_llm_config(llm_config) return CONTEXT.llm() diff --git a/metagpt/roles/engineer.py b/metagpt/roles/engineer.py index bc56ca813..8b0895a69 100644 --- a/metagpt/roles/engineer.py +++ b/metagpt/roles/engineer.py @@ -110,7 +110,7 @@ class Engineer(Role): # Code review if review: action = WriteCodeReview(i_context=coding_context, context=self.context, llm=self.llm) - self._init_action_system_message(action) + self._init_action(action) coding_context = await action.run() await src_file_repo.save( coding_context.filename, diff --git a/metagpt/roles/role.py b/metagpt/roles/role.py index 10b60d30e..e7e5ead84 100644 --- a/metagpt/roles/role.py +++ b/metagpt/roles/role.py @@ -146,7 +146,7 @@ class Role(SerializationMixin, ContextMixin, BaseModel): super().__init__(**data) if self.is_human: - self.llm = HumanProvider() + self.llm = HumanProvider(None) self.llm.system_prompt = self._get_prefix() self._watch(data.get("watch") or [UserRequirement]) @@ -222,7 +222,8 @@ class Role(SerializationMixin, ContextMixin, BaseModel): def _setting(self): return f"{self.name}({self.profile})" - def _init_action_system_message(self, action: Action): + def _init_action(self, action: Action): + action.set_llm(self.llm, override=False) action.set_prefix(self._get_prefix()) def set_action(self, action: Action): @@ -238,7 +239,7 @@ class Role(SerializationMixin, ContextMixin, BaseModel): self._reset() for action in actions: if not isinstance(action, Action): - i = action(name="", llm=self.llm) + i = action() else: if self.is_human and not isinstance(action.llm, HumanProvider): logger.warning( @@ -247,7 +248,7 @@ class Role(SerializationMixin, ContextMixin, BaseModel): f"try passing in Action classes instead of initialized instances" ) i = action - self._init_action_system_message(i) + self._init_action(i) self.actions.append(i) self.states.append(f"{len(self.actions)}. {action}") diff --git a/tests/metagpt/provider/test_spark_api.py b/tests/metagpt/provider/test_spark_api.py index 213c19676..2cb6bf559 100644 --- a/tests/metagpt/provider/test_spark_api.py +++ b/tests/metagpt/provider/test_spark_api.py @@ -1,9 +1,11 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- # @Desc : the unittest of spark api +from pathlib import Path import pytest +from metagpt.config2 import Config from metagpt.provider.spark_api import GetMessageFromWeb, SparkLLM from tests.metagpt.provider.mock_llm_config import mock_llm_config @@ -33,6 +35,14 @@ def mock_spark_get_msg_from_web_run(self) -> str: return resp_content +@pytest.mark.asyncio +async def test_spark_aask(): + llm = SparkLLM(Config.model_validate_yaml(Path.home() / ".metagpt" / "spark.yaml").llm) + + resp = await llm.aask("Hello!") + print(resp) + + @pytest.mark.asyncio async def test_spark_acompletion(mocker): mocker.patch("metagpt.provider.spark_api.GetMessageFromWeb.run", mock_spark_get_msg_from_web_run) diff --git a/tests/metagpt/test_context_mixin.py b/tests/metagpt/test_context_mixin.py index 2c237b2ec..cc202a473 100644 --- a/tests/metagpt/test_context_mixin.py +++ b/tests/metagpt/test_context_mixin.py @@ -5,10 +5,15 @@ @Author : alexanderwu @File : test_context_mixin.py """ +import pytest from pydantic import BaseModel +from metagpt.actions import Action from metagpt.config2 import Config from metagpt.context_mixin import ContextMixin +from metagpt.environment import Environment +from metagpt.roles import Role +from metagpt.team import Team from tests.metagpt.provider.mock_llm_config import ( mock_llm_config, mock_llm_config_proxy, @@ -91,3 +96,27 @@ def test_config_mixin_4_multi_inheritance_override_config(): print(obj.__dict__.keys()) assert "private_config" in obj.__dict__.keys() assert obj.llm.model == "mock_zhipu_model" + + +@pytest.mark.asyncio +async def test_debate_two_roles(): + config = Config.default() + config.llm.model = "gpt-4-1106-preview" + action1 = Action(config=config, name="AlexSay", instruction="Say your opinion with emotion and don't repeat it") + action2 = Action(name="BobSay", instruction="Say your opinion with emotion and don't repeat it") + biden = Role( + name="Alex", profile="Democratic candidate", goal="Win the election", actions=[action1], watch=[action2] + ) + trump = Role( + name="Bob", profile="Republican candidate", goal="Win the election", actions=[action2], watch=[action1] + ) + env = Environment(desc="US election live broadcast") + team = Team(investment=10.0, env=env, roles=[biden, trump]) + + print(action1.llm.system_prompt) + print(action2.llm.system_prompt) + print(biden.llm.system_prompt) + print(trump.llm.system_prompt) + + history = await team.run(idea="Topic: climate change. Under 80 words per message.", send_to="Alex", n_round=3) + assert "Alex" in history From 6e44b2b515e6afedf02ce6e63f8862ebf51395b9 Mon Sep 17 00:00:00 2001 From: geekan Date: Thu, 11 Jan 2024 21:48:42 +0800 Subject: [PATCH 15/18] fix llm set --- examples/debate_simple.py | 2 ++ metagpt/actions/action.py | 2 +- metagpt/context_mixin.py | 2 ++ metagpt/provider/openai_api.py | 4 +++- metagpt/roles/role.py | 18 ++++++++++++++++-- tests/data/rsp_cache.json | 5 ++++- tests/metagpt/actions/test_action_node.py | 16 +++++++--------- tests/metagpt/test_context_mixin.py | 13 +++---------- 8 files changed, 38 insertions(+), 24 deletions(-) diff --git a/examples/debate_simple.py b/examples/debate_simple.py index aa95c5b85..869e02a0e 100644 --- a/examples/debate_simple.py +++ b/examples/debate_simple.py @@ -13,7 +13,9 @@ from metagpt.roles import Role from metagpt.team import Team action1 = Action(name="AlexSay", instruction="Express your opinion with emotion and don't repeat it") +action1.llm.model = "gpt-4-1106-preview" action2 = Action(name="BobSay", instruction="Express your opinion with emotion and don't repeat it") +action2.llm.model = "gpt-3.5-turbo-1106" alex = Role(name="Alex", profile="Democratic candidate", goal="Win the election", actions=[action1], watch=[action2]) bob = Role(name="Bob", profile="Republican candidate", goal="Win the election", actions=[action2], watch=[action1]) env = Environment(desc="US election live broadcast") diff --git a/metagpt/actions/action.py b/metagpt/actions/action.py index fa8bd3bb4..6e029e5d2 100644 --- a/metagpt/actions/action.py +++ b/metagpt/actions/action.py @@ -25,7 +25,7 @@ from metagpt.utils.file_repository import FileRepository class Action(SerializationMixin, ContextMixin, BaseModel): - model_config = ConfigDict(arbitrary_types_allowed=True, exclude=["llm"]) + model_config = ConfigDict(arbitrary_types_allowed=True) name: str = "" i_context: Union[dict, CodingContext, CodeSummarizeContext, TestingContext, RunCodeContext, str, None] = "" diff --git a/metagpt/context_mixin.py b/metagpt/context_mixin.py index 94c2dcd37..1d239d2e4 100644 --- a/metagpt/context_mixin.py +++ b/metagpt/context_mixin.py @@ -57,6 +57,8 @@ class ContextMixin(BaseModel): def set_config(self, config: Config, override=False): """Set config""" self.set("private_config", config, override) + if config is not None: + _ = self.llm # init llm def set_llm(self, llm: BaseLLM, override=False): """Set llm""" diff --git a/metagpt/provider/openai_api.py b/metagpt/provider/openai_api.py index d60bb8773..2741485bd 100644 --- a/metagpt/provider/openai_api.py +++ b/metagpt/provider/openai_api.py @@ -220,10 +220,12 @@ class OpenAILLM(BaseLLM): @handle_exception def _update_costs(self, usage: CompletionUsage): - if self.config.calc_usage and usage: + if self.config.calc_usage and usage and self.cost_manager: self.cost_manager.update_cost(usage.prompt_tokens, usage.completion_tokens, self.model) def get_costs(self) -> Costs: + if not self.cost_manager: + return Costs() return self.cost_manager.get_costs() def _get_max_tokens(self, messages: list[dict]): diff --git a/metagpt/roles/role.py b/metagpt/roles/role.py index e7e5ead84..cc432d81f 100644 --- a/metagpt/roles/role.py +++ b/metagpt/roles/role.py @@ -131,6 +131,13 @@ class Role(SerializationMixin, ContextMixin, BaseModel): role_id: str = "" states: list[str] = [] + + # scenarios to set action system_prompt: + # 1. `__init__` while using Role(actions=[...]) + # 2. add action to role while using `role.set_action(action)` + # 3. set_todo while using `role.set_todo(action)` + # 4. when role.system_prompt is being updated (e.g. by `role.system_prompt = "..."`) + # Additional, if llm is not set, we will use role's llm actions: list[SerializeAsAny[Action]] = Field(default=[], validate_default=True) rc: RoleContext = Field(default_factory=RoleContext) addresses: set[str] = set() @@ -222,6 +229,12 @@ class Role(SerializationMixin, ContextMixin, BaseModel): def _setting(self): return f"{self.name}({self.profile})" + @model_validator(mode="after") + def _check_actions(self): + """Check actions and set llm and prefix for each action.""" + self.set_actions(self.actions) + return self + def _init_action(self, action: Action): action.set_llm(self.llm, override=False) action.set_prefix(self._get_prefix()) @@ -306,6 +319,7 @@ class Role(SerializationMixin, ContextMixin, BaseModel): if env: env.set_addresses(self, self.addresses) self.llm.system_prompt = self._get_prefix() + self.set_actions(self.actions) # reset actions to update llm and prefix def _get_prefix(self): """Get the role prefix""" @@ -318,7 +332,8 @@ class Role(SerializationMixin, ContextMixin, BaseModel): prefix += CONSTRAINT_TEMPLATE.format(**{"constraints": self.constraints}) if self.rc.env and self.rc.env.desc: - other_role_names = ", ".join(self.rc.env.role_names()) + all_roles = self.rc.env.role_names() + other_role_names = ", ".join([r for r in all_roles if r != self.name]) env_desc = f"You are in {self.rc.env.desc} with roles({other_role_names})." prefix += env_desc return prefix @@ -478,7 +493,6 @@ class Role(SerializationMixin, ContextMixin, BaseModel): if not msg.cause_by: msg.cause_by = UserRequirement self.put_message(msg) - if not await self._observe(): # If there is no new information, suspend and wait logger.debug(f"{self._setting}: no news. waiting.") diff --git a/tests/data/rsp_cache.json b/tests/data/rsp_cache.json index 32c8f850a..456a4146e 100644 --- a/tests/data/rsp_cache.json +++ b/tests/data/rsp_cache.json @@ -189,5 +189,8 @@ "\n## context\n\n### Project Name\n20240111180901\n\n### Original Requirements\n['需要一个基于LLM做总结的搜索引擎']\n\n### Search Information\n-\n\n\n-----\n\n## format example\n[CONTENT]\n{\n \"Language\": \"en_us\",\n \"Programming Language\": \"Python\",\n \"Original Requirements\": \"Create a 2048 game\",\n \"Product Goals\": [\n \"Create an engaging user experience\",\n \"Improve accessibility, be responsive\",\n \"More beautiful UI\"\n ],\n \"User Stories\": [\n \"As a player, I want to be able to choose difficulty levels\",\n \"As a player, I want to see my score after each game\",\n \"As a player, I want to get restart button when I lose\",\n \"As a player, I want to see beautiful UI that make me feel good\",\n \"As a player, I want to play game via mobile phone\"\n ],\n \"Competitive Analysis\": [\n \"2048 Game A: Simple interface, lacks responsive features\",\n \"play2048.co: Beautiful and responsive UI with my best score shown\",\n \"2048game.com: Responsive UI with my best score shown, but many ads\"\n ],\n \"Competitive Quadrant Chart\": \"quadrantChart\\n title \\\"Reach and engagement of campaigns\\\"\\n x-axis \\\"Low Reach\\\" --> \\\"High Reach\\\"\\n y-axis \\\"Low Engagement\\\" --> \\\"High Engagement\\\"\\n quadrant-1 \\\"We should expand\\\"\\n quadrant-2 \\\"Need to promote\\\"\\n quadrant-3 \\\"Re-evaluate\\\"\\n quadrant-4 \\\"May be improved\\\"\\n \\\"Campaign A\\\": [0.3, 0.6]\\n \\\"Campaign B\\\": [0.45, 0.23]\\n \\\"Campaign C\\\": [0.57, 0.69]\\n \\\"Campaign D\\\": [0.78, 0.34]\\n \\\"Campaign E\\\": [0.40, 0.34]\\n \\\"Campaign F\\\": [0.35, 0.78]\\n \\\"Our Target Product\\\": [0.5, 0.6]\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [\n [\n \"P0\",\n \"The main code ...\"\n ],\n [\n \"P0\",\n \"The game algorithm ...\"\n ]\n ],\n \"UI Design draft\": \"Basic function description with a simple style and layout.\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- Language: # Provide the language used in the project, typically matching the user's requirement language.\n- Programming Language: # Python/JavaScript or other mainstream programming language.\n- Original Requirements: # Place the original user's requirements here.\n- Product Goals: typing.List[str] # Provide up to three clear, orthogonal product goals.\n- User Stories: typing.List[str] # Provide up to 3 to 5 scenario-based user stories.\n- Competitive Analysis: typing.List[str] # Provide 5 to 7 competitive products.\n- Competitive Quadrant Chart: # Use mermaid quadrantChart syntax. Distribute scores evenly between 0 and 1\n- Requirement Analysis: # Provide a detailed analysis of the requirements.\n- Requirement Pool: typing.List[typing.List[str]] # List down the top-5 requirements with their priority (P0, P1, P2).\n- UI Design draft: # Provide a simple description of UI elements, functions, style, and layout.\n- Anything UNCLEAR: # Mention any aspects of the project that are unclear and try to clarify them.\n\n\n## constraint\nLanguage: Please use the same language as Human INPUT.\nFormat: output wrapped inside [CONTENT][/CONTENT] like format example, nothing else.\n\n## action\nFollow instructions of nodes, generate output and make sure it follows the format example.\n": "[CONTENT]\n{\n \"Language\": \"zh_cn\",\n \"Programming Language\": \"LLM\",\n \"Original Requirements\": \"需要一个基于LLM做总结的搜索引擎\",\n \"Product Goals\": [],\n \"User Stories\": [],\n \"Competitive Analysis\": [],\n \"Competitive Quadrant Chart\": \"\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [],\n \"UI Design draft\": \"\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]", "\n## context\n\n### Project Name\n20240111181214\n\n### Original Requirements\n['需要一个基于LLM做总结的搜索引擎']\n\n### Search Information\n-\n\n\n-----\n\n## format example\n[CONTENT]\n{\n \"Language\": \"en_us\",\n \"Programming Language\": \"Python\",\n \"Original Requirements\": \"Create a 2048 game\",\n \"Product Goals\": [\n \"Create an engaging user experience\",\n \"Improve accessibility, be responsive\",\n \"More beautiful UI\"\n ],\n \"User Stories\": [\n \"As a player, I want to be able to choose difficulty levels\",\n \"As a player, I want to see my score after each game\",\n \"As a player, I want to get restart button when I lose\",\n \"As a player, I want to see beautiful UI that make me feel good\",\n \"As a player, I want to play game via mobile phone\"\n ],\n \"Competitive Analysis\": [\n \"2048 Game A: Simple interface, lacks responsive features\",\n \"play2048.co: Beautiful and responsive UI with my best score shown\",\n \"2048game.com: Responsive UI with my best score shown, but many ads\"\n ],\n \"Competitive Quadrant Chart\": \"quadrantChart\\n title \\\"Reach and engagement of campaigns\\\"\\n x-axis \\\"Low Reach\\\" --> \\\"High Reach\\\"\\n y-axis \\\"Low Engagement\\\" --> \\\"High Engagement\\\"\\n quadrant-1 \\\"We should expand\\\"\\n quadrant-2 \\\"Need to promote\\\"\\n quadrant-3 \\\"Re-evaluate\\\"\\n quadrant-4 \\\"May be improved\\\"\\n \\\"Campaign A\\\": [0.3, 0.6]\\n \\\"Campaign B\\\": [0.45, 0.23]\\n \\\"Campaign C\\\": [0.57, 0.69]\\n \\\"Campaign D\\\": [0.78, 0.34]\\n \\\"Campaign E\\\": [0.40, 0.34]\\n \\\"Campaign F\\\": [0.35, 0.78]\\n \\\"Our Target Product\\\": [0.5, 0.6]\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [\n [\n \"P0\",\n \"The main code ...\"\n ],\n [\n \"P0\",\n \"The game algorithm ...\"\n ]\n ],\n \"UI Design draft\": \"Basic function description with a simple style and layout.\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- Language: # Provide the language used in the project, typically matching the user's requirement language.\n- Programming Language: # Python/JavaScript or other mainstream programming language.\n- Original Requirements: # Place the original user's requirements here.\n- Product Goals: typing.List[str] # Provide up to three clear, orthogonal product goals.\n- User Stories: typing.List[str] # Provide up to 3 to 5 scenario-based user stories.\n- Competitive Analysis: typing.List[str] # Provide 5 to 7 competitive products.\n- Competitive Quadrant Chart: # Use mermaid quadrantChart syntax. Distribute scores evenly between 0 and 1\n- Requirement Analysis: # Provide a detailed analysis of the requirements.\n- Requirement Pool: typing.List[typing.List[str]] # List down the top-5 requirements with their priority (P0, P1, P2).\n- UI Design draft: # Provide a simple description of UI elements, functions, style, and layout.\n- Anything UNCLEAR: # Mention any aspects of the project that are unclear and try to clarify them.\n\n\n## constraint\nLanguage: Please use the same language as Human INPUT.\nFormat: output wrapped inside [CONTENT][/CONTENT] like format example, nothing else.\n\n## action\nFollow instructions of nodes, generate output and make sure it follows the format example.\n": "[CONTENT]\n{\n \"Language\": \"zh_cn\",\n \"Programming Language\": \"LLM\",\n \"Original Requirements\": \"需要一个基于LLM做总结的搜索引擎\",\n \"Product Goals\": [],\n \"User Stories\": [],\n \"Competitive Analysis\": [],\n \"Competitive Quadrant Chart\": \"\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [],\n \"UI Design draft\": \"\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]", "\n## context\n\n### Project Name\n20240111181426\n\n### Original Requirements\n['开发一个基于大语言模型与私有知识库的搜索引擎,希望可以基于大语言模型进行搜索总结']\n\n### Search Information\n-\n\n\n-----\n\n## format example\n[CONTENT]\n{\n \"Language\": \"en_us\",\n \"Programming Language\": \"Python\",\n \"Original Requirements\": \"Create a 2048 game\",\n \"Product Goals\": [\n \"Create an engaging user experience\",\n \"Improve accessibility, be responsive\",\n \"More beautiful UI\"\n ],\n \"User Stories\": [\n \"As a player, I want to be able to choose difficulty levels\",\n \"As a player, I want to see my score after each game\",\n \"As a player, I want to get restart button when I lose\",\n \"As a player, I want to see beautiful UI that make me feel good\",\n \"As a player, I want to play game via mobile phone\"\n ],\n \"Competitive Analysis\": [\n \"2048 Game A: Simple interface, lacks responsive features\",\n \"play2048.co: Beautiful and responsive UI with my best score shown\",\n \"2048game.com: Responsive UI with my best score shown, but many ads\"\n ],\n \"Competitive Quadrant Chart\": \"quadrantChart\\n title \\\"Reach and engagement of campaigns\\\"\\n x-axis \\\"Low Reach\\\" --> \\\"High Reach\\\"\\n y-axis \\\"Low Engagement\\\" --> \\\"High Engagement\\\"\\n quadrant-1 \\\"We should expand\\\"\\n quadrant-2 \\\"Need to promote\\\"\\n quadrant-3 \\\"Re-evaluate\\\"\\n quadrant-4 \\\"May be improved\\\"\\n \\\"Campaign A\\\": [0.3, 0.6]\\n \\\"Campaign B\\\": [0.45, 0.23]\\n \\\"Campaign C\\\": [0.57, 0.69]\\n \\\"Campaign D\\\": [0.78, 0.34]\\n \\\"Campaign E\\\": [0.40, 0.34]\\n \\\"Campaign F\\\": [0.35, 0.78]\\n \\\"Our Target Product\\\": [0.5, 0.6]\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [\n [\n \"P0\",\n \"The main code ...\"\n ],\n [\n \"P0\",\n \"The game algorithm ...\"\n ]\n ],\n \"UI Design draft\": \"Basic function description with a simple style and layout.\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- Language: # Provide the language used in the project, typically matching the user's requirement language.\n- Programming Language: # Python/JavaScript or other mainstream programming language.\n- Original Requirements: # Place the original user's requirements here.\n- Product Goals: typing.List[str] # Provide up to three clear, orthogonal product goals.\n- User Stories: typing.List[str] # Provide up to 3 to 5 scenario-based user stories.\n- Competitive Analysis: typing.List[str] # Provide 5 to 7 competitive products.\n- Competitive Quadrant Chart: # Use mermaid quadrantChart syntax. Distribute scores evenly between 0 and 1\n- Requirement Analysis: # Provide a detailed analysis of the requirements.\n- Requirement Pool: typing.List[typing.List[str]] # List down the top-5 requirements with their priority (P0, P1, P2).\n- UI Design draft: # Provide a simple description of UI elements, functions, style, and layout.\n- Anything UNCLEAR: # Mention any aspects of the project that are unclear and try to clarify them.\n\n\n## constraint\nLanguage: Please use the same language as Human INPUT.\nFormat: output wrapped inside [CONTENT][/CONTENT] like format example, nothing else.\n\n## action\nFollow instructions of nodes, generate output and make sure it follows the format example.\n": "[CONTENT]\n{\n \"Language\": \"zh_cn\",\n \"Programming Language\": \"Python\",\n \"Original Requirements\": \"开发一个基于大语言模型与私有知识库的搜索引擎,希望可以基于大语言模型进行搜索总结\",\n \"Product Goals\": [\n \"提供高效的搜索功能\",\n \"整合私有知识库\",\n \"生成准确的搜索总结\"\n ],\n \"User Stories\": [\n \"作为用户,我希望能够快速找到所需信息\",\n \"作为用户,我希望搜索结果能够涵盖私有知识库内容\",\n \"作为用户,我希望搜索总结能够准确反映所需信息\"\n ],\n \"Competitive Analysis\": [\n \"搜索引擎A:搜索速度快,但不支持私有知识库整合\",\n \"搜索引擎B:支持私有知识库整合,但搜索总结不够准确\",\n \"搜索引擎C:准确的搜索总结,但不支持私有知识库整合\"\n ],\n \"Competitive Quadrant Chart\": \"quadrantChart\\n title \\\"搜索引擎比较\\\"\\n x-axis \\\"低速度\\\" --> \\\"高速度\\\"\\n y-axis \\\"低准确性\\\" --> \\\"高准确性\\\"\\n quadrant-1 \\\"速度快,准确性低\\\"\\n quadrant-2 \\\"速度慢,准确性低\\\"\\n quadrant-3 \\\"速度慢,准确性高\\\"\\n quadrant-4 \\\"速度快,准确性高\\\"\\n \\\"搜索引擎A\\\": [0.8, 0.3]\\n \\\"搜索引擎B\\\": [0.4, 0.2]\\n \\\"搜索引擎C\\\": [0.2, 0.9]\\n \\\"我们的目标产品\\\": [0.7, 0.8]\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [\n [\n \"P0\",\n \"基于大语言模型的搜索功能\"\n ],\n [\n \"P0\",\n \"私有知识库整合\"\n ],\n [\n \"P1\",\n \"搜索总结生成\"\n ]\n ],\n \"UI Design draft\": \"简洁的搜索界面,包含私有知识库搜索选项。\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]", - "\n## context\n\n### Project Name\n20240111181426\n\n### Original Requirements\n['']\n\n### Search Information\n-\n\n\n-----\n\n## format example\n[CONTENT]\n{\n \"Language\": \"en_us\",\n \"Programming Language\": \"Python\",\n \"Original Requirements\": \"Create a 2048 game\",\n \"Product Goals\": [\n \"Create an engaging user experience\",\n \"Improve accessibility, be responsive\",\n \"More beautiful UI\"\n ],\n \"User Stories\": [\n \"As a player, I want to be able to choose difficulty levels\",\n \"As a player, I want to see my score after each game\",\n \"As a player, I want to get restart button when I lose\",\n \"As a player, I want to see beautiful UI that make me feel good\",\n \"As a player, I want to play game via mobile phone\"\n ],\n \"Competitive Analysis\": [\n \"2048 Game A: Simple interface, lacks responsive features\",\n \"play2048.co: Beautiful and responsive UI with my best score shown\",\n \"2048game.com: Responsive UI with my best score shown, but many ads\"\n ],\n \"Competitive Quadrant Chart\": \"quadrantChart\\n title \\\"Reach and engagement of campaigns\\\"\\n x-axis \\\"Low Reach\\\" --> \\\"High Reach\\\"\\n y-axis \\\"Low Engagement\\\" --> \\\"High Engagement\\\"\\n quadrant-1 \\\"We should expand\\\"\\n quadrant-2 \\\"Need to promote\\\"\\n quadrant-3 \\\"Re-evaluate\\\"\\n quadrant-4 \\\"May be improved\\\"\\n \\\"Campaign A\\\": [0.3, 0.6]\\n \\\"Campaign B\\\": [0.45, 0.23]\\n \\\"Campaign C\\\": [0.57, 0.69]\\n \\\"Campaign D\\\": [0.78, 0.34]\\n \\\"Campaign E\\\": [0.40, 0.34]\\n \\\"Campaign F\\\": [0.35, 0.78]\\n \\\"Our Target Product\\\": [0.5, 0.6]\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [\n [\n \"P0\",\n \"The main code ...\"\n ],\n [\n \"P0\",\n \"The game algorithm ...\"\n ]\n ],\n \"UI Design draft\": \"Basic function description with a simple style and layout.\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- Language: # Provide the language used in the project, typically matching the user's requirement language.\n- Programming Language: # Python/JavaScript or other mainstream programming language.\n- Original Requirements: # Place the original user's requirements here.\n- Product Goals: typing.List[str] # Provide up to three clear, orthogonal product goals.\n- User Stories: typing.List[str] # Provide up to 3 to 5 scenario-based user stories.\n- Competitive Analysis: typing.List[str] # Provide 5 to 7 competitive products.\n- Competitive Quadrant Chart: # Use mermaid quadrantChart syntax. Distribute scores evenly between 0 and 1\n- Requirement Analysis: # Provide a detailed analysis of the requirements.\n- Requirement Pool: typing.List[typing.List[str]] # List down the top-5 requirements with their priority (P0, P1, P2).\n- UI Design draft: # Provide a simple description of UI elements, functions, style, and layout.\n- Anything UNCLEAR: # Mention any aspects of the project that are unclear and try to clarify them.\n\n\n## constraint\nLanguage: Please use the same language as Human INPUT.\nFormat: output wrapped inside [CONTENT][/CONTENT] like format example, nothing else.\n\n## action\nFollow instructions of nodes, generate output and make sure it follows the format example.\n": "[CONTENT]\n{\n \"Language\": \"en_us\",\n \"Programming Language\": \"Python\",\n \"Original Requirements\": \"\",\n \"Product Goals\": [],\n \"User Stories\": [],\n \"Competitive Analysis\": [],\n \"Competitive Quadrant Chart\": \"quadrantChart\\n title \\\"Reach and engagement of campaigns\\\"\\n x-axis \\\"Low Reach\\\" --> \\\"High Reach\\\"\\n y-axis \\\"Low Engagement\\\" --> \\\"High Engagement\\\"\\n quadrant-1 \\\"We should expand\\\"\\n quadrant-2 \\\"Need to promote\\\"\\n quadrant-3 \\\"Re-evaluate\\\"\\n quadrant-4 \\\"May be improved\\\"\\n \\\"Campaign A\\\": [0.3, 0.6]\\n \\\"Campaign B\\\": [0.45, 0.23]\\n \\\"Campaign C\\\": [0.57, 0.69]\\n \\\"Campaign D\\\": [0.78, 0.34]\\n \\\"Campaign E\\\": [0.40, 0.34]\\n \\\"Campaign F\\\": [0.35, 0.78]\\n \\\"Our Target Product\\\": [0.5, 0.6]\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [],\n \"UI Design draft\": \"Basic function description with a simple style and layout.\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]" + "\n## context\n\n### Project Name\n20240111181426\n\n### Original Requirements\n['']\n\n### Search Information\n-\n\n\n-----\n\n## format example\n[CONTENT]\n{\n \"Language\": \"en_us\",\n \"Programming Language\": \"Python\",\n \"Original Requirements\": \"Create a 2048 game\",\n \"Product Goals\": [\n \"Create an engaging user experience\",\n \"Improve accessibility, be responsive\",\n \"More beautiful UI\"\n ],\n \"User Stories\": [\n \"As a player, I want to be able to choose difficulty levels\",\n \"As a player, I want to see my score after each game\",\n \"As a player, I want to get restart button when I lose\",\n \"As a player, I want to see beautiful UI that make me feel good\",\n \"As a player, I want to play game via mobile phone\"\n ],\n \"Competitive Analysis\": [\n \"2048 Game A: Simple interface, lacks responsive features\",\n \"play2048.co: Beautiful and responsive UI with my best score shown\",\n \"2048game.com: Responsive UI with my best score shown, but many ads\"\n ],\n \"Competitive Quadrant Chart\": \"quadrantChart\\n title \\\"Reach and engagement of campaigns\\\"\\n x-axis \\\"Low Reach\\\" --> \\\"High Reach\\\"\\n y-axis \\\"Low Engagement\\\" --> \\\"High Engagement\\\"\\n quadrant-1 \\\"We should expand\\\"\\n quadrant-2 \\\"Need to promote\\\"\\n quadrant-3 \\\"Re-evaluate\\\"\\n quadrant-4 \\\"May be improved\\\"\\n \\\"Campaign A\\\": [0.3, 0.6]\\n \\\"Campaign B\\\": [0.45, 0.23]\\n \\\"Campaign C\\\": [0.57, 0.69]\\n \\\"Campaign D\\\": [0.78, 0.34]\\n \\\"Campaign E\\\": [0.40, 0.34]\\n \\\"Campaign F\\\": [0.35, 0.78]\\n \\\"Our Target Product\\\": [0.5, 0.6]\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [\n [\n \"P0\",\n \"The main code ...\"\n ],\n [\n \"P0\",\n \"The game algorithm ...\"\n ]\n ],\n \"UI Design draft\": \"Basic function description with a simple style and layout.\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- Language: # Provide the language used in the project, typically matching the user's requirement language.\n- Programming Language: # Python/JavaScript or other mainstream programming language.\n- Original Requirements: # Place the original user's requirements here.\n- Product Goals: typing.List[str] # Provide up to three clear, orthogonal product goals.\n- User Stories: typing.List[str] # Provide up to 3 to 5 scenario-based user stories.\n- Competitive Analysis: typing.List[str] # Provide 5 to 7 competitive products.\n- Competitive Quadrant Chart: # Use mermaid quadrantChart syntax. Distribute scores evenly between 0 and 1\n- Requirement Analysis: # Provide a detailed analysis of the requirements.\n- Requirement Pool: typing.List[typing.List[str]] # List down the top-5 requirements with their priority (P0, P1, P2).\n- UI Design draft: # Provide a simple description of UI elements, functions, style, and layout.\n- Anything UNCLEAR: # Mention any aspects of the project that are unclear and try to clarify them.\n\n\n## constraint\nLanguage: Please use the same language as Human INPUT.\nFormat: output wrapped inside [CONTENT][/CONTENT] like format example, nothing else.\n\n## action\nFollow instructions of nodes, generate output and make sure it follows the format example.\n": "[CONTENT]\n{\n \"Language\": \"en_us\",\n \"Programming Language\": \"Python\",\n \"Original Requirements\": \"\",\n \"Product Goals\": [],\n \"User Stories\": [],\n \"Competitive Analysis\": [],\n \"Competitive Quadrant Chart\": \"quadrantChart\\n title \\\"Reach and engagement of campaigns\\\"\\n x-axis \\\"Low Reach\\\" --> \\\"High Reach\\\"\\n y-axis \\\"Low Engagement\\\" --> \\\"High Engagement\\\"\\n quadrant-1 \\\"We should expand\\\"\\n quadrant-2 \\\"Need to promote\\\"\\n quadrant-3 \\\"Re-evaluate\\\"\\n quadrant-4 \\\"May be improved\\\"\\n \\\"Campaign A\\\": [0.3, 0.6]\\n \\\"Campaign B\\\": [0.45, 0.23]\\n \\\"Campaign C\\\": [0.57, 0.69]\\n \\\"Campaign D\\\": [0.78, 0.34]\\n \\\"Campaign E\\\": [0.40, 0.34]\\n \\\"Campaign F\\\": [0.35, 0.78]\\n \\\"Our Target Product\\\": [0.5, 0.6]\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [],\n \"UI Design draft\": \"Basic function description with a simple style and layout.\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]", + "## History Messages\n0: Human: Topic: climate change. Under 80 words per message.\n\n## Actions\nLanguage: Please use the same language as Human INPUT.\nSay your opinion with emotion and don't repeat it": "I believe that climate change is a critical issue that requires urgent action. It's alarming to see the impact of human activities on the environment and the devastating consequences it has on ecosystems and communities. We need to prioritize sustainable practices and reduce our carbon footprint to mitigate the effects of climate change. It's essential for the well-being of future generations and the health of our planet.", + "## History Messages\n0: Alex(Democratic candidate): I believe that climate change is a critical issue that requires urgent action. It's alarming to see the impact of human activities on the environment and the devastating consequences it has on ecosystems and communities. We need to prioritize sustainable practices and reduce our carbon footprint to mitigate the effects of climate change. It's essential for the well-being of future generations and the health of our planet.\n\n## Actions\nLanguage: Please use the same language as Human INPUT.\nSay your opinion with emotion and don't repeat it": "I completely agree with Alex. Climate change is a critical issue that demands immediate attention. The impact of human activities on the environment is devastating, and urgent action is necessary to prioritize sustainable practices and reduce our carbon footprint. It's essential for the well-being of future generations and the health of our planet.", + "## History Messages\n0: Bob(Republican candidate): I completely agree with Alex. Climate change is a critical issue that demands immediate attention. The impact of human activities on the environment is devastating, and urgent action is necessary to prioritize sustainable practices and reduce our carbon footprint. It's essential for the well-being of future generations and the health of our planet.\n1: Alex(Democratic candidate): I believe that climate change is a critical issue that requires urgent action. It's alarming to see the impact of human activities on the environment and the devastating consequences it has on ecosystems and communities. We need to prioritize sustainable practices and reduce our carbon footprint to mitigate the effects of climate change. It's essential for the well-being of future generations and the health of our planet.\n2: Human: Topic: climate change. Under 80 words per message.\n\n## Actions\nLanguage: Please use the same language as Human INPUT.\nSay your opinion with emotion and don't repeat it": "I completely agree with both Bob and Alex. Climate change is a critical issue that demands immediate attention. The impact of human activities on the environment is devastating, and urgent action is necessary to prioritize sustainable practices and reduce our carbon footprint. It's essential for the well-being of future generations and the health of our planet." } \ No newline at end of file diff --git a/tests/metagpt/actions/test_action_node.py b/tests/metagpt/actions/test_action_node.py index fd2c83ac9..53de9cc75 100644 --- a/tests/metagpt/actions/test_action_node.py +++ b/tests/metagpt/actions/test_action_node.py @@ -23,14 +23,12 @@ from metagpt.team import Team async def test_debate_two_roles(): action1 = Action(name="AlexSay", instruction="Express your opinion with emotion and don't repeat it") action2 = Action(name="BobSay", instruction="Express your opinion with emotion and don't repeat it") - biden = Role( + alex = Role( name="Alex", profile="Democratic candidate", goal="Win the election", actions=[action1], watch=[action2] ) - trump = Role( - name="Bob", profile="Republican candidate", goal="Win the election", actions=[action2], watch=[action1] - ) + bob = Role(name="Bob", profile="Republican candidate", goal="Win the election", actions=[action2], watch=[action1]) env = Environment(desc="US election live broadcast") - team = Team(investment=10.0, env=env, roles=[biden, trump]) + team = Team(investment=10.0, env=env, roles=[alex, bob]) history = await team.run(idea="Topic: climate change. Under 80 words per message.", send_to="Alex", n_round=3) assert "Alex" in history @@ -39,9 +37,9 @@ async def test_debate_two_roles(): @pytest.mark.asyncio async def test_debate_one_role_in_env(): action = Action(name="Debate", instruction="Express your opinion with emotion and don't repeat it") - biden = Role(name="Alex", profile="Democratic candidate", goal="Win the election", actions=[action]) + alex = Role(name="Alex", profile="Democratic candidate", goal="Win the election", actions=[action]) env = Environment(desc="US election live broadcast") - team = Team(investment=10.0, env=env, roles=[biden]) + team = Team(investment=10.0, env=env, roles=[alex]) history = await team.run(idea="Topic: climate change. Under 80 words per message.", send_to="Alex", n_round=3) assert "Alex" in history @@ -49,8 +47,8 @@ async def test_debate_one_role_in_env(): @pytest.mark.asyncio async def test_debate_one_role(): action = Action(name="Debate", instruction="Express your opinion with emotion and don't repeat it") - biden = Role(name="Alex", profile="Democratic candidate", goal="Win the election", actions=[action]) - msg: Message = await biden.run("Topic: climate change. Under 80 words per message.") + alex = Role(name="Alex", profile="Democratic candidate", goal="Win the election", actions=[action]) + msg: Message = await alex.run("Topic: climate change. Under 80 words per message.") assert len(msg.content) > 10 assert msg.sent_from == "metagpt.roles.role.Role" diff --git a/tests/metagpt/test_context_mixin.py b/tests/metagpt/test_context_mixin.py index cc202a473..a1222c125 100644 --- a/tests/metagpt/test_context_mixin.py +++ b/tests/metagpt/test_context_mixin.py @@ -104,19 +104,12 @@ async def test_debate_two_roles(): config.llm.model = "gpt-4-1106-preview" action1 = Action(config=config, name="AlexSay", instruction="Say your opinion with emotion and don't repeat it") action2 = Action(name="BobSay", instruction="Say your opinion with emotion and don't repeat it") - biden = Role( + alex = Role( name="Alex", profile="Democratic candidate", goal="Win the election", actions=[action1], watch=[action2] ) - trump = Role( - name="Bob", profile="Republican candidate", goal="Win the election", actions=[action2], watch=[action1] - ) + bob = Role(name="Bob", profile="Republican candidate", goal="Win the election", actions=[action2], watch=[action1]) env = Environment(desc="US election live broadcast") - team = Team(investment=10.0, env=env, roles=[biden, trump]) - - print(action1.llm.system_prompt) - print(action2.llm.system_prompt) - print(biden.llm.system_prompt) - print(trump.llm.system_prompt) + team = Team(investment=10.0, env=env, roles=[alex, bob]) history = await team.run(idea="Topic: climate change. Under 80 words per message.", send_to="Alex", n_round=3) assert "Alex" in history From 0e1c8da56dbf2885fe5f91bde2ccf9407671fad3 Mon Sep 17 00:00:00 2001 From: geekan Date: Thu, 11 Jan 2024 21:49:27 +0800 Subject: [PATCH 16/18] add spark to provider init --- metagpt/provider/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/metagpt/provider/__init__.py b/metagpt/provider/__init__.py index 33f43b148..675734811 100644 --- a/metagpt/provider/__init__.py +++ b/metagpt/provider/__init__.py @@ -15,6 +15,7 @@ from metagpt.provider.zhipuai_api import ZhiPuAILLM from metagpt.provider.azure_openai_api import AzureOpenAILLM from metagpt.provider.metagpt_api import MetaGPTLLM from metagpt.provider.human_provider import HumanProvider +from metagpt.provider.spark_api import SparkLLM __all__ = [ "FireworksLLM", @@ -26,4 +27,5 @@ __all__ = [ "MetaGPTLLM", "OllamaLLM", "HumanProvider", + "SparkLLM", ] From 784732093e8bad07df6de0239e1ee667521925bf Mon Sep 17 00:00:00 2001 From: geekan Date: Thu, 11 Jan 2024 21:50:54 +0800 Subject: [PATCH 17/18] refine comments --- metagpt/provider/spark_api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/metagpt/provider/spark_api.py b/metagpt/provider/spark_api.py index 0a8169636..5e89c26d5 100644 --- a/metagpt/provider/spark_api.py +++ b/metagpt/provider/spark_api.py @@ -26,14 +26,14 @@ from metagpt.provider.llm_provider_registry import register_provider class SparkLLM(BaseLLM): def __init__(self, config: LLMConfig): self.config = config - logger.warning("当前方法无法支持异步运行。当你使用acompletion时,并不能并行访问。") + logger.warning("SparkLLM:当前方法无法支持异步运行。当你使用acompletion时,并不能并行访问。") def get_choice_text(self, rsp: dict) -> str: return rsp["payload"]["choices"]["text"][-1]["content"] async def acompletion_text(self, messages: list[dict], stream=False, timeout: int = 3) -> str: # 不支持 - logger.warning("当前方法无法支持异步运行。当你使用acompletion时,并不能并行访问。") + # logger.warning("当前方法无法支持异步运行。当你使用acompletion时,并不能并行访问。") w = GetMessageFromWeb(messages, self.config) return w.run() From 312d327d55d56c437cd3e7863d5f3d71389046b5 Mon Sep 17 00:00:00 2001 From: geekan Date: Thu, 11 Jan 2024 22:30:26 +0800 Subject: [PATCH 18/18] test for mixin --- metagpt/config2.py | 7 ++++- metagpt/const.py | 2 +- metagpt/roles/role.py | 7 +++-- metagpt/startup.py | 4 +-- tests/metagpt/provider/test_spark_api.py | 3 +- tests/metagpt/test_context_mixin.py | 39 ++++++++++++++++-------- 6 files changed, 41 insertions(+), 21 deletions(-) diff --git a/metagpt/config2.py b/metagpt/config2.py index c916b9b60..2d4ac0930 100644 --- a/metagpt/config2.py +++ b/metagpt/config2.py @@ -18,7 +18,7 @@ from metagpt.configs.redis_config import RedisConfig from metagpt.configs.s3_config import S3Config from metagpt.configs.search_config import SearchConfig from metagpt.configs.workspace_config import WorkspaceConfig -from metagpt.const import METAGPT_ROOT +from metagpt.const import CONFIG_ROOT, METAGPT_ROOT from metagpt.utils.yaml_model import YamlModel @@ -81,6 +81,11 @@ class Config(CLIParams, YamlModel): AZURE_TTS_REGION: str = "" mermaid_engine: str = "nodejs" + @classmethod + def from_home(cls, path): + """Load config from ~/.metagpt/config.yaml""" + return Config.model_validate_yaml(CONFIG_ROOT / path) + @classmethod def default(cls): """Load default config diff --git a/metagpt/const.py b/metagpt/const.py index 811ff9516..8e89b0526 100644 --- a/metagpt/const.py +++ b/metagpt/const.py @@ -47,7 +47,7 @@ def get_metagpt_root(): # METAGPT PROJECT ROOT AND VARS - +CONFIG_ROOT = Path.home() / ".metagpt" METAGPT_ROOT = get_metagpt_root() # Dependent on METAGPT_PROJECT_ROOT DEFAULT_WORKSPACE_ROOT = METAGPT_ROOT / "workspace" diff --git a/metagpt/roles/role.py b/metagpt/roles/role.py index cc432d81f..6e05937a7 100644 --- a/metagpt/roles/role.py +++ b/metagpt/roles/role.py @@ -155,6 +155,7 @@ class Role(SerializationMixin, ContextMixin, BaseModel): if self.is_human: self.llm = HumanProvider(None) + self._check_actions() self.llm.system_prompt = self._get_prefix() self._watch(data.get("watch") or [UserRequirement]) @@ -229,14 +230,16 @@ class Role(SerializationMixin, ContextMixin, BaseModel): def _setting(self): return f"{self.name}({self.profile})" - @model_validator(mode="after") def _check_actions(self): """Check actions and set llm and prefix for each action.""" self.set_actions(self.actions) return self def _init_action(self, action: Action): - action.set_llm(self.llm, override=False) + if not action.private_config: + action.set_llm(self.llm, override=True) + else: + action.set_llm(self.llm, override=False) action.set_prefix(self._get_prefix()) def set_action(self, action: Action): diff --git a/metagpt/startup.py b/metagpt/startup.py index 14092edd2..771cde80c 100644 --- a/metagpt/startup.py +++ b/metagpt/startup.py @@ -7,7 +7,7 @@ from pathlib import Path import typer from metagpt.config2 import config -from metagpt.const import METAGPT_ROOT +from metagpt.const import CONFIG_ROOT, METAGPT_ROOT app = typer.Typer(add_completion=False, pretty_exceptions_show_locals=False) @@ -118,7 +118,7 @@ def startup( def copy_config_to(config_path=METAGPT_ROOT / "config" / "config2.yaml"): """Initialize the configuration file for MetaGPT.""" - target_path = Path.home() / ".metagpt" / "config2.yaml" + target_path = CONFIG_ROOT / "config2.yaml" # 创建目标目录(如果不存在) target_path.parent.mkdir(parents=True, exist_ok=True) diff --git a/tests/metagpt/provider/test_spark_api.py b/tests/metagpt/provider/test_spark_api.py index 2cb6bf559..f5a6f66fd 100644 --- a/tests/metagpt/provider/test_spark_api.py +++ b/tests/metagpt/provider/test_spark_api.py @@ -1,7 +1,6 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- # @Desc : the unittest of spark api -from pathlib import Path import pytest @@ -37,7 +36,7 @@ def mock_spark_get_msg_from_web_run(self) -> str: @pytest.mark.asyncio async def test_spark_aask(): - llm = SparkLLM(Config.model_validate_yaml(Path.home() / ".metagpt" / "spark.yaml").llm) + llm = SparkLLM(Config.from_home("spark.yaml").llm) resp = await llm.aask("Hello!") print(resp) diff --git a/tests/metagpt/test_context_mixin.py b/tests/metagpt/test_context_mixin.py index a1222c125..472d67a27 100644 --- a/tests/metagpt/test_context_mixin.py +++ b/tests/metagpt/test_context_mixin.py @@ -99,17 +99,30 @@ def test_config_mixin_4_multi_inheritance_override_config(): @pytest.mark.asyncio -async def test_debate_two_roles(): - config = Config.default() - config.llm.model = "gpt-4-1106-preview" - action1 = Action(config=config, name="AlexSay", instruction="Say your opinion with emotion and don't repeat it") - action2 = Action(name="BobSay", instruction="Say your opinion with emotion and don't repeat it") - alex = Role( - name="Alex", profile="Democratic candidate", goal="Win the election", actions=[action1], watch=[action2] - ) - bob = Role(name="Bob", profile="Republican candidate", goal="Win the election", actions=[action2], watch=[action1]) - env = Environment(desc="US election live broadcast") - team = Team(investment=10.0, env=env, roles=[alex, bob]) +async def test_config_priority(): + """If action's config is set, then its llm will be set, otherwise, it will use the role's llm""" + gpt4t = Config.from_home("gpt-4-1106-preview.yaml") + gpt35 = Config.default() + gpt4 = Config.default() + gpt4.llm.model = "gpt-4-0613" - history = await team.run(idea="Topic: climate change. Under 80 words per message.", send_to="Alex", n_round=3) - assert "Alex" in history + a1 = Action(config=gpt4t, name="Say", instruction="Say your opinion with emotion and don't repeat it") + a2 = Action(name="Say", instruction="Say your opinion with emotion and don't repeat it") + a3 = Action(name="Vote", instruction="Vote for the candidate, and say why you vote for him/her") + + # it will not work for a1 because the config is already set + A = Role(name="A", profile="Democratic candidate", goal="Win the election", actions=[a1], watch=[a2], config=gpt4) + # it will work for a2 because the config is not set + B = Role(name="B", profile="Republican candidate", goal="Win the election", actions=[a2], watch=[a1], config=gpt4) + # ditto + C = Role(name="C", profile="Voter", goal="Vote for the candidate", actions=[a3], watch=[a1, a2], config=gpt35) + + env = Environment(desc="US election live broadcast") + Team(investment=10.0, env=env, roles=[A, B, C]) + + assert a1.llm.model == "gpt-4-1106-preview" + assert a2.llm.model == "gpt-4-0613" + assert a3.llm.model == "gpt-3.5-turbo-1106" + + # history = await team.run(idea="Topic: climate change. Under 80 words per message.", send_to="a1", n_round=3) + # assert "Alex" in history