diff --git a/config/config2.yaml b/config/config2.yaml index 0040023a8..5e7f34809 100644 --- a/config/config2.yaml +++ b/config/config2.yaml @@ -1,4 +1,3 @@ llm: - gpt3t: - api_key: "YOUR_API_KEY" - model: "gpt-3.5-turbo-1106" \ No newline at end of file + api_key: "YOUR_API_KEY" + model: "gpt-3.5-turbo-1106" \ No newline at end of file diff --git a/examples/example.pkl b/examples/example.pkl index 94e0fe63b..b7454edee 100644 Binary files a/examples/example.pkl and b/examples/example.pkl differ diff --git a/metagpt/actions/research.py b/metagpt/actions/research.py index 6fd6ca139..2755628c9 100644 --- a/metagpt/actions/research.py +++ b/metagpt/actions/research.py @@ -184,7 +184,7 @@ class WebBrowseAndSummarize(Action): super().__init__(**kwargs) self.web_browser_engine = WebBrowserEngine( - engine=WebBrowserEngineType.CUSTOM if self.browse_func else None, + engine=WebBrowserEngineType.CUSTOM if self.browse_func else WebBrowserEngineType.PLAYWRIGHT, run_func=self.browse_func, ) diff --git a/metagpt/config2.py b/metagpt/config2.py index c0991a6a0..c916b9b60 100644 --- a/metagpt/config2.py +++ b/metagpt/config2.py @@ -9,7 +9,7 @@ import os from pathlib import Path from typing import Dict, Iterable, List, Literal, Optional -from pydantic import BaseModel, Field, model_validator +from pydantic import BaseModel, model_validator from metagpt.configs.browser_config import BrowserConfig from metagpt.configs.llm_config import LLMConfig, LLMType @@ -44,15 +44,15 @@ class Config(CLIParams, YamlModel): """Configurations for MetaGPT""" # Key Parameters - llm: Dict[str, LLMConfig] = Field(default_factory=Dict) + llm: LLMConfig # Global Proxy. Will be used if llm.proxy is not set proxy: str = "" # Tool Parameters - search: Dict[str, SearchConfig] = {} - browser: Dict[str, BrowserConfig] = {"default": BrowserConfig()} - mermaid: Dict[str, MermaidConfig] = {"default": MermaidConfig()} + search: Optional[SearchConfig] = None + browser: BrowserConfig = BrowserConfig() + mermaid: MermaidConfig = MermaidConfig() # Storage Parameters s3: Optional[S3Config] = None @@ -110,46 +110,17 @@ class Config(CLIParams, YamlModel): self.reqa_file = reqa_file self.max_auto_summarize_code = max_auto_summarize_code - def _get_llm_config(self, name: Optional[str] = None) -> LLMConfig: - """Get LLM instance by name""" - if name is None: - # Use the first LLM as default - name = list(self.llm.keys())[0] - if name not in self.llm: - raise ValueError(f"LLM {name} not found in config") - return self.llm[name] - - def get_llm_configs_by_type(self, llm_type: LLMType) -> List[LLMConfig]: - """Get LLM instance by type""" - return [v for k, v in self.llm.items() if v.api_type == llm_type] - - def get_llm_config_by_type(self, llm_type: LLMType) -> Optional[LLMConfig]: - """Get LLM instance by type""" - llm = self.get_llm_configs_by_type(llm_type) - if llm: - return llm[0] - return None - - def get_llm_config(self, name: Optional[str] = None, provider: LLMType = None) -> LLMConfig: - """Return a LLMConfig instance""" - if provider: - llm_configs = self.get_llm_configs_by_type(provider) - - if len(llm_configs) == 0: - raise ValueError(f"Cannot find llm config with name {name} and provider {provider}") - # return the first one if name is None, or return the only one - llm_config = llm_configs[0] - else: - llm_config = self._get_llm_config(name) - return llm_config - def get_openai_llm(self) -> Optional[LLMConfig]: """Get OpenAI LLMConfig by name. If no OpenAI, raise Exception""" - return self.get_llm_config_by_type(LLMType.OPENAI) + if self.llm.api_type == LLMType.OPENAI: + return self.llm + return None def get_azure_llm(self) -> Optional[LLMConfig]: """Get Azure LLMConfig by name. If no Azure, raise Exception""" - return self.get_llm_config_by_type(LLMType.AZURE) + if self.llm.api_type == LLMType.AZURE: + return self.llm + return None def merge_dict(dicts: Iterable[Dict]) -> Dict: diff --git a/metagpt/configs/llm_config.py b/metagpt/configs/llm_config.py index 620827630..626d4242f 100644 --- a/metagpt/configs/llm_config.py +++ b/metagpt/configs/llm_config.py @@ -40,6 +40,7 @@ class LLMConfig(YamlModel): api_type: LLMType = LLMType.OPENAI base_url: str = "https://api.openai.com/v1" api_version: Optional[str] = None + model: Optional[str] = None # also stands for DEPLOYMENT_NAME # For Spark(Xunfei), maybe remove later diff --git a/metagpt/context.py b/metagpt/context.py index 1c351ef22..663c1730a 100644 --- a/metagpt/context.py +++ b/metagpt/context.py @@ -12,7 +12,7 @@ from typing import Optional from pydantic import BaseModel, ConfigDict from metagpt.config2 import Config -from metagpt.configs.llm_config import LLMConfig, LLMType +from metagpt.configs.llm_config import LLMConfig from metagpt.const import OPTIONS from metagpt.provider.base_llm import BaseLLM from metagpt.provider.llm_provider_registry import create_llm_instance @@ -77,10 +77,10 @@ class Context(BaseModel): # self._llm = None # return self._llm - def llm(self, name: Optional[str] = None, provider: LLMType = None) -> BaseLLM: + def llm(self) -> BaseLLM: """Return a LLM instance, fixme: support cache""" # if self._llm is None: - self._llm = create_llm_instance(self.config.get_llm_config(name, provider)) + self._llm = create_llm_instance(self.config.llm) if self._llm.cost_manager is None: self._llm.cost_manager = self.cost_manager return self._llm @@ -140,12 +140,6 @@ class ContextMixin(BaseModel): """Set llm""" self.set("_llm", llm, override) - def use_llm(self, name: Optional[str] = None, provider: LLMType = None) -> BaseLLM: - """Use a LLM instance""" - self._llm_config = self.config.get_llm_config(name, provider) - self._llm = None - return self.llm - @property def config(self) -> Config: """Role config: role config > context config""" diff --git a/metagpt/llm.py b/metagpt/llm.py index d393738bb..4c9993441 100644 --- a/metagpt/llm.py +++ b/metagpt/llm.py @@ -6,14 +6,12 @@ @File : llm.py """ -from typing import Optional -from metagpt.configs.llm_config import LLMType from metagpt.context import CONTEXT from metagpt.provider.base_llm import BaseLLM -def LLM(name: Optional[str] = None, provider: LLMType = LLMType.OPENAI) -> BaseLLM: +def LLM() -> BaseLLM: """get the default llm provider if name is None""" # context.use_llm(name=name, provider=provider) - return CONTEXT.llm(name=name, provider=provider) + return CONTEXT.llm() diff --git a/metagpt/tools/search_engine_googleapi.py b/metagpt/tools/search_engine_googleapi.py index 65e1af109..0a8f796cb 100644 --- a/metagpt/tools/search_engine_googleapi.py +++ b/metagpt/tools/search_engine_googleapi.py @@ -35,7 +35,7 @@ class GoogleAPIWrapper(BaseModel): @field_validator("google_api_key", mode="before") @classmethod def check_google_api_key(cls, val: str): - val = val or config.search["google"].api_key + val = val or config.search.api_key if not val: raise ValueError( "To use, make sure you provide the google_api_key when constructing an object. Alternatively, " @@ -47,7 +47,7 @@ class GoogleAPIWrapper(BaseModel): @field_validator("google_cse_id", mode="before") @classmethod def check_google_cse_id(cls, val: str): - val = val or config.search["google"].cse_id + val = val or config.search.cse_id if not val: raise ValueError( "To use, make sure you provide the google_cse_id when constructing an object. Alternatively, " diff --git a/metagpt/tools/search_engine_serpapi.py b/metagpt/tools/search_engine_serpapi.py index 2d21aa85c..a8d5b49d0 100644 --- a/metagpt/tools/search_engine_serpapi.py +++ b/metagpt/tools/search_engine_serpapi.py @@ -32,7 +32,7 @@ class SerpAPIWrapper(BaseModel): @field_validator("serpapi_api_key", mode="before") @classmethod def check_serpapi_api_key(cls, val: str): - val = val or config.search["serpapi"].api_key + val = val or config.search.api_key if not val: raise ValueError( "To use, make sure you provide the serpapi_api_key when constructing an object. Alternatively, " diff --git a/metagpt/tools/search_engine_serper.py b/metagpt/tools/search_engine_serper.py index d67148e14..39cb936b8 100644 --- a/metagpt/tools/search_engine_serper.py +++ b/metagpt/tools/search_engine_serper.py @@ -25,7 +25,7 @@ class SerperWrapper(BaseModel): @field_validator("serper_api_key", mode="before") @classmethod def check_serper_api_key(cls, val: str): - val = val or config.search["serper"].api_key + val = val or config.search.api_key if not val: raise ValueError( "To use, make sure you provide the serper_api_key when constructing an object. Alternatively, " diff --git a/metagpt/tools/ut_writer.py b/metagpt/tools/ut_writer.py index a155c27ab..243871aff 100644 --- a/metagpt/tools/ut_writer.py +++ b/metagpt/tools/ut_writer.py @@ -282,6 +282,6 @@ class UTGenerator: """Choose based on different calling methods""" result = "" if self.chatgpt_method == "API": - result = await GPTAPI(config.get_llm_config()).aask_code(messages=messages) + result = await GPTAPI(config.get_openai_llm()).aask_code(messages=messages) return result diff --git a/metagpt/tools/web_browser_engine_playwright.py b/metagpt/tools/web_browser_engine_playwright.py index 00f2c6bab..14c19816d 100644 --- a/metagpt/tools/web_browser_engine_playwright.py +++ b/metagpt/tools/web_browser_engine_playwright.py @@ -28,12 +28,10 @@ class PlaywrightWrapper: def __init__( self, - browser_type: Literal["chromium", "firefox", "webkit"] | None = None, + browser_type: Literal["chromium", "firefox", "webkit"] | None = "chromium", launch_kwargs: dict | None = None, **kwargs, ) -> None: - if browser_type is None: - browser_type = config.browser["playwright"].driver self.browser_type = browser_type launch_kwargs = launch_kwargs or {} if config.proxy and "proxy" not in launch_kwargs: diff --git a/tests/data/rsp_cache.json b/tests/data/rsp_cache.json index b173c789b..25f7ae0b4 100644 --- a/tests/data/rsp_cache.json +++ b/tests/data/rsp_cache.json @@ -166,5 +166,18 @@ "\nNOTICE\nRole: You are a professional engineer; the main goal is to write google-style, elegant, modular, easy to read and maintain code\nLanguage: Please use the same language as the user requirement, but the title and code should be still in English. For example, if the user speaks Chinese, the specific text of your answer should also be in Chinese.\nATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenced \"Format example\".\n\n# Context\n## Design\n{\"Implementation approach\":\"We will use Python and the curses library to create the snake game. The game logic will be implemented in a separate module, and the main.py file will handle the user interface and game loop.\",\"File list\":[\"main.py\",\"game.py\"],\"Data structures and interfaces\":\"\\nclassDiagram\\n class Game {\\n -Snake snake\\n -Food food\\n -Score score\\n +__init__(width: int, height: int)\\n +start_game()\\n +move_snake(direction: str)\\n +generate_food()\\n +update_score(points: int)\\n }\\n class Snake {\\n -body list\\n -direction str\\n +__init__(x: int, y: int)\\n +move(direction: str)\\n +grow()\\n +collides_with_self() bool\\n }\\n class Food {\\n -position tuple\\n +__init__(x: int, y: int)\\n +get_position() tuple\\n }\\n class Score {\\n -points int\\n +__init__()\\n +increase(points: int)\\n }\\n Game --> Snake\\n Game --> Food\\n Game --> Score\\n\",\"Program call flow\":\"\\nsequenceDiagram\\n participant M as Main\\n participant G as Game\\n M->>G: start_game()\\n M->>G: move_snake(direction)\\n G->>G: generate_food()\\n G->>G: update_score(points)\\n\",\"Anything UNCLEAR\":\"Please provide more details on the game mechanics and user interactions.\"}\n\n## Tasks\n{\"Required Python packages\":[\"curses==2.2.0\"],\"Required Other language third-party packages\":[\"No third-party dependencies required\"],\"Logic Analysis\":[[\"game.py\",\"Contains Game class and ... functions\"],[\"main.py\",\"Contains main function, from game import Game\"]],\"Task list\":[\"game.py\",\"main.py\"],\"Full API spec\":\"\",\"Shared Knowledge\":\"'game.py' contains functions shared across the project.\",\"Anything UNCLEAR\":\"Please provide more details on the game mechanics and user interactions.\"}\n\n## Legacy Code\n```Code\n----- game.py\n## game.py\n\nimport curses\n\nclass Snake:\n def __init__(self, x: int, y: int):\n self.body = [(x, y)]\n self.direction = 'right'\n\n def move(self, direction: str):\n if direction == 'up' and self.direction != 'down':\n self.direction = 'up'\n elif direction == 'down' and self.direction != 'up':\n self.direction = 'down'\n elif direction == 'left' and self.direction != 'right':\n self.direction = 'left'\n elif direction == 'right' and self.direction != 'left':\n self.direction = 'right'\n\n head = self.body[0]\n x, y = head\n if self.direction == 'up':\n new_head = (x, y - 1)\n elif self.direction == 'down':\n new_head = (x, y + 1)\n elif self.direction == 'left':\n new_head = (x - 1, y)\n elif self.direction == 'right':\n new_head = (x + 1, y)\n self.body.insert(0, new_head)\n\n def grow(self):\n tail = self.body[-1]\n x, y = tail\n if self.direction == 'up':\n new_tail = (x, y + 1)\n elif self.direction == 'down':\n new_tail = (x, y - 1)\n elif self.direction == 'left':\n new_tail = (x + 1, y)\n elif self.direction == 'right':\n new_tail = (x - 1, y)\n self.body.append(new_tail)\n\n def collides_with_self(self) -> bool:\n return len(self.body) != len(set(self.body))\n\nclass Food:\n def __init__(self, x: int, y: int):\n self.position = (x, y)\n\n def get_position(self) -> tuple:\n return self.position\n\nclass Score:\n def __init__(self):\n self.points = 0\n\n def increase(self, points: int):\n self.points += points\n\nclass Game:\n def __init__(self, width: int, height: int):\n self.snake = Snake(width // 2, height // 2)\n self.food = None\n self.score = Score()\n self.width = width\n self.height = height\n\n def start_game(self):\n self.generate_food()\n\n def move_snake(self, direction: str):\n self.snake.move(direction)\n if self.check_collision():\n return False\n self.check_eat()\n return True\n\n def generate_food(self):\n import random\n x = random.randint(0, self.width - 1)\n y = random.randint(0, self.height - 1)\n self.food = Food(x, y)\n\n def update_score(self, points: int):\n self.score.increase(points)\n\n def check_collision(self) -> bool:\n head = self.snake.body[0]\n if head[0] < 0 or head[0] >= self.width or head[1] < 0 or head[1] >= self.height:\n return True\n if self.snake.collides_with_self():\n return True\n return False\n\n def check_eat(self):\n if self.snake.body[0] == self.food.get_position():\n self.snake.grow()\n self.generate_food()\n self.update_score(10)\n\n\n```\n\n## Debug logs\n```text\n\n\n\n```\n\n## Bug Feedback logs\n```text\n\n```\n\n# Format example\n## Code: main.py\n```python\n## main.py\n...\n```\n\n# Instruction: Based on the context, follow \"Format example\", write code.\n\n## Code: main.py. Write code with triple quoto, based on the following attentions and context.\n1. Only One file: do your best to implement THIS ONLY ONE FILE.\n2. COMPLETE CODE: Your code will be part of the entire project, so please implement complete, reliable, reusable code snippets.\n3. Set default value: If there is any setting, ALWAYS SET A DEFAULT VALUE, ALWAYS USE STRONG TYPE AND EXPLICIT VARIABLE. AVOID circular import.\n4. Follow design: YOU MUST FOLLOW \"Data structures and interfaces\". DONT CHANGE ANY DESIGN. Do not use public member functions that do not exist in your design.\n5. CAREFULLY CHECK THAT YOU DONT MISS ANY NECESSARY CLASS/FUNCTION IN THIS FILE.\n6. Before using a external variable/module, make sure you import it first.\n7. Write out EVERY CODE DETAIL, DON'T LEAVE TODO.\n\n": "```python\n## main.py\n\nfrom game import Game\n\ndef main():\n width = 20 # Set default width\n height = 20 # Set default height\n game = Game(width, height)\n game.start_game()\n\n while True:\n # Get user input for direction\n direction = input(\"Enter direction (up/down/left/right): \")\n if direction in ['up', 'down', 'left', 'right']:\n if not game.move_snake(direction):\n print(\"Game over!\")\n break\n else:\n print(\"Invalid direction!\")\n\nif __name__ == \"__main__\":\n main()\n```", "\n# System\nRole: You are a professional software engineer, and your main task is to review and revise the code. You need to ensure that the code conforms to the google-style standards, is elegantly designed and modularized, easy to read and maintain.\nLanguage: Please use the same language as the user requirement, but the title and code should be still in English. For example, if the user speaks Chinese, the specific text of your answer should also be in Chinese.\nATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenced \"Format example\".\n\n# Context\n## System Design\n{\"Implementation approach\":\"We will use Python and the curses library to create the snake game. The game logic will be implemented in a separate module, and the main.py file will handle the user interface and game loop.\",\"File list\":[\"main.py\",\"game.py\"],\"Data structures and interfaces\":\"\\nclassDiagram\\n class Game {\\n -Snake snake\\n -Food food\\n -Score score\\n +__init__(width: int, height: int)\\n +start_game()\\n +move_snake(direction: str)\\n +generate_food()\\n +update_score(points: int)\\n }\\n class Snake {\\n -body list\\n -direction str\\n +__init__(x: int, y: int)\\n +move(direction: str)\\n +grow()\\n +collides_with_self() bool\\n }\\n class Food {\\n -position tuple\\n +__init__(x: int, y: int)\\n +get_position() tuple\\n }\\n class Score {\\n -points int\\n +__init__()\\n +increase(points: int)\\n }\\n Game --> Snake\\n Game --> Food\\n Game --> Score\\n\",\"Program call flow\":\"\\nsequenceDiagram\\n participant M as Main\\n participant G as Game\\n M->>G: start_game()\\n M->>G: move_snake(direction)\\n G->>G: generate_food()\\n G->>G: update_score(points)\\n\",\"Anything UNCLEAR\":\"Please provide more details on the game mechanics and user interactions.\"}\n\n## Tasks\n{\"Required Python packages\":[\"curses==2.2.0\"],\"Required Other language third-party packages\":[\"No third-party dependencies required\"],\"Logic Analysis\":[[\"game.py\",\"Contains Game class and ... functions\"],[\"main.py\",\"Contains main function, from game import Game\"]],\"Task list\":[\"game.py\",\"main.py\"],\"Full API spec\":\"\",\"Shared Knowledge\":\"'game.py' contains functions shared across the project.\",\"Anything UNCLEAR\":\"Please provide more details on the game mechanics and user interactions.\"}\n\n## Code Files\n----- game.py\n## game.py\n\nimport curses\n\nclass Snake:\n def __init__(self, x: int, y: int):\n self.body = [(x, y)]\n self.direction = 'right'\n\n def move(self, direction: str):\n if direction == 'up' and self.direction != 'down':\n self.direction = 'up'\n elif direction == 'down' and self.direction != 'up':\n self.direction = 'down'\n elif direction == 'left' and self.direction != 'right':\n self.direction = 'left'\n elif direction == 'right' and self.direction != 'left':\n self.direction = 'right'\n\n head = self.body[0]\n x, y = head\n if self.direction == 'up':\n new_head = (x, y - 1)\n elif self.direction == 'down':\n new_head = (x, y + 1)\n elif self.direction == 'left':\n new_head = (x - 1, y)\n elif self.direction == 'right':\n new_head = (x + 1, y)\n self.body.insert(0, new_head)\n\n def grow(self):\n tail = self.body[-1]\n x, y = tail\n if self.direction == 'up':\n new_tail = (x, y + 1)\n elif self.direction == 'down':\n new_tail = (x, y - 1)\n elif self.direction == 'left':\n new_tail = (x + 1, y)\n elif self.direction == 'right':\n new_tail = (x - 1, y)\n self.body.append(new_tail)\n\n def collides_with_self(self) -> bool:\n return len(self.body) != len(set(self.body))\n\nclass Food:\n def __init__(self, x: int, y: int):\n self.position = (x, y)\n\n def get_position(self) -> tuple:\n return self.position\n\nclass Score:\n def __init__(self):\n self.points = 0\n\n def increase(self, points: int):\n self.points += points\n\nclass Game:\n def __init__(self, width: int, height: int):\n self.snake = Snake(width // 2, height // 2)\n self.food = None\n self.score = Score()\n self.width = width\n self.height = height\n\n def start_game(self):\n self.generate_food()\n\n def move_snake(self, direction: str):\n self.snake.move(direction)\n if self.check_collision():\n return False\n self.check_eat()\n return True\n\n def generate_food(self):\n import random\n x = random.randint(0, self.width - 1)\n y = random.randint(0, self.height - 1)\n self.food = Food(x, y)\n\n def update_score(self, points: int):\n self.score.increase(points)\n\n def check_collision(self) -> bool:\n head = self.snake.body[0]\n if head[0] < 0 or head[0] >= self.width or head[1] < 0 or head[1] >= self.height:\n return True\n if self.snake.collides_with_self():\n return True\n return False\n\n def check_eat(self):\n if self.snake.body[0] == self.food.get_position():\n self.snake.grow()\n self.generate_food()\n self.update_score(10)\n\n\n\n\n## Code to be Reviewed: main.py\n```Code\n## main.py\n\nfrom game import Game\n\ndef main():\n width = 20 # Set default width\n height = 20 # Set default height\n game = Game(width, height)\n game.start_game()\n\n while True:\n # Get user input for direction\n direction = input(\"Enter direction (up/down/left/right): \")\n if direction in ['up', 'down', 'left', 'right']:\n if not game.move_snake(direction):\n print(\"Game over!\")\n break\n else:\n print(\"Invalid direction!\")\n\nif __name__ == \"__main__\":\n main()\n\n```\n\n\n\n# Format example 1\n## Code Review: main.py\n1. No, we should fix the logic of class A due to ...\n2. ...\n3. ...\n4. No, function B is not implemented, ...\n5. ...\n6. ...\n\n## Actions\n1. Fix the `handle_events` method to update the game state only if a move is successful.\n ```python\n def handle_events(self):\n for event in pygame.event.get():\n if event.type == pygame.QUIT:\n return False\n if event.type == pygame.KEYDOWN:\n moved = False\n if event.key == pygame.K_UP:\n moved = self.game.move('UP')\n elif event.key == pygame.K_DOWN:\n moved = self.game.move('DOWN')\n elif event.key == pygame.K_LEFT:\n moved = self.game.move('LEFT')\n elif event.key == pygame.K_RIGHT:\n moved = self.game.move('RIGHT')\n if moved:\n # Update the game state only if a move was successful\n self.render()\n return True\n ```\n2. Implement function B\n\n## Code Review Result\nLBTM\n\n# Format example 2\n## Code Review: main.py\n1. Yes.\n2. Yes.\n3. Yes.\n4. Yes.\n5. Yes.\n6. Yes.\n\n## Actions\npass\n\n## Code Review Result\nLGTM\n\n\n\n# Instruction: Based on the actual code situation, follow one of the \"Format example\". Return only 1 file under review.\n\n## Code Review: Ordered List. Based on the \"Code to be Reviewed\", provide key, clear, concise, and specific answer. If any answer is no, explain how to fix it step by step.\n1. Is the code implemented as per the requirements? If not, how to achieve it? Analyse it step by step.\n2. Is the code logic completely correct? If there are errors, please indicate how to correct them.\n3. Does the existing code follow the \"Data structures and interfaces\"?\n4. Are all functions implemented? If there is no implementation, please indicate how to achieve it step by step.\n5. Have all necessary pre-dependencies been imported? If not, indicate which ones need to be imported\n6. Are methods from other files being reused correctly?\n\n## Actions: Ordered List. Things that should be done after CR, such as implementing class A and function B\n\n## Code Review Result: str. If the code doesn't have bugs, we don't need to rewrite it, so answer LGTM and stop. ONLY ANSWER LGTM/LBTM.\nLGTM/LBTM\n\n": "## Code Review: main.py\n1. The code is implemented as per the requirements. The main function initializes the game and handles user input for the snake's direction.\n2. The code logic is correct. It correctly handles user input and updates the game state based on the snake's movement.\n3. The existing code follows the \"Data structures and interfaces\" as defined in the class diagram.\n4. All necessary functions are implemented in the code.\n5. The necessary pre-dependencies have been imported. The required Python package \"curses==2.2.0\" has been imported.\n6. The methods from the \"game.py\" file are being reused correctly.\n\n## Actions\npass\n\n## Code Review Result\nLGTM", "\n## context\n\n### Project Name\n20240110212717\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\n20240110212717\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\n20240110212717\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\n20240110220803\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]", + "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 -*-\nimport asyncio\nimport shutil\nfrom pathlib import Path\n\nimport typer\n\nfrom metagpt.config2 import config\nfrom metagpt.const import METAGPT_ROOT\n\napp = typer.Typer(add_completion=False, pretty_exceptions_show_locals=False)\n\n\ndef generate_repo(\n idea,\n investment,\n n_round,\n code_review,\n run_tests,\n implement,\n project_name,\n inc,\n project_path,\n reqa_file,\n max_auto_summarize_code,\n recover_path,\n):\n \"\"\"Run the startup logic. Can be called from CLI or other Python scripts.\"\"\"\n from metagpt.roles import (\n Architect,\n Engineer,\n ProductManager,\n ProjectManager,\n QaEngineer,\n )\n from metagpt.team import Team\n\n config.update_via_cli(project_path, project_name, inc, reqa_file, max_auto_summarize_code)\n\n if not recover_path:\n company = Team()\n company.hire(\n [\n ProductManager(),\n Architect(),\n ProjectManager(),\n ]\n )\n\n if implement or code_review:\n company.hire([Engineer(n_borg=5, use_code_review=code_review)])\n\n if run_tests:\n company.hire([QaEngineer()])\n else:\n stg_path = Path(recover_path)\n if not stg_path.exists() or not str(stg_path).endswith(\"team\"):\n raise FileNotFoundError(f\"{recover_path} not exists or not endswith `team`\")\n\n company = Team.deserialize(stg_path=stg_path)\n idea = company.idea\n\n company.invest(investment)\n company.run_project(idea)\n asyncio.run(company.run(n_round=n_round))\n\n\n@app.command(\"\", help=\"Start a new project.\")\ndef startup(\n idea: str = typer.Argument(None, help=\"Your innovative idea, such as 'Create a 2048 game.'\"),\n investment: float = typer.Option(default=3.0, help=\"Dollar amount to invest in the AI company.\"),\n n_round: int = typer.Option(default=5, help=\"Number of rounds for the simulation.\"),\n code_review: bool = typer.Option(default=True, help=\"Whether to use code review.\"),\n run_tests: bool = typer.Option(default=False, help=\"Whether to enable QA for adding & running tests.\"),\n implement: bool = typer.Option(default=True, help=\"Enable or disable code implementation.\"),\n project_name: str = typer.Option(default=\"\", help=\"Unique project name, such as 'game_2048'.\"),\n inc: bool = typer.Option(default=False, help=\"Incremental mode. Use it to coop with existing repo.\"),\n project_path: str = typer.Option(\n default=\"\",\n help=\"Specify the directory path of the old version project to fulfill the incremental requirements.\",\n ),\n reqa_file: str = typer.Option(\n default=\"\", help=\"Specify the source file name for rewriting the quality assurance code.\"\n ),\n max_auto_summarize_code: int = typer.Option(\n default=0,\n help=\"The maximum number of times the 'SummarizeCode' action is automatically invoked, with -1 indicating \"\n \"unlimited. This parameter is used for debugging the workflow.\",\n ),\n recover_path: str = typer.Option(default=None, help=\"recover the project from existing serialized storage\"),\n init_config: bool = typer.Option(default=False, help=\"Initialize the configuration file for MetaGPT.\"),\n):\n \"\"\"Run a startup. Be a boss.\"\"\"\n if init_config:\n copy_config_to()\n return\n\n if idea is None:\n typer.echo(\"Missing argument 'IDEA'. Run 'metagpt --help' for more information.\")\n raise typer.Exit()\n\n return generate_repo(\n idea,\n investment,\n n_round,\n code_review,\n run_tests,\n implement,\n project_name,\n inc,\n project_path,\n reqa_file,\n max_auto_summarize_code,\n recover_path,\n )\n\n\ndef copy_config_to(config_path=METAGPT_ROOT / \"config\" / \"config2.yaml\"):\n \"\"\"Initialize the configuration file for MetaGPT.\"\"\"\n target_path = Path.home() / \".metagpt\" / \"config2.yaml\"\n\n # 创建目标目录(如果不存在)\n target_path.parent.mkdir(parents=True, exist_ok=True)\n\n # 如果目标文件已经存在,则重命名为 .bak\n if target_path.exists():\n backup_path = target_path.with_suffix(\".bak\")\n target_path.rename(backup_path)\n print(f\"Existing configuration file backed up at {backup_path}\")\n\n # 复制文件\n shutil.copy(str(config_path), target_path)\n print(f\"Configuration file initialized at {target_path}\")\n\n\nif __name__ == \"__main__\":\n app()\n\n```\n\n---\nTranslate the code above into Mermaid Sequence Diagram.": "```mermaid\nsequenceDiagram\n participant app as app\n participant typer as typer\n participant generate_repo as generate_repo\n participant Team as company\n participant ProductManager as ProductManager\n participant Architect as Architect\n participant ProjectManager as ProjectManager\n participant Engineer as Engineer\n participant QaEngineer as QaEngineer\n\n app -> typer: startup()\n typer -> generate_repo: generate_repo()\n generate_repo -> config: config.update_via_cli()\n generate_repo -> company: company.hire([ProductManager, Architect, ProjectManager])\n generate_repo -> company: company.hire([Engineer])\n generate_repo -> company: company.hire([QaEngineer])\n generate_repo -> company: company.invest()\n generate_repo -> company: company.run_project()\n generate_repo -> company: asyncio.run(company.run())\n\n Note right of generate_repo: If recover_path is provided,
deserialize Team from recover_path\n```", + "You are a python code to Mermaid Sequence Diagram translator in function detail#SYSTEM_MSG_END#```python\n#!/usr/bin/env python\n\nfrom __future__ import annotations\n\nimport asyncio\nimport json\nfrom concurrent import futures\nfrom typing import Literal, overload\n\nfrom metagpt.config2 import config\n\ntry:\n from duckduckgo_search import DDGS\nexcept ImportError:\n raise ImportError(\n \"To use this module, you should have the `duckduckgo_search` Python package installed. \"\n \"You can install it by running the command: `pip install -e.[search-ddg]`\"\n )\n\n\nclass DDGAPIWrapper:\n \"\"\"Wrapper around duckduckgo_search API.\n\n To use this module, you should have the `duckduckgo_search` Python package installed.\n \"\"\"\n\n def __init__(\n self,\n *,\n loop: asyncio.AbstractEventLoop | None = None,\n executor: futures.Executor | None = None,\n ):\n kwargs = {}\n if config.proxy:\n kwargs[\"proxies\"] = config.proxy\n self.loop = loop\n self.executor = executor\n self.ddgs = DDGS(**kwargs)\n\n @overload\n def run(\n self,\n query: str,\n max_results: int = 8,\n as_string: Literal[True] = True,\n focus: list[str] | None = None,\n ) -> str:\n ...\n\n @overload\n def run(\n self,\n query: str,\n max_results: int = 8,\n as_string: Literal[False] = False,\n focus: list[str] | None = None,\n ) -> list[dict[str, str]]:\n ...\n\n async def run(\n self,\n query: str,\n max_results: int = 8,\n as_string: bool = True,\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\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,\n self._search_from_ddgs,\n query,\n max_results,\n )\n search_results = await future\n\n # Return the list of search result URLs\n if as_string:\n return json.dumps(search_results, ensure_ascii=False)\n return search_results\n\n def _search_from_ddgs(self, query: str, max_results: int):\n return [\n {\"link\": i[\"href\"], \"snippet\": i[\"body\"], \"title\": i[\"title\"]}\n for (_, i) in zip(range(max_results), self.ddgs.text(query))\n ]\n\n\nif __name__ == \"__main__\":\n import fire\n\n fire.Fire(DDGAPIWrapper().run)\n\n```\n\n---\nTranslate the code above into Mermaid Sequence Diagram.": "```mermaid\nsequenceDiagram\n participant User\n participant DDGAPIWrapper\n participant asyncio\n participant futures\n participant DDGS\n participant config\n\n User->>DDGAPIWrapper: run(query, max_results, as_string)\n DDGAPIWrapper->>asyncio: get_event_loop()\n asyncio->>DDGAPIWrapper: loop\n alt config.proxy\n DDGAPIWrapper->>config: proxy\n end\n DDGAPIWrapper->>futures: Executor\n futures->>DDGAPIWrapper: executor\n DDGAPIWrapper->>DDGS: __init__(**kwargs)\n DDGAPIWrapper->>asyncio: run_in_executor(executor, _search_from_ddgs, query, max_results)\n asyncio->>DDGAPIWrapper: future\n DDGAPIWrapper->>DDGS: text(query)\n DDGS-->>DDGAPIWrapper: search results\n DDGAPIWrapper-->>asyncio: search_results\n asyncio-->>DDGAPIWrapper: await future\n DDGAPIWrapper-->>User: search results\n```", + "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 -*-\n\"\"\"\n@Time : 2023/5/23 18:27\n@Author : alexanderwu\n@File : search_engine_serpapi.py\n\"\"\"\nfrom typing import Any, Dict, Optional, Tuple\n\nimport aiohttp\nfrom pydantic import BaseModel, ConfigDict, Field, field_validator\n\nfrom metagpt.config2 import config\n\n\nclass SerpAPIWrapper(BaseModel):\n model_config = ConfigDict(arbitrary_types_allowed=True)\n\n search_engine: Any = None #: :meta private:\n params: dict = Field(\n default_factory=lambda: {\n \"engine\": \"google\",\n \"google_domain\": \"google.com\",\n \"gl\": \"us\",\n \"hl\": \"en\",\n }\n )\n # should add `validate_default=True` to check with default value\n serpapi_api_key: Optional[str] = Field(default=None, validate_default=True)\n aiosession: Optional[aiohttp.ClientSession] = None\n\n @field_validator(\"serpapi_api_key\", mode=\"before\")\n @classmethod\n def check_serpapi_api_key(cls, val: str):\n val = val or config.search[\"serpapi\"].api_key\n if not val:\n raise ValueError(\n \"To use, make sure you provide the serpapi_api_key when constructing an object. Alternatively, \"\n \"ensure that the environment variable SERPAPI_API_KEY is set with your API key. You can obtain \"\n \"an API key from https://serpapi.com/.\"\n )\n return val\n\n async def run(self, query, max_results: int = 8, as_string: bool = True, **kwargs: Any) -> str:\n \"\"\"Run query through SerpAPI and parse result async.\"\"\"\n result = await self.results(query, max_results)\n return self._process_response(result, as_string=as_string)\n\n async def results(self, query: str, max_results: int) -> dict:\n \"\"\"Use aiohttp to run query through SerpAPI and return the results async.\"\"\"\n\n def construct_url_and_params() -> Tuple[str, Dict[str, str]]:\n params = self.get_params(query)\n params[\"source\"] = \"python\"\n params[\"num\"] = max_results\n params[\"output\"] = \"json\"\n url = \"https://serpapi.com/search\"\n return url, params\n\n url, params = construct_url_and_params()\n if not self.aiosession:\n async with aiohttp.ClientSession() as session:\n async with session.get(url, params=params) as response:\n res = await response.json()\n else:\n async with self.aiosession.get(url, params=params) as response:\n res = await response.json()\n\n return res\n\n def get_params(self, query: str) -> Dict[str, str]:\n \"\"\"Get parameters for SerpAPI.\"\"\"\n _params = {\n \"api_key\": self.serpapi_api_key,\n \"q\": query,\n }\n params = {**self.params, **_params}\n return params\n\n @staticmethod\n def _process_response(res: dict, as_string: bool) -> str:\n \"\"\"Process response from SerpAPI.\"\"\"\n # logger.debug(res)\n focus = [\"title\", \"snippet\", \"link\"]\n get_focused = lambda x: {i: j for i, j in x.items() if i in focus}\n\n if \"error\" in res.keys():\n raise ValueError(f\"Got error from SerpAPI: {res['error']}\")\n if \"answer_box\" in res.keys() and \"answer\" in res[\"answer_box\"].keys():\n toret = res[\"answer_box\"][\"answer\"]\n elif \"answer_box\" in res.keys() and \"snippet\" in res[\"answer_box\"].keys():\n toret = res[\"answer_box\"][\"snippet\"]\n elif \"answer_box\" in res.keys() and \"snippet_highlighted_words\" in res[\"answer_box\"].keys():\n toret = res[\"answer_box\"][\"snippet_highlighted_words\"][0]\n elif \"sports_results\" in res.keys() and \"game_spotlight\" in res[\"sports_results\"].keys():\n toret = res[\"sports_results\"][\"game_spotlight\"]\n elif \"knowledge_graph\" in res.keys() and \"description\" in res[\"knowledge_graph\"].keys():\n toret = res[\"knowledge_graph\"][\"description\"]\n elif \"snippet\" in res[\"organic_results\"][0].keys():\n toret = res[\"organic_results\"][0][\"snippet\"]\n else:\n toret = \"No good search result found\"\n\n toret_l = []\n if \"answer_box\" in res.keys() and \"snippet\" in res[\"answer_box\"].keys():\n toret_l += [get_focused(res[\"answer_box\"])]\n if res.get(\"organic_results\"):\n toret_l += [get_focused(i) for i in res.get(\"organic_results\")]\n\n return str(toret) + \"\\n\" + str(toret_l) if as_string else toret_l\n\n\nif __name__ == \"__main__\":\n import fire\n\n fire.Fire(SerpAPIWrapper().run)\n\n```\n\n---\nTranslate the code above into Mermaid Sequence Diagram.": "```mermaid\nsequenceDiagram\n participant SerpAPIWrapper\n participant aiohttp\n participant session\n participant response\n participant fire\n\n Note over SerpAPIWrapper: Initialization\n SerpAPIWrapper->>SerpAPIWrapper: __init__\n\n Note over SerpAPIWrapper: Run query through SerpAPI\n SerpAPIWrapper->>SerpAPIWrapper: run(query, max_results, as_string, **kwargs)\n SerpAPIWrapper->>SerpAPIWrapper: results(query, max_results)\n SerpAPIWrapper->>SerpAPIWrapper: get_params(query)\n SerpAPIWrapper->>aiohttp: session.get(url, params)\n aiohttp->>session: get(url, params)\n session->>response: response.json()\n response-->>session: res\n session-->>aiohttp: res\n aiohttp-->>SerpAPIWrapper: res\n SerpAPIWrapper-->>SerpAPIWrapper: _process_response(result, as_string)\n\n Note over SerpAPIWrapper: Use aiohttp to run query through SerpAPI\n SerpAPIWrapper->>SerpAPIWrapper: results(query, max_results)\n SerpAPIWrapper->>SerpAPIWrapper: get_params(query)\n SerpAPIWrapper->>aiohttp: ClientSession()\n aiohttp->>session: get(url, params)\n session->>response: response.json()\n response-->>session: res\n session-->>aiohttp: res\n aiohttp-->>SerpAPIWrapper: res\n\n Note over SerpAPIWrapper: Get parameters for SerpAPI\n SerpAPIWrapper->>SerpAPIWrapper: get_params(query)\n\n Note over SerpAPIWrapper: Process response from SerpAPI\n SerpAPIWrapper->>SerpAPIWrapper: _process_response(res, as_string)\n\n Note over fire: Main function\n fire->>SerpAPIWrapper: run\n\n```", + "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 -*-\n\"\"\"\n@Time : 2023/5/23 18:27\n@Author : alexanderwu\n@File : search_engine_serpapi.py\n\"\"\"\nimport json\nfrom typing import Any, Dict, Optional, Tuple\n\nimport aiohttp\nfrom pydantic import BaseModel, ConfigDict, Field, field_validator\n\nfrom metagpt.config2 import config\n\n\nclass SerperWrapper(BaseModel):\n model_config = ConfigDict(arbitrary_types_allowed=True)\n\n search_engine: Any = None #: :meta private:\n payload: dict = Field(default_factory=lambda: {\"page\": 1, \"num\": 10})\n serper_api_key: Optional[str] = Field(default=None, validate_default=True)\n aiosession: Optional[aiohttp.ClientSession] = None\n\n @field_validator(\"serper_api_key\", mode=\"before\")\n @classmethod\n def check_serper_api_key(cls, val: str):\n val = val or config.search[\"serper\"].api_key\n if not val:\n raise ValueError(\n \"To use, make sure you provide the serper_api_key when constructing an object. Alternatively, \"\n \"ensure that the environment variable SERPER_API_KEY is set with your API key. You can obtain \"\n \"an API key from https://serper.dev/.\"\n )\n return val\n\n async def run(self, query: str, max_results: int = 8, as_string: bool = True, **kwargs: Any) -> str:\n \"\"\"Run query through Serper and parse result async.\"\"\"\n if isinstance(query, str):\n return self._process_response((await self.results([query], max_results))[0], as_string=as_string)\n else:\n results = [self._process_response(res, as_string) for res in await self.results(query, max_results)]\n return \"\\n\".join(results) if as_string else results\n\n async def results(self, queries: list[str], max_results: int = 8) -> dict:\n \"\"\"Use aiohttp to run query through Serper and return the results async.\"\"\"\n\n def construct_url_and_payload_and_headers() -> Tuple[str, Dict[str, str]]:\n payloads = self.get_payloads(queries, max_results)\n url = \"https://google.serper.dev/search\"\n headers = self.get_headers()\n return url, payloads, headers\n\n url, payloads, headers = construct_url_and_payload_and_headers()\n if not self.aiosession:\n async with aiohttp.ClientSession() as session:\n async with session.post(url, data=payloads, headers=headers) as response:\n res = await response.json()\n else:\n async with self.aiosession.get.post(url, data=payloads, headers=headers) as response:\n res = await response.json()\n\n return res\n\n def get_payloads(self, queries: list[str], max_results: int) -> Dict[str, str]:\n \"\"\"Get payloads for Serper.\"\"\"\n payloads = []\n for query in queries:\n _payload = {\n \"q\": query,\n \"num\": max_results,\n }\n payloads.append({**self.payload, **_payload})\n return json.dumps(payloads, sort_keys=True)\n\n def get_headers(self) -> Dict[str, str]:\n headers = {\"X-API-KEY\": self.serper_api_key, \"Content-Type\": \"application/json\"}\n return headers\n\n @staticmethod\n def _process_response(res: dict, as_string: bool = False) -> str:\n \"\"\"Process response from SerpAPI.\"\"\"\n # logger.debug(res)\n focus = [\"title\", \"snippet\", \"link\"]\n\n def get_focused(x):\n return {i: j for i, j in x.items() if i in focus}\n\n if \"error\" in res.keys():\n raise ValueError(f\"Got error from SerpAPI: {res['error']}\")\n if \"answer_box\" in res.keys() and \"answer\" in res[\"answer_box\"].keys():\n toret = res[\"answer_box\"][\"answer\"]\n elif \"answer_box\" in res.keys() and \"snippet\" in res[\"answer_box\"].keys():\n toret = res[\"answer_box\"][\"snippet\"]\n elif \"answer_box\" in res.keys() and \"snippet_highlighted_words\" in res[\"answer_box\"].keys():\n toret = res[\"answer_box\"][\"snippet_highlighted_words\"][0]\n elif \"sports_results\" in res.keys() and \"game_spotlight\" in res[\"sports_results\"].keys():\n toret = res[\"sports_results\"][\"game_spotlight\"]\n elif \"knowledge_graph\" in res.keys() and \"description\" in res[\"knowledge_graph\"].keys():\n toret = res[\"knowledge_graph\"][\"description\"]\n elif \"snippet\" in res[\"organic\"][0].keys():\n toret = res[\"organic\"][0][\"snippet\"]\n else:\n toret = \"No good search result found\"\n\n toret_l = []\n if \"answer_box\" in res.keys() and \"snippet\" in res[\"answer_box\"].keys():\n toret_l += [get_focused(res[\"answer_box\"])]\n if res.get(\"organic\"):\n toret_l += [get_focused(i) for i in res.get(\"organic\")]\n\n return str(toret) + \"\\n\" + str(toret_l) if as_string else toret_l\n\n\nif __name__ == \"__main__\":\n import fire\n\n fire.Fire(SerperWrapper().run)\n\n```\n\n---\nTranslate the code above into Mermaid Sequence Diagram.": "```mermaid\nsequenceDiagram\n participant User\n participant SerperWrapper\n participant aiohttp\n participant pydantic\n participant config\n\n User ->> SerperWrapper: run(query: str, max_results: int, as_string: bool, **kwargs: Any)\n SerperWrapper ->> SerperWrapper: _process_response(response: dict, as_string: bool)\n SerperWrapper ->> SerperWrapper: get_payloads(queries: list[str], max_results: int)\n SerperWrapper ->> SerperWrapper: get_headers()\n SerperWrapper ->> aiohttp: ClientSession.post(url, data, headers)\n aiohttp ->> SerperWrapper: response\n SerperWrapper ->> aiohttp: ClientSession.get.post(url, data, headers)\n aiohttp ->> SerperWrapper: response\n SerperWrapper ->> aiohttp: ClientSession.post(url, data, headers)\n aiohttp ->> SerperWrapper: response\n SerperWrapper ->> User: str\n```", + "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[\"google\"].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[\"google\"].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 ConfigDict\n participant Field\n participant field_validator\n participant asyncio\n participant futures\n participant urlparse\n participant httplib2\n participant logger\n participant build\n participant HttpError\n participant GoogleAPIWrapper\n participant fire\n\n BaseModel ->> ConfigDict: model_config\n BaseModel ->> Field: google_api_key\n BaseModel ->> Field: google_cse_id\n BaseModel ->> Field: loop\n BaseModel ->> Field: executor\n Field ->> field_validator: check_google_api_key\n Field ->> field_validator: check_google_cse_id\n GoogleAPIWrapper ->> urlparse: parse_result\n urlparse ->> httplib2: Http\n urlparse ->> httplib2: ProxyInfo\n httplib2 ->> logger: exception\n build ->> GoogleAPIWrapper: google_api_client\n GoogleAPIWrapper ->> asyncio: run\n asyncio ->> futures: run_in_executor\n futures ->> GoogleAPIWrapper: google_api_client.list\n GoogleAPIWrapper ->> HttpError: HttpError\n HttpError ->> logger: exception\n GoogleAPIWrapper ->> safe_google_results: safe_google_results\n safe_google_results -->> GoogleAPIWrapper: safe_message\n GoogleAPIWrapper -->> fire: run\n```", + "You are a python code to Mermaid Sequence Diagram translator in function detail#SYSTEM_MSG_END#```python\nNone\n```\n\n---\nTranslate the code above into Mermaid Sequence Diagram.": "```mermaid\nsequenceDiagram\n participant PythonCode\n PythonCode->>Mermaid: None\n```", + "You are a python code to Mermaid Sequence Diagram translator in function detail#SYSTEM_MSG_END#```python\n#!/usr/bin/env python\n\"\"\"\n@Modified By: mashenquan, 2023/8/22. A definition has been provided for the return value of _think: returning false indicates that further reasoning cannot continue.\n@Modified By: mashenquan, 2023-11-1. According to Chapter 2.2.1 and 2.2.2 of RFC 116, change the data type of\n the `cause_by` value in the `Message` to a string to support the new message distribution feature.\n\"\"\"\n\nimport asyncio\nimport re\n\nfrom pydantic import BaseModel\n\nfrom metagpt.actions import Action, CollectLinks, ConductResearch, WebBrowseAndSummarize\nfrom metagpt.actions.research import get_research_system_text\nfrom metagpt.const import RESEARCH_PATH\nfrom metagpt.logs import logger\nfrom metagpt.roles.role import Role, RoleReactMode\nfrom metagpt.schema import Message\n\n\nclass Report(BaseModel):\n topic: str\n links: dict[str, list[str]] = None\n summaries: list[tuple[str, str]] = None\n content: str = \"\"\n\n\nclass Researcher(Role):\n name: str = \"David\"\n profile: str = \"Researcher\"\n goal: str = \"Gather information and conduct research\"\n constraints: str = \"Ensure accuracy and relevance of information\"\n language: str = \"en-us\"\n\n def __init__(self, **kwargs):\n super().__init__(**kwargs)\n self.set_actions(\n [CollectLinks(name=self.name), WebBrowseAndSummarize(name=self.name), ConductResearch(name=self.name)]\n )\n self._set_react_mode(react_mode=RoleReactMode.BY_ORDER.value)\n if self.language not in (\"en-us\", \"zh-cn\"):\n logger.warning(f\"The language `{self.language}` has not been tested, it may not work.\")\n\n async def _think(self) -> bool:\n if self.rc.todo is None:\n self._set_state(0)\n return True\n\n if self.rc.state + 1 < len(self.states):\n self._set_state(self.rc.state + 1)\n else:\n self.set_todo(None)\n return False\n\n async def _act(self) -> Message:\n logger.info(f\"{self._setting}: to do {self.rc.todo}({self.rc.todo.name})\")\n todo = self.rc.todo\n msg = self.rc.memory.get(k=1)[0]\n if isinstance(msg.instruct_content, Report):\n instruct_content = msg.instruct_content\n topic = instruct_content.topic\n else:\n topic = msg.content\n\n research_system_text = self.research_system_text(topic, todo)\n if isinstance(todo, CollectLinks):\n links = await todo.run(topic, 4, 4)\n ret = Message(\n content=\"\", instruct_content=Report(topic=topic, links=links), role=self.profile, cause_by=todo\n )\n elif isinstance(todo, WebBrowseAndSummarize):\n links = instruct_content.links\n todos = (todo.run(*url, query=query, system_text=research_system_text) for (query, url) in links.items())\n summaries = await asyncio.gather(*todos)\n summaries = list((url, summary) for i in summaries for (url, summary) in i.items() if summary)\n ret = Message(\n content=\"\", instruct_content=Report(topic=topic, summaries=summaries), role=self.profile, cause_by=todo\n )\n else:\n summaries = instruct_content.summaries\n summary_text = \"\\n---\\n\".join(f\"url: {url}\\nsummary: {summary}\" for (url, summary) in summaries)\n content = await self.rc.todo.run(topic, summary_text, system_text=research_system_text)\n ret = Message(\n content=\"\",\n instruct_content=Report(topic=topic, content=content),\n role=self.profile,\n cause_by=self.rc.todo,\n )\n self.rc.memory.add(ret)\n return ret\n\n def research_system_text(self, topic, current_task: Action) -> str:\n \"\"\"BACKWARD compatible\n This allows sub-class able to define its own system prompt based on topic.\n return the previous implementation to have backward compatible\n Args:\n topic:\n language:\n\n Returns: str\n \"\"\"\n return get_research_system_text(topic, self.language)\n\n async def react(self) -> Message:\n msg = await super().react()\n report = msg.instruct_content\n self.write_report(report.topic, report.content)\n return msg\n\n def write_report(self, topic: str, content: str):\n filename = re.sub(r'[\\\\/:\"*?<>|]+', \" \", topic)\n filename = filename.replace(\"\\n\", \"\")\n if not RESEARCH_PATH.exists():\n RESEARCH_PATH.mkdir(parents=True)\n filepath = RESEARCH_PATH / f\"{filename}.md\"\n filepath.write_text(content)\n\n\nif __name__ == \"__main__\":\n import fire\n\n async def main(topic: str, language=\"en-us\"):\n role = Researcher(language=language)\n await role.run(topic)\n\n fire.Fire(main)\n\n```\n\n---\nTranslate the code above into Mermaid Sequence Diagram.": "```mermaid\nsequenceDiagram\n participant Role\n participant CollectLinks\n participant WebBrowseAndSummarize\n participant ConductResearch\n participant Message\n participant Report\n\n Role->>Role: Gather information and conduct research\n Role->>Role: Ensure accuracy and relevance of information\n Role->>Role: Set react mode to BY_ORDER\n\n Role->>Role: to do {todo}({todo.name})\n Role->>CollectLinks: run(topic, 4, 4)\n CollectLinks-->>Role: links\n Role->>Message: Report(topic, links)\n Role->>Role: Add message to memory\n\n Role->>WebBrowseAndSummarize: run(url, query, system_text)\n WebBrowseAndSummarize-->>Role: summaries\n Role->>Message: Report(topic, summaries)\n Role->>Role: Add message to memory\n\n Role->>ConductResearch: run(topic, summary_text, system_text)\n ConductResearch-->>Role: content\n Role->>Message: Report(topic, content)\n Role->>Role: Add message to memory\n\n Role->>Role: React\n Role->>Role: Write report to file\n```", + "You are a python code to Mermaid Sequence Diagram translator in function detail#SYSTEM_MSG_END#```python\n\"\"\"Code Docstring Generator.\n\nThis script provides a tool to automatically generate docstrings for Python code. It uses the specified style to create\ndocstrings for the given code and system text.\n\nUsage:\n python3 -m metagpt.actions.write_docstring [--overwrite] [--style=]\n\nArguments:\n filename The path to the Python file for which you want to generate docstrings.\n\nOptions:\n --overwrite If specified, overwrite the original file with the code containing docstrings.\n --style= Specify the style of the generated docstrings.\n Valid values: 'google', 'numpy', or 'sphinx'.\n Default: 'google'\n\nExample:\n python3 -m metagpt.actions.write_docstring ./metagpt/startup.py --overwrite False --style=numpy\n\nThis script uses the 'fire' library to create a command-line interface. It generates docstrings for the given Python code using\nthe specified docstring style and adds them to the code.\n\"\"\"\nfrom __future__ import annotations\n\nimport ast\nfrom pathlib import Path\nfrom typing import Literal, Optional\n\nfrom metagpt.actions.action import Action\nfrom metagpt.utils.common import OutputParser, aread, awrite\nfrom metagpt.utils.pycst import merge_docstring\n\nPYTHON_DOCSTRING_SYSTEM = \"\"\"### Requirements\n1. Add docstrings to the given code following the {style} style.\n2. Replace the function body with an Ellipsis object(...) to reduce output.\n3. If the types are already annotated, there is no need to include them in the docstring.\n4. Extract only class, function or the docstrings for the module parts from the given Python code, avoiding any other text.\n\n### Input Example\n```python\ndef function_with_pep484_type_annotations(param1: int) -> bool:\n return isinstance(param1, int)\n\nclass ExampleError(Exception):\n def __init__(self, msg: str):\n self.msg = msg\n```\n\n### Output Example\n```python\n{example}\n```\n\"\"\"\n\n# https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html\n\nPYTHON_DOCSTRING_EXAMPLE_GOOGLE = '''\ndef function_with_pep484_type_annotations(param1: int) -> bool:\n \"\"\"Example function with PEP 484 type annotations.\n\n Extended description of function.\n\n Args:\n param1: The first parameter.\n\n Returns:\n The return value. True for success, False otherwise.\n \"\"\"\n ...\n\nclass ExampleError(Exception):\n \"\"\"Exceptions are documented in the same way as classes.\n\n The __init__ method was documented in the class level docstring.\n\n Args:\n msg: Human readable string describing the exception.\n\n Attributes:\n msg: Human readable string describing the exception.\n \"\"\"\n ...\n'''\n\nPYTHON_DOCSTRING_EXAMPLE_NUMPY = '''\ndef function_with_pep484_type_annotations(param1: int) -> bool:\n \"\"\"\n Example function with PEP 484 type annotations.\n\n Extended description of function.\n\n Parameters\n ----------\n param1\n The first parameter.\n\n Returns\n -------\n bool\n The return value. True for success, False otherwise.\n \"\"\"\n ...\n\nclass ExampleError(Exception):\n \"\"\"\n Exceptions are documented in the same way as classes.\n\n The __init__ method was documented in the class level docstring.\n\n Parameters\n ----------\n msg\n Human readable string describing the exception.\n\n Attributes\n ----------\n msg\n Human readable string describing the exception.\n \"\"\"\n ...\n'''\n\nPYTHON_DOCSTRING_EXAMPLE_SPHINX = '''\ndef function_with_pep484_type_annotations(param1: int) -> bool:\n \"\"\"Example function with PEP 484 type annotations.\n\n Extended description of function.\n\n :param param1: The first parameter.\n :type param1: int\n\n :return: The return value. True for success, False otherwise.\n :rtype: bool\n \"\"\"\n ...\n\nclass ExampleError(Exception):\n \"\"\"Exceptions are documented in the same way as classes.\n\n The __init__ method was documented in the class level docstring.\n\n :param msg: Human-readable string describing the exception.\n :type msg: str\n \"\"\"\n ...\n'''\n\n_python_docstring_style = {\n \"google\": PYTHON_DOCSTRING_EXAMPLE_GOOGLE.strip(),\n \"numpy\": PYTHON_DOCSTRING_EXAMPLE_NUMPY.strip(),\n \"sphinx\": PYTHON_DOCSTRING_EXAMPLE_SPHINX.strip(),\n}\n\n\nclass WriteDocstring(Action):\n \"\"\"This class is used to write docstrings for code.\n\n Attributes:\n desc: A string describing the action.\n \"\"\"\n\n desc: str = \"Write docstring for code.\"\n i_context: Optional[str] = None\n\n async def run(\n self,\n code: str,\n system_text: str = PYTHON_DOCSTRING_SYSTEM,\n style: Literal[\"google\", \"numpy\", \"sphinx\"] = \"google\",\n ) -> str:\n \"\"\"Writes docstrings for the given code and system text in the specified style.\n\n Args:\n code: A string of Python code.\n system_text: A string of system text.\n style: A string specifying the style of the docstring. Can be 'google', 'numpy', or 'sphinx'.\n\n Returns:\n The Python code with docstrings added.\n \"\"\"\n system_text = system_text.format(style=style, example=_python_docstring_style[style])\n simplified_code = _simplify_python_code(code)\n documented_code = await self._aask(f\"```python\\n{simplified_code}\\n```\", [system_text])\n documented_code = OutputParser.parse_python_code(documented_code)\n return merge_docstring(code, documented_code)\n\n @staticmethod\n async def write_docstring(\n filename: str | Path, overwrite: bool = False, style: Literal[\"google\", \"numpy\", \"sphinx\"] = \"google\"\n ) -> str:\n data = await aread(str(filename))\n code = await WriteDocstring().run(data, style=style)\n if overwrite:\n await awrite(filename, code)\n return code\n\n\ndef _simplify_python_code(code: str) -> None:\n \"\"\"Simplifies the given Python code by removing expressions and the last if statement.\n\n Args:\n code: A string of Python code.\n\n Returns:\n The simplified Python code.\n \"\"\"\n code_tree = ast.parse(code)\n code_tree.body = [i for i in code_tree.body if not isinstance(i, ast.Expr)]\n if isinstance(code_tree.body[-1], ast.If):\n code_tree.body.pop()\n return ast.unparse(code_tree)\n\n\nif __name__ == \"__main__\":\n import fire\n\n fire.Fire(WriteDocstring.write_docstring)\n\n```\n\n---\nTranslate the code above into Mermaid Sequence Diagram.": "```mermaid\nsequenceDiagram\n participant User\n participant \"WriteDocstring\" as WD\n participant \"OutputParser\" as OP\n participant \"aread\" as AR\n participant \"awrite\" as AW\n\n User ->> WD: write_docstring(filename, overwrite, style)\n WD ->> AR: aread(filename)\n AR -->> WD: data\n WD ->> WD: run(data, style)\n WD ->> OP: parse_python_code(documented_code)\n OP -->> WD: documented_code\n WD ->> WD: merge_docstring(code, documented_code)\n WD ->> AW: awrite(filename, code)\n AW -->> WD: code\n WD -->> User: code\n```", + "\n## context\n\n### Project Name\n20240110221009\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\n20240110221525\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\n20240110221737\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\n20240110221737\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]" } \ No newline at end of file diff --git a/tests/metagpt/provider/test_openai.py b/tests/metagpt/provider/test_openai.py index ee69da861..ca9e918da 100644 --- a/tests/metagpt/provider/test_openai.py +++ b/tests/metagpt/provider/test_openai.py @@ -12,7 +12,7 @@ from tests.metagpt.provider.mock_llm_config import ( @pytest.mark.asyncio async def test_aask_code(): - llm = LLM(name="gpt3t") + llm = LLM() msg = [{"role": "user", "content": "Write a python hello world code."}] rsp = await llm.aask_code(msg) # -> {'language': 'python', 'code': "print('Hello, World!')"} @@ -24,7 +24,7 @@ async def test_aask_code(): @pytest.mark.asyncio async def test_aask_code_str(): - llm = LLM(name="gpt3t") + llm = LLM() msg = "Write a python hello world code." rsp = await llm.aask_code(msg) # -> {'language': 'python', 'code': "print('Hello, World!')"} assert "language" in rsp @@ -34,7 +34,7 @@ async def test_aask_code_str(): @pytest.mark.asyncio async def test_aask_code_message(): - llm = LLM(name="gpt3t") + llm = LLM() msg = UserMessage("Write a python hello world code.") rsp = await llm.aask_code(msg) # -> {'language': 'python', 'code': "print('Hello, World!')"} assert "language" in rsp diff --git a/tests/metagpt/test_config.py b/tests/metagpt/test_config.py index c804702dd..97d84ed09 100644 --- a/tests/metagpt/test_config.py +++ b/tests/metagpt/test_config.py @@ -10,7 +10,10 @@ from pydantic import BaseModel from metagpt.config2 import Config from metagpt.configs.llm_config import LLMType from metagpt.context import ContextMixin -from tests.metagpt.provider.mock_llm_config import mock_llm_config +from tests.metagpt.provider.mock_llm_config import ( + mock_llm_config, + mock_llm_config_proxy, +) def test_config_1(): @@ -21,9 +24,9 @@ def test_config_1(): def test_config_from_dict(): - cfg = Config(llm={"default": mock_llm_config}) + cfg = Config(llm=mock_llm_config) assert cfg - assert cfg.llm["default"].api_key == "mock_api_key" + assert cfg.llm.api_key == "mock_api_key" class ModelX(ContextMixin, BaseModel): @@ -47,11 +50,11 @@ def test_config_mixin_1(): def test_config_mixin_2(): - i = Config(llm={"default": mock_llm_config}) - j = Config(llm={"new": mock_llm_config}) + 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["default"] == mock_llm_config + assert obj._config.llm == mock_llm_config obj.set_config(j) # obj already has a config, so it will not be set @@ -60,16 +63,16 @@ def test_config_mixin_2(): def test_config_mixin_3(): """Test config mixin with multiple inheritance""" - i = Config(llm={"default": mock_llm_config}) - j = Config(llm={"new": mock_llm_config}) + 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["default"] == mock_llm_config + 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["default"] == mock_llm_config + assert obj._config.llm == mock_llm_config assert obj.a == "a" assert obj.b == "b" diff --git a/tests/metagpt/tools/test_search_engine.py b/tests/metagpt/tools/test_search_engine.py index 411929f64..1cdecb3e9 100644 --- a/tests/metagpt/tools/test_search_engine.py +++ b/tests/metagpt/tools/test_search_engine.py @@ -49,13 +49,14 @@ class MockSearchEnine: async def test_search_engine(search_engine_type, run_func: Callable, max_results: int, as_string: bool, aiohttp_mocker): # Prerequisites cache_json_path = None + # FIXME: 不能使用全局的config,而是要自己实例化对应的config if search_engine_type is SearchEngineType.SERPAPI_GOOGLE: - assert config.search["serpapi"] + assert config.search cache_json_path = search_cache_path / f"serpapi-metagpt-{max_results}.json" elif search_engine_type is SearchEngineType.DIRECT_GOOGLE: - assert config.search["google"] + assert config.search elif search_engine_type is SearchEngineType.SERPER_GOOGLE: - assert config.search["serper"] + assert config.search cache_json_path = search_cache_path / f"serper-metagpt-{max_results}.json" if cache_json_path: