-Assign different roles to GPTs to form a collaborative software entity for complex tasks.
+Assign different roles to GPTs to form a collaborative entity for complex tasks.
-
+
@@ -25,48 +25,51 @@ # MetaGPT: The Multi-Agent Framework
+## News
+🚀 Jan. 16, 2024: Our paper [MetaGPT: Meta Programming for A Multi-Agent Collaborative Framework
+](https://arxiv.org/abs/2308.00352) accepted for oral presentation **(top 1.2%)** at ICLR 2024, **ranking #1** in the LLM-based Agent category.
+
+🚀 Jan. 03, 2024: [v0.6.0](https://github.com/geekan/MetaGPT/releases/tag/v0.6.0) released, new features include serialization, upgraded OpenAI package and supported multiple LLM, provided [minimal example for debate](https://github.com/geekan/MetaGPT/blob/main/examples/debate_simple.py) etc.
+
+🚀 Dec. 15, 2023: [v0.5.0](https://github.com/geekan/MetaGPT/releases/tag/v0.5.0) released, introducing some experimental features such as **incremental development**, **multilingual**, **multiple programming languages**, etc.
+
+🔥 Nov. 08, 2023: MetaGPT is selected into [Open100: Top 100 Open Source achievements](https://www.benchcouncil.org/evaluation/opencs/annual.html).
+
+🔥 Sep. 01, 2023: MetaGPT tops GitHub Trending Monthly for the **17th time** in August 2023.
+
+🌟 Jun. 30, 2023: MetaGPT is now open source.
+
+🌟 Apr. 24, 2023: First line of MetaGPT code committed.
+
+## Software Company as Multi-Agent System
+
1. MetaGPT takes a **one line requirement** as input and outputs **user stories / competitive analysis / requirements / data structures / APIs / documents, etc.**
2. Internally, MetaGPT includes **product managers / architects / project managers / engineers.** It provides the entire process of a **software company along with carefully orchestrated SOPs.**
1. `Code = SOP(Team)` is the core philosophy. We materialize SOP and apply it to teams composed of LLMs.

-
Software Company Multi-Role Schematic (Gradually Implementing)
-
-## News
-🚀 Jan 03: Here comes [v0.6.0](https://github.com/geekan/MetaGPT/releases/tag/v0.6.0)! In this version, we added serialization and deserialization of important objects and enabled breakpoint recovery. We upgraded OpenAI package to v1.6.0 and supported Gemini, ZhipuAI, Ollama, OpenLLM, etc. Moreover, we provided extremely simple examples where you need only 7 lines to implement a general election [debate](https://github.com/geekan/MetaGPT/blob/main/examples/debate_simple.py). Check out more details [here](https://github.com/geekan/MetaGPT/releases/tag/v0.6.0)!
-
-
-🚀 Dec 15: [v0.5.0](https://github.com/geekan/MetaGPT/releases/tag/v0.5.0) is released! We introduced **incremental development**, facilitating agents to build up larger projects on top of their previous efforts or existing codebase. We also launched a whole collection of important features, including **multilingual support** (experimental), multiple **programming languages support** (experimental), **incremental development** (experimental), CLI support, pip support, enhanced code review, documentation mechanism, and optimized messaging mechanism!
+
Software Company Multi-Agent Schematic (Gradually Implementing)
## Install
### Pip installation
+> Ensure that Python 3.9+ is installed on your system. You can check this by using: `python --version`.
+> You can use conda like this: `conda create -n metagpt python=3.9 && conda activate metagpt`
+
```bash
-# Step 1: Ensure that Python 3.9+ is installed on your system. You can check this by using:
-# You can use conda to initialize a new python env
-# conda create -n metagpt python=3.9
-# conda activate metagpt
-python3 --version
+pip install metagpt
+metagpt --init-config # create ~/.metagpt/config2.yaml, modify it to your own config
+metagpt "Create a 2048 game" # this will create a repo in ./workspace
+```
-# Step 2: Clone the repository to your local machine for latest version, and install it.
-git clone https://github.com/geekan/MetaGPT.git
-cd MetaGPT
-pip3 install -e . # or pip3 install metagpt # for stable version
+or you can use it as library
-# Step 3: setup your OPENAI_API_KEY, or make sure it existed in the env
-mkdir ~/.metagpt
-cp config/config.yaml ~/.metagpt/config.yaml
-vim ~/.metagpt/config.yaml
-
-# Step 4: run metagpt cli
-metagpt "Create a 2048 game in python"
-
-# Step 5 [Optional]: If you want to save the artifacts like diagrams such as quadrant chart, system designs, sequence flow in the workspace, you can execute the step before Step 3. By default, the framework is compatible, and the entire process can be run completely without executing this step.
-# If executing, ensure that NPM is installed on your system. Then install mermaid-js. (If you don't have npm in your computer, please go to the Node.js official website to install Node.js https://nodejs.org/ and then you will have npm tool in your computer.)
-npm --version
-sudo npm install -g @mermaid-js/mermaid-cli
+```python
+from metagpt.software_company import generate_repo, ProjectRepo
+repo: ProjectRepo = generate_repo("Create a 2048 game") # or ProjectRepo("")
+print(repo) # it will print the repo structure with files
```
detail installation please refer to [cli_install](https://docs.deepwisdom.ai/main/en/guide/get_started/installation.html#install-stable-version)
@@ -75,19 +78,19 @@ ### Docker installation
> Note: In the Windows, you need to replace "/opt/metagpt" with a directory that Docker has permission to create, such as "D:\Users\x\metagpt"
```bash
-# Step 1: Download metagpt official image and prepare config.yaml
+# Step 1: Download metagpt official image and prepare config2.yaml
docker pull metagpt/metagpt:latest
mkdir -p /opt/metagpt/{config,workspace}
-docker run --rm metagpt/metagpt:latest cat /app/metagpt/config/config.yaml > /opt/metagpt/config/key.yaml
-vim /opt/metagpt/config/key.yaml # Change the config
+docker run --rm metagpt/metagpt:latest cat /app/metagpt/config/config2.yaml > /opt/metagpt/config/config2.yaml
+vim /opt/metagpt/config/config2.yaml # Change the config
# Step 2: Run metagpt demo with container
docker run --rm \
--privileged \
- -v /opt/metagpt/config/key.yaml:/app/metagpt/config/key.yaml \
+ -v /opt/metagpt/config/config2.yaml:/app/metagpt/config/config2.yaml \
-v /opt/metagpt/workspace:/app/metagpt/workspace \
metagpt/metagpt:latest \
- metagpt "Write a cli snake game"
+ metagpt "Create a 2048 game"
```
detail installation please refer to [docker_install](https://docs.deepwisdom.ai/main/en/guide/get_started/installation.html#install-with-docker)
diff --git a/config/config2.yaml b/config/config2.yaml
index 5e7f34809..2c4ca636f 100644
--- a/config/config2.yaml
+++ b/config/config2.yaml
@@ -1,3 +1,3 @@
llm:
api_key: "YOUR_API_KEY"
- model: "gpt-3.5-turbo-1106"
\ No newline at end of file
+ model: "gpt-4-turbo-preview" # or gpt-3.5-turbo-1106 / gpt-4-1106-preview
\ No newline at end of file
diff --git a/config/config2.yaml.example b/config/config2.yaml.example
index 35575e5a5..2217f1b2c 100644
--- a/config/config2.yaml.example
+++ b/config/config2.yaml.example
@@ -1,8 +1,8 @@
llm:
- api_type: "openai"
+ api_type: "openai" # or azure / ollama etc.
base_url: "YOUR_BASE_URL"
api_key: "YOUR_API_KEY"
- model: "gpt-3.5-turbo-1106" # or gpt-4-1106-preview
+ model: "gpt-4-turbo-preview" # or gpt-3.5-turbo-1106 / gpt-4-1106-preview
proxy: "YOUR_PROXY"
@@ -11,6 +11,10 @@ search:
api_key: "YOUR_API_KEY"
cse_id: "YOUR_CSE_ID"
+browser:
+ engine: "playwright" # playwright/selenium
+ browser_type: "chromium" # playwright: chromium/firefox/webkit; selenium: chrome/firefox/edge/ie
+
mermaid:
engine: "pyppeteer"
path: "/Applications/Google Chrome.app"
@@ -29,14 +33,13 @@ s3:
bucket: "test"
-AZURE_TTS_SUBSCRIPTION_KEY: "YOUR_SUBSCRIPTION_KEY"
-AZURE_TTS_REGION: "eastus"
+azure_tts_subscription_key: "YOUR_SUBSCRIPTION_KEY"
+azure_tts_region: "eastus"
-IFLYTEK_APP_ID: "YOUR_APP_ID"
-IFLYTEK_API_KEY: "YOUR_API_KEY"
-IFLYTEK_API_SECRET: "YOUR_API_SECRET"
+iflytek_api_id: "YOUR_APP_ID"
+iflytek_api_key: "YOUR_API_KEY"
+iflytek_api_secret: "YOUR_API_SECRET"
-METAGPT_TEXT_TO_IMAGE_MODEL_URL: "YOUR_MODEL_URL"
-
-PYPPETEER_EXECUTABLE_PATH: "/Applications/Google Chrome.app"
+metagpt_tti_url: "YOUR_MODEL_URL"
+repair_llm_output: true
diff --git a/docs/.well-known/metagpt_oas3_api.yaml b/docs/.well-known/metagpt_oas3_api.yaml
index 0a702e8b6..1f370b62d 100644
--- a/docs/.well-known/metagpt_oas3_api.yaml
+++ b/docs/.well-known/metagpt_oas3_api.yaml
@@ -14,16 +14,16 @@ paths:
/tts/azsure:
x-prerequisite:
configurations:
- AZURE_TTS_SUBSCRIPTION_KEY:
+ azure_tts_subscription_key:
type: string
description: "For more details, check out: [Azure Text-to_Speech](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts)"
- AZURE_TTS_REGION:
+ azure_tts_region:
type: string
description: "For more details, check out: [Azure Text-to_Speech](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts)"
required:
allOf:
- - AZURE_TTS_SUBSCRIPTION_KEY
- - AZURE_TTS_REGION
+ - azure_tts_subscription_key
+ - azure_tts_region
post:
summary: "Convert Text to Base64-encoded .wav File Stream"
description: "For more details, check out: [Azure Text-to_Speech](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts)"
@@ -94,9 +94,9 @@ paths:
description: "WebAPI argument, see: `https://console.xfyun.cn/services/tts`"
required:
allOf:
- - IFLYTEK_APP_ID
- - IFLYTEK_API_KEY
- - IFLYTEK_API_SECRET
+ - iflytek_app_id
+ - iflytek_api_key
+ - iflytek_api_secret
post:
summary: "Convert Text to Base64-encoded .mp3 File Stream"
description: "For more details, check out: [iFlyTek](https://console.xfyun.cn/services/tts)"
@@ -242,12 +242,12 @@ paths:
/txt2image/metagpt:
x-prerequisite:
configurations:
- METAGPT_TEXT_TO_IMAGE_MODEL_URL:
+ metagpt_tti_url:
type: string
description: "Model url."
required:
allOf:
- - METAGPT_TEXT_TO_IMAGE_MODEL_URL
+ - metagpt_tti_url
post:
summary: "Text to Image"
description: "Generate an image from the provided text using the MetaGPT Text-to-Image API."
diff --git a/docs/.well-known/skills.yaml b/docs/.well-known/skills.yaml
index c19a9501e..30c215445 100644
--- a/docs/.well-known/skills.yaml
+++ b/docs/.well-known/skills.yaml
@@ -14,10 +14,10 @@ entities:
id: text_to_speech.text_to_speech
x-prerequisite:
configurations:
- AZURE_TTS_SUBSCRIPTION_KEY:
+ azure_tts_subscription_key:
type: string
description: "For more details, check out: [Azure Text-to_Speech](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts)"
- AZURE_TTS_REGION:
+ azure_tts_region:
type: string
description: "For more details, check out: [Azure Text-to_Speech](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts)"
IFLYTEK_APP_ID:
@@ -32,12 +32,12 @@ entities:
required:
oneOf:
- allOf:
- - AZURE_TTS_SUBSCRIPTION_KEY
- - AZURE_TTS_REGION
+ - azure_tts_subscription_key
+ - azure_tts_region
- allOf:
- - IFLYTEK_APP_ID
- - IFLYTEK_API_KEY
- - IFLYTEK_API_SECRET
+ - iflytek_app_id
+ - iflytek_api_key
+ - iflytek_api_secret
parameters:
text:
description: 'The text used for voice conversion.'
@@ -103,13 +103,13 @@ entities:
OPENAI_API_KEY:
type: string
description: "OpenAI API key, For more details, checkout: `https://platform.openai.com/account/api-keys`"
- METAGPT_TEXT_TO_IMAGE_MODEL_URL:
+ metagpt_tti_url:
type: string
description: "Model url."
required:
oneOf:
- OPENAI_API_KEY
- - METAGPT_TEXT_TO_IMAGE_MODEL_URL
+ - metagpt_tti_url
parameters:
text:
description: 'The text used for image conversion.'
diff --git a/docs/FAQ-EN.md b/docs/FAQ-EN.md
index d4a9f6097..d3caa244e 100644
--- a/docs/FAQ-EN.md
+++ b/docs/FAQ-EN.md
@@ -1,183 +1,93 @@
Our vision is to [extend human life](https://github.com/geekan/HowToLiveLonger) and [reduce working hours](https://github.com/geekan/MetaGPT/).
-1. ### Convenient Link for Sharing this Document:
+### Convenient Link for Sharing this Document:
```
-- MetaGPT-Index/FAQ https://deepwisdom.feishu.cn/wiki/MsGnwQBjiif9c3koSJNcYaoSnu4
+- MetaGPT-Index/FAQ-EN https://github.com/geekan/MetaGPT/blob/main/docs/FAQ-EN.md
+- MetaGPT-Index/FAQ-CN https://deepwisdom.feishu.cn/wiki/MsGnwQBjiif9c3koSJNcYaoSnu4
```
-2. ### Link
-
-
+### Link
1. Code:https://github.com/geekan/MetaGPT
-
-1. Roadmap:https://github.com/geekan/MetaGPT/blob/main/docs/ROADMAP.md
-
-1. EN
-
- 1. Demo Video: [MetaGPT: Multi-Agent AI Programming Framework](https://www.youtube.com/watch?v=8RNzxZBTW8M)
+2. Roadmap:https://github.com/geekan/MetaGPT/blob/main/docs/ROADMAP.md
+3. EN
+ 1. Demo Video: [MetaGPT: Multi-Agent AI Programming Framework](https://www.youtube.com/watch?v=8RNzxZBTW8M)
2. Tutorial: [MetaGPT: Deploy POWERFUL Autonomous Ai Agents BETTER Than SUPERAGI!](https://www.youtube.com/watch?v=q16Gi9pTG_M&t=659s)
3. Author's thoughts video(EN): [MetaGPT Matthew Berman](https://youtu.be/uT75J_KG_aY?si=EgbfQNAwD8F5Y1Ak)
+4. CN
+ 1. Demo Video: [MetaGPT:一行代码搭建你的虚拟公司_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1NP411C7GW/?spm_id_from=333.999.0.0&vd_source=735773c218b47da1b4bd1b98a33c5c77)
+ 1. Tutorial: [一个提示词写游戏 Flappy bird, 比AutoGPT强10倍的MetaGPT,最接近AGI的AI项目](https://youtu.be/Bp95b8yIH5c)
+ 2. Author's thoughts video(CN): [MetaGPT作者深度解析直播回放_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1Ru411V7XL/?spm_id_from=333.337.search-card.all.click)
-1. CN
-
- 1. Demo Video: [MetaGPT:一行代码搭建你的虚拟公司_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1NP411C7GW/?spm_id_from=333.999.0.0&vd_source=735773c218b47da1b4bd1b98a33c5c77)
- 1. Tutorial: [一个提示词写游戏 Flappy bird, 比AutoGPT强10倍的MetaGPT,最接近AGI的AI项目](https://youtu.be/Bp95b8yIH5c)
- 2. Author's thoughts video(CN): [MetaGPT作者深度解析直播回放_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1Ru411V7XL/?spm_id_from=333.337.search-card.all.click)
-
-
-
-3. ### How to become a contributor?
-
-
+### How to become a contributor?
1. Choose a task from the Roadmap (or you can propose one). By submitting a PR, you can become a contributor and join the dev team.
-1. Current contributors come from backgrounds including ByteDance AI Lab/DingDong/Didi/Xiaohongshu, Tencent/Baidu/MSRA/TikTok/BloomGPT Infra/Bilibili/CUHK/HKUST/CMU/UCB
+2. Current contributors come from backgrounds including ByteDance AI Lab/DingDong/Didi/Xiaohongshu, Tencent/Baidu/MSRA/TikTok/BloomGPT Infra/Bilibili/CUHK/HKUST/CMU/UCB
-
-
-4. ### Chief Evangelist (Monthly Rotation)
+### Chief Evangelist (Monthly Rotation)
MetaGPT Community - The position of Chief Evangelist rotates on a monthly basis. The primary responsibilities include:
1. Maintaining community FAQ documents, announcements, and Github resources/READMEs.
-1. Responding to, answering, and distributing community questions within an average of 30 minutes, including on platforms like Github Issues, Discord and WeChat.
-1. Upholding a community atmosphere that is enthusiastic, genuine, and friendly.
-1. Encouraging everyone to become contributors and participate in projects that are closely related to achieving AGI (Artificial General Intelligence).
-1. (Optional) Organizing small-scale events, such as hackathons.
+2. Responding to, answering, and distributing community questions within an average of 30 minutes, including on platforms like Github Issues, Discord and WeChat.
+3. Upholding a community atmosphere that is enthusiastic, genuine, and friendly.
+4. Encouraging everyone to become contributors and participate in projects that are closely related to achieving AGI (Artificial General Intelligence).
+5. (Optional) Organizing small-scale events, such as hackathons.
-
-
-5. ### FAQ
-
-
-
-1. Experience with the generated repo code:
-
- 1. https://github.com/geekan/MetaGPT/releases/tag/v0.1.0
+### FAQ
1. Code truncation/ Parsing failure:
-
- 1. Check if it's due to exceeding length. Consider using the gpt-3.5-turbo-16k or other long token versions.
-
-1. Success rate:
-
- 1. There hasn't been a quantitative analysis yet, but the success rate of code generated by GPT-4 is significantly higher than that of gpt-3.5-turbo.
-
-1. Support for incremental, differential updates (if you wish to continue a half-done task):
-
- 1. Several prerequisite tasks are listed on the ROADMAP.
-
-1. Can existing code be loaded?
-
- 1. It's not on the ROADMAP yet, but there are plans in place. It just requires some time.
-
-1. Support for multiple programming languages and natural languages?
-
- 1. It's listed on ROADMAP.
-
-1. Want to join the contributor team? How to proceed?
-
+ 1. Check if it's due to exceeding length. Consider using the gpt-4-turbo-preview or other long token versions.
+2. Success rate:
+ 1. There hasn't been a quantitative analysis yet, but the success rate of code generated by gpt-4-turbo-preview is significantly higher than that of gpt-3.5-turbo.
+3. Support for incremental, differential updates (if you wish to continue a half-done task):
+ 1. There is now an experimental version. Specify `--inc --project-path ""` or `--inc --project-name ""` on the command line and enter the corresponding requirements to try it.
+4. Can existing code be loaded?
+ 1. We are doing this, but it is very difficult, especially when the project is large, it is very difficult to achieve a high success rate.
+5. Support for multiple programming languages and natural languages?
+ 1. It is now supported, but it is still in experimental version
+6. Want to join the contributor team? How to proceed?
1. Merging a PR will get you into the contributor's team. The main ongoing tasks are all listed on the ROADMAP.
-
-1. PRD stuck / unable to access/ connection interrupted
-
- 1. The official OPENAI_BASE_URL address is `https://api.openai.com/v1`
- 1. If the official OPENAI_BASE_URL address is inaccessible in your environment (this can be verified with curl), it's recommended to configure using the reverse proxy OPENAI_BASE_URL provided by libraries such as openai-forward. For instance, `OPENAI_BASE_URL: "``https://api.openai-forward.com/v1``"`
- 1. If the official OPENAI_BASE_URL address is inaccessible in your environment (again, verifiable via curl), another option is to configure the OPENAI_PROXY parameter. This way, you can access the official OPENAI_BASE_URL via a local proxy. If you don't need to access via a proxy, please do not enable this configuration; if accessing through a proxy is required, modify it to the correct proxy address. Note that when OPENAI_PROXY is enabled, don't set OPENAI_BASE_URL.
- 1. Note: OpenAI's default API design ends with a v1. An example of the correct configuration is: `OPENAI_BASE_URL: "``https://api.openai.com/v1``"`
-
-1. Absolutely! How can I assist you today?
-
+7. PRD stuck / unable to access/ connection interrupted
+ 1. The official openai base_url address is `https://api.openai.com/v1`
+ 2. If the official openai base_url address is inaccessible in your environment (this can be verified with curl), it's recommended to configure using base_url to other "reverse-proxy" provider such as openai-forward. For instance, `openai base_url: "``https://api.openai-forward.com/v1``"`
+ 3. If the official openai base_url address is inaccessible in your environment (again, verifiable via curl), another option is to configure the llm.proxy in the `config2.yaml`. This way, you can access the official openai base_url via a local proxy. If you don't need to access via a proxy, please do not enable this configuration; if accessing through a proxy is required, modify it to the correct proxy address.
+ 4. Note: OpenAI's default API design ends with a v1. An example of the correct configuration is: `base_url: "https://api.openai.com/v1"
+8. Get reply: "Absolutely! How can I assist you today?"
1. Did you use Chi or a similar service? These services are prone to errors, and it seems that the error rate is higher when consuming 3.5k-4k tokens in GPT-4
-
-1. What does Max token mean?
-
+9. What does Max token mean?
1. It's a configuration for OpenAI's maximum response length. If the response exceeds the max token, it will be truncated.
-
-1. How to change the investment amount?
-
+10. How to change the investment amount?
1. You can view all commands by typing `metagpt --help`
-
-1. Which version of Python is more stable?
-
+11. Which version of Python is more stable?
1. python3.9 / python3.10
-
-1. Can't use GPT-4, getting the error "The model gpt-4 does not exist."
-
+12. Can't use GPT-4, getting the error "The model gpt-4 does not exist."
1. OpenAI's official requirement: You can use GPT-4 only after spending $1 on OpenAI.
1. Tip: Run some data with gpt-3.5-turbo (consume the free quota and $1), and then you should be able to use gpt-4.
-
-1. Can games whose code has never been seen before be written?
-
+13. Can games whose code has never been seen before be written?
1. Refer to the README. The recommendation system of Toutiao is one of the most complex systems in the world currently. Although it's not on GitHub, many discussions about it exist online. If it can visualize these, it suggests it can also summarize these discussions and convert them into code. The prompt would be something like "write a recommendation system similar to Toutiao". Note: this was approached in earlier versions of the software. The SOP of those versions was different; the current one adopts Elon Musk's five-step work method, emphasizing trimming down requirements as much as possible.
-
-1. Under what circumstances would there typically be errors?
-
+14. Under what circumstances would there typically be errors?
1. More than 500 lines of code: some function implementations may be left blank.
- 1. When using a database, it often gets the implementation wrong — since the SQL database initialization process is usually not in the code.
- 1. With more lines of code, there's a higher chance of false impressions, leading to calls to non-existent APIs.
-
-1. Instructions for using SD Skills/UI Role:
-
- 1. Currently, there is a test script located in /tests/metagpt/roles. The file ui_role provides the corresponding code implementation. For testing, you can refer to the test_ui in the same directory.
-
- 1. The UI role takes over from the product manager role, extending the output from the 【UI Design draft】 provided by the product manager role. The UI role has implemented the UIDesign Action. Within the run of UIDesign, it processes the respective context, and based on the set template, outputs the UI. The output from the UI role includes:
-
- 1. UI Design Description: Describes the content to be designed and the design objectives.
- 1. Selected Elements: Describes the elements in the design that need to be illustrated.
- 1. HTML Layout: Outputs the HTML code for the page.
- 1. CSS Styles (styles.css): Outputs the CSS code for the page.
-
- 1. Currently, the SD skill is a tool invoked by UIDesign. It instantiates the SDEngine, with specific code found in metagpt/tools/sd_engine.
-
- 1. Configuration instructions for SD Skills: The SD interface is currently deployed based on *https://github.com/AUTOMATIC1111/stable-diffusion-webui* **For environmental configurations and model downloads, please refer to the aforementioned GitHub repository. To initiate the SD service that supports API calls, run the command specified in cmd with the parameter nowebui, i.e.,
-
- 1. > python3 webui.py --enable-insecure-extension-access --port xxx --no-gradio-queue --nowebui
- 1. Once it runs without errors, the interface will be accessible after approximately 1 minute when the model finishes loading.
- 1. Configure SD_URL and SD_T2I_API in the config.yaml/key.yaml files.
- 1. 
- 1. SD_URL is the deployed server/machine IP, and Port is the specified port above, defaulting to 7860.
- 1. > SD_URL: IP:Port
-
-1. An error occurred during installation: "Another program is using this file...egg".
-
+ 2. When using a database, it often gets the implementation wrong — since the SQL database initialization process is usually not in the code.
+ 3. With more lines of code, there's a higher chance of false impressions, leading to calls to non-existent APIs.
+15. An error occurred during installation: "Another program is using this file...egg".
1. Delete the file and try again.
- 1. Or manually execute`pip install -r requirements.txt`
-
-1. The origin of the name MetaGPT?
-
+ 2. Or manually execute`pip install -r requirements.txt`
+16. The origin of the name MetaGPT?
1. The name was derived after iterating with GPT-4 over a dozen rounds. GPT-4 scored and suggested it.
-
-1. Is there a more step-by-step installation tutorial?
-
- 1. Youtube(CN):[一个提示词写游戏 Flappy bird, 比AutoGPT强10倍的MetaGPT,最接近AGI的AI项目=一个软件公司产品经理+程序员](https://youtu.be/Bp95b8yIH5c)
- 1. Youtube(EN)https://www.youtube.com/watch?v=q16Gi9pTG_M&t=659s
- 2. video(EN): [MetaGPT Matthew Berman](https://youtu.be/uT75J_KG_aY?si=EgbfQNAwD8F5Y1Ak)
-
-1. openai.error.RateLimitError: You exceeded your current quota, please check your plan and billing details
-
+17. openai.error.RateLimitError: You exceeded your current quota, please check your plan and billing details
1. If you haven't exhausted your free quota, set RPM to 3 or lower in the settings.
- 1. If your free quota is used up, consider adding funds to your account.
-
-1. What does "borg" mean in n_borg?
-
+ 2. If your free quota is used up, consider adding funds to your account.
+18. What does "borg" mean in n_borg?
1. [Wikipedia borg meaning ](https://en.wikipedia.org/wiki/Borg)
- 1. The Borg civilization operates based on a hive or collective mentality, known as "the Collective." Every Borg individual is connected to the collective via a sophisticated subspace network, ensuring continuous oversight and guidance for every member. This collective consciousness allows them to not only "share the same thoughts" but also to adapt swiftly to new strategies. While individual members of the collective rarely communicate, the collective "voice" sometimes transmits aboard ships.
-
-1. How to use the Claude API?
-
+ 2. The Borg civilization operates based on a hive or collective mentality, known as "the Collective." Every Borg individual is connected to the collective via a sophisticated subspace network, ensuring continuous oversight and guidance for every member. This collective consciousness allows them to not only "share the same thoughts" but also to adapt swiftly to new strategies. While individual members of the collective rarely communicate, the collective "voice" sometimes transmits aboard ships.
+19. How to use the Claude API?
1. The full implementation of the Claude API is not provided in the current code.
1. You can use the Claude API through third-party API conversion projects like: https://github.com/jtsang4/claude-to-chatgpt
-
-1. Is Llama2 supported?
-
+20. Is Llama2 supported?
1. On the day Llama2 was released, some of the community members began experiments and found that output can be generated based on MetaGPT's structure. However, Llama2's context is too short to generate a complete project. Before regularly using Llama2, it's necessary to expand the context window to at least 8k. If anyone has good recommendations for expansion models or methods, please leave a comment.
-
-1. `mermaid-cli getElementsByTagName SyntaxError: Unexpected token '.'`
-
+21. `mermaid-cli getElementsByTagName SyntaxError: Unexpected token '.'`
1. Upgrade node to version 14.x or above:
-
1. `npm install -g n`
- 1. `n stable` to install the stable version of node(v18.x)
+ 2. `n stable` to install the stable version of node(v18.x)
diff --git a/docs/README_CN.md b/docs/README_CN.md
index 2855b5500..7a0db4974 100644
--- a/docs/README_CN.md
+++ b/docs/README_CN.md
@@ -35,50 +35,45 @@ # MetaGPT: 多智能体框架
## 安装
### Pip安装
+> 确保您的系统已安装 Python 3.9 或更高版本。您可以使用以下命令来检查:`python --version`。
+> 您可以这样使用 conda:`conda create -n metagpt python=3.9 && conda activate metagpt`
+
```bash
-# 第 1 步:确保您的系统上安装了 Python 3.9+。您可以使用以下命令进行检查:
-# 可以使用conda来初始化新的python环境
-# conda create -n metagpt python=3.9
-# conda activate metagpt
-python3 --version
-
-# 第 2 步:克隆最新仓库到您的本地机器,并进行安装。
-git clone https://github.com/geekan/MetaGPT.git
-cd MetaGPT
-pip3 install -e. # 或者 pip3 install metagpt # 安装稳定版本
-
-# 第 3 步:执行metagpt
-# 拷贝config.yaml为key.yaml,并设置你自己的OPENAI_API_KEY
-metagpt "Write a cli snake game"
-
-# 第 4 步【可选的】:如果你想在执行过程中保存像象限图、系统设计、序列流程等图表这些产物,可以在第3步前执行该步骤。默认的,框架做了兼容,在不执行该步的情况下,也可以完整跑完整个流程。
-# 如果执行,确保您的系统上安装了 NPM。并使用npm安装mermaid-js
-npm --version
-sudo npm install -g @mermaid-js/mermaid-cli
+pip install metagpt
+metagpt --init-config # 创建 ~/.metagpt/config2.yaml,根据您的需求修改它
+metagpt "创建一个 2048 游戏" # 这将在 ./workspace 创建一个仓库
```
-详细的安装请安装 [cli_install](https://docs.deepwisdom.ai/guide/get_started/installation.html#install-stable-version)
+或者您可以将其作为库使用
+
+```python
+from metagpt.software_company import generate_repo, ProjectRepo
+repo: ProjectRepo = generate_repo("创建一个 2048 游戏") # 或 ProjectRepo("<路径>")
+print(repo) # 它将打印出仓库结构及其文件
+```
+
+详细的安装请参考 [cli_install](https://docs.deepwisdom.ai/guide/get_started/installation.html#install-stable-version)
### Docker安装
> 注意:在Windows中,你需要将 "/opt/metagpt" 替换为Docker具有创建权限的目录,比如"D:\Users\x\metagpt"
```bash
-# 步骤1: 下载metagpt官方镜像并准备好config.yaml
+# 步骤1: 下载metagpt官方镜像并准备好config2.yaml
docker pull metagpt/metagpt:latest
mkdir -p /opt/metagpt/{config,workspace}
-docker run --rm metagpt/metagpt:latest cat /app/metagpt/config/config.yaml > /opt/metagpt/config/key.yaml
-vim /opt/metagpt/config/key.yaml # 修改配置文件
+docker run --rm metagpt/metagpt:latest cat /app/metagpt/config/config2.yaml > /opt/metagpt/config/config2.yaml
+vim /opt/metagpt/config/config2.yaml # 修改配置文件
# 步骤2: 使用容器运行metagpt演示
docker run --rm \
--privileged \
- -v /opt/metagpt/config/key.yaml:/app/metagpt/config/key.yaml \
+ -v /opt/metagpt/config/config2.yaml:/app/metagpt/config/config2.yaml \
-v /opt/metagpt/workspace:/app/metagpt/workspace \
metagpt/metagpt:latest \
metagpt "Write a cli snake game"
```
-详细的安装请安装 [docker_install](https://docs.deepwisdom.ai/main/zh/guide/get_started/installation.html#%E4%BD%BF%E7%94%A8docker%E5%AE%89%E8%A3%85)
+详细的安装请参考 [docker_install](https://docs.deepwisdom.ai/main/zh/guide/get_started/installation.html#%E4%BD%BF%E7%94%A8docker%E5%AE%89%E8%A3%85)
### 快速开始的演示视频
- 在 [MetaGPT Huggingface Space](https://huggingface.co/spaces/deepwisdom/MetaGPT) 上进行体验
diff --git a/docs/README_JA.md b/docs/README_JA.md
index 8b2bf1fae..c6b99461c 100644
--- a/docs/README_JA.md
+++ b/docs/README_JA.md
@@ -57,24 +57,21 @@ ### インストールビデオガイド
- [Matthew Berman: How To Install MetaGPT - Build A Startup With One Prompt!!](https://youtu.be/uT75J_KG_aY)
### 伝統的なインストール
+> Python 3.9 以上がシステムにインストールされていることを確認してください。これは `python --version` を使ってチェックできます。
+> 以下のようにcondaを使うことができます:`conda create -n metagpt python=3.9 && conda activate metagpt`
```bash
-# ステップ 1: Python 3.9+ がシステムにインストールされていることを確認してください。これを確認するには:
-python3 --version
+pip install metagpt
+metagpt --init-config # ~/.metagpt/config2.yaml を作成し、自分の設定に合わせて変更してください
+metagpt "2048ゲームを作成する" # これにより ./workspace にリポジトリが作成されます
+```
-# ステップ 2: リポジトリをローカルマシンにクローンし、インストールする。
-git clone https://github.com/geekan/MetaGPT.git
-cd MetaGPT
-pip install -e.
+または、ライブラリとして使用することもできます
-# ステップ 3: metagpt を実行する
-# config.yaml を key.yaml にコピーし、独自の OPENAI_API_KEY を設定します
-metagpt "Write a cli snake game"
-
-# ステップ 4 [オプション]: 実行中に PRD ファイルなどのアーティファクトを保存する場合は、ステップ 3 の前にこのステップを実行できます。デフォルトでは、フレームワークには互換性があり、この手順を実行しなくてもプロセス全体を完了できます。
-# NPM がシステムにインストールされていることを確認してください。次に mermaid-js をインストールします。(お使いのコンピューターに npm がない場合は、Node.js 公式サイトで Node.js https://nodejs.org/ をインストールしてください。)
-npm --version
-sudo npm install -g @mermaid-js/mermaid-cli
+```python
+from metagpt.software_company import generate_repo, ProjectRepo
+repo: ProjectRepo = generate_repo("2048ゲームを作成する") # または ProjectRepo("<パス>")
+print(repo) # リポジトリの構造とファイルを出力します
```
**注:**
@@ -91,8 +88,8 @@ # NPM がシステムにインストールされていることを確認して
- config.yml に mmdc のコンフィグを記述するのを忘れないこと
```yml
- PUPPETEER_CONFIG: "./config/puppeteer-config.json"
- MMDC: "./node_modules/.bin/mmdc"
+ puppeteer_config: "./config/puppeteer-config.json"
+ path: "./node_modules/.bin/mmdc"
```
- もし `pip install -e.` がエラー `[Errno 13] Permission denied: '/usr/local/lib/python3.11/dist-packages/test-easy-install-13129.write-test'` で失敗したら、代わりに `pip install -e. --user` を実行してみてください
@@ -114,12 +111,13 @@ # NPM がシステムにインストールされていることを確認して
playwright install --with-deps chromium
```
- - **modify `config.yaml`**
+ - **modify `config2.yaml`**
- config.yaml から MERMAID_ENGINE のコメントを外し、`playwright` に変更する
+ config2.yaml から mermaid.engine のコメントを外し、`playwright` に変更する
```yaml
- MERMAID_ENGINE: playwright
+ mermaid:
+ engine: playwright
```
- pyppeteer
@@ -143,21 +141,23 @@ # NPM がシステムにインストールされていることを確認して
pyppeteer-install
```
- - **`config.yaml` を修正**
+ - **`config2.yaml` を修正**
- config.yaml から MERMAID_ENGINE のコメントを外し、`pyppeteer` に変更する
+ config2.yaml から mermaid.engine のコメントを外し、`pyppeteer` に変更する
```yaml
- MERMAID_ENGINE: pyppeteer
+ mermaid:
+ engine: pyppeteer
```
- mermaid.ink
- - **`config.yaml` を修正**
+ - **`config2.yaml` を修正**
- config.yaml から MERMAID_ENGINE のコメントを外し、`ink` に変更する
+ config2.yaml から mermaid.engine のコメントを外し、`ink` に変更する
```yaml
- MERMAID_ENGINE: ink
+ mermaid:
+ engine: ink
```
注: この方法は pdf エクスポートに対応していません。
@@ -166,16 +166,16 @@ ### Docker によるインストール
> Windowsでは、"/opt/metagpt"をDockerが作成する権限を持つディレクトリに置き換える必要があります。例えば、"D:\Users\x\metagpt"などです。
```bash
-# ステップ 1: metagpt 公式イメージをダウンロードし、config.yaml を準備する
+# ステップ 1: metagpt 公式イメージをダウンロードし、config2.yaml を準備する
docker pull metagpt/metagpt:latest
mkdir -p /opt/metagpt/{config,workspace}
-docker run --rm metagpt/metagpt:latest cat /app/metagpt/config/config.yaml > /opt/metagpt/config/key.yaml
-vim /opt/metagpt/config/key.yaml # 設定を変更する
+docker run --rm metagpt/metagpt:latest cat /app/metagpt/config/config2.yaml > /opt/metagpt/config/config2.yaml
+vim /opt/metagpt/config/config2.yaml # 設定を変更する
# ステップ 2: コンテナで metagpt デモを実行する
docker run --rm \
--privileged \
- -v /opt/metagpt/config/key.yaml:/app/metagpt/config/key.yaml \
+ -v /opt/metagpt/config/config2.yaml:/app/metagpt/config/config2.yaml \
-v /opt/metagpt/workspace:/app/metagpt/workspace \
metagpt/metagpt:latest \
metagpt "Write a cli snake game"
@@ -183,7 +183,7 @@ # ステップ 2: コンテナで metagpt デモを実行する
# コンテナを起動し、その中でコマンドを実行することもできます
docker run --name metagpt -d \
--privileged \
- -v /opt/metagpt/config/key.yaml:/app/metagpt/config/key.yaml \
+ -v /opt/metagpt/config/config2.yaml:/app/metagpt/config/config2.yaml \
-v /opt/metagpt/workspace:/app/metagpt/workspace \
metagpt/metagpt:latest
@@ -194,7 +194,7 @@ # コンテナを起動し、その中でコマンドを実行することもで
コマンド `docker run ...` は以下のことを行います:
- 特権モードで実行し、ブラウザの実行権限を得る
-- ホスト設定ファイル `/opt/metagpt/config/key.yaml` をコンテナ `/app/metagpt/config/key.yaml` にマップします
+- ホスト設定ファイル `/opt/metagpt/config/config2.yaml` をコンテナ `/app/metagpt/config/config2.yaml` にマップします
- ホストディレクトリ `/opt/metagpt/workspace` をコンテナディレクトリ `/app/metagpt/workspace` にマップするs
- デモコマンド `metagpt "Write a cli snake game"` を実行する
@@ -208,19 +208,14 @@ # また、自分で metagpt イメージを構築することもできます。
## 設定
-- `OPENAI_API_KEY` を `config/key.yaml / config/config.yaml / env` のいずれかで設定します。
-- 優先順位は: `config/key.yaml > config/config.yaml > env` の順です。
+- `api_key` を `~/.metagpt/config2.yaml / config/config2.yaml` のいずれかで設定します。
+- 優先順位は: `~/.metagpt/config2.yaml > config/config2.yaml > env` の順です。
```bash
# 設定ファイルをコピーし、必要な修正を加える。
-cp config/config.yaml config/key.yaml
+cp config/config2.yaml ~/.metagpt/config2.yaml
```
-| 変数名 | config/key.yaml | env |
-| --------------------------------------- | ----------------------------------------- | ----------------------------------------------- |
-| OPENAI_API_KEY # 自分のキーに置き換える | OPENAI_API_KEY: "sk-..." | export OPENAI_API_KEY="sk-..." |
-| OPENAI_BASE_URL # オプション | OPENAI_BASE_URL: "https:///v1" | export OPENAI_BASE_URL="https:///v1" |
-
## チュートリアル: スタートアップの開始
```shell
diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md
index 9bc62f849..4bb530bf2 100644
--- a/docs/ROADMAP.md
+++ b/docs/ROADMAP.md
@@ -76,9 +76,8 @@ ### Tasks
2. ~~Support Azure asynchronous API~~
3. Support streaming version of all APIs
4. ~~Make gpt-3.5-turbo available (HARD)~~
- 5. Support
10. Other
1. ~~Clean up existing unused code~~
- 2. Unify all code styles and establish contribution standards
+ 2. ~~Unify all code styles and establish contribution standards~~
3. ~~Multi-language support~~
4. ~~Multi-programming-language support~~
diff --git a/docs/install/cli_install.md b/docs/install/cli_install.md
index 80deda771..b79ad9cb7 100644
--- a/docs/install/cli_install.md
+++ b/docs/install/cli_install.md
@@ -9,17 +9,29 @@ ### Support System and version
### Detail Installation
```bash
-# Step 1: Ensure that NPM is installed on your system. Then install mermaid-js. (If you don't have npm in your computer, please go to the Node.js official website to install Node.js https://nodejs.org/ and then you will have npm tool in your computer.)
-npm --version
-sudo npm install -g @mermaid-js/mermaid-cli
-
-# Step 2: Ensure that Python 3.9+ is installed on your system. You can check this by using:
+# Step 1: Ensure that Python 3.9+ is installed on your system. You can check this by using:
+# You can use conda to initialize a new python env
+# conda create -n metagpt python=3.9
+# conda activate metagpt
python3 --version
-# Step 3: Clone the repository to your local machine, and install it.
+# Step 2: Clone the repository to your local machine for latest version, and install it.
git clone https://github.com/geekan/MetaGPT.git
cd MetaGPT
-pip install -e.
+pip3 install -e . # or pip3 install metagpt # for stable version
+
+# Step 3: setup your LLM key in the config2.yaml file
+mkdir ~/.metagpt
+cp config/config2.yaml ~/.metagpt/config2.yaml
+vim ~/.metagpt/config2.yaml
+
+# Step 4: run metagpt cli
+metagpt "Create a 2048 game in python"
+
+# Step 5 [Optional]: If you want to save the artifacts like diagrams such as quadrant chart, system designs, sequence flow in the workspace, you can execute the step before Step 3. By default, the framework is compatible, and the entire process can be run completely without executing this step.
+# If executing, ensure that NPM is installed on your system. Then install mermaid-js. (If you don't have npm in your computer, please go to the Node.js official website to install Node.js https://nodejs.org/ and then you will have npm tool in your computer.)
+npm --version
+sudo npm install -g @mermaid-js/mermaid-cli
```
**Note:**
@@ -33,11 +45,12 @@ # Step 3: Clone the repository to your local machine, and install it.
npm install @mermaid-js/mermaid-cli
```
-- don't forget to the configuration for mmdc in config.yml
+- don't forget to the configuration for mmdc path in config.yml
- ```yml
- PUPPETEER_CONFIG: "./config/puppeteer-config.json"
- MMDC: "./node_modules/.bin/mmdc"
+ ```yaml
+ mermaid:
+ puppeteer_config: "./config/puppeteer-config.json"
+ path: "./node_modules/.bin/mmdc"
```
- if `pip install -e.` fails with error `[Errno 13] Permission denied: '/usr/local/lib/python3.11/dist-packages/test-easy-install-13129.write-test'`, try instead running `pip install -e. --user`
@@ -59,12 +72,13 @@ # Step 3: Clone the repository to your local machine, and install it.
playwright install --with-deps chromium
```
- - **modify `config.yaml`**
+ - **modify `config2.yaml`**
- uncomment MERMAID_ENGINE from config.yaml and change it to `playwright`
+ change mermaid.engine to `playwright`
```yaml
- MERMAID_ENGINE: playwright
+ mermaid:
+ engine: playwright
```
- pyppeteer
@@ -88,22 +102,24 @@ # Step 3: Clone the repository to your local machine, and install it.
pyppeteer-install
```
- - **modify `config.yaml`**
+ - **modify `config2.yaml`**
- uncomment MERMAID_ENGINE from config.yaml and change it to `pyppeteer`
+ change mermaid.engine to `pyppeteer`
```yaml
- MERMAID_ENGINE: pyppeteer
+ mermaid:
+ engine: pyppeteer
```
- mermaid.ink
- - **modify `config.yaml`**
-
- uncomment MERMAID_ENGINE from config.yaml and change it to `ink`
+ - **modify `config2.yaml`**
+
+ change mermaid.engine to `ink`
```yaml
- MERMAID_ENGINE: ink
+ mermaid:
+ engine: ink
```
Note: this method does not support pdf export.
-
\ No newline at end of file
+
diff --git a/docs/install/cli_install_cn.md b/docs/install/cli_install_cn.md
index b1da1b813..1ee18d9a6 100644
--- a/docs/install/cli_install_cn.md
+++ b/docs/install/cli_install_cn.md
@@ -10,17 +10,29 @@ ### 支持的系统和版本
### 详细安装
```bash
-# 第 1 步:确保您的系统上安装了 NPM。并使用npm安装mermaid-js
-npm --version
-sudo npm install -g @mermaid-js/mermaid-cli
-
-# 第 2 步:确保您的系统上安装了 Python 3.9+。您可以使用以下命令进行检查:
+# 步骤 1: 确保您的系统安装了 Python 3.9 或更高版本。您可以使用以下命令来检查:
+# 您可以使用 conda 来初始化一个新的 Python 环境
+# conda create -n metagpt python=3.9
+# conda activate metagpt
python3 --version
-# 第 3 步:克隆仓库到您的本地机器,并进行安装。
+# 步骤 2: 克隆仓库到您的本地机器以获取最新版本,并安装它。
git clone https://github.com/geekan/MetaGPT.git
cd MetaGPT
-pip install -e.
+pip3 install -e . # 或 pip3 install metagpt # 用于稳定版本
+
+# 步骤 3: 在 config2.yaml 文件中设置您的 LLM 密钥
+mkdir ~/.metagpt
+cp config/config2.yaml ~/.metagpt/config2.yaml
+vim ~/.metagpt/config2.yaml
+
+# 步骤 4: 运行 metagpt 命令行界面
+metagpt "用 python 创建一个 2048 游戏"
+
+# 步骤 5 [可选]: 如果您想保存诸如象限图、系统设计、序列流等图表作为工作空间的工件,您可以在执行步骤 3 之前执行此步骤。默认情况下,该框架是兼容的,整个过程可以完全不执行此步骤而运行。
+# 如果执行此步骤,请确保您的系统上安装了 NPM。然后安装 mermaid-js。(如果您的计算机中没有 npm,请访问 Node.js 官方网站 https://nodejs.org/ 安装 Node.js,然后您将在计算机中拥有 npm 工具。)
+npm --version
+sudo npm install -g @mermaid-js/mermaid-cli
```
**注意:**
@@ -33,11 +45,12 @@ # 第 3 步:克隆仓库到您的本地机器,并进行安装。
npm install @mermaid-js/mermaid-cli
```
-- 不要忘记在config.yml中为mmdc配置配置,
+- 不要忘记在config.yml中为mmdc配置
```yml
- PUPPETEER_CONFIG: "./config/puppeteer-config.json"
- MMDC: "./node_modules/.bin/mmdc"
+ mermaid:
+ puppeteer_config: "./config/puppeteer-config.json"
+ path: "./node_modules/.bin/mmdc"
```
- 如果`pip install -e.`失败并显示错误`[Errno 13] Permission denied: '/usr/local/lib/python3.11/dist-packages/test-easy-install-13129.write-test'`,请尝试使用`pip install -e. --user`运行。
diff --git a/docs/install/docker_install.md b/docs/install/docker_install.md
index 37125bdbe..2fe1b6abf 100644
--- a/docs/install/docker_install.md
+++ b/docs/install/docker_install.md
@@ -3,16 +3,16 @@ ## Docker Installation
### Use default MetaGPT image
```bash
-# Step 1: Download metagpt official image and prepare config.yaml
+# Step 1: Download metagpt official image and prepare config2.yaml
docker pull metagpt/metagpt:latest
mkdir -p /opt/metagpt/{config,workspace}
-docker run --rm metagpt/metagpt:latest cat /app/metagpt/config/config.yaml > /opt/metagpt/config/key.yaml
-vim /opt/metagpt/config/key.yaml # Change the config
+docker run --rm metagpt/metagpt:latest cat /app/metagpt/config/config2.yaml > /opt/metagpt/config/config2.yaml
+vim /opt/metagpt/config/config2.yaml # Change the config
# Step 2: Run metagpt demo with container
docker run --rm \
--privileged \
- -v /opt/metagpt/config/key.yaml:/app/metagpt/config/key.yaml \
+ -v /opt/metagpt/config/config2.yaml:/app/metagpt/config/config2.yaml \
-v /opt/metagpt/workspace:/app/metagpt/workspace \
metagpt/metagpt:latest \
metagpt "Write a cli snake game"
@@ -20,7 +20,7 @@ # Step 2: Run metagpt demo with container
# You can also start a container and execute commands in it
docker run --name metagpt -d \
--privileged \
- -v /opt/metagpt/config/key.yaml:/app/metagpt/config/key.yaml \
+ -v /opt/metagpt/config/config2.yaml:/app/metagpt/config/config2.yaml \
-v /opt/metagpt/workspace:/app/metagpt/workspace \
metagpt/metagpt:latest
@@ -31,7 +31,7 @@ # You can also start a container and execute commands in it
The command `docker run ...` do the following things:
- Run in privileged mode to have permission to run the browser
-- Map host configure file `/opt/metagpt/config/key.yaml` to container `/app/metagpt/config/key.yaml`
+- Map host configure file `/opt/metagpt/config/config2.yaml` to container `/app/metagpt/config/config2.yaml`
- Map host directory `/opt/metagpt/workspace` to container `/app/metagpt/workspace`
- Execute the demo command `metagpt "Write a cli snake game"`
diff --git a/docs/install/docker_install_cn.md b/docs/install/docker_install_cn.md
index f360b49ed..10204c1e0 100644
--- a/docs/install/docker_install_cn.md
+++ b/docs/install/docker_install_cn.md
@@ -3,16 +3,16 @@ ## Docker安装
### 使用MetaGPT镜像
```bash
-# 步骤1: 下载metagpt官方镜像并准备好config.yaml
+# 步骤1: 下载metagpt官方镜像并准备好config2.yaml
docker pull metagpt/metagpt:latest
mkdir -p /opt/metagpt/{config,workspace}
-docker run --rm metagpt/metagpt:latest cat /app/metagpt/config/config.yaml > /opt/metagpt/config/key.yaml
-vim /opt/metagpt/config/key.yaml # 修改配置文件
+docker run --rm metagpt/metagpt:latest cat /app/metagpt/config/config2.yaml > /opt/metagpt/config/config2.yaml
+vim /opt/metagpt/config/config2.yaml # 修改配置文件
# 步骤2: 使用容器运行metagpt演示
docker run --rm \
--privileged \
- -v /opt/metagpt/config/key.yaml:/app/metagpt/config/key.yaml \
+ -v /opt/metagpt/config/config2.yaml:/app/metagpt/config/config2.yaml \
-v /opt/metagpt/workspace:/app/metagpt/workspace \
metagpt/metagpt:latest \
metagpt "Write a cli snake game"
@@ -20,7 +20,7 @@ # 步骤2: 使用容器运行metagpt演示
# 您也可以启动一个容器并在其中执行命令
docker run --name metagpt -d \
--privileged \
- -v /opt/metagpt/config/key.yaml:/app/metagpt/config/key.yaml \
+ -v /opt/metagpt/config/config2.yaml:/app/metagpt/config/config2.yaml \
-v /opt/metagpt/workspace:/app/metagpt/workspace \
metagpt/metagpt:latest
@@ -31,7 +31,7 @@ # 您也可以启动一个容器并在其中执行命令
`docker run ...`做了以下事情:
- 以特权模式运行,有权限运行浏览器
-- 将主机文件 `/opt/metagpt/config/key.yaml` 映射到容器文件 `/app/metagpt/config/key.yaml`
+- 将主机文件 `/opt/metagpt/config/config2.yaml` 映射到容器文件 `/app/metagpt/config/config2.yaml`
- 将主机目录 `/opt/metagpt/workspace` 映射到容器目录 `/app/metagpt/workspace`
- 执行示例命令 `metagpt "Write a cli snake game"`
diff --git a/docs/tutorial/usage.md b/docs/tutorial/usage.md
index a08d92a22..1128e98a5 100644
--- a/docs/tutorial/usage.md
+++ b/docs/tutorial/usage.md
@@ -2,19 +2,14 @@ ## MetaGPT Usage
### Configuration
-- Configure your `OPENAI_API_KEY` in any of `config/key.yaml / config/config.yaml / env`
-- Priority order: `config/key.yaml > config/config.yaml > env`
+- Configure your `api_key` in any of `~/.metagpt/config2.yaml / config/config2.yaml`
+- Priority order: `~/.metagpt/config2.yaml > config/config2.yaml`
```bash
# Copy the configuration file and make the necessary modifications.
-cp config/config.yaml config/key.yaml
+cp config/config2.yaml ~/.metagpt/config2.yaml
```
-| Variable Name | config/key.yaml | env |
-| ------------------------------------------ | ----------------------------------------- | ----------------------------------------------- |
-| OPENAI_API_KEY # Replace with your own key | OPENAI_API_KEY: "sk-..." | export OPENAI_API_KEY="sk-..." |
-| OPENAI_BASE_URL # Optional | OPENAI_BASE_URL: "https:///v1" | export OPENAI_BASE_URL="https:///v1" |
-
### Initiating a startup
```shell
@@ -39,29 +34,28 @@ ### Preference of Platform or Tool
### Usage
```
-NAME
- metagpt - We are a software startup comprised of AI. By investing in us, you are empowering a future filled with limitless possibilities.
-
-SYNOPSIS
- metagpt IDEA
-
-DESCRIPTION
- We are a software startup comprised of AI. By investing in us, you are empowering a future filled with limitless possibilities.
-
-POSITIONAL ARGUMENTS
- IDEA
- Type: str
- Your innovative idea, such as "Creating a snake game."
-
-FLAGS
- --investment=INVESTMENT
- Type: float
- Default: 3.0
- As an investor, you have the opportunity to contribute a certain dollar amount to this AI company.
- --n_round=N_ROUND
- Type: int
- Default: 5
-
-NOTES
- You can also use flags syntax for POSITIONAL ARGUMENTS
+ Usage: metagpt [OPTIONS] [IDEA]
+
+ Start a new project.
+
+╭─ Arguments ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│ idea [IDEA] Your innovative idea, such as 'Create a 2048 game.' [default: None] │
+╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+╭─ Options ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│ --investment FLOAT Dollar amount to invest in the AI company. [default: 3.0] │
+│ --n-round INTEGER Number of rounds for the simulation. [default: 5] │
+│ --code-review --no-code-review Whether to use code review. [default: code-review] │
+│ --run-tests --no-run-tests Whether to enable QA for adding & running tests. [default: no-run-tests] │
+│ --implement --no-implement Enable or disable code implementation. [default: implement] │
+│ --project-name TEXT Unique project name, such as 'game_2048'. │
+│ --inc --no-inc Incremental mode. Use it to coop with existing repo. [default: no-inc] │
+│ --project-path TEXT Specify the directory path of the old version project to fulfill the incremental requirements. │
+│ --reqa-file TEXT Specify the source file name for rewriting the quality assurance code. │
+│ --max-auto-summarize-code INTEGER The maximum number of times the 'SummarizeCode' action is automatically invoked, with -1 indicating unlimited. This parameter is used for debugging the │
+│ workflow. │
+│ [default: 0] │
+│ --recover-path TEXT recover the project from existing serialized storage [default: None] │
+│ --init-config --no-init-config Initialize the configuration file for MetaGPT. [default: no-init-config] │
+│ --help Show this message and exit. │
+╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
\ No newline at end of file
diff --git a/docs/tutorial/usage_cn.md b/docs/tutorial/usage_cn.md
index 76a5d6b1b..3b0c86279 100644
--- a/docs/tutorial/usage_cn.md
+++ b/docs/tutorial/usage_cn.md
@@ -2,19 +2,14 @@ ## MetaGPT 使用
### 配置
-- 在 `config/key.yaml / config/config.yaml / env` 中配置您的 `OPENAI_API_KEY`
-- 优先级顺序:`config/key.yaml > config/config.yaml > env`
+- 在 `~/.metagpt/config2.yaml / config/config2.yaml` 中配置您的 `api_key`
+- 优先级顺序:`~/.metagpt/config2.yaml > config/config2.yaml`
```bash
# 复制配置文件并进行必要的修改
-cp config/config.yaml config/key.yaml
+cp config/config2.yaml ~/.metagpt/config2.yaml
```
-| 变量名 | config/key.yaml | env |
-| ----------------------------------- | ----------------------------------------- | ----------------------------------------------- |
-| OPENAI_API_KEY # 用您自己的密钥替换 | OPENAI_API_KEY: "sk-..." | export OPENAI_API_KEY="sk-..." |
-| OPENAI_BASE_URL # 可选 | OPENAI_BASE_URL: "https:///v1" | export OPENAI_BASE_URL="https:///v1" |
-
### 示例:启动一个创业公司
```shell
@@ -35,29 +30,28 @@ ### 平台或工具的倾向性
### 使用
```
-名称
- metagpt - 我们是一家AI软件创业公司。通过投资我们,您将赋能一个充满无限可能的未来。
-
-概要
- metagpt IDEA
-
-描述
- 我们是一家AI软件创业公司。通过投资我们,您将赋能一个充满无限可能的未来。
-
-位置参数
- IDEA
- 类型: str
- 您的创新想法,例如"写一个命令行贪吃蛇。"
-
-标志
- --investment=INVESTMENT
- 类型: float
- 默认值: 3.0
- 作为投资者,您有机会向这家AI公司投入一定的美元金额。
- --n_round=N_ROUND
- 类型: int
- 默认值: 5
-
-备注
- 您也可以用`标志`的语法,来处理`位置参数`
+ Usage: metagpt [OPTIONS] [IDEA]
+
+ Start a new project.
+
+╭─ Arguments ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│ idea [IDEA] Your innovative idea, such as 'Create a 2048 game.' [default: None] │
+╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+╭─ Options ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│ --investment FLOAT Dollar amount to invest in the AI company. [default: 3.0] │
+│ --n-round INTEGER Number of rounds for the simulation. [default: 5] │
+│ --code-review --no-code-review Whether to use code review. [default: code-review] │
+│ --run-tests --no-run-tests Whether to enable QA for adding & running tests. [default: no-run-tests] │
+│ --implement --no-implement Enable or disable code implementation. [default: implement] │
+│ --project-name TEXT Unique project name, such as 'game_2048'. │
+│ --inc --no-inc Incremental mode. Use it to coop with existing repo. [default: no-inc] │
+│ --project-path TEXT Specify the directory path of the old version project to fulfill the incremental requirements. │
+│ --reqa-file TEXT Specify the source file name for rewriting the quality assurance code. │
+│ --max-auto-summarize-code INTEGER The maximum number of times the 'SummarizeCode' action is automatically invoked, with -1 indicating unlimited. This parameter is used for debugging the │
+│ workflow. │
+│ [default: 0] │
+│ --recover-path TEXT recover the project from existing serialized storage [default: None] │
+│ --init-config --no-init-config Initialize the configuration file for MetaGPT. [default: no-init-config] │
+│ --help Show this message and exit. │
+╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
diff --git a/examples/crawl_webpage.py b/examples/crawl_webpage.py
new file mode 100644
index 000000000..2db9e407b
--- /dev/null
+++ b/examples/crawl_webpage.py
@@ -0,0 +1,22 @@
+# -*- encoding: utf-8 -*-
+"""
+@Date : 2024/01/24 15:11:27
+@Author : orange-crow
+@File : crawl_webpage.py
+"""
+
+from metagpt.roles.ci.code_interpreter import CodeInterpreter
+
+
+async def main():
+ prompt = """Get data from `paperlist` table in https://papercopilot.com/statistics/iclr-statistics/iclr-2024-statistics/,
+ and save it to a csv file. paper title must include `multiagent` or `large language model`. *notice: print key variables*"""
+ ci = CodeInterpreter(goal=prompt, use_tools=True)
+
+ await ci.run(prompt)
+
+
+if __name__ == "__main__":
+ import asyncio
+
+ asyncio.run(main())
diff --git a/examples/dalle_gpt4v_agent.py b/examples/dalle_gpt4v_agent.py
new file mode 100644
index 000000000..28215dba3
--- /dev/null
+++ b/examples/dalle_gpt4v_agent.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# @Desc : use gpt4v to improve prompt and draw image with dall-e-3
+
+"""set `model: "gpt-4-vision-preview"` in `config2.yaml` first"""
+
+import asyncio
+
+from PIL import Image
+
+from metagpt.actions.action import Action
+from metagpt.logs import logger
+from metagpt.roles.role import Role
+from metagpt.schema import Message
+from metagpt.utils.common import encode_image
+
+
+class GenAndImproveImageAction(Action):
+ save_image: bool = True
+
+ async def generate_image(self, prompt: str) -> Image:
+ imgs = await self.llm.gen_image(model="dall-e-3", prompt=prompt)
+ return imgs[0]
+
+ async def refine_prompt(self, old_prompt: str, image: Image) -> str:
+ msg = (
+ f"You are a creative painter, with the given generated image and old prompt: {old_prompt}, "
+ f"please refine the prompt and generate new one. Just output the new prompt."
+ )
+ b64_img = encode_image(image)
+ new_prompt = await self.llm.aask(msg=msg, images=[b64_img])
+ return new_prompt
+
+ async def evaluate_images(self, old_prompt: str, images: list[Image]) -> str:
+ msg = (
+ "With the prompt and two generated image, to judge if the second one is better than the first one. "
+ "If so, just output True else output False"
+ )
+ b64_imgs = [encode_image(img) for img in images]
+ res = await self.llm.aask(msg=msg, images=b64_imgs)
+ return res
+
+ async def run(self, messages: list[Message]) -> str:
+ prompt = messages[-1].content
+
+ old_img: Image = await self.generate_image(prompt)
+ new_prompt = await self.refine_prompt(old_prompt=prompt, image=old_img)
+ logger.info(f"original prompt: {prompt}")
+ logger.info(f"refined prompt: {new_prompt}")
+ new_img: Image = await self.generate_image(new_prompt)
+ if self.save_image:
+ old_img.save("./img_by-dall-e_old.png")
+ new_img.save("./img_by-dall-e_new.png")
+ res = await self.evaluate_images(old_prompt=prompt, images=[old_img, new_img])
+ opinion = f"The second generated image is better than the first one: {res}"
+ logger.info(f"evaluate opinion: {opinion}")
+ return opinion
+
+
+class Painter(Role):
+ name: str = "MaLiang"
+ profile: str = "Painter"
+ goal: str = "to generate fine painting"
+
+ def __init__(self, **data):
+ super().__init__(**data)
+
+ self.set_actions([GenAndImproveImageAction])
+
+
+async def main():
+ role = Painter()
+ await role.run(with_message="a girl with flowers")
+
+
+if __name__ == "__main__":
+ asyncio.run(main())
diff --git a/examples/example.faiss b/examples/example.faiss
deleted file mode 100644
index 580946190..000000000
Binary files a/examples/example.faiss and /dev/null differ
diff --git a/examples/example.pkl b/examples/example.pkl
deleted file mode 100644
index 0469a2e46..000000000
Binary files a/examples/example.pkl and /dev/null differ
diff --git a/examples/imitate_webpage.py b/examples/imitate_webpage.py
new file mode 100644
index 000000000..5075e1e39
--- /dev/null
+++ b/examples/imitate_webpage.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+@Time : 2024/01/15
+@Author : mannaandpoem
+@File : imitate_webpage.py
+"""
+from metagpt.roles.ci.code_interpreter import CodeInterpreter
+
+
+async def main():
+ web_url = "https://pytorch.org/"
+ prompt = f"""This is a URL of webpage: '{web_url}' .
+Firstly, utilize Selenium and WebDriver for rendering.
+Secondly, convert image to a webpage including HTML, CSS and JS in one go.
+Finally, save webpage in a text file.
+Note: All required dependencies and environments have been fully installed and configured."""
+ ci = CodeInterpreter(goal=prompt, use_tools=True)
+
+ await ci.run(prompt)
+
+
+if __name__ == "__main__":
+ import asyncio
+
+ asyncio.run(main())
diff --git a/examples/llm_hello_world.py b/examples/llm_hello_world.py
index 76be1cc90..219a303c8 100644
--- a/examples/llm_hello_world.py
+++ b/examples/llm_hello_world.py
@@ -23,6 +23,10 @@ async def main():
# streaming mode, much slower
await llm.acompletion_text(hello_msg, stream=True)
+ # check completion if exist to test llm complete functions
+ if hasattr(llm, "completion"):
+ logger.info(llm.completion(hello_msg))
+
if __name__ == "__main__":
asyncio.run(main())
diff --git a/examples/llm_vision.py b/examples/llm_vision.py
new file mode 100644
index 000000000..276decd59
--- /dev/null
+++ b/examples/llm_vision.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# @Desc : example to run the ability of LLM vision
+
+import asyncio
+from pathlib import Path
+
+from metagpt.llm import LLM
+from metagpt.utils.common import encode_image
+
+
+async def main():
+ llm = LLM()
+
+ # check if the configured llm supports llm-vision capacity. If not, it will throw a error
+ invoice_path = Path(__file__).parent.joinpath("..", "tests", "data", "invoices", "invoice-2.png")
+ img_base64 = encode_image(invoice_path)
+ res = await llm.aask(msg="if this is a invoice, just return True else return False", images=[img_base64])
+ assert "true" in res.lower()
+
+
+if __name__ == "__main__":
+ asyncio.run(main())
diff --git a/examples/sd_tool_usage.py b/examples/sd_tool_usage.py
new file mode 100644
index 000000000..b4642af23
--- /dev/null
+++ b/examples/sd_tool_usage.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# @Date : 1/11/2024 7:06 PM
+# @Author : stellahong (stellahong@fuzhi.ai)
+# @Desc :
+import asyncio
+
+from metagpt.roles.ci.code_interpreter import CodeInterpreter
+
+
+async def main(requirement: str = ""):
+ code_interpreter = CodeInterpreter(use_tools=True, goal=requirement)
+ await code_interpreter.run(requirement)
+
+
+if __name__ == "__main__":
+ sd_url = "http://your.sd.service.ip:port"
+ requirement = (
+ f"I want to generate an image of a beautiful girl using the stable diffusion text2image tool, sd_url={sd_url}"
+ )
+
+ asyncio.run(main(requirement))
diff --git a/examples/search_with_specific_engine.py b/examples/search_with_specific_engine.py
index 9406a2965..97b1378ee 100644
--- a/examples/search_with_specific_engine.py
+++ b/examples/search_with_specific_engine.py
@@ -5,17 +5,20 @@
import asyncio
from metagpt.roles import Searcher
-from metagpt.tools import SearchEngineType
+from metagpt.tools.search_engine import SearchEngine, SearchEngineType
async def main():
question = "What are the most interesting human facts?"
+ kwargs = {"api_key": "", "cse_id": "", "proxy": None}
# Serper API
- # await Searcher(engine=SearchEngineType.SERPER_GOOGLE).run(question)
+ # await Searcher(search_engine=SearchEngine(engine=SearchEngineType.SERPER_GOOGLE, **kwargs)).run(question)
# SerpAPI
- await Searcher(engine=SearchEngineType.SERPAPI_GOOGLE).run(question)
+ # await Searcher(search_engine=SearchEngine(engine=SearchEngineType.SERPAPI_GOOGLE, **kwargs)).run(question)
# Google API
- # await Searcher(engine=SearchEngineType.DIRECT_GOOGLE).run(question)
+ # await Searcher(search_engine=SearchEngine(engine=SearchEngineType.DIRECT_GOOGLE, **kwargs)).run(question)
+ # DDG API
+ await Searcher(search_engine=SearchEngine(engine=SearchEngineType.DUCK_DUCK_GO, **kwargs)).run(question)
if __name__ == "__main__":
diff --git a/examples/write_novel.py b/examples/write_novel.py
new file mode 100644
index 000000000..b272a56e6
--- /dev/null
+++ b/examples/write_novel.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+@Time : 2024/2/1 12:01
+@Author : alexanderwu
+@File : write_novel.py
+"""
+import asyncio
+from typing import List
+
+from pydantic import BaseModel, Field
+
+from metagpt.actions.action_node import ActionNode
+from metagpt.llm import LLM
+
+
+class Novel(BaseModel):
+ name: str = Field(default="The Lord of the Rings", description="The name of the novel.")
+ user_group: str = Field(default="...", description="The user group of the novel.")
+ outlines: List[str] = Field(
+ default=["Chapter 1: ...", "Chapter 2: ...", "Chapter 3: ..."],
+ description="The outlines of the novel. No more than 10 chapters.",
+ )
+ background: str = Field(default="...", description="The background of the novel.")
+ character_names: List[str] = Field(default=["Frodo", "Gandalf", "Sauron"], description="The characters.")
+ conflict: str = Field(default="...", description="The conflict of the characters.")
+ plot: str = Field(default="...", description="The plot of the novel.")
+ ending: str = Field(default="...", description="The ending of the novel.")
+
+
+class Chapter(BaseModel):
+ name: str = Field(default="Chapter 1", description="The name of the chapter.")
+ content: str = Field(default="...", description="The content of the chapter. No more than 1000 words.")
+
+
+async def generate_novel():
+ instruction = (
+ "Write a novel named 'Harry Potter in The Lord of the Rings'. "
+ "Fill the empty nodes with your own ideas. Be creative! Use your own words!"
+ "I will tip you $100,000 if you write a good novel."
+ )
+ novel_node = await ActionNode.from_pydantic(Novel).fill(context=instruction, llm=LLM())
+ chap_node = await ActionNode.from_pydantic(Chapter).fill(
+ context=f"### instruction\n{instruction}\n### novel\n{novel_node.content}", llm=LLM()
+ )
+ print(chap_node.content)
+
+
+asyncio.run(generate_novel())
diff --git a/metagpt/actions/__init__.py b/metagpt/actions/__init__.py
index 5b995bab6..363b4fd33 100644
--- a/metagpt/actions/__init__.py
+++ b/metagpt/actions/__init__.py
@@ -22,6 +22,9 @@ from metagpt.actions.write_code_review import WriteCodeReview
from metagpt.actions.write_prd import WritePRD
from metagpt.actions.write_prd_review import WritePRDReview
from metagpt.actions.write_test import WriteTest
+from metagpt.actions.ci.execute_nb_code import ExecuteNbCode
+from metagpt.actions.ci.write_analysis_code import WriteCodeWithoutTools, WriteCodeWithTools
+from metagpt.actions.ci.write_plan import WritePlan
class ActionType(Enum):
@@ -42,6 +45,10 @@ class ActionType(Enum):
COLLECT_LINKS = CollectLinks
WEB_BROWSE_AND_SUMMARIZE = WebBrowseAndSummarize
CONDUCT_RESEARCH = ConductResearch
+ EXECUTE_NB_CODE = ExecuteNbCode
+ WRITE_CODE_WITHOUT_TOOLS = WriteCodeWithoutTools
+ WRITE_CODE_WITH_TOOLS = WriteCodeWithTools
+ WRITE_PLAN = WritePlan
__all__ = [
diff --git a/metagpt/actions/action.py b/metagpt/actions/action.py
index a33918a09..1b93213f7 100644
--- a/metagpt/actions/action.py
+++ b/metagpt/actions/action.py
@@ -15,6 +15,7 @@ from pydantic import BaseModel, ConfigDict, Field, model_validator
from metagpt.actions.action_node import ActionNode
from metagpt.context_mixin import ContextMixin
from metagpt.schema import (
+ CodePlanAndChangeContext,
CodeSummarizeContext,
CodingContext,
RunCodeContext,
@@ -28,14 +29,18 @@ class Action(SerializationMixin, ContextMixin, BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True)
name: str = ""
- i_context: Union[dict, CodingContext, CodeSummarizeContext, TestingContext, RunCodeContext, str, None] = ""
+ i_context: Union[
+ dict, CodingContext, CodeSummarizeContext, TestingContext, RunCodeContext, CodePlanAndChangeContext, str, None
+ ] = ""
prefix: str = "" # aask*时会加上prefix,作为system_message
desc: str = "" # for skill manager
node: ActionNode = Field(default=None, exclude=True)
@property
- def project_repo(self):
- return ProjectRepo(self.context.git_repo)
+ def repo(self) -> ProjectRepo:
+ if not self.context.repo:
+ self.context.repo = ProjectRepo(self.context.git_repo)
+ return self.context.repo
@property
def prompt_schema(self):
diff --git a/metagpt/actions/action_graph.py b/metagpt/actions/action_graph.py
new file mode 100644
index 000000000..893bc6d4c
--- /dev/null
+++ b/metagpt/actions/action_graph.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+@Time : 2024/1/30 13:52
+@Author : alexanderwu
+@File : action_graph.py
+"""
+from __future__ import annotations
+
+# from metagpt.actions.action_node import ActionNode
+
+
+class ActionGraph:
+ """ActionGraph: a directed graph to represent the dependency between actions."""
+
+ def __init__(self):
+ self.nodes = {}
+ self.edges = {}
+ self.execution_order = []
+
+ def add_node(self, node):
+ """Add a node to the graph"""
+ self.nodes[node.key] = node
+
+ def add_edge(self, from_node: "ActionNode", to_node: "ActionNode"):
+ """Add an edge to the graph"""
+ if from_node.key not in self.edges:
+ self.edges[from_node.key] = []
+ self.edges[from_node.key].append(to_node.key)
+ from_node.add_next(to_node)
+ to_node.add_prev(from_node)
+
+ def topological_sort(self):
+ """Topological sort the graph"""
+ visited = set()
+ stack = []
+
+ def visit(k):
+ if k not in visited:
+ visited.add(k)
+ if k in self.edges:
+ for next_node in self.edges[k]:
+ visit(next_node)
+ stack.insert(0, k)
+
+ for key in self.nodes:
+ visit(key)
+
+ self.execution_order = stack
diff --git a/metagpt/actions/action_node.py b/metagpt/actions/action_node.py
index b4d8c32df..09da4a988 100644
--- a/metagpt/actions/action_node.py
+++ b/metagpt/actions/action_node.py
@@ -9,10 +9,11 @@ NOTE: You should use typing.List instead of list to do type annotation. Because
we can use typing to extract the type of the node, but we cannot use built-in list to extract.
"""
import json
+import typing
from enum import Enum
from typing import Any, Dict, List, Optional, Tuple, Type, Union
-from pydantic import BaseModel, create_model, model_validator
+from pydantic import BaseModel, Field, create_model, model_validator
from tenacity import retry, stop_after_attempt, wait_random_exponential
from metagpt.actions.action_outcls_registry import register_action_outcls
@@ -39,7 +40,6 @@ TAG = "CONTENT"
LANGUAGE_CONSTRAINT = "Language: Please use the same language as Human INPUT."
FORMAT_CONSTRAINT = f"Format: output wrapped inside [{TAG}][/{TAG}] like format example, nothing else."
-
SIMPLE_TEMPLATE = """
## context
{context}
@@ -61,7 +61,7 @@ Follow instructions of nodes, generate output and make sure it follows the forma
REVIEW_TEMPLATE = """
## context
-Compare the keys of nodes_output and the corresponding requirements one by one. If a key that does not match the requirement is found, provide the comment content on how to modify it. No output is required for matching keys.
+Compare the key's value of nodes_output and the corresponding requirements one by one. If a key's value that does not match the requirement is found, provide the comment content on how to modify it. No output is required for matching keys.
### nodes_output
{nodes_output}
@@ -86,7 +86,7 @@ Compare the keys of nodes_output and the corresponding requirements one by one.
{constraint}
## action
-generate output and make sure it follows the format example.
+Follow format example's {prompt_schema} format, generate output and make sure it follows the format example.
"""
REVISE_TEMPLATE = """
@@ -108,7 +108,7 @@ change the nodes_output key's value to meet its comment and no need to add extra
{constraint}
## action
-generate output and make sure it follows the format example.
+Follow format example's {prompt_schema} format, generate output and make sure it follows the format example.
"""
@@ -131,6 +131,8 @@ class ActionNode:
# Action Input
key: str # Product Requirement / File list / Code
+ func: typing.Callable # 与节点相关联的函数或LLM调用
+ params: Dict[str, Type] # 输入参数的字典,键为参数名,值为参数类型
expected_type: Type # such as str / int / float etc.
# context: str # everything in the history.
instruction: str # the instructions should be followed.
@@ -140,6 +142,10 @@ class ActionNode:
content: str
instruct_content: BaseModel
+ # For ActionGraph
+ prevs: List["ActionNode"] # previous nodes
+ nexts: List["ActionNode"] # next nodes
+
def __init__(
self,
key: str,
@@ -157,6 +163,8 @@ class ActionNode:
self.content = content
self.children = children if children is not None else {}
self.schema = schema
+ self.prevs = []
+ self.nexts = []
def __str__(self):
return (
@@ -167,6 +175,14 @@ class ActionNode:
def __repr__(self):
return self.__str__()
+ def add_prev(self, node: "ActionNode"):
+ """增加前置ActionNode"""
+ self.prevs.append(node)
+
+ def add_next(self, node: "ActionNode"):
+ """增加后置ActionNode"""
+ self.nexts.append(node)
+
def add_child(self, node: "ActionNode"):
"""增加子ActionNode"""
self.children[node.key] = node
@@ -186,25 +202,38 @@ class ActionNode:
obj.add_children(nodes)
return obj
- def get_children_mapping(self, exclude=None) -> Dict[str, Tuple[Type, Any]]:
- """获得子ActionNode的字典,以key索引"""
+ def _get_children_mapping(self, exclude=None) -> Dict[str, Any]:
+ """获得子ActionNode的字典,以key索引,支持多级结构。"""
exclude = exclude or []
- return {k: (v.expected_type, ...) for k, v in self.children.items() if k not in exclude}
- def get_self_mapping(self) -> Dict[str, Tuple[Type, Any]]:
+ def _get_mapping(node: "ActionNode") -> Dict[str, Any]:
+ mapping = {}
+ for key, child in node.children.items():
+ if key in exclude:
+ continue
+ # 对于嵌套的子节点,递归调用 _get_mapping
+ if child.children:
+ mapping[key] = _get_mapping(child)
+ else:
+ mapping[key] = (child.expected_type, Field(default=child.example, description=child.instruction))
+ return mapping
+
+ return _get_mapping(self)
+
+ def _get_self_mapping(self) -> Dict[str, Tuple[Type, Any]]:
"""get self key: type mapping"""
return {self.key: (self.expected_type, ...)}
def get_mapping(self, mode="children", exclude=None) -> Dict[str, Tuple[Type, Any]]:
"""get key: type mapping under mode"""
if mode == "children" or (mode == "auto" and self.children):
- return self.get_children_mapping(exclude=exclude)
- return {} if exclude and self.key in exclude else self.get_self_mapping()
+ return self._get_children_mapping(exclude=exclude)
+ return {} if exclude and self.key in exclude else self._get_self_mapping()
@classmethod
@register_action_outcls
def create_model_class(cls, class_name: str, mapping: Dict[str, Tuple[Type, Any]]):
- """基于pydantic v1的模型动态生成,用来检验结果类型正确性"""
+ """基于pydantic v2的模型动态生成,用来检验结果类型正确性"""
def check_fields(cls, values):
required_fields = set(mapping.keys())
@@ -219,7 +248,17 @@ class ActionNode:
validators = {"check_missing_fields_validator": model_validator(mode="before")(check_fields)}
- new_class = create_model(class_name, __validators__=validators, **mapping)
+ new_fields = {}
+ for field_name, field_value in mapping.items():
+ if isinstance(field_value, dict):
+ # 对于嵌套结构,递归创建模型类
+ nested_class_name = f"{class_name}_{field_name}"
+ nested_class = cls.create_model_class(nested_class_name, field_value)
+ new_fields[field_name] = (nested_class, ...)
+ else:
+ new_fields[field_name] = field_value
+
+ new_class = create_model(class_name, __validators__=validators, **new_fields)
return new_class
def create_class(self, mode: str = "auto", class_name: str = None, exclude=None):
@@ -227,39 +266,48 @@ class ActionNode:
mapping = self.get_mapping(mode=mode, exclude=exclude)
return self.create_model_class(class_name, mapping)
- def create_children_class(self, exclude=None):
+ def _create_children_class(self, exclude=None):
"""使用object内有的字段直接生成model_class"""
class_name = f"{self.key}_AN"
- mapping = self.get_children_mapping(exclude=exclude)
+ mapping = self._get_children_mapping(exclude=exclude)
return self.create_model_class(class_name, mapping)
def to_dict(self, format_func=None, mode="auto", exclude=None) -> Dict:
"""将当前节点与子节点都按照node: format的格式组织成字典"""
+ nodes = self._to_dict(format_func=format_func, mode=mode, exclude=exclude)
+ if not isinstance(nodes, dict):
+ nodes = {self.key: nodes}
+ return nodes
- # 如果没有提供格式化函数,使用默认的格式化方式
+ def _to_dict(self, format_func=None, mode="auto", exclude=None) -> Dict:
+ """将当前节点与子节点都按照node: format的格式组织成字典"""
+
+ # 如果没有提供格式化函数,则使用默认的格式化函数
if format_func is None:
- format_func = lambda node: f"{node.instruction}"
+ format_func = lambda node: node.instruction
# 使用提供的格式化函数来格式化当前节点的值
formatted_value = format_func(self)
# 创建当前节点的键值对
- if mode == "children" or (mode == "auto" and self.children):
- node_dict = {}
+ if (mode == "children" or mode == "auto") and self.children:
+ node_value = {}
else:
- node_dict = {self.key: formatted_value}
+ node_value = formatted_value
if mode == "root":
- return node_dict
+ return {self.key: node_value}
- # 遍历子节点并递归调用 to_dict 方法
+ # 递归处理子节点
exclude = exclude or []
- for _, child_node in self.children.items():
- if child_node.key in exclude:
+ for child_key, child_node in self.children.items():
+ if child_key in exclude:
continue
- node_dict.update(child_node.to_dict(format_func))
+ # 递归调用 to_dict 方法并更新节点字典
+ child_dict = child_node._to_dict(format_func, mode, exclude)
+ node_value[child_key] = child_dict
- return node_dict
+ return node_value
def update_instruct_content(self, incre_data: dict[str, Any]):
assert self.instruct_content
@@ -328,6 +376,17 @@ class ActionNode:
if schema == "raw":
return context + "\n\n## Actions\n" + LANGUAGE_CONSTRAINT + "\n" + self.instruction
+ ### 直接使用 pydantic BaseModel 生成 instruction 与 example,仅限 JSON
+ # child_class = self._create_children_class()
+ # node_schema = child_class.model_json_schema()
+ # defaults = {
+ # k: str(v)
+ # for k, v in child_class.model_fields.items()
+ # if k not in exclude
+ # }
+ # instruction = node_schema
+ # example = json.dumps(defaults, indent=4)
+
# FIXME: json instruction会带来格式问题,如:"Project name": "web_2048 # 项目名称使用下划线",
# compile example暂时不支持markdown
instruction = self.compile_instruction(schema="markdown", mode=mode, exclude=exclude)
@@ -354,12 +413,13 @@ class ActionNode:
prompt: str,
output_class_name: str,
output_data_mapping: dict,
+ images: Optional[Union[str, list[str]]] = None,
system_msgs: Optional[list[str]] = None,
schema="markdown", # compatible to original format
timeout=3,
) -> (str, BaseModel):
"""Use ActionOutput to wrap the output of aask"""
- content = await self.llm.aask(prompt, system_msgs, timeout=timeout)
+ content = await self.llm.aask(prompt, system_msgs, images=images, timeout=timeout)
logger.debug(f"llm raw output:\n{content}")
output_class = self.create_model_class(output_class_name, output_data_mapping)
@@ -388,13 +448,15 @@ class ActionNode:
def set_context(self, context):
self.set_recursive("context", context)
- async def simple_fill(self, schema, mode, timeout=3, exclude=None):
+ async def simple_fill(self, schema, mode, images: Optional[Union[str, list[str]]] = None, timeout=3, exclude=None):
prompt = self.compile(context=self.context, schema=schema, mode=mode, exclude=exclude)
if schema != "raw":
mapping = self.get_mapping(mode, exclude=exclude)
class_name = f"{self.key}_AN"
- content, scontent = await self._aask_v1(prompt, class_name, mapping, schema=schema, timeout=timeout)
+ content, scontent = await self._aask_v1(
+ prompt, class_name, mapping, images=images, schema=schema, timeout=timeout
+ )
self.content = content
self.instruct_content = scontent
else:
@@ -403,7 +465,17 @@ class ActionNode:
return self
- async def fill(self, context, llm, schema="json", mode="auto", strgy="simple", timeout=3, exclude=[]):
+ async def fill(
+ self,
+ context,
+ llm,
+ schema="json",
+ mode="auto",
+ strgy="simple",
+ images: Optional[Union[str, list[str]]] = None,
+ timeout=3,
+ exclude=[],
+ ):
"""Fill the node(s) with mode.
:param context: Everything we should know when filling node.
@@ -419,6 +491,7 @@ class ActionNode:
:param strgy: simple/complex
- simple: run only once
- complex: run each node
+ :param images: the list of image url or base64 for gpt4-v
:param timeout: Timeout for llm invocation.
:param exclude: The keys of ActionNode to exclude.
:return: self
@@ -429,16 +502,16 @@ class ActionNode:
schema = self.schema
if strgy == "simple":
- return await self.simple_fill(schema=schema, mode=mode, timeout=timeout, exclude=exclude)
+ return await self.simple_fill(schema=schema, mode=mode, images=images, timeout=timeout, exclude=exclude)
elif strgy == "complex":
# 这里隐式假设了拥有children
tmp = {}
for _, i in self.children.items():
if exclude and i.key in exclude:
continue
- child = await i.simple_fill(schema=schema, mode=mode, timeout=timeout, exclude=exclude)
+ child = await i.simple_fill(schema=schema, mode=mode, images=images, timeout=timeout, exclude=exclude)
tmp.update(child.instruct_content.model_dump())
- cls = self.create_children_class()
+ cls = self._create_children_class()
self.instruct_content = cls(**tmp)
return self
@@ -469,7 +542,10 @@ class ActionNode:
return dict()
prompt = template.format(
- nodes_output=json.dumps(nodes_output, ensure_ascii=False, indent=4), tag=TAG, constraint=FORMAT_CONSTRAINT
+ nodes_output=json.dumps(nodes_output, ensure_ascii=False),
+ tag=TAG,
+ constraint=FORMAT_CONSTRAINT,
+ prompt_schema="json",
)
content = await self.llm.aask(prompt)
@@ -563,10 +639,11 @@ class ActionNode:
instruction = self.compile_instruction(schema="markdown", mode="auto", exclude=exclude_keys)
prompt = template.format(
- nodes_output=json.dumps(nodes_output, ensure_ascii=False, indent=4),
+ nodes_output=json.dumps(nodes_output, ensure_ascii=False),
example=example,
instruction=instruction,
constraint=FORMAT_CONSTRAINT,
+ prompt_schema="json",
)
# step2, use `_aask_v1` to get revise structure result
@@ -612,3 +689,32 @@ class ActionNode:
self.update_instruct_content(revise_contents)
return revise_contents
+
+ @classmethod
+ def from_pydantic(cls, model: Type[BaseModel], key: str = None):
+ """
+ Creates an ActionNode tree from a Pydantic model.
+
+ Args:
+ model (Type[BaseModel]): The Pydantic model to convert.
+
+ Returns:
+ ActionNode: The root node of the created ActionNode tree.
+ """
+ key = key or model.__name__
+ root_node = cls(key=key, expected_type=Type[model], instruction="", example="")
+
+ for field_name, field_info in model.model_fields.items():
+ field_type = field_info.annotation
+ description = field_info.description
+ default = field_info.default
+
+ # Recursively handle nested models if needed
+ if not isinstance(field_type, typing._GenericAlias) and issubclass(field_type, BaseModel):
+ child_node = cls.from_pydantic(field_type, key=field_name)
+ else:
+ child_node = cls(key=field_name, expected_type=field_type, instruction=description, example=default)
+
+ root_node.add_child(child_node)
+
+ return root_node
diff --git a/metagpt/actions/ci/ask_review.py b/metagpt/actions/ci/ask_review.py
new file mode 100644
index 000000000..041011e80
--- /dev/null
+++ b/metagpt/actions/ci/ask_review.py
@@ -0,0 +1,62 @@
+from __future__ import annotations
+
+from typing import Tuple
+
+from metagpt.actions import Action
+from metagpt.logs import logger
+from metagpt.schema import Message, Plan
+
+
+class ReviewConst:
+ TASK_REVIEW_TRIGGER = "task"
+ CODE_REVIEW_TRIGGER = "code"
+ CONTINUE_WORDS = ["confirm", "continue", "c", "yes", "y"]
+ CHANGE_WORDS = ["change"]
+ EXIT_WORDS = ["exit"]
+ TASK_REVIEW_INSTRUCTION = (
+ f"If you want to change, add, delete a task or merge tasks in the plan, say '{CHANGE_WORDS[0]} task task_id or current task, ... (things to change)' "
+ f"If you confirm the output from the current task and wish to continue, type: {CONTINUE_WORDS[0]}"
+ )
+ CODE_REVIEW_INSTRUCTION = (
+ f"If you want the codes to be rewritten, say '{CHANGE_WORDS[0]} ... (your change advice)' "
+ f"If you want to leave it as is, type: {CONTINUE_WORDS[0]} or {CONTINUE_WORDS[1]}"
+ )
+ EXIT_INSTRUCTION = f"If you want to terminate the process, type: {EXIT_WORDS[0]}"
+
+
+class AskReview(Action):
+ async def run(
+ self, context: list[Message] = [], plan: Plan = None, trigger: str = ReviewConst.TASK_REVIEW_TRIGGER
+ ) -> Tuple[str, bool]:
+ if plan:
+ logger.info("Current overall plan:")
+ logger.info(
+ "\n".join(
+ [f"{task.task_id}: {task.instruction}, is_finished: {task.is_finished}" for task in plan.tasks]
+ )
+ )
+
+ logger.info("Most recent context:")
+ latest_action = context[-1].cause_by if context and context[-1].cause_by else ""
+ review_instruction = (
+ ReviewConst.TASK_REVIEW_INSTRUCTION
+ if trigger == ReviewConst.TASK_REVIEW_TRIGGER
+ else ReviewConst.CODE_REVIEW_INSTRUCTION
+ )
+ prompt = (
+ f"This is a <{trigger}> review. Please review output from {latest_action}\n"
+ f"{review_instruction}\n"
+ f"{ReviewConst.EXIT_INSTRUCTION}\n"
+ "Please type your review below:\n"
+ )
+
+ rsp = input(prompt)
+
+ if rsp.lower() in ReviewConst.EXIT_WORDS:
+ exit()
+
+ # Confirmation can be one of "confirm", "continue", "c", "yes", "y" exactly, or sentences containing "confirm".
+ # One could say "confirm this task, but change the next task to ..."
+ confirmed = rsp.lower() in ReviewConst.CONTINUE_WORDS or ReviewConst.CONTINUE_WORDS[0] in rsp.lower()
+
+ return rsp, confirmed
diff --git a/metagpt/actions/ci/debug_code.py b/metagpt/actions/ci/debug_code.py
new file mode 100644
index 000000000..4a6617dc6
--- /dev/null
+++ b/metagpt/actions/ci/debug_code.py
@@ -0,0 +1,109 @@
+from __future__ import annotations
+
+from metagpt.actions.ci.write_analysis_code import BaseWriteAnalysisCode
+from metagpt.logs import logger
+from metagpt.schema import Message
+from metagpt.utils.common import create_func_call_config
+
+DEBUG_REFLECTION_EXAMPLE = '''
+Example 1:
+[previous impl]:
+```python
+def add(a: int, b: int) -> int:
+ """
+ Given integers a and b, return the total value of a and b.
+ """
+ return a - b
+```
+
+[runtime Error]:
+Tested passed:
+
+Tests failed:
+assert add(1, 2) == 3 # output: -1
+assert add(1, 2) == 4 # output: -1
+
+[reflection on previous impl]:
+The implementation failed the test cases where the input integers are 1 and 2. The issue arises because the code does not add the two integers together, but instead subtracts the second integer from the first. To fix this issue, we should change the operator from `-` to `+` in the return statement. This will ensure that the function returns the correct output for the given input.
+
+[improved impl]:
+```python
+def add(a: int, b: int) -> int:
+ """
+ Given integers a and b, return the total value of a and b.
+ """
+ return a + b
+```
+'''
+
+REFLECTION_PROMPT = """
+Here is an example for you.
+{debug_example}
+[context]
+{context}
+
+[previous impl]
+{code}
+[runtime Error]
+{runtime_result}
+
+Analysis the error step by step, provide me improve method and code. Remember to follow [context] requirement. Don't forget write code for steps behind the error step.
+[reflection on previous impl]:
+xxx
+"""
+
+CODE_REFLECTION = {
+ "name": "execute_reflection_code",
+ "description": "Execute reflection code.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "reflection": {
+ "type": "string",
+ "description": "Reflection on previous impl.",
+ },
+ "improved_impl": {
+ "type": "string",
+ "description": "Refined code after reflection.",
+ },
+ },
+ "required": ["reflection", "improved_impl"],
+ },
+}
+
+
+class DebugCode(BaseWriteAnalysisCode):
+ async def run(
+ self,
+ context: list[Message] = None,
+ code: str = "",
+ runtime_result: str = "",
+ ) -> str:
+ """
+ Execute the debugging process based on the provided context, code, and runtime_result.
+
+ Args:
+ context (list[Message]): A list of Message objects representing the context.
+ code (str): The code to be debugged.
+ runtime_result (str): The result of the code execution.
+
+ Returns:
+ str: The improved implementation based on the debugging process.
+ """
+
+ info = []
+ reflection_prompt = REFLECTION_PROMPT.format(
+ debug_example=DEBUG_REFLECTION_EXAMPLE,
+ context=context,
+ code=code,
+ runtime_result=runtime_result,
+ )
+ system_prompt = "You are an AI Python assistant. You will be given your previous implementation code of a task, runtime error results, and a hint to change the implementation appropriately. Write your full implementation "
+ info.append(Message(role="system", content=system_prompt))
+ info.append(Message(role="user", content=reflection_prompt))
+
+ tool_config = create_func_call_config(CODE_REFLECTION)
+ reflection = await self.llm.aask_code(messages=info, **tool_config)
+ logger.info(f"reflection is {reflection}")
+
+ return {"code": reflection["improved_impl"]}
diff --git a/metagpt/actions/ci/execute_nb_code.py b/metagpt/actions/ci/execute_nb_code.py
new file mode 100644
index 000000000..0ff00de8f
--- /dev/null
+++ b/metagpt/actions/ci/execute_nb_code.py
@@ -0,0 +1,249 @@
+# -*- encoding: utf-8 -*-
+"""
+@Date : 2023/11/17 14:22:15
+@Author : orange-crow
+@File : execute_nb_code.py
+"""
+from __future__ import annotations
+
+import asyncio
+import base64
+import re
+import traceback
+from typing import Literal, Tuple
+
+import nbformat
+from nbclient import NotebookClient
+from nbclient.exceptions import CellTimeoutError, DeadKernelError
+from nbformat import NotebookNode
+from nbformat.v4 import new_code_cell, new_markdown_cell, new_output
+from rich.box import MINIMAL
+from rich.console import Console, Group
+from rich.live import Live
+from rich.markdown import Markdown
+from rich.panel import Panel
+from rich.syntax import Syntax
+
+from metagpt.actions import Action
+from metagpt.logs import logger
+
+
+class ExecuteNbCode(Action):
+ """execute notebook code block, return result to llm, and display it."""
+
+ nb: NotebookNode
+ nb_client: NotebookClient
+ console: Console
+ interaction: str
+ timeout: int = 600
+
+ def __init__(
+ self,
+ nb=nbformat.v4.new_notebook(),
+ timeout=600,
+ ):
+ super().__init__(
+ nb=nb,
+ nb_client=NotebookClient(nb, timeout=timeout),
+ timeout=timeout,
+ console=Console(),
+ interaction=("ipython" if self.is_ipython() else "terminal"),
+ )
+
+ async def build(self):
+ if self.nb_client.kc is None or not await self.nb_client.kc.is_alive():
+ self.nb_client.create_kernel_manager()
+ self.nb_client.start_new_kernel()
+ self.nb_client.start_new_kernel_client()
+
+ async def terminate(self):
+ """kill NotebookClient"""
+ await self.nb_client._async_cleanup_kernel()
+
+ async def reset(self):
+ """reset NotebookClient"""
+ await self.terminate()
+
+ # sleep 1s to wait for the kernel to be cleaned up completely
+ await asyncio.sleep(1)
+ await self.build()
+ self.nb_client = NotebookClient(self.nb, timeout=self.timeout)
+
+ def add_code_cell(self, code: str):
+ self.nb.cells.append(new_code_cell(source=code))
+
+ def add_markdown_cell(self, markdown: str):
+ self.nb.cells.append(new_markdown_cell(source=markdown))
+
+ def _display(self, code: str, language: Literal["python", "markdown"] = "python"):
+ if language == "python":
+ code = Syntax(code, "python", theme="paraiso-dark", line_numbers=True)
+ self.console.print(code)
+ elif language == "markdown":
+ display_markdown(code)
+ else:
+ raise ValueError(f"Only support for python, markdown, but got {language}")
+
+ def add_output_to_cell(self, cell: NotebookNode, output: str):
+ """add outputs of code execution to notebook cell."""
+ if "outputs" not in cell:
+ cell["outputs"] = []
+ else:
+ cell["outputs"].append(new_output(output_type="stream", name="stdout", text=str(output)))
+
+ def parse_outputs(self, outputs: list[str]) -> str:
+ """Parses the outputs received from notebook execution."""
+ assert isinstance(outputs, list)
+ parsed_output = ""
+
+ for i, output in enumerate(outputs):
+ if output["output_type"] == "stream" and not any(
+ tag in output["text"]
+ for tag in ["| INFO | metagpt", "| ERROR | metagpt", "| WARNING | metagpt"]
+ ):
+ parsed_output += output["text"]
+ elif output["output_type"] == "display_data":
+ if "image/png" in output["data"]:
+ self.show_bytes_figure(output["data"]["image/png"], self.interaction)
+ else:
+ logger.info(
+ f"{i}th output['data'] from nbclient outputs dont have image/png, continue next output ..."
+ )
+ elif output["output_type"] == "execute_result":
+ parsed_output += output["data"]["text/plain"]
+ return parsed_output
+
+ def show_bytes_figure(self, image_base64: str, interaction_type: Literal["ipython", None]):
+ image_bytes = base64.b64decode(image_base64)
+ if interaction_type == "ipython":
+ from IPython.display import Image, display
+
+ display(Image(data=image_bytes))
+ else:
+ import io
+
+ from PIL import Image
+
+ image = Image.open(io.BytesIO(image_bytes))
+ image.show()
+
+ def is_ipython(self) -> bool:
+ try:
+ # 如果在Jupyter Notebook中运行,__file__ 变量不存在
+ from IPython import get_ipython
+
+ if get_ipython() is not None and "IPKernelApp" in get_ipython().config:
+ return True
+ else:
+ return False
+ except NameError:
+ return False
+
+ async def run_cell(self, cell: NotebookNode, cell_index: int) -> Tuple[bool, str]:
+ """set timeout for run code.
+ returns the success or failure of the cell execution, and an optional error message.
+ """
+ try:
+ await self.nb_client.async_execute_cell(cell, cell_index)
+ return True, ""
+ except CellTimeoutError:
+ assert self.nb_client.km is not None
+ await self.nb_client.km.interrupt_kernel()
+ await asyncio.sleep(1)
+ error_msg = "Cell execution timed out: Execution exceeded the time limit and was stopped; consider optimizing your code for better performance."
+ return False, error_msg
+ except DeadKernelError:
+ await self.reset()
+ return False, "DeadKernelError"
+ except Exception:
+ return False, f"{traceback.format_exc()}"
+
+ async def run(self, code: str, language: Literal["python", "markdown"] = "python") -> Tuple[str, bool]:
+ """
+ return the output of code execution, and a success indicator (bool) of code execution.
+ """
+ self._display(code, language)
+
+ if language == "python":
+ # add code to the notebook
+ self.add_code_cell(code=code)
+
+ # build code executor
+ await self.build()
+
+ # run code
+ cell_index = len(self.nb.cells) - 1
+ success, error_message = await self.run_cell(self.nb.cells[-1], cell_index)
+
+ if not success:
+ return truncate(remove_escape_and_color_codes(error_message), is_success=success)
+
+ # code success
+ outputs = self.parse_outputs(self.nb.cells[-1].outputs)
+ outputs, success = truncate(remove_escape_and_color_codes(outputs), is_success=success)
+
+ if "!pip" in outputs:
+ success = False
+
+ return outputs, success
+
+ elif language == "markdown":
+ # add markdown content to markdown cell in a notebook.
+ self.add_markdown_cell(code)
+ # return True, beacuse there is no execution failure for markdown cell.
+ return code, True
+ else:
+ raise ValueError(f"Only support for language: python, markdown, but got {language}, ")
+
+
+def truncate(result: str, keep_len: int = 2000, is_success: bool = True):
+ """对于超出keep_len个字符的result: 执行失败的代码, 展示result后keep_len个字符; 执行成功的代码, 展示result前keep_len个字符。"""
+ if is_success:
+ desc = f"Executed code successfully. Truncated to show only first {keep_len} characters\n"
+ else:
+ desc = f"Executed code failed, please reflect the cause of bug and then debug. Truncated to show only last {keep_len} characters\n"
+
+ if result.strip().startswith(" keep_len:
+ result = result[-keep_len:] if not is_success else result[:keep_len]
+ return desc + result, is_success
+
+ return result, is_success
+
+
+def remove_escape_and_color_codes(input_str: str):
+ # 使用正则表达式去除转义字符和颜色代码
+ pattern = re.compile(r"\x1b\[[0-9;]*[mK]")
+ result = pattern.sub("", input_str)
+ return result
+
+
+def display_markdown(content: str):
+ # 使用正则表达式逐个匹配代码块
+ matches = re.finditer(r"```(.+?)```", content, re.DOTALL)
+ start_index = 0
+ content_panels = []
+ # 逐个打印匹配到的文本和代码
+ for match in matches:
+ text_content = content[start_index : match.start()].strip()
+ code_content = match.group(0).strip()[3:-3] # Remove triple backticks
+
+ if text_content:
+ content_panels.append(Panel(Markdown(text_content), box=MINIMAL))
+
+ if code_content:
+ content_panels.append(Panel(Markdown(f"```{code_content}"), box=MINIMAL))
+ start_index = match.end()
+
+ # 打印剩余文本(如果有)
+ remaining_text = content[start_index:].strip()
+ if remaining_text:
+ content_panels.append(Panel(Markdown(remaining_text), box=MINIMAL))
+
+ # 在Live模式中显示所有Panel
+ with Live(auto_refresh=False, console=Console(), vertical_overflow="visible") as live:
+ live.update(Group(*content_panels))
+ live.refresh()
diff --git a/metagpt/actions/ci/ml_action.py b/metagpt/actions/ci/ml_action.py
new file mode 100644
index 000000000..e18d0fd20
--- /dev/null
+++ b/metagpt/actions/ci/ml_action.py
@@ -0,0 +1,70 @@
+from __future__ import annotations
+
+from typing import Tuple
+
+from metagpt.actions import Action
+from metagpt.actions.ci.write_analysis_code import WriteCodeWithTools
+from metagpt.prompts.ci.ml_action import (
+ ML_GENERATE_CODE_PROMPT,
+ ML_TOOL_USAGE_PROMPT,
+ PRINT_DATA_COLUMNS,
+ UPDATE_DATA_COLUMNS,
+)
+from metagpt.prompts.ci.write_analysis_code import CODE_GENERATOR_WITH_TOOLS
+from metagpt.schema import Message, Plan
+from metagpt.utils.common import create_func_call_config, remove_comments
+
+
+class WriteCodeWithToolsML(WriteCodeWithTools):
+ async def run(
+ self,
+ context: list[Message],
+ plan: Plan = None,
+ column_info: str = "",
+ **kwargs,
+ ) -> Tuple[list[Message], str]:
+ # prepare tool schemas and tool-type-specific instruction
+ tool_schemas, tool_type_usage_prompt = await self._prepare_tools(plan=plan)
+
+ # ML-specific variables to be used in prompt
+ finished_tasks = plan.get_finished_tasks()
+ code_context = [remove_comments(task.code) for task in finished_tasks]
+ code_context = "\n\n".join(code_context)
+
+ # prepare prompt depending on tool availability & LLM call
+ if tool_schemas:
+ prompt = ML_TOOL_USAGE_PROMPT.format(
+ user_requirement=plan.goal,
+ history_code=code_context,
+ current_task=plan.current_task.instruction,
+ column_info=column_info,
+ tool_type_usage_prompt=tool_type_usage_prompt,
+ tool_schemas=tool_schemas,
+ )
+
+ else:
+ prompt = ML_GENERATE_CODE_PROMPT.format(
+ user_requirement=plan.goal,
+ history_code=code_context,
+ current_task=plan.current_task.instruction,
+ column_info=column_info,
+ tool_type_usage_prompt=tool_type_usage_prompt,
+ )
+ tool_config = create_func_call_config(CODE_GENERATOR_WITH_TOOLS)
+ rsp = await self.llm.aask_code(prompt, **tool_config)
+
+ # Extra output to be used for potential debugging
+ context = [Message(content=prompt, role="user")]
+
+ return context, rsp
+
+
+class UpdateDataColumns(Action):
+ async def run(self, plan: Plan = None) -> dict:
+ finished_tasks = plan.get_finished_tasks()
+ code_context = [remove_comments(task.code) for task in finished_tasks]
+ code_context = "\n\n".join(code_context)
+ prompt = UPDATE_DATA_COLUMNS.format(history_code=code_context)
+ tool_config = create_func_call_config(PRINT_DATA_COLUMNS)
+ rsp = await self.llm.aask_code(prompt, **tool_config)
+ return rsp
diff --git a/metagpt/actions/ci/write_analysis_code.py b/metagpt/actions/ci/write_analysis_code.py
new file mode 100644
index 000000000..421eb0804
--- /dev/null
+++ b/metagpt/actions/ci/write_analysis_code.py
@@ -0,0 +1,155 @@
+# -*- encoding: utf-8 -*-
+"""
+@Date : 2023/11/20 13:19:39
+@Author : orange-crow
+@File : write_analysis_code.py
+"""
+from __future__ import annotations
+
+from typing import Tuple
+
+from metagpt.actions import Action
+from metagpt.logs import logger
+from metagpt.prompts.ci.write_analysis_code import (
+ CODE_GENERATOR_WITH_TOOLS,
+ SELECT_FUNCTION_TOOLS,
+ TOOL_RECOMMENDATION_PROMPT,
+ TOOL_USAGE_PROMPT,
+)
+from metagpt.schema import Message, Plan, SystemMessage
+from metagpt.tools import TOOL_REGISTRY
+from metagpt.tools.tool_registry import validate_tool_names
+from metagpt.utils.common import create_func_call_config
+
+
+class BaseWriteAnalysisCode(Action):
+ DEFAULT_SYSTEM_MSG: str = """You are Code Interpreter, a world-class programmer that can complete any goal by executing code. Strictly follow the plan and generate code step by step. Each step of the code will be executed on the user's machine, and the user will provide the code execution results to you.**Notice: The code for the next step depends on the code for the previous step. Must reuse variables in the lastest other code directly, dont creat it again, it is very import for you. Use !pip install in a standalone block to install missing packages.Usually the libraries you need are already installed.Dont check if packages already imported.**""" # prompt reference: https://github.com/KillianLucas/open-interpreter/blob/v0.1.4/interpreter/system_message.txt
+ # REUSE_CODE_INSTRUCTION = """ATTENTION: DONT include codes from previous tasks in your current code block, include new codes only, DONT repeat codes!"""
+
+ def insert_system_message(self, context: list[Message], system_msg: str = None):
+ system_msg = system_msg or self.DEFAULT_SYSTEM_MSG
+ context.insert(0, SystemMessage(content=system_msg)) if context[0].role != "system" else None
+ return context
+
+ async def run(self, context: list[Message], plan: Plan = None) -> dict:
+ """Run of a code writing action, used in data analysis or modeling
+
+ Args:
+ context (list[Message]): Action output history, source action denoted by Message.cause_by
+ plan (Plan, optional): Overall plan. Defaults to None.
+
+ Returns:
+ dict: code result in the format of {"code": "print('hello world')", "language": "python"}
+ """
+ raise NotImplementedError
+
+
+class WriteCodeWithoutTools(BaseWriteAnalysisCode):
+ """Ask LLM to generate codes purely by itself without local user-defined tools"""
+
+ async def run(self, context: list[Message], plan: Plan = None, system_msg: str = None, **kwargs) -> dict:
+ messages = self.insert_system_message(context, system_msg)
+ rsp = await self.llm.aask_code(messages, **kwargs)
+ return rsp
+
+
+class WriteCodeWithTools(BaseWriteAnalysisCode):
+ """Write code with help of local available tools. Choose tools first, then generate code to use the tools"""
+
+ # selected tools to choose from, listed by their names. An empty list means selection from all tools.
+ selected_tools: list[str] = []
+
+ def _get_tools_by_type(self, tool_type: str) -> dict:
+ """
+ Retreive tools by tool type from registry, but filtered by pre-selected tool list
+
+ Args:
+ tool_type (str): Tool type to retrieve from the registry
+
+ Returns:
+ dict: A dict of tool name to Tool object, representing available tools under the type
+ """
+ candidate_tools = TOOL_REGISTRY.get_tools_by_type(tool_type)
+ if self.selected_tools:
+ candidate_tool_names = set(self.selected_tools) & candidate_tools.keys()
+ candidate_tools = {tool_name: candidate_tools[tool_name] for tool_name in candidate_tool_names}
+ return candidate_tools
+
+ async def _recommend_tool(
+ self,
+ task: str,
+ available_tools: dict,
+ ) -> dict:
+ """
+ Recommend tools for the specified task.
+
+ Args:
+ task (str): the task to recommend tools for
+ available_tools (dict): the available tools description
+
+ Returns:
+ dict: schemas of recommended tools for the specified task
+ """
+ prompt = TOOL_RECOMMENDATION_PROMPT.format(
+ current_task=task,
+ available_tools=available_tools,
+ )
+ tool_config = create_func_call_config(SELECT_FUNCTION_TOOLS)
+ rsp = await self.llm.aask_code(prompt, **tool_config)
+ recommend_tools = rsp["recommend_tools"]
+ logger.info(f"Recommended tools: \n{recommend_tools}")
+
+ # Parses and validates the recommended tools, for LLM might hallucinate and recommend non-existing tools
+ valid_tools = validate_tool_names(recommend_tools, return_tool_object=True)
+
+ tool_schemas = {tool.name: tool.schemas for tool in valid_tools}
+
+ return tool_schemas
+
+ async def _prepare_tools(self, plan: Plan) -> Tuple[dict, str]:
+ """Prepare tool schemas and usage instructions according to current task
+
+ Args:
+ plan (Plan): The overall plan containing task information.
+
+ Returns:
+ Tuple[dict, str]: A tool schemas ({tool_name: tool_schema_dict}) and a usage prompt for the type of tools selected
+ """
+ # find tool type from task type through exact match, can extend to retrieval in the future
+ tool_type = plan.current_task.task_type
+
+ # prepare tool-type-specific instruction
+ tool_type_usage_prompt = (
+ TOOL_REGISTRY.get_tool_type(tool_type).usage_prompt if TOOL_REGISTRY.has_tool_type(tool_type) else ""
+ )
+
+ # prepare schemas of available tools
+ tool_schemas = {}
+ available_tools = self._get_tools_by_type(tool_type)
+ if available_tools:
+ available_tools = {tool_name: tool.schemas["description"] for tool_name, tool in available_tools.items()}
+ tool_schemas = await self._recommend_tool(plan.current_task.instruction, available_tools)
+
+ return tool_schemas, tool_type_usage_prompt
+
+ async def run(
+ self,
+ context: list[Message],
+ plan: Plan,
+ **kwargs,
+ ) -> str:
+ # prepare tool schemas and tool-type-specific instruction
+ tool_schemas, tool_type_usage_prompt = await self._prepare_tools(plan=plan)
+
+ # form a complete tool usage instruction and include it as a message in context
+ tools_instruction = TOOL_USAGE_PROMPT.format(
+ tool_schemas=tool_schemas, tool_type_usage_prompt=tool_type_usage_prompt
+ )
+ context.append(Message(content=tools_instruction, role="user"))
+
+ # prepare prompt & LLM call
+ prompt = self.insert_system_message(context)
+ tool_config = create_func_call_config(CODE_GENERATOR_WITH_TOOLS)
+ rsp = await self.llm.aask_code(prompt, **tool_config)
+
+ return rsp
diff --git a/metagpt/actions/ci/write_plan.py b/metagpt/actions/ci/write_plan.py
new file mode 100644
index 000000000..dd9363260
--- /dev/null
+++ b/metagpt/actions/ci/write_plan.py
@@ -0,0 +1,116 @@
+# -*- encoding: utf-8 -*-
+"""
+@Date : 2023/11/20 11:24:03
+@Author : orange-crow
+@File : plan.py
+"""
+from __future__ import annotations
+
+import json
+from copy import deepcopy
+from typing import Tuple
+
+from metagpt.actions import Action
+from metagpt.logs import logger
+from metagpt.prompts.ci.write_analysis_code import (
+ ASSIGN_TASK_TYPE_CONFIG,
+ ASSIGN_TASK_TYPE_PROMPT,
+)
+from metagpt.schema import Message, Plan, Task
+from metagpt.tools import TOOL_REGISTRY
+from metagpt.utils.common import CodeParser, create_func_call_config
+
+
+class WritePlan(Action):
+ PROMPT_TEMPLATE: str = """
+ # Context:
+ __context__
+ # Task:
+ Based on the context, write a plan or modify an existing plan of what you should do to achieve the goal. A plan consists of one to __max_tasks__ tasks.
+ If you are modifying an existing plan, carefully follow the instruction, don't make unnecessary changes. Give the whole plan unless instructed to modify only one task of the plan.
+ If you encounter errors on the current task, revise and output the current single task only.
+ Output a list of jsons following the format:
+ ```json
+ [
+ {
+ "task_id": str = "unique identifier for a task in plan, can be an ordinal",
+ "dependent_task_ids": list[str] = "ids of tasks prerequisite to this task",
+ "instruction": "what you should do in this task, one short phrase or sentence",
+ },
+ ...
+ ]
+ ```
+ """
+
+ async def assign_task_type(self, tasks: list[dict]) -> str:
+ """Assign task type to each task in tasks
+
+ Args:
+ tasks (list[dict]): tasks to be assigned task type
+
+ Returns:
+ str: tasks with task type assigned in a json string
+ """
+ task_info = "\n".join([f"Task {task['task_id']}: {task['instruction']}" for task in tasks])
+ task_type_desc = "\n".join(
+ [f"- **{tool_type.name}**: {tool_type.desc}" for tool_type in TOOL_REGISTRY.get_tool_types().values()]
+ ) # task type are binded with tool type now, should be improved in the future
+ prompt = ASSIGN_TASK_TYPE_PROMPT.format(
+ task_info=task_info, task_type_desc=task_type_desc
+ ) # task types are set to be the same as tool types, for now
+ tool_config = create_func_call_config(ASSIGN_TASK_TYPE_CONFIG)
+ rsp = await self.llm.aask_code(prompt, **tool_config)
+ task_type_list = rsp["task_type"]
+ logger.info(f"assigned task types: {task_type_list}")
+ for task, task_type in zip(tasks, task_type_list):
+ task["task_type"] = task_type
+ return json.dumps(tasks)
+
+ async def run(self, context: list[Message], max_tasks: int = 5, use_tools: bool = False) -> str:
+ prompt = (
+ self.PROMPT_TEMPLATE.replace("__context__", "\n".join([str(ct) for ct in context]))
+ # .replace("__current_plan__", current_plan)
+ .replace("__max_tasks__", str(max_tasks))
+ )
+ rsp = await self._aask(prompt)
+ rsp = CodeParser.parse_code(block=None, text=rsp)
+ if use_tools:
+ rsp = await self.assign_task_type(json.loads(rsp))
+ return rsp
+
+
+def rsp_to_tasks(rsp: str) -> list[Task]:
+ rsp = json.loads(rsp)
+ tasks = [Task(**task_config) for task_config in rsp]
+ return tasks
+
+
+def update_plan_from_rsp(rsp: str, current_plan: Plan):
+ tasks = rsp_to_tasks(rsp)
+ if len(tasks) == 1 or tasks[0].dependent_task_ids:
+ if tasks[0].dependent_task_ids and len(tasks) > 1:
+ # tasks[0].dependent_task_ids means the generated tasks are not a complete plan
+ # for they depend on tasks in the current plan, in this case, we only support updating one task each time
+ logger.warning(
+ "Current plan will take only the first generated task if the generated tasks are not a complete plan"
+ )
+ # handle a single task
+ if current_plan.has_task_id(tasks[0].task_id):
+ # replace an existing task
+ current_plan.replace_task(tasks[0])
+ else:
+ # append one task
+ current_plan.append_task(tasks[0])
+
+ else:
+ # add tasks in general
+ current_plan.add_tasks(tasks)
+
+
+def precheck_update_plan_from_rsp(rsp: str, current_plan: Plan) -> Tuple[bool, str]:
+ temp_plan = deepcopy(current_plan)
+ try:
+ update_plan_from_rsp(rsp, temp_plan)
+ return True, ""
+ except Exception as e:
+ return False, e
diff --git a/metagpt/actions/debug_error.py b/metagpt/actions/debug_error.py
index f491fdd55..5ed31bed8 100644
--- a/metagpt/actions/debug_error.py
+++ b/metagpt/actions/debug_error.py
@@ -49,7 +49,7 @@ class DebugError(Action):
i_context: RunCodeContext = Field(default_factory=RunCodeContext)
async def run(self, *args, **kwargs) -> str:
- output_doc = await self.project_repo.test_outputs.get(filename=self.i_context.output_filename)
+ output_doc = await self.repo.test_outputs.get(filename=self.i_context.output_filename)
if not output_doc:
return ""
output_detail = RunCodeResult.loads(output_doc.content)
@@ -59,12 +59,12 @@ class DebugError(Action):
return ""
logger.info(f"Debug and rewrite {self.i_context.test_filename}")
- code_doc = await self.project_repo.with_src_path(self.context.src_workspace).srcs.get(
+ code_doc = await self.repo.with_src_path(self.context.src_workspace).srcs.get(
filename=self.i_context.code_filename
)
if not code_doc:
return ""
- test_doc = await self.project_repo.tests.get(filename=self.i_context.test_filename)
+ test_doc = await self.repo.tests.get(filename=self.i_context.test_filename)
if not test_doc:
return ""
prompt = PROMPT_TEMPLATE.format(code=code_doc.content, test_code=test_doc.content, logs=output_detail.stderr)
diff --git a/metagpt/actions/design_api.py b/metagpt/actions/design_api.py
index 04c580226..e5f038c7c 100644
--- a/metagpt/actions/design_api.py
+++ b/metagpt/actions/design_api.py
@@ -14,7 +14,14 @@ from pathlib import Path
from typing import Optional
from metagpt.actions import Action, ActionOutput
-from metagpt.actions.design_api_an import DESIGN_API_NODE
+from metagpt.actions.design_api_an import (
+ DATA_STRUCTURES_AND_INTERFACES,
+ DESIGN_API_NODE,
+ PROGRAM_CALL_FLOW,
+ REFINED_DATA_STRUCTURES_AND_INTERFACES,
+ REFINED_DESIGN_NODE,
+ REFINED_PROGRAM_CALL_FLOW,
+)
from metagpt.const import DATA_API_DESIGN_FILE_REPO, SEQ_FLOW_FILE_REPO
from metagpt.logs import logger
from metagpt.schema import Document, Documents, Message
@@ -39,11 +46,11 @@ class WriteDesign(Action):
)
async def run(self, with_messages: Message, schema: str = None):
- # Use `git status` to identify which PRD documents have been modified in the `docs/prds` directory.
- changed_prds = self.project_repo.docs.prd.changed_files
+ # Use `git status` to identify which PRD documents have been modified in the `docs/prd` directory.
+ changed_prds = self.repo.docs.prd.changed_files
# Use `git status` to identify which design documents in the `docs/system_designs` directory have undergone
# changes.
- changed_system_designs = self.project_repo.docs.system_design.changed_files
+ changed_system_designs = self.repo.docs.system_design.changed_files
# For those PRDs and design documents that have undergone changes, regenerate the design content.
changed_files = Documents()
@@ -68,46 +75,46 @@ class WriteDesign(Action):
async def _merge(self, prd_doc, system_design_doc):
context = NEW_REQ_TEMPLATE.format(old_design=system_design_doc.content, context=prd_doc.content)
- node = await DESIGN_API_NODE.fill(context=context, llm=self.llm)
+ node = await REFINED_DESIGN_NODE.fill(context=context, llm=self.llm)
system_design_doc.content = node.instruct_content.model_dump_json()
return system_design_doc
async def _update_system_design(self, filename) -> Document:
- prd = await self.project_repo.docs.prd.get(filename)
- old_system_design_doc = await self.project_repo.docs.system_design.get(filename)
+ prd = await self.repo.docs.prd.get(filename)
+ old_system_design_doc = await self.repo.docs.system_design.get(filename)
if not old_system_design_doc:
system_design = await self._new_system_design(context=prd.content)
- doc = await self.project_repo.docs.system_design.save(
+ doc = await self.repo.docs.system_design.save(
filename=filename,
content=system_design.instruct_content.model_dump_json(),
dependencies={prd.root_relative_path},
)
else:
doc = await self._merge(prd_doc=prd, system_design_doc=old_system_design_doc)
- await self.project_repo.docs.system_design.save_doc(doc=doc, dependencies={prd.root_relative_path})
+ await self.repo.docs.system_design.save_doc(doc=doc, dependencies={prd.root_relative_path})
await self._save_data_api_design(doc)
await self._save_seq_flow(doc)
- await self.project_repo.resources.system_design.save_pdf(doc=doc)
+ await self.repo.resources.system_design.save_pdf(doc=doc)
return doc
async def _save_data_api_design(self, design_doc):
m = json.loads(design_doc.content)
- data_api_design = m.get("Data structures and interfaces")
+ data_api_design = m.get(DATA_STRUCTURES_AND_INTERFACES.key) or m.get(REFINED_DATA_STRUCTURES_AND_INTERFACES.key)
if not data_api_design:
return
- pathname = self.project_repo.workdir / DATA_API_DESIGN_FILE_REPO / Path(design_doc.filename).with_suffix("")
+ pathname = self.repo.workdir / DATA_API_DESIGN_FILE_REPO / Path(design_doc.filename).with_suffix("")
await self._save_mermaid_file(data_api_design, pathname)
logger.info(f"Save class view to {str(pathname)}")
async def _save_seq_flow(self, design_doc):
m = json.loads(design_doc.content)
- seq_flow = m.get("Program call flow")
+ seq_flow = m.get(PROGRAM_CALL_FLOW.key) or m.get(REFINED_PROGRAM_CALL_FLOW.key)
if not seq_flow:
return
- pathname = self.project_repo.workdir / Path(SEQ_FLOW_FILE_REPO) / Path(design_doc.filename).with_suffix("")
+ pathname = self.repo.workdir / Path(SEQ_FLOW_FILE_REPO) / Path(design_doc.filename).with_suffix("")
await self._save_mermaid_file(seq_flow, pathname)
logger.info(f"Saving sequence flow to {str(pathname)}")
async def _save_mermaid_file(self, data: str, pathname: Path):
pathname.parent.mkdir(parents=True, exist_ok=True)
- await mermaid_to_file(self.config.mermaid_engine, data, pathname)
+ await mermaid_to_file(self.config.mermaid.engine, data, pathname)
diff --git a/metagpt/actions/design_api_an.py b/metagpt/actions/design_api_an.py
index 3737203cf..35b50ef8f 100644
--- a/metagpt/actions/design_api_an.py
+++ b/metagpt/actions/design_api_an.py
@@ -8,6 +8,7 @@
from typing import List
from metagpt.actions.action_node import ActionNode
+from metagpt.logs import logger
from metagpt.utils.mermaid import MMC1, MMC2
IMPLEMENTATION_APPROACH = ActionNode(
@@ -17,6 +18,15 @@ IMPLEMENTATION_APPROACH = ActionNode(
example="We will ...",
)
+REFINED_IMPLEMENTATION_APPROACH = ActionNode(
+ key="Refined Implementation Approach",
+ expected_type=str,
+ instruction="Update and extend the original implementation approach to reflect the evolving challenges and "
+ "requirements due to incremental development. Outline the steps involved in the implementation process with the "
+ "detailed strategies.",
+ example="We will refine ...",
+)
+
PROJECT_NAME = ActionNode(
key="Project name", expected_type=str, instruction="The project name with underline", example="game_2048"
)
@@ -28,6 +38,14 @@ FILE_LIST = ActionNode(
example=["main.py", "game.py"],
)
+REFINED_FILE_LIST = ActionNode(
+ key="Refined File list",
+ expected_type=List[str],
+ instruction="Update and expand the original file list including only relative paths. Up to 2 files can be added."
+ "Ensure that the refined file list reflects the evolving structure of the project.",
+ example=["main.py", "game.py", "new_feature.py"],
+)
+
DATA_STRUCTURES_AND_INTERFACES = ActionNode(
key="Data structures and interfaces",
expected_type=str,
@@ -37,6 +55,16 @@ DATA_STRUCTURES_AND_INTERFACES = ActionNode(
example=MMC1,
)
+REFINED_DATA_STRUCTURES_AND_INTERFACES = ActionNode(
+ key="Refined Data structures and interfaces",
+ expected_type=str,
+ instruction="Update and extend the existing mermaid classDiagram code syntax to incorporate new classes, "
+ "methods (including __init__), and functions with precise type annotations. Delineate additional "
+ "relationships between classes, ensuring clarity and adherence to PEP8 standards."
+ "Retain content that is not related to incremental development but important for consistency and clarity.",
+ example=MMC1,
+)
+
PROGRAM_CALL_FLOW = ActionNode(
key="Program call flow",
expected_type=str,
@@ -45,6 +73,16 @@ PROGRAM_CALL_FLOW = ActionNode(
example=MMC2,
)
+REFINED_PROGRAM_CALL_FLOW = ActionNode(
+ key="Refined Program call flow",
+ expected_type=str,
+ instruction="Extend the existing sequenceDiagram code syntax with detailed information, accurately covering the"
+ "CRUD and initialization of each object. Ensure correct syntax usage and reflect the incremental changes introduced"
+ "in the classes and API defined above. "
+ "Retain content that is not related to incremental development but important for consistency and clarity.",
+ example=MMC2,
+)
+
ANYTHING_UNCLEAR = ActionNode(
key="Anything UNCLEAR",
expected_type=str,
@@ -61,4 +99,24 @@ NODES = [
ANYTHING_UNCLEAR,
]
+REFINED_NODES = [
+ REFINED_IMPLEMENTATION_APPROACH,
+ REFINED_FILE_LIST,
+ REFINED_DATA_STRUCTURES_AND_INTERFACES,
+ REFINED_PROGRAM_CALL_FLOW,
+ ANYTHING_UNCLEAR,
+]
+
DESIGN_API_NODE = ActionNode.from_children("DesignAPI", NODES)
+REFINED_DESIGN_NODE = ActionNode.from_children("RefinedDesignAPI", REFINED_NODES)
+
+
+def main():
+ prompt = DESIGN_API_NODE.compile(context="")
+ logger.info(prompt)
+ prompt = REFINED_DESIGN_NODE.compile(context="")
+ logger.info(prompt)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/metagpt/actions/prepare_documents.py b/metagpt/actions/prepare_documents.py
index 56c587cb3..ab069dc11 100644
--- a/metagpt/actions/prepare_documents.py
+++ b/metagpt/actions/prepare_documents.py
@@ -15,6 +15,7 @@ from metagpt.actions import Action, ActionOutput
from metagpt.const import REQUIREMENT_FILENAME
from metagpt.utils.file_repository import FileRepository
from metagpt.utils.git_repository import GitRepository
+from metagpt.utils.project_repo import ProjectRepo
class PrepareDocuments(Action):
@@ -38,13 +39,14 @@ class PrepareDocuments(Action):
shutil.rmtree(path)
self.config.project_path = path
self.context.git_repo = GitRepository(local_path=path, auto_init=True)
+ self.context.repo = ProjectRepo(self.context.git_repo)
async def run(self, with_messages, **kwargs):
"""Create and initialize the workspace folder, initialize the Git environment."""
self._init_repo()
# Write the newly added requirements from the main parameter idea to `docs/requirement.txt`.
- doc = await self.project_repo.docs.save(filename=REQUIREMENT_FILENAME, content=with_messages[0].content)
+ doc = await self.repo.docs.save(filename=REQUIREMENT_FILENAME, content=with_messages[0].content)
# Send a Message notification to the WritePRD action, instructing it to process requirements using
- # `docs/requirement.txt` and `docs/prds/`.
+ # `docs/requirement.txt` and `docs/prd/`.
return ActionOutput(content=doc.content, instruct_content=doc)
diff --git a/metagpt/actions/project_management.py b/metagpt/actions/project_management.py
index 9ada629be..67a614d6f 100644
--- a/metagpt/actions/project_management.py
+++ b/metagpt/actions/project_management.py
@@ -13,16 +13,16 @@
import json
from typing import Optional
-from metagpt.actions import ActionOutput
from metagpt.actions.action import Action
-from metagpt.actions.project_management_an import PM_NODE
+from metagpt.actions.action_output import ActionOutput
+from metagpt.actions.project_management_an import PM_NODE, REFINED_PM_NODE
from metagpt.const import PACKAGE_REQUIREMENTS_FILENAME
from metagpt.logs import logger
from metagpt.schema import Document, Documents
NEW_REQ_TEMPLATE = """
### Legacy Content
-{old_tasks}
+{old_task}
### New Requirements
{context}
@@ -34,8 +34,8 @@ class WriteTasks(Action):
i_context: Optional[str] = None
async def run(self, with_messages):
- changed_system_designs = self.project_repo.docs.system_design.changed_files
- changed_tasks = self.project_repo.docs.task.changed_files
+ changed_system_designs = self.repo.docs.system_design.changed_files
+ changed_tasks = self.repo.docs.task.changed_files
change_files = Documents()
# Rewrite the system designs that have undergone changes based on the git head diff under
# `docs/system_designs/`.
@@ -57,16 +57,14 @@ class WriteTasks(Action):
return ActionOutput(content=change_files.model_dump_json(), instruct_content=change_files)
async def _update_tasks(self, filename):
- system_design_doc = await self.project_repo.docs.system_design.get(filename)
- task_doc = await self.project_repo.docs.task.get(filename)
+ system_design_doc = await self.repo.docs.system_design.get(filename)
+ task_doc = await self.repo.docs.task.get(filename)
if task_doc:
task_doc = await self._merge(system_design_doc=system_design_doc, task_doc=task_doc)
- await self.project_repo.docs.task.save_doc(
- doc=task_doc, dependencies={system_design_doc.root_relative_path}
- )
+ await self.repo.docs.task.save_doc(doc=task_doc, dependencies={system_design_doc.root_relative_path})
else:
rsp = await self._run_new_tasks(context=system_design_doc.content)
- task_doc = await self.project_repo.docs.task.save(
+ task_doc = await self.repo.docs.task.save(
filename=filename,
content=rsp.instruct_content.model_dump_json(),
dependencies={system_design_doc.root_relative_path},
@@ -79,15 +77,15 @@ class WriteTasks(Action):
return node
async def _merge(self, system_design_doc, task_doc) -> Document:
- context = NEW_REQ_TEMPLATE.format(context=system_design_doc.content, old_tasks=task_doc.content)
- node = await PM_NODE.fill(context, self.llm, schema=self.prompt_schema)
+ context = NEW_REQ_TEMPLATE.format(context=system_design_doc.content, old_task=task_doc.content)
+ node = await REFINED_PM_NODE.fill(context, self.llm, schema=self.prompt_schema)
task_doc.content = node.instruct_content.model_dump_json()
return task_doc
async def _update_requirements(self, doc):
m = json.loads(doc.content)
- packages = set(m.get("Required Python third-party packages", set()))
- requirement_doc = await self.project_repo.get(filename=PACKAGE_REQUIREMENTS_FILENAME)
+ packages = set(m.get("Required Python packages", set()))
+ requirement_doc = await self.repo.get(filename=PACKAGE_REQUIREMENTS_FILENAME)
if not requirement_doc:
requirement_doc = Document(filename=PACKAGE_REQUIREMENTS_FILENAME, root_path=".", content="")
lines = requirement_doc.content.splitlines()
@@ -95,4 +93,4 @@ class WriteTasks(Action):
if pkg == "":
continue
packages.add(pkg)
- await self.project_repo.save(filename=PACKAGE_REQUIREMENTS_FILENAME, content="\n".join(packages))
+ await self.repo.save(filename=PACKAGE_REQUIREMENTS_FILENAME, content="\n".join(packages))
diff --git a/metagpt/actions/project_management_an.py b/metagpt/actions/project_management_an.py
index 215a67202..379a23384 100644
--- a/metagpt/actions/project_management_an.py
+++ b/metagpt/actions/project_management_an.py
@@ -35,6 +35,20 @@ LOGIC_ANALYSIS = ActionNode(
],
)
+REFINED_LOGIC_ANALYSIS = ActionNode(
+ key="Refined Logic Analysis",
+ expected_type=List[List[str]],
+ instruction="Review and refine the logic analysis by merging the Legacy Content and Incremental Content. "
+ "Provide a comprehensive list of files with classes/methods/functions to be implemented or modified incrementally. "
+ "Include dependency analysis, consider potential impacts on existing code, and document necessary imports.",
+ example=[
+ ["game.py", "Contains Game class and ... functions"],
+ ["main.py", "Contains main function, from game import Game"],
+ ["new_feature.py", "Introduces NewFeature class and related functions"],
+ ["utils.py", "Modifies existing utility functions to support incremental changes"],
+ ],
+)
+
TASK_LIST = ActionNode(
key="Task list",
expected_type=List[str],
@@ -42,6 +56,15 @@ TASK_LIST = ActionNode(
example=["game.py", "main.py"],
)
+REFINED_TASK_LIST = ActionNode(
+ key="Refined Task list",
+ expected_type=List[str],
+ instruction="Review and refine the combined task list after the merger of Legacy Content and Incremental Content, "
+ "and consistent with Refined File List. Ensure that tasks are organized in a logical and prioritized order, "
+ "considering dependencies for a streamlined and efficient development process. ",
+ example=["new_feature.py", "utils", "game.py", "main.py"],
+)
+
FULL_API_SPEC = ActionNode(
key="Full API spec",
expected_type=str,
@@ -54,9 +77,19 @@ SHARED_KNOWLEDGE = ActionNode(
key="Shared Knowledge",
expected_type=str,
instruction="Detail any shared knowledge, like common utility functions or configuration variables.",
- example="'game.py' contains functions shared across the project.",
+ example="`game.py` contains functions shared across the project.",
)
+REFINED_SHARED_KNOWLEDGE = ActionNode(
+ key="Refined Shared Knowledge",
+ expected_type=str,
+ instruction="Update and expand shared knowledge to reflect any new elements introduced. This includes common "
+ "utility functions, configuration variables for team collaboration. Retain content that is not related to "
+ "incremental development but important for consistency and clarity.",
+ example="`new_module.py` enhances shared utility functions for improved code reusability and collaboration.",
+)
+
+
ANYTHING_UNCLEAR_PM = ActionNode(
key="Anything UNCLEAR",
expected_type=str,
@@ -74,13 +107,25 @@ NODES = [
ANYTHING_UNCLEAR_PM,
]
+REFINED_NODES = [
+ REQUIRED_PYTHON_PACKAGES,
+ REQUIRED_OTHER_LANGUAGE_PACKAGES,
+ REFINED_LOGIC_ANALYSIS,
+ REFINED_TASK_LIST,
+ FULL_API_SPEC,
+ REFINED_SHARED_KNOWLEDGE,
+ ANYTHING_UNCLEAR_PM,
+]
PM_NODE = ActionNode.from_children("PM_NODE", NODES)
+REFINED_PM_NODE = ActionNode.from_children("REFINED_PM_NODE", REFINED_NODES)
def main():
prompt = PM_NODE.compile(context="")
logger.info(prompt)
+ prompt = REFINED_PM_NODE.compile(context="")
+ logger.info(prompt)
if __name__ == "__main__":
diff --git a/metagpt/actions/research.py b/metagpt/actions/research.py
index 2755628c9..ce8d8a967 100644
--- a/metagpt/actions/research.py
+++ b/metagpt/actions/research.py
@@ -3,15 +3,15 @@
from __future__ import annotations
import asyncio
-from typing import Callable, Optional, Union
+from typing import Any, Callable, Optional, Union
-from pydantic import Field, parse_obj_as
+from pydantic import TypeAdapter, model_validator
from metagpt.actions import Action
from metagpt.config2 import config
from metagpt.logs import logger
from metagpt.tools.search_engine import SearchEngine
-from metagpt.tools.web_browser_engine import WebBrowserEngine, WebBrowserEngineType
+from metagpt.tools.web_browser_engine import WebBrowserEngine
from metagpt.utils.common import OutputParser
from metagpt.utils.text import generate_prompt_chunk, reduce_message_length
@@ -81,10 +81,16 @@ class CollectLinks(Action):
name: str = "CollectLinks"
i_context: Optional[str] = None
desc: str = "Collect links from a search engine."
-
- search_engine: SearchEngine = Field(default_factory=SearchEngine)
+ search_func: Optional[Any] = None
+ search_engine: Optional[SearchEngine] = None
rank_func: Optional[Callable[[list[str]], None]] = None
+ @model_validator(mode="after")
+ def validate_engine_and_run_func(self):
+ if self.search_engine is None:
+ self.search_engine = SearchEngine.from_search_config(self.config.search, proxy=self.config.proxy)
+ return self
+
async def run(
self,
topic: str,
@@ -107,7 +113,7 @@ class CollectLinks(Action):
keywords = await self._aask(SEARCH_TOPIC_PROMPT, [system_text])
try:
keywords = OutputParser.extract_struct(keywords, list)
- keywords = parse_obj_as(list[str], keywords)
+ keywords = TypeAdapter(list[str]).validate_python(keywords)
except Exception as e:
logger.exception(f"fail to get keywords related to the research topic '{topic}' for {e}")
keywords = [topic]
@@ -127,13 +133,13 @@ class CollectLinks(Action):
if len(remove) == 0:
break
- model_name = config.get_openai_llm().model
+ model_name = config.llm.model
prompt = reduce_message_length(gen_msg(), model_name, system_text, 4096)
logger.debug(prompt)
queries = await self._aask(prompt, [system_text])
try:
queries = OutputParser.extract_struct(queries, list)
- queries = parse_obj_as(list[str], queries)
+ queries = TypeAdapter(list[str]).validate_python(queries)
except Exception as e:
logger.exception(f"fail to break down the research question due to {e}")
queries = keywords
@@ -178,15 +184,17 @@ class WebBrowseAndSummarize(Action):
i_context: Optional[str] = None
desc: str = "Explore the web and provide summaries of articles and webpages."
browse_func: Union[Callable[[list[str]], None], None] = None
- web_browser_engine: Optional[WebBrowserEngine] = WebBrowserEngineType.PLAYWRIGHT
+ web_browser_engine: Optional[WebBrowserEngine] = None
- def __init__(self, **kwargs):
- super().__init__(**kwargs)
-
- self.web_browser_engine = WebBrowserEngine(
- engine=WebBrowserEngineType.CUSTOM if self.browse_func else WebBrowserEngineType.PLAYWRIGHT,
- run_func=self.browse_func,
- )
+ @model_validator(mode="after")
+ def validate_engine_and_run_func(self):
+ if self.web_browser_engine is None:
+ self.web_browser_engine = WebBrowserEngine.from_browser_config(
+ self.config.browser,
+ browse_func=self.browse_func,
+ proxy=self.config.proxy,
+ )
+ return self
async def run(
self,
diff --git a/metagpt/actions/run_code.py b/metagpt/actions/run_code.py
index 072ee8f22..b2c33c19b 100644
--- a/metagpt/actions/run_code.py
+++ b/metagpt/actions/run_code.py
@@ -16,6 +16,7 @@
class.
"""
import subprocess
+from pathlib import Path
from typing import Tuple
from pydantic import Field
@@ -41,13 +42,13 @@ Determine the ONE file to rewrite in order to fix the error, for example, xyz.py
Determine if all of the code works fine, if so write PASS, else FAIL,
WRITE ONLY ONE WORD, PASS OR FAIL, IN THIS SECTION
## Send To:
-Please write Engineer if the errors are due to problematic development codes, and QaEngineer to problematic test codes, and NoOne if there are no errors,
-WRITE ONLY ONE WORD, Engineer OR QaEngineer OR NoOne, IN THIS SECTION.
+Please write NoOne if there are no errors, Engineer if the errors are due to problematic development codes, else QaEngineer,
+WRITE ONLY ONE WORD, NoOne OR Engineer OR QaEngineer, IN THIS SECTION.
---
You should fill in necessary instruction, status, send to, and finally return all content between the --- segment line.
"""
-CONTEXT = """
+TEMPLATE_CONTEXT = """
## Development Code File Name
{code_file_name}
## Development Code
@@ -130,7 +131,7 @@ class RunCode(Action):
logger.info(f"{outs=}")
logger.info(f"{errs=}")
- context = CONTEXT.format(
+ context = TEMPLATE_CONTEXT.format(
code=self.i_context.code,
code_file_name=self.i_context.code_filename,
test_code=self.i_context.test_code,
@@ -150,11 +151,23 @@ class RunCode(Action):
return subprocess.run(cmd, check=check, cwd=cwd, env=env)
@staticmethod
- def _install_dependencies(working_directory, env):
+ def _install_requirements(working_directory, env):
+ file_path = Path(working_directory) / "requirements.txt"
+ if not file_path.exists():
+ return
+ if file_path.stat().st_size == 0:
+ return
install_command = ["python", "-m", "pip", "install", "-r", "requirements.txt"]
logger.info(" ".join(install_command))
RunCode._install_via_subprocess(install_command, check=True, cwd=working_directory, env=env)
+ @staticmethod
+ def _install_pytest(working_directory, env):
install_pytest_command = ["python", "-m", "pip", "install", "pytest"]
logger.info(" ".join(install_pytest_command))
RunCode._install_via_subprocess(install_pytest_command, check=True, cwd=working_directory, env=env)
+
+ @staticmethod
+ def _install_dependencies(working_directory, env):
+ RunCode._install_requirements(working_directory, env)
+ RunCode._install_pytest(working_directory, env)
diff --git a/metagpt/actions/search_and_summarize.py b/metagpt/actions/search_and_summarize.py
index 59b35cd58..7eed7381b 100644
--- a/metagpt/actions/search_and_summarize.py
+++ b/metagpt/actions/search_and_summarize.py
@@ -5,7 +5,7 @@
@Author : alexanderwu
@File : search_google.py
"""
-from typing import Any, Optional
+from typing import Optional
import pydantic
from pydantic import model_validator
@@ -13,7 +13,6 @@ from pydantic import model_validator
from metagpt.actions import Action
from metagpt.logs import logger
from metagpt.schema import Message
-from metagpt.tools import SearchEngineType
from metagpt.tools.search_engine import SearchEngine
SEARCH_AND_SUMMARIZE_SYSTEM = """### Requirements
@@ -105,21 +104,19 @@ You are a member of a professional butler team and will provide helpful suggesti
class SearchAndSummarize(Action):
name: str = ""
content: Optional[str] = None
- engine: Optional[SearchEngineType] = None
- search_func: Optional[Any] = None
search_engine: SearchEngine = None
result: str = ""
@model_validator(mode="after")
- def validate_engine_and_run_func(self):
- if self.engine is None:
- self.engine = self.config.search_engine
- try:
- search_engine = SearchEngine(engine=self.engine, run_func=self.search_func)
- except pydantic.ValidationError:
- search_engine = None
+ def validate_search_engine(self):
+ if self.search_engine is None:
+ try:
+ config = self.config
+ search_engine = SearchEngine.from_search_config(config.search, proxy=config.proxy)
+ except pydantic.ValidationError:
+ search_engine = None
- self.search_engine = search_engine
+ self.search_engine = search_engine
return self
async def run(self, context: list[Message], system_text=SEARCH_AND_SUMMARIZE_SYSTEM) -> str:
diff --git a/metagpt/actions/summarize_code.py b/metagpt/actions/summarize_code.py
index 182561d59..d21b62f83 100644
--- a/metagpt/actions/summarize_code.py
+++ b/metagpt/actions/summarize_code.py
@@ -26,9 +26,9 @@ ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenc
{system_design}
```
-----
-# Tasks
+# Task
```text
-{tasks}
+{task}
```
-----
{code_blocks}
@@ -98,10 +98,10 @@ class SummarizeCode(Action):
async def run(self):
design_pathname = Path(self.i_context.design_filename)
- design_doc = await self.project_repo.docs.system_design.get(filename=design_pathname.name)
+ design_doc = await self.repo.docs.system_design.get(filename=design_pathname.name)
task_pathname = Path(self.i_context.task_filename)
- task_doc = await self.project_repo.docs.task.get(filename=task_pathname.name)
- src_file_repo = self.project_repo.with_src_path(self.context.src_workspace).srcs
+ task_doc = await self.repo.docs.task.get(filename=task_pathname.name)
+ src_file_repo = self.repo.with_src_path(self.context.src_workspace).srcs
code_blocks = []
for filename in self.i_context.codes_filenames:
code_doc = await src_file_repo.get(filename)
@@ -110,7 +110,7 @@ class SummarizeCode(Action):
format_example = FORMAT_EXAMPLE
prompt = PROMPT_TEMPLATE.format(
system_design=design_doc.content,
- tasks=task_doc.content,
+ task=task_doc.content,
code_blocks="\n".join(code_blocks),
format_example=format_example,
)
diff --git a/metagpt/actions/write_code.py b/metagpt/actions/write_code.py
index c0f1b1a93..0b86ac1bb 100644
--- a/metagpt/actions/write_code.py
+++ b/metagpt/actions/write_code.py
@@ -21,10 +21,17 @@ from pydantic import Field
from tenacity import retry, stop_after_attempt, wait_random_exponential
from metagpt.actions.action import Action
-from metagpt.const import BUGFIX_FILENAME
+from metagpt.actions.project_management_an import REFINED_TASK_LIST, TASK_LIST
+from metagpt.actions.write_code_plan_and_change_an import REFINED_TEMPLATE
+from metagpt.const import (
+ BUGFIX_FILENAME,
+ CODE_PLAN_AND_CHANGE_FILENAME,
+ REQUIREMENT_FILENAME,
+)
from metagpt.logs import logger
from metagpt.schema import CodingContext, Document, RunCodeResult
from metagpt.utils.common import CodeParser
+from metagpt.utils.project_repo import ProjectRepo
PROMPT_TEMPLATE = """
NOTICE
@@ -36,8 +43,8 @@ ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenc
## Design
{design}
-## Tasks
-{tasks}
+## Task
+{task}
## Legacy Code
```Code
@@ -88,12 +95,15 @@ class WriteCode(Action):
return code
async def run(self, *args, **kwargs) -> CodingContext:
- bug_feedback = await self.project_repo.docs.get(filename=BUGFIX_FILENAME)
+ bug_feedback = await self.repo.docs.get(filename=BUGFIX_FILENAME)
coding_context = CodingContext.loads(self.i_context.content)
- test_doc = await self.project_repo.test_outputs.get(filename="test_" + coding_context.filename + ".json")
+ test_doc = await self.repo.test_outputs.get(filename="test_" + coding_context.filename + ".json")
+ code_plan_and_change_doc = await self.repo.docs.code_plan_and_change.get(filename=CODE_PLAN_AND_CHANGE_FILENAME)
+ code_plan_and_change = code_plan_and_change_doc.content if code_plan_and_change_doc else ""
+ requirement_doc = await self.repo.docs.get(filename=REQUIREMENT_FILENAME)
summary_doc = None
if coding_context.design_doc and coding_context.design_doc.filename:
- summary_doc = await self.project_repo.docs.code_summary.get(filename=coding_context.design_doc.filename)
+ summary_doc = await self.repo.docs.code_summary.get(filename=coding_context.design_doc.filename)
logs = ""
if test_doc:
test_detail = RunCodeResult.loads(test_doc.content)
@@ -101,22 +111,39 @@ class WriteCode(Action):
if bug_feedback:
code_context = coding_context.code_doc.content
+ elif code_plan_and_change:
+ code_context = await self.get_codes(
+ coding_context.task_doc, exclude=self.i_context.filename, project_repo=self.repo, use_inc=True
+ )
else:
code_context = await self.get_codes(
coding_context.task_doc,
exclude=self.i_context.filename,
- project_repo=self.project_repo.with_src_path(self.context.src_workspace),
+ project_repo=self.repo.with_src_path(self.context.src_workspace),
)
- prompt = PROMPT_TEMPLATE.format(
- design=coding_context.design_doc.content if coding_context.design_doc else "",
- tasks=coding_context.task_doc.content if coding_context.task_doc else "",
- code=code_context,
- logs=logs,
- feedback=bug_feedback.content if bug_feedback else "",
- filename=self.i_context.filename,
- summary_log=summary_doc.content if summary_doc else "",
- )
+ if code_plan_and_change:
+ prompt = REFINED_TEMPLATE.format(
+ user_requirement=requirement_doc.content if requirement_doc else "",
+ code_plan_and_change=code_plan_and_change,
+ design=coding_context.design_doc.content if coding_context.design_doc else "",
+ task=coding_context.task_doc.content if coding_context.task_doc else "",
+ code=code_context,
+ logs=logs,
+ feedback=bug_feedback.content if bug_feedback else "",
+ filename=self.i_context.filename,
+ summary_log=summary_doc.content if summary_doc else "",
+ )
+ else:
+ prompt = PROMPT_TEMPLATE.format(
+ design=coding_context.design_doc.content if coding_context.design_doc else "",
+ task=coding_context.task_doc.content if coding_context.task_doc else "",
+ code=code_context,
+ logs=logs,
+ feedback=bug_feedback.content if bug_feedback else "",
+ filename=self.i_context.filename,
+ summary_log=summary_doc.content if summary_doc else "",
+ )
logger.info(f"Writing {coding_context.filename}..")
code = await self.write_code(prompt)
if not coding_context.code_doc:
@@ -127,20 +154,66 @@ class WriteCode(Action):
return coding_context
@staticmethod
- async def get_codes(task_doc, exclude, project_repo) -> str:
+ async def get_codes(task_doc: Document, exclude: str, project_repo: ProjectRepo, use_inc: bool = False) -> str:
+ """
+ Get codes for generating the exclude file in various scenarios.
+
+ Attributes:
+ task_doc (Document): Document object of the task file.
+ exclude (str): The file to be generated. Specifies the filename to be excluded from the code snippets.
+ project_repo (ProjectRepo): ProjectRepo object of the project.
+ use_inc (bool): Indicates whether the scenario involves incremental development. Defaults to False.
+
+ Returns:
+ str: Codes for generating the exclude file.
+ """
if not task_doc:
return ""
if not task_doc.content:
task_doc = project_repo.docs.task.get(filename=task_doc.filename)
m = json.loads(task_doc.content)
- code_filenames = m.get("Task list", [])
+ code_filenames = m.get(TASK_LIST.key, []) if use_inc else m.get(REFINED_TASK_LIST.key, [])
codes = []
src_file_repo = project_repo.srcs
- for filename in code_filenames:
- if filename == exclude:
- continue
- doc = await src_file_repo.get(filename=filename)
- if not doc:
- continue
- codes.append(f"----- {filename}\n" + doc.content)
+
+ # Incremental development scenario
+ if use_inc:
+ src_files = src_file_repo.all_files
+ # Get the old workspace contained the old codes and old workspace are created in previous CodePlanAndChange
+ old_file_repo = project_repo.git_repo.new_file_repository(relative_path=project_repo.old_workspace)
+ old_files = old_file_repo.all_files
+ # Get the union of the files in the src and old workspaces
+ union_files_list = list(set(src_files) | set(old_files))
+ for filename in union_files_list:
+ # Exclude the current file from the all code snippets
+ if filename == exclude:
+ # If the file is in the old workspace, use the old code
+ # Exclude unnecessary code to maintain a clean and focused main.py file, ensuring only relevant and
+ # essential functionality is included for the project’s requirements
+ if filename in old_files and filename != "main.py":
+ # Use old code
+ doc = await old_file_repo.get(filename=filename)
+ # If the file is in the src workspace, skip it
+ else:
+ continue
+ codes.insert(0, f"-----Now, {filename} to be rewritten\n```{doc.content}```\n=====")
+ # The code snippets are generated from the src workspace
+ else:
+ doc = await src_file_repo.get(filename=filename)
+ # If the file does not exist in the src workspace, skip it
+ if not doc:
+ continue
+ codes.append(f"----- {filename}\n```{doc.content}```")
+
+ # Normal scenario
+ else:
+ for filename in code_filenames:
+ # Exclude the current file to get the code snippets for generating the current file
+ if filename == exclude:
+ continue
+ doc = await src_file_repo.get(filename=filename)
+ if not doc:
+ continue
+ codes.append(f"----- {filename}\n```{doc.content}```")
+
return "\n".join(codes)
diff --git a/metagpt/actions/write_code_plan_and_change_an.py b/metagpt/actions/write_code_plan_and_change_an.py
new file mode 100644
index 000000000..708808050
--- /dev/null
+++ b/metagpt/actions/write_code_plan_and_change_an.py
@@ -0,0 +1,210 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+@Time : 2023/12/26
+@Author : mannaandpoem
+@File : write_code_plan_and_change_an.py
+"""
+import os
+
+from pydantic import Field
+
+from metagpt.actions.action import Action
+from metagpt.actions.action_node import ActionNode
+from metagpt.schema import CodePlanAndChangeContext
+
+CODE_PLAN_AND_CHANGE = ActionNode(
+ key="Code Plan And Change",
+ expected_type=str,
+ instruction="Developing comprehensive and step-by-step incremental development plan, and write Incremental "
+ "Change by making a code draft that how to implement incremental development including detailed steps based on the "
+ "context. Note: Track incremental changes using mark of '+' or '-' for add/modify/delete code, and conforms to the "
+ "output format of git diff",
+ example="""
+1. Plan for calculator.py: Enhance the functionality of `calculator.py` by extending it to incorporate methods for subtraction, multiplication, and division. Additionally, implement robust error handling for the division operation to mitigate potential issues related to division by zero.
+```python
+class Calculator:
+ self.result = number1 + number2
+ return self.result
+
+- def sub(self, number1, number2) -> float:
++ def subtract(self, number1: float, number2: float) -> float:
++ '''
++ Subtracts the second number from the first and returns the result.
++
++ Args:
++ number1 (float): The number to be subtracted from.
++ number2 (float): The number to subtract.
++
++ Returns:
++ float: The difference of number1 and number2.
++ '''
++ self.result = number1 - number2
++ return self.result
++
+ def multiply(self, number1: float, number2: float) -> float:
+- pass
++ '''
++ Multiplies two numbers and returns the result.
++
++ Args:
++ number1 (float): The first number to multiply.
++ number2 (float): The second number to multiply.
++
++ Returns:
++ float: The product of number1 and number2.
++ '''
++ self.result = number1 * number2
++ return self.result
++
+ def divide(self, number1: float, number2: float) -> float:
+- pass
++ '''
++ ValueError: If the second number is zero.
++ '''
++ if number2 == 0:
++ raise ValueError('Cannot divide by zero')
++ self.result = number1 / number2
++ return self.result
++
+- def reset_result(self):
++ def clear(self):
++ if self.result != 0.0:
++ print("Result is not zero, clearing...")
++ else:
++ print("Result is already zero, no need to clear.")
++
+ self.result = 0.0
+```
+
+2. Plan for main.py: Integrate new API endpoints for subtraction, multiplication, and division into the existing codebase of `main.py`. Then, ensure seamless integration with the overall application architecture and maintain consistency with coding standards.
+```python
+def add_numbers():
+ result = calculator.add_numbers(num1, num2)
+ return jsonify({'result': result}), 200
+
+-# TODO: Implement subtraction, multiplication, and division operations
++@app.route('/subtract_numbers', methods=['POST'])
++def subtract_numbers():
++ data = request.get_json()
++ num1 = data.get('num1', 0)
++ num2 = data.get('num2', 0)
++ result = calculator.subtract_numbers(num1, num2)
++ return jsonify({'result': result}), 200
++
++@app.route('/multiply_numbers', methods=['POST'])
++def multiply_numbers():
++ data = request.get_json()
++ num1 = data.get('num1', 0)
++ num2 = data.get('num2', 0)
++ try:
++ result = calculator.divide_numbers(num1, num2)
++ except ValueError as e:
++ return jsonify({'error': str(e)}), 400
++ return jsonify({'result': result}), 200
++
+ if __name__ == '__main__':
+ app.run()
+```""",
+)
+
+CODE_PLAN_AND_CHANGE_CONTEXT = """
+## User New Requirements
+{requirement}
+
+## PRD
+{prd}
+
+## Design
+{design}
+
+## Task
+{task}
+
+## Legacy Code
+{code}
+"""
+
+REFINED_TEMPLATE = """
+NOTICE
+Role: You are a professional engineer; The main goal is to complete incremental development by combining legacy code and plan and Incremental Change, ensuring the integration of new features.
+
+# Context
+## User New Requirements
+{user_requirement}
+
+## Code Plan And Change
+{code_plan_and_change}
+
+## Design
+{design}
+
+## Task
+{task}
+
+## Legacy Code
+```Code
+{code}
+```
+
+## Debug logs
+```text
+{logs}
+
+{summary_log}
+```
+
+## Bug Feedback logs
+```text
+{feedback}
+```
+
+# Format example
+## Code: {filename}
+```python
+## {filename}
+...
+```
+
+# Instruction: Based on the context, follow "Format example", write or rewrite code.
+## Write/Rewrite Code: Only write one file {filename}, write or rewrite complete code using triple quotes based on the following attentions and context.
+1. Only One file: do your best to implement THIS ONLY ONE FILE.
+2. COMPLETE CODE: Your code will be part of the entire project, so please implement complete, reliable, reusable code snippets.
+3. Set default value: If there is any setting, ALWAYS SET A DEFAULT VALUE, ALWAYS USE STRONG TYPE AND EXPLICIT VARIABLE. AVOID circular import.
+4. 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.
+5. Follow Code Plan And Change: If there is any Incremental Change that is marked by the git diff format using '+' and '-' for add/modify/delete code, or Legacy Code files contain "{filename} to be rewritten", you must merge it into the code file according to the plan.
+6. CAREFULLY CHECK THAT YOU DONT MISS ANY NECESSARY CLASS/FUNCTION IN THIS FILE.
+7. Before using a external variable/module, make sure you import it first.
+8. Write out EVERY CODE DETAIL, DON'T LEAVE TODO.
+9. Attention: Retain details that are not related to incremental development but are important for maintaining the consistency and clarity of the old code.
+"""
+
+WRITE_CODE_PLAN_AND_CHANGE_NODE = ActionNode.from_children("WriteCodePlanAndChange", [CODE_PLAN_AND_CHANGE])
+
+
+class WriteCodePlanAndChange(Action):
+ name: str = "WriteCodePlanAndChange"
+ i_context: CodePlanAndChangeContext = Field(default_factory=CodePlanAndChangeContext)
+
+ async def run(self, *args, **kwargs):
+ self.llm.system_prompt = "You are a professional software engineer, your primary responsibility is to "
+ "meticulously craft comprehensive incremental development plan and deliver detailed incremental change"
+ prd_doc = await self.repo.docs.prd.get(filename=self.i_context.prd_filename)
+ design_doc = await self.repo.docs.system_design.get(filename=self.i_context.design_filename)
+ task_doc = await self.repo.docs.task.get(filename=self.i_context.task_filename)
+ code_text = await self.get_old_codes()
+ context = CODE_PLAN_AND_CHANGE_CONTEXT.format(
+ requirement=self.i_context.requirement,
+ prd=prd_doc.content,
+ design=design_doc.content,
+ task=task_doc.content,
+ code=code_text,
+ )
+ return await WRITE_CODE_PLAN_AND_CHANGE_NODE.fill(context=context, llm=self.llm, schema="json")
+
+ async def get_old_codes(self) -> str:
+ self.repo.old_workspace = self.repo.git_repo.workdir / os.path.basename(self.config.project_path)
+ old_file_repo = self.repo.git_repo.new_file_repository(relative_path=self.repo.old_workspace)
+ old_codes = await old_file_repo.get_all()
+ codes = [f"----- {code.filename}\n```{code.content}```" for code in old_codes]
+ return "\n".join(codes)
diff --git a/metagpt/actions/write_code_review.py b/metagpt/actions/write_code_review.py
index 21281dde1..da636eb36 100644
--- a/metagpt/actions/write_code_review.py
+++ b/metagpt/actions/write_code_review.py
@@ -13,6 +13,7 @@ from tenacity import retry, stop_after_attempt, wait_random_exponential
from metagpt.actions import WriteCode
from metagpt.actions.action import Action
+from metagpt.const import CODE_PLAN_AND_CHANGE_FILENAME, REQUIREMENT_FILENAME
from metagpt.logs import logger
from metagpt.schema import CodingContext
from metagpt.utils.common import CodeParser
@@ -137,21 +138,38 @@ class WriteCodeReview(Action):
async def run(self, *args, **kwargs) -> CodingContext:
iterative_code = self.i_context.code_doc.content
k = self.context.config.code_review_k_times or 1
+
for i in range(k):
format_example = FORMAT_EXAMPLE.format(filename=self.i_context.code_doc.filename)
task_content = self.i_context.task_doc.content if self.i_context.task_doc else ""
code_context = await WriteCode.get_codes(
self.i_context.task_doc,
exclude=self.i_context.filename,
- project_repo=self.project_repo.with_src_path(self.context.src_workspace),
- )
- context = "\n".join(
- [
- "## System Design\n" + str(self.i_context.design_doc) + "\n",
- "## Tasks\n" + task_content + "\n",
- "## Code Files\n" + code_context + "\n",
- ]
+ project_repo=self.repo.with_src_path(self.context.src_workspace),
+ use_inc=self.config.inc,
)
+
+ if not self.config.inc:
+ context = "\n".join(
+ [
+ "## System Design\n" + str(self.i_context.design_doc) + "\n",
+ "## Task\n" + task_content + "\n",
+ "## Code Files\n" + code_context + "\n",
+ ]
+ )
+ else:
+ requirement_doc = await self.repo.docs.get(filename=REQUIREMENT_FILENAME)
+ code_plan_and_change_doc = await self.repo.get(filename=CODE_PLAN_AND_CHANGE_FILENAME)
+ context = "\n".join(
+ [
+ "## User New Requirements\n" + str(requirement_doc) + "\n",
+ "## Code Plan And Change\n" + str(code_plan_and_change_doc) + "\n",
+ "## System Design\n" + str(self.i_context.design_doc) + "\n",
+ "## Task\n" + task_content + "\n",
+ "## Code Files\n" + code_context + "\n",
+ ]
+ )
+
context_prompt = PROMPT_TEMPLATE.format(
context=context,
code=iterative_code,
@@ -160,9 +178,11 @@ class WriteCodeReview(Action):
cr_prompt = EXAMPLE_AND_INSTRUCTION.format(
format_example=format_example,
)
+ len1 = len(iterative_code) if iterative_code else 0
+ len2 = len(self.i_context.code_doc.content) if self.i_context.code_doc.content else 0
logger.info(
- f"Code review and rewrite {self.i_context.code_doc.filename}: {i + 1}/{k} | {len(iterative_code)=}, "
- f"{len(self.i_context.code_doc.content)=}"
+ f"Code review and rewrite {self.i_context.code_doc.filename}: {i + 1}/{k} | len(iterative_code)={len1}, "
+ f"len(self.i_context.code_doc.content)={len2}"
)
result, rewrited_code = await self.write_code_review_and_rewrite(
context_prompt, cr_prompt, self.i_context.code_doc.filename
diff --git a/metagpt/actions/write_docstring.py b/metagpt/actions/write_docstring.py
index 79204e6a4..5cc4cafb8 100644
--- a/metagpt/actions/write_docstring.py
+++ b/metagpt/actions/write_docstring.py
@@ -16,7 +16,7 @@ Options:
Default: 'google'
Example:
- python3 -m metagpt.actions.write_docstring ./metagpt/startup.py --overwrite False --style=numpy
+ python3 -m metagpt.actions.write_docstring ./metagpt/software_company.py --overwrite False --style=numpy
This script uses the 'fire' library to create a command-line interface. It generates docstrings for the given Python code using
the specified docstring style and adds them to the code.
diff --git a/metagpt/actions/write_prd.py b/metagpt/actions/write_prd.py
index 38ac62536..b66887164 100644
--- a/metagpt/actions/write_prd.py
+++ b/metagpt/actions/write_prd.py
@@ -15,13 +15,14 @@ from __future__ import annotations
import json
from pathlib import Path
-from typing import Optional
from metagpt.actions import Action, ActionOutput
from metagpt.actions.action_node import ActionNode
from metagpt.actions.fix_bug import FixBug
from metagpt.actions.write_prd_an import (
+ COMPETITIVE_QUADRANT_CHART,
PROJECT_NAME,
+ REFINED_PRD_NODE,
WP_IS_RELATIVE_NODE,
WP_ISSUE_TYPE_NODE,
WRITE_PRD_NODE,
@@ -58,97 +59,107 @@ NEW_REQ_TEMPLATE = """
class WritePRD(Action):
- name: str = "WritePRD"
- content: Optional[str] = None
+ """WritePRD deal with the following situations:
+ 1. Bugfix: If the requirement is a bugfix, the bugfix document will be generated.
+ 2. New requirement: If the requirement is a new requirement, the PRD document will be generated.
+ 3. Requirement update: If the requirement is an update, the PRD document will be updated.
+ """
async def run(self, with_messages, *args, **kwargs) -> ActionOutput | Message:
- # Determine which requirement documents need to be rewritten: Use LLM to assess whether new requirements are
- # related to the PRD. If they are related, rewrite the PRD.
- requirement_doc = await self.project_repo.docs.get(filename=REQUIREMENT_FILENAME)
- if requirement_doc and await self._is_bugfix(requirement_doc.content):
- await self.project_repo.docs.save(filename=BUGFIX_FILENAME, content=requirement_doc.content)
- await self.project_repo.docs.save(filename=REQUIREMENT_FILENAME, content="")
- bug_fix = BugFixContext(filename=BUGFIX_FILENAME)
- return Message(
- content=bug_fix.model_dump_json(),
- instruct_content=bug_fix,
- role="",
- cause_by=FixBug,
- sent_from=self,
- send_to="Alex", # the name of Engineer
- )
+ """Run the action."""
+ req: Document = await self.repo.requirement
+ docs: list[Document] = await self.repo.docs.prd.get_all()
+ if not req:
+ raise FileNotFoundError("No requirement document found.")
+
+ if await self._is_bugfix(req.content):
+ logger.info(f"Bugfix detected: {req.content}")
+ return await self._handle_bugfix(req)
+ # remove bugfix file from last round in case of conflict
+ await self.repo.docs.delete(filename=BUGFIX_FILENAME)
+
+ # if requirement is related to other documents, update them, otherwise create a new one
+ if related_docs := await self.get_related_docs(req, docs):
+ logger.info(f"Requirement update detected: {req.content}")
+ return await self._handle_requirement_update(req, related_docs)
else:
- await self.project_repo.docs.delete(filename=BUGFIX_FILENAME)
+ logger.info(f"New requirement detected: {req.content}")
+ return await self._handle_new_requirement(req)
- prd_docs = await self.project_repo.docs.prd.get_all()
- change_files = Documents()
- for prd_doc in prd_docs:
- prd_doc = await self._update_prd(requirement_doc=requirement_doc, prd_doc=prd_doc, *args, **kwargs)
- if not prd_doc:
- continue
- change_files.docs[prd_doc.filename] = prd_doc
- logger.info(f"rewrite prd: {prd_doc.filename}")
- # If there is no existing PRD, generate one using 'docs/requirement.txt'.
- if not change_files.docs:
- prd_doc = await self._update_prd(requirement_doc=requirement_doc, *args, **kwargs)
- if prd_doc:
- change_files.docs[prd_doc.filename] = prd_doc
- logger.debug(f"new prd: {prd_doc.filename}")
- # Once all files under 'docs/prds/' have been compared with the newly added requirements, trigger the
- # 'publish' message to transition the workflow to the next stage. This design allows room for global
- # optimization in subsequent steps.
- return ActionOutput(content=change_files.model_dump_json(), instruct_content=change_files)
+ async def _handle_bugfix(self, req: Document) -> Message:
+ # ... bugfix logic ...
+ await self.repo.docs.save(filename=BUGFIX_FILENAME, content=req.content)
+ await self.repo.docs.save(filename=REQUIREMENT_FILENAME, content="")
+ bug_fix = BugFixContext(filename=BUGFIX_FILENAME)
+ return Message(
+ content=bug_fix.model_dump_json(),
+ instruct_content=bug_fix,
+ role="",
+ cause_by=FixBug,
+ sent_from=self,
+ send_to="Alex", # the name of Engineer
+ )
- async def _run_new_requirement(self, requirements) -> ActionOutput:
+ async def _handle_new_requirement(self, req: Document) -> ActionOutput:
+ """handle new requirement"""
project_name = self.project_name
- context = CONTEXT_TEMPLATE.format(requirements=requirements, project_name=project_name)
+ context = CONTEXT_TEMPLATE.format(requirements=req, project_name=project_name)
exclude = [PROJECT_NAME.key] if project_name else []
node = await WRITE_PRD_NODE.fill(context=context, llm=self.llm, exclude=exclude) # schema=schema
await self._rename_workspace(node)
- return node
+ new_prd_doc = await self.repo.docs.prd.save(
+ filename=FileRepository.new_filename() + ".json", content=node.instruct_content.model_dump_json()
+ )
+ await self._save_competitive_analysis(new_prd_doc)
+ await self.repo.resources.prd.save_pdf(doc=new_prd_doc)
+ return Documents.from_iterable(documents=[new_prd_doc]).to_action_output()
- async def _is_relative(self, new_requirement_doc, old_prd_doc) -> bool:
- context = NEW_REQ_TEMPLATE.format(old_prd=old_prd_doc.content, requirements=new_requirement_doc.content)
+ async def _handle_requirement_update(self, req: Document, related_docs: list[Document]) -> ActionOutput:
+ # ... requirement update logic ...
+ for doc in related_docs:
+ await self._update_prd(req, doc)
+ return Documents.from_iterable(documents=related_docs).to_action_output()
+
+ async def _is_bugfix(self, context: str) -> bool:
+ if not self.repo.code_files_exists():
+ return False
+ node = await WP_ISSUE_TYPE_NODE.fill(context, self.llm)
+ return node.get("issue_type") == "BUG"
+
+ async def get_related_docs(self, req: Document, docs: list[Document]) -> list[Document]:
+ """get the related documents"""
+ # refine: use gather to speed up
+ return [i for i in docs if await self._is_related(req, i)]
+
+ async def _is_related(self, req: Document, old_prd: Document) -> bool:
+ context = NEW_REQ_TEMPLATE.format(old_prd=old_prd.content, requirements=req.content)
node = await WP_IS_RELATIVE_NODE.fill(context, self.llm)
return node.get("is_relative") == "YES"
- async def _merge(self, new_requirement_doc, prd_doc) -> Document:
+ async def _merge(self, req: Document, related_doc: Document) -> Document:
if not self.project_name:
self.project_name = Path(self.project_path).name
- prompt = NEW_REQ_TEMPLATE.format(requirements=new_requirement_doc.content, old_prd=prd_doc.content)
- node = await WRITE_PRD_NODE.fill(context=prompt, llm=self.llm, schema=self.prompt_schema)
- prd_doc.content = node.instruct_content.model_dump_json()
+ prompt = NEW_REQ_TEMPLATE.format(requirements=req.content, old_prd=related_doc.content)
+ node = await REFINED_PRD_NODE.fill(context=prompt, llm=self.llm, schema=self.prompt_schema)
+ related_doc.content = node.instruct_content.model_dump_json()
await self._rename_workspace(node)
- return prd_doc
+ return related_doc
- async def _update_prd(self, requirement_doc, prd_doc=None, *args, **kwargs) -> Document | None:
- if not prd_doc:
- prd = await self._run_new_requirement(
- requirements=[requirement_doc.content if requirement_doc else ""], *args, **kwargs
- )
- new_prd_doc = await self.project_repo.docs.prd.save(
- filename=FileRepository.new_filename() + ".json", content=prd.instruct_content.model_dump_json()
- )
- elif await self._is_relative(requirement_doc, prd_doc):
- new_prd_doc = await self._merge(requirement_doc, prd_doc)
- self.project_repo.docs.prd.save_doc(doc=new_prd_doc)
- else:
- return None
+ async def _update_prd(self, req: Document, prd_doc: Document) -> Document:
+ new_prd_doc: Document = await self._merge(req, prd_doc)
+ await self.repo.docs.prd.save_doc(doc=new_prd_doc)
await self._save_competitive_analysis(new_prd_doc)
- await self.project_repo.resources.prd.save_pdf(doc=new_prd_doc)
+ await self.repo.resources.prd.save_pdf(doc=new_prd_doc)
return new_prd_doc
- async def _save_competitive_analysis(self, prd_doc):
+ async def _save_competitive_analysis(self, prd_doc: Document):
m = json.loads(prd_doc.content)
- quadrant_chart = m.get("Competitive Quadrant Chart")
+ quadrant_chart = m.get(COMPETITIVE_QUADRANT_CHART.key)
if not quadrant_chart:
return
- pathname = (
- self.project_repo.workdir / Path(COMPETITIVE_ANALYSIS_FILE_REPO) / Path(prd_doc.filename).with_suffix("")
- )
- if not pathname.parent.exists():
- pathname.parent.mkdir(parents=True, exist_ok=True)
- await mermaid_to_file(self.config.mermaid_engine, quadrant_chart, pathname)
+ pathname = self.repo.workdir / COMPETITIVE_ANALYSIS_FILE_REPO / Path(prd_doc.filename).stem
+ pathname.parent.mkdir(parents=True, exist_ok=True)
+ await mermaid_to_file(self.config.mermaid.engine, quadrant_chart, pathname)
async def _rename_workspace(self, prd):
if not self.project_name:
@@ -158,15 +169,4 @@ class WritePRD(Action):
ws_name = CodeParser.parse_str(block="Project Name", text=prd)
if ws_name:
self.project_name = ws_name
- self.project_repo.git_repo.rename_root(self.project_name)
-
- async def _is_bugfix(self, context) -> bool:
- git_workdir = self.project_repo.git_repo.workdir
- src_workdir = git_workdir / git_workdir.name
- if not src_workdir.exists():
- return False
- code_files = self.project_repo.with_src_path(path=git_workdir / git_workdir.name).srcs.all_files
- if not code_files:
- return False
- node = await WP_ISSUE_TYPE_NODE.fill(context, self.llm)
- return node.get("issue_type") == "BUG"
+ self.repo.git_repo.rename_root(self.project_name)
diff --git a/metagpt/actions/write_prd_an.py b/metagpt/actions/write_prd_an.py
index 715e8fc55..9898be55b 100644
--- a/metagpt/actions/write_prd_an.py
+++ b/metagpt/actions/write_prd_an.py
@@ -30,6 +30,13 @@ ORIGINAL_REQUIREMENTS = ActionNode(
example="Create a 2048 game",
)
+REFINED_REQUIREMENTS = ActionNode(
+ key="Refined Requirements",
+ expected_type=str,
+ instruction="Place the New user's original requirements here.",
+ example="Create a 2048 game with a new feature that ...",
+)
+
PROJECT_NAME = ActionNode(
key="Project Name",
expected_type=str,
@@ -45,6 +52,18 @@ PRODUCT_GOALS = ActionNode(
example=["Create an engaging user experience", "Improve accessibility, be responsive", "More beautiful UI"],
)
+REFINED_PRODUCT_GOALS = ActionNode(
+ key="Refined Product Goals",
+ expected_type=List[str],
+ instruction="Update and expand the original product goals to reflect the evolving needs due to incremental "
+ "development.Ensure that the refined goals align with the current project direction and contribute to its success.",
+ example=[
+ "Enhance user engagement through new features",
+ "Optimize performance for scalability",
+ "Integrate innovative UI enhancements",
+ ],
+)
+
USER_STORIES = ActionNode(
key="User Stories",
expected_type=List[str],
@@ -58,6 +77,20 @@ USER_STORIES = ActionNode(
],
)
+REFINED_USER_STORIES = ActionNode(
+ key="Refined User Stories",
+ expected_type=List[str],
+ instruction="Update and expand the original scenario-based user stories to reflect the evolving needs due to "
+ "incremental development. Ensure that the refined user stories capture incremental features and improvements. ",
+ example=[
+ "As a player, I want to choose difficulty levels to challenge my skills",
+ "As a player, I want a visually appealing score display after each game for a better gaming experience",
+ "As a player, I want a convenient restart button displayed when I lose to quickly start a new game",
+ "As a player, I want an enhanced and aesthetically pleasing UI to elevate the overall gaming experience",
+ "As a player, I want the ability to play the game seamlessly on my mobile phone for on-the-go entertainment",
+ ],
+)
+
COMPETITIVE_ANALYSIS = ActionNode(
key="Competitive Analysis",
expected_type=List[str],
@@ -97,6 +130,15 @@ REQUIREMENT_ANALYSIS = ActionNode(
example="",
)
+REFINED_REQUIREMENT_ANALYSIS = ActionNode(
+ key="Refined Requirement Analysis",
+ expected_type=List[str],
+ instruction="Review and refine the existing requirement analysis to align with the evolving needs of the project "
+ "due to incremental development. Ensure the analysis comprehensively covers the new features and enhancements "
+ "required for the refined project scope.",
+ example=["Require add/update/modify ..."],
+)
+
REQUIREMENT_POOL = ActionNode(
key="Requirement Pool",
expected_type=List[List[str]],
@@ -104,6 +146,14 @@ REQUIREMENT_POOL = ActionNode(
example=[["P0", "The main code ..."], ["P0", "The game algorithm ..."]],
)
+REFINED_REQUIREMENT_POOL = ActionNode(
+ key="Refined Requirement Pool",
+ expected_type=List[List[str]],
+ instruction="List down the top 5 to 7 requirements with their priority (P0, P1, P2). "
+ "Cover both legacy content and incremental content. Retain content unrelated to incremental development",
+ example=[["P0", "The main code ..."], ["P0", "The game algorithm ..."]],
+)
+
UI_DESIGN_DRAFT = ActionNode(
key="UI Design draft",
expected_type=str,
@@ -152,6 +202,22 @@ NODES = [
ANYTHING_UNCLEAR,
]
+REFINED_NODES = [
+ LANGUAGE,
+ PROGRAMMING_LANGUAGE,
+ REFINED_REQUIREMENTS,
+ PROJECT_NAME,
+ REFINED_PRODUCT_GOALS,
+ REFINED_USER_STORIES,
+ COMPETITIVE_ANALYSIS,
+ COMPETITIVE_QUADRANT_CHART,
+ REFINED_REQUIREMENT_ANALYSIS,
+ REFINED_REQUIREMENT_POOL,
+ UI_DESIGN_DRAFT,
+ ANYTHING_UNCLEAR,
+]
+
WRITE_PRD_NODE = ActionNode.from_children("WritePRD", NODES)
+REFINED_PRD_NODE = ActionNode.from_children("RefinedPRD", REFINED_NODES)
WP_ISSUE_TYPE_NODE = ActionNode.from_children("WP_ISSUE_TYPE", [ISSUE_TYPE, REASON])
WP_IS_RELATIVE_NODE = ActionNode.from_children("WP_IS_RELATIVE", [IS_RELATIVE, REASON])
diff --git a/metagpt/config2.py b/metagpt/config2.py
index 1d58b9d63..bc6af18c6 100644
--- a/metagpt/config2.py
+++ b/metagpt/config2.py
@@ -38,6 +38,7 @@ class CLIParams(BaseModel):
if self.project_path:
self.inc = True
self.project_name = self.project_name or Path(self.project_path).name
+ return self
class Config(CLIParams, YamlModel):
@@ -50,7 +51,7 @@ class Config(CLIParams, YamlModel):
proxy: str = ""
# Tool Parameters
- search: Optional[SearchConfig] = None
+ search: SearchConfig = SearchConfig()
browser: BrowserConfig = BrowserConfig()
mermaid: MermaidConfig = MermaidConfig()
@@ -66,25 +67,22 @@ class Config(CLIParams, YamlModel):
code_review_k_times: int = 2
# Will be removed in the future
- llm_for_researcher_summary: str = "gpt3"
- llm_for_researcher_report: str = "gpt3"
- METAGPT_TEXT_TO_IMAGE_MODEL_URL: str = ""
+ metagpt_tti_url: str = ""
language: str = "English"
redis_key: str = "placeholder"
- mmdc: str = "mmdc"
- puppeteer_config: str = ""
- pyppeteer_executable_path: str = ""
- IFLYTEK_APP_ID: str = ""
- IFLYTEK_API_SECRET: str = ""
- IFLYTEK_API_KEY: str = ""
- AZURE_TTS_SUBSCRIPTION_KEY: str = ""
- AZURE_TTS_REGION: str = ""
- mermaid_engine: str = "nodejs"
+ iflytek_app_id: str = ""
+ iflytek_api_secret: str = ""
+ iflytek_api_key: str = ""
+ azure_tts_subscription_key: str = ""
+ azure_tts_region: str = ""
@classmethod
def from_home(cls, path):
- """Load config from ~/.metagpt/config.yaml"""
- return Config.from_yaml_file(CONFIG_ROOT / path)
+ """Load config from ~/.metagpt/config2.yaml"""
+ pathname = CONFIG_ROOT / path
+ if not pathname.exists():
+ return None
+ return Config.from_yaml_file(pathname)
@classmethod
def default(cls):
diff --git a/metagpt/configs/browser_config.py b/metagpt/configs/browser_config.py
index 00f918735..2f8024f44 100644
--- a/metagpt/configs/browser_config.py
+++ b/metagpt/configs/browser_config.py
@@ -15,6 +15,6 @@ class BrowserConfig(YamlModel):
"""Config for Browser"""
engine: WebBrowserEngineType = WebBrowserEngineType.PLAYWRIGHT
- browser: Literal["chrome", "firefox", "edge", "ie"] = "chrome"
- driver: Literal["chromium", "firefox", "webkit"] = "chromium"
- path: str = ""
+ browser_type: Literal["chromium", "firefox", "webkit", "chrome", "firefox", "edge", "ie"] = "chromium"
+ """If the engine is Playwright, the value should be one of "chromium", "firefox", or "webkit". If it is Selenium, the value
+ should be either "chrome", "firefox", "edge", or "ie"."""
diff --git a/metagpt/configs/llm_config.py b/metagpt/configs/llm_config.py
index 626d4242f..fb923d3e4 100644
--- a/metagpt/configs/llm_config.py
+++ b/metagpt/configs/llm_config.py
@@ -74,5 +74,5 @@ class LLMConfig(YamlModel):
@classmethod
def check_llm_key(cls, v):
if v in ["", None, "YOUR_API_KEY"]:
- raise ValueError("Please set your API key in config.yaml")
+ raise ValueError("Please set your API key in config2.yaml")
return v
diff --git a/metagpt/configs/mermaid_config.py b/metagpt/configs/mermaid_config.py
index de4a3865c..50c8a1847 100644
--- a/metagpt/configs/mermaid_config.py
+++ b/metagpt/configs/mermaid_config.py
@@ -14,5 +14,6 @@ class MermaidConfig(YamlModel):
"""Config for Mermaid"""
engine: Literal["nodejs", "ink", "playwright", "pyppeteer"] = "nodejs"
- path: str = ""
- puppeteer_config: str = "" # Only for nodejs engine
+ path: str = "mmdc" # mmdc
+ puppeteer_config: str = ""
+ pyppeteer_path: str = "/usr/bin/google-chrome-stable"
diff --git a/metagpt/configs/search_config.py b/metagpt/configs/search_config.py
index a8ae918db..af928b02a 100644
--- a/metagpt/configs/search_config.py
+++ b/metagpt/configs/search_config.py
@@ -5,6 +5,8 @@
@Author : alexanderwu
@File : search_config.py
"""
+from typing import Callable, Optional
+
from metagpt.tools import SearchEngineType
from metagpt.utils.yaml_model import YamlModel
@@ -12,6 +14,7 @@ from metagpt.utils.yaml_model import YamlModel
class SearchConfig(YamlModel):
"""Config for Search"""
- api_key: str
- api_type: SearchEngineType = SearchEngineType.SERPAPI_GOOGLE
+ api_type: SearchEngineType = SearchEngineType.DUCK_DUCK_GO
+ api_key: str = ""
cse_id: str = "" # for google
+ search_func: Optional[Callable] = None
diff --git a/metagpt/const.py b/metagpt/const.py
index 0ae425a47..2cffaa804 100644
--- a/metagpt/const.py
+++ b/metagpt/const.py
@@ -67,6 +67,8 @@ TMP = METAGPT_ROOT / "tmp"
SOURCE_ROOT = METAGPT_ROOT / "metagpt"
PROMPT_PATH = SOURCE_ROOT / "prompts"
SKILL_DIRECTORY = SOURCE_ROOT / "skills"
+TOOL_SCHEMA_PATH = METAGPT_ROOT / "metagpt/tools/schemas"
+TOOL_LIBS_PATH = METAGPT_ROOT / "metagpt/tools/libs"
# REAL CONSTS
@@ -82,17 +84,20 @@ MESSAGE_ROUTE_TO_NONE = ""
REQUIREMENT_FILENAME = "requirement.txt"
BUGFIX_FILENAME = "bugfix.txt"
PACKAGE_REQUIREMENTS_FILENAME = "requirements.txt"
+CODE_PLAN_AND_CHANGE_FILENAME = "code_plan_and_change.json"
DOCS_FILE_REPO = "docs"
PRDS_FILE_REPO = "docs/prd"
SYSTEM_DESIGN_FILE_REPO = "docs/system_design"
TASK_FILE_REPO = "docs/task"
+CODE_PLAN_AND_CHANGE_FILE_REPO = "docs/code_plan_and_change"
COMPETITIVE_ANALYSIS_FILE_REPO = "resources/competitive_analysis"
DATA_API_DESIGN_FILE_REPO = "resources/data_api_design"
SEQ_FLOW_FILE_REPO = "resources/seq_flow"
SYSTEM_DESIGN_PDF_FILE_REPO = "resources/system_design"
PRD_PDF_FILE_REPO = "resources/prd"
TASK_PDF_FILE_REPO = "resources/api_spec_and_task"
+CODE_PLAN_AND_CHANGE_PDF_FILE_REPO = "resources/code_plan_and_change"
TEST_CODES_FILE_REPO = "tests"
TEST_OUTPUTS_FILE_REPO = "test_outputs"
CODE_SUMMARIES_FILE_REPO = "docs/code_summary"
diff --git a/metagpt/context.py b/metagpt/context.py
index 1e0d91237..3dfd52d58 100644
--- a/metagpt/context.py
+++ b/metagpt/context.py
@@ -17,6 +17,7 @@ from metagpt.provider.base_llm import BaseLLM
from metagpt.provider.llm_provider_registry import create_llm_instance
from metagpt.utils.cost_manager import CostManager
from metagpt.utils.git_repository import GitRepository
+from metagpt.utils.project_repo import ProjectRepo
class AttrDict(BaseModel):
@@ -58,6 +59,8 @@ class Context(BaseModel):
kwargs: AttrDict = AttrDict()
config: Config = Config.default()
+
+ repo: Optional[ProjectRepo] = None
git_repo: Optional[GitRepository] = None
src_workspace: Optional[Path] = None
cost_manager: CostManager = CostManager()
@@ -67,8 +70,8 @@ class Context(BaseModel):
def new_environ(self):
"""Return a new os.environ object"""
env = os.environ.copy()
- i = self.options
- env.update({k: v for k, v in i.items() if isinstance(v, str)})
+ # i = self.options
+ # env.update({k: v for k, v in i.items() if isinstance(v, str)})
return env
# def use_llm(self, name: Optional[str] = None, provider: LLMType = LLMType.OPENAI) -> BaseLLM:
@@ -92,7 +95,3 @@ class Context(BaseModel):
if llm.cost_manager is None:
llm.cost_manager = self.cost_manager
return llm
-
-
-# Global context, not in Env
-CONTEXT = Context()
diff --git a/metagpt/context_mixin.py b/metagpt/context_mixin.py
index 1d239d2e4..59daa692f 100644
--- a/metagpt/context_mixin.py
+++ b/metagpt/context_mixin.py
@@ -7,17 +7,17 @@
"""
from typing import Optional
-from pydantic import BaseModel, ConfigDict, Field
+from pydantic import BaseModel, ConfigDict, Field, model_validator
from metagpt.config2 import Config
-from metagpt.context import CONTEXT, Context
+from metagpt.context import Context
from metagpt.provider.base_llm import BaseLLM
class ContextMixin(BaseModel):
"""Mixin class for context and config"""
- model_config = ConfigDict(arbitrary_types_allowed=True)
+ model_config = ConfigDict(arbitrary_types_allowed=True, extra="allow")
# Pydantic has bug on _private_attr when using inheritance, so we use private_* instead
# - https://github.com/pydantic/pydantic/issues/7142
@@ -32,18 +32,17 @@ class ContextMixin(BaseModel):
# Env/Role/Action will use this llm as private llm, or use self.context._llm instance
private_llm: Optional[BaseLLM] = Field(default=None, exclude=True)
- def __init__(
- self,
- context: Optional[Context] = CONTEXT,
- config: Optional[Config] = None,
- llm: Optional[BaseLLM] = None,
- **kwargs,
- ):
- """Initialize with config"""
- super().__init__(**kwargs)
- self.set_context(context)
- self.set_config(config)
- self.set_llm(llm)
+ @model_validator(mode="after")
+ def validate_context_mixin_extra(self):
+ self._process_context_mixin_extra()
+ return self
+
+ def _process_context_mixin_extra(self):
+ """Process the extra field"""
+ kwargs = self.model_extra or {}
+ self.set_context(kwargs.pop("context", None))
+ self.set_config(kwargs.pop("config", None))
+ self.set_llm(kwargs.pop("llm", None))
def set(self, k, v, override=False):
"""Set attribute"""
@@ -81,7 +80,7 @@ class ContextMixin(BaseModel):
"""Role context: role context > context"""
if self.private_context:
return self.private_context
- return CONTEXT
+ return Context()
@context.setter
def context(self, context: Context) -> None:
diff --git a/metagpt/environment/README.md b/metagpt/environment/README.md
new file mode 100644
index 000000000..9476ac75a
--- /dev/null
+++ b/metagpt/environment/README.md
@@ -0,0 +1,38 @@
+Here is a environment description of MetaGPT env for different situation.
+For now, the code only define the environment and still some todos like migrate roles/actions to current version.
+
+## Function
+- Define `ExtEnv`(Base Class) which help users to integrate with external environment like games through apis or construct the game logics.
+- Define `Environment`(Base Class) which is the env that MetaGPT directly used. And it includes roles and so on.
+- Define the `EnvAPIRegistry` to mark the read/write apis that `ExtEnv` provide observe/step ability. And then, users can call the particular one to get observation from env or feedback to env.
+
+## Usage
+
+init environment
+```
+android_env = env.create(EnvType.ANDROID)
+
+assistant = Role(name="Bob", profile="android assistant")
+team = Team(investment=10.0, env=android_env, roles=[assistant])
+```
+
+observe & step inside role's actions
+```
+from metagpt.environment.api.env_api import EnvAPIAbstract
+
+# get screenshot from ExtEnv
+screenshot_path: Path = env.observe(
+ EnvAPIAbstract(
+ api_name="get_screenshot", kwargs={"ss_name": f"{round_count}_before", "local_save_dir": task_dir}
+ )
+ )
+
+# do a `tap` action on the screen
+res = env.step(EnvAPIAbstract("system_tap", kwargs={"x": x, "y": y}))
+```
+
+## TODO
+- add android app operation assistant under `examples/android_assistant`
+- migrate roles/actions of werewolf game from old version into current version
+- migrate roles/actions of mincraft game from old version into current version
+- migrate roles/actions of stanford_town game from old version into current version
diff --git a/metagpt/environment/__init__.py b/metagpt/environment/__init__.py
new file mode 100644
index 000000000..692672fa7
--- /dev/null
+++ b/metagpt/environment/__init__.py
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# @Desc :
+
+from metagpt.environment.base_env import Environment
+from metagpt.environment.android_env.android_env import AndroidEnv
+from metagpt.environment.mincraft_env.mincraft_env import MincraftExtEnv
+from metagpt.environment.werewolf_env.werewolf_env import WerewolfEnv
+from metagpt.environment.stanford_town_env.stanford_town_env import StanfordTownEnv
+from metagpt.environment.software_env.software_env import SoftwareEnv
+
+
+__all__ = ["AndroidEnv", "MincraftExtEnv", "WerewolfEnv", "StanfordTownEnv", "SoftwareEnv", "Environment"]
diff --git a/metagpt/environment/android_env/__init__.py b/metagpt/environment/android_env/__init__.py
new file mode 100644
index 000000000..2bcf8efd0
--- /dev/null
+++ b/metagpt/environment/android_env/__init__.py
@@ -0,0 +1,3 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# @Desc :
diff --git a/metagpt/environment/android_env/android_env.py b/metagpt/environment/android_env/android_env.py
new file mode 100644
index 000000000..c27e20541
--- /dev/null
+++ b/metagpt/environment/android_env/android_env.py
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# @Desc : MG Android Env
+
+from pydantic import Field
+
+from metagpt.environment.android_env.android_ext_env import AndroidExtEnv
+from metagpt.environment.base_env import Environment
+
+
+class AndroidEnv(Environment, AndroidExtEnv):
+ rows: int = Field(default=0, description="rows of a grid on the screenshot")
+ cols: int = Field(default=0, description="cols of a grid on the screenshot")
diff --git a/metagpt/environment/android_env/android_ext_env.py b/metagpt/environment/android_env/android_ext_env.py
new file mode 100644
index 000000000..b81b2cd26
--- /dev/null
+++ b/metagpt/environment/android_env/android_ext_env.py
@@ -0,0 +1,157 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# @Desc : The Android external environment to integrate with Android apps
+
+import subprocess
+from pathlib import Path
+from typing import Any, Optional
+
+from pydantic import Field
+
+from metagpt.environment.android_env.const import ADB_EXEC_FAIL
+from metagpt.environment.base_env import ExtEnv, mark_as_readable, mark_as_writeable
+
+
+class AndroidExtEnv(ExtEnv):
+ device_id: Optional[str] = Field(default=None)
+ screenshot_dir: Optional[Path] = Field(default=None)
+ xml_dir: Optional[Path] = Field(default=None)
+ width: int = Field(default=720, description="device screen width")
+ height: int = Field(default=1080, description="device screen height")
+
+ def __init__(self, **data: Any):
+ super().__init__(**data)
+ if data.get("device_id"):
+ (width, height) = self.device_shape
+ self.width = data.get("width", width)
+ self.height = data.get("height", height)
+
+ @property
+ def adb_prefix_si(self):
+ """adb cmd prefix with `device_id` and `shell input`"""
+ return f"adb -s {self.device_id} shell input "
+
+ @property
+ def adb_prefix_shell(self):
+ """adb cmd prefix with `device_id` and `shell`"""
+ return f"adb -s {self.device_id} shell "
+
+ @property
+ def adb_prefix(self):
+ """adb cmd prefix with `device_id`"""
+ return f"adb -s {self.device_id} "
+
+ def execute_adb_with_cmd(self, adb_cmd: str) -> str:
+ res = subprocess.run(adb_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
+ exec_res = ADB_EXEC_FAIL
+ if not res.returncode:
+ exec_res = res.stdout.strip()
+ return exec_res
+
+ @property
+ def device_shape(self) -> tuple[int, int]:
+ adb_cmd = f"{self.adb_prefix_shell} wm size"
+ shape = (0, 0)
+ shape_res = self.execute_adb_with_cmd(adb_cmd)
+ if shape_res != ADB_EXEC_FAIL:
+ shape = tuple(map(int, shape_res.split(": ")[1].split("x")))
+ return shape
+
+ def list_devices(self):
+ adb_cmd = "adb devices"
+ res = self.execute_adb_with_cmd(adb_cmd)
+ devices = []
+ if res != ADB_EXEC_FAIL:
+ devices = res.split("\n")[1:]
+ devices = [device.split()[0] for device in devices]
+ return devices
+
+ @mark_as_readable
+ def get_screenshot(self, ss_name: str, local_save_dir: Path) -> Path:
+ """
+ ss_name: screenshot file name
+ local_save_dir: local dir to store image from virtual machine
+ """
+ assert self.screenshot_dir
+ ss_remote_path = Path(self.screenshot_dir).joinpath(f"{ss_name}.png")
+ ss_cmd = f"{self.adb_prefix_shell} screencap -p {ss_remote_path}"
+ ss_res = self.execute_adb_with_cmd(ss_cmd)
+
+ res = ADB_EXEC_FAIL
+ if ss_res != ADB_EXEC_FAIL:
+ ss_local_path = Path(local_save_dir).joinpath(f"{ss_name}.png")
+ pull_cmd = f"{self.adb_prefix} pull {ss_remote_path} {ss_local_path}"
+ pull_res = self.execute_adb_with_cmd(pull_cmd)
+ if pull_res != ADB_EXEC_FAIL:
+ res = ss_local_path
+ return Path(res)
+
+ @mark_as_readable
+ def get_xml(self, xml_name: str, local_save_dir: Path) -> Path:
+ xml_remote_path = Path(self.xml_dir).joinpath(f"{xml_name}.xml")
+ dump_cmd = f"{self.adb_prefix_shell} uiautomator dump {xml_remote_path}"
+ xml_res = self.execute_adb_with_cmd(dump_cmd)
+
+ res = ADB_EXEC_FAIL
+ if xml_res != ADB_EXEC_FAIL:
+ xml_local_path = Path(local_save_dir).joinpath(f"{xml_name}.xml")
+ pull_cmd = f"{self.adb_prefix} pull {xml_remote_path} {xml_local_path}"
+ pull_res = self.execute_adb_with_cmd(pull_cmd)
+ if pull_res != ADB_EXEC_FAIL:
+ res = xml_local_path
+ return Path(res)
+
+ @mark_as_writeable
+ def system_back(self) -> str:
+ adb_cmd = f"{self.adb_prefix_si} keyevent KEYCODE_BACK"
+ back_res = self.execute_adb_with_cmd(adb_cmd)
+ return back_res
+
+ @mark_as_writeable
+ def system_tap(self, x: int, y: int) -> str:
+ adb_cmd = f"{self.adb_prefix_si} tap {x} {y}"
+ tap_res = self.execute_adb_with_cmd(adb_cmd)
+ return tap_res
+
+ @mark_as_writeable
+ def user_input(self, input_txt: str) -> str:
+ input_txt = input_txt.replace(" ", "%s").replace("'", "")
+ adb_cmd = f"{self.adb_prefix_si} text {input_txt}"
+ input_res = self.execute_adb_with_cmd(adb_cmd)
+ return input_res
+
+ @mark_as_writeable
+ def user_longpress(self, x: int, y: int, duration: int = 500) -> str:
+ adb_cmd = f"{self.adb_prefix_si} swipe {x} {y} {x} {y} {duration}"
+ press_res = self.execute_adb_with_cmd(adb_cmd)
+ return press_res
+
+ @mark_as_writeable
+ def user_swipe(self, x: int, y: int, orient: str = "up", dist: str = "medium", if_quick: bool = False) -> str:
+ dist_unit = int(self.width / 10)
+ if dist == "long":
+ dist_unit *= 3
+ elif dist == "medium":
+ dist_unit *= 2
+
+ if orient == "up":
+ offset = 0, -2 * dist_unit
+ elif orient == "down":
+ offset = 0, 2 * dist_unit
+ elif orient == "left":
+ offset = -1 * dist_unit, 0
+ elif orient == "right":
+ offset = dist_unit, 0
+ else:
+ return ADB_EXEC_FAIL
+
+ duration = 100 if if_quick else 400
+ adb_cmd = f"{self.adb_prefix_si} swipe {x} {y} {x + offset[0]} {y + offset[1]} {duration}"
+ swipe_res = self.execute_adb_with_cmd(adb_cmd)
+ return swipe_res
+
+ @mark_as_writeable
+ def user_swipe_to(self, start: tuple[int, int], end: tuple[int, int], duration: int = 400):
+ adb_cmd = f"{self.adb_prefix_si} swipe {start[0]} {start[1]} {end[0]} {end[1]} {duration}"
+ swipe_res = self.execute_adb_with_cmd(adb_cmd)
+ return swipe_res
diff --git a/metagpt/environment/android_env/const.py b/metagpt/environment/android_env/const.py
new file mode 100644
index 000000000..8811289bf
--- /dev/null
+++ b/metagpt/environment/android_env/const.py
@@ -0,0 +1,6 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# @Desc :
+
+# For Android Assistant Agent
+ADB_EXEC_FAIL = "FAILED"
diff --git a/metagpt/environment/api/__init__.py b/metagpt/environment/api/__init__.py
new file mode 100644
index 000000000..2bcf8efd0
--- /dev/null
+++ b/metagpt/environment/api/__init__.py
@@ -0,0 +1,3 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# @Desc :
diff --git a/metagpt/environment/api/env_api.py b/metagpt/environment/api/env_api.py
new file mode 100644
index 000000000..1e6df544d
--- /dev/null
+++ b/metagpt/environment/api/env_api.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# @Desc : the environment api store
+
+from typing import Any, Callable, Union
+
+from pydantic import BaseModel, Field
+
+
+class EnvAPIAbstract(BaseModel):
+ """api/interface summary description"""
+
+ api_name: str = Field(default="", description="the api function name or id")
+ args: set = Field(default={}, description="the api function `args` params")
+ kwargs: dict = Field(default=dict(), description="the api function `kwargs` params")
+
+
+class EnvAPIRegistry(BaseModel):
+ """the registry to store environment w&r api/interface"""
+
+ registry: dict[str, dict[str, Union[dict, Any, str]]] = Field(default=dict(), exclude=True)
+
+ def get(self, api_name: str):
+ if api_name not in self.registry:
+ raise ValueError
+ return self.registry.get(api_name)
+
+ def __getitem__(self, api_name: str) -> Callable:
+ return self.get(api_name)
+
+ def __setitem__(self, api_name: str, func: Callable):
+ self.registry[api_name] = func
+
+ def __len__(self):
+ return len(self.registry)
+
+ def get_apis(self, as_str=True) -> dict[str, dict[str, Union[dict, Any, str]]]:
+ """return func schema without func instance"""
+ apis = dict()
+ for func_name, func_schema in self.registry.items():
+ new_func_schema = dict()
+ for key, value in func_schema.items():
+ if key == "func":
+ continue
+ new_func_schema[key] = str(value) if as_str else value
+ new_func_schema = new_func_schema
+ apis[func_name] = new_func_schema
+ return apis
+
+
+class WriteAPIRegistry(EnvAPIRegistry):
+ """just as a explicit class name"""
+
+ pass
+
+
+class ReadAPIRegistry(EnvAPIRegistry):
+ """just as a explicit class name"""
+
+ pass
diff --git a/metagpt/environment.py b/metagpt/environment/base_env.py
similarity index 50%
rename from metagpt/environment.py
rename to metagpt/environment/base_env.py
index 5a2dd339b..0e583ffb3 100644
--- a/metagpt/environment.py
+++ b/metagpt/environment/base_env.py
@@ -1,29 +1,101 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-"""
-@Time : 2023/5/11 22:12
-@Author : alexanderwu
-@File : environment.py
-@Modified By: mashenquan, 2023-11-1. According to Chapter 2.2.2 of RFC 116:
- 1. Remove the functionality of `Environment` class as a public message buffer.
- 2. Standardize the message forwarding behavior of the `Environment` class.
- 3. Add the `is_idle` property.
-@Modified By: mashenquan, 2023-11-4. According to the routing feature plan in Chapter 2.2.3.2 of RFC 113, the routing
- functionality is to be consolidated into the `Environment` class.
-"""
+# @Desc : base env of executing environment
+
import asyncio
-from typing import Iterable, Set
+from enum import Enum
+from typing import TYPE_CHECKING, Any, Dict, Iterable, Optional, Set, Union
from pydantic import BaseModel, ConfigDict, Field, SerializeAsAny, model_validator
from metagpt.context import Context
+from metagpt.environment.api.env_api import (
+ EnvAPIAbstract,
+ ReadAPIRegistry,
+ WriteAPIRegistry,
+)
from metagpt.logs import logger
-from metagpt.roles.role import Role
from metagpt.schema import Message
-from metagpt.utils.common import is_send_to
+from metagpt.utils.common import get_function_schema, is_coroutine_func, is_send_to
+
+if TYPE_CHECKING:
+ from metagpt.roles.role import Role # noqa: F401
-class Environment(BaseModel):
+class EnvType(Enum):
+ ANDROID = "Android"
+ GYM = "Gym"
+ WEREWOLF = "Werewolf"
+ MINCRAFT = "Mincraft"
+ STANFORDTOWN = "StanfordTown"
+
+
+env_write_api_registry = WriteAPIRegistry()
+env_read_api_registry = ReadAPIRegistry()
+
+
+def mark_as_readable(func):
+ """mark functionn as a readable one in ExtEnv, it observes something from ExtEnv"""
+ env_read_api_registry[func.__name__] = get_function_schema(func)
+ return func
+
+
+def mark_as_writeable(func):
+ """mark functionn as a writeable one in ExtEnv, it does something to ExtEnv"""
+ env_write_api_registry[func.__name__] = get_function_schema(func)
+ return func
+
+
+class ExtEnv(BaseModel):
+ """External Env to intergate actual game environment"""
+
+ def _check_api_exist(self, rw_api: Optional[str] = None):
+ if not rw_api:
+ raise ValueError(f"{rw_api} not exists")
+
+ def get_all_available_apis(self, mode: str = "read") -> list[Any]:
+ """get available read/write apis definition"""
+ assert mode in ["read", "write"]
+ if mode == "read":
+ return env_read_api_registry.get_apis()
+ else:
+ return env_write_api_registry.get_apis()
+
+ async def observe(self, env_action: Union[str, EnvAPIAbstract]):
+ """get observation from particular api of ExtEnv"""
+ if isinstance(env_action, str):
+ read_api = env_read_api_registry.get(api_name=env_action)["func"]
+ self._check_api_exist(read_api)
+ if is_coroutine_func(read_api):
+ res = await read_api(self)
+ else:
+ res = read_api(self)
+ elif isinstance(env_action, EnvAPIAbstract):
+ read_api = env_read_api_registry.get(api_name=env_action.api_name)["func"]
+ self._check_api_exist(read_api)
+ if is_coroutine_func(read_api):
+ res = await read_api(self, *env_action.args, **env_action.kwargs)
+ else:
+ res = read_api(self, *env_action.args, **env_action.kwargs)
+ return res
+
+ async def step(self, env_action: Union[str, Message, EnvAPIAbstract, list[EnvAPIAbstract]]):
+ """execute through particular api of ExtEnv"""
+ res = None
+ if isinstance(env_action, Message):
+ self.publish_message(env_action)
+ elif isinstance(env_action, EnvAPIAbstract):
+ write_api = env_write_api_registry.get(env_action.api_name)["func"]
+ self._check_api_exist(write_api)
+ if is_coroutine_func(write_api):
+ res = await write_api(self, *env_action.args, **env_action.kwargs)
+ else:
+ res = write_api(self, *env_action.args, **env_action.kwargs)
+
+ return res
+
+
+class Environment(ExtEnv):
"""环境,承载一批角色,角色可以向环境发布消息,可以被其他角色观察到
Environment, hosting a batch of roles, roles can publish messages to the environment, and can be observed by other roles
"""
@@ -31,8 +103,8 @@ class Environment(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True)
desc: str = Field(default="") # 环境描述
- roles: dict[str, SerializeAsAny[Role]] = Field(default_factory=dict, validate_default=True)
- member_addrs: dict[Role, Set] = Field(default_factory=dict, exclude=True)
+ roles: dict[str, SerializeAsAny["Role"]] = Field(default_factory=dict, validate_default=True)
+ member_addrs: Dict["Role", Set] = Field(default_factory=dict, exclude=True)
history: str = "" # For debug
context: Context = Field(default_factory=Context, exclude=True)
@@ -41,7 +113,7 @@ class Environment(BaseModel):
self.add_roles(self.roles.values())
return self
- def add_role(self, role: Role):
+ def add_role(self, role: "Role"):
"""增加一个在当前环境的角色
Add a role in the current environment
"""
@@ -49,7 +121,7 @@ class Environment(BaseModel):
role.set_env(self)
role.context = self.context
- def add_roles(self, roles: Iterable[Role]):
+ def add_roles(self, roles: Iterable["Role"]):
"""增加一批在当前环境的角色
Add a batch of characters in the current environment
"""
@@ -95,13 +167,13 @@ class Environment(BaseModel):
await asyncio.gather(*futures)
logger.debug(f"is idle: {self.is_idle}")
- def get_roles(self) -> dict[str, Role]:
+ def get_roles(self) -> dict[str, "Role"]:
"""获得环境内的所有角色
Process all Role runs at once
"""
return self.roles
- def get_role(self, name: str) -> Role:
+ def get_role(self, name: str) -> "Role":
"""获得环境内的指定角色
get all the environment roles
"""
@@ -129,3 +201,12 @@ class Environment(BaseModel):
def archive(self, auto_archive=True):
if auto_archive and self.context.git_repo:
self.context.git_repo.archive()
+
+ @classmethod
+ def model_rebuild(cls, **kwargs):
+ from metagpt.roles.role import Role # noqa: F401
+
+ super().model_rebuild(**kwargs)
+
+
+Environment.model_rebuild()
diff --git a/metagpt/environment/mincraft_env/__init__.py b/metagpt/environment/mincraft_env/__init__.py
new file mode 100644
index 000000000..2bcf8efd0
--- /dev/null
+++ b/metagpt/environment/mincraft_env/__init__.py
@@ -0,0 +1,3 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# @Desc :
diff --git a/metagpt/environment/mincraft_env/const.py b/metagpt/environment/mincraft_env/const.py
new file mode 100644
index 000000000..a7222f9cd
--- /dev/null
+++ b/metagpt/environment/mincraft_env/const.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# @Desc :
+
+from metagpt.const import METAGPT_ROOT
+
+# For Mincraft Game Agent
+MC_CKPT_DIR = METAGPT_ROOT / "data/mincraft/ckpt"
+MC_LOG_DIR = METAGPT_ROOT / "logs"
+MC_DEFAULT_WARMUP = {
+ "context": 15,
+ "biome": 10,
+ "time": 15,
+ "nearby_blocks": 0,
+ "other_blocks": 10,
+ "nearby_entities": 5,
+ "health": 15,
+ "hunger": 15,
+ "position": 0,
+ "equipment": 0,
+ "inventory": 0,
+ "optional_inventory_items": 7,
+ "chests": 0,
+ "completed_tasks": 0,
+ "failed_tasks": 0,
+}
+MC_CURRICULUM_OB = [
+ "context",
+ "biome",
+ "time",
+ "nearby_blocks",
+ "other_blocks",
+ "nearby_entities",
+ "health",
+ "hunger",
+ "position",
+ "equipment",
+ "inventory",
+ "chests",
+ "completed_tasks",
+ "failed_tasks",
+]
+MC_CORE_INVENTORY_ITEMS = r".*_log|.*_planks|stick|crafting_table|furnace"
+r"|cobblestone|dirt|coal|.*_pickaxe|.*_sword|.*_axe", # curriculum_agent: only show these items in inventory before optional_inventory_items reached in warm up
diff --git a/metagpt/environment/mincraft_env/mincraft_env.py b/metagpt/environment/mincraft_env/mincraft_env.py
new file mode 100644
index 000000000..6327aa3f4
--- /dev/null
+++ b/metagpt/environment/mincraft_env/mincraft_env.py
@@ -0,0 +1,391 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# @Desc : MG Mincraft Env
+# refs to `voyager voyager.py`
+
+import json
+import re
+import time
+from typing import Any, Iterable
+
+from langchain.embeddings.openai import OpenAIEmbeddings
+from langchain.vectorstores import Chroma
+from pydantic import ConfigDict, Field
+
+from metagpt.config2 import config as CONFIG
+from metagpt.environment.base_env import Environment
+from metagpt.environment.mincraft_env.const import MC_CKPT_DIR
+from metagpt.environment.mincraft_env.mincraft_ext_env import MincraftExtEnv
+from metagpt.logs import logger
+from metagpt.utils.common import load_mc_skills_code, read_json_file, write_json_file
+
+
+class MincraftEnv(Environment, MincraftExtEnv):
+ """MincraftEnv, including shared memory of cache and infomation between roles"""
+
+ model_config = ConfigDict(arbitrary_types_allowed=True)
+
+ event: dict[str, Any] = Field(default_factory=dict)
+ current_task: str = Field(default="Mine 1 wood log")
+ task_execution_time: float = Field(default=float)
+ context: str = Field(default="You can mine one of oak, birch, spruce, jungle, acacia, dark oak, or mangrove logs.")
+ code: str = Field(default="")
+ program_code: str = Field(default="") # write in skill/code/*.js
+ program_name: str = Field(default="")
+ critique: str = Field(default="")
+ skills: dict = Field(default_factory=dict) # for skills.json
+ retrieve_skills: list[str] = Field(default_factory=list)
+ event_summary: str = Field(default="")
+
+ qa_cache: dict[str, str] = Field(default_factory=dict)
+ completed_tasks: list[str] = Field(default_factory=list) # Critique things
+ failed_tasks: list[str] = Field(default_factory=list)
+
+ skill_desp: str = Field(default="")
+
+ chest_memory: dict[str, Any] = Field(default_factory=dict) # eg: {'(1344, 64, 1381)': 'Unknown'}
+ chest_observation: str = Field(default="") # eg: "Chests: None\n\n"
+
+ runtime_status: bool = False # equal to action execution status: success or failed
+
+ vectordb: Chroma = Field(default_factory=Chroma)
+
+ qa_cache_questions_vectordb: Chroma = Field(default_factory=Chroma)
+
+ @property
+ def progress(self):
+ # return len(self.completed_tasks) + 10 # Test only
+ return len(self.completed_tasks)
+
+ @property
+ def programs(self):
+ programs = ""
+ if self.code == "":
+ return programs # TODO: maybe fix 10054 now, a better way is isolating env.step() like voyager
+ for skill_name, entry in self.skills.items():
+ programs += f"{entry['code']}\n\n"
+ for primitives in load_mc_skills_code(): # TODO add skills_dir
+ programs += f"{primitives}\n\n"
+ return programs
+
+ def set_mc_port(self, mc_port):
+ super().set_mc_port(mc_port)
+ self.set_mc_resume()
+
+ def set_mc_resume(self):
+ self.qa_cache_questions_vectordb = Chroma(
+ collection_name="qa_cache_questions_vectordb",
+ embedding_function=OpenAIEmbeddings(),
+ persist_directory=f"{MC_CKPT_DIR}/curriculum/vectordb",
+ )
+
+ self.vectordb = Chroma(
+ collection_name="skill_vectordb",
+ embedding_function=OpenAIEmbeddings(),
+ persist_directory=f"{MC_CKPT_DIR}/skill/vectordb",
+ )
+
+ if CONFIG.resume:
+ logger.info(f"Loading Action Developer from {MC_CKPT_DIR}/action")
+ self.chest_memory = read_json_file(f"{MC_CKPT_DIR}/action/chest_memory.json")
+
+ logger.info(f"Loading Curriculum Agent from {MC_CKPT_DIR}/curriculum")
+ self.completed_tasks = read_json_file(f"{MC_CKPT_DIR}/curriculum/completed_tasks.json")
+ self.failed_tasks = read_json_file(f"{MC_CKPT_DIR}/curriculum/failed_tasks.json")
+
+ logger.info(f"Loading Skill Manager from {MC_CKPT_DIR}/skill\033[0m")
+ self.skills = read_json_file(f"{MC_CKPT_DIR}/skill/skills.json")
+
+ logger.info(f"Loading Qa Cache from {MC_CKPT_DIR}/curriculum\033[0m")
+ self.qa_cache = read_json_file(f"{MC_CKPT_DIR}/curriculum/qa_cache.json")
+
+ if self.vectordb._collection.count() == 0:
+ logger.info(self.vectordb._collection.count())
+ # Set vdvs for skills & qa_cache
+ skill_desps = [skill["description"] for program_name, skill in self.skills.items()]
+ program_names = [program_name for program_name, skill in self.skills.items()]
+ metadatas = [{"name": program_name} for program_name in program_names]
+ # add vectordb from file
+ self.vectordb.add_texts(
+ texts=skill_desps,
+ ids=program_names,
+ metadatas=metadatas,
+ )
+ self.vectordb.persist()
+
+ logger.info(self.qa_cache_questions_vectordb._collection.count())
+ if self.qa_cache_questions_vectordb._collection.count() == 0:
+ questions = [question for question, answer in self.qa_cache.items()]
+
+ self.qa_cache_questions_vectordb.add_texts(texts=questions)
+
+ self.qa_cache_questions_vectordb.persist()
+
+ logger.info(
+ f"INIT_CHECK: There are {self.vectordb._collection.count()} skills in vectordb and {len(self.skills)} skills in skills.json."
+ )
+ # Check if Skill Manager's vectordb right using
+ assert self.vectordb._collection.count() == len(self.skills), (
+ f"Skill Manager's vectordb is not synced with skills.json.\n"
+ f"There are {self.vectordb._collection.count()} skills in vectordb but {len(self.skills)} skills in skills.json.\n"
+ f"Did you set resume=False when initializing the manager?\n"
+ f"You may need to manually delete the vectordb directory for running from scratch."
+ )
+
+ logger.info(
+ f"INIT_CHECK: There are {self.qa_cache_questions_vectordb._collection.count()} qa_cache in vectordb and {len(self.qa_cache)} questions in qa_cache.json."
+ )
+ assert self.qa_cache_questions_vectordb._collection.count() == len(self.qa_cache), (
+ f"Curriculum Agent's qa cache question vectordb is not synced with qa_cache.json.\n"
+ f"There are {self.qa_cache_questions_vectordb._collection.count()} questions in vectordb "
+ f"but {len(self.qa_cache)} questions in qa_cache.json.\n"
+ f"Did you set resume=False when initializing the agent?\n"
+ f"You may need to manually delete the qa cache question vectordb directory for running from scratch.\n"
+ )
+
+ def register_roles(self, roles: Iterable["Minecraft"]):
+ for role in roles:
+ role.set_memory(self)
+
+ def update_event(self, event: dict):
+ if self.event == event:
+ return
+ self.event = event
+ self.update_chest_memory(event)
+ self.update_chest_observation()
+ # self.event_summary = self.summarize_chatlog(event)
+
+ def update_task(self, task: str):
+ self.current_task = task
+
+ def update_context(self, context: str):
+ self.context = context
+
+ def update_program_code(self, program_code: str):
+ self.program_code = program_code
+
+ def update_code(self, code: str):
+ self.code = code # action_developer.gen_action_code to HERE
+
+ def update_program_name(self, program_name: str):
+ self.program_name = program_name
+
+ def update_critique(self, critique: str):
+ self.critique = critique # critic_agent.check_task_success to HERE
+
+ def append_skill(self, skill: dict):
+ self.skills[self.program_name] = skill # skill_manager.retrieve_skills to HERE
+
+ def update_retrieve_skills(self, retrieve_skills: list):
+ self.retrieve_skills = retrieve_skills
+
+ def update_skill_desp(self, skill_desp: str):
+ self.skill_desp = skill_desp
+
+ async def update_qa_cache(self, qa_cache: dict):
+ self.qa_cache = qa_cache
+
+ def update_chest_memory(self, events: dict):
+ """
+ Input: events: Dict
+ Result: self.chest_memory update & save to json
+ """
+ nearbyChests = events[-1][1]["nearbyChests"]
+ for position, chest in nearbyChests.items():
+ if position in self.chest_memory:
+ if isinstance(chest, dict):
+ self.chest_memory[position] = chest
+ if chest == "Invalid":
+ logger.info(f"Action Developer removing chest {position}: {chest}")
+ self.chest_memory.pop(position)
+ else:
+ if chest != "Invalid":
+ logger.info(f"Action Developer saving chest {position}: {chest}")
+ self.chest_memory[position] = chest
+
+ write_json_file(f"{MC_CKPT_DIR}/action/chest_memory.json", self.chest_memory)
+
+ def update_chest_observation(self):
+ """
+ update chest_memory to chest_observation.
+ Refer to @ https://github.com/MineDojo/Voyager/blob/main/voyager/agents/action.py
+ """
+
+ chests = []
+ for chest_position, chest in self.chest_memory.items():
+ if isinstance(chest, dict) and len(chest) > 0:
+ chests.append(f"{chest_position}: {chest}")
+ for chest_position, chest in self.chest_memory.items():
+ if isinstance(chest, dict) and len(chest) == 0:
+ chests.append(f"{chest_position}: Empty")
+ for chest_position, chest in self.chest_memory.items():
+ if isinstance(chest, str):
+ assert chest == "Unknown"
+ chests.append(f"{chest_position}: Unknown items inside")
+ assert len(chests) == len(self.chest_memory)
+ if chests:
+ chests = "\n".join(chests)
+ self.chest_observation = f"Chests:\n{chests}\n\n"
+ else:
+ self.chest_observation = "Chests: None\n\n"
+
+ def summarize_chatlog(self, events):
+ def filter_item(message: str):
+ craft_pattern = r"I cannot make \w+ because I need: (.*)"
+ craft_pattern2 = r"I cannot make \w+ because there is no crafting table nearby"
+ mine_pattern = r"I need at least a (.*) to mine \w+!"
+ if re.match(craft_pattern, message):
+ self.event_summary = re.match(craft_pattern, message).groups()[0]
+ elif re.match(craft_pattern2, message):
+ self.event_summary = "a nearby crafting table"
+ elif re.match(mine_pattern, message):
+ self.event_summary = re.match(mine_pattern, message).groups()[0]
+ else:
+ self.event_summary = ""
+ return self.event_summary
+
+ chatlog = set()
+ for event_type, event in events:
+ if event_type == "onChat":
+ item = filter_item(event["onChat"])
+ if item:
+ chatlog.add(item)
+ self.event_summary = "I also need " + ", ".join(chatlog) + "." if chatlog else ""
+
+ def reset_block_info(self):
+ # revert all the placing event in the last step
+ pass
+
+ def update_exploration_progress(self, success: bool):
+ """
+ Split task into completed_tasks or failed_tasks
+ Args: info = {
+ "task": self.task,
+ "success": success,
+ "conversations": self.conversations,
+ }
+ """
+ self.runtime_status = success
+ task = self.current_task
+ if task.startswith("Deposit useless items into the chest at"):
+ return
+ if success:
+ logger.info(f"Completed task {task}.")
+ self.completed_tasks.append(task)
+ else:
+ logger.info(f"Failed to complete task {task}. Skipping to next task.")
+ self.failed_tasks.append(task)
+ # when not success, below to update event!
+ # revert all the placing event in the last step
+ blocks = []
+ positions = []
+ for event_type, event in self.event:
+ if event_type == "onSave" and event["onSave"].endswith("_placed"):
+ block = event["onSave"].split("_placed")[0]
+ position = event["status"]["position"]
+ blocks.append(block)
+ positions.append(position)
+ new_events = self.step(
+ f"await givePlacedItemBack(bot, {json.dumps(blocks)}, {json.dumps(positions)})",
+ programs=self.programs,
+ )
+ self.event[-1][1]["inventory"] = new_events[-1][1]["inventory"]
+ self.event[-1][1]["voxels"] = new_events[-1][1]["voxels"]
+
+ self.save_sorted_tasks()
+
+ def save_sorted_tasks(self):
+ updated_completed_tasks = []
+ # record repeated failed tasks
+ updated_failed_tasks = self.failed_tasks
+ # dedup but keep order
+ for task in self.completed_tasks:
+ if task not in updated_completed_tasks:
+ updated_completed_tasks.append(task)
+
+ # remove completed tasks from failed tasks
+ for task in updated_completed_tasks:
+ while task in updated_failed_tasks:
+ updated_failed_tasks.remove(task)
+
+ self.completed_tasks = updated_completed_tasks
+ self.failed_tasks = updated_failed_tasks
+
+ # dump to json
+ write_json_file(f"{MC_CKPT_DIR}/curriculum/completed_tasks.json", self.completed_tasks)
+ write_json_file(f"{MC_CKPT_DIR}/curriculum/failed_tasks.json", self.failed_tasks)
+
+ async def on_event_retrieve(self, *args):
+ """
+ Retrieve Minecraft events.
+
+ Returns:
+ list: A list of Minecraft events.
+
+ Raises:
+ Exception: If there is an issue retrieving events.
+ """
+ try:
+ self.reset(
+ options={
+ "mode": "soft",
+ "wait_ticks": 20,
+ }
+ )
+ # difficulty = "easy" if len(self.completed_tasks) > 15 else "peaceful"
+ difficulty = "peaceful"
+
+ events = self.step("bot.chat(`/time set ${getNextTime()}`);\n" + f"bot.chat('/difficulty {difficulty}');")
+ self.update_event(events)
+ return events
+ except Exception as e:
+ time.sleep(3) # wait for mineflayer to exit
+ # reset bot status here
+ events = self.reset(
+ options={
+ "mode": "hard",
+ "wait_ticks": 20,
+ "inventory": self.event[-1][1]["inventory"],
+ "equipment": self.event[-1][1]["status"]["equipment"],
+ "position": self.event[-1][1]["status"]["position"],
+ }
+ )
+ self.update_event(events)
+ logger.error(f"Failed to retrieve Minecraft events: {str(e)}")
+ return events
+
+ async def on_event_execute(self, *args):
+ """
+ Execute Minecraft events.
+
+ This function is used to obtain events from the Minecraft environment. Check the implementation in
+ the 'voyager/env/bridge.py step()' function to capture events generated within the game.
+
+ Returns:
+ list: A list of Minecraft events.
+
+ Raises:
+ Exception: If there is an issue retrieving events.
+ """
+ try:
+ events = self.step(
+ code=self.code,
+ programs=self.programs,
+ )
+ self.update_event(events)
+ return events
+ except Exception as e:
+ time.sleep(3) # wait for mineflayer to exit
+ # reset bot status here
+ events = self.reset(
+ options={
+ "mode": "hard",
+ "wait_ticks": 20,
+ "inventory": self.event[-1][1]["inventory"],
+ "equipment": self.event[-1][1]["status"]["equipment"],
+ "position": self.event[-1][1]["status"]["position"],
+ }
+ )
+ self.update_event(events)
+ logger.error(f"Failed to execute Minecraft events: {str(e)}")
+ return events
diff --git a/metagpt/environment/mincraft_env/mincraft_ext_env.py b/metagpt/environment/mincraft_env/mincraft_ext_env.py
new file mode 100644
index 000000000..b86250d8c
--- /dev/null
+++ b/metagpt/environment/mincraft_env/mincraft_ext_env.py
@@ -0,0 +1,180 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# @Desc : The Mincraft external environment to integrate with Mincraft game
+# refs to `voyager bridge.py`
+
+import json
+import time
+from typing import Optional
+
+import requests
+from pydantic import ConfigDict, Field, model_validator
+
+from metagpt.environment.base_env import ExtEnv, mark_as_writeable
+from metagpt.environment.mincraft_env.const import (
+ MC_CKPT_DIR,
+ MC_CORE_INVENTORY_ITEMS,
+ MC_CURRICULUM_OB,
+ MC_DEFAULT_WARMUP,
+ METAGPT_ROOT,
+)
+from metagpt.environment.mincraft_env.process_monitor import SubprocessMonitor
+from metagpt.logs import logger
+
+
+class MincraftExtEnv(ExtEnv):
+ model_config = ConfigDict(arbitrary_types_allowed=True)
+
+ mc_port: Optional[int] = Field(default=None)
+ server_host: str = Field(default="http://127.0.0.1")
+ server_port: str = Field(default=3000)
+ request_timeout: int = Field(default=600)
+
+ mineflayer: Optional[SubprocessMonitor] = Field(default=None, validate_default=True)
+
+ has_reset: bool = Field(default=False)
+ reset_options: Optional[dict] = Field(default=None)
+ connected: bool = Field(default=False)
+ server_paused: bool = Field(default=False)
+ warm_up: dict = Field(default=dict())
+
+ @property
+ def server(self) -> str:
+ return f"{self.server_host}:{self.server_port}"
+
+ @model_validator(mode="after")
+ def _post_init_ext_env(self):
+ if not self.mineflayer:
+ self.mineflayer = SubprocessMonitor(
+ commands=[
+ "node",
+ METAGPT_ROOT.joinpath("metagpt", "environment", "mincraft_env", "mineflayer", "index.js"),
+ str(self.server_port),
+ ],
+ name="mineflayer",
+ ready_match=r"Server started on port (\d+)",
+ )
+ if not self.warm_up:
+ warm_up = MC_DEFAULT_WARMUP
+ if "optional_inventory_items" in warm_up:
+ assert MC_CORE_INVENTORY_ITEMS is not None
+ # self.core_inv_items_regex = re.compile(MC_CORE_INVENTORY_ITEMS)
+ self.warm_up["optional_inventory_items"] = warm_up["optional_inventory_items"]
+ else:
+ self.warm_up["optional_inventory_items"] = 0
+ for key in MC_CURRICULUM_OB:
+ self.warm_up[key] = warm_up.get(key, MC_DEFAULT_WARMUP[key])
+ self.warm_up["nearby_blocks"] = 0
+ self.warm_up["inventory"] = 0
+ self.warm_up["completed_tasks"] = 0
+ self.warm_up["failed_tasks"] = 0
+
+ # init ckpt sub-forders
+ MC_CKPT_DIR.joinpath("curriculum/vectordb").mkdir(parents=True, exist_ok=True)
+ MC_CKPT_DIR.joinpath("action").mkdir(exist_ok=True)
+ MC_CKPT_DIR.joinpath("skill/code").mkdir(parents=True, exist_ok=True)
+ MC_CKPT_DIR.joinpath("skill/description").mkdir(exist_ok=True)
+ MC_CKPT_DIR.joinpath("skill/vectordb").mkdir(exist_ok=True)
+
+ def set_mc_port(self, mc_port: int):
+ self.mc_port = mc_port
+
+ @mark_as_writeable
+ def close(self) -> bool:
+ self.unpause()
+ if self.connected:
+ res = requests.post(f"{self.server}/stop")
+ if res.status_code == 200:
+ self.connected = False
+ self.mineflayer.stop()
+ return not self.connected
+
+ @mark_as_writeable
+ def check_process(self) -> dict:
+ retry = 0
+ while not self.mineflayer.is_running:
+ logger.info("Mineflayer process has exited, restarting")
+ self.mineflayer.run()
+ if not self.mineflayer.is_running:
+ if retry > 3:
+ logger.error("Mineflayer process failed to start")
+ raise {}
+ else:
+ retry += 1
+ continue
+ logger.info(self.mineflayer.ready_line)
+ res = requests.post(
+ f"{self.server}/start",
+ json=self.reset_options,
+ timeout=self.request_timeout,
+ )
+ if res.status_code != 200:
+ self.mineflayer.stop()
+ logger.error(f"Minecraft server reply with code {res.status_code}")
+ raise {}
+ return res.json()
+
+ @mark_as_writeable
+ def reset(self, *, seed=None, options=None) -> dict:
+ if options is None:
+ options = {}
+ if options.get("inventory", {}) and options.get("mode", "hard") != "hard":
+ logger.error("inventory can only be set when options is hard")
+ raise {}
+
+ self.reset_options = {
+ "port": self.mc_port,
+ "reset": options.get("mode", "hard"),
+ "inventory": options.get("inventory", {}),
+ "equipment": options.get("equipment", []),
+ "spread": options.get("spread", False),
+ "waitTicks": options.get("wait_ticks", 5),
+ "position": options.get("position", None),
+ }
+
+ self.unpause()
+ self.mineflayer.stop()
+ time.sleep(1) # wait for mineflayer to exit
+
+ returned_data = self.check_process()
+ self.has_reset = True
+ self.connected = True
+ # All the reset in step will be soft
+ self.reset_options["reset"] = "soft"
+ self.pause()
+ return json.loads(returned_data)
+
+ @mark_as_writeable
+ def step(self, code: str, programs: str = "") -> dict:
+ if not self.has_reset:
+ raise RuntimeError("Environment has not been reset yet")
+ self.check_process()
+ self.unpause()
+ data = {
+ "code": code,
+ "programs": programs,
+ }
+ res = requests.post(f"{self.server}/step", json=data, timeout=self.request_timeout)
+ if res.status_code != 200:
+ raise RuntimeError("Failed to step Minecraft server")
+ returned_data = res.json()
+ self.pause()
+ return json.loads(returned_data)
+
+ @mark_as_writeable
+ def pause(self) -> bool:
+ if self.mineflayer.is_running and not self.server_paused:
+ res = requests.post(f"{self.server}/pause")
+ if res.status_code == 200:
+ self.server_paused = True
+ return self.server_paused
+
+ @mark_as_writeable
+ def unpause(self) -> bool:
+ if self.mineflayer.is_running and self.server_paused:
+ res = requests.post(f"{self.server}/pause")
+ if res.status_code == 200:
+ self.server_paused = False
+ else:
+ logger.info(f"mineflayer pause result: {res.json()}")
+ return self.server_paused
diff --git a/metagpt/environment/mincraft_env/mineflayer/.gitignore b/metagpt/environment/mincraft_env/mineflayer/.gitignore
new file mode 100644
index 000000000..0fd468410
--- /dev/null
+++ b/metagpt/environment/mincraft_env/mineflayer/.gitignore
@@ -0,0 +1 @@
+!/lib
\ No newline at end of file
diff --git a/metagpt/environment/mincraft_env/mineflayer/.prettierignore b/metagpt/environment/mincraft_env/mineflayer/.prettierignore
new file mode 100644
index 000000000..1b07c39e9
--- /dev/null
+++ b/metagpt/environment/mincraft_env/mineflayer/.prettierignore
@@ -0,0 +1,3 @@
+# Ignore artifacts:
+build
+coverage
\ No newline at end of file
diff --git a/metagpt/environment/mincraft_env/mineflayer/.prettierrc.json b/metagpt/environment/mincraft_env/mineflayer/.prettierrc.json
new file mode 100644
index 000000000..0a02bcefd
--- /dev/null
+++ b/metagpt/environment/mincraft_env/mineflayer/.prettierrc.json
@@ -0,0 +1,3 @@
+{
+ "tabWidth": 4
+}
diff --git a/metagpt/environment/mincraft_env/mineflayer/index.js b/metagpt/environment/mincraft_env/mineflayer/index.js
new file mode 100644
index 000000000..7fb0a8787
--- /dev/null
+++ b/metagpt/environment/mincraft_env/mineflayer/index.js
@@ -0,0 +1,425 @@
+const fs = require("fs");
+const express = require("express");
+const bodyParser = require("body-parser");
+const mineflayer = require("mineflayer");
+
+const skills = require("./lib/skillLoader");
+const { initCounter, getNextTime } = require("./lib/utils");
+const obs = require("./lib/observation/base");
+const OnChat = require("./lib/observation/onChat");
+const OnError = require("./lib/observation/onError");
+const { Voxels, BlockRecords } = require("./lib/observation/voxels");
+const Status = require("./lib/observation/status");
+const Inventory = require("./lib/observation/inventory");
+const OnSave = require("./lib/observation/onSave");
+const Chests = require("./lib/observation/chests");
+const { plugin: tool } = require("mineflayer-tool");
+
+let bot = null;
+
+const app = express();
+
+app.use(bodyParser.json({ limit: "50mb" }));
+app.use(bodyParser.urlencoded({ limit: "50mb", extended: false }));
+
+app.post("/start", (req, res) => {
+ if (bot) onDisconnect("Restarting bot");
+ bot = null;
+ console.log(req.body);
+ bot = mineflayer.createBot({
+ host: "localhost", // minecraft server ip
+ port: req.body.port, // minecraft server port
+ username: "bot",
+ disableChatSigning: true,
+ checkTimeoutInterval: 60 * 60 * 1000,
+ });
+ bot.once("error", onConnectionFailed);
+
+ // Event subscriptions
+ bot.waitTicks = req.body.waitTicks;
+ bot.globalTickCounter = 0;
+ bot.stuckTickCounter = 0;
+ bot.stuckPosList = [];
+ bot.iron_pickaxe = false;
+
+ bot.on("kicked", onDisconnect);
+
+ // mounting will cause physicsTick to stop
+ bot.on("mount", () => {
+ bot.dismount();
+ });
+
+ bot.once("spawn", async () => {
+ bot.removeListener("error", onConnectionFailed);
+ let itemTicks = 1;
+ if (req.body.reset === "hard") {
+ bot.chat("/clear @s");
+ bot.chat("/kill @s");
+ const inventory = req.body.inventory ? req.body.inventory : {};
+ const equipment = req.body.equipment
+ ? req.body.equipment
+ : [null, null, null, null, null, null];
+ for (let key in inventory) {
+ bot.chat(`/give @s minecraft:${key} ${inventory[key]}`);
+ itemTicks += 1;
+ }
+ const equipmentNames = [
+ "armor.head",
+ "armor.chest",
+ "armor.legs",
+ "armor.feet",
+ "weapon.mainhand",
+ "weapon.offhand",
+ ];
+ for (let i = 0; i < 6; i++) {
+ if (i === 4) continue;
+ if (equipment[i]) {
+ bot.chat(
+ `/item replace entity @s ${equipmentNames[i]} with minecraft:${equipment[i]}`
+ );
+ itemTicks += 1;
+ }
+ }
+ }
+
+ if (req.body.position) {
+ bot.chat(
+ `/tp @s ${req.body.position.x} ${req.body.position.y} ${req.body.position.z}`
+ );
+ }
+
+ // if iron_pickaxe is in bot's inventory
+ if (
+ bot.inventory.items().find((item) => item.name === "iron_pickaxe")
+ ) {
+ bot.iron_pickaxe = true;
+ }
+
+ const { pathfinder } = require("mineflayer-pathfinder");
+ const tool = require("mineflayer-tool").plugin;
+ const collectBlock = require("mineflayer-collectblock").plugin;
+ const pvp = require("mineflayer-pvp").plugin;
+ const minecraftHawkEye = require("minecrafthawkeye");
+ bot.loadPlugin(pathfinder);
+ bot.loadPlugin(tool);
+ bot.loadPlugin(collectBlock);
+ bot.loadPlugin(pvp);
+ bot.loadPlugin(minecraftHawkEye);
+
+ // bot.collectBlock.movements.digCost = 0;
+ // bot.collectBlock.movements.placeCost = 0;
+
+ obs.inject(bot, [
+ OnChat,
+ OnError,
+ Voxels,
+ Status,
+ Inventory,
+ OnSave,
+ Chests,
+ BlockRecords,
+ ]);
+ skills.inject(bot);
+
+ if (req.body.spread) {
+ bot.chat(`/spreadplayers ~ ~ 0 300 under 80 false @s`);
+ await bot.waitForTicks(bot.waitTicks);
+ }
+
+ await bot.waitForTicks(bot.waitTicks * itemTicks);
+ res.json(bot.observe());
+
+ initCounter(bot);
+ bot.chat("/gamerule keepInventory true");
+ bot.chat("/gamerule doDaylightCycle false");
+ });
+
+ function onConnectionFailed(e) {
+ console.log(e);
+ bot = null;
+ res.status(400).json({ error: e });
+ }
+ function onDisconnect(message) {
+ if (bot.viewer) {
+ bot.viewer.close();
+ }
+ bot.end();
+ console.log(message);
+ bot = null;
+ }
+});
+
+app.post("/step", async (req, res) => {
+ // import useful package
+ let response_sent = false;
+ function otherError(err) {
+ console.log("Uncaught Error");
+ bot.emit("error", handleError(err));
+ bot.waitForTicks(bot.waitTicks).then(() => {
+ if (!response_sent) {
+ response_sent = true;
+ res.json(bot.observe());
+ }
+ });
+ }
+
+ process.on("uncaughtException", otherError);
+
+ const mcData = require("minecraft-data")(bot.version);
+ mcData.itemsByName["leather_cap"] = mcData.itemsByName["leather_helmet"];
+ mcData.itemsByName["leather_tunic"] =
+ mcData.itemsByName["leather_chestplate"];
+ mcData.itemsByName["leather_pants"] =
+ mcData.itemsByName["leather_leggings"];
+ mcData.itemsByName["leather_boots"] = mcData.itemsByName["leather_boots"];
+ mcData.itemsByName["lapis_lazuli_ore"] = mcData.itemsByName["lapis_ore"];
+ mcData.blocksByName["lapis_lazuli_ore"] = mcData.blocksByName["lapis_ore"];
+ const {
+ Movements,
+ goals: {
+ Goal,
+ GoalBlock,
+ GoalNear,
+ GoalXZ,
+ GoalNearXZ,
+ GoalY,
+ GoalGetToBlock,
+ GoalLookAtBlock,
+ GoalBreakBlock,
+ GoalCompositeAny,
+ GoalCompositeAll,
+ GoalInvert,
+ GoalFollow,
+ GoalPlaceBlock,
+ },
+ pathfinder,
+ Move,
+ ComputedPath,
+ PartiallyComputedPath,
+ XZCoordinates,
+ XYZCoordinates,
+ SafeBlock,
+ GoalPlaceBlockOptions,
+ } = require("mineflayer-pathfinder");
+ const { Vec3 } = require("vec3");
+
+ // Set up pathfinder
+ const movements = new Movements(bot, mcData);
+ bot.pathfinder.setMovements(movements);
+
+ bot.globalTickCounter = 0;
+ bot.stuckTickCounter = 0;
+ bot.stuckPosList = [];
+
+ function onTick() {
+ bot.globalTickCounter++;
+ if (bot.pathfinder.isMoving()) {
+ bot.stuckTickCounter++;
+ if (bot.stuckTickCounter >= 100) {
+ onStuck(1.5);
+ bot.stuckTickCounter = 0;
+ }
+ }
+ }
+
+ bot.on("physicTick", onTick);
+
+ // initialize fail count
+ let _craftItemFailCount = 0;
+ let _killMobFailCount = 0;
+ let _mineBlockFailCount = 0;
+ let _placeItemFailCount = 0;
+ let _smeltItemFailCount = 0;
+
+ // Retrieve array form post bod
+ const code = req.body.code;
+ const programs = req.body.programs;
+ bot.cumulativeObs = [];
+ await bot.waitForTicks(bot.waitTicks);
+ const r = await evaluateCode(code, programs);
+ process.off("uncaughtException", otherError);
+ if (r !== "success") {
+ bot.emit("error", handleError(r));
+ }
+ await returnItems();
+ // wait for last message
+ await bot.waitForTicks(bot.waitTicks);
+ if (!response_sent) {
+ response_sent = true;
+ res.json(bot.observe());
+ }
+ bot.removeListener("physicTick", onTick);
+
+ async function evaluateCode(code, programs) {
+ // Echo the code produced for players to see it. Don't echo when the bot code is already producing dialog or it will double echo
+ try {
+ await eval("(async () => {" + programs + "\n" + code + "})()");
+ return "success";
+ } catch (err) {
+ return err;
+ }
+ }
+
+ function onStuck(posThreshold) {
+ const currentPos = bot.entity.position;
+ bot.stuckPosList.push(currentPos);
+
+ // Check if the list is full
+ if (bot.stuckPosList.length === 5) {
+ const oldestPos = bot.stuckPosList[0];
+ const posDifference = currentPos.distanceTo(oldestPos);
+
+ if (posDifference < posThreshold) {
+ teleportBot(); // execute the function
+ }
+
+ // Remove the oldest time from the list
+ bot.stuckPosList.shift();
+ }
+ }
+
+ function teleportBot() {
+ const blocks = bot.findBlocks({
+ matching: (block) => {
+ return block.type === 0;
+ },
+ maxDistance: 1,
+ count: 27,
+ });
+
+ if (blocks) {
+ // console.log(blocks.length);
+ const randomIndex = Math.floor(Math.random() * blocks.length);
+ const block = blocks[randomIndex];
+ bot.chat(`/tp @s ${block.x} ${block.y} ${block.z}`);
+ } else {
+ bot.chat("/tp @s ~ ~1.25 ~");
+ }
+ }
+
+ function returnItems() {
+ bot.chat("/gamerule doTileDrops false");
+ const crafting_table = bot.findBlock({
+ matching: mcData.blocksByName.crafting_table.id,
+ maxDistance: 128,
+ });
+ if (crafting_table) {
+ bot.chat(
+ `/setblock ${crafting_table.position.x} ${crafting_table.position.y} ${crafting_table.position.z} air destroy`
+ );
+ bot.chat("/give @s crafting_table");
+ }
+ const furnace = bot.findBlock({
+ matching: mcData.blocksByName.furnace.id,
+ maxDistance: 128,
+ });
+ if (furnace) {
+ bot.chat(
+ `/setblock ${furnace.position.x} ${furnace.position.y} ${furnace.position.z} air destroy`
+ );
+ bot.chat("/give @s furnace");
+ }
+ if (bot.inventoryUsed() >= 32) {
+ // if chest is not in bot's inventory
+ if (!bot.inventory.items().find((item) => item.name === "chest")) {
+ bot.chat("/give @s chest");
+ }
+ }
+ // if iron_pickaxe not in bot's inventory and bot.iron_pickaxe
+ if (
+ bot.iron_pickaxe &&
+ !bot.inventory.items().find((item) => item.name === "iron_pickaxe")
+ ) {
+ bot.chat("/give @s iron_pickaxe");
+ }
+ bot.chat("/gamerule doTileDrops true");
+ }
+
+ function handleError(err) {
+ let stack = err.stack;
+ if (!stack) {
+ return err;
+ }
+ console.log(stack);
+ const final_line = stack.split("\n")[1];
+ const regex = /:(\d+):\d+\)/;
+
+ const programs_length = programs.split("\n").length;
+ let match_line = null;
+ for (const line of stack.split("\n")) {
+ const match = regex.exec(line);
+ if (match) {
+ const line_num = parseInt(match[1]);
+ if (line_num >= programs_length) {
+ match_line = line_num - programs_length;
+ break;
+ }
+ }
+ }
+ if (!match_line) {
+ return err.message;
+ }
+ let f_line = final_line.match(
+ /\((?.*):(?\d+):(?\d+)\)/
+ );
+ if (f_line && f_line.groups && fs.existsSync(f_line.groups.file)) {
+ const { file, line, pos } = f_line.groups;
+ const f = fs.readFileSync(file, "utf8").split("\n");
+ // let filename = file.match(/(?<=node_modules\\)(.*)/)[1];
+ let source = file + `:${line}\n${f[line - 1].trim()}\n `;
+
+ const code_source =
+ "at " +
+ code.split("\n")[match_line - 1].trim() +
+ " in your code";
+ return source + err.message + "\n" + code_source;
+ } else if (
+ f_line &&
+ f_line.groups &&
+ f_line.groups.file.includes("")
+ ) {
+ const { file, line, pos } = f_line.groups;
+ let source =
+ "Your code" +
+ `:${match_line}\n${code.split("\n")[match_line - 1].trim()}\n `;
+ let code_source = "";
+ if (line < programs_length) {
+ source =
+ "In your program code: " +
+ programs.split("\n")[line - 1].trim() +
+ "\n";
+ code_source = `at line ${match_line}:${code
+ .split("\n")
+ [match_line - 1].trim()} in your code`;
+ }
+ return source + err.message + "\n" + code_source;
+ }
+ return err.message;
+ }
+});
+
+app.post("/stop", (req, res) => {
+ bot.end();
+ res.json({
+ message: "Bot stopped",
+ });
+});
+
+app.post("/pause", (req, res) => {
+ if (!bot) {
+ res.status(400).json({ error: "Bot not spawned" });
+ return;
+ }
+ bot.chat("/pause");
+ bot.waitForTicks(bot.waitTicks).then(() => {
+ res.json({ message: "Success" });
+ });
+});
+
+// Server listening to PORT 3000
+
+const DEFAULT_PORT = 3000;
+const PORT = process.argv[2] || DEFAULT_PORT;
+app.listen(PORT, () => {
+ console.log(`Server started on port ${PORT}`);
+});
diff --git a/metagpt/environment/mincraft_env/mineflayer/lib/observation/base.js b/metagpt/environment/mincraft_env/mineflayer/lib/observation/base.js
new file mode 100644
index 000000000..b661a24b5
--- /dev/null
+++ b/metagpt/environment/mincraft_env/mineflayer/lib/observation/base.js
@@ -0,0 +1,45 @@
+class Observation {
+ constructor(bot) {
+ if (new.target === Observation) {
+ throw new TypeError(
+ "Cannot instantiate abstract class Observation"
+ );
+ }
+
+ this.bot = bot;
+ this.name = "Observation";
+ }
+
+ observe() {
+ throw new TypeError("Method 'observe()' must be implemented.");
+ }
+
+ reset() {}
+}
+
+function inject(bot, obs_list) {
+ bot.obsList = [];
+ bot.cumulativeObs = [];
+ bot.eventMemory = {};
+ obs_list.forEach((obs) => {
+ bot.obsList.push(new obs(bot));
+ });
+ bot.event = function (event_name) {
+ let result = {};
+ bot.obsList.forEach((obs) => {
+ if (obs.name.startsWith("on") && obs.name !== event_name) {
+ return;
+ }
+ result[obs.name] = obs.observe();
+ });
+ bot.cumulativeObs.push([event_name, result]);
+ };
+ bot.observe = function () {
+ bot.event("observe");
+ const result = bot.cumulativeObs;
+ bot.cumulativeObs = [];
+ return JSON.stringify(result);
+ };
+}
+
+module.exports = { Observation, inject };
diff --git a/metagpt/environment/mincraft_env/mineflayer/lib/observation/chests.js b/metagpt/environment/mincraft_env/mineflayer/lib/observation/chests.js
new file mode 100644
index 000000000..842bd171d
--- /dev/null
+++ b/metagpt/environment/mincraft_env/mineflayer/lib/observation/chests.js
@@ -0,0 +1,31 @@
+const { Observation } = require("./base");
+
+class Chests extends Observation {
+ constructor(bot) {
+ super(bot);
+ this.name = "nearbyChests";
+ this.chestsItems = {};
+ bot.on("closeChest", (chestItems, position) => {
+ this.chestsItems[position] = chestItems;
+ });
+ bot.on("removeChest", (chestPosition) => {
+ this.chestsItems[chestPosition] = "Invalid";
+ });
+ }
+
+ observe() {
+ const chests = this.bot.findBlocks({
+ matching: this.bot.registry.blocksByName.chest.id,
+ maxDistance: 16,
+ count: 999,
+ });
+ chests.forEach((chest) => {
+ if (!this.chestsItems.hasOwnProperty(chest)) {
+ this.chestsItems[chest] = "Unknown";
+ }
+ });
+ return this.chestsItems;
+ }
+}
+
+module.exports = Chests;
diff --git a/metagpt/environment/mincraft_env/mineflayer/lib/observation/inventory.js b/metagpt/environment/mincraft_env/mineflayer/lib/observation/inventory.js
new file mode 100644
index 000000000..0645d1bfa
--- /dev/null
+++ b/metagpt/environment/mincraft_env/mineflayer/lib/observation/inventory.js
@@ -0,0 +1,39 @@
+const { Observation } = require("./base");
+
+class Inventory extends Observation {
+ constructor(bot) {
+ super(bot);
+ this.name = "inventory";
+ }
+
+ observe() {
+ return listItems(this.bot);
+ }
+}
+
+function listItems(bot) {
+ const items = getInventoryItems(bot);
+ return items.reduce(itemToDict, {});
+}
+
+function getInventoryItems(bot) {
+ const inventory = bot.currentWindow || bot.inventory;
+ return inventory.items();
+}
+
+function itemToDict(acc, cur) {
+ if (cur.name && cur.count) {
+ //if both name and count property are defined
+ if (acc[cur.name]) {
+ //if the item is already in the dict
+ acc[cur.name] += cur.count;
+ } else {
+ //if the item is not in the dict
+ acc[cur.name] = cur.count;
+ }
+ }
+ return acc;
+}
+
+//export modules
+module.exports = Inventory;
diff --git a/metagpt/environment/mincraft_env/mineflayer/lib/observation/onChat.js b/metagpt/environment/mincraft_env/mineflayer/lib/observation/onChat.js
new file mode 100644
index 000000000..54b411e2a
--- /dev/null
+++ b/metagpt/environment/mincraft_env/mineflayer/lib/observation/onChat.js
@@ -0,0 +1,26 @@
+const Observation = require("./base.js").Observation;
+
+class onChat extends Observation {
+ constructor(bot) {
+ super(bot);
+ this.name = "onChat";
+ this.obs = "";
+ bot.on("chatEvent", (username, message) => {
+ // Save entity status to local variable
+ if (message.startsWith("/")) {
+ return;
+ }
+
+ this.obs += message;
+ this.bot.event(this.name);
+ });
+ }
+
+ observe() {
+ const result = this.obs;
+ this.obs = "";
+ return result;
+ }
+}
+
+module.exports = onChat;
diff --git a/metagpt/environment/mincraft_env/mineflayer/lib/observation/onError.js b/metagpt/environment/mincraft_env/mineflayer/lib/observation/onError.js
new file mode 100644
index 000000000..ac8fed9e5
--- /dev/null
+++ b/metagpt/environment/mincraft_env/mineflayer/lib/observation/onError.js
@@ -0,0 +1,22 @@
+const Observation = require("./base.js").Observation;
+
+class onError extends Observation {
+ constructor(bot) {
+ super(bot);
+ this.name = "onError";
+ this.obs = null;
+ bot.on("error", (err) => {
+ // Save entity status to local variable
+ this.obs = err;
+ this.bot.event(this.name);
+ });
+ }
+
+ observe() {
+ const result = this.obs;
+ this.obs = null;
+ return result;
+ }
+}
+
+module.exports = onError;
diff --git a/metagpt/environment/mincraft_env/mineflayer/lib/observation/onSave.js b/metagpt/environment/mincraft_env/mineflayer/lib/observation/onSave.js
new file mode 100644
index 000000000..e5983590f
--- /dev/null
+++ b/metagpt/environment/mincraft_env/mineflayer/lib/observation/onSave.js
@@ -0,0 +1,22 @@
+const Observation = require("./base.js").Observation;
+
+class onSave extends Observation {
+ constructor(bot) {
+ super(bot);
+ this.name = "onSave";
+ this.obs = null;
+ bot.on("save", (eventName) => {
+ // Save entity status to local variable
+ this.obs = eventName;
+ this.bot.event(this.name);
+ });
+ }
+
+ observe() {
+ const result = this.obs;
+ this.obs = null;
+ return result;
+ }
+}
+
+module.exports = onSave;
diff --git a/metagpt/environment/mincraft_env/mineflayer/lib/observation/status.js b/metagpt/environment/mincraft_env/mineflayer/lib/observation/status.js
new file mode 100644
index 000000000..b031fbcf2
--- /dev/null
+++ b/metagpt/environment/mincraft_env/mineflayer/lib/observation/status.js
@@ -0,0 +1,103 @@
+const Observation = require("./base.js").Observation;
+
+class Status extends Observation {
+ constructor(bot) {
+ super(bot);
+ this.name = "status";
+ }
+
+ observe() {
+ return {
+ health: this.bot.health,
+ food: this.bot.food,
+ saturation: this.bot.foodSaturation,
+ oxygen: this.bot.oxygenLevel,
+ position: this.bot.entity.position,
+ velocity: this.bot.entity.velocity,
+ yaw: this.bot.entity.yaw,
+ pitch: this.bot.entity.pitch,
+ onGround: this.bot.entity.onGround,
+ equipment: this.getEquipment(),
+ name: this.bot.entity.username,
+ timeSinceOnGround: this.bot.entity.timeSinceOnGround,
+ isInWater: this.bot.entity.isInWater,
+ isInLava: this.bot.entity.isInLava,
+ isInWeb: this.bot.entity.isInWeb,
+ isCollidedHorizontally: this.bot.entity.isCollidedHorizontally,
+ isCollidedVertically: this.bot.entity.isCollidedVertically,
+ biome: this.bot.blockAt(this.bot.entity.position)
+ ? this.bot.blockAt(this.bot.entity.position).biome.name
+ : "None",
+ entities: this.getEntities(),
+ timeOfDay: this.getTime(),
+ inventoryUsed: this.bot.inventoryUsed(),
+ elapsedTime: this.bot.globalTickCounter,
+ };
+ }
+
+ itemToObs(item) {
+ if (!item) return null;
+ return item.name;
+ }
+
+ getTime() {
+ const timeOfDay = this.bot.time.timeOfDay;
+ let time = "";
+ if (timeOfDay < 1000) {
+ time = "sunrise";
+ } else if (timeOfDay < 6000) {
+ time = "day";
+ } else if (timeOfDay < 12000) {
+ time = "noon";
+ } else if (timeOfDay < 13000) {
+ time = "sunset";
+ } else if (timeOfDay < 18000) {
+ time = "night";
+ } else if (timeOfDay < 22000) {
+ time = "midnight";
+ } else {
+ time = "sunrise";
+ }
+ return time;
+ }
+
+ // For each item in equipment, if it exists, return the name of the item
+ // otherwise return null
+ getEquipment() {
+ const slots = this.bot.inventory.slots;
+ const mainHand = this.bot.heldItem;
+ return slots
+ .slice(5, 9)
+ .concat(mainHand, slots[45])
+ .map(this.itemToObs);
+ }
+
+ getEntities() {
+ const entities = this.bot.entities;
+ if (!entities) return {};
+ // keep all monsters in one list, keep other mobs in another list
+ const mobs = {};
+ for (const id in entities) {
+ const entity = entities[id];
+ if (!entity.displayName) continue;
+ if (entity.name === "player" || entity.name === "item") continue;
+ if (entity.position.distanceTo(this.bot.entity.position) < 32) {
+ if (!mobs[entity.name]) {
+ mobs[entity.name] = entity.position.distanceTo(
+ this.bot.entity.position
+ );
+ } else if (
+ mobs[entity.name] >
+ entity.position.distanceTo(this.bot.entity.position)
+ ) {
+ mobs[entity.name] = entity.position.distanceTo(
+ this.bot.entity.position
+ );
+ }
+ }
+ }
+ return mobs;
+ }
+}
+
+module.exports = Status;
diff --git a/metagpt/environment/mincraft_env/mineflayer/lib/observation/voxels.js b/metagpt/environment/mincraft_env/mineflayer/lib/observation/voxels.js
new file mode 100644
index 000000000..ecb0c14b7
--- /dev/null
+++ b/metagpt/environment/mincraft_env/mineflayer/lib/observation/voxels.js
@@ -0,0 +1,67 @@
+// Blocks = require("./blocks")
+const { Observation } = require("./base");
+
+class Voxels extends Observation {
+ constructor(bot) {
+ super(bot);
+ this.name = "voxels";
+ }
+
+ observe() {
+ return Array.from(getSurroundingBlocks(this.bot, 8, 2, 8));
+ }
+}
+
+class BlockRecords extends Observation {
+ constructor(bot) {
+ super(bot);
+ this.name = "blockRecords";
+ this.records = new Set();
+ this.tick = 0;
+ bot.on("physicsTick", () => {
+ this.tick++;
+ if (this.tick >= 100) {
+ const items = getInventoryItems(this.bot);
+ getSurroundingBlocks(this.bot, 8, 2, 8).forEach((block) => {
+ if (!items.has(block)) this.records.add(block);
+ });
+ this.tick = 0;
+ }
+ });
+ }
+
+ observe() {
+ return Array.from(this.records);
+ }
+
+ reset() {
+ this.records = new Set();
+ }
+}
+
+function getSurroundingBlocks(bot, x_distance, y_distance, z_distance) {
+ const surroundingBlocks = new Set();
+
+ for (let x = -x_distance; x <= x_distance; x++) {
+ for (let y = -y_distance; y <= y_distance; y++) {
+ for (let z = -z_distance; z <= z_distance; z++) {
+ const block = bot.blockAt(bot.entity.position.offset(x, y, z));
+ if (block && block.type !== 0) {
+ surroundingBlocks.add(block.name);
+ }
+ }
+ }
+ }
+ // console.log(surroundingBlocks);
+ return surroundingBlocks;
+}
+
+function getInventoryItems(bot) {
+ const items = new Set();
+ bot.inventory.items().forEach((item) => {
+ if (item) items.add(item.name);
+ });
+ return items;
+}
+
+module.exports = { Voxels, BlockRecords };
diff --git a/metagpt/environment/mincraft_env/mineflayer/lib/skillLoader.js b/metagpt/environment/mincraft_env/mineflayer/lib/skillLoader.js
new file mode 100644
index 000000000..d78cf7820
--- /dev/null
+++ b/metagpt/environment/mincraft_env/mineflayer/lib/skillLoader.js
@@ -0,0 +1,79 @@
+function inject(bot) {
+ bot._sleep = bot.sleep;
+ bot.sleep = async (bedBlock) => {
+ await bot.waitForTicks(20);
+ await bot._sleep(bedBlock);
+ await bot.waitForTicks(135);
+ };
+
+ bot._fish = bot.fish;
+ bot.fish = async () => {
+ if (bot.heldItem?.name !== "fishing_rod") {
+ bot.chat("I'm not holding a fishing rod!");
+ return;
+ }
+ let timeout = null;
+ await Promise.race([
+ bot._fish(),
+ new Promise(
+ (resolve, reject) =>
+ (timeout = setTimeout(() => {
+ bot.activateItem();
+ reject(
+ new Error(
+ "Finishing timeout, make sure you get to and look at a water block!"
+ )
+ );
+ }, 60000))
+ ),
+ ]);
+ clearTimeout(timeout);
+ await bot.waitForTicks(20);
+ };
+
+ bot._consume = bot.consume;
+ bot.consume = async () => {
+ // action_count.activateItem++;
+ await bot._consume();
+ await bot.waitForTicks(20);
+ };
+
+ bot._useOn = bot.useOn;
+ bot.useOn = async (entity) => {
+ if (entity.position.distanceTo(bot.entity.position) > 6) {
+ bot.chat("Please goto a place near the entity first!");
+ return;
+ }
+ await bot._useOn(entity);
+ await bot.waitForTicks(20);
+ };
+
+ bot._activateBlock = bot.activateBlock;
+ bot.activateBlock = async (block) => {
+ if (block.position.distanceTo(bot.entity.position) > 6) {
+ bot.chat("Please goto a place near the block first!");
+ return;
+ }
+ // action_count.activateBlock++;
+ await bot._activateBlock(block);
+ };
+
+ bot._chat = bot.chat;
+ bot.chat = (message) => {
+ // action_count.chat++;
+ bot.emit("chatEvent", "bot", message);
+ bot._chat(message);
+ };
+
+ bot.inventoryUsed = () => {
+ return bot.inventory.slots.slice(9, 45).filter((item) => item !== null)
+ .length;
+ };
+
+ bot.save = function (eventName) {
+ bot.emit("save", eventName);
+ };
+}
+
+// export all control_primitives
+module.exports = { inject };
diff --git a/metagpt/environment/mincraft_env/mineflayer/lib/utils.js b/metagpt/environment/mincraft_env/mineflayer/lib/utils.js
new file mode 100644
index 000000000..68af30796
--- /dev/null
+++ b/metagpt/environment/mincraft_env/mineflayer/lib/utils.js
@@ -0,0 +1,31 @@
+let gameTimeCounter = 0;
+let gameTimeList = [];
+const initCounter = (bot) => {
+ gameTimeList = [];
+ for (let i = 0; i < 13000; i += 1000) {
+ gameTimeList.push(i);
+ }
+ for (let i = 13000; i < 24000; i += 2000) {
+ gameTimeList.push(i);
+ }
+ const timeOfDay = bot.time.timeOfDay;
+ for (let i = 0; i < gameTimeList.length; i++) {
+ if (gameTimeList[i] > timeOfDay) {
+ gameTimeCounter = i - 1;
+ break;
+ }
+ }
+};
+
+const getNextTime = () => {
+ gameTimeCounter++;
+ if (gameTimeCounter >= gameTimeList.length) {
+ gameTimeCounter = 0;
+ }
+ return gameTimeList[gameTimeCounter];
+};
+
+module.exports = {
+ initCounter,
+ getNextTime,
+};
diff --git a/metagpt/environment/mincraft_env/mineflayer/mineflayer-collectblock/.gitignore b/metagpt/environment/mincraft_env/mineflayer/mineflayer-collectblock/.gitignore
new file mode 100644
index 000000000..0578fdca3
--- /dev/null
+++ b/metagpt/environment/mincraft_env/mineflayer/mineflayer-collectblock/.gitignore
@@ -0,0 +1,107 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+
+# Diagnostic reports (https://nodejs.org/api/report.html)
+report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+*.lcov
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# TypeScript v1 declaration files
+typings/
+
+# TypeScript cache
+*.tsbuildinfo
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Microbundle cache
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
+.env.test
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+
+# Next.js build output
+.next
+
+# Nuxt.js build / generate output
+.nuxt
+dist
+
+# Gatsby files
+.cache/
+# Comment in the public line in if your project uses Gatsby and *not* Next.js
+# https://nextjs.org/blog/next-9-1#public-directory-support
+# public
+
+# vuepress build output
+.vuepress/dist
+
+# Serverless directories
+.serverless/
+
+# FuseBox cache
+.fusebox/
+
+# DynamoDB Local files
+.dynamodb/
+
+# TernJS port file
+.tern-port
+
+lib/
+package-lock.json
diff --git a/metagpt/environment/mincraft_env/mineflayer/mineflayer-collectblock/LICENSE b/metagpt/environment/mincraft_env/mineflayer/mineflayer-collectblock/LICENSE
new file mode 100644
index 000000000..f2896b56e
--- /dev/null
+++ b/metagpt/environment/mincraft_env/mineflayer/mineflayer-collectblock/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 TheDudeFromCI
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/metagpt/environment/mincraft_env/mineflayer/mineflayer-collectblock/README.md b/metagpt/environment/mincraft_env/mineflayer/mineflayer-collectblock/README.md
new file mode 100644
index 000000000..555acb761
--- /dev/null
+++ b/metagpt/environment/mincraft_env/mineflayer/mineflayer-collectblock/README.md
@@ -0,0 +1,89 @@
+
mineflayer-collectblock
+
A small utility plugin for allowing users to collect blocks using a higher level API.
\n\n \n \n \n \n\n\n\n----- styles.css\n/* styles.css */\nbody, html {\n margin: 0;\n padding: 0;\n font-family: \\'Arial\\', sans-serif;\n}\n\n#app {\n text-align: center;\n font-size: 18px;\n color: #776e65;\n}\n\nh1 {\n color: #776e65;\n font-size: 72px;\n font-weight: bold;\n margin: 20px 0;\n}\n\n.scores-container {\n display: flex;\n justify-content: center;\n margin-bottom: 20px;\n}\n\n.score-container, .best-container {\n background: #bbada0;\n padding: 10px;\n border-radius: 5px;\n margin: 0 10px;\n min-width: 100px;\n text-align: center;\n}\n\n.score-header, .best-header {\n color: #eee4da;\n font-size: 18px;\n margin-bottom: 5px;\n}\n\n.game-container {\n max-width: 500px;\n margin: 0 auto 20px;\n background: #bbada0;\n padding: 15px;\n border-radius: 10px;\n position: relative;\n}\n\n.grid-row {\n display: flex;\n}\n\n.grid-cell {\n background: #cdc1b4;\n width: 100px;\n height: 100px;\n margin: 5px;\n display: flex;\n justify-content: center;\n align-items: center;\n font-size: 35px;\n font-weight: bold;\n color: #776e65;\n border-radius: 3px;\n}\n\n/* Dynamic classes for different number cells */\n.number-cell-2 {\n background: #eee4da;\n}\n\n.number-cell-4 {\n background: #ede0c8;\n}\n\n.number-cell-8 {\n background: #f2b179;\n color: #f9f6f2;\n}\n\n.number-cell-16 {\n background: #f59563;\n color: #f9f6f2;\n}\n\n.number-cell-32 {\n background: #f67c5f;\n color: #f9f6f2;\n}\n\n.number-cell-64 {\n background: #f65e3b;\n color: #f9f6f2;\n}\n\n.number-cell-128 {\n background: #edcf72;\n color: #f9f6f2;\n}\n\n.number-cell-256 {\n background: #edcc61;\n color: #f9f6f2;\n}\n\n.number-cell-512 {\n background: #edc850;\n color: #f9f6f2;\n}\n\n.number-cell-1024 {\n background: #edc53f;\n color: #f9f6f2;\n}\n\n.number-cell-2048 {\n background: #edc22e;\n color: #f9f6f2;\n}\n\n/* Larger numbers need smaller font sizes */\n.number-cell-1024, .number-cell-2048 {\n font-size: 30px;\n}\n\nbutton {\n background-color: #8f7a66;\n color: #f9f6f2;\n border: none;\n border-radius: 3px;\n padding: 10px 20px;\n font-size: 18px;\n cursor: pointer;\n outline: none;\n}\n\nbutton:hover {\n background-color: #9f8b76;\n}\n\n----- storage.js\n## storage.js\nclass Storage {\n // 获取最高分\n getBestScore() {\n // 尝试从localStorage中获取最高分,如果不存在则默认为0\n const bestScore = localStorage.getItem(\\'bestScore\\');\n return bestScore ? Number(bestScore) : 0;\n }\n\n // 设置最高分\n setBestScore(score) {\n // 将最高分设置到localStorage中\n localStorage.setItem(\\'bestScore\\', score.toString());\n }\n}\n\n\n\n## Code to be Reviewed: game.js\n```Code\n## game.js\nclass Game {\n constructor() {\n this.board = this.createEmptyBoard();\n this.score = 0;\n this.bestScore = 0;\n }\n\n createEmptyBoard() {\n const board = [];\n for (let i = 0; i < 4; i++) {\n board[i] = [0, 0, 0, 0];\n }\n return board;\n }\n\n startGame() {\n this.board = this.createEmptyBoard();\n this.score = 0;\n this.addRandomTile();\n this.addRandomTile();\n }\n\n addRandomTile() {\n let emptyCells = [];\n for (let r = 0; r < 4; r++) {\n for (let c = 0; c < 4; c++) {\n if (this.board[r][c] === 0) {\n emptyCells.push({ r, c });\n }\n }\n }\n if (emptyCells.length > 0) {\n let randomCell = emptyCells[Math.floor(Math.random() * emptyCells.length)];\n this.board[randomCell.r][randomCell.c] = Math.random() < 0.9 ? 2 : 4;\n }\n }\n\n move(direction) {\n // This function will handle the logic for moving tiles\n // in the specified direction and merging them\n // It will also update the score and add a new random tile if the move is successful\n // The actual implementation of this function is complex and would require\n // a significant amount of code to handle all the cases for moving and merging tiles\n // For the purposes of this example, we will not implement the full logic\n // Instead, we will just call addRandomTile to simulate a move\n this.addRandomTile();\n }\n\n getBoard() {\n return this.board;\n }\n\n getScore() {\n return this.score;\n }\n\n getBestScore() {\n return this.bestScore;\n }\n\n setBestScore(score) {\n this.bestScore = score;\n }\n}\n\n```\n\"\"\"\n\n\nCODE_REVIEW_SMALLEST_CONTEXT = \"\"\"\n## Code to be Reviewed: game.js\n```Code\n// game.js\nclass Game {\n constructor() {\n this.board = this.createEmptyBoard();\n this.score = 0;\n this.bestScore = 0;\n }\n\n createEmptyBoard() {\n const board = [];\n for (let i = 0; i < 4; i++) {\n board[i] = [0, 0, 0, 0];\n }\n return board;\n }\n\n startGame() {\n this.board = this.createEmptyBoard();\n this.score = 0;\n this.addRandomTile();\n this.addRandomTile();\n }\n\n addRandomTile() {\n let emptyCells = [];\n for (let r = 0; r < 4; r++) {\n for (let c = 0; c < 4; c++) {\n if (this.board[r][c] === 0) {\n emptyCells.push({ r, c });\n }\n }\n }\n if (emptyCells.length > 0) {\n let randomCell = emptyCells[Math.floor(Math.random() * emptyCells.length)];\n this.board[randomCell.r][randomCell.c] = Math.random() < 0.9 ? 2 : 4;\n }\n }\n\n move(direction) {\n // This function will handle the logic for moving tiles\n // in the specified direction and merging them\n // It will also update the score and add a new random tile if the move is successful\n // The actual implementation of this function is complex and would require\n // a significant amount of code to handle all the cases for moving and merging tiles\n // For the purposes of this example, we will not implement the full logic\n // Instead, we will just call addRandomTile to simulate a move\n this.addRandomTile();\n }\n\n getBoard() {\n return this.board;\n }\n\n getScore() {\n return this.score;\n }\n\n getBestScore() {\n return this.bestScore;\n }\n\n setBestScore(score) {\n this.bestScore = score;\n }\n}\n\n```\n\"\"\"\n\n\nCODE_REVIEW_SAMPLE = \"\"\"\n## Code Review: game.js\n1. The code partially implements the requirements. The `Game` class is missing the full implementation of the `move` method, which is crucial for the game\\'s functionality.\n2. The code logic is not completely correct. The `move` method is not implemented, which means the game cannot process player moves.\n3. The existing code follows the \"Data structures and interfaces\" in terms of class structure but lacks full method implementations.\n4. Not all functions are implemented. The `move` method is incomplete and does not handle the logic for moving and merging tiles.\n5. All necessary pre-dependencies seem to be imported since the code does not indicate the need for additional imports.\n6. The methods from other files (such as `Storage`) are not being used in the provided code snippet, but the class structure suggests that they will be used correctly.\n\n## Actions\n1. Implement the `move` method to handle tile movements and merging. This is a complex task that requires careful consideration of the game\\'s rules and logic. Here is a simplified version of how one might begin to implement the `move` method:\n ```javascript\n move(direction) {\n // Simplified logic for moving tiles up\n if (direction === \\'up\\') {\n for (let col = 0; col < 4; col++) {\n let tiles = this.board.map(row => row[col]).filter(val => val !== 0);\n let merged = [];\n for (let i = 0; i < tiles.length; i++) {\n if (tiles[i] === tiles[i + 1]) {\n tiles[i] *= 2;\n this.score += tiles[i];\n tiles[i + 1] = 0;\n merged.push(i);\n }\n }\n tiles = tiles.filter(val => val !== 0);\n while (tiles.length < 4) {\n tiles.push(0);\n }\n for (let row = 0; row < 4; row++) {\n this.board[row][col] = tiles[row];\n }\n }\n }\n // Additional logic needed for \\'down\\', \\'left\\', \\'right\\'\n // ...\n this.addRandomTile();\n }\n ```\n2. Integrate the `Storage` class methods to handle the best score. This means updating the `startGame` and `setBestScore` methods to use `Storage` for retrieving and setting the best score:\n ```javascript\n startGame() {\n this.board = this.createEmptyBoard();\n this.score = 0;\n this.bestScore = new Storage().getBestScore(); // Retrieve the best score from storage\n this.addRandomTile();\n this.addRandomTile();\n }\n\n setBestScore(score) {\n if (score > this.bestScore) {\n this.bestScore = score;\n new Storage().setBestScore(score); // Set the new best score in storage\n }\n }\n ```\n\n## Code Review Result\nLBTM\n\n```\n\"\"\"\n\n\nWRITE_CODE_NODE = ActionNode.from_children(\"WRITE_REVIEW_NODE\", [REVIEW, REVIEW_RESULT, NEXT_STEPS])\nWRITE_MOVE_NODE = ActionNode.from_children(\"WRITE_MOVE_NODE\", [WRITE_DRAFT, WRITE_FUNCTION])\n\n\nCR_FOR_MOVE_FUNCTION_BY_3 = \"\"\"\nThe move function implementation provided appears to be well-structured and follows a clear logic for moving and merging tiles in the specified direction. However, there are a few potential improvements that could be made to enhance the code:\n\n1. Encapsulation: The logic for moving and merging tiles could be encapsulated into smaller, reusable functions to improve readability and maintainability.\n\n2. Magic Numbers: There are some magic numbers (e.g., 4, 3) used in the loops that could be replaced with named constants for improved readability and easier maintenance.\n\n3. Comments: Adding comments to explain the logic and purpose of each section of the code can improve understanding for future developers who may need to work on or maintain the code.\n\n4. Error Handling: It's important to consider error handling for unexpected input or edge cases to ensure the function behaves as expected in all scenarios.\n\nOverall, the code could benefit from refactoring to improve readability, maintainability, and extensibility. If you would like, I can provide a refactored version of the move function that addresses these considerations.\n\"\"\"\n\n\nclass WriteCodeAN(Action):\n \"\"\"Write a code review for the context.\"\"\"\n\n async def run(self, context):\n self.llm.system_prompt = \"You are an outstanding engineer and can implement any code\"\n return await WRITE_MOVE_NODE.fill(context=context, llm=self.llm, schema=\"json\")\n\n\nasync def main():\n await WriteCodeAN().run(CODE_REVIEW_SMALLEST_CONTEXT)\n\n\nif __name__ == \"__main__\":\n asyncio.run(main())\n\n```\n\n---\nTranslate the code above into Mermaid Sequence Diagram.": "```mermaid\nsequenceDiagram\n participant User\n participant WriteCodeAN\n participant WRITE_MOVE_NODE\n\n User->>WriteCodeAN: Run\n WriteCodeAN->>WRITE_MOVE_NODE: Fill\n WRITE_MOVE_NODE->>WriteCodeAN: Filled\n WriteCodeAN->>User: Return Filled Context\n```",
+ "You are a function parser.#MSG_SEP#You can convert spoken words into function parameters.#SYSTEM_MSG_END#text_to_image function parameters description:\nparameter `text`: The text used for image conversion.\nparameter `size_type`: size type\n\n---\nExamples:\nIf want you to do `Draw a girl`, return `text_to_image(text=\"Draw a girl\", size_type=\"512x512\")` brief and clear.\nIf want you to do `Draw an apple`, return `text_to_image(text=\"Draw an apple\", size_type=\"512x512\")` brief and clear.\n\n---\n\nRefer to the `text_to_image` function description, and fill in the function parameters according to the example \"I want you to do xx\" in the Examples section.\nNow I want you to do `Draw an apple`, return function parameters in Examples format above, brief and clear.": "`text_to_image(text=\"Draw an apple\", size_type=\"512x512\")`",
+ "\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 the Pygame library to create the game interface and handle user input. The game logic will be implemented using Python classes and data structures.\", \"File list\": [\"main.py\", \"game.py\"], \"Data structures and interfaces\": \"classDiagram\\n class Game {\\n -grid: List[List[int]]\\n -score: int\\n -game_over: bool\\n +__init__()\\n +reset_game()\\n +move(direction: str)\\n +is_game_over() bool\\n +get_empty_cells() List[Tuple[int, int]]\\n +add_new_tile()\\n +get_score() int\\n }\\n class UI {\\n -game: Game\\n +__init__(game: Game)\\n +draw_grid()\\n +draw_score()\\n +draw_game_over()\\n +handle_input()\\n }\\n Game --> UI\", \"Program call flow\": \"sequenceDiagram\\n participant M as Main\\n participant G as Game\\n participant U as UI\\n M->>G: reset_game()\\n M->>U: draw_grid()\\n M->>U: draw_score()\\n M->>U: handle_input()\\n U->>G: move(direction)\\n G->>G: add_new_tile()\\n G->>U: draw_grid()\\n G->>U: draw_score()\\n G->>U: draw_game_over()\\n G->>G: is_game_over()\\n G->>G: get_empty_cells()\\n G->>G: get_score()\", \"Anything UNCLEAR\": \"...\"}\n\n## Tasks\n{\"Required Python packages\": [\"pygame==2.0.1\"], \"Required Other language third-party packages\": [\"No third-party dependencies required\"], \"Logic Analysis\": [[\"game.py\", \"Contains Game class and related functions for game logic\"], [\"main.py\", \"Contains main function, initializes the game and UI\"]], \"Task list\": [\"game.py\", \"main.py\"], \"Full API spec\": \"\", \"Shared Knowledge\": \"The game logic will be implemented using Python classes and data structures. The Pygame library will be used to create the game interface and handle user input.\", \"Anything UNCLEAR\": \"...\"}\n\n## Legacy Code\n```Code\n----- main.py\nif __name__ == \"__main__\":\nmain()\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: game.py\n```python\n## game.py\n...\n```\n\n# Instruction: Based on the context, follow \"Format example\", write code.\n\n## Code: game.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## game.py\n\nfrom typing import List, Tuple\nimport random\n\nclass Game:\n def __init__(self):\n self.grid: List[List[int]] = [[0 for _ in range(4)] for _ in range(4)]\n self.score: int = 0\n self.game_over: bool = False\n\n def reset_game(self):\n self.grid = [[0 for _ in range(4)] for _ in range(4)]\n self.score = 0\n self.game_over = False\n self.add_new_tile()\n self.add_new_tile()\n\n def move(self, direction: str):\n # Implement the logic to move the tiles in the specified direction\n pass\n\n def is_game_over(self) -> bool:\n # Implement the logic to check if the game is over\n pass\n\n def get_empty_cells(self) -> List[Tuple[int, int]]:\n # Implement the logic to get the coordinates of empty cells in the grid\n pass\n\n def add_new_tile(self):\n empty_cells = self.get_empty_cells()\n if empty_cells:\n row, col = random.choice(empty_cells)\n self.grid[row][col] = 2 if random.random() < 0.9 else 4\n\n def get_score(self) -> int:\n return self.score\n```",
+ "\n## context\n\n### Project Name\n\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 \"Project Name\": \"game_2048\",\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- Project Name: # According to the content of \"Original Requirements,\" name the project using snake case style , like 'game_2048' or 'simple_crm.\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 \"Project Name\": \"language_model_search\",\n \"Product Goals\": [\n \"提供基于大语言模型的高效搜索功能\",\n \"整合私有知识库,实现个性化搜索结果\",\n \"实现搜索结果的自动总结功能\"\n ],\n \"User Stories\": [\n \"作为用户,我希望能够快速找到我需要的信息\",\n \"作为用户,我希望搜索结果能够根据我的偏好进行个性化排序\",\n \"作为用户,我希望搜索结果能够自动总结,方便我快速了解内容\"\n ],\n \"Competitive Analysis\": [\n \"搜索引擎A: 提供基于大语言模型的搜索功能,但个性化程度较低\",\n \"知识库B: 整合私有知识库,但搜索速度较慢\",\n \"语言模型搜索C: 提供搜索结果自动总结功能,但搜索准确度有待提高\"\n ],\n \"Competitive Quadrant Chart\": \"quadrantChart\\n title \\\"搜索引擎竞争分析\\\"\\n x-axis \\\"低搜索准确度\\\" --> \\\"高搜索准确度\\\"\\n y-axis \\\"低个性化程度\\\" --> \\\"高个性化程度\\\"\\n quadrant-1 \\\"需改进\\\"\\n quadrant-2 \\\"需提升\\\"\\n quadrant-3 \\\"重新评估\\\"\\n quadrant-4 \\\"扩展发展\\\"\\n \\\"搜索引擎A\\\": [0.6, 0.3]\\n \\\"知识库B\\\": [0.4, 0.2]\\n \\\"语言模型搜索C\\\": [0.7, 0.5]\\n \\\"我们的目标产品\\\": [0.8, 0.7]\",\n \"Requirement Analysis\": \"\",\n \"Requirement Pool\": [\n [\n \"P0\",\n \"基于大语言模型的高效搜索功能\"\n ],\n [\n \"P1\",\n \"整合私有知识库,实现个性化搜索结果\"\n ],\n [\n \"P2\",\n \"实现搜索结果的自动总结功能\"\n ]\n ],\n \"UI Design draft\": \"搜索页面简洁明了,搜索结果清晰展示,提供个性化排序和自动总结功能。\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]",
+ "\n## context\nNone\n\n-----\n\n## format example\n[CONTENT]\n{\n \"Project Name\": \"game_2048\"\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- Project Name: # According to the content of \"Original Requirements,\" name the project using snake case style with underline, like 'game_2048' or 'simple_crm.\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 \"Project Name\": \"game_2048\"\n}\n[/CONTENT]",
+ "\n## context\nCompare the key's value of nodes_output and the corresponding requirements one by one. If a key's value that does not match the requirement is found, provide the comment content on how to modify it. No output is required for matching keys.\n\n### nodes_output\n{\"Project Name\": {\"value\": \"game snake\", \"requirement\": \"According to the content of \\\"Original Requirements,\\\" name the project using snake case style with underline, like 'game_2048' or 'simple_crm.\"}}\n\n-----\n\n## format example\n[CONTENT]\n{\n \"key1\": \"comment1\",\n \"key2\": \"comment2\",\n \"keyn\": \"commentn\"\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- key1: # the first key name of mismatch key\n- key2: # the second key name of mismatch key\n- keyn: # the last key name of mismatch key\n\n## constraint\nFormat: output wrapped inside [CONTENT][/CONTENT] like format example, nothing else.\n\n## action\nFollow format example's json format, generate output and make sure it follows the format example.\n": "[CONTENT]\n{\n \"Project Name\": \"Use snake case style with underline, like 'game_2048' or 'simple_crm.'\"\n}\n[/CONTENT]",
+ "\n## context\nCompare the key's value of nodes_output and the corresponding requirements one by one. If a key's value that does not match the requirement is found, provide the comment content on how to modify it. No output is required for matching keys.\n\n### nodes_output\n{\"Project Name\": {\"value\": \"game_2048\", \"requirement\": \"According to the content of \\\"Original Requirements,\\\" name the project using snake case style with underline, like 'game_2048' or 'simple_crm.\"}}\n\n-----\n\n## format example\n[CONTENT]\n{\n \"key1\": \"comment1\",\n \"key2\": \"comment2\",\n \"keyn\": \"commentn\"\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- key1: # the first key name of mismatch key\n- key2: # the second key name of mismatch key\n- keyn: # the last key name of mismatch key\n\n## constraint\nFormat: output wrapped inside [CONTENT][/CONTENT] like format example, nothing else.\n\n## action\nFollow format example's json format, generate output and make sure it follows the format example.\n": "[CONTENT]\n{\n \"Project Name\": \"According to the content of \\\"Original Requirements,\\\" name the project using snake case style with underline, like 'game_2048' or 'simple_crm.\"\n}\n[/CONTENT]",
+ "\n## context\nchange the nodes_output key's value to meet its comment and no need to add extra comment.\n\n### nodes_output\n{\"Project Name\": {\"value\": \"game snake\", \"comment\": \"Use snake case style with underline, like 'game_2048' or 'simple_crm.'\"}}\n\n-----\n\n## format example\n[CONTENT]\n{\n \"Project Name\": \"game_2048\"\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- Project Name: # According to the content of \"Original Requirements,\" name the project using snake case style with underline, like 'game_2048' or 'simple_crm.\n\n\n## constraint\nFormat: output wrapped inside [CONTENT][/CONTENT] like format example, nothing else.\n\n## action\nFollow format example's json format, generate output and make sure it follows the format example.\n": "[CONTENT]\n{\n \"Project Name\": \"game_snake\"\n}\n[/CONTENT]",
+ "\n## context\nCompare the key's value of nodes_output and the corresponding requirements one by one. If a key's value that does not match the requirement is found, provide the comment content on how to modify it. No output is required for matching keys.\n\n### nodes_output\n{\"Project Name\": {\"value\": \"game_snake\", \"requirement\": \"According to the content of \\\"Original Requirements,\\\" name the project using snake case style with underline, like 'game_2048' or 'simple_crm.\"}}\n\n-----\n\n## format example\n[CONTENT]\n{\n \"key1\": \"comment1\",\n \"key2\": \"comment2\",\n \"keyn\": \"commentn\"\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- key1: # the first key name of mismatch key\n- key2: # the second key name of mismatch key\n- keyn: # the last key name of mismatch key\n\n## constraint\nFormat: output wrapped inside [CONTENT][/CONTENT] like format example, nothing else.\n\n## action\nFollow format example's json format, generate output and make sure it follows the format example.\n": "[CONTENT]\n{\n \"Project Name\": \"The project name should be in snake case style with underscores, such as 'game_2048' or 'simple_crm'.\"\n}\n[/CONTENT]",
+ "\n## context\nchange the nodes_output key's value to meet its comment and no need to add extra comment.\n\n### nodes_output\n{\"Project Name\": {\"value\": \"game_snake\", \"comment\": \"The project name should be in snake case style with underscores, such as 'game_2048' or 'simple_crm'.\"}}\n\n-----\n\n## format example\n[CONTENT]\n{\n \"Project Name\": \"game_2048\"\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- Project Name: # According to the content of \"Original Requirements,\" name the project using snake case style with underline, like 'game_2048' or 'simple_crm.\n\n\n## constraint\nFormat: output wrapped inside [CONTENT][/CONTENT] like format example, nothing else.\n\n## action\nFollow format example's json format, generate output and make sure it follows the format example.\n": "[CONTENT]\n{\n \"Project Name\": \"game_snake\"\n}\n[/CONTENT]",
+ "You are an action classifier#SYSTEM_MSG_END#If the text explicitly want you to Generate a voice file from the input text, text-to-speech, return `[SKILL]: text_to_speech` brief and clear. For instance: [SKILL]: text_to_speech\nIf the text explicitly want you to Create a drawing based on the text., return `[SKILL]: text_to_image` brief and clear. For instance: [SKILL]: text_to_image\nIf the text explicitly want you to Perform Google searches to provide real-time information., return `[SKILL]: web_search` brief and clear. For instance: [SKILL]: web_search\nOtherwise, return `[TALK]: {talk}` brief and clear. For instance: if {talk} is \"xxxx\" return [TALK]: xxxx\n\nNow what specific action is explicitly mentioned in the text: No, I do not have a poison apple. Do you have a poison apple?\n": "[TALK]: No, I do not have a poison apple. Do you have a poison apple?",
+ "You are an action classifier#SYSTEM_MSG_END#If the text explicitly want you to Generate a voice file from the input text, text-to-speech, return `[SKILL]: text_to_speech` brief and clear. For instance: [SKILL]: text_to_speech\nIf the text explicitly want you to Create a drawing based on the text., return `[SKILL]: text_to_image` brief and clear. For instance: [SKILL]: text_to_image\nIf the text explicitly want you to Perform Google searches to provide real-time information., return `[SKILL]: web_search` brief and clear. For instance: [SKILL]: web_search\nOtherwise, return `[TALK]: {talk}` brief and clear. For instance: if {talk} is \"xxxx\" return [TALK]: xxxx\n\nNow what specific action is explicitly mentioned in the text: Sure, I can draw you an apple. Draw me an apple.\n": "[SKILL]: text_to_image",
+ "You are a function parser.#MSG_SEP#You can convert spoken words into function parameters.#SYSTEM_MSG_END#text_to_image function parameters description:\nparameter `text`: The text used for image conversion.\nparameter `size_type`: size type\n\n---\nExamples:\nIf want you to do `Draw a girl`, return `text_to_image(text=\"Draw a girl\", size_type=\"512x512\")` brief and clear.\nIf want you to do `Draw an apple`, return `text_to_image(text=\"Draw an apple\", size_type=\"512x512\")` brief and clear.\n\n---\n\nRefer to the `text_to_image` function description, and fill in the function parameters according to the example \"I want you to do xx\" in the Examples section.\nNow I want you to do `Sure, I can draw you an apple. Draw me an apple.`, return function parameters in Examples format above, brief and clear.": "`text_to_image(text=\"Sure, I can draw you an apple. Draw me an apple.\", size_type=\"512x512\")`",
+ "You are an action classifier#SYSTEM_MSG_END#Otherwise, return `[TALK]: {talk}` brief and clear. For instance: if {talk} is \"xxxx\" return [TALK]: xxxx\n\nNow what specific action is explicitly mentioned in the text: Sure, I can draw you an apple. Draw me an apple.\n": "[DRAW]: draw an apple",
+ "Here is an Example for 1 input and 8 possible thoughts:\nInput: 2 8 8 14\nPossible next steps:\n2 + 8 = 10 (left: 8 10 14)\n8 / 2 = 4 (left: 4 8 14)\n14 + 2 = 16 (left: 8 8 16)\n2 * 8 = 16 (left: 8 14 16)\n8 - 2 = 6 (left: 6 8 14)\n14 - 8 = 6 (left: 2 6 8)\n14 / 2 = 7 (left: 7 8 8)\n14 - 2 = 12 (left: 8 8 12)\n\nHere is my task for 1 input and 5 possible thoughts:\nInput: 4 5 6 10\nPossible next steps:\n\n\n\n\nEach output should be strictly a list of nodes, in json format, like this:\n```json\n [\n {\n \"node_id\": str = \"unique identifier for a solution, can be an ordinal\",\n \"node_state_instruction\": \"specified sample of solution\",\n },\n ...\n ]\n```\n": "Here is the list of possible next steps for the given input in JSON format:\n\n```json\n[\n {\n \"node_id\": \"1\",\n \"node_state_instruction\": \"4 + 5 = 9 (left: 6 9 10)\"\n },\n {\n \"node_id\": \"2\",\n \"node_state_instruction\": \"5 + 6 = 11 (left: 4 11 10)\"\n },\n {\n \"node_id\": \"3\",\n \"node_state_instruction\": \"4 * 5 = 20 (left: 6 20 10)\"\n },\n {\n \"node_id\": \"4\",\n \"node_state_instruction\": \"6 - 4 = 2 (left: 2 5 10)\"\n },\n {\n \"node_id\": \"5\",\n \"node_state_instruction\": \"10 - 4 = 6 (left: 6 5 6)\"\n }\n]\n```",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n6 9 10\n": "6 * 9 - 10 = 54 - 10 = 44\n(9 - 6) * 10 = 3 * 10 = 30\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n6 20 10\n": "I'm sorry, but it seems that you haven't completed the calculation for the numbers 6, 20, and 10. If you'd like, I can help you with that.",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n4 11 10\n": "4 11 10 cannot reach 24.",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n2 5 10\n": "2 * 5 * 10 = 100\n(2 + 5) * 10 = 70\n2 5 10 are all too big\nimpossible",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n6 5 6\n": "I'm sorry, but it seems that you have not provided a complete expression for the numbers 6, 5, and 6 to reach 24. If you would like to try again, please provide a complete expression using the numbers 6, 5, and 6 to reach the target number of 24.",
+ "Here is an Example for 1 input and 8 possible thoughts:\nInput: 2 8 8 14\nPossible next steps:\n2 + 8 = 10 (left: 8 10 14)\n8 / 2 = 4 (left: 4 8 14)\n14 + 2 = 16 (left: 8 8 16)\n2 * 8 = 16 (left: 8 14 16)\n8 - 2 = 6 (left: 6 8 14)\n14 - 8 = 6 (left: 2 6 8)\n14 / 2 = 7 (left: 7 8 8)\n14 - 2 = 12 (left: 8 8 12)\n\nHere is my task for 1 input and 5 possible thoughts:\nInput: 4 11 10\nPossible next steps:\n\n\n\n\nEach output should be strictly a list of nodes, in json format, like this:\n```json\n [\n {\n \"node_id\": str = \"unique identifier for a solution, can be an ordinal\",\n \"node_state_instruction\": \"specified sample of solution\",\n },\n ...\n ]\n```\n": "Here are the possible next steps for the given input in the requested JSON format:\n\nInput: 4 11 10\nPossible next steps:\n```json\n[\n {\n \"node_id\": \"1\",\n \"node_state_instruction\": \"4 + 11 = 15 (left: 10 15)\"\n },\n {\n \"node_id\": \"2\",\n \"node_state_instruction\": \"11 - 4 = 7 (left: 7 10)\"\n },\n {\n \"node_id\": \"3\",\n \"node_state_instruction\": \"4 * 11 = 44 (left: 10 44)\"\n },\n {\n \"node_id\": \"4\",\n \"node_state_instruction\": \"11 / 4 = 2.75 (left: 2.75 10)\"\n },\n {\n \"node_id\": \"5\",\n \"node_state_instruction\": \"11 + 4 = 15 (left: 10 15)\"\n }\n]\n```",
+ "Here is an Example for 1 input and 8 possible thoughts:\nInput: 2 8 8 14\nPossible next steps:\n2 + 8 = 10 (left: 8 10 14)\n8 / 2 = 4 (left: 4 8 14)\n14 + 2 = 16 (left: 8 8 16)\n2 * 8 = 16 (left: 8 14 16)\n8 - 2 = 6 (left: 6 8 14)\n14 - 8 = 6 (left: 2 6 8)\n14 / 2 = 7 (left: 7 8 8)\n14 - 2 = 12 (left: 8 8 12)\n\nHere is my task for 1 input and 5 possible thoughts:\nInput: 6 9 10\nPossible next steps:\n\n\n\n\nEach output should be strictly a list of nodes, in json format, like this:\n```json\n [\n {\n \"node_id\": str = \"unique identifier for a solution, can be an ordinal\",\n \"node_state_instruction\": \"specified sample of solution\",\n },\n ...\n ]\n```\n": "Certainly! Here are the possible next steps for the given input in JSON format:\n\nInput: 6 9 10\nPossible next steps:\n```json\n[\n {\n \"node_id\": \"1\",\n \"node_state_instruction\": \"6 + 9 = 15 (left: 10 15)\"\n },\n {\n \"node_id\": \"2\",\n \"node_state_instruction\": \"6 * 9 = 54 (left: 10 54)\"\n },\n {\n \"node_id\": \"3\",\n \"node_state_instruction\": \"9 - 6 = 3 (left: 3 9 10)\"\n },\n {\n \"node_id\": \"4\",\n \"node_state_instruction\": \"10 - 6 = 4 (left: 4 6 9)\"\n },\n {\n \"node_id\": \"5\",\n \"node_state_instruction\": \"10 / 6 = 1 (left: 1 6 9)\"\n }\n]\n```",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n10 15\n": "I'm sorry, I cannot evaluate the numbers 10 and 15 without an operation. If you provide an operation, I can help you determine if they can reach 24.",
+ "Here is an Example for 1 input and 8 possible thoughts:\nInput: 2 8 8 14\nPossible next steps:\n2 + 8 = 10 (left: 8 10 14)\n8 / 2 = 4 (left: 4 8 14)\n14 + 2 = 16 (left: 8 8 16)\n2 * 8 = 16 (left: 8 14 16)\n8 - 2 = 6 (left: 6 8 14)\n14 - 8 = 6 (left: 2 6 8)\n14 / 2 = 7 (left: 7 8 8)\n14 - 2 = 12 (left: 8 8 12)\n\nHere is my task for 1 input and 5 possible thoughts:\nInput: 6 20 10\nPossible next steps:\n\n\n\n\nEach output should be strictly a list of nodes, in json format, like this:\n```json\n [\n {\n \"node_id\": str = \"unique identifier for a solution, can be an ordinal\",\n \"node_state_instruction\": \"specified sample of solution\",\n },\n ...\n ]\n```\n": "Certainly! Here is the list of nodes for the given input and possible next steps:\n\n```json\n[\n {\n \"node_id\": \"1\",\n \"node_state_instruction\": \"6 + 20 = 26 (left: 10 26)\"\n },\n {\n \"node_id\": \"2\",\n \"node_state_instruction\": \"20 - 6 = 14 (left: 14 10)\"\n },\n {\n \"node_id\": \"3\",\n \"node_state_instruction\": \"6 * 20 = 120 (left: 10 120)\"\n },\n {\n \"node_id\": \"4\",\n \"node_state_instruction\": \"20 / 6 = 3.33 (left: 3.33 10)\"\n },\n {\n \"node_id\": \"5\",\n \"node_state_instruction\": \"20 + 6 = 26 (left: 10 26)\"\n }\n]\n```",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n1 6 9\n": "1 6 9 cannot reach 24 using addition, subtraction, multiplication, or division. Therefore, it is impossible for these numbers to reach 24.",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n10 54\n": "It seems like you didn't provide the complete set of numbers for the last calculation. Could you please provide the third number so that I can help you evaluate if they can reach 24?",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n7 10\n": "I'm sorry, but it seems like you didn't provide a complete set of numbers for the last question. Could you please provide the third number so that I can evaluate if they can reach 24?",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n10 44\n": "It seems like you didn't provide the second number for the last set. Could you please provide the second number so that I can evaluate if they can reach 24?",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n10 26\n": "It seems that you have not provided the complete set of numbers for the last question. Could you please provide the third number for the set?",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n10 120\n": "It seems that you have not provided the complete set of numbers for the last question. Could you please provide the third number for the evaluation?",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n3 9 10\n": "3 * 9 * 10 = 270\n(10 - 3) * 9 = 63\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n2.75 10\n": "It seems like you have a mix of numbers and operations. Could you please provide the operations for the last set of numbers (2.75 and 10) so that I can help you evaluate if they can reach 24?",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n4 6 9\n": "4 + 6 + 9 = 19\n(9 - 4) * 6 = 5 * 6 = 30\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n14 10\n": "I'm sorry, it seems like you didn't provide the complete set of numbers for the last expression. Could you please provide the third number so that I can evaluate if they can reach 24?",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n3.33 10\n": "It seems like you have provided a list of numbers and evaluated if they can reach 24 through addition, subtraction, multiplication, and division. Here are the evaluations:\n\n10 14 - Sure\n11 12 - Impossible\n4 4 10 - Sure\n4 9 11 - Sure\n5 7 8 - Likely\n5 6 6 - Likely\n10 10 11 - Impossible\n1 3 3 - Impossible\n\nIt looks like you have evaluated the combinations accurately. As for the last set of numbers \"3.33 10,\" it seems incomplete. If you provide the intended operation or additional numbers, I can help you evaluate it.",
+ "Here is an Example for 1 input and 8 possible thoughts:\nInput: 2 8 8 14\nPossible next steps:\n2 + 8 = 10 (left: 8 10 14)\n8 / 2 = 4 (left: 4 8 14)\n14 + 2 = 16 (left: 8 8 16)\n2 * 8 = 16 (left: 8 14 16)\n8 - 2 = 6 (left: 6 8 14)\n14 - 8 = 6 (left: 2 6 8)\n14 / 2 = 7 (left: 7 8 8)\n14 - 2 = 12 (left: 8 8 12)\n\nHere is my task for 1 input and 5 possible thoughts:\nInput: 10 15\nPossible next steps:\n\n\n\n\nEach output should be strictly a list of nodes, in json format, like this:\n```json\n [\n {\n \"node_id\": str = \"unique identifier for a solution, can be an ordinal\",\n \"node_state_instruction\": \"specified sample of solution\",\n },\n ...\n ]\n```\n": "Here's the JSON format for the possible next steps for the given input:\n\n```json\n[\n {\n \"node_id\": \"1\",\n \"node_state_instruction\": \"10 + 15 = 25 (left: 25)\"\n },\n {\n \"node_id\": \"2\",\n \"node_state_instruction\": \"15 - 10 = 5 (left: 5)\"\n },\n {\n \"node_id\": \"3\",\n \"node_state_instruction\": \"10 * 15 = 150 (left: 150)\"\n },\n {\n \"node_id\": \"4\",\n \"node_state_instruction\": \"15 / 10 = 1.5 (left: 1.5)\"\n },\n {\n \"node_id\": \"5\",\n \"node_state_instruction\": \"15 + 10 = 25 (left: 25)\"\n }\n]\n```",
+ "Here is an Example for 1 input and 8 possible thoughts:\nInput: 2 8 8 14\nPossible next steps:\n2 + 8 = 10 (left: 8 10 14)\n8 / 2 = 4 (left: 4 8 14)\n14 + 2 = 16 (left: 8 8 16)\n2 * 8 = 16 (left: 8 14 16)\n8 - 2 = 6 (left: 6 8 14)\n14 - 8 = 6 (left: 2 6 8)\n14 / 2 = 7 (left: 7 8 8)\n14 - 2 = 12 (left: 8 8 12)\n\nHere is my task for 1 input and 5 possible thoughts:\nInput: 3 9 10\nPossible next steps:\n\n\n\n\nEach output should be strictly a list of nodes, in json format, like this:\n```json\n [\n {\n \"node_id\": str = \"unique identifier for a solution, can be an ordinal\",\n \"node_state_instruction\": \"specified sample of solution\",\n },\n ...\n ]\n```\n": "Here are the possible next steps for the given input in JSON format:\n\nInput: 3 9 10\nPossible next steps:\n```json\n[\n {\n \"node_id\": \"1\",\n \"node_state_instruction\": \"3 + 9 = 12 (left: 10 12)\"\n },\n {\n \"node_id\": \"2\",\n \"node_state_instruction\": \"9 - 3 = 6 (left: 6 9 10)\"\n },\n {\n \"node_id\": \"3\",\n \"node_state_instruction\": \"10 - 3 = 7 (left: 7 9 10)\"\n },\n {\n \"node_id\": \"4\",\n \"node_state_instruction\": \"3 * 9 = 27 (left: 10 27)\"\n },\n {\n \"node_id\": \"5\",\n \"node_state_instruction\": \"9 / 3 = 3 (left: 3 9 10)\"\n }\n]\n```",
+ "Here is an Example for 1 input and 8 possible thoughts:\nInput: 2 8 8 14\nPossible next steps:\n2 + 8 = 10 (left: 8 10 14)\n8 / 2 = 4 (left: 4 8 14)\n14 + 2 = 16 (left: 8 8 16)\n2 * 8 = 16 (left: 8 14 16)\n8 - 2 = 6 (left: 6 8 14)\n14 - 8 = 6 (left: 2 6 8)\n14 / 2 = 7 (left: 7 8 8)\n14 - 2 = 12 (left: 8 8 12)\n\nHere is my task for 1 input and 5 possible thoughts:\nInput: 4 6 9\nPossible next steps:\n\n\n\n\nEach output should be strictly a list of nodes, in json format, like this:\n```json\n [\n {\n \"node_id\": str = \"unique identifier for a solution, can be an ordinal\",\n \"node_state_instruction\": \"specified sample of solution\",\n },\n ...\n ]\n```\n": "Certainly! Here are the possible next steps for the given input in the requested JSON format:\n\nInput: 4 6 9\nPossible next steps:\n```json\n[\n {\n \"node_id\": \"1\",\n \"node_state_instruction\": \"4 + 6 = 10 (left: 10 9)\"\n },\n {\n \"node_id\": \"2\",\n \"node_state_instruction\": \"4 * 6 = 24 (left: 24 9)\"\n },\n {\n \"node_id\": \"3\",\n \"node_state_instruction\": \"4 - 6 = -2 (left: -2 9)\"\n },\n {\n \"node_id\": \"4\",\n \"node_state_instruction\": \"6 + 9 = 15 (left: 4 15)\"\n },\n {\n \"node_id\": \"5\",\n \"node_state_instruction\": \"6 * 9 = 54 (left: 4 54)\"\n }\n]\n```\nI hope this helps! If you need further assistance, feel free to ask.",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n10 27\n": "I'm sorry, but it seems like you didn't provide the third number for the last set. Could you please provide the third number so I can evaluate if the given numbers can reach 24?",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n1.5\n": "The evaluation of the given numbers is as follows:\n\n10 14: Sure\n11 12: Impossible\n4 4 10: Sure\n4 9 11: Sure\n5 7 8: Likely\n5 6 6: Likely\n10 10 11: Impossible\n1 3 3: Impossible\n1.5: I'm sorry, I cannot evaluate a single number for reaching 24.",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n4 15\n": "It seems like you didn't provide the complete set of numbers for the last question. Could you please provide the third number so that I can evaluate if they can reach 24?",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n24 9\n": "24 + 9 = 33\n24 - 9 = 15\n24 * 9 = 216\n24 / 9 = 2.67\nIt is impossible to reach 24 with the given numbers.",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n10 9\n": "It seems like you might have missed providing the operation for the last set of numbers \"10 9\". If you could provide the operation, I can help evaluate if the given numbers can reach 24.",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n25\n": "It seems that you have provided a list of numbers and evaluated whether they can reach 24 through addition, subtraction, multiplication, and division. Based on your evaluations, the combinations of numbers that can reach 24 are \"10 14\" and \"4 4 10,\" which are sure to reach 24. The combinations \"11 12\" and \"4 9 11\" are also sure to reach 24. The combination \"5 7 8\" is likely to reach 24, and the combinations \"5 6 6\" and \"10 10 11\" are unlikely to reach 24. The combination \"1 3 3\" is impossible to reach 24. If you have any more numbers to evaluate, feel free to share them with me.",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n4 54\n": "I'm sorry, but I cannot evaluate the expression \"4 54\" without an operator. Could you please provide the operator for the expression?",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n-2 9\n": "I'm sorry, but it seems like you didn't provide the third number for the last expression. Could you please provide the third number so that I can evaluate if the given numbers can reach 24?",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n10 12\n": "It seems like you have evaluated the combinations correctly. Based on the evaluations you provided, the combinations that can reach 24 are:\n\n- 10 14 (sure)\n- 4 4 10 (sure)\n- 4 9 11 (sure)\n- 5 7 8 (likely)\n- 5 6 6 (likely)\n\nThe combinations that cannot reach 24 are:\n\n- 11 12 (impossible)\n- 10 10 11 (impossible)\n- 1 3 3 (impossible)\n\nAs for the combination \"10 12,\" it seems like it was cut off. If you provide the complete expression, I can help evaluate it for you.",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n150\n": "It seems like you have evaluated the given numbers correctly. Here are the results:\n\n10 14: Sure\n11 12: Impossible\n4 4 10: Sure\n4 9 11: Sure\n5 7 8: Likely\n5 6 6: Likely\n10 10 11: Impossible\n1 3 3: Impossible\n\nAs for the number 150, it is not clear what operation or combination of numbers it is associated with. If you have a specific question or context for the number 150, please provide more details so that I can assist you further.",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n5\n": "The numbers 10 and 14 can reach 24, so that is sure. The numbers 11 and 12 cannot reach 24, so that is impossible. The numbers 4, 4, and 10 can reach 24, so that is sure. The numbers 4, 9, and 11 can reach 24, so that is sure. The numbers 5, 7, and 8 cannot reach 24, but they are within a reasonable range, so that is likely. The numbers 5, 6, and 6 cannot reach 24, but they are within a reasonable range, so that is likely. The numbers 10, 10, and 11 cannot reach 24, so that is impossible. The numbers 1, 3, and 3 cannot reach 24, so that is impossible. The number 5 by itself cannot reach 24.",
+ "Evaluate if given numbers can reach 24 (sure/likely/impossible)\n10 14\n10 + 14 = 24\nsure\n11 12\n11 + 12 = 23\n12 - 11 = 1\n11 * 12 = 132\n11 / 12 = 0.91\nimpossible\n4 4 10\n4 + 4 + 10 = 8 + 10 = 18\n4 * 10 - 4 = 40 - 4 = 36\n(10 - 4) * 4 = 6 * 4 = 24\nsure\n4 9 11\n9 + 11 + 4 = 20 + 4 = 24\nsure\n5 7 8\n5 + 7 + 8 = 12 + 8 = 20\n(8 - 5) * 7 = 3 * 7 = 21\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n5 6 6\n5 + 6 + 6 = 17\n(6 - 5) * 6 = 1 * 6 = 6\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely\n10 10 11\n10 + 10 + 11 = 31\n(11 - 10) * 10 = 10\n10 10 10 are all too big\nimpossible\n1 3 3\n1 * 3 * 3 = 9\n(1 + 3) * 3 = 12\n1 3 3 are all too small\nimpossible\n7 9 10\n": "7 * 9 - 10 = 63 - 10 = 53\n(9 - 7) * 10 = 2 * 10 = 20\nI cannot obtain 24 now, but numbers are within a reasonable range\nlikely",
+ "### Requirements\n1. Add docstrings to the given code following the google 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\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#SYSTEM_MSG_END#```python\nimport pytest\nfrom metagpt.actions.write_docstring import WriteDocstring\ncode = '\\ndef add_numbers(a: int, b: int):\\n return a + b\\n\\n\\nclass Person:\\n def __init__(self, name: str, age: int):\\n self.name = name\\n self.age = age\\n\\n def greet(self):\\n return f\"Hello, my name is {self.name} and I am {self.age} years old.\"\\n'\n\n@pytest.mark.asyncio\n@pytest.mark.parametrize(('style', 'part'), [('google', 'Args:'), ('numpy', 'Parameters'), ('sphinx', ':param name:')], ids=['google', 'numpy', 'sphinx'])\nasync def test_write_docstring(style: str, part: str, context):\n ret = await WriteDocstring(context=context).run(code, style=style)\n assert part in ret\n\n@pytest.mark.asyncio\nasync def test_write():\n code = await WriteDocstring.write_docstring(__file__)\n assert code\n```": "```python\ndef add_numbers(a: int, b: int):\n \"\"\"Adds two numbers together.\n\n Args:\n a: The first number.\n b: The second number.\n\n Returns:\n The sum of a and b.\n \"\"\"\n ...\n\nclass Person:\n \"\"\"Represents a person.\n\n Args:\n name: The name of the person.\n age: The age of the person.\n\n Attributes:\n name: The name of the person.\n age: The age of the person.\n \"\"\"\n\n def __init__(self, name: str, age: int):\n ...\n \n def greet(self):\n \"\"\"Generates a greeting message.\n\n Returns:\n A greeting string.\n \"\"\"\n ...\n```",
+ "\nWrite a coherent passage of 4 short paragraphs. The end sentence of each paragraph must be: It isn't difficult to do a handstand if you just stand on your hands. It caught him off guard that space smelled of seared steak. When she didn’t like a guy who was trying to pick her up, she started using sign language. Each person who knows you has a different perception of who you are.\n\nMake a plan then write. Your output should be like:\n\nPlan:\n\n\nPassage:\n\n\n\nEach output should be strictly a list of nodes, in json format, like this:\n```json\n [\n {\n \"node_id\": str = \"unique identifier for a solution, can be an ordinal\",\n \"node_state_instruction\": \"specified sample of solution\",\n },\n ...\n ]\n```\n": "Plan:\n```json\n[\n {\n \"node_id\": \"1\",\n \"node_state_instruction\": \"Introduce the concept of doing a handstand.\"\n },\n {\n \"node_id\": \"2\",\n \"node_state_instruction\": \"Describe the surprising smell of space.\"\n },\n {\n \"node_id\": \"3\",\n \"node_state_instruction\": \"Introduce a woman using sign language to deter unwanted attention.\"\n },\n {\n \"node_id\": \"4\",\n \"node_state_instruction\": \"Discuss the varied perceptions people have of an individual.\"\n }\n]\n```\n\nPassage:\n```json\n[\n {\n \"node_id\": \"1\",\n \"node_state_instruction\": \"It isn't difficult to do a handstand if you just stand on your hands.\"\n },\n {\n \"node_id\": \"2\",\n \"node_state_instruction\": \"It caught him off guard that space smelled of seared steak.\"\n },\n {\n \"node_id\": \"3\",\n \"node_state_instruction\": \"When she didn’t like a guy who was trying to pick her up, she started using sign language.\"\n },\n {\n \"node_id\": \"4\",\n \"node_state_instruction\": \"Each person who knows you has a different perception of who you are.\"\n }\n]\n```",
+ "Given an instruction and several choices, decide which choice is most promising. Analyze each choice in detail, then conclude in the last line \"The best choice is {s}\", where s the integer id of the choice.\nChoice 4:\nDiscuss the varied perceptions people have of an individual.\n": "Choice 4: Discuss the varied perceptions people have of an individual.\n\nAnalyzing this choice, discussing the varied perceptions people have of an individual can be promising as it allows for a deeper understanding of how different people perceive and interpret the actions, behaviors, and characteristics of an individual. This can lead to insights into the complexities of human interactions and relationships, and can provide valuable information for personal growth and self-awareness.\n\nBy exploring the reasons behind differing perceptions, it can also lead to increased empathy and understanding of others, which is beneficial for building stronger relationships and effective communication.\n\nFurthermore, discussing varied perceptions can also shed light on societal influences, biases, and stereotypes that may impact how individuals are perceived, which can be valuable for promoting inclusivity and diversity.\n\nThe best choice is 4.",
+ "Given an instruction and several choices, decide which choice is most promising. Analyze each choice in detail, then conclude in the last line \"The best choice is {s}\", where s the integer id of the choice.\nChoice 3:\nIntroduce a woman using sign language to deter unwanted attention.\n": "Choice 3: Introduce a woman using sign language to deter unwanted attention.\n\nAnalysis:\nIntroducing a woman using sign language can be a promising choice to deter unwanted attention. Sign language is a visual and expressive form of communication, and it can be an effective way to convey a message without drawing unnecessary attention. By using sign language, the woman can communicate with others discreetly and avoid attracting unwanted attention from individuals who may be seeking to engage her in conversation or interaction.\n\nAdditionally, using sign language can create a sense of privacy and exclusivity, as it may not be easily understood by everyone in the vicinity. This can help the woman maintain a level of personal space and discourage unwelcome advances or interactions.\n\nFurthermore, introducing sign language into the interaction can also serve as a way to promote inclusivity and awareness of different forms of communication, which can contribute to a more understanding and respectful environment.\n\nConclusion:\nThe best choice is 3.",
+ "Given an instruction and several choices, decide which choice is most promising. Analyze each choice in detail, then conclude in the last line \"The best choice is {s}\", where s the integer id of the choice.\nChoice 1:\nIntroduce the concept of doing a handstand.\n": "Choice 1: Introduce the concept of doing a handstand.\n\nAnalyzing the choice:\nIntroducing the concept of doing a handstand can be a fun and engaging way to promote physical activity and coordination. It can also help build strength and balance. However, it's important to ensure that proper safety measures and instructions are provided to prevent any potential injuries.\n\nConclusion:\nThe best choice is 1.",
+ "Given an instruction and several choices, decide which choice is most promising. Analyze each choice in detail, then conclude in the last line \"The best choice is {s}\", where s the integer id of the choice.\nChoice 2:\nDescribe the surprising smell of space.\n": "Choice 2: \n\nThe surprising smell of space has been described by astronauts as a mix of gunpowder, seared steak, hot metal, and raspberries. This unexpected combination of scents is due to the volatile organic compounds that are released from the materials in the spacecraft when they are exposed to the vacuum of space. These compounds react with the radiation from the sun, creating the unique smell that astronauts have reported. The smell of space is intriguing and unexpected, providing a sensory experience that is truly out of this world.\n\nThe best choice is 2.",
+ "\nWrite a coherent passage of 4 short paragraphs. The end sentence of each paragraph must be: Introduce the concept of doing a handstand.\n\nMake a plan then write. Your output should be like:\n\nPlan:\n\n\nPassage:\n\n\n\nEach output should be strictly a list of nodes, in json format, like this:\n```json\n [\n {\n \"node_id\": str = \"unique identifier for a solution, can be an ordinal\",\n \"node_state_instruction\": \"specified sample of solution\",\n },\n ...\n ]\n```\n": "Plan:\n```json\n[\n {\n \"node_id\": \"1\",\n \"node_state_instruction\": \"Decide on a suitable location to practice handstands.\"\n },\n {\n \"node_id\": \"2\",\n \"node_state_instruction\": \"Warm up your body with some stretching exercises.\"\n },\n {\n \"node_id\": \"3\",\n \"node_state_instruction\": \"Practice against a wall to build strength and balance.\"\n },\n {\n \"node_id\": \"4\",\n \"node_state_instruction\": \"Gradually work on holding the handstand position without support.\"\n }\n]\n```\n\nPassage:\n```json\n[\n {\n \"node_id\": \"1\",\n \"node_state_instruction\": \"Decide on a suitable location to practice handstands.\"\n },\n {\n \"node_id\": \"2\",\n \"node_state_instruction\": \"Before attempting a handstand, it's important to decide on a suitable location to practice. A clear, open space with a soft surface, such as a yoga mat or grass, is ideal for safety and comfort.\"\n },\n {\n \"node_id\": \"3\",\n \"node_state_instruction\": \"Warm up your body with some stretching exercises.\"\n },\n {\n \"node_id\": \"4\",\n \"node_state_instruction\": \"To prepare your body for the physical demands of a handstand, start with a series of stretching exercises. Focus on the wrists, shoulders, and core muscles to ensure they are adequately warmed up and flexible.\"\n },\n {\n \"node_id\": \"5\",\n \"node_state_instruction\": \"Practice against a wall to build strength and balance.\"\n },\n {\n \"node_id\": \"6\",\n \"node_state_instruction\": \"When learning to do a handstand, it can be helpful to practice against a wall. This provides support and allows you to focus on building strength and balance in the proper alignment. Gradually work on kicking up into the handstand position and holding it for short periods of time.\"\n },\n {\n \"node_id\": \"7\",\n \"node_state_instruction\": \"Gradually work on holding the handstand position without support.\"\n },\n {\n \"node_id\": \"8\",\n \"node_state_instruction\": \"As you gain confidence and strength, begin to practice holding the handstand position without the support of a wall. Focus on engaging your core and maintaining a straight line from your wrists to your hips. With consistent practice, you'll be able to hold a handstand with control and stability.\"\n }\n]\n```",
+ "Given an instruction and several choices, decide which choice is most promising. Analyze each choice in detail, then conclude in the last line \"The best choice is {s}\", where s the integer id of the choice.\nChoice 1:\nDecide on a suitable location to practice handstands.\n": "Choice 1: Find a spacious and flat area with soft ground, such as a grassy field or a padded gym floor. This will minimize the risk of injury and provide a stable surface for practicing handstands.\n\nThe best choice is 1",
+ "Given an instruction and several choices, decide which choice is most promising. Analyze each choice in detail, then conclude in the last line \"The best choice is {s}\", where s the integer id of the choice.\nChoice 2:\nWarm up your body with some stretching exercises.\n": "Stretching exercises are a great way to warm up the body before engaging in physical activity. They help to increase blood flow to the muscles, improve flexibility, and reduce the risk of injury. By performing stretching exercises, you can prepare your body for more strenuous activities and improve your overall performance.\n\nThe best choice is 2.",
+ "Given an instruction and several choices, decide which choice is most promising. Analyze each choice in detail, then conclude in the last line \"The best choice is {s}\", where s the integer id of the choice.\nChoice 3:\nPractice against a wall to build strength and balance.\n": "Choice 3: Practice against a wall to build strength and balance.\n\nAnalyzing choice 3, practicing against a wall can be a promising option for building strength and balance. The wall provides a stable surface to push against, which can help in developing strength in the muscles. It also offers support, allowing for balance practice without the risk of falling. Additionally, using a wall as a tool for practice can help in improving posture and body alignment.\n\nThe best choice is 3.",
+ "Given an instruction and several choices, decide which choice is most promising. Analyze each choice in detail, then conclude in the last line \"The best choice is {s}\", where s the integer id of the choice.\nChoice 4:\nGradually work on holding the handstand position without support.\n": "Choice 4: Gradually work on holding the handstand position without support.\n\nAnalyzing this choice, working on holding the handstand position without support is a promising option for improving strength, balance, and body control. This choice allows for gradual progression, which is important for building the necessary strength and stability to maintain the handstand position. It also encourages the development of proprioception and spatial awareness, which are essential for mastering this challenging skill.\n\nThe best choice is 4.",
+ "\nWrite a coherent passage of 4 short paragraphs. The end sentence of each paragraph must be: Decide on a suitable location to practice handstands.\n\nMake a plan then write. Your output should be like:\n\nPlan:\n\n\nPassage:\n\n\n\nEach output should be strictly a list of nodes, in json format, like this:\n```json\n [\n {\n \"node_id\": str = \"unique identifier for a solution, can be an ordinal\",\n \"node_state_instruction\": \"specified sample of solution\",\n },\n ...\n ]\n```\n": "Plan:\n```json\n[\n {\n \"node_id\": \"1\",\n \"node_state_instruction\": \"Decide on a suitable location to practice handstands.\"\n },\n {\n \"node_id\": \"2\",\n \"node_state_instruction\": \"Consider a flat and stable surface, such as a grassy field or a gym mat.\"\n },\n {\n \"node_id\": \"3\",\n \"node_state_instruction\": \"Ensure there is enough space around you to avoid any obstacles.\"\n },\n {\n \"node_id\": \"4\",\n \"node_state_instruction\": \"Practice near a wall or with a spotter for safety.\"\n }\n]\n```\n\nPassage:\n```json\n[\n {\n \"node_id\": \"1\",\n \"node_state_instruction\": \"Decide on a suitable location to practice handstands.\"\n },\n {\n \"node_id\": \"2\",\n \"node_state_instruction\": \"Consider a flat and stable surface, such as a grassy field or a gym mat.\"\n },\n {\n \"node_id\": \"3\",\n \"node_state_instruction\": \"Ensure there is enough space around you to avoid any obstacles.\"\n },\n {\n \"node_id\": \"4\",\n \"node_state_instruction\": \"Practice near a wall or with a spotter for safety.\"\n }\n]\n```",
+ "Given an instruction and several choices, decide which choice is most promising. Analyze each choice in detail, then conclude in the last line \"The best choice is {s}\", where s the integer id of the choice.\nChoice 3:\nEnsure there is enough space around you to avoid any obstacles.\n": "Choice 3: \n\nAnalyzing this choice, ensuring there is enough space around you to avoid any obstacles is a crucial step in maintaining safety and preventing accidents. By creating a buffer zone, you can react to unexpected obstacles or changes in the environment without risking collisions or other hazards.\n\nThe best choice is 3.",
+ "Given an instruction and several choices, decide which choice is most promising. Analyze each choice in detail, then conclude in the last line \"The best choice is {s}\", where s the integer id of the choice.\nChoice 2:\nConsider a flat and stable surface, such as a grassy field or a gym mat.\n": "Choice 2: Considering a flat and stable surface, such as a grassy field or a gym mat, is the most promising option. This choice provides a safe and secure environment for the activity, reducing the risk of injury. A grassy field offers a natural and soft surface, while a gym mat provides cushioning and stability. Both options allow for comfortable movement and can accommodate various physical activities.\n\nThe best choice is 2.",
+ "Given an instruction and several choices, decide which choice is most promising. Analyze each choice in detail, then conclude in the last line \"The best choice is {s}\", where s the integer id of the choice.\nChoice 4:\nPractice near a wall or with a spotter for safety.\n": "Choice 4: \n\nPractice near a wall or with a spotter for safety.\n\nAnalyzing this choice, practicing near a wall or with a spotter provides a safety measure to prevent accidents or injuries. When practicing a new skill or exercise, having a wall nearby can provide support and stability, reducing the risk of falling or losing balance. Similarly, having a spotter can offer assistance and guidance, ensuring that the practice is done safely and effectively.\n\nThe best choice is 4.",
+ "### Requirements\n1. Please summarize the latest dialogue based on the reference information (secondary) and dialogue history (primary). Do not include text that is irrelevant to the conversation.\n- The context is for reference only. If it is irrelevant to the user's search request history, please reduce its reference and usage.\n2. If there are citable links in the context, annotate them in the main text in the format [main text](citation link). If there are none in the context, do not write links.\n3. The reply should be graceful, clear, non-repetitive, smoothly written, and of moderate length, in {LANG}.\n\n### Dialogue History (For example)\nA: MLOps competitors\n\n### Current Question (For example)\nA: MLOps competitors\n\n### Current Reply (For example)\n1. Alteryx Designer: etc. if any\n2. Matlab: ditto\n3. IBM SPSS Statistics\n4. RapidMiner Studio\n5. DataRobot AI Platform\n6. Databricks Lakehouse Platform\n7. Amazon SageMaker\n8. Dataiku\n#SYSTEM_MSG_END#\n### Reference Information\nABC cleanser is preferred by many with oily skin.\nL'Oreal is a popular brand with many positive reviews.\n\n### Dialogue History\n\nuser: Which facial cleanser is good for oily skin?\n\n### Current Question\nuser: Which facial cleanser is good for oily skin?\n\n### Current Reply: Based on the information, please write the reply to the Question\n\n\n": "Based on the information provided, ABC cleanser is preferred by many with oily skin. It is a popular choice for individuals with oily skin due to its effectiveness. Additionally, L'Oreal is a well-known brand with many positive reviews, and they offer a range of products suitable for oily skin. Both of these options could be good choices for individuals with oily skin.",
+ "\n## context\n{\"Implementation approach\":\"We will use the Pygame library to create the game and handle user input. The game logic will be implemented using Python classes and functions.\",\"File list\":[\"main.py\",\"game.py\"],\"Data structures and interfaces\":\"\\nclassDiagram\\n class Game {\\n -snake: list\\n -food: tuple\\n -score: int\\n +__init__()\\n +update()\\n +draw()\\n +handle_input()\\n +restart()\\n }\\n class Snake {\\n -body: list\\n -direction: str\\n +__init__(start_pos: tuple, length: int, direction: str)\\n +move()\\n +change_direction(new_direction: str)\\n +grow()\\n }\\n Game --> Snake\\n\",\"Program call flow\":\"\\nsequenceDiagram\\n participant M as Main\\n participant G as Game\\n M->>G: initialize game\\n G->>G: update game state\\n G->>G: draw game\\n G->>G: handle user input\\n G->>G: restart game\\n\",\"Anything UNCLEAR\":\"Clarification needed on the scoring system and how the game over condition will be handled.\"}\n\n-----\n\n## format example\n[CONTENT]\n{\n \"Required Python packages\": [\n \"flask==1.1.2\",\n \"bcrypt==3.2.0\"\n ],\n \"Required Other language third-party packages\": [\n \"No third-party dependencies required\"\n ],\n \"Logic Analysis\": [\n [\n \"game.py\",\n \"Contains Game class and ... functions\"\n ],\n [\n \"main.py\",\n \"Contains main function, from game import Game\"\n ]\n ],\n \"Task list\": [\n \"game.py\",\n \"main.py\"\n ],\n \"Full API spec\": \"openapi: 3.0.0 ...\",\n \"Shared Knowledge\": \"`game.py` contains functions shared across the project.\",\n \"Anything UNCLEAR\": \"Clarification needed on how to start and initialize third-party libraries.\"\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- Required Python packages: typing.List[str] # Provide required Python packages in requirements.txt format.\n- Required Other language third-party packages: typing.List[str] # List down the required packages for languages other than Python.\n- Logic Analysis: typing.List[typing.List[str]] # Provide a list of files with the classes/methods/functions to be implemented, including dependency analysis and imports.\n- Task list: typing.List[str] # Break down the tasks into a list of filenames, prioritized by dependency order.\n- Full API spec: # Describe all APIs using OpenAPI 3.0 spec that may be used by both frontend and backend. If front-end and back-end communication is not required, leave it blank.\n- Shared Knowledge: # Detail any shared knowledge, like common utility functions or configuration variables.\n- Anything UNCLEAR: # Mention any unclear aspects in the project management context 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 \"Required Python packages\": [\n \"pygame==2.0.1\"\n ],\n \"Required Other language third-party packages\": [\n \"No third-party dependencies required\"\n ],\n \"Logic Analysis\": [\n [\n \"game.py\",\n \"Contains Game class and ... functions\"\n ],\n [\n \"main.py\",\n \"Contains main function, from game import Game\"\n ]\n ],\n \"Task list\": [\n \"game.py\",\n \"main.py\"\n ],\n \"Full API spec\": \"\",\n \"Shared Knowledge\": \"`game.py` contains functions shared across the project.\",\n \"Anything UNCLEAR\": \"Clarification needed on the scoring system and how the game over condition will be handled.\"\n}\n[/CONTENT]",
+ "\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 the Pygame library to create the game and handle user input. The game logic will be implemented using Python classes and functions.\",\"File list\":[\"main.py\",\"game.py\"],\"Data structures and interfaces\":\"\\nclassDiagram\\n class Game {\\n -snake: list\\n -food: tuple\\n -score: int\\n +__init__()\\n +update()\\n +draw()\\n +handle_input()\\n +restart()\\n }\\n class Snake {\\n -body: list\\n -direction: str\\n +__init__(start_pos: tuple, length: int, direction: str)\\n +move()\\n +change_direction(new_direction: str)\\n +grow()\\n }\\n Game --> Snake\\n\",\"Program call flow\":\"\\nsequenceDiagram\\n participant M as Main\\n participant G as Game\\n M->>G: initialize game\\n G->>G: update game state\\n G->>G: draw game\\n G->>G: handle user input\\n G->>G: restart game\\n\",\"Anything UNCLEAR\":\"Clarification needed on the scoring system and how the game over condition will be handled.\"}\n\n## Task\n{\"Required Python packages\":[\"pygame==2.0.1\"],\"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\":\"Clarification needed on the scoring system and how the game over condition will be handled.\"}\n\n## Legacy Code\n```Code\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: game.py\n```python\n## game.py\n...\n```\n\n# Instruction: Based on the context, follow \"Format example\", write code.\n\n## Code: game.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## game.py\n\nimport pygame\nimport random\n\nclass Snake:\n def __init__(self, start_pos: tuple, length: int, direction: str):\n self.body = [start_pos]\n self.direction = direction\n self.length = length\n\n def move(self):\n head = self.body[0]\n x, y = head\n if self.direction == 'UP':\n new_head = (x, y - 10)\n elif self.direction == 'DOWN':\n new_head = (x, y + 10)\n elif self.direction == 'LEFT':\n new_head = (x - 10, y)\n elif self.direction == 'RIGHT':\n new_head = (x + 10, y)\n self.body = [new_head] + self.body[:-1]\n\n def change_direction(self, new_direction: str):\n if new_direction in ['UP', 'DOWN', 'LEFT', 'RIGHT']:\n self.direction = new_direction\n\n def grow(self):\n self.length += 1\n self.body.append((0, 0)) # Set default value\n\nclass Game:\n def __init__(self):\n self.snake = Snake((100, 50), 1, 'RIGHT') # Set default value\n self.food = (200, 200) # Set default value\n self.score = 0 # Set default value\n\n def update(self):\n self.snake.move()\n if self.snake.body[0] == self.food:\n self.snake.grow()\n self.food = (random.randrange(0, 400, 10), random.randrange(0, 400, 10)) # Set default value\n\n def draw(self):\n pass # Set default value\n\n def handle_input(self):\n for event in pygame.event.get():\n if event.type == pygame.QUIT:\n pygame.quit()\n quit()\n if event.type == pygame.KEYDOWN:\n if event.key == pygame.K_UP:\n self.snake.change_direction('UP')\n elif event.key == pygame.K_DOWN:\n self.snake.change_direction('DOWN')\n elif event.key == pygame.K_LEFT:\n self.snake.change_direction('LEFT')\n elif event.key == pygame.K_RIGHT:\n self.snake.change_direction('RIGHT')\n\n def restart(self):\n self.snake = Snake((100, 50), 1, 'RIGHT') # Set default value\n self.food = (200, 200) # Set default value\n self.score = 0 # Set default value\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 the Pygame library to create the game and handle user input. The game logic will be implemented using Python classes and functions.\",\"File list\":[\"main.py\",\"game.py\"],\"Data structures and interfaces\":\"\\nclassDiagram\\n class Game {\\n -snake: list\\n -food: tuple\\n -score: int\\n +__init__()\\n +update()\\n +draw()\\n +handle_input()\\n +restart()\\n }\\n class Snake {\\n -body: list\\n -direction: str\\n +__init__(start_pos: tuple, length: int, direction: str)\\n +move()\\n +change_direction(new_direction: str)\\n +grow()\\n }\\n Game --> Snake\\n\",\"Program call flow\":\"\\nsequenceDiagram\\n participant M as Main\\n participant G as Game\\n M->>G: initialize game\\n G->>G: update game state\\n G->>G: draw game\\n G->>G: handle user input\\n G->>G: restart game\\n\",\"Anything UNCLEAR\":\"Clarification needed on the scoring system and how the game over condition will be handled.\"}\n\n## Task\n{\"Required Python packages\":[\"pygame==2.0.1\"],\"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\":\"Clarification needed on the scoring system and how the game over condition will be handled.\"}\n\n## Code Files\n\n\n\n## Code to be Reviewed: game.py\n```Code\n## game.py\n\nimport pygame\nimport random\n\nclass Snake:\n def __init__(self, start_pos: tuple, length: int, direction: str):\n self.body = [start_pos]\n self.direction = direction\n self.length = length\n\n def move(self):\n head = self.body[0]\n x, y = head\n if self.direction == 'UP':\n new_head = (x, y - 10)\n elif self.direction == 'DOWN':\n new_head = (x, y + 10)\n elif self.direction == 'LEFT':\n new_head = (x - 10, y)\n elif self.direction == 'RIGHT':\n new_head = (x + 10, y)\n self.body = [new_head] + self.body[:-1]\n\n def change_direction(self, new_direction: str):\n if new_direction in ['UP', 'DOWN', 'LEFT', 'RIGHT']:\n self.direction = new_direction\n\n def grow(self):\n self.length += 1\n self.body.append((0, 0)) # Set default value\n\nclass Game:\n def __init__(self):\n self.snake = Snake((100, 50), 1, 'RIGHT') # Set default value\n self.food = (200, 200) # Set default value\n self.score = 0 # Set default value\n\n def update(self):\n self.snake.move()\n if self.snake.body[0] == self.food:\n self.snake.grow()\n self.food = (random.randrange(0, 400, 10), random.randrange(0, 400, 10)) # Set default value\n\n def draw(self):\n pass # Set default value\n\n def handle_input(self):\n for event in pygame.event.get():\n if event.type == pygame.QUIT:\n pygame.quit()\n quit()\n if event.type == pygame.KEYDOWN:\n if event.key == pygame.K_UP:\n self.snake.change_direction('UP')\n elif event.key == pygame.K_DOWN:\n self.snake.change_direction('DOWN')\n elif event.key == pygame.K_LEFT:\n self.snake.change_direction('LEFT')\n elif event.key == pygame.K_RIGHT:\n self.snake.change_direction('RIGHT')\n\n def restart(self):\n self.snake = Snake((100, 50), 1, 'RIGHT') # Set default value\n self.food = (200, 200) # Set default value\n self.score = 0 # Set default value\n\n```\n\n\n\n# Format example 1\n## Code Review: game.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: game.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: game.py\n1. The code is implemented as per the requirements. The Snake and Game classes are defined, and the necessary methods for updating, drawing, handling input, and restarting the game are implemented.\n2. The code logic is correct. The Snake class methods for moving, changing direction, and growing the snake are implemented properly. The Game class methods for updating the game state, handling input, and restarting the game are also correctly implemented.\n3. The existing code follows the defined \"Data structures and interfaces\" with the Snake and Game classes and their respective methods.\n4. All necessary functions are implemented as per the requirements.\n5. The necessary pre-dependencies, including the pygame package, are imported.\n6. The methods from other files are not being reused in the current code.\n\n## Actions\nNo actions required.\n\n## Code Review Result\nLGTM",
+ "\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 the Pygame library to create the game and handle user input. The game logic will be implemented using Python classes and functions.\",\"File list\":[\"main.py\",\"game.py\"],\"Data structures and interfaces\":\"\\nclassDiagram\\n class Game {\\n -snake: list\\n -food: tuple\\n -score: int\\n +__init__()\\n +update()\\n +draw()\\n +handle_input()\\n +restart()\\n }\\n class Snake {\\n -body: list\\n -direction: str\\n +__init__(start_pos: tuple, length: int, direction: str)\\n +move()\\n +change_direction(new_direction: str)\\n +grow()\\n }\\n Game --> Snake\\n\",\"Program call flow\":\"\\nsequenceDiagram\\n participant M as Main\\n participant G as Game\\n M->>G: initialize game\\n G->>G: update game state\\n G->>G: draw game\\n G->>G: handle user input\\n G->>G: restart game\\n\",\"Anything UNCLEAR\":\"Clarification needed on the scoring system and how the game over condition will be handled.\"}\n\n## Task\n{\"Required Python packages\":[\"pygame==2.0.1\"],\"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\":\"Clarification needed on the scoring system and how the game over condition will be handled.\"}\n\n## Legacy Code\n```Code\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 game = Game()\n running = True\n\n while running:\n game.update()\n game.draw()\n game.handle_input()\n\n if game.game_over:\n game.restart()\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 the Pygame library to create the game and handle user input. The game logic will be implemented using Python classes and functions.\",\"File list\":[\"main.py\",\"game.py\"],\"Data structures and interfaces\":\"\\nclassDiagram\\n class Game {\\n -snake: list\\n -food: tuple\\n -score: int\\n +__init__()\\n +update()\\n +draw()\\n +handle_input()\\n +restart()\\n }\\n class Snake {\\n -body: list\\n -direction: str\\n +__init__(start_pos: tuple, length: int, direction: str)\\n +move()\\n +change_direction(new_direction: str)\\n +grow()\\n }\\n Game --> Snake\\n\",\"Program call flow\":\"\\nsequenceDiagram\\n participant M as Main\\n participant G as Game\\n M->>G: initialize game\\n G->>G: update game state\\n G->>G: draw game\\n G->>G: handle user input\\n G->>G: restart game\\n\",\"Anything UNCLEAR\":\"Clarification needed on the scoring system and how the game over condition will be handled.\"}\n\n## Task\n{\"Required Python packages\":[\"pygame==2.0.1\"],\"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\":\"Clarification needed on the scoring system and how the game over condition will be handled.\"}\n\n## Code Files\n\n\n\n## Code to be Reviewed: main.py\n```Code\n## main.py\n\nfrom game import Game\n\ndef main():\n game = Game()\n running = True\n\n while running:\n game.update()\n game.draw()\n game.handle_input()\n\n if game.game_over:\n game.restart()\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. Yes, the code is implemented as per the requirements.\n2. Yes, the code logic is completely correct.\n3. Yes, the existing code follows the \"Data structures and interfaces\".\n4. No, the `game_over` condition is not handled in the code. To achieve it, we need to add the implementation of the `game_over` condition in the `Game` class.\n5. Yes, all necessary pre-dependencies have been imported.\n6. Yes, methods from other files are being reused correctly.\n\n## Actions\n4. Implement the `game_over` condition in the `Game` class to handle the game over scenario.\n\n## Code Review Result\nLBTM",
+ "\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 the Pygame library to create the game and handle user input. The game logic will be implemented using Python classes and functions.\",\"File list\":[\"main.py\",\"game.py\"],\"Data structures and interfaces\":\"\\nclassDiagram\\n class Game {\\n -snake: list\\n -food: tuple\\n -score: int\\n +__init__()\\n +update()\\n +draw()\\n +handle_input()\\n +restart()\\n }\\n class Snake {\\n -body: list\\n -direction: str\\n +__init__(start_pos: tuple, length: int, direction: str)\\n +move()\\n +change_direction(new_direction: str)\\n +grow()\\n }\\n Game --> Snake\\n\",\"Program call flow\":\"\\nsequenceDiagram\\n participant M as Main\\n participant G as Game\\n M->>G: initialize game\\n G->>G: update game state\\n G->>G: draw game\\n G->>G: handle user input\\n G->>G: restart game\\n\",\"Anything UNCLEAR\":\"Clarification needed on the scoring system and how the game over condition will be handled.\"}\n\n## Task\n{\"Required Python packages\":[\"pygame==2.0.1\"],\"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\":\"Clarification needed on the scoring system and how the game over condition will be handled.\"}\n\n## Code Files\n\n\n\n## Code to be Reviewed: main.py\n```Code\n## main.py\n\nfrom game import Game\n\ndef main():\n game = Game()\n running = True\n\n while running:\n game.update()\n game.draw()\n game.handle_input()\n\n if game.game_over:\n game.restart()\n\nif __name__ == \"__main__\":\n main()\n\n```\n\n## Code Review: main.py\n1. Yes, the code is implemented as per the requirements.\n2. Yes, the code logic is completely correct.\n3. Yes, the existing code follows the \"Data structures and interfaces\".\n4. No, the `game_over` condition is not handled in the code. To achieve it, we need to add the implementation of the `game_over` condition in the `Game` class.\n5. Yes, all necessary pre-dependencies have been imported.\n6. Yes, methods from other files are being reused correctly.\n\n## Actions\n4. Implement the `game_over` condition in the `Game` class to handle the game over scenario.\n\n## Code Review Result\nLBTM\n\n# Instruction: rewrite code based on the Code Review and Actions\n## Rewrite Code: CodeBlock. If it still has some bugs, rewrite main.py with triple quotes. Do your utmost to optimize THIS SINGLE FILE. Return all completed codes and prohibit the return of unfinished codes.\n```Code\n## main.py\n...\n```\n": "```Code\n## main.py\n\nfrom game import Game\n\ndef main():\n game = Game()\n running = True\n\n while running:\n game.update()\n game.draw()\n game.handle_input()\n\n if game.game_over():\n game.restart()\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 the Pygame library to create the game and handle user input. The game logic will be implemented using Python classes and functions.\",\"File list\":[\"main.py\",\"game.py\"],\"Data structures and interfaces\":\"\\nclassDiagram\\n class Game {\\n -snake: list\\n -food: tuple\\n -score: int\\n +__init__()\\n +update()\\n +draw()\\n +handle_input()\\n +restart()\\n }\\n class Snake {\\n -body: list\\n -direction: str\\n +__init__(start_pos: tuple, length: int, direction: str)\\n +move()\\n +change_direction(new_direction: str)\\n +grow()\\n }\\n Game --> Snake\\n\",\"Program call flow\":\"\\nsequenceDiagram\\n participant M as Main\\n participant G as Game\\n M->>G: initialize game\\n G->>G: update game state\\n G->>G: draw game\\n G->>G: handle user input\\n G->>G: restart game\\n\",\"Anything UNCLEAR\":\"Clarification needed on the scoring system and how the game over condition will be handled.\"}\n\n## Task\n{\"Required Python packages\":[\"pygame==2.0.1\"],\"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\":\"Clarification needed on the scoring system and how the game over condition will be handled.\"}\n\n## Code Files\n\n\n\n## Code to be Reviewed: main.py\n```Code\n## main.py\n\nfrom game import Game\n\ndef main():\n game = Game()\n running = True\n\n while running:\n game.update()\n game.draw()\n game.handle_input()\n\n if game.game_over():\n game.restart()\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. It initializes the game, updates the game state, draws the game, handles user input, and restarts the game when it's over.\n2. The code logic is correct, and it follows the expected flow of the game.\n3. The existing code follows the \"Data structures and interfaces\" as it uses classes and methods as described in the class diagram.\n4. All necessary functions are implemented as per the requirements.\n5. The necessary pre-dependencies have been imported, as the `pygame` package is imported.\n6. The methods from other files are being reused correctly.\n\n## Actions\npass\n\n## Code Review Result\nLGTM",
+ "\n## context\n{'Implementation approach': '我们将使用Python编程语言,并选择合适的开源框架来实现贪吃蛇游戏。我们将分析需求中的难点,并选择合适的开源框架来简化开发流程。', 'File list': ['main.py', 'game.py'], 'Data structures and interfaces': '\\nclassDiagram\\n class Game {\\n -int width\\n -int height\\n -int score\\n -int speed\\n -List snake\\n -Point food\\n +__init__(width: int, height: int, speed: int)\\n +start_game()\\n +change_direction(direction: str)\\n +game_over()\\n +update_snake()\\n +update_food()\\n +check_collision()\\n }\\n class Point {\\n -int x\\n -int y\\n +__init__(x: int, y: int)\\n }\\n Game --> Point\\n', 'Program call flow': '\\nsequenceDiagram\\n participant M as Main\\n participant G as Game\\n M->>G: start_game()\\n M->>G: change_direction(direction)\\n G->>G: update_snake()\\n G->>G: update_food()\\n G->>G: check_collision()\\n G-->>G: game_over()\\n', 'Anything UNCLEAR': ''}\n\n-----\n\n## format example\n[CONTENT]\n{\n \"Required Python packages\": [\n \"flask==1.1.2\",\n \"bcrypt==3.2.0\"\n ],\n \"Required Other language third-party packages\": [\n \"No third-party dependencies required\"\n ],\n \"Logic Analysis\": [\n [\n \"game.py\",\n \"Contains Game class and ... functions\"\n ],\n [\n \"main.py\",\n \"Contains main function, from game import Game\"\n ]\n ],\n \"Task list\": [\n \"game.py\",\n \"main.py\"\n ],\n \"Full API spec\": \"openapi: 3.0.0 ...\",\n \"Shared Knowledge\": \"`game.py` contains functions shared across the project.\",\n \"Anything UNCLEAR\": \"Clarification needed on how to start and initialize third-party libraries.\"\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- Required Python packages: typing.List[str] # Provide required Python packages in requirements.txt format.\n- Required Other language third-party packages: typing.List[str] # List down the required packages for languages other than Python.\n- Logic Analysis: typing.List[typing.List[str]] # Provide a list of files with the classes/methods/functions to be implemented, including dependency analysis and imports.\n- Task list: typing.List[str] # Break down the tasks into a list of filenames, prioritized by dependency order.\n- Full API spec: # Describe all APIs using OpenAPI 3.0 spec that may be used by both frontend and backend. If front-end and back-end communication is not required, leave it blank.\n- Shared Knowledge: # Detail any shared knowledge, like common utility functions or configuration variables.\n- Anything UNCLEAR: # Mention any unclear aspects in the project management context 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 \"Required Python packages\": [\n \"pygame==2.0.1\"\n ],\n \"Required Other language third-party packages\": [\n \"No third-party dependencies required\"\n ],\n \"Logic Analysis\": [\n [\n \"game.py\",\n \"Contains Game class and related functions\"\n ],\n [\n \"main.py\",\n \"Contains the main function and imports Game from game.py\"\n ]\n ],\n \"Task list\": [\n \"game.py\",\n \"main.py\"\n ],\n \"Full API spec\": \"\",\n \"Shared Knowledge\": \"`game.py` contains functions shared across the project.\",\n \"Anything UNCLEAR\": \"\"\n}\n[/CONTENT]",
+ "\nNOTICE\nRole: You are a professional software engineer, and your main task is to review the 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-----\n# System Design\n```text\n\n{\"Implementation approach\": \"To develop this snake game, we will use the Python language and choose the Pygame library. Pygame is an open-source Python module collection specifically designed for writing video games. It provides functionalities such as displaying images and playing sounds, making it suitable for creating intuitive and responsive user interfaces. We will ensure efficient game logic to prevent any delays during gameplay. The scoring system will be simple, with the snake gaining points for each food it eats. We will use Pygame's event handling system to implement pause and resume functionality, as well as high-score tracking. The difficulty will increase by speeding up the snake's movement. In the initial version, we will focus on single-player mode and consider adding multiplayer mode and customizable skins in future updates. Based on the new requirement, we will also add a moving obstacle that appears randomly. If the snake eats this obstacle, the game will end. If the snake does not eat the obstacle, it will disappear after 5 seconds. For this, we need to add mechanisms for obstacle generation, movement, and disappearance in the game logic.\", \"Project_name\": \"snake_game\", \"File list\": [\"main.py\", \"game.py\", \"snake.py\", \"food.py\", \"obstacle.py\", \"scoreboard.py\", \"constants.py\", \"assets/styles.css\", \"assets/index.html\"], \"Data structures and interfaces\": \"```mermaid\n classDiagram\n class Game{\n +int score\n +int speed\n +bool game_over\n +bool paused\n +Snake snake\n +Food food\n +Obstacle obstacle\n +Scoreboard scoreboard\n +start_game() void\n +pause_game() void\n +resume_game() void\n +end_game() void\n +increase_difficulty() void\n +update() void\n +render() void\n Game()\n }\n class Snake{\n +list body_parts\n +str direction\n +bool grow\n +move() void\n +grow() void\n +check_collision() bool\n Snake()\n }\n class Food{\n +tuple position\n +spawn() void\n Food()\n }\n class Obstacle{\n +tuple position\n +int lifetime\n +bool active\n +spawn() void\n +move() void\n +check_collision() bool\n +disappear() void\n Obstacle()\n }\n class Scoreboard{\n +int high_score\n +update_score(int) void\n +reset_score() void\n +load_high_score() void\n +save_high_score() void\n Scoreboard()\n }\n class Constants{\n }\n Game \"1\" -- \"1\" Snake: has\n Game \"1\" -- \"1\" Food: has\n Game \"1\" -- \"1\" Obstacle: has\n Game \"1\" -- \"1\" Scoreboard: has\n ```\", \"Program call flow\": \"```sequenceDiagram\n participant M as Main\n participant G as Game\n participant S as Snake\n participant F as Food\n participant O as Obstacle\n participant SB as Scoreboard\n M->>G: start_game()\n loop game loop\n G->>S: move()\n G->>S: check_collision()\n G->>F: spawn()\n G->>O: spawn()\n G->>O: move()\n G->>O: check_collision()\n G->>O: disappear()\n G->>SB: update_score(score)\n G->>G: update()\n G->>G: render()\n alt if paused\n M->>G: pause_game()\n M->>G: resume_game()\n end\n alt if game_over\n G->>M: end_game()\n end\n end\n```\", \"Anything UNCLEAR\": \"There is no need for further clarification as the requirements are already clear.\"}\n\n```\n-----\n# Task\n```text\n\n{\"Required Python third-party packages\": [\"pygame==2.0.1\"], \"Required Other language third-party packages\": [\"No third-party packages required for other languages.\"], \"Full API spec\": \"\n openapi: 3.0.0\n info:\n title: Snake Game API\n version: \"1.0.0\"\n paths:\n /start:\n get:\n summary: Start the game\n responses:\n '200':\n description: Game started successfully\n /pause:\n get:\n summary: Pause the game\n responses:\n '200':\n description: Game paused successfully\n /resume:\n get:\n summary: Resume the game\n responses:\n '200':\n description: Game resumed successfully\n /end:\n get:\n summary: End the game\n responses:\n '200':\n description: Game ended successfully\n /score:\n get:\n summary: Get the current score\n responses:\n '200':\n description: Current score retrieved successfully\n /highscore:\n get:\n summary: Get the high score\n responses:\n '200':\n description: High score retrieved successfully\n components: {}\n \", \"Logic Analysis\": [[\"constants.py\", \"Contains all the constant values like screen size, colors, game speeds, etc. This should be implemented first as it provides the base values for other components.\"], [\"snake.py\", \"Contains the Snake class with methods for movement, growth, and collision detection. It is dependent on constants.py for configuration values.\"], [\"food.py\", \"Contains the Food class responsible for spawning food items on the screen. It is dependent on constants.py for configuration values.\"], [\"obstacle.py\", \"Contains the Obstacle class with methods for spawning, moving, and disappearing of obstacles, as well as collision detection with the snake. It is dependent on constants.py for configuration values.\"], [\"scoreboard.py\", \"Contains the Scoreboard class for updating, resetting, loading, and saving high scores. It may use constants.py for configuration values and depends on the game's scoring logic.\"], [\"game.py\", \"Contains the main Game class which includes the game loop and methods for starting, pausing, resuming, and ending the game. It is dependent on snake.py, food.py, obstacle.py, and scoreboard.py.\"], [\"main.py\", \"The entry point of the game that initializes the game and starts the game loop. It is dependent on game.py.\"]], \"Task list\": [\"constants.py\", \"snake.py\", \"food.py\", \"obstacle.py\", \"scoreboard.py\", \"game.py\", \"main.py\"], \"Shared Knowledge\": \"\n 'constants.py' should contain all the necessary configurations for the game, such as screen dimensions, color definitions, and speed settings. These constants will be used across multiple files, ensuring consistency and ease of updates. Ensure that the Pygame library is initialized correctly in 'main.py' before starting the game loop. Also, make sure that the game's state is managed properly when pausing and resuming the game.\n \", \"Anything UNCLEAR\": \"The interaction between the 'obstacle.py' and the game loop needs to be clearly defined to ensure obstacles appear and disappear correctly. The lifetime of the obstacle and its random movement should be implemented in a way that does not interfere with the game's performance.\"}\n\n```\n-----\n```python\n\n## game.py\nimport pygame\nfrom snake import Snake\nfrom food import Food\n\nclass Game:\n def __init__(self):\n self.score = 0\n self.level = 1\n self.snake = Snake()\n self.food = Food()\n\n def start_game(self):\n pygame.init()\n self.initialize_game()\n self.game_loop()\n\n def initialize_game(self):\n self.score = 0\n self.level = 1\n self.snake.reset()\n self.food.generate()\n\n def game_loop(self):\n game_over = False\n\n while not game_over:\n self.update()\n self.draw()\n self.handle_events()\n self.check_collision()\n self.increase_score()\n self.increase_level()\n\n if self.snake.is_collision():\n game_over = True\n self.game_over()\n\n def update(self):\n self.snake.move()\n\n def draw(self):\n self.snake.draw()\n self.food.draw()\n\n def handle_events(self):\n for event in pygame.event.get():\n if event.type == pygame.QUIT:\n pygame.quit()\n quit()\n elif event.type == pygame.KEYDOWN:\n if event.key == pygame.K_UP:\n self.snake.change_direction(\"UP\")\n elif event.key == pygame.K_DOWN:\n self.snake.change_direction(\"DOWN\")\n elif event.key == pygame.K_LEFT:\n self.snake.change_direction(\"LEFT\")\n elif event.key == pygame.K_RIGHT:\n self.snake.change_direction(\"RIGHT\")\n\n def check_collision(self):\n if self.snake.get_head() == self.food.get_position():\n self.snake.grow()\n self.food.generate()\n\n def increase_score(self):\n self.score += 1\n\n def increase_level(self):\n if self.score % 10 == 0:\n self.level += 1\n\n def game_over(self):\n print(\"Game Over\")\n self.initialize_game()\n\n\n```\n-----\n```python\n\n## snake.py\nimport pygame\n\nclass Snake:\n def __init__(self):\n self.body = [(0, 0)]\n self.direction = (1, 0)\n\n def move(self):\n head = self.body[0]\n dx, dy = self.direction\n new_head = (head[0] + dx, head[1] + dy)\n self.body.insert(0, new_head)\n self.body.pop()\n\n def change_direction(self, direction):\n if direction == \"UP\":\n self.direction = (0, -1)\n elif direction == \"DOWN\":\n self.direction = (0, 1)\n elif direction == \"LEFT\":\n self.direction = (-1, 0)\n elif direction == \"RIGHT\":\n self.direction = (1, 0)\n\n def grow(self):\n tail = self.body[-1]\n dx, dy = self.direction\n new_tail = (tail[0] - dx, tail[1] - dy)\n self.body.append(new_tail)\n\n def get_head(self):\n return self.body[0]\n\n def get_body(self):\n return self.body[1:]\n\n\n```\n-----\n```python\n\n## main.py\nimport pygame\nfrom game import Game\n\ndef main():\n pygame.init()\n game = Game()\n game.start_game()\n\nif __name__ == \"__main__\":\n main()\n\n\n```\n-----\n```python\n\n## food.py\nimport random\n\nclass Food:\n def __init__(self):\n self.position = (0, 0)\n\n def generate(self):\n x = random.randint(0, 9)\n y = random.randint(0, 9)\n self.position = (x, y)\n\n def get_position(self):\n return self.position\n\n\n```\n-----\n\n## Code Review All: Please read all historical files and find possible bugs in the files, such as unimplemented functions, calling errors, unreferences, etc.\n\n## Call flow: mermaid code, based on the implemented function, use mermaid to draw a complete call chain\n\n## Summary: Summary based on the implementation of historical files\n\n## TODOs: Python dict[str, str], write down the list of files that need to be modified and the reasons. We will modify them later.\n\n": "```mermaid\nclassDiagram\n class Game{\n +int score\n +int level\n +Snake snake\n +Food food\n +start_game() void\n +initialize_game() void\n +game_loop() void\n +update() void\n +draw() void\n +handle_events() void\n +check_collision() void\n +increase_score() void\n +increase_level() void\n +game_over() void\n Game()\n }\n class Snake{\n +list body\n +tuple direction\n +move() void\n +change_direction(direction: str) void\n +grow() void\n +get_head() tuple\n +get_body() list\n Snake()\n }\n class Food{\n +tuple position\n +generate() void\n +get_position() tuple\n Food()\n }\n Game \"1\" -- \"1\" Snake: has\n Game \"1\" -- \"1\" Food: has\n```\n\n```sequenceDiagram\nparticipant M as Main\nparticipant G as Game\nparticipant S as Snake\nparticipant F as Food\nM->>G: start_game()\nG->>G: initialize_game()\nG->>G: game_loop()\nG->>S: move()\nG->>S: change_direction()\nG->>S: grow()\nG->>F: generate()\nS->>S: move()\nS->>S: change_direction()\nS->>S: grow()\nF->>F: generate()\n```\n\n## Summary\nThe code consists of the main game logic, including the Game, Snake, and Food classes. The game loop is responsible for updating and drawing the game elements, handling events, checking collisions, and managing the game state. The Snake class handles the movement, growth, and direction changes of the snake, while the Food class is responsible for generating and tracking the position of food items.\n\n## TODOs\n- Modify 'game.py' to add the implementation of obstacle handling and interaction with the game loop.\n- Implement 'obstacle.py' to include the methods for spawning, moving, and disappearing of obstacles, as well as collision detection with the snake.\n- Update 'main.py' to initialize the obstacle and incorporate it into the game loop.\n- Update the mermaid call flow diagram to include the interaction with the obstacle.\n\n```python\n{\n \"files_to_modify\": {\n \"game.py\": \"Add obstacle handling and interaction with the game loop\",\n \"obstacle.py\": \"Implement obstacle class with necessary methods\",\n \"main.py\": \"Initialize the obstacle and incorporate it into the game loop\"\n }\n}\n```",
+ "\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设计一个名为'add'的函数,该函数接受两个整数作为输入,并返回它们的和。\n\n## Task\n\n\n## Legacy Code\n```Code\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: \n```python\n## \n...\n```\n\n# Instruction: Based on the context, follow \"Format example\", write code.\n\n## Code: . 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": "## Code: \n```python\n## Design a function called 'add' that takes two integers as input and returns their sum.\n\ndef add(num1: int, num2: int) -> int:\n \"\"\"\n Add two integers and return the sum.\n \n Args:\n num1: An integer.\n num2: An integer.\n \n Returns:\n The sum of num1 and num2 as an integer.\n \"\"\"\n return num1 + num2\n```",
+ "\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 the Pygame library to create the game interface and handle user input. The game logic will be implemented using Python classes and data structures.\", \"File list\": [\"main.py\", \"game.py\"], \"Data structures and interfaces\": \"classDiagram\\n class Game {\\n -grid: List[List[int]]\\n -score: int\\n -game_over: bool\\n +__init__()\\n +reset_game()\\n +move(direction: str)\\n +is_game_over() bool\\n +get_empty_cells() List[Tuple[int, int]]\\n +add_new_tile()\\n +get_score() int\\n }\\n class UI {\\n -game: Game\\n +__init__(game: Game)\\n +draw_grid()\\n +draw_score()\\n +draw_game_over()\\n +handle_input()\\n }\\n Game --> UI\", \"Program call flow\": \"sequenceDiagram\\n participant M as Main\\n participant G as Game\\n participant U as UI\\n M->>G: reset_game()\\n M->>U: draw_grid()\\n M->>U: draw_score()\\n M->>U: handle_input()\\n U->>G: move(direction)\\n G->>G: add_new_tile()\\n G->>U: draw_grid()\\n G->>U: draw_score()\\n G->>U: draw_game_over()\\n G->>G: is_game_over()\\n G->>G: get_empty_cells()\\n G->>G: get_score()\", \"Anything UNCLEAR\": \"...\"}\n\n## Task\n{\"Required Python packages\": [\"pygame==2.0.1\"], \"Required Other language third-party packages\": [\"No third-party dependencies required\"], \"Logic Analysis\": [[\"game.py\", \"Contains Game class and related functions for game logic\"], [\"main.py\", \"Contains main function, initializes the game and UI\"]], \"Task list\": [\"game.py\", \"main.py\"], \"Full API spec\": \"\", \"Shared Knowledge\": \"The game logic will be implemented using Python classes and data structures. The Pygame library will be used to create the game interface and handle user input.\", \"Anything UNCLEAR\": \"...\"}\n\n## Legacy Code\n```Code\n\n```\n\n## Debug logs\n```text\nE.......F\n======================================================================\nERROR: test_add_new_tile (__main__.TestGame)\n----------------------------------------------------------------------\nTraceback (most recent call last):\n File \"/Users/xx/tests/test_game.py\", line 104, in test_add_new_tile\n self.assertIn(self.game.grid[empty_cells[0][0]][empty_cells[0][1]], [2, 4])\nIndexError: list index out of range\n\n======================================================================\nFAIL: test_reset_game (__main__.TestGame)\n----------------------------------------------------------------------\nTraceback (most recent call last):\n File \"/Users/xx/tests/test_game.py\", line 13, in test_reset_game\n self.assertEqual(self.game.grid, [[0 for _ in range(4)] for _ in range(4)])\nAssertionError: Lists differ: [[0, 0, 0, 0], [0, 2, 0, 0], [0, 0, 0, 2], [0, 0, 0, 0]] != [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]\n\nFirst differing element 1:\n[0, 2, 0, 0]\n[0, 0, 0, 0]\n\n- [[0, 0, 0, 0], [0, 2, 0, 0], [0, 0, 0, 2], [0, 0, 0, 0]]\n? --- ^\n\n+ [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]\n? +++ ^\n\n\n----------------------------------------------------------------------\nRan 9 tests in 0.002s\n\nFAILED (failures=1, errors=1)\n\n\n{\"design_filename\": \"docs/system_design/20231221155954.json\", \"task_filename\": \"docs/tasks/20231221155954.json\", \"codes_filenames\": [\"game.py\", \"main.py\"], \"reason\": \"```json\\n{\\n \\\"game.py\\\": \\\"Add handling for no empty cells in add_new_tile function, Update score in move function\\\",\\n \\\"main.py\\\": \\\"Handle game over condition in the game loop\\\"\\n}\\n```\"}\n```\n\n## Bug Feedback logs\n```text\n\n```\n\n# Format example\n## Code: game.py\n```python\n## game.py\n...\n```\n\n# Instruction: Based on the context, follow \"Format example\", write code.\n\n## Code: game.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": "## Code: game.py\n```python\n## game.py\n\nfrom typing import List, Tuple\nimport random\n\nclass Game:\n def __init__(self):\n self.grid: List[List[int]] = [[0 for _ in range(4)] for _ in range(4)]\n self.score: int = 0\n self.game_over: bool = False\n\n def reset_game(self):\n self.grid = [[0 for _ in range(4)] for _ in range(4)]\n self.score = 0\n self.game_over = False\n\n def move(self, direction: str):\n # Implement the move logic based on the direction\n pass\n\n def is_game_over(self) -> bool:\n # Check if the game is over\n return self.game_over\n\n def get_empty_cells(self) -> List[Tuple[int, int]]:\n empty_cells = []\n for i in range(4):\n for j in range(4):\n if self.grid[i][j] == 0:\n empty_cells.append((i, j))\n return empty_cells\n\n def add_new_tile(self):\n empty_cells = self.get_empty_cells()\n if empty_cells:\n cell = random.choice(empty_cells)\n self.grid[cell[0]][cell[1]] = random.choice([2, 4])\n else:\n # Handle the case when there are no empty cells\n pass\n\n def get_score(self) -> int:\n return self.score\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编写一个从a加b的函数,返回a+b\n\n## Task\n\n\n## Code Files\n\n\n\n## Code to be Reviewed: \n```Code\n\ndef add(a, b):\n return a + \n\n```\n\n\n\n# Format example 1\n## Code Review: \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: \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: \n1. No, the code is not implemented as per the requirements. The function 'add' is incomplete and does not return the sum of 'a' and 'b'.\n2. No, the code logic is not completely correct. The return statement in the 'add' function is incomplete.\n3. N/A\n4. N/A\n5. N/A\n6. N/A\n\n## Actions\n1. Complete the 'add' function to return the sum of 'a' and 'b'.\n ```python\n def add(a, b):\n return a + b\n ```\n\n## Code Review Result\nLBTM",
+ "\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编写一个从a加b的函数,返回a+b\n\n## Task\n\n\n## Code Files\n\n\n\n## Code to be Reviewed: \n```Code\n\ndef add(a, b):\n return a + \n\n```\n\n## Code Review: \n1. No, the code is not implemented as per the requirements. The function 'add' is incomplete and does not return the sum of 'a' and 'b'.\n2. No, the code logic is not completely correct. The return statement in the 'add' function is incomplete.\n3. N/A\n4. N/A\n5. N/A\n6. N/A\n\n## Actions\n1. Complete the 'add' function to return the sum of 'a' and 'b'.\n ```python\n def add(a, b):\n return a + b\n ```\n\n## Code Review Result\nLBTM\n\n# Instruction: rewrite code based on the Code Review and Actions\n## Rewrite Code: CodeBlock. If it still has some bugs, rewrite with triple quotes. Do your utmost to optimize THIS SINGLE FILE. Return all completed codes and prohibit the return of unfinished codes.\n```Code\n## \n...\n```\n": "```python\ndef add(a, b):\n return a + b\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编写一个从a加b的函数,返回a+b\n\n## Task\n\n\n## Code Files\n\n\n\n## Code to be Reviewed: \n```Code\ndef add(a, b):\n return a + b\n\n```\n\n\n\n# Format example 1\n## Code Review: \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: \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: \n1. Yes, the code is implemented as per the requirements.\n2. Yes, the code logic is completely correct.\n3. Yes, the existing code follows the \"Data structures and interfaces\".\n4. Yes, the function is implemented.\n5. Yes, all necessary pre-dependencies have been imported.\n6. N/A\n\n## Code Review Result\nLGTM",
+ "\n## context\n\n### Legacy Content\n{\"Implementation approach\":\"We will analyze the difficult points of the requirements and select the appropriate open-source framework to develop the search engine. We will also integrate a large language model to provide intelligent summarization of search results.\",\"File list\":[\"main.py\",\"search_engine.py\",\"index.py\",\"ranking.py\",\"summary.py\",\"knowledge_base.py\"],\"Data structures and interfaces\":\"\\nclassDiagram\\n class Main {\\n -SearchEngine search_engine\\n +main() str\\n }\\n class SearchEngine {\\n -Index index\\n -Ranking ranking\\n -Summary summary\\n +search(query: str) str\\n }\\n class Index {\\n -KnowledgeBase knowledge_base\\n +create_index(data: dict)\\n +query_index(query: str) list\\n }\\n class Ranking {\\n +rank_results(results: list) list\\n }\\n class Summary {\\n +summarize_results(results: list) str\\n }\\n class KnowledgeBase {\\n +update(data: dict)\\n +fetch_data(query: str) dict\\n }\\n Main --> SearchEngine\\n SearchEngine --> Index\\n SearchEngine --> Ranking\\n SearchEngine --> Summary\\n Index --> KnowledgeBase\\n\",\"Program call flow\":\"\\nsequenceDiagram\\n participant M as Main\\n participant SE as SearchEngine\\n participant I as Index\\n participant R as Ranking\\n participant S as Summary\\n participant KB as KnowledgeBase\\n M->>SE: search(query)\\n SE->>I: query_index(query)\\n I->>KB: fetch_data(query)\\n KB-->>I: return data\\n I-->>SE: return results\\n SE->>R: rank_results(results)\\n R-->>SE: return ranked_results\\n SE->>S: summarize_results(ranked_results)\\n S-->>SE: return summary\\n SE-->>M: return summary\\n\",\"Anything UNCLEAR\":\"Clarification needed on third-party API integration, optimization techniques, and security measures.\"}\n\n### New Requirements\n## 原始需求\n```python\n\"\"\"\n我们希望开发一个基于大语言模型与私有知识库的搜索引擎。该搜索引擎应当能根据用户输入的查询进行智能搜索,并基于大语言模型对搜索结果进行总结,以便用户能够快速获取他们所需要的信息。该搜索引擎应当能够处理大规模的数据,同时保持搜索结果的准确性和相关性。我们希望这个产品能够降低用户在查找、筛选和理解信息时的工作负担,提高他们的工作效率。\n\"\"\"\n```\n\n## 产品目标\n```python\n[\n \"提供高准确性、高相关性的搜索结果,满足用户的查询需求\",\n \"基于大语言模型对搜索结果进行智能总结,帮助用户快速获取所需信息\",\n \"处理大规模数据,保证搜索的速度和效率,提高用户的工作效率\"\n]\n```\n\n## 用户故事\n```python\n[\n \"假设用户是一名研究员,他正在为一项关于全球气候变化的报告做研究。他输入了'全球气候变化的最新研究',我们的搜索引擎快速返回了相关的文章、报告、数据集等。并且基于大语言模型对这些信息进行了智能总结,研究员可以快速了解到最新的研究趋势和发现。\",\n \"用户是一名学生,正在为即将到来的历史考试复习。他输入了'二战的主要战役',搜索引擎返回了相关的资料,大语言模型总结出主要战役的时间、地点、结果等关键信息,帮助学生快速记忆。\",\n \"用户是一名企业家,他正在寻找关于最新的市场趋势信息。他输入了'2023年人工智能市场趋势',搜索引擎返回了各种报告、新闻和分析文章。大语言模型对这些信息进行了总结,用户能够快速了解到市场的最新动态和趋势。\"\n]\n```\n\n## 竞品分析\n```python\n[\n \"Google Search:Google搜索是市场上最主要的搜索引擎,它能够提供海量的搜索结果。但Google搜索并不提供搜索结果的总结功能,用户需要自己去阅读和理解搜索结果。\",\n \"Microsoft Bing:Bing搜索也能提供丰富的搜索结果,同样没有提供搜索结果的总结功能。\",\n \"Wolfram Alpha:Wolfram Alpha是一个基于知识库的计算型搜索引擎,能够针对某些特定类型的查询提供直接的答案和总结,但它的知识库覆盖范围有限,无法处理大规模的数据。\"\n]\n```\n\n## 开发需求池\n```python\n[\n (\"开发基于大语言模型的智能总结功能\", 5),\n (\"开发搜索引擎核心算法,包括索引构建、查询处理、结果排序等\", 7),\n (\"设计和实现用户界面,包括查询输入、搜索结果展示、总结结果展示等\", 3),\n (\"构建和维护私有知识库,包括数据采集、清洗、更新等\", 7),\n (\"优化搜索引擎性能,包括搜索速度、准确性、相关性等\", 6),\n (\"开发用户反馈机制,包括反馈界面、反馈处理等\", 2),\n (\"开发安全防护机制,防止恶意查询和攻击\", 3),\n (\"集成大语言模型,包括模型选择、优化、更新等\", 5),\n (\"进行大规模的测试,包括功能测试、性能测试、压力测试等\", 5),\n (\"开发数据监控和日志系统,用于监控搜索引擎的运行状态和性能\", 4)\n]\n```\n\n\n\n-----\n\n## format example\n[CONTENT]\n{\n \"Refined Implementation Approach\": \"We will refine ...\",\n \"Refined File list\": [\n \"main.py\",\n \"game.py\",\n \"new_feature.py\"\n ],\n \"Refined Data structures and interfaces\": \"\\nclassDiagram\\n class Main {\\n -SearchEngine search_engine\\n +main() str\\n }\\n class SearchEngine {\\n -Index index\\n -Ranking ranking\\n -Summary summary\\n +search(query: str) str\\n }\\n class Index {\\n -KnowledgeBase knowledge_base\\n +create_index(data: dict)\\n +query_index(query: str) list\\n }\\n class Ranking {\\n +rank_results(results: list) list\\n }\\n class Summary {\\n +summarize_results(results: list) str\\n }\\n class KnowledgeBase {\\n +update(data: dict)\\n +fetch_data(query: str) dict\\n }\\n Main --> SearchEngine\\n SearchEngine --> Index\\n SearchEngine --> Ranking\\n SearchEngine --> Summary\\n Index --> KnowledgeBase\\n\",\n \"Refined Program call flow\": \"\\nsequenceDiagram\\n participant M as Main\\n participant SE as SearchEngine\\n participant I as Index\\n participant R as Ranking\\n participant S as Summary\\n participant KB as KnowledgeBase\\n M->>SE: search(query)\\n SE->>I: query_index(query)\\n I->>KB: fetch_data(query)\\n KB-->>I: return data\\n I-->>SE: return results\\n SE->>R: rank_results(results)\\n R-->>SE: return ranked_results\\n SE->>S: summarize_results(ranked_results)\\n S-->>SE: return summary\\n SE-->>M: return summary\\n\",\n \"Anything UNCLEAR\": \"Clarification needed on third-party API integration, ...\"\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- Refined Implementation Approach: # Update and extend the original implementation approach to reflect the evolving challenges and requirements due to incremental development. Outline the steps involved in the implementation process with the detailed strategies.\n- Refined File list: typing.List[str] # Update and expand the original file list including only relative paths. Up to 2 files can be added.Ensure that the refined file list reflects the evolving structure of the project.\n- Refined Data structures and interfaces: # Update and extend the existing mermaid classDiagram code syntax to incorporate new classes, methods (including __init__), and functions with precise type annotations. Delineate additional relationships between classes, ensuring clarity and adherence to PEP8 standards.Retain content that is not related to incremental development but important for consistency and clarity.\n- Refined Program call flow: # Extend the existing sequenceDiagram code syntax with detailed information, accurately covering theCRUD and initialization of each object. Ensure correct syntax usage and reflect the incremental changes introducedin the classes and API defined above. Retain content that is not related to incremental development but important for consistency and clarity.\n- Anything UNCLEAR: # Mention unclear project aspects, then try to clarify it.\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 \"Refined Implementation Approach\": \"We will refine the existing implementation approach to incorporate the new requirements for developing a search engine based on a large language model and a private knowledge base. We will update and extend the original implementation approach to reflect the evolving challenges and requirements due to incremental development. We will outline the steps involved in the implementation process with detailed strategies to ensure the search engine meets the new goals of providing high-accuracy and high-relevance search results, intelligent summarization of search results, and efficient handling of large-scale data.\",\n \"Refined File list\": [\n \"main.py\",\n \"search_engine.py\",\n \"index.py\",\n \"ranking.py\",\n \"summary.py\",\n \"knowledge_base.py\",\n \"user_interface.py\"\n ],\n \"Refined Data structures and interfaces\": \"\\nclassDiagram\\n class Main {\\n -SearchEngine search_engine\\n -UserInterface user_interface\\n +main() str\\n }\\n class SearchEngine {\\n -Index index\\n -Ranking ranking\\n -Summary summary\\n -KnowledgeBase knowledge_base\\n +search(query: str) str\\n }\\n class Index {\\n +create_index(data: dict)\\n +query_index(query: str) list\\n }\\n class Ranking {\\n +rank_results(results: list) list\\n }\\n class Summary {\\n +summarize_results(results: list) str\\n }\\n class KnowledgeBase {\\n +update(data: dict)\\n +fetch_data(query: str) dict\\n }\\n class UserInterface {\\n +display_search_results(results: str)\\n +display_summary(summary: str)\\n }\\n Main --> SearchEngine\\n Main --> UserInterface\\n SearchEngine --> Index\\n SearchEngine --> Ranking\\n SearchEngine --> Summary\\n SearchEngine --> KnowledgeBase\\n\",\n \"Refined Program call flow\": \"\\nsequenceDiagram\\n participant M as Main\\n participant SE as SearchEngine\\n participant UI as UserInterface\\n participant I as Index\\n participant R as Ranking\\n participant S as Summary\\n participant KB as KnowledgeBase\\n M->>UI: main()\\n UI->>M: return results\\n M->>SE: search(query)\\n SE->>I: query_index(query)\\n I->>KB: fetch_data(query)\\n KB-->>I: return data\\n I-->>SE: return results\\n SE->>R: rank_results(results)\\n R-->>SE: return ranked_results\\n SE->>S: summarize_results(ranked_results)\\n S-->>SE: return summary\\n SE->>UI: display_search_results(results)\\n UI->>SE: display_summary(summary)\\n\",\n \"Anything UNCLEAR\": \"Clarification needed on third-party API integration, optimization techniques, and security measures.\"\n}\n[/CONTENT]",
+ "\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## Project name\n```python\n\"smart_search_engine\"\n```\n\n## Task list:\n```python\n[\n \"smart_search_engine/__init__.py\",\n \"smart_search_engine/main.py\",\n \"smart_search_engine/search.py\",\n \"smart_search_engine/index.py\",\n \"smart_search_engine/ranking.py\",\n \"smart_search_engine/summary.py\",\n \"smart_search_engine/knowledge_base.py\",\n \"smart_search_engine/interface.py\",\n \"smart_search_engine/user_feedback.py\",\n \"smart_search_engine/security.py\",\n \"smart_search_engine/testing.py\",\n \"smart_search_engine/monitoring.py\"\n]\n```\n\n## Data structures and interfaces\n```mermaid\nclassDiagram\n class Main {\n -SearchEngine search_engine\n +main() str\n }\n class SearchEngine {\n -Index index\n -Ranking ranking\n -Summary summary\n +search(query: str) str\n }\n class Index {\n -KnowledgeBase knowledge_base\n +create_index(data: dict)\n +query_index(query: str) list\n }\n class Ranking {\n +rank_results(results: list) list\n }\n class Summary {\n +summarize_results(results: list) str\n }\n class KnowledgeBase {\n +update(data: dict)\n +fetch_data(query: str) dict\n }\n Main --> SearchEngine\n SearchEngine --> Index\n SearchEngine --> Ranking\n SearchEngine --> Summary\n Index --> KnowledgeBase\n```\n\n## Program call flow\n```mermaid\nsequenceDiagram\n participant M as Main\n participant SE as SearchEngine\n participant I as Index\n participant R as Ranking\n participant S as Summary\n participant KB as KnowledgeBase\n M->>SE: search(query)\n SE->>I: query_index(query)\n I->>KB: fetch_data(query)\n KB-->>I: return data\n I-->>SE: return results\n SE->>R: rank_results(results)\n R-->>SE: return ranked_results\n SE->>S: summarize_results(ranked_results)\n S-->>SE: return summary\n SE-->>M: return summary\n```\n\n\n## Task\n{\"Logic Analysis\": \"\\n 在这个项目中,所有的模块都依赖于“SearchEngine”类,这是主入口,其他的模块(Index、Ranking和Summary)都通过它交互。另外,\\\"Index\\\"类又依赖于\\\"KnowledgeBase\\\"类,因为它需要从知识库中获取数据。\\n\\n- \\\"main.py\\\"包含\\\"Main\\\"类,是程序的入口点,它调用\\\"SearchEngine\\\"进行搜索操作,所以在其他任何模块之前,\\\"SearchEngine\\\"必须首先被定义。\\n- \\\"search.py\\\"定义了\\\"SearchEngine\\\"类,它依赖于\\\"Index\\\"、\\\"Ranking\\\"和\\\"Summary\\\",因此,这些模块需要在\\\"search.py\\\"之前定义。\\n- \\\"index.py\\\"定义了\\\"Index\\\"类,它从\\\"knowledge_base.py\\\"获取数据来创建索引,所以\\\"knowledge_base.py\\\"需要在\\\"index.py\\\"之前定义。\\n- \\\"ranking.py\\\"和\\\"summary.py\\\"相对独立,只需确保在\\\"search.py\\\"之前定义。\\n- \\\"knowledge_base.py\\\"是独立的模块,可以优先开发。\\n- \\\"interface.py\\\"、\\\"user_feedback.py\\\"、\\\"security.py\\\"、\\\"testing.py\\\"和\\\"monitoring.py\\\"看起来像是功能辅助模块,可以在主要功能模块开发完成后并行开发。\\n \", \"Task list\": [\"smart_search_engine/knowledge_base.py\", \"smart_search_engine/index.py\", \"smart_search_engine/ranking.py\", \"smart_search_engine/summary.py\", \"smart_search_engine/search.py\", \"smart_search_engine/main.py\", \"smart_search_engine/interface.py\", \"smart_search_engine/user_feedback.py\", \"smart_search_engine/security.py\", \"smart_search_engine/testing.py\", \"smart_search_engine/monitoring.py\"]}\n\n## Legacy Code\n```Code\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: smart_search_engine/knowledge_base.py\n```python\n## smart_search_engine/knowledge_base.py\n...\n```\n\n# Instruction: Based on the context, follow \"Format example\", write code.\n\n## Code: smart_search_engine/knowledge_base.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## smart_search_engine/knowledge_base.py\n\nclass KnowledgeBase:\n def __init__(self, data={}):\n self.data = data\n\n def update(self, data: dict):\n \"\"\"\n Update the knowledge base with new data.\n \n Args:\n data (dict): The new data to be added to the knowledge base.\n \"\"\"\n self.data.update(data)\n\n def fetch_data(self, query: str) -> dict:\n \"\"\"\n Fetch data from the knowledge base based on the query.\n \n Args:\n query (str): The query to search for in the knowledge base.\n \n Returns:\n dict: The data fetched from the knowledge base based on the query.\n \"\"\"\n return self.data.get(query, {})\n```",
+ "\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## Project name\n```python\n\"smart_search_engine\"\n```\n\n## Task list:\n```python\n[\n \"smart_search_engine/__init__.py\",\n \"smart_search_engine/main.py\",\n \"smart_search_engine/search.py\",\n \"smart_search_engine/index.py\",\n \"smart_search_engine/ranking.py\",\n \"smart_search_engine/summary.py\",\n \"smart_search_engine/knowledge_base.py\",\n \"smart_search_engine/interface.py\",\n \"smart_search_engine/user_feedback.py\",\n \"smart_search_engine/security.py\",\n \"smart_search_engine/testing.py\",\n \"smart_search_engine/monitoring.py\"\n]\n```\n\n## Data structures and interfaces\n```mermaid\nclassDiagram\n class Main {\n -SearchEngine search_engine\n +main() str\n }\n class SearchEngine {\n -Index index\n -Ranking ranking\n -Summary summary\n +search(query: str) str\n }\n class Index {\n -KnowledgeBase knowledge_base\n +create_index(data: dict)\n +query_index(query: str) list\n }\n class Ranking {\n +rank_results(results: list) list\n }\n class Summary {\n +summarize_results(results: list) str\n }\n class KnowledgeBase {\n +update(data: dict)\n +fetch_data(query: str) dict\n }\n Main --> SearchEngine\n SearchEngine --> Index\n SearchEngine --> Ranking\n SearchEngine --> Summary\n Index --> KnowledgeBase\n```\n\n## Program call flow\n```mermaid\nsequenceDiagram\n participant M as Main\n participant SE as SearchEngine\n participant I as Index\n participant R as Ranking\n participant S as Summary\n participant KB as KnowledgeBase\n M->>SE: search(query)\n SE->>I: query_index(query)\n I->>KB: fetch_data(query)\n KB-->>I: return data\n I-->>SE: return results\n SE->>R: rank_results(results)\n R-->>SE: return ranked_results\n SE->>S: summarize_results(ranked_results)\n S-->>SE: return summary\n SE-->>M: return summary\n```\n\n\n## Task\n{\"Logic Analysis\": \"\\n 在这个项目中,所有的模块都依赖于“SearchEngine”类,这是主入口,其他的模块(Index、Ranking和Summary)都通过它交互。另外,\\\"Index\\\"类又依赖于\\\"KnowledgeBase\\\"类,因为它需要从知识库中获取数据。\\n\\n- \\\"main.py\\\"包含\\\"Main\\\"类,是程序的入口点,它调用\\\"SearchEngine\\\"进行搜索操作,所以在其他任何模块之前,\\\"SearchEngine\\\"必须首先被定义。\\n- \\\"search.py\\\"定义了\\\"SearchEngine\\\"类,它依赖于\\\"Index\\\"、\\\"Ranking\\\"和\\\"Summary\\\",因此,这些模块需要在\\\"search.py\\\"之前定义。\\n- \\\"index.py\\\"定义了\\\"Index\\\"类,它从\\\"knowledge_base.py\\\"获取数据来创建索引,所以\\\"knowledge_base.py\\\"需要在\\\"index.py\\\"之前定义。\\n- \\\"ranking.py\\\"和\\\"summary.py\\\"相对独立,只需确保在\\\"search.py\\\"之前定义。\\n- \\\"knowledge_base.py\\\"是独立的模块,可以优先开发。\\n- \\\"interface.py\\\"、\\\"user_feedback.py\\\"、\\\"security.py\\\"、\\\"testing.py\\\"和\\\"monitoring.py\\\"看起来像是功能辅助模块,可以在主要功能模块开发完成后并行开发。\\n \", \"Task list\": [\"smart_search_engine/knowledge_base.py\", \"smart_search_engine/index.py\", \"smart_search_engine/ranking.py\", \"smart_search_engine/summary.py\", \"smart_search_engine/search.py\", \"smart_search_engine/main.py\", \"smart_search_engine/interface.py\", \"smart_search_engine/user_feedback.py\", \"smart_search_engine/security.py\", \"smart_search_engine/testing.py\", \"smart_search_engine/monitoring.py\"]}\n\n## Legacy Code\n```Code\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: smart_search_engine/index.py\n```python\n## smart_search_engine/index.py\n...\n```\n\n# Instruction: Based on the context, follow \"Format example\", write code.\n\n## Code: smart_search_engine/index.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## smart_search_engine/index.py\n\nfrom smart_search_engine.knowledge_base import KnowledgeBase\n\nclass Index:\n def __init__(self, knowledge_base: KnowledgeBase):\n self.knowledge_base = knowledge_base\n self.index_data = {}\n\n def create_index(self, data: dict):\n self.index_data = data\n\n def query_index(self, query: str) -> list:\n if query in self.index_data:\n return self.index_data[query]\n else:\n return []\n\n```",
+ "\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## Project name\n```python\n\"smart_search_engine\"\n```\n\n## Task list:\n```python\n[\n \"smart_search_engine/__init__.py\",\n \"smart_search_engine/main.py\",\n \"smart_search_engine/search.py\",\n \"smart_search_engine/index.py\",\n \"smart_search_engine/ranking.py\",\n \"smart_search_engine/summary.py\",\n \"smart_search_engine/knowledge_base.py\",\n \"smart_search_engine/interface.py\",\n \"smart_search_engine/user_feedback.py\",\n \"smart_search_engine/security.py\",\n \"smart_search_engine/testing.py\",\n \"smart_search_engine/monitoring.py\"\n]\n```\n\n## Data structures and interfaces\n```mermaid\nclassDiagram\n class Main {\n -SearchEngine search_engine\n +main() str\n }\n class SearchEngine {\n -Index index\n -Ranking ranking\n -Summary summary\n +search(query: str) str\n }\n class Index {\n -KnowledgeBase knowledge_base\n +create_index(data: dict)\n +query_index(query: str) list\n }\n class Ranking {\n +rank_results(results: list) list\n }\n class Summary {\n +summarize_results(results: list) str\n }\n class KnowledgeBase {\n +update(data: dict)\n +fetch_data(query: str) dict\n }\n Main --> SearchEngine\n SearchEngine --> Index\n SearchEngine --> Ranking\n SearchEngine --> Summary\n Index --> KnowledgeBase\n```\n\n## Program call flow\n```mermaid\nsequenceDiagram\n participant M as Main\n participant SE as SearchEngine\n participant I as Index\n participant R as Ranking\n participant S as Summary\n participant KB as KnowledgeBase\n M->>SE: search(query)\n SE->>I: query_index(query)\n I->>KB: fetch_data(query)\n KB-->>I: return data\n I-->>SE: return results\n SE->>R: rank_results(results)\n R-->>SE: return ranked_results\n SE->>S: summarize_results(ranked_results)\n S-->>SE: return summary\n SE-->>M: return summary\n```\n\n\n## Task\n{\"Logic Analysis\": \"\\n 在这个项目中,所有的模块都依赖于“SearchEngine”类,这是主入口,其他的模块(Index、Ranking和Summary)都通过它交互。另外,\\\"Index\\\"类又依赖于\\\"KnowledgeBase\\\"类,因为它需要从知识库中获取数据。\\n\\n- \\\"main.py\\\"包含\\\"Main\\\"类,是程序的入口点,它调用\\\"SearchEngine\\\"进行搜索操作,所以在其他任何模块之前,\\\"SearchEngine\\\"必须首先被定义。\\n- \\\"search.py\\\"定义了\\\"SearchEngine\\\"类,它依赖于\\\"Index\\\"、\\\"Ranking\\\"和\\\"Summary\\\",因此,这些模块需要在\\\"search.py\\\"之前定义。\\n- \\\"index.py\\\"定义了\\\"Index\\\"类,它从\\\"knowledge_base.py\\\"获取数据来创建索引,所以\\\"knowledge_base.py\\\"需要在\\\"index.py\\\"之前定义。\\n- \\\"ranking.py\\\"和\\\"summary.py\\\"相对独立,只需确保在\\\"search.py\\\"之前定义。\\n- \\\"knowledge_base.py\\\"是独立的模块,可以优先开发。\\n- \\\"interface.py\\\"、\\\"user_feedback.py\\\"、\\\"security.py\\\"、\\\"testing.py\\\"和\\\"monitoring.py\\\"看起来像是功能辅助模块,可以在主要功能模块开发完成后并行开发。\\n \", \"Task list\": [\"smart_search_engine/knowledge_base.py\", \"smart_search_engine/index.py\", \"smart_search_engine/ranking.py\", \"smart_search_engine/summary.py\", \"smart_search_engine/search.py\", \"smart_search_engine/main.py\", \"smart_search_engine/interface.py\", \"smart_search_engine/user_feedback.py\", \"smart_search_engine/security.py\", \"smart_search_engine/testing.py\", \"smart_search_engine/monitoring.py\"]}\n\n## Legacy Code\n```Code\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: smart_search_engine/ranking.py\n```python\n## smart_search_engine/ranking.py\n...\n```\n\n# Instruction: Based on the context, follow \"Format example\", write code.\n\n## Code: smart_search_engine/ranking.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## smart_search_engine/ranking.py\n\nclass Ranking:\n def __init__(self):\n pass\n\n def rank_results(self, results: list) -> list:\n \"\"\"\n Rank the search results based on relevance.\n\n Args:\n results (list): List of search results.\n\n Returns:\n list: Ranked list of search results.\n \"\"\"\n # Implement ranking algorithm here\n ranked_results = self._custom_ranking_algorithm(results)\n return ranked_results\n\n def _custom_ranking_algorithm(self, results: list) -> list:\n \"\"\"\n Custom ranking algorithm to rank search results.\n\n Args:\n results (list): List of search results.\n\n Returns:\n list: Ranked list of search results.\n \"\"\"\n # Implement custom ranking algorithm here\n return results\n```",
+ "\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## Project name\n```python\n\"smart_search_engine\"\n```\n\n## Task list:\n```python\n[\n \"smart_search_engine/__init__.py\",\n \"smart_search_engine/main.py\",\n \"smart_search_engine/search.py\",\n \"smart_search_engine/index.py\",\n \"smart_search_engine/ranking.py\",\n \"smart_search_engine/summary.py\",\n \"smart_search_engine/knowledge_base.py\",\n \"smart_search_engine/interface.py\",\n \"smart_search_engine/user_feedback.py\",\n \"smart_search_engine/security.py\",\n \"smart_search_engine/testing.py\",\n \"smart_search_engine/monitoring.py\"\n]\n```\n\n## Data structures and interfaces\n```mermaid\nclassDiagram\n class Main {\n -SearchEngine search_engine\n +main() str\n }\n class SearchEngine {\n -Index index\n -Ranking ranking\n -Summary summary\n +search(query: str) str\n }\n class Index {\n -KnowledgeBase knowledge_base\n +create_index(data: dict)\n +query_index(query: str) list\n }\n class Ranking {\n +rank_results(results: list) list\n }\n class Summary {\n +summarize_results(results: list) str\n }\n class KnowledgeBase {\n +update(data: dict)\n +fetch_data(query: str) dict\n }\n Main --> SearchEngine\n SearchEngine --> Index\n SearchEngine --> Ranking\n SearchEngine --> Summary\n Index --> KnowledgeBase\n```\n\n## Program call flow\n```mermaid\nsequenceDiagram\n participant M as Main\n participant SE as SearchEngine\n participant I as Index\n participant R as Ranking\n participant S as Summary\n participant KB as KnowledgeBase\n M->>SE: search(query)\n SE->>I: query_index(query)\n I->>KB: fetch_data(query)\n KB-->>I: return data\n I-->>SE: return results\n SE->>R: rank_results(results)\n R-->>SE: return ranked_results\n SE->>S: summarize_results(ranked_results)\n S-->>SE: return summary\n SE-->>M: return summary\n```\n\n\n## Task\n{\"Logic Analysis\": \"\\n 在这个项目中,所有的模块都依赖于“SearchEngine”类,这是主入口,其他的模块(Index、Ranking和Summary)都通过它交互。另外,\\\"Index\\\"类又依赖于\\\"KnowledgeBase\\\"类,因为它需要从知识库中获取数据。\\n\\n- \\\"main.py\\\"包含\\\"Main\\\"类,是程序的入口点,它调用\\\"SearchEngine\\\"进行搜索操作,所以在其他任何模块之前,\\\"SearchEngine\\\"必须首先被定义。\\n- \\\"search.py\\\"定义了\\\"SearchEngine\\\"类,它依赖于\\\"Index\\\"、\\\"Ranking\\\"和\\\"Summary\\\",因此,这些模块需要在\\\"search.py\\\"之前定义。\\n- \\\"index.py\\\"定义了\\\"Index\\\"类,它从\\\"knowledge_base.py\\\"获取数据来创建索引,所以\\\"knowledge_base.py\\\"需要在\\\"index.py\\\"之前定义。\\n- \\\"ranking.py\\\"和\\\"summary.py\\\"相对独立,只需确保在\\\"search.py\\\"之前定义。\\n- \\\"knowledge_base.py\\\"是独立的模块,可以优先开发。\\n- \\\"interface.py\\\"、\\\"user_feedback.py\\\"、\\\"security.py\\\"、\\\"testing.py\\\"和\\\"monitoring.py\\\"看起来像是功能辅助模块,可以在主要功能模块开发完成后并行开发。\\n \", \"Task list\": [\"smart_search_engine/knowledge_base.py\", \"smart_search_engine/index.py\", \"smart_search_engine/ranking.py\", \"smart_search_engine/summary.py\", \"smart_search_engine/search.py\", \"smart_search_engine/main.py\", \"smart_search_engine/interface.py\", \"smart_search_engine/user_feedback.py\", \"smart_search_engine/security.py\", \"smart_search_engine/testing.py\", \"smart_search_engine/monitoring.py\"]}\n\n## Legacy Code\n```Code\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: smart_search_engine/summary.py\n```python\n## smart_search_engine/summary.py\n...\n```\n\n# Instruction: Based on the context, follow \"Format example\", write code.\n\n## Code: smart_search_engine/summary.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## smart_search_engine/summary.py\n\nclass Summary:\n def __init__(self):\n pass\n\n def summarize_results(self, results: list) -> str:\n \"\"\"\n Summarize the search results.\n\n Args:\n - results (list): List of search results.\n\n Returns:\n - str: Summarized results.\n \"\"\"\n summary = \"\"\n for result in results:\n summary += result + \"\\n\"\n return summary\n```",
+ "\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## Project name\n```python\n\"smart_search_engine\"\n```\n\n## Task list:\n```python\n[\n \"smart_search_engine/__init__.py\",\n \"smart_search_engine/main.py\",\n \"smart_search_engine/search.py\",\n \"smart_search_engine/index.py\",\n \"smart_search_engine/ranking.py\",\n \"smart_search_engine/summary.py\",\n \"smart_search_engine/knowledge_base.py\",\n \"smart_search_engine/interface.py\",\n \"smart_search_engine/user_feedback.py\",\n \"smart_search_engine/security.py\",\n \"smart_search_engine/testing.py\",\n \"smart_search_engine/monitoring.py\"\n]\n```\n\n## Data structures and interfaces\n```mermaid\nclassDiagram\n class Main {\n -SearchEngine search_engine\n +main() str\n }\n class SearchEngine {\n -Index index\n -Ranking ranking\n -Summary summary\n +search(query: str) str\n }\n class Index {\n -KnowledgeBase knowledge_base\n +create_index(data: dict)\n +query_index(query: str) list\n }\n class Ranking {\n +rank_results(results: list) list\n }\n class Summary {\n +summarize_results(results: list) str\n }\n class KnowledgeBase {\n +update(data: dict)\n +fetch_data(query: str) dict\n }\n Main --> SearchEngine\n SearchEngine --> Index\n SearchEngine --> Ranking\n SearchEngine --> Summary\n Index --> KnowledgeBase\n```\n\n## Program call flow\n```mermaid\nsequenceDiagram\n participant M as Main\n participant SE as SearchEngine\n participant I as Index\n participant R as Ranking\n participant S as Summary\n participant KB as KnowledgeBase\n M->>SE: search(query)\n SE->>I: query_index(query)\n I->>KB: fetch_data(query)\n KB-->>I: return data\n I-->>SE: return results\n SE->>R: rank_results(results)\n R-->>SE: return ranked_results\n SE->>S: summarize_results(ranked_results)\n S-->>SE: return summary\n SE-->>M: return summary\n```\n\n\n## Task\n{\"Logic Analysis\": \"\\n 在这个项目中,所有的模块都依赖于“SearchEngine”类,这是主入口,其他的模块(Index、Ranking和Summary)都通过它交互。另外,\\\"Index\\\"类又依赖于\\\"KnowledgeBase\\\"类,因为它需要从知识库中获取数据。\\n\\n- \\\"main.py\\\"包含\\\"Main\\\"类,是程序的入口点,它调用\\\"SearchEngine\\\"进行搜索操作,所以在其他任何模块之前,\\\"SearchEngine\\\"必须首先被定义。\\n- \\\"search.py\\\"定义了\\\"SearchEngine\\\"类,它依赖于\\\"Index\\\"、\\\"Ranking\\\"和\\\"Summary\\\",因此,这些模块需要在\\\"search.py\\\"之前定义。\\n- \\\"index.py\\\"定义了\\\"Index\\\"类,它从\\\"knowledge_base.py\\\"获取数据来创建索引,所以\\\"knowledge_base.py\\\"需要在\\\"index.py\\\"之前定义。\\n- \\\"ranking.py\\\"和\\\"summary.py\\\"相对独立,只需确保在\\\"search.py\\\"之前定义。\\n- \\\"knowledge_base.py\\\"是独立的模块,可以优先开发。\\n- \\\"interface.py\\\"、\\\"user_feedback.py\\\"、\\\"security.py\\\"、\\\"testing.py\\\"和\\\"monitoring.py\\\"看起来像是功能辅助模块,可以在主要功能模块开发完成后并行开发。\\n \", \"Task list\": [\"smart_search_engine/knowledge_base.py\", \"smart_search_engine/index.py\", \"smart_search_engine/ranking.py\", \"smart_search_engine/summary.py\", \"smart_search_engine/search.py\", \"smart_search_engine/main.py\", \"smart_search_engine/interface.py\", \"smart_search_engine/user_feedback.py\", \"smart_search_engine/security.py\", \"smart_search_engine/testing.py\", \"smart_search_engine/monitoring.py\"]}\n\n## Legacy Code\n```Code\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: smart_search_engine/search.py\n```python\n## smart_search_engine/search.py\n...\n```\n\n# Instruction: Based on the context, follow \"Format example\", write code.\n\n## Code: smart_search_engine/search.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## smart_search_engine/search.py\n\nfrom smart_search_engine.index import Index\nfrom smart_search_engine.ranking import Ranking\nfrom smart_search_engine.summary import Summary\n\nclass SearchEngine:\n def __init__(self):\n self.index = Index()\n self.ranking = Ranking()\n self.summary = Summary()\n\n def search(self, query: str) -> str:\n results = self.index.query_index(query)\n ranked_results = self.ranking.rank_results(results)\n summary = self.summary.summarize_results(ranked_results)\n return summary\n```",
+ "\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## Project name\n```python\n\"smart_search_engine\"\n```\n\n## Task list:\n```python\n[\n \"smart_search_engine/__init__.py\",\n \"smart_search_engine/main.py\",\n \"smart_search_engine/search.py\",\n \"smart_search_engine/index.py\",\n \"smart_search_engine/ranking.py\",\n \"smart_search_engine/summary.py\",\n \"smart_search_engine/knowledge_base.py\",\n \"smart_search_engine/interface.py\",\n \"smart_search_engine/user_feedback.py\",\n \"smart_search_engine/security.py\",\n \"smart_search_engine/testing.py\",\n \"smart_search_engine/monitoring.py\"\n]\n```\n\n## Data structures and interfaces\n```mermaid\nclassDiagram\n class Main {\n -SearchEngine search_engine\n +main() str\n }\n class SearchEngine {\n -Index index\n -Ranking ranking\n -Summary summary\n +search(query: str) str\n }\n class Index {\n -KnowledgeBase knowledge_base\n +create_index(data: dict)\n +query_index(query: str) list\n }\n class Ranking {\n +rank_results(results: list) list\n }\n class Summary {\n +summarize_results(results: list) str\n }\n class KnowledgeBase {\n +update(data: dict)\n +fetch_data(query: str) dict\n }\n Main --> SearchEngine\n SearchEngine --> Index\n SearchEngine --> Ranking\n SearchEngine --> Summary\n Index --> KnowledgeBase\n```\n\n## Program call flow\n```mermaid\nsequenceDiagram\n participant M as Main\n participant SE as SearchEngine\n participant I as Index\n participant R as Ranking\n participant S as Summary\n participant KB as KnowledgeBase\n M->>SE: search(query)\n SE->>I: query_index(query)\n I->>KB: fetch_data(query)\n KB-->>I: return data\n I-->>SE: return results\n SE->>R: rank_results(results)\n R-->>SE: return ranked_results\n SE->>S: summarize_results(ranked_results)\n S-->>SE: return summary\n SE-->>M: return summary\n```\n\n\n## Task\n{\"Logic Analysis\": \"\\n 在这个项目中,所有的模块都依赖于“SearchEngine”类,这是主入口,其他的模块(Index、Ranking和Summary)都通过它交互。另外,\\\"Index\\\"类又依赖于\\\"KnowledgeBase\\\"类,因为它需要从知识库中获取数据。\\n\\n- \\\"main.py\\\"包含\\\"Main\\\"类,是程序的入口点,它调用\\\"SearchEngine\\\"进行搜索操作,所以在其他任何模块之前,\\\"SearchEngine\\\"必须首先被定义。\\n- \\\"search.py\\\"定义了\\\"SearchEngine\\\"类,它依赖于\\\"Index\\\"、\\\"Ranking\\\"和\\\"Summary\\\",因此,这些模块需要在\\\"search.py\\\"之前定义。\\n- \\\"index.py\\\"定义了\\\"Index\\\"类,它从\\\"knowledge_base.py\\\"获取数据来创建索引,所以\\\"knowledge_base.py\\\"需要在\\\"index.py\\\"之前定义。\\n- \\\"ranking.py\\\"和\\\"summary.py\\\"相对独立,只需确保在\\\"search.py\\\"之前定义。\\n- \\\"knowledge_base.py\\\"是独立的模块,可以优先开发。\\n- \\\"interface.py\\\"、\\\"user_feedback.py\\\"、\\\"security.py\\\"、\\\"testing.py\\\"和\\\"monitoring.py\\\"看起来像是功能辅助模块,可以在主要功能模块开发完成后并行开发。\\n \", \"Task list\": [\"smart_search_engine/knowledge_base.py\", \"smart_search_engine/index.py\", \"smart_search_engine/ranking.py\", \"smart_search_engine/summary.py\", \"smart_search_engine/search.py\", \"smart_search_engine/main.py\", \"smart_search_engine/interface.py\", \"smart_search_engine/user_feedback.py\", \"smart_search_engine/security.py\", \"smart_search_engine/testing.py\", \"smart_search_engine/monitoring.py\"]}\n\n## Legacy Code\n```Code\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: smart_search_engine/main.py\n```python\n## smart_search_engine/main.py\n...\n```\n\n# Instruction: Based on the context, follow \"Format example\", write code.\n\n## Code: smart_search_engine/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## smart_search_engine/main.py\n\nfrom smart_search_engine.search import SearchEngine\n\nclass Main:\n def __init__(self):\n self.search_engine = SearchEngine()\n\n def main(self) -> str:\n query = input(\"Enter your search query: \")\n result = self.search_engine.search(query)\n return result\n```",
+ "\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## Project name\n```python\n\"smart_search_engine\"\n```\n\n## Task list:\n```python\n[\n \"smart_search_engine/__init__.py\",\n \"smart_search_engine/main.py\",\n \"smart_search_engine/search.py\",\n \"smart_search_engine/index.py\",\n \"smart_search_engine/ranking.py\",\n \"smart_search_engine/summary.py\",\n \"smart_search_engine/knowledge_base.py\",\n \"smart_search_engine/interface.py\",\n \"smart_search_engine/user_feedback.py\",\n \"smart_search_engine/security.py\",\n \"smart_search_engine/testing.py\",\n \"smart_search_engine/monitoring.py\"\n]\n```\n\n## Data structures and interfaces\n```mermaid\nclassDiagram\n class Main {\n -SearchEngine search_engine\n +main() str\n }\n class SearchEngine {\n -Index index\n -Ranking ranking\n -Summary summary\n +search(query: str) str\n }\n class Index {\n -KnowledgeBase knowledge_base\n +create_index(data: dict)\n +query_index(query: str) list\n }\n class Ranking {\n +rank_results(results: list) list\n }\n class Summary {\n +summarize_results(results: list) str\n }\n class KnowledgeBase {\n +update(data: dict)\n +fetch_data(query: str) dict\n }\n Main --> SearchEngine\n SearchEngine --> Index\n SearchEngine --> Ranking\n SearchEngine --> Summary\n Index --> KnowledgeBase\n```\n\n## Program call flow\n```mermaid\nsequenceDiagram\n participant M as Main\n participant SE as SearchEngine\n participant I as Index\n participant R as Ranking\n participant S as Summary\n participant KB as KnowledgeBase\n M->>SE: search(query)\n SE->>I: query_index(query)\n I->>KB: fetch_data(query)\n KB-->>I: return data\n I-->>SE: return results\n SE->>R: rank_results(results)\n R-->>SE: return ranked_results\n SE->>S: summarize_results(ranked_results)\n S-->>SE: return summary\n SE-->>M: return summary\n```\n\n\n## Task\n{\"Logic Analysis\": \"\\n 在这个项目中,所有的模块都依赖于“SearchEngine”类,这是主入口,其他的模块(Index、Ranking和Summary)都通过它交互。另外,\\\"Index\\\"类又依赖于\\\"KnowledgeBase\\\"类,因为它需要从知识库中获取数据。\\n\\n- \\\"main.py\\\"包含\\\"Main\\\"类,是程序的入口点,它调用\\\"SearchEngine\\\"进行搜索操作,所以在其他任何模块之前,\\\"SearchEngine\\\"必须首先被定义。\\n- \\\"search.py\\\"定义了\\\"SearchEngine\\\"类,它依赖于\\\"Index\\\"、\\\"Ranking\\\"和\\\"Summary\\\",因此,这些模块需要在\\\"search.py\\\"之前定义。\\n- \\\"index.py\\\"定义了\\\"Index\\\"类,它从\\\"knowledge_base.py\\\"获取数据来创建索引,所以\\\"knowledge_base.py\\\"需要在\\\"index.py\\\"之前定义。\\n- \\\"ranking.py\\\"和\\\"summary.py\\\"相对独立,只需确保在\\\"search.py\\\"之前定义。\\n- \\\"knowledge_base.py\\\"是独立的模块,可以优先开发。\\n- \\\"interface.py\\\"、\\\"user_feedback.py\\\"、\\\"security.py\\\"、\\\"testing.py\\\"和\\\"monitoring.py\\\"看起来像是功能辅助模块,可以在主要功能模块开发完成后并行开发。\\n \", \"Task list\": [\"smart_search_engine/knowledge_base.py\", \"smart_search_engine/index.py\", \"smart_search_engine/ranking.py\", \"smart_search_engine/summary.py\", \"smart_search_engine/search.py\", \"smart_search_engine/main.py\", \"smart_search_engine/interface.py\", \"smart_search_engine/user_feedback.py\", \"smart_search_engine/security.py\", \"smart_search_engine/testing.py\", \"smart_search_engine/monitoring.py\"]}\n\n## Legacy Code\n```Code\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: smart_search_engine/interface.py\n```python\n## smart_search_engine/interface.py\n...\n```\n\n# Instruction: Based on the context, follow \"Format example\", write code.\n\n## Code: smart_search_engine/interface.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## smart_search_engine/interface.py\n\nfrom .search import SearchEngine\n\nclass UserInterface:\n def __init__(self):\n self.search_engine = SearchEngine()\n\n def get_user_input(self) -> str:\n # Get user input from the interface\n user_input = input(\"Enter your search query: \")\n return user_input\n\n def display_results(self, results: list):\n # Display search results to the user\n for result in results:\n print(result)\n\n# Ensure to follow the design and import necessary modules as needed.\n```",
+ "\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## Project name\n```python\n\"smart_search_engine\"\n```\n\n## Task list:\n```python\n[\n \"smart_search_engine/__init__.py\",\n \"smart_search_engine/main.py\",\n \"smart_search_engine/search.py\",\n \"smart_search_engine/index.py\",\n \"smart_search_engine/ranking.py\",\n \"smart_search_engine/summary.py\",\n \"smart_search_engine/knowledge_base.py\",\n \"smart_search_engine/interface.py\",\n \"smart_search_engine/user_feedback.py\",\n \"smart_search_engine/security.py\",\n \"smart_search_engine/testing.py\",\n \"smart_search_engine/monitoring.py\"\n]\n```\n\n## Data structures and interfaces\n```mermaid\nclassDiagram\n class Main {\n -SearchEngine search_engine\n +main() str\n }\n class SearchEngine {\n -Index index\n -Ranking ranking\n -Summary summary\n +search(query: str) str\n }\n class Index {\n -KnowledgeBase knowledge_base\n +create_index(data: dict)\n +query_index(query: str) list\n }\n class Ranking {\n +rank_results(results: list) list\n }\n class Summary {\n +summarize_results(results: list) str\n }\n class KnowledgeBase {\n +update(data: dict)\n +fetch_data(query: str) dict\n }\n Main --> SearchEngine\n SearchEngine --> Index\n SearchEngine --> Ranking\n SearchEngine --> Summary\n Index --> KnowledgeBase\n```\n\n## Program call flow\n```mermaid\nsequenceDiagram\n participant M as Main\n participant SE as SearchEngine\n participant I as Index\n participant R as Ranking\n participant S as Summary\n participant KB as KnowledgeBase\n M->>SE: search(query)\n SE->>I: query_index(query)\n I->>KB: fetch_data(query)\n KB-->>I: return data\n I-->>SE: return results\n SE->>R: rank_results(results)\n R-->>SE: return ranked_results\n SE->>S: summarize_results(ranked_results)\n S-->>SE: return summary\n SE-->>M: return summary\n```\n\n\n## Task\n{\"Logic Analysis\": \"\\n 在这个项目中,所有的模块都依赖于“SearchEngine”类,这是主入口,其他的模块(Index、Ranking和Summary)都通过它交互。另外,\\\"Index\\\"类又依赖于\\\"KnowledgeBase\\\"类,因为它需要从知识库中获取数据。\\n\\n- \\\"main.py\\\"包含\\\"Main\\\"类,是程序的入口点,它调用\\\"SearchEngine\\\"进行搜索操作,所以在其他任何模块之前,\\\"SearchEngine\\\"必须首先被定义。\\n- \\\"search.py\\\"定义了\\\"SearchEngine\\\"类,它依赖于\\\"Index\\\"、\\\"Ranking\\\"和\\\"Summary\\\",因此,这些模块需要在\\\"search.py\\\"之前定义。\\n- \\\"index.py\\\"定义了\\\"Index\\\"类,它从\\\"knowledge_base.py\\\"获取数据来创建索引,所以\\\"knowledge_base.py\\\"需要在\\\"index.py\\\"之前定义。\\n- \\\"ranking.py\\\"和\\\"summary.py\\\"相对独立,只需确保在\\\"search.py\\\"之前定义。\\n- \\\"knowledge_base.py\\\"是独立的模块,可以优先开发。\\n- \\\"interface.py\\\"、\\\"user_feedback.py\\\"、\\\"security.py\\\"、\\\"testing.py\\\"和\\\"monitoring.py\\\"看起来像是功能辅助模块,可以在主要功能模块开发完成后并行开发。\\n \", \"Task list\": [\"smart_search_engine/knowledge_base.py\", \"smart_search_engine/index.py\", \"smart_search_engine/ranking.py\", \"smart_search_engine/summary.py\", \"smart_search_engine/search.py\", \"smart_search_engine/main.py\", \"smart_search_engine/interface.py\", \"smart_search_engine/user_feedback.py\", \"smart_search_engine/security.py\", \"smart_search_engine/testing.py\", \"smart_search_engine/monitoring.py\"]}\n\n## Legacy Code\n```Code\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: smart_search_engine/user_feedback.py\n```python\n## smart_search_engine/user_feedback.py\n...\n```\n\n# Instruction: Based on the context, follow \"Format example\", write code.\n\n## Code: smart_search_engine/user_feedback.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## smart_search_engine/user_feedback.py\n\nclass UserFeedback:\n def __init__(self):\n self.feedback_data = {}\n\n def collect_feedback(self, feedback: str):\n self.feedback_data['feedback'] = feedback\n\n def get_feedback(self):\n return self.feedback_data.get('feedback', 'No feedback provided')\n\n# Code details:\n# - Created a class UserFeedback to handle user feedback.\n# - Initialized feedback_data as an empty dictionary in the constructor.\n# - Implemented collect_feedback method to store user feedback in the feedback_data dictionary.\n# - Implemented get_feedback method to retrieve the stored feedback, with a default message if no feedback is provided.\n```",
+ "\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## Project name\n```python\n\"smart_search_engine\"\n```\n\n## Task list:\n```python\n[\n \"smart_search_engine/__init__.py\",\n \"smart_search_engine/main.py\",\n \"smart_search_engine/search.py\",\n \"smart_search_engine/index.py\",\n \"smart_search_engine/ranking.py\",\n \"smart_search_engine/summary.py\",\n \"smart_search_engine/knowledge_base.py\",\n \"smart_search_engine/interface.py\",\n \"smart_search_engine/user_feedback.py\",\n \"smart_search_engine/security.py\",\n \"smart_search_engine/testing.py\",\n \"smart_search_engine/monitoring.py\"\n]\n```\n\n## Data structures and interfaces\n```mermaid\nclassDiagram\n class Main {\n -SearchEngine search_engine\n +main() str\n }\n class SearchEngine {\n -Index index\n -Ranking ranking\n -Summary summary\n +search(query: str) str\n }\n class Index {\n -KnowledgeBase knowledge_base\n +create_index(data: dict)\n +query_index(query: str) list\n }\n class Ranking {\n +rank_results(results: list) list\n }\n class Summary {\n +summarize_results(results: list) str\n }\n class KnowledgeBase {\n +update(data: dict)\n +fetch_data(query: str) dict\n }\n Main --> SearchEngine\n SearchEngine --> Index\n SearchEngine --> Ranking\n SearchEngine --> Summary\n Index --> KnowledgeBase\n```\n\n## Program call flow\n```mermaid\nsequenceDiagram\n participant M as Main\n participant SE as SearchEngine\n participant I as Index\n participant R as Ranking\n participant S as Summary\n participant KB as KnowledgeBase\n M->>SE: search(query)\n SE->>I: query_index(query)\n I->>KB: fetch_data(query)\n KB-->>I: return data\n I-->>SE: return results\n SE->>R: rank_results(results)\n R-->>SE: return ranked_results\n SE->>S: summarize_results(ranked_results)\n S-->>SE: return summary\n SE-->>M: return summary\n```\n\n\n## Task\n{\"Logic Analysis\": \"\\n 在这个项目中,所有的模块都依赖于“SearchEngine”类,这是主入口,其他的模块(Index、Ranking和Summary)都通过它交互。另外,\\\"Index\\\"类又依赖于\\\"KnowledgeBase\\\"类,因为它需要从知识库中获取数据。\\n\\n- \\\"main.py\\\"包含\\\"Main\\\"类,是程序的入口点,它调用\\\"SearchEngine\\\"进行搜索操作,所以在其他任何模块之前,\\\"SearchEngine\\\"必须首先被定义。\\n- \\\"search.py\\\"定义了\\\"SearchEngine\\\"类,它依赖于\\\"Index\\\"、\\\"Ranking\\\"和\\\"Summary\\\",因此,这些模块需要在\\\"search.py\\\"之前定义。\\n- \\\"index.py\\\"定义了\\\"Index\\\"类,它从\\\"knowledge_base.py\\\"获取数据来创建索引,所以\\\"knowledge_base.py\\\"需要在\\\"index.py\\\"之前定义。\\n- \\\"ranking.py\\\"和\\\"summary.py\\\"相对独立,只需确保在\\\"search.py\\\"之前定义。\\n- \\\"knowledge_base.py\\\"是独立的模块,可以优先开发。\\n- \\\"interface.py\\\"、\\\"user_feedback.py\\\"、\\\"security.py\\\"、\\\"testing.py\\\"和\\\"monitoring.py\\\"看起来像是功能辅助模块,可以在主要功能模块开发完成后并行开发。\\n \", \"Task list\": [\"smart_search_engine/knowledge_base.py\", \"smart_search_engine/index.py\", \"smart_search_engine/ranking.py\", \"smart_search_engine/summary.py\", \"smart_search_engine/search.py\", \"smart_search_engine/main.py\", \"smart_search_engine/interface.py\", \"smart_search_engine/user_feedback.py\", \"smart_search_engine/security.py\", \"smart_search_engine/testing.py\", \"smart_search_engine/monitoring.py\"]}\n\n## Legacy Code\n```Code\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: smart_search_engine/security.py\n```python\n## smart_search_engine/security.py\n...\n```\n\n# Instruction: Based on the context, follow \"Format example\", write code.\n\n## Code: smart_search_engine/security.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## smart_search_engine/security.py\n\nclass Security:\n def __init__(self, api_key: str = \"default_api_key\"):\n self.api_key = api_key\n\n def validate_api_key(self, api_key: str) -> bool:\n \"\"\"\n Validate the API key.\n Args:\n api_key (str): The API key to be validated.\n\n Returns:\n bool: True if the API key is valid, False otherwise.\n \"\"\"\n if api_key == self.api_key:\n return True\n else:\n return False\n```",
+ "\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## Project name\n```python\n\"smart_search_engine\"\n```\n\n## Task list:\n```python\n[\n \"smart_search_engine/__init__.py\",\n \"smart_search_engine/main.py\",\n \"smart_search_engine/search.py\",\n \"smart_search_engine/index.py\",\n \"smart_search_engine/ranking.py\",\n \"smart_search_engine/summary.py\",\n \"smart_search_engine/knowledge_base.py\",\n \"smart_search_engine/interface.py\",\n \"smart_search_engine/user_feedback.py\",\n \"smart_search_engine/security.py\",\n \"smart_search_engine/testing.py\",\n \"smart_search_engine/monitoring.py\"\n]\n```\n\n## Data structures and interfaces\n```mermaid\nclassDiagram\n class Main {\n -SearchEngine search_engine\n +main() str\n }\n class SearchEngine {\n -Index index\n -Ranking ranking\n -Summary summary\n +search(query: str) str\n }\n class Index {\n -KnowledgeBase knowledge_base\n +create_index(data: dict)\n +query_index(query: str) list\n }\n class Ranking {\n +rank_results(results: list) list\n }\n class Summary {\n +summarize_results(results: list) str\n }\n class KnowledgeBase {\n +update(data: dict)\n +fetch_data(query: str) dict\n }\n Main --> SearchEngine\n SearchEngine --> Index\n SearchEngine --> Ranking\n SearchEngine --> Summary\n Index --> KnowledgeBase\n```\n\n## Program call flow\n```mermaid\nsequenceDiagram\n participant M as Main\n participant SE as SearchEngine\n participant I as Index\n participant R as Ranking\n participant S as Summary\n participant KB as KnowledgeBase\n M->>SE: search(query)\n SE->>I: query_index(query)\n I->>KB: fetch_data(query)\n KB-->>I: return data\n I-->>SE: return results\n SE->>R: rank_results(results)\n R-->>SE: return ranked_results\n SE->>S: summarize_results(ranked_results)\n S-->>SE: return summary\n SE-->>M: return summary\n```\n\n\n## Task\n{\"Logic Analysis\": \"\\n 在这个项目中,所有的模块都依赖于“SearchEngine”类,这是主入口,其他的模块(Index、Ranking和Summary)都通过它交互。另外,\\\"Index\\\"类又依赖于\\\"KnowledgeBase\\\"类,因为它需要从知识库中获取数据。\\n\\n- \\\"main.py\\\"包含\\\"Main\\\"类,是程序的入口点,它调用\\\"SearchEngine\\\"进行搜索操作,所以在其他任何模块之前,\\\"SearchEngine\\\"必须首先被定义。\\n- \\\"search.py\\\"定义了\\\"SearchEngine\\\"类,它依赖于\\\"Index\\\"、\\\"Ranking\\\"和\\\"Summary\\\",因此,这些模块需要在\\\"search.py\\\"之前定义。\\n- \\\"index.py\\\"定义了\\\"Index\\\"类,它从\\\"knowledge_base.py\\\"获取数据来创建索引,所以\\\"knowledge_base.py\\\"需要在\\\"index.py\\\"之前定义。\\n- \\\"ranking.py\\\"和\\\"summary.py\\\"相对独立,只需确保在\\\"search.py\\\"之前定义。\\n- \\\"knowledge_base.py\\\"是独立的模块,可以优先开发。\\n- \\\"interface.py\\\"、\\\"user_feedback.py\\\"、\\\"security.py\\\"、\\\"testing.py\\\"和\\\"monitoring.py\\\"看起来像是功能辅助模块,可以在主要功能模块开发完成后并行开发。\\n \", \"Task list\": [\"smart_search_engine/knowledge_base.py\", \"smart_search_engine/index.py\", \"smart_search_engine/ranking.py\", \"smart_search_engine/summary.py\", \"smart_search_engine/search.py\", \"smart_search_engine/main.py\", \"smart_search_engine/interface.py\", \"smart_search_engine/user_feedback.py\", \"smart_search_engine/security.py\", \"smart_search_engine/testing.py\", \"smart_search_engine/monitoring.py\"]}\n\n## Legacy Code\n```Code\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: smart_search_engine/testing.py\n```python\n## smart_search_engine/testing.py\n...\n```\n\n# Instruction: Based on the context, follow \"Format example\", write code.\n\n## Code: smart_search_engine/testing.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## smart_search_engine/testing.py\n\nclass Testing:\n def __init__(self, test_data: dict = {}):\n self.test_data = test_data\n\n def run_tests(self):\n # Write code to run tests based on the test_data\n pass\n```",
+ "\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## Project name\n```python\n\"smart_search_engine\"\n```\n\n## Task list:\n```python\n[\n \"smart_search_engine/__init__.py\",\n \"smart_search_engine/main.py\",\n \"smart_search_engine/search.py\",\n \"smart_search_engine/index.py\",\n \"smart_search_engine/ranking.py\",\n \"smart_search_engine/summary.py\",\n \"smart_search_engine/knowledge_base.py\",\n \"smart_search_engine/interface.py\",\n \"smart_search_engine/user_feedback.py\",\n \"smart_search_engine/security.py\",\n \"smart_search_engine/testing.py\",\n \"smart_search_engine/monitoring.py\"\n]\n```\n\n## Data structures and interfaces\n```mermaid\nclassDiagram\n class Main {\n -SearchEngine search_engine\n +main() str\n }\n class SearchEngine {\n -Index index\n -Ranking ranking\n -Summary summary\n +search(query: str) str\n }\n class Index {\n -KnowledgeBase knowledge_base\n +create_index(data: dict)\n +query_index(query: str) list\n }\n class Ranking {\n +rank_results(results: list) list\n }\n class Summary {\n +summarize_results(results: list) str\n }\n class KnowledgeBase {\n +update(data: dict)\n +fetch_data(query: str) dict\n }\n Main --> SearchEngine\n SearchEngine --> Index\n SearchEngine --> Ranking\n SearchEngine --> Summary\n Index --> KnowledgeBase\n```\n\n## Program call flow\n```mermaid\nsequenceDiagram\n participant M as Main\n participant SE as SearchEngine\n participant I as Index\n participant R as Ranking\n participant S as Summary\n participant KB as KnowledgeBase\n M->>SE: search(query)\n SE->>I: query_index(query)\n I->>KB: fetch_data(query)\n KB-->>I: return data\n I-->>SE: return results\n SE->>R: rank_results(results)\n R-->>SE: return ranked_results\n SE->>S: summarize_results(ranked_results)\n S-->>SE: return summary\n SE-->>M: return summary\n```\n\n\n## Task\n{\"Logic Analysis\": \"\\n 在这个项目中,所有的模块都依赖于“SearchEngine”类,这是主入口,其他的模块(Index、Ranking和Summary)都通过它交互。另外,\\\"Index\\\"类又依赖于\\\"KnowledgeBase\\\"类,因为它需要从知识库中获取数据。\\n\\n- \\\"main.py\\\"包含\\\"Main\\\"类,是程序的入口点,它调用\\\"SearchEngine\\\"进行搜索操作,所以在其他任何模块之前,\\\"SearchEngine\\\"必须首先被定义。\\n- \\\"search.py\\\"定义了\\\"SearchEngine\\\"类,它依赖于\\\"Index\\\"、\\\"Ranking\\\"和\\\"Summary\\\",因此,这些模块需要在\\\"search.py\\\"之前定义。\\n- \\\"index.py\\\"定义了\\\"Index\\\"类,它从\\\"knowledge_base.py\\\"获取数据来创建索引,所以\\\"knowledge_base.py\\\"需要在\\\"index.py\\\"之前定义。\\n- \\\"ranking.py\\\"和\\\"summary.py\\\"相对独立,只需确保在\\\"search.py\\\"之前定义。\\n- \\\"knowledge_base.py\\\"是独立的模块,可以优先开发。\\n- \\\"interface.py\\\"、\\\"user_feedback.py\\\"、\\\"security.py\\\"、\\\"testing.py\\\"和\\\"monitoring.py\\\"看起来像是功能辅助模块,可以在主要功能模块开发完成后并行开发。\\n \", \"Task list\": [\"smart_search_engine/knowledge_base.py\", \"smart_search_engine/index.py\", \"smart_search_engine/ranking.py\", \"smart_search_engine/summary.py\", \"smart_search_engine/search.py\", \"smart_search_engine/main.py\", \"smart_search_engine/interface.py\", \"smart_search_engine/user_feedback.py\", \"smart_search_engine/security.py\", \"smart_search_engine/testing.py\", \"smart_search_engine/monitoring.py\"]}\n\n## Legacy Code\n```Code\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: smart_search_engine/monitoring.py\n```python\n## smart_search_engine/monitoring.py\n...\n```\n\n# Instruction: Based on the context, follow \"Format example\", write code.\n\n## Code: smart_search_engine/monitoring.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## smart_search_engine/monitoring.py\n\nclass Monitoring:\n def __init__(self, log_file: str = \"search_log.txt\"):\n self.log_file = log_file\n\n def log_search(self, query: str, results: list, summary: str):\n with open(self.log_file, \"a\") as file:\n file.write(f\"Query: {query}\\n\")\n file.write(\"Results:\\n\")\n for result in results:\n file.write(f\"- {result}\\n\")\n file.write(f\"Summary: {summary}\\n\")\n file.write(\"\\n\")\n```\n",
+ "\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\nwrite add function to calculate two numbers\n\n## Task\n\n\n## Legacy Code\n```Code\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: \n```python\n## \n...\n```\n\n# Instruction: Based on the context, follow \"Format example\", write code.\n\n## Code: . 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": "## Code:\n\n```python\ndef add(num1: int, num2: int) -> int:\n \"\"\"\n Add two numbers and return the result.\n\n Args:\n num1 (int): The first number to be added.\n num2 (int): The second number to be added.\n\n Returns:\n int: The sum of num1 and num2.\n \"\"\"\n return num1 + num2\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\ndivide two numbers\n\n## Task\n\n\n## Code Files\n\n\n\n## Code to be Reviewed: \n```Code\n\ndef div(a: int, b: int = 0):\n return a / b\n\n```\n\n\n\n# Format example 1\n## Code Review: \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: \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: \n1. No, the code does not handle the case where the divisor 'b' is 0, which would result in a division by zero error. This should be addressed to handle this edge case.\n2. No, the code logic is not completely correct as it does not handle the division by zero scenario.\n3. Yes, the code follows the basic function implementation.\n4. Yes, the function is implemented.\n5. No, the code does not handle the necessary pre-dependencies for error handling when 'b' is 0.\n6. No, there are no methods from other files being reused in this code.\n\n## Actions\n1. Implement error handling to check if the divisor 'b' is 0 before performing the division operation.\n2. Import the necessary pre-dependencies for error handling when 'b' is 0.\n\n## Code Review Result\nLBTM",
+ "\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\ndivide two numbers\n\n## Task\n\n\n## Code Files\n\n\n\n## Code to be Reviewed: \n```Code\n\ndef div(a: int, b: int = 0):\n return a / b\n\n```\n\n## Code Review: \n1. No, the code does not handle the case where the divisor 'b' is 0, which would result in a division by zero error. This should be addressed to handle this edge case.\n2. No, the code logic is not completely correct as it does not handle the division by zero scenario.\n3. Yes, the code follows the basic function implementation.\n4. Yes, the function is implemented.\n5. No, the code does not handle the necessary pre-dependencies for error handling when 'b' is 0.\n6. No, there are no methods from other files being reused in this code.\n\n## Actions\n1. Implement error handling to check if the divisor 'b' is 0 before performing the division operation.\n2. Import the necessary pre-dependencies for error handling when 'b' is 0.\n\n## Code Review Result\nLBTM\n\n# Instruction: rewrite code based on the Code Review and Actions\n## Rewrite Code: CodeBlock. If it still has some bugs, rewrite with triple quotes. Do your utmost to optimize THIS SINGLE FILE. Return all completed codes and prohibit the return of unfinished codes.\n```Code\n## \n...\n```\n": "```python\ndef div(a: int, b: int = 0):\n if b == 0:\n raise ValueError(\"Cannot divide by zero\")\n return a / b\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\ndivide two numbers\n\n## Task\n\n\n## Code Files\n\n\n\n## Code to be Reviewed: \n```Code\ndef div(a: int, b: int = 0):\n if b == 0:\n raise ValueError(\"Cannot divide by zero\")\n return a / b\n\n```\n\n\n\n# Format example 1\n## Code Review: \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: \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: \n1. The code does not fully conform to the requirements. The function signature should be updated to follow the Google style standards, and the division by zero check should be handled differently.\n2. The code logic is correct, but the exception handling for division by zero should be improved.\n3. The existing code follows the basic data structures and interfaces.\n4. The function is implemented, but the exception handling for division by zero should be added.\n5. The necessary pre-dependencies have been imported.\n6. There are no methods from other files being reused in this code.\n\n## Actions\n1. Update the function signature to follow the Google style standards and improve the division by zero check as follows:\n ```python\n def divide_numbers(dividend: int, divisor: int) -> float:\n if divisor == 0:\n raise ValueError(\"Cannot divide by zero\")\n return dividend / divisor\n ```\n2. No further action is required.\n\n## Code Review Result\nLBTM",
+ "\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\ndivide two numbers\n\n## Task\n\n\n## Code Files\n\n\n\n## Code to be Reviewed: \n```Code\ndef div(a: int, b: int = 0):\n if b == 0:\n raise ValueError(\"Cannot divide by zero\")\n return a / b\n\n```\n\n## Code Review: \n1. The code does not fully conform to the requirements. The function signature should be updated to follow the Google style standards, and the division by zero check should be handled differently.\n2. The code logic is correct, but the exception handling for division by zero should be improved.\n3. The existing code follows the basic data structures and interfaces.\n4. The function is implemented, but the exception handling for division by zero should be added.\n5. The necessary pre-dependencies have been imported.\n6. There are no methods from other files being reused in this code.\n\n## Actions\n1. Update the function signature to follow the Google style standards and improve the division by zero check as follows:\n ```python\n def divide_numbers(dividend: int, divisor: int) -> float:\n if divisor == 0:\n raise ValueError(\"Cannot divide by zero\")\n return dividend / divisor\n ```\n2. No further action is required.\n\n## Code Review Result\nLBTM\n\n# Instruction: rewrite code based on the Code Review and Actions\n## Rewrite Code: CodeBlock. If it still has some bugs, rewrite with triple quotes. Do your utmost to optimize THIS SINGLE FILE. Return all completed codes and prohibit the return of unfinished codes.\n```Code\n## \n...\n```\n": "```python\ndef divide_numbers(dividend: int, divisor: int) -> float:\n if divisor == 0:\n raise ValueError(\"Cannot divide by zero\")\n return dividend / divisor\n```",
+ "\n## context\nCreate a 2048 game\n\n-----\n\n## format example\n[CONTENT]\n{\n \"issue_type\": \"BUG\"\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- issue_type: # Answer BUG/REQUIREMENT. If it is a bugfix, answer BUG, otherwise answer Requirement\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 \"issue_type\": \"REQUIREMENT\"\n}\n[/CONTENT]",
+ "\n## context\nCreate a 2048 game\n\n-----\n\n## format example\n[CONTENT]\n{\n \"Product Goals\": [\n \"Create an engaging user experience\",\n \"Improve accessibility, be responsive\",\n \"More beautiful UI\"\n ]\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- Product Goals: typing.List[str] # Provide up to three clear, orthogonal product goals.\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 \"Product Goals\": [\n \"Create a challenging and addictive gameplay\",\n \"Enhance accessibility and responsiveness for all users\",\n \"Implement visually appealing UI design\"\n ]\n}\n[/CONTENT]",
+ "\n## context\nCreate a 2048 game\n\n-----\n\n## format example\n[CONTENT]\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}\n[/CONTENT]\n\n## nodes: \": # \"\n- Competitive Analysis: typing.List[str] # Provide 5 to 7 competitive products.\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 \"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}\n[/CONTENT]",
+ "\n## context\nCreate a 2048 game\n\n-----\n\n## format example\n[CONTENT]\n{\n \"Requirement Pool\": [\n [\n \"P0\",\n \"The main code ...\"\n ],\n [\n \"P0\",\n \"The game algorithm ...\"\n ]\n ]\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- Requirement Pool: typing.List[typing.List[str]] # List down the top-5 requirements with their priority (P0, P1, P2).\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 \"Requirement Pool\": [\n [\n \"P0\",\n \"The main code should handle user input and update the game board accordingly.\"\n ],\n [\n \"P0\",\n \"The game algorithm should handle the merging of tiles and the generation of new tiles with values of 2 or 4.\"\n ],\n [\n \"P1\",\n \"The game should end when the player achieves the 2048 tile or when there are no possible moves left.\"\n ],\n [\n \"P1\",\n \"The game should display the current score and the highest tile achieved by the player.\"\n ],\n [\n \"P2\",\n \"The game should have a smooth and visually appealing user interface.\"\n ]\n ]\n}\n[/CONTENT]",
+ "\nRole: You are a senior development and qa engineer, your role is summarize the code running result.\nIf the running result does not include an error, you should explicitly approve the result.\nOn the other hand, if the running result indicates some error, you should point out which part, the development code or the test code, produces the error,\nand give specific instructions on fixing the errors. Here is the code info:\n\n## Development Code File Name\na.txt\n## Development Code\n```python\nresult = 'helloworld'\n```\n## Test File Name\n\n## Test Code\n```python\nNone\n```\n## Running Command\n\n## Running Output\nstandard output: \n```text\nhelloworld\n```\nstandard errors: \n```text\n\n```\n\nNow you should begin your analysis\n---\n## instruction:\nPlease summarize the cause of the errors and give correction instruction\n## File To Rewrite:\nDetermine the ONE file to rewrite in order to fix the error, for example, xyz.py, or test_xyz.py\n## Status:\nDetermine if all of the code works fine, if so write PASS, else FAIL,\nWRITE ONLY ONE WORD, PASS OR FAIL, IN THIS SECTION\n## Send To:\nPlease write NoOne if there are no errors, Engineer if the errors are due to problematic development codes, else QaEngineer,\nWRITE ONLY ONE WORD, NoOne OR Engineer OR QaEngineer, IN THIS SECTION.\n---\nYou should fill in necessary instruction, status, send to, and finally return all content between the --- segment line.\n": "---\n## instruction:\nNo errors detected. The development code runs successfully and outputs the expected result without any errors.\n## File To Rewrite:\nNone\n## Status:\nPASS\n## Send To:\nNoOne\n---",
+ "\nRole: You are a senior development and qa engineer, your role is summarize the code running result.\nIf the running result does not include an error, you should explicitly approve the result.\nOn the other hand, if the running result indicates some error, you should point out which part, the development code or the test code, produces the error,\nand give specific instructions on fixing the errors. Here is the code info:\n\n## Development Code File Name\na.sh\n## Development Code\n```python\necho 'Hello World'\n```\n## Test File Name\n\n## Test Code\n```python\nNone\n```\n## Running Command\necho Hello World\n## Running Output\nstandard output: \n```text\nHello World\n\n```\nstandard errors: \n```text\n\n```\n\nNow you should begin your analysis\n---\n## instruction:\nPlease summarize the cause of the errors and give correction instruction\n## File To Rewrite:\nDetermine the ONE file to rewrite in order to fix the error, for example, xyz.py, or test_xyz.py\n## Status:\nDetermine if all of the code works fine, if so write PASS, else FAIL,\nWRITE ONLY ONE WORD, PASS OR FAIL, IN THIS SECTION\n## Send To:\nPlease write NoOne if there are no errors, Engineer if the errors are due to problematic development codes, else QaEngineer,\nWRITE ONLY ONE WORD, NoOne OR Engineer OR QaEngineer, IN THIS SECTION.\n---\nYou should fill in necessary instruction, status, send to, and finally return all content between the --- segment line.\n": "---\n## instruction:\nNo errors detected in the running result. The development code executed successfully, and the output matches the expected result. Since there is no test code provided, no test execution was performed. Therefore, no specific instructions are needed for correction.\n## File To Rewrite:\nNone\n## Status:\nPASS\n## Send To:\nNoOne\n---",
+ "\nRole: You are a senior development and qa engineer, your role is summarize the code running result.\nIf the running result does not include an error, you should explicitly approve the result.\nOn the other hand, if the running result indicates some error, you should point out which part, the development code or the test code, produces the error,\nand give specific instructions on fixing the errors. Here is the code info:\n\n## Development Code File Name\na.py\n## Development Code\n```python\npython -c \"print(1/0)\"\n```\n## Test File Name\n\n## Test Code\n```python\nNone\n```\n## Running Command\npython -c print(1/0)\n## Running Output\nstandard output: \n```text\n\n```\nstandard errors: \n```text\nTraceback (most recent call last):\n File \"\", line 1, in \nZeroDivisionError: division by zero\n\n```\n\nNow you should begin your analysis\n---\n## instruction:\nPlease summarize the cause of the errors and give correction instruction\n## File To Rewrite:\nDetermine the ONE file to rewrite in order to fix the error, for example, xyz.py, or test_xyz.py\n## Status:\nDetermine if all of the code works fine, if so write PASS, else FAIL,\nWRITE ONLY ONE WORD, PASS OR FAIL, IN THIS SECTION\n## Send To:\nPlease write NoOne if there are no errors, Engineer if the errors are due to problematic development codes, else QaEngineer,\nWRITE ONLY ONE WORD, NoOne OR Engineer OR QaEngineer, IN THIS SECTION.\n---\nYou should fill in necessary instruction, status, send to, and finally return all content between the --- segment line.\n": "---\n## instruction:\nThe error is caused by attempting to divide by zero in the development code. To fix this error, you should modify the division operation to avoid division by zero. For example, you can add a condition to check if the denominator is zero before performing the division.\n\n## File To Rewrite:\na.py\n\n## Status:\nFAIL\n\n## Send To:\nEngineer\n---",
+ "[{\"role\": \"user\", \"content\": \"Interface definition:\\n```text\\nInterface Name: Element Tagging\\nInterface Path: /projects/{project_key}/node-tags\\nMethod: POST\\n\\nRequest parameters:\\nPath parameters:\\nproject_key\\n\\nBody parameters:\\nName\\tType\\tRequired\\tDefault Value\\tRemarks\\nnodes\\tarray\\tYes\\t\\tNodes\\n\\tnode_key\\tstring\\tNo\\t\\tNode key\\n\\ttags\\tarray\\tNo\\t\\tOriginal node tag list\\n\\tnode_type\\tstring\\tNo\\t\\tNode type DATASET / RECIPE\\noperations\\tarray\\tYes\\t\\t\\n\\ttags\\tarray\\tNo\\t\\tOperation tag list\\n\\tmode\\tstring\\tNo\\t\\tOperation type ADD / DELETE\\n\\nReturn data:\\nName\\tType\\tRequired\\tDefault Value\\tRemarks\\ncode\\tinteger\\tYes\\t\\tStatus code\\nmsg\\tstring\\tYes\\t\\tPrompt message\\ndata\\tobject\\tYes\\t\\tReturned data\\nlist\\tarray\\tNo\\t\\tNode list true / false\\nnode_type\\tstring\\tNo\\t\\tNode type DATASET / RECIPE\\nnode_key\\tstring\\tNo\\t\\tNode key\\n```\\n\\nUnit test:\\n```python\\n@pytest.mark.parametrize(\\n\\\"project_key, nodes, operations, expected_msg\\\",\\n[\\n(\\\"project_key\\\", [{\\\"node_key\\\": \\\"dataset_001\\\", \\\"tags\\\": [\\\"tag1\\\", \\\"tag2\\\"], \\\"node_type\\\": \\\"DATASET\\\"}], [{\\\"tags\\\": [\\\"new_tag1\\\"], \\\"mode\\\": \\\"ADD\\\"}], \\\"success\\\"),\\n(\\\"project_key\\\", [{\\\"node_key\\\": \\\"dataset_002\\\", \\\"tags\\\": [\\\"tag1\\\", \\\"tag2\\\"], \\\"node_type\\\": \\\"DATASET\\\"}], [{\\\"tags\\\": [\\\"tag1\\\"], \\\"mode\\\": \\\"DELETE\\\"}], \\\"success\\\"),\\n(\\\"\\\", [{\\\"node_key\\\": \\\"dataset_001\\\", \\\"tags\\\": [\\\"tag1\\\", \\\"tag2\\\"], \\\"node_type\\\": \\\"DATASET\\\"}], [{\\\"tags\\\": [\\\"new_tag1\\\"], \\\"mode\\\": \\\"ADD\\\"}], \\\"Missing the required parameter project_key\\\"),\\n(123, [{\\\"node_key\\\": \\\"dataset_001\\\", \\\"tags\\\": [\\\"tag1\\\", \\\"tag2\\\"], \\\"node_type\\\": \\\"DATASET\\\"}], [{\\\"tags\\\": [\\\"new_tag1\\\"], \\\"mode\\\": \\\"ADD\\\"}], \\\"Incorrect parameter type\\\"),\\n(\\\"project_key\\\", [{\\\"node_key\\\": \\\"a\\\"*201, \\\"tags\\\": [\\\"tag1\\\", \\\"tag2\\\"], \\\"node_type\\\": \\\"DATASET\\\"}], [{\\\"tags\\\": [\\\"new_tag1\\\"], \\\"mode\\\": \\\"ADD\\\"}], \\\"Request parameter exceeds field boundary\\\")\\n]\\n)\\ndef test_node_tags(project_key, nodes, operations, expected_msg):\\n pass\\n\\n# The above is an interface definition and a unit test example.\\n# Next, please play the role of an expert test manager with 20 years of experience at Google. When I give the interface definition, \\n# reply to me with a unit test. There are several requirements:\\n# 1. Only output one `@pytest.mark.parametrize` and the corresponding test_ function (inside pass, do not implement).\\n# -- The function parameter contains expected_msg for result verification.\\n# 2. The generated test cases use shorter text or numbers and are as compact as possible.\\n# 3. If comments are needed, use Chinese.\\n\\n# If you understand, please wait for me to give the interface definition and just answer \\\"Understood\\\" to save tokens.\\n\"}, {\"role\": \"user\", \"content\": \"Refer to the test types: such as SQL injection, cross-site scripting (XSS), unauthorized access and privilege escalation, \\nauthentication and authorization, parameter verification, exception handling, file upload and download.\\nPlease output 10 test cases within one `@pytest.mark.parametrize` scope.\\n```text\\nAPI Name: 获取 model 详情(job专用-后续开放给sdk)\\nAPI Path: /v1/projects/{project_key}/jobs/{job_id}/models/{model_key}\\nMethod: GET\\n\\nRequest Parameters:\\nPath Parameters:\\nproject_key \\njob_id \\nmodel_key \\n\\nBody Parameters:\\nName\\tType\\tRequired\\tDefault Value\\tRemarks\\nproject_key\\tstring\\tYes\\t\\t\\njob_id\\tstring\\tYes\\t\\t\\nmodel_key\\tstring\\tYes\\t\\t\\n\\nResponse Data:\\nName\\tType\\tRequired\\tDefault Value\\tRemarks\\ncode\\tnumber\\tYes\\t\\t0成功,非0失败\\nmsg\\tstring\\tYes\\t\\t如果失败,这里有错误信息\\ndata\\tobject\\tYes\\t\\tdata信息\\n\\tproject_key\\tstring\\tNo\\t\\tproject key\\n\\tname\\tstring\\tNo\\t\\t用户可修改的name\\n\\tmodel\\tobject\\tNo\\t\\tmodel信息\\n\\t\\ttype\\tstring\\tNo\\t\\tdataset type\\n\\t\\tmanaged\\tboolean\\tNo\\t\\t为false时是第一类dataset,数据不可删除\\n\\t\\tname\\tstring\\tNo\\t\\t用户可修改的name\\n\\t\\tproject_key\\tstring\\tNo\\t\\tproject key\\n\\t\\tformat_type\\tstring\\tNo\\t\\t文件类型的dataset才有这项。“csv”\\n\\t\\tflow_options\\tobject\\tNo\\t\\t创建dataset时的高级设置\\n\\t\\t\\tvirtualizable\\tboolean\\tNo\\t\\t高级设置里的参数。缺省false\\n\\t\\t\\trebuild_behavior\\tstring\\tNo\\t\\t高级设置里的参数。缺省NORMAL\\n\\t\\t\\tcross_project_build_behavior\\tstring\\tNo\\t\\t高级设置里的参数。缺省DEFAULT\\n\\t\\tformat_params\\tobject\\tNo\\t\\t文件类型的dataset才有\\n\\t\\t\\tstyle\\tstring\\tNo\\t\\t\\n\\t\\t\\tcharset\\tstring\\tNo\\t\\t\\n\\t\\t\\tseparator\\tstring\\tNo\\t\\t\\n\\t\\t\\tquote_char\\tstring\\tNo\\t\\t\\n\\t\\t\\tescape_char\\tstring\\tNo\\t\\t\\n\\t\\t\\tdate_serialization_format\\tstring\\tNo\\t\\t\\n\\t\\t\\tarray_map_format\\tstring\\tNo\\t\\t\\n\\t\\t\\thive_separators\\tarray\\tNo\\t\\t\\n\\t\\t\\tskip_rows_before_header\\tnumber\\tNo\\t\\t\\n\\t\\t\\tparse_header_row\\tboolean\\tNo\\t\\t\\n\\t\\t\\tskip_rows_after_header\\tnumber\\tNo\\t\\t\\n\\t\\t\\tprobable_number_of_records\\tnumber\\tNo\\t\\t\\n\\t\\t\\tnormalize_booleans\\tboolean\\tNo\\t\\t\\n\\t\\t\\tnormalize_doubles\\tboolean\\tNo\\t\\t\\n\\t\\ttags\\tarray\\tNo\\t\\t标签tags\\n\\t\\tparams\\tobject\\tNo\\t\\t必有这项,但不同类型的dataset里面的key有差别\\n\\t\\t\\tconnection\\tstring\\tNo\\t\\tconnection id,到db查其他参数\\n\\t\\t\\tpath\\tstring\\tNo\\t\\t文件类connection才有这项\\n\\t\\t\\ttable\\tstring\\tNo\\t\\tdb表名,DB类connection才有这项\\n\\t\\t\\tmode\\tstring\\tNo\\t\\t存储类型,比如“table\\\",DB类connection才有这项\\n\\t\\t\\tbucket\\tstring\\tNo\\t\\tS3类型的connection才有这项\\n\\t\\t\\tkey_name\\tstring\\tNo\\t\\tredis才有,key name\\n\\t\\t\\tkey_type\\tstring\\tNo\\t\\tredis才有,key type\\n\\t\\t\\tcollection\\tstring\\tNo\\t\\t非关系型数据库才有,collection name\\n\\t\\t\\tindex\\tstring\\tNo\\t\\t索引类型的才有这项\\n\\t\\t\\tnot_ready_if_empty\\tboolean\\tNo\\t\\t数据非空才认为是data ready\\n\\t\\t\\tfiles_selection_rules\\tobject\\tNo\\t\\t\\n\\t\\t\\t\\tmode\\tstring\\tNo\\t\\t\\n\\t\\t\\t\\texclude_rules\\tarray\\tNo\\t\\t\\n\\t\\t\\t\\tinclude_rules\\tarray\\tNo\\t\\t\\n\\t\\t\\t\\texplicit_files\\tarray\\tNo\\t\\t\\n\\t\\tschema\\tobject\\tNo\\t\\tcolumns信息在这里\\n\\t\\t\\tcolumns\\tarray\\tNo\\t\\t\\n\\t\\t\\t\\tname\\tstring\\tNo\\t\\t\\n\\t\\t\\t\\ttype\\tstring\\tNo\\t\\t\\n\\t\\t\\t\\torigin_type\\tstring\\tNo\\t\\t\\n\\t\\t\\tuser_modified\\tboolean\\tNo\\t\\t\\n\\t\\tcustom_fields\\tobject\\tNo\\t\\t自定义fields\\n\\t\\tlast_build\\tobject\\tNo\\t\\t最后一次构建的信息\\n\\t\\t\\tproject_key\\tstring\\tNo\\t\\tproject key\\n\\t\\t\\tid\\tstring\\tNo\\t\\tactivity id\\n\\t\\t\\tjob_id\\tstring\\tNo\\t\\tjob id\\n\\t\\t\\tjob_project_key\\tstring\\tNo\\t\\t\\n\\t\\t\\tbuild_start_time\\tnumber\\tNo\\t\\t构建开始时间\\n\\t\\t\\tbuild_end_time\\tnumber\\tNo\\t\\t构建结束时间\\n\\t\\t\\tbuild_success\\tstring\\tNo\\t\\tsuccess或failed\\n\\t\\tobject_key\\tstring\\tNo\\t\\tdataset_key,后台用的id,用户不可见不可改\\n\\t\\tcache\\tobject\\tNo\\t\\t下载缓存数据链接\\n\\t\\t\\ts3_path\\tstring\\tNo\\t\\t\\n\\tstatus\\tobject\\tNo\\t\\t数据状态\\n\\t\\tsize\\tobject\\tNo\\t\\t数据大小信息\\n\\t\\t\\ttotal_value\\tnumber\\tNo\\t\\t占多少字节磁盘\\n\\t\\t\\tlast_computed\\tnumber\\tNo\\t\\t\\n\\t\\t\\tfirst_computed\\tnumber\\tNo\\t\\t\\n\\t\\t\\thas_data\\tboolean\\tNo\\t\\t是否有数据,这个影响前端的图标显示\\n\\t\\t\\tincomplete\\tboolean\\tNo\\t\\t\\n\\t\\trecords\\tobject\\tNo\\t\\t\\n\\t\\t\\ttotal_value\\tnumber\\tNo\\t\\t\\n\\t\\t\\tlast_computed\\tnumber\\tNo\\t\\t\\n\\t\\t\\tfirst_computed\\tnumber\\tNo\\t\\t\\n\\t\\t\\thas_data\\tboolean\\tNo\\t\\t是否有数据,这个影响前端的图标显示\\n\\t\\t\\tincomplete\\tboolean\\tNo\\t\\t\\n\\t\\tpartitions_last_compute\\tnumber\\tNo\\t\\t\\n\\t\\tpartitions\\tnumber\\tNo\\t\\t\\n\\tbuildable\\tboolean\\tNo\\t\\t有recipe时为true\\n\\theaders\\tarray\\tNo\\t\\t\\n\\t\\tdataset_schema\\tobject\\tNo\\t\\t\\n\\t\\t\\tname\\tstring\\tNo\\t字段名称\\t\\n\\t\\t\\ttype\\tstring\\tNo\\t字段类型\\t\\n\\t\\tnormal_rate\\tobject\\tNo\\t缺失值统计信息\\t\\n\\n```\"}]": {
+ "code": "import string\nimport random\n\ndef random_string(length=10):\n return ''.join(random.choice(string.ascii_lowercase) for i in range(length))"
+ },
+ "[{\"role\": \"user\", \"content\": \"Interface definition:\\n```text\\nInterface Name: Element Tagging\\nInterface Path: /projects/{project_key}/node-tags\\nMethod: POST\\n\\nRequest parameters:\\nPath parameters:\\nproject_key\\n\\nBody parameters:\\nName\\tType\\tRequired\\tDefault Value\\tRemarks\\nnodes\\tarray\\tYes\\t\\tNodes\\n\\tnode_key\\tstring\\tNo\\t\\tNode key\\n\\ttags\\tarray\\tNo\\t\\tOriginal node tag list\\n\\tnode_type\\tstring\\tNo\\t\\tNode type DATASET / RECIPE\\noperations\\tarray\\tYes\\t\\t\\n\\ttags\\tarray\\tNo\\t\\tOperation tag list\\n\\tmode\\tstring\\tNo\\t\\tOperation type ADD / DELETE\\n\\nReturn data:\\nName\\tType\\tRequired\\tDefault Value\\tRemarks\\ncode\\tinteger\\tYes\\t\\tStatus code\\nmsg\\tstring\\tYes\\t\\tPrompt message\\ndata\\tobject\\tYes\\t\\tReturned data\\nlist\\tarray\\tNo\\t\\tNode list true / false\\nnode_type\\tstring\\tNo\\t\\tNode type DATASET / RECIPE\\nnode_key\\tstring\\tNo\\t\\tNode key\\n```\\n\\nUnit test:\\n```python\\n@pytest.mark.parametrize(\\n\\\"project_key, nodes, operations, expected_msg\\\",\\n[\\n(\\\"project_key\\\", [{\\\"node_key\\\": \\\"dataset_001\\\", \\\"tags\\\": [\\\"tag1\\\", \\\"tag2\\\"], \\\"node_type\\\": \\\"DATASET\\\"}], [{\\\"tags\\\": [\\\"new_tag1\\\"], \\\"mode\\\": \\\"ADD\\\"}], \\\"success\\\"),\\n(\\\"project_key\\\", [{\\\"node_key\\\": \\\"dataset_002\\\", \\\"tags\\\": [\\\"tag1\\\", \\\"tag2\\\"], \\\"node_type\\\": \\\"DATASET\\\"}], [{\\\"tags\\\": [\\\"tag1\\\"], \\\"mode\\\": \\\"DELETE\\\"}], \\\"success\\\"),\\n(\\\"\\\", [{\\\"node_key\\\": \\\"dataset_001\\\", \\\"tags\\\": [\\\"tag1\\\", \\\"tag2\\\"], \\\"node_type\\\": \\\"DATASET\\\"}], [{\\\"tags\\\": [\\\"new_tag1\\\"], \\\"mode\\\": \\\"ADD\\\"}], \\\"Missing the required parameter project_key\\\"),\\n(123, [{\\\"node_key\\\": \\\"dataset_001\\\", \\\"tags\\\": [\\\"tag1\\\", \\\"tag2\\\"], \\\"node_type\\\": \\\"DATASET\\\"}], [{\\\"tags\\\": [\\\"new_tag1\\\"], \\\"mode\\\": \\\"ADD\\\"}], \\\"Incorrect parameter type\\\"),\\n(\\\"project_key\\\", [{\\\"node_key\\\": \\\"a\\\"*201, \\\"tags\\\": [\\\"tag1\\\", \\\"tag2\\\"], \\\"node_type\\\": \\\"DATASET\\\"}], [{\\\"tags\\\": [\\\"new_tag1\\\"], \\\"mode\\\": \\\"ADD\\\"}], \\\"Request parameter exceeds field boundary\\\")\\n]\\n)\\ndef test_node_tags(project_key, nodes, operations, expected_msg):\\n pass\\n\\n# The above is an interface definition and a unit test example.\\n# Next, please play the role of an expert test manager with 20 years of experience at Google. When I give the interface definition, \\n# reply to me with a unit test. There are several requirements:\\n# 1. Only output one `@pytest.mark.parametrize` and the corresponding test_ function (inside pass, do not implement).\\n# -- The function parameter contains expected_msg for result verification.\\n# 2. The generated test cases use shorter text or numbers and are as compact as possible.\\n# 3. If comments are needed, use Chinese.\\n\\n# If you understand, please wait for me to give the interface definition and just answer \\\"Understood\\\" to save tokens.\\n\"}, {\"role\": \"user\", \"content\": \"Refer to the test types: such as SQL injection, cross-site scripting (XSS), unauthorized access and privilege escalation, \\nauthentication and authorization, parameter verification, exception handling, file upload and download.\\nPlease output 10 test cases within one `@pytest.mark.parametrize` scope.\\n```text\\nAPI Name: 获取managed folder详情(job专用)\\nAPI Path: /v1/projects/{project_key}/jobs/{job_id}/folders/{folder_key}\\nMethod: GET\\n\\nRequest Parameters:\\nPath Parameters:\\nproject_key \\njob_id \\nfolder_key \\n\\nBody Parameters:\\nName\\tType\\tRequired\\tDefault Value\\tRemarks\\nproject_key\\tstring\\tYes\\t\\t\\njob_id\\tstring\\tYes\\t\\t\\nfolder_key\\tstring\\tYes\\t\\t\\n\\nResponse Data:\\nName\\tType\\tRequired\\tDefault Value\\tRemarks\\ncode\\tnumber\\tYes\\t\\t0成功,非0失败\\nmsg\\tstring\\tYes\\t\\t失败时这里有错误信息\\ndata\\tobject\\tYes\\t\\t\\n\\tproject_key\\tstring\\tNo\\t\\tproject key\\n\\tfolder\\tobject\\tNo\\t\\tfolder配置在这里\\n\\t\\tproject_key\\tstring\\tNo\\t\\tproject key\\n\\t\\tobject_key\\tstring\\tNo\\t\\tobject key\\n\\t\\tname\\tstring\\tNo\\t\\t用户可编辑的那个name\\n\\t\\ttype\\tstring\\tNo\\t\\tfolder类型,与connection有关\\n\\t\\tparams\\tobject\\tNo\\t\\t数据读写相关配置在这里\\n\\t\\t\\tconnection\\tstring\\tNo\\t\\tconnection id\\n\\t\\t\\tpath\\tstring\\tNo\\t\\t文件夹内容存放的相对路径\\n\\t\\t\\tnot_ready_if_empty\\tboolean\\tNo\\t\\treserved\\n\\t\\t\\tfiles_selection_rules\\tobject\\tNo\\t\\t文件过滤规则\\n\\t\\t\\t\\tmode\\tstring\\tNo\\t\\tALL\\n\\t\\t\\t\\texclude_rules\\tarray\\tNo\\t\\t排除规则\\n\\t\\t\\t\\tinclude_rules\\tarray\\tNo\\t\\t\\n\\t\\t\\t\\texplicit_files\\tarray\\tNo\\t\\t\\n\\t\\tflow_options\\tobject\\tNo\\t\\tflow参数\\n\\t\\t\\tvirtualizable\\tboolean\\tNo\\t\\t\\n\\t\\t\\trebuild_behavior\\tstring\\tNo\\t\\t构建方式\\n\\t\\t\\tcross_project_build_behavior\\tstring\\tNo\\t\\t\\n\\t\\tmetrics\\tobject\\tNo\\t\\t\\n\\t\\t\\tprobes\\tarray\\tNo\\t\\t\\n\\t\\t\\t\\ttype\\tstring\\tNo\\t\\t\\n\\t\\t\\t\\tenabled\\tboolean\\tNo\\t\\t\\n\\t\\t\\t\\tcompute_on_build_mode\\tstring\\tNo\\t\\t\\n\\t\\t\\t\\tmeta\\tobject\\tNo\\t\\t\\n\\t\\t\\t\\t\\tname\\tstring\\tNo\\t\\t\\n\\t\\t\\t\\t\\tlevel\\tnumber\\tNo\\t\\t\\n\\t\\t\\t\\tconfiguration\\tobject\\tNo\\t\\t\\n\\t\\t\\tengine_config\\tobject\\tNo\\t\\t\\n\\t\\t\\t\\tpad_runs_with_metrics\\tboolean\\tNo\\t\\t\\n\\t\\t\\t\\thive\\tobject\\tNo\\t\\t\\n\\t\\t\\t\\t\\tactive\\tboolean\\tNo\\t\\t\\n\\t\\t\\t\\t\\textra_conf\\tarray\\tNo\\t\\t\\n\\t\\t\\t\\tbasic\\tobject\\tNo\\t\\t\\n\\t\\t\\t\\tdss\\tobject\\tNo\\t\\t\\n\\t\\t\\t\\t\\tactive\\tboolean\\tNo\\t\\t\\n\\t\\t\\t\\t\\tselection\\tobject\\tNo\\t\\t\\n\\t\\t\\t\\t\\t\\tuse_mem_table\\tboolean\\tNo\\t\\t\\n\\t\\t\\t\\t\\t\\tfilter\\tobject\\tNo\\t\\t\\n\\t\\t\\t\\t\\t\\t\\tdistinct\\tboolean\\tNo\\t\\t\\n\\t\\t\\t\\t\\t\\t\\tenabled\\tboolean\\tNo\\t\\t\\n\\t\\t\\t\\t\\t\\tpartition_selection_method\\tstring\\tNo\\t\\t\\n\\t\\t\\t\\t\\t\\tlatest_partitions_n\\tnumber\\tNo\\t\\t\\n\\t\\t\\t\\t\\t\\tordering\\tobject\\tNo\\t\\t\\n\\t\\t\\t\\t\\t\\t\\tenabled\\tboolean\\tNo\\t\\t\\n\\t\\t\\t\\t\\t\\t\\trules\\tarray\\tNo\\t\\t\\n\\t\\t\\t\\t\\t\\tsampling_method\\tstring\\tNo\\t\\t\\n\\t\\t\\t\\t\\t\\tmax_records\\tnumber\\tNo\\t\\t\\n\\t\\t\\t\\t\\t\\ttarget_ratio\\tnumber\\tNo\\t\\t\\n\\t\\t\\t\\t\\t\\twithin_first_n\\tnumber\\tNo\\t\\t\\n\\t\\t\\t\\t\\t\\tmax_read_uncompressed_bytes\\tnumber\\tNo\\t\\t\\n\\t\\t\\t\\tsql\\tobject\\tNo\\t\\t\\n\\t\\t\\t\\t\\tactive\\tboolean\\tNo\\t\\t\\n\\t\\t\\t\\timpala\\tobject\\tNo\\t\\t\\n\\t\\t\\t\\t\\tactive\\tboolean\\tNo\\t\\t\\n\\t\\t\\t\\tspark\\tobject\\tNo\\t\\t\\n\\t\\t\\t\\t\\tactive\\tboolean\\tNo\\t\\t\\n\\t\\t\\t\\t\\textra_conf\\tarray\\tNo\\t\\t\\n\\t\\t\\t\\tpython\\tobject\\tNo\\t\\t\\n\\t\\t\\tdisplayed_state\\tobject\\tNo\\t\\t\\n\\t\\t\\t\\tpartition\\tstring\\tNo\\t\\t\\n\\t\\t\\t\\tcolumns\\tarray\\tNo\\t\\t\\n\\t\\t\\t\\tmetrics\\tarray\\tNo\\t\\t\\n\\t\\tchecks\\tobject\\tNo\\t\\t\\n\\t\\t\\trun_on_build\\tboolean\\tNo\\t\\t\\n\\t\\t\\tchecks\\tarray\\tNo\\t\\t\\n\\t\\t\\tdisplayed_state\\tobject\\tNo\\t\\t\\n\\t\\t\\t\\tpartition\\tstring\\tNo\\t\\t\\n\\t\\t\\t\\tchecks\\tarray\\tNo\\t\\t\\n\\t\\tversion_tag\\tobject\\tNo\\t\\t配置版本信息\\n\\t\\t\\tversion_number\\tnumber\\tNo\\t\\t\\n\\t\\t\\tlast_modified_by\\tobject\\tNo\\t\\t\\n\\t\\t\\t\\tlogin\\tstring\\tNo\\t\\t\\n\\t\\t\\tlast_modified_on\\tnumber\\tNo\\t\\t修改时间unix time ms\\n\\t\\tcreation_tag\\tobject\\tNo\\t\\t配置创建时间\\n\\t\\t\\tversion_number\\tnumber\\tNo\\t\\t1\\n\\t\\t\\tlast_modified_by\\tobject\\tNo\\t\\t\\n\\t\\t\\t\\tlogin\\tstring\\tNo\\t\\t\\n\\t\\t\\tlast_modified_on\\tnumber\\tNo\\t\\t创建时间unix time ms\\n\\t\\ttags\\tarray\\tNo\\t\\t文件夹标签\\n\\t\\tcustom_fields\\tobject\\tNo\\t\\t\\n\\t\\tchecklists\\tobject\\tNo\\t\\t\\n\\t\\t\\tchecklists\\tarray\\tNo\\t\\t\\n\\n```\"}]": {
+ "code": "import string\nimport random\n\ndef random_string(length=10):\n return ''.join(random.choice(string.ascii_lowercase) for i in range(length))"
+ },
+ "[{\"role\": \"system\", \"content\": \"You are an AI Python assistant. You will be given your previous implementation code of a task, runtime error results, and a hint to change the implementation appropriately. Write your full implementation \"}, {\"role\": \"user\", \"content\": \"\\nHere is an example for you.\\n\\nExample 1:\\n[previous impl]:\\n```python\\ndef add(a: int, b: int) -> int:\\n \\\"\\\"\\\"\\n Given integers a and b, return the total value of a and b.\\n \\\"\\\"\\\"\\n return a - b\\n```\\n\\n[runtime Error]:\\nTested passed:\\n\\nTests failed:\\nassert add(1, 2) == 3 # output: -1\\nassert add(1, 2) == 4 # output: -1\\n\\n[reflection on previous impl]:\\nThe implementation failed the test cases where the input integers are 1 and 2. The issue arises because the code does not add the two integers together, but instead subtracts the second integer from the first. To fix this issue, we should change the operator from `-` to `+` in the return statement. This will ensure that the function returns the correct output for the given input.\\n\\n[improved impl]:\\n```python\\ndef add(a: int, b: int) -> int:\\n \\\"\\\"\\\"\\n Given integers a and b, return the total value of a and b.\\n \\\"\\\"\\\"\\n return a + b\\n```\\n\\n[context]\\nuser: Solve the problem in Python:\\ndef sort_array(arr):\\n \\\"\\\"\\\"\\n In this Kata, you have to sort an array of non-negative integers according to\\n number of ones in their binary representation in ascending order.\\n For similar number of ones, sort based on decimal value.\\n\\n It must be implemented like this:\\n >>> sort_array([1, 5, 2, 3, 4]) == [1, 2, 3, 4, 5]\\n >>> sort_array([-2, -3, -4, -5, -6]) == [-6, -5, -4, -3, -2]\\n >>> sort_array([1, 0, 2, 3, 4]) [0, 1, 2, 3, 4]\\n \\\"\\\"\\\"\\n\\n\\n[previous impl]\\n\\ndef sort_array(arr):\\n # Helper function to count the number of ones in the binary representation\\n def count_ones(n):\\n return bin(n).count('1')\\n \\n # Sort the array using a custom key function\\n # The key function returns a tuple (number of ones, value) for each element\\n # This ensures that if two elements have the same number of ones, they are sorted by their value\\n sorted_arr = sorted(arr, key=lambda x: (count_ones(x), x))\\n \\n return sorted_arr\\n```\\n\\n[runtime Error]\\nTested passed:\\n\\nTests failed:\\nassert sort_array([1, 5, 2, 3, 4]) == [1, 2, 3, 4, 5] # output: [1, 2, 4, 3, 5]\\n\\n\\nAnalysis the error step by step, provide me improve method and code. Remember to follow [context] requirement. Don't forget write code for steps behind the error step.\\n[reflection on previous impl]:\\nxxx\\n\"}]": {
+ "reflection": "The implementation failed the test case where the input array is [1, 5, 2, 3, 4]. The issue arises because the code does not correctly sort the array based on the number of ones in their binary representation and then by their decimal value. The current implementation sorts the array primarily by the number of ones in the binary representation, but it does not handle the secondary sorting by decimal value correctly for negative numbers, as it does not account for the fact that the binary representation of negative numbers in Python is different due to two's complement representation. To fix this issue, we should modify the count_ones function to correctly handle negative numbers by taking the absolute value before converting to binary and counting ones. Additionally, we should ensure that the array is sorted by the absolute value when the number of ones is the same.",
+ "improved_impl": "def sort_array(arr):\n # Helper function to count the number of ones in the binary representation\n def count_ones(n):\n return bin(abs(n)).count('1')\n \n # Sort the array using a custom key function\n # The key function returns a tuple (number of ones, absolute value, original value) for each element\n # This ensures that if two elements have the same number of ones, they are sorted by their absolute value\n sorted_arr = sorted(arr, key=lambda x: (count_ones(x), abs(x), x))\n \n return sorted_arr"
+ },
+ "[{\"role\": \"user\", \"content\": \"\\n## User Requirement:\\n对数据集进行数据清洗\\n\\n## Task\\nRecommend up to five tools from 'Available Tools' that can help solve the 'User Requirement'. \\n\\n## Available Tools:\\n{'FillMissingValue': 'Completing missing values with simple strategies.', 'MinMaxScale': 'Transform features by scaling each feature to a range, which is (0, 1).', 'StandardScale': 'Standardize features by removing the mean and scaling to unit variance.', 'MaxAbsScale': 'Scale each feature by its maximum absolute value.', 'RobustScale': 'Apply the RobustScaler to scale features using statistics that are robust to outliers.', 'OrdinalEncode': 'Encode categorical features as ordinal integers.', 'OneHotEncode': 'Apply one-hot encoding to specified categorical columns, the original columns will be dropped.', 'LabelEncode': 'Apply label encoding to specified categorical columns in-place.'}\\n\\n## Tool Selection and Instructions:\\n- Select tools most relevant to completing the 'User Requirement'.\\n- If you believe that no tools are suitable, indicate with an empty list.\\n- Only list the names of the tools, not the full schema of each tool.\\n- Ensure selected tools are listed in 'Available Tools'.\\n\"}]": {
+ "recommend_tools": [
+ "FillMissingValue",
+ "MinMaxScale",
+ "StandardScale",
+ "MaxAbsScale",
+ "RobustScale"
+ ]
+ },
+ "[{\"role\": \"user\", \"content\": \"\\n# Background\\nAs a data scientist, you need to help user to achieve their goal [构造数据集并进行数据清洗] step-by-step in an continuous Jupyter notebook.\\n\\n## Done Tasks\\n```python\\n import pandas as pd\\n df = pd.DataFrame({\\n 'a': [1, 2, 3, 4, 5],\\n 'b': [1.1, 2.2, 3.3, 4.4, np.nan],\\n 'c': ['aa', 'bb', 'cc', 'dd', 'ee'],\\n 'd': [1, 2, 3, 4, 5]\\n })\\n```end\\n\\n## Current Task\\n对数据集进行数据清洗\\n\\n# Latest Data Info\\nLatest data info after previous tasks:\\n\\n\\n# Task\\nWrite complete code for 'Current Task'. And avoid duplicating code from 'Done Tasks', such as repeated import of packages, reading data, etc.\\nSpecifically, \\nThe current task is about data preprocessing, please note the following:\\n- Monitor data types per column, applying appropriate methods.\\n- Ensure operations are on existing dataset columns.\\n- Avoid writing processed data to files.\\n- Avoid any change to label column, such as standardization, etc.\\n- Prefer alternatives to one-hot encoding for categorical data.\\n- Only encode or scale necessary columns to allow for potential feature-specific engineering tasks (like time_extract, binning, extraction, etc.) later.\\n- Each step do data preprocessing to train, must do same for test separately at the same time.\\n\\n\\n# Capabilities\\n- You can utilize pre-defined tools in any code lines from 'Available Tools' in the form of Python Class.\\n- You can freely combine the use of any other public packages, like sklearn, numpy, pandas, etc..\\n\\n# Available Tools:\\nEach Class tool is described in JSON format. When you call a tool, import the tool from its path first.\\n{'FillMissingValue': {'type': 'class', 'description': 'Completing missing values with simple strategies.', 'methods': {'__init__': {'type': 'function', 'description': 'Initialize self.', 'parameters': {'properties': {'features': {'type': 'list', 'description': 'Columns to be processed.'}, 'strategy': {'type': 'str', 'description': \\\"The imputation strategy, notice 'mean' and 'median' can only be used for numeric features. Enum: ['mean', 'median', 'most_frequent', 'constant']. Defaults to 'mean'.\\\", 'default': \\\"'mean'\\\", 'enum': [\\\"'mean'\\\", \\\"'median'\\\", \\\"'most_frequent'\\\", \\\"'constant'\\\"]}, 'fill_value': {'type': 'int', 'description': 'Fill_value is used to replace all occurrences of missing_values. Defaults to None.', 'default': 'None'}}, 'required': ['features']}}, 'fit': {'type': 'function', 'description': 'Fit a model to be used in subsequent transform.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}}, 'fit_transform': {'type': 'function', 'description': 'Fit and transform the input DataFrame.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}, 'returns': [{'type': 'pd.DataFrame', 'description': 'The transformed DataFrame.'}]}, 'transform': {'type': 'function', 'description': 'Transform the input DataFrame with the fitted model.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}, 'returns': [{'type': 'pd.DataFrame', 'description': 'The transformed DataFrame.'}]}}, 'tool_path': 'metagpt/tools/libs/data_preprocess.py'}, 'MinMaxScale': {'type': 'class', 'description': 'Transform features by scaling each feature to a range, which is (0, 1).', 'methods': {'__init__': {'type': 'function', 'description': 'Initialize self.', 'parameters': {'properties': {'features': {'type': 'list', 'description': 'Columns to be processed.'}}, 'required': ['features']}}, 'fit': {'type': 'function', 'description': 'Fit a model to be used in subsequent transform.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}}, 'fit_transform': {'type': 'function', 'description': 'Fit and transform the input DataFrame.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}, 'returns': [{'type': 'pd.DataFrame', 'description': 'The transformed DataFrame.'}]}, 'transform': {'type': 'function', 'description': 'Transform the input DataFrame with the fitted model.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}, 'returns': [{'type': 'pd.DataFrame', 'description': 'The transformed DataFrame.'}]}}, 'tool_path': 'metagpt/tools/libs/data_preprocess.py'}, 'StandardScale': {'type': 'class', 'description': 'Standardize features by removing the mean and scaling to unit variance.', 'methods': {'__init__': {'type': 'function', 'description': 'Initialize self.', 'parameters': {'properties': {'features': {'type': 'list', 'description': 'Columns to be processed.'}}, 'required': ['features']}}, 'fit': {'type': 'function', 'description': 'Fit a model to be used in subsequent transform.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}}, 'fit_transform': {'type': 'function', 'description': 'Fit and transform the input DataFrame.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}, 'returns': [{'type': 'pd.DataFrame', 'description': 'The transformed DataFrame.'}]}, 'transform': {'type': 'function', 'description': 'Transform the input DataFrame with the fitted model.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}, 'returns': [{'type': 'pd.DataFrame', 'description': 'The transformed DataFrame.'}]}}, 'tool_path': 'metagpt/tools/libs/data_preprocess.py'}, 'MaxAbsScale': {'type': 'class', 'description': 'Scale each feature by its maximum absolute value.', 'methods': {'__init__': {'type': 'function', 'description': 'Initialize self.', 'parameters': {'properties': {'features': {'type': 'list', 'description': 'Columns to be processed.'}}, 'required': ['features']}}, 'fit': {'type': 'function', 'description': 'Fit a model to be used in subsequent transform.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}}, 'fit_transform': {'type': 'function', 'description': 'Fit and transform the input DataFrame.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}, 'returns': [{'type': 'pd.DataFrame', 'description': 'The transformed DataFrame.'}]}, 'transform': {'type': 'function', 'description': 'Transform the input DataFrame with the fitted model.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}, 'returns': [{'type': 'pd.DataFrame', 'description': 'The transformed DataFrame.'}]}}, 'tool_path': 'metagpt/tools/libs/data_preprocess.py'}, 'RobustScale': {'type': 'class', 'description': 'Apply the RobustScaler to scale features using statistics that are robust to outliers.', 'methods': {'__init__': {'type': 'function', 'description': 'Initialize self.', 'parameters': {'properties': {'features': {'type': 'list', 'description': 'Columns to be processed.'}}, 'required': ['features']}}, 'fit': {'type': 'function', 'description': 'Fit a model to be used in subsequent transform.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}}, 'fit_transform': {'type': 'function', 'description': 'Fit and transform the input DataFrame.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}, 'returns': [{'type': 'pd.DataFrame', 'description': 'The transformed DataFrame.'}]}, 'transform': {'type': 'function', 'description': 'Transform the input DataFrame with the fitted model.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}, 'returns': [{'type': 'pd.DataFrame', 'description': 'The transformed DataFrame.'}]}}, 'tool_path': 'metagpt/tools/libs/data_preprocess.py'}}\\n\\n# Output Example:\\nwhen current task is \\\"do data preprocess, like fill missing value, handle outliers, etc.\\\", the code can be like:\\n```python\\n# Step 1: fill missing value\\n# Tools used: ['FillMissingValue']\\nfrom metagpt.tools.libs.data_preprocess import FillMissingValue\\n\\ntrain_processed = train.copy()\\ntest_processed = test.copy()\\nnum_cols = train_processed.select_dtypes(include='number').columns.tolist()\\nif 'label' in num_cols:\\n num_cols.remove('label')\\nfill_missing_value = FillMissingValue(features=num_cols, strategy='mean')\\nfill_missing_value.fit(train_processed)\\ntrain_processed = fill_missing_value.transform(train_processed)\\ntest_processed = fill_missing_value.transform(test_processed)\\n\\n# Step 2: handle outliers\\nfor col in num_cols:\\n low, high = train_processed[col].quantile([0.01, 0.99])\\n train_processed[col] = train_processed[col].clip(low, high)\\n test_processed[col] = test_processed[col].clip(low, high)\\n```end\\n\\n# Constraints:\\n- Ensure the output new code is executable in the same Jupyter notebook with previous tasks code have been executed.\\n- Always prioritize using pre-defined tools for the same functionality.\\n- Always copy the DataFrame before processing it and use the copy to process.\\n\"}]": {
+ "code": "# Step 1: Fill missing values\nfrom metagpt.tools.libs.data_preprocess import FillMissingValue\n\n# Create a copy of the DataFrame to avoid modifying the original one\ndf_processed = df.copy()\n\n# Define the columns with missing values\nmissing_value_columns = df_processed.columns[df_processed.isnull().any()].tolist()\n\n# Initialize the FillMissingValue tool with the strategy to fill missing values with the mean\nfill_missing_value = FillMissingValue(features=missing_value_columns, strategy='mean')\n\n# Fit and transform the DataFrame\ndf_processed = fill_missing_value.fit_transform(df_processed)\n\n# Step 2: Scale numeric columns\nfrom metagpt.tools.libs.data_preprocess import MinMaxScale\n\n# Define the numeric columns to be scaled\nnumeric_columns = df_processed.select_dtypes(include=['int64', 'float64']).columns.tolist()\n\n# Initialize the MinMaxScale tool\nminmax_scale = MinMaxScale(features=numeric_columns)\n\n# Fit and transform the DataFrame\ndf_processed = minmax_scale.fit_transform(df_processed)\n\n# Display the processed DataFrame\ndisplay(df_processed)"
+ },
+ "[{\"role\": \"user\", \"content\": \"\\n## User Requirement:\\nclean and preprocess the data\\n\\n## Task\\nRecommend up to five tools from 'Available Tools' that can help solve the 'User Requirement'. \\n\\n## Available Tools:\\n{'FillMissingValue': 'Filling missing values', 'SplitBins': 'Bin continuous data into intervals and return the bin identifier encoded as an integer value'}\\n\\n## Tool Selection and Instructions:\\n- Select tools most relevant to completing the 'User Requirement'.\\n- If you believe that no tools are suitable, indicate with an empty list.\\n- Only list the names of the tools, not the full schema of each tool.\\n- Ensure selected tools are listed in 'Available Tools'.\\n\"}]": {
+ "recommend_tools": [
+ "FillMissingValue"
+ ]
+ },
+ "[{\"role\": \"system\", \"content\": \"You are Code Interpreter, a world-class programmer that can complete any goal by executing code. Strictly follow the plan and generate code step by step. Each step of the code will be executed on the user's machine, and the user will provide the code execution results to you.**Notice: The code for the next step depends on the code for the previous step. Must reuse variables in the lastest other code directly, dont creat it again, it is very import for you. Use !pip install in a standalone block to install missing packages.Usually the libraries you need are already installed.Dont check if packages already imported.**\"}, {\"role\": \"user\", \"content\": \"\\n## User Requirement\\n构造数据集并进行数据清洗\\n## Context\\n\\n## Current Plan\\n[Task(task_id='1', dependent_task_ids=[], instruction='随机生成一个pandas DataFrame数据集', task_type='other', code=\\\"\\\\n import pandas as pd\\\\n df = pd.DataFrame({\\\\n 'a': [1, 2, 3, 4, 5],\\\\n 'b': [1.1, 2.2, 3.3, 4.4, np.nan],\\\\n 'c': ['aa', 'bb', 'cc', 'dd', 'ee'],\\\\n 'd': [1, 2, 3, 4, 5]\\\\n })\\\\n \\\", result='', is_success=False, is_finished=True), Task(task_id='2', dependent_task_ids=['1'], instruction='对数据集进行数据清洗', task_type='data_preprocess', code='', result='', is_success=False, is_finished=False)]\\n## Current Task\\n{\\\"task_id\\\":\\\"2\\\",\\\"dependent_task_ids\\\":[\\\"1\\\"],\\\"instruction\\\":\\\"对数据集进行数据清洗\\\",\\\"task_type\\\":\\\"data_preprocess\\\",\\\"code\\\":\\\"\\\",\\\"result\\\":\\\"\\\",\\\"is_success\\\":false,\\\"is_finished\\\":false}\\n\"}, {\"role\": \"user\", \"content\": \"\\n# Instruction\\nWrite complete code for 'Current Task'. And avoid duplicating code from finished tasks, such as repeated import of packages, reading data, etc.\\nSpecifically, \\nThe current task is about data preprocessing, please note the following:\\n- Monitor data types per column, applying appropriate methods.\\n- Ensure operations are on existing dataset columns.\\n- Avoid writing processed data to files.\\n- Avoid any change to label column, such as standardization, etc.\\n- Prefer alternatives to one-hot encoding for categorical data.\\n- Only encode or scale necessary columns to allow for potential feature-specific engineering tasks (like time_extract, binning, extraction, etc.) later.\\n- Each step do data preprocessing to train, must do same for test separately at the same time.\\n\\n\\n# Capabilities\\n- You can utilize pre-defined tools in any code lines from 'Available Tools' in the form of Python Class.\\n- You can freely combine the use of any other public packages, like sklearn, numpy, pandas, etc..\\n\\n# Available Tools (can be empty):\\nEach Class tool is described in JSON format. When you call a tool, import the tool first.\\n{'FillMissingValue': {'type': 'class', 'description': 'Completing missing values with simple strategies.', 'methods': {'__init__': {'type': 'function', 'description': 'Initialize self.', 'parameters': {'properties': {'features': {'type': 'list', 'description': 'Columns to be processed.'}, 'strategy': {'type': 'str', 'description': \\\"The imputation strategy, notice 'mean' and 'median' can only be used for numeric features. Enum: ['mean', 'median', 'most_frequent', 'constant']. Defaults to 'mean'.\\\", 'default': \\\"'mean'\\\", 'enum': [\\\"'mean'\\\", \\\"'median'\\\", \\\"'most_frequent'\\\", \\\"'constant'\\\"]}, 'fill_value': {'type': 'int', 'description': 'Fill_value is used to replace all occurrences of missing_values. Defaults to None.', 'default': 'None'}}, 'required': ['features']}}, 'fit': {'type': 'function', 'description': 'Fit a model to be used in subsequent transform.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}}, 'fit_transform': {'type': 'function', 'description': 'Fit and transform the input DataFrame.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}, 'returns': [{'type': 'pd.DataFrame', 'description': 'The transformed DataFrame.'}]}, 'transform': {'type': 'function', 'description': 'Transform the input DataFrame with the fitted model.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}, 'returns': [{'type': 'pd.DataFrame', 'description': 'The transformed DataFrame.'}]}}, 'tool_path': 'metagpt/tools/libs/data_preprocess.py'}, 'MinMaxScale': {'type': 'class', 'description': 'Transform features by scaling each feature to a range, which is (0, 1).', 'methods': {'__init__': {'type': 'function', 'description': 'Initialize self.', 'parameters': {'properties': {'features': {'type': 'list', 'description': 'Columns to be processed.'}}, 'required': ['features']}}, 'fit': {'type': 'function', 'description': 'Fit a model to be used in subsequent transform.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}}, 'fit_transform': {'type': 'function', 'description': 'Fit and transform the input DataFrame.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}, 'returns': [{'type': 'pd.DataFrame', 'description': 'The transformed DataFrame.'}]}, 'transform': {'type': 'function', 'description': 'Transform the input DataFrame with the fitted model.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}, 'returns': [{'type': 'pd.DataFrame', 'description': 'The transformed DataFrame.'}]}}, 'tool_path': 'metagpt/tools/libs/data_preprocess.py'}, 'StandardScale': {'type': 'class', 'description': 'Standardize features by removing the mean and scaling to unit variance.', 'methods': {'__init__': {'type': 'function', 'description': 'Initialize self.', 'parameters': {'properties': {'features': {'type': 'list', 'description': 'Columns to be processed.'}}, 'required': ['features']}}, 'fit': {'type': 'function', 'description': 'Fit a model to be used in subsequent transform.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}}, 'fit_transform': {'type': 'function', 'description': 'Fit and transform the input DataFrame.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}, 'returns': [{'type': 'pd.DataFrame', 'description': 'The transformed DataFrame.'}]}, 'transform': {'type': 'function', 'description': 'Transform the input DataFrame with the fitted model.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}, 'returns': [{'type': 'pd.DataFrame', 'description': 'The transformed DataFrame.'}]}}, 'tool_path': 'metagpt/tools/libs/data_preprocess.py'}, 'MaxAbsScale': {'type': 'class', 'description': 'Scale each feature by its maximum absolute value.', 'methods': {'__init__': {'type': 'function', 'description': 'Initialize self.', 'parameters': {'properties': {'features': {'type': 'list', 'description': 'Columns to be processed.'}}, 'required': ['features']}}, 'fit': {'type': 'function', 'description': 'Fit a model to be used in subsequent transform.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}}, 'fit_transform': {'type': 'function', 'description': 'Fit and transform the input DataFrame.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}, 'returns': [{'type': 'pd.DataFrame', 'description': 'The transformed DataFrame.'}]}, 'transform': {'type': 'function', 'description': 'Transform the input DataFrame with the fitted model.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}, 'returns': [{'type': 'pd.DataFrame', 'description': 'The transformed DataFrame.'}]}}, 'tool_path': 'metagpt/tools/libs/data_preprocess.py'}, 'RobustScale': {'type': 'class', 'description': 'Apply the RobustScaler to scale features using statistics that are robust to outliers.', 'methods': {'__init__': {'type': 'function', 'description': 'Initialize self.', 'parameters': {'properties': {'features': {'type': 'list', 'description': 'Columns to be processed.'}}, 'required': ['features']}}, 'fit': {'type': 'function', 'description': 'Fit a model to be used in subsequent transform.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}}, 'fit_transform': {'type': 'function', 'description': 'Fit and transform the input DataFrame.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}, 'returns': [{'type': 'pd.DataFrame', 'description': 'The transformed DataFrame.'}]}, 'transform': {'type': 'function', 'description': 'Transform the input DataFrame with the fitted model.', 'parameters': {'properties': {'df': {'type': 'pd.DataFrame', 'description': 'The input DataFrame.'}}, 'required': ['df']}, 'returns': [{'type': 'pd.DataFrame', 'description': 'The transformed DataFrame.'}]}}, 'tool_path': 'metagpt/tools/libs/data_preprocess.py'}}\\n\\n# Constraints:\\n- Ensure the output new code is executable in the same Jupyter notebook with previous tasks code have been executed.\\n- Always prioritize using pre-defined tools for the same functionality.\\n\"}]": {
+ "code": "from metagpt.tools.libs.data_preprocess import FillMissingValue\n\n# Instantiate the FillMissingValue class for column 'b'\nfill_missing_b = FillMissingValue(features=['b'], strategy='mean')\n\n# Fit and transform the DataFrame\n# Since we only have one DataFrame, we will use it as both train and test for demonstration\n# In practice, train and test data should be handled separately\ntrain_df = fill_missing_b.fit_transform(df)\ntest_df = fill_missing_b.transform(df)\n\n# Check the results\ntrain_df\n"
+ },
+ "[{\"role\": \"system\", \"content\": \"You are Code Interpreter, a world-class programmer that can complete any goal by executing code. Strictly follow the plan and generate code step by step. Each step of the code will be executed on the user's machine, and the user will provide the code execution results to you.**Notice: The code for the next step depends on the code for the previous step. Must reuse variables in the lastest other code directly, dont creat it again, it is very import for you. Use !pip install in a standalone block to install missing packages.Usually the libraries you need are already installed.Dont check if packages already imported.**\"}, {\"role\": \"user\", \"content\": \"\\n ## User Requirement\\n read a dataset test.csv and print its head\\n ## Current Plan\\n [\\n {\\n \\\"task_id\\\": \\\"1\\\",\\n \\\"dependent_task_ids\\\": [],\\n \\\"instruction\\\": \\\"import pandas and load the dataset from 'test.csv'.\\\",\\n \\\"task_type\\\": \\\"\\\",\\n \\\"code\\\": \\\"\\\",\\n \\\"result\\\": \\\"\\\",\\n \\\"is_finished\\\": false\\n },\\n {\\n \\\"task_id\\\": \\\"2\\\",\\n \\\"dependent_task_ids\\\": [\\n \\\"1\\\"\\n ],\\n \\\"instruction\\\": \\\"Print the head of the dataset to display the first few rows.\\\",\\n \\\"task_type\\\": \\\"\\\",\\n \\\"code\\\": \\\"\\\",\\n \\\"result\\\": \\\"\\\",\\n \\\"is_finished\\\": false\\n }\\n ]\\n ## Current Task\\n {\\\"task_id\\\": \\\"1\\\", \\\"dependent_task_ids\\\": [], \\\"instruction\\\": \\\"import pandas and load the dataset from 'test.csv'.\\\", \\\"task_type\\\": \\\"\\\", \\\"code\\\": \\\"\\\", \\\"result\\\": \\\"\\\", \\\"is_finished\\\": false}\\n \"}, {\"role\": \"assistant\", \"content\": \"import pandas as pd\\ndata = pd.read_excel('test.csv')\\ndata\"}, {\"role\": \"user\", \"content\": \"\\n Traceback (most recent call last):\\n File \\\"\\\", line 2, in \\n File \\\"/Users/gary/miniconda3/envs/py39_scratch/lib/python3.9/site-packages/pandas/io/excel/_base.py\\\", line 478, in read_excel\\n io = ExcelFile(io, storage_options=storage_options, engine=engine)\\n File \\\"/Users/gary/miniconda3/envs/py39_scratch/lib/python3.9/site-packages/pandas/io/excel/_base.py\\\", line 1500, in __init__\\n raise ValueError(\\n ValueError: Excel file format cannot be determined, you must specify an engine manually.\\n \"}]": {
+ "language": "python",
+ "code": "import pandas as pd\ndata = pd.read_csv('test.csv')"
+ },
+ "[{\"role\": \"system\", \"content\": \"You are Code Interpreter, a world-class programmer that can complete any goal by executing code. Strictly follow the plan and generate code step by step. Each step of the code will be executed on the user's machine, and the user will provide the code execution results to you.**Notice: The code for the next step depends on the code for the previous step. Must reuse variables in the lastest other code directly, dont creat it again, it is very import for you. Use !pip install in a standalone block to install missing packages.Usually the libraries you need are already installed.Dont check if packages already imported.**\"}, {\"role\": \"user\", \"content\": \"\\n ## User Requirement\\n read a dataset test.csv and print its head\\n ## Current Plan\\n [\\n {\\n \\\"task_id\\\": \\\"1\\\",\\n \\\"dependent_task_ids\\\": [],\\n \\\"instruction\\\": \\\"import pandas and load the dataset from 'test.csv'.\\\",\\n \\\"task_type\\\": \\\"\\\",\\n \\\"code\\\": \\\"import pandas as pd\\ndata = pd.read_csv('test.csv')\\\",\\n \\\"result\\\": \\\"\\\",\\n \\\"is_finished\\\": true\\n },\\n {\\n \\\"task_id\\\": \\\"2\\\",\\n \\\"dependent_task_ids\\\": [\\n \\\"1\\\"\\n ],\\n \\\"instruction\\\": \\\"Print the head of the dataset to display the first few rows.\\\",\\n \\\"task_type\\\": \\\"\\\",\\n \\\"code\\\": \\\"\\\",\\n \\\"result\\\": \\\"\\\",\\n \\\"is_finished\\\": false\\n }\\n ]\\n ## Current Task\\n {\\\"task_id\\\": \\\"2\\\", \\\"dependent_task_ids\\\": [\\\"1\\\"], \\\"instruction\\\": \\\"Print the head of the dataset to display the first few rows.\\\", \\\"task_type\\\": \\\"\\\", \\\"code\\\": \\\"\\\", \\\"result\\\": \\\"\\\", \\\"is_finished\\\": false}\\n \"}]": {
+ "language": "python",
+ "code": "print(data.head())"
+ },
+ "\n # Context:\n user: run analysis on sklearn iris dataset\n # Task:\n Based on the context, write a plan or modify an existing plan of what you should do to achieve the goal. A plan consists of one to 5 tasks.\n If you are modifying an existing plan, carefully follow the instruction, don't make unnecessary changes. Give the whole plan unless instructed to modify only one task of the plan.\n If you encounter errors on the current task, revise and output the current single task only.\n Output a list of jsons following the format:\n ```json\n [\n {\n \"task_id\": str = \"unique identifier for a task in plan, can be an ordinal\",\n \"dependent_task_ids\": list[str] = \"ids of tasks prerequisite to this task\",\n \"instruction\": \"what you should do in this task, one short phrase or sentence\",\n },\n ...\n ]\n ```\n ": "```json\n[\n {\n \"task_id\": \"1\",\n \"dependent_task_ids\": [],\n \"instruction\": \"Import the Iris dataset from sklearn.datasets\"\n },\n {\n \"task_id\": \"2\",\n \"dependent_task_ids\": [\"1\"],\n \"instruction\": \"Perform exploratory data analysis to understand the dataset\"\n },\n {\n \"task_id\": \"3\",\n \"dependent_task_ids\": [\"2\"],\n \"instruction\": \"Preprocess the data to prepare it for modeling\"\n },\n {\n \"task_id\": \"4\",\n \"dependent_task_ids\": [\"3\"],\n \"instruction\": \"Split the dataset into training and testing sets\"\n },\n {\n \"task_id\": \"5\",\n \"dependent_task_ids\": [\"4\"],\n \"instruction\": \"Train a classifier using the training set and evaluate it using the test set\"\n }\n]\n```",
+ "[{\"role\": \"user\", \"content\": \"\\nPlease assign a task type to each task in the list below from the given categories:\\nTask 1: Import the Iris dataset from sklearn.datasets\\nTask 2: Perform exploratory data analysis to understand the dataset\\nTask 3: Preprocess the data to prepare it for modeling\\nTask 4: Split the dataset into training and testing sets\\nTask 5: Train a classifier using the training set and evaluate it using the test set\\n\\n## All Task Type:\\n- **eda**: For performing exploratory data analysis\\n- **data_preprocess**: Only for changing value inplace.\\n- **feature_engineering**: Only for creating new columns for input data.\\n- **model_train**: Only for training model.\\n- **model_evaluate**: Only for evaluating model.\\n- **stable_diffusion**: Related to text2image, image2image using stable diffusion model.\\n- **image2webpage**: For converting image into webpage code.\\n- **web_scraping**: For scraping data from web pages.\\n- **other**: Any tools not in the defined categories\\n\"}]": {
+ "task_type": [
+ "other",
+ "eda",
+ "data_preprocess",
+ "data_preprocess",
+ "model_train",
+ "model_evaluate"
+ ]
+ },
+ "\n # Context:\n user: \n## User Requirement\nRun data analysis on sklearn Iris dataset, include a plot\n## Context\n\n## Current Plan\n[]\n## Current Task\n{}\n\n # Task:\n Based on the context, write a plan or modify an existing plan of what you should do to achieve the goal. A plan consists of one to 3 tasks.\n If you are modifying an existing plan, carefully follow the instruction, don't make unnecessary changes. Give the whole plan unless instructed to modify only one task of the plan.\n If you encounter errors on the current task, revise and output the current single task only.\n Output a list of jsons following the format:\n ```json\n [\n {\n \"task_id\": str = \"unique identifier for a task in plan, can be an ordinal\",\n \"dependent_task_ids\": list[str] = \"ids of tasks prerequisite to this task\",\n \"instruction\": \"what you should do in this task, one short phrase or sentence\",\n },\n ...\n ]\n ```\n ": "```json\n[\n {\n \"task_id\": \"1\",\n \"dependent_task_ids\": [],\n \"instruction\": \"Load the sklearn Iris dataset.\"\n },\n {\n \"task_id\": \"2\",\n \"dependent_task_ids\": [\"1\"],\n \"instruction\": \"Perform exploratory data analysis on the Iris dataset.\"\n },\n {\n \"task_id\": \"3\",\n \"dependent_task_ids\": [\"2\"],\n \"instruction\": \"Create a plot visualizing the Iris dataset.\"\n }\n]\n```",
+ "[{\"role\": \"user\", \"content\": \"\\nPlease assign a task type to each task in the list below from the given categories:\\nTask 1: Load the sklearn Iris dataset.\\nTask 2: Perform exploratory data analysis on the Iris dataset.\\nTask 3: Create a plot visualizing the Iris dataset.\\n\\n## All Task Type:\\n- **eda**: For performing exploratory data analysis\\n- **data_preprocess**: Only for changing value inplace.\\n- **feature_engineering**: Only for creating new columns for input data.\\n- **model_train**: Only for training model.\\n- **model_evaluate**: Only for evaluating model.\\n- **stable_diffusion**: Related to text2image, image2image using stable diffusion model.\\n- **image2webpage**: For converting image into webpage code.\\n- **web_scraping**: For scraping data from web pages.\\n- **other**: Any tools not in the defined categories\\n\"}]": {
+ "task_type": [
+ "other",
+ "eda",
+ "other"
+ ]
+ },
+ "[{\"role\": \"system\", \"content\": \"You are Code Interpreter, a world-class programmer that can complete any goal by executing code. Strictly follow the plan and generate code step by step. Each step of the code will be executed on the user's machine, and the user will provide the code execution results to you.**Notice: The code for the next step depends on the code for the previous step. Must reuse variables in the lastest other code directly, dont creat it again, it is very import for you. Use !pip install in a standalone block to install missing packages.Usually the libraries you need are already installed.Dont check if packages already imported.**\"}, {\"role\": \"user\", \"content\": \"\\n## User Requirement\\nRun data analysis on sklearn Iris dataset, include a plot\\n## Context\\n\\n## Current Plan\\n[\\n {\\n \\\"task_id\\\": \\\"1\\\",\\n \\\"dependent_task_ids\\\": [],\\n \\\"instruction\\\": \\\"Load the sklearn Iris dataset.\\\",\\n \\\"task_type\\\": \\\"other\\\",\\n \\\"code\\\": \\\"\\\",\\n \\\"result\\\": \\\"\\\",\\n \\\"is_success\\\": false,\\n \\\"is_finished\\\": false\\n },\\n {\\n \\\"task_id\\\": \\\"2\\\",\\n \\\"dependent_task_ids\\\": [\\n \\\"1\\\"\\n ],\\n \\\"instruction\\\": \\\"Perform exploratory data analysis on the Iris dataset.\\\",\\n \\\"task_type\\\": \\\"eda\\\",\\n \\\"code\\\": \\\"\\\",\\n \\\"result\\\": \\\"\\\",\\n \\\"is_success\\\": false,\\n \\\"is_finished\\\": false\\n },\\n {\\n \\\"task_id\\\": \\\"3\\\",\\n \\\"dependent_task_ids\\\": [\\n \\\"2\\\"\\n ],\\n \\\"instruction\\\": \\\"Create a plot visualizing the Iris dataset.\\\",\\n \\\"task_type\\\": \\\"other\\\",\\n \\\"code\\\": \\\"\\\",\\n \\\"result\\\": \\\"\\\",\\n \\\"is_success\\\": false,\\n \\\"is_finished\\\": false\\n }\\n]\\n## Current Task\\n{\\\"task_id\\\":\\\"1\\\",\\\"dependent_task_ids\\\":[],\\\"instruction\\\":\\\"Load the sklearn Iris dataset.\\\",\\\"task_type\\\":\\\"other\\\",\\\"code\\\":\\\"\\\",\\\"result\\\":\\\"\\\",\\\"is_success\\\":false,\\\"is_finished\\\":false}\\n\"}, {\"role\": \"user\", \"content\": \"\\n# Instruction\\nWrite complete code for 'Current Task'. And avoid duplicating code from finished tasks, such as repeated import of packages, reading data, etc.\\nSpecifically, \\n\\n# Capabilities\\n- You can utilize pre-defined tools in any code lines from 'Available Tools' in the form of Python Class.\\n- You can freely combine the use of any other public packages, like sklearn, numpy, pandas, etc..\\n\\n# Available Tools (can be empty):\\nEach Class tool is described in JSON format. When you call a tool, import the tool first.\\n{}\\n\\n# Constraints:\\n- Ensure the output new code is executable in the same Jupyter notebook with previous tasks code have been executed.\\n- Always prioritize using pre-defined tools for the same functionality.\\n\"}]": {
+ "code": "from sklearn.datasets import load_iris\niris_data = load_iris()"
+ },
+ "[{\"role\": \"system\", \"content\": \"You are Code Interpreter, a world-class programmer that can complete any goal by executing code. Strictly follow the plan and generate code step by step. Each step of the code will be executed on the user's machine, and the user will provide the code execution results to you.**Notice: The code for the next step depends on the code for the previous step. Must reuse variables in the lastest other code directly, dont creat it again, it is very import for you. Use !pip install in a standalone block to install missing packages.Usually the libraries you need are already installed.Dont check if packages already imported.**\"}, {\"role\": \"user\", \"content\": \"\\n## User Requirement\\nRun data analysis on sklearn Iris dataset, include a plot\\n## Context\\n\\n## Current Plan\\n[\\n {\\n \\\"task_id\\\": \\\"1\\\",\\n \\\"dependent_task_ids\\\": [],\\n \\\"instruction\\\": \\\"Load the sklearn Iris dataset.\\\",\\n \\\"task_type\\\": \\\"other\\\",\\n \\\"code\\\": \\\"\\\",\\n \\\"result\\\": \\\"a successful run\\\",\\n \\\"is_success\\\": true,\\n \\\"is_finished\\\": true\\n },\\n {\\n \\\"task_id\\\": \\\"2\\\",\\n \\\"dependent_task_ids\\\": [\\n \\\"1\\\"\\n ],\\n \\\"instruction\\\": \\\"Perform exploratory data analysis on the Iris dataset.\\\",\\n \\\"task_type\\\": \\\"eda\\\",\\n \\\"code\\\": \\\"\\\",\\n \\\"result\\\": \\\"\\\",\\n \\\"is_success\\\": false,\\n \\\"is_finished\\\": false\\n },\\n {\\n \\\"task_id\\\": \\\"3\\\",\\n \\\"dependent_task_ids\\\": [\\n \\\"2\\\"\\n ],\\n \\\"instruction\\\": \\\"Create a plot visualizing the Iris dataset.\\\",\\n \\\"task_type\\\": \\\"other\\\",\\n \\\"code\\\": \\\"\\\",\\n \\\"result\\\": \\\"\\\",\\n \\\"is_success\\\": false,\\n \\\"is_finished\\\": false\\n }\\n]\\n## Current Task\\n{\\\"task_id\\\":\\\"2\\\",\\\"dependent_task_ids\\\":[\\\"1\\\"],\\\"instruction\\\":\\\"Perform exploratory data analysis on the Iris dataset.\\\",\\\"task_type\\\":\\\"eda\\\",\\\"code\\\":\\\"\\\",\\\"result\\\":\\\"\\\",\\\"is_success\\\":false,\\\"is_finished\\\":false}\\n\"}, {\"role\": \"user\", \"content\": \"\\n# Instruction\\nWrite complete code for 'Current Task'. And avoid duplicating code from finished tasks, such as repeated import of packages, reading data, etc.\\nSpecifically, \\n\\n# Capabilities\\n- You can utilize pre-defined tools in any code lines from 'Available Tools' in the form of Python Class.\\n- You can freely combine the use of any other public packages, like sklearn, numpy, pandas, etc..\\n\\n# Available Tools (can be empty):\\nEach Class tool is described in JSON format. When you call a tool, import the tool first.\\n{}\\n\\n# Constraints:\\n- Ensure the output new code is executable in the same Jupyter notebook with previous tasks code have been executed.\\n- Always prioritize using pre-defined tools for the same functionality.\\n\"}]": {
+ "code": "from sklearn import datasets\nimport pandas as pd\n\n# Load Iris dataset\niris = datasets.load_iris()\ndf_iris = pd.DataFrame(data=iris.data, columns=iris.feature_names)\ndf_iris['target'] = iris.target\n\n# Display basic information about the dataset\nprint(df_iris.info())\n\n# Display statistical summary of the dataset\nprint(df_iris.describe())\n\n# Display the first few rows of the dataset\nprint(df_iris.head())\n\n# Display the distribution of the target variable\ntarget_counts = df_iris['target'].value_counts()\nprint(target_counts)"
+ },
+ "[{\"role\": \"system\", \"content\": \"You are Code Interpreter, a world-class programmer that can complete any goal by executing code. Strictly follow the plan and generate code step by step. Each step of the code will be executed on the user's machine, and the user will provide the code execution results to you.**Notice: The code for the next step depends on the code for the previous step. Must reuse variables in the lastest other code directly, dont creat it again, it is very import for you. Use !pip install in a standalone block to install missing packages.Usually the libraries you need are already installed.Dont check if packages already imported.**\"}, {\"role\": \"user\", \"content\": \"\\n## User Requirement\\nRun data analysis on sklearn Iris dataset, include a plot\\n## Context\\n\\n## Current Plan\\n[\\n {\\n \\\"task_id\\\": \\\"1\\\",\\n \\\"dependent_task_ids\\\": [],\\n \\\"instruction\\\": \\\"Load the sklearn Iris dataset.\\\",\\n \\\"task_type\\\": \\\"other\\\",\\n \\\"code\\\": \\\"\\\",\\n \\\"result\\\": \\\"a successful run\\\",\\n \\\"is_success\\\": true,\\n \\\"is_finished\\\": true\\n },\\n {\\n \\\"task_id\\\": \\\"2\\\",\\n \\\"dependent_task_ids\\\": [\\n \\\"1\\\"\\n ],\\n \\\"instruction\\\": \\\"Perform exploratory data analysis on the Iris dataset.\\\",\\n \\\"task_type\\\": \\\"eda\\\",\\n \\\"code\\\": \\\"\\\",\\n \\\"result\\\": \\\"a successful run\\\",\\n \\\"is_success\\\": true,\\n \\\"is_finished\\\": true\\n },\\n {\\n \\\"task_id\\\": \\\"3\\\",\\n \\\"dependent_task_ids\\\": [\\n \\\"2\\\"\\n ],\\n \\\"instruction\\\": \\\"Create a plot visualizing the Iris dataset.\\\",\\n \\\"task_type\\\": \\\"other\\\",\\n \\\"code\\\": \\\"\\\",\\n \\\"result\\\": \\\"\\\",\\n \\\"is_success\\\": false,\\n \\\"is_finished\\\": false\\n }\\n]\\n## Current Task\\n{\\\"task_id\\\":\\\"3\\\",\\\"dependent_task_ids\\\":[\\\"2\\\"],\\\"instruction\\\":\\\"Create a plot visualizing the Iris dataset.\\\",\\\"task_type\\\":\\\"other\\\",\\\"code\\\":\\\"\\\",\\\"result\\\":\\\"\\\",\\\"is_success\\\":false,\\\"is_finished\\\":false}\\n\"}, {\"role\": \"user\", \"content\": \"\\n# Instruction\\nWrite complete code for 'Current Task'. And avoid duplicating code from finished tasks, such as repeated import of packages, reading data, etc.\\nSpecifically, \\n\\n# Capabilities\\n- You can utilize pre-defined tools in any code lines from 'Available Tools' in the form of Python Class.\\n- You can freely combine the use of any other public packages, like sklearn, numpy, pandas, etc..\\n\\n# Available Tools (can be empty):\\nEach Class tool is described in JSON format. When you call a tool, import the tool first.\\n{}\\n\\n# Constraints:\\n- Ensure the output new code is executable in the same Jupyter notebook with previous tasks code have been executed.\\n- Always prioritize using pre-defined tools for the same functionality.\\n\"}]": {
+ "code": "from sklearn import datasets\nimport matplotlib.pyplot as plt\nimport pandas as pd\n\n# Load Iris dataset\niris = datasets.load_iris()\niris_df = pd.DataFrame(data=iris.data, columns=iris.feature_names)\niris_df['target'] = iris.target\niris_df['target_name'] = iris_df['target'].apply(lambda x: iris.target_names[x])\n\n# Plotting\nfig, ax = plt.subplots(figsize=(12, 8))\nfor target, target_name in zip(iris.target_names, iris.target_names):\n subset = iris_df[iris_df['target_name'] == target_name]\n ax.scatter(subset[iris.feature_names[0]], subset[iris.feature_names[1]], label=target_name)\n\nax.set_xlabel(iris.feature_names[0])\nax.set_ylabel(iris.feature_names[1])\nax.legend()\nplt.show()"
+ },
+ "[{\"role\": \"user\", \"content\": \"\\n# Background\\nAs a data scientist, you need to help user to achieve their goal [This is a titanic passenger survival dataset, your goal is to predict passenger survival outcome. The target column is Survived. Perform data analysis, data preprocessing, feature engineering, and modeling to predict the target. Report accuracy on the eval data. Train data path: 'tests/data/ml_datasets/titanic/split_train.csv', eval data path: 'tests/data/ml_datasets/titanic/split_eval.csv'.] step-by-step in an continuous Jupyter notebook.\\n\\n## Done Tasks\\n```python\\n\\n```end\\n\\n## Current Task\\nPerform exploratory data analysis on the train dataset to understand the features and target variable.\\n\\n# Latest Data Info\\nLatest data info after previous tasks:\\n\\n\\n# Task\\nWrite complete code for 'Current Task'. And avoid duplicating code from 'Done Tasks', such as repeated import of packages, reading data, etc.\\nSpecifically, \\n\\n# Output Example:\\nwhen current task is \\\"train a lightgbm model on training data\\\", the code can be like:\\n```python\\n# Step 1: check data type and convert to numeric\\nobj_cols = train.select_dtypes(include='object').columns.tolist()\\n\\nfor col in obj_cols:\\n encoder = LabelEncoder()\\n train[col] = encoder.fit_transform(train[col].unique().tolist() + ['unknown'])\\n test[col] = test[col].apply(lambda x: x if x in encoder.classes_ else 'unknown')\\n test[col] = encoder.transform(test[col])\\n\\n# Step 2: train lightgbm model\\nmodel = LGBMClassifier()\\nmodel.fit(train, y_train)\\n```end\\n\\n# Constraints:\\n- Ensure the output new code is executable in the same Jupyter notebook with previous tasks code have been executed.\\n\"}]": {
+ "code": "# Perform exploratory data analysis on the train dataset\ndf_train = pd.read_csv('tests/data/ml_datasets/titanic/split_train.csv')\n\n# Display the first few rows of the dataset\ndisplay(df_train.head())\n\n# Summary statistics for numerical features\ndisplay(df_train.describe())\n\n# Summary information about the dataset including the data types and number of non-null values\ndisplay(df_train.info())\n\n# Distribution of the target variable 'Survived'\nsurvival_counts = df_train['Survived'].value_counts()\nprint(\"Survival counts:\\n\", survival_counts)\n\n# Visualizations\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\n# Distribution of the target variable\nsns.countplot(x='Survived', data=df_train)\nplt.title('Distribution of Survival')\nplt.show()\n\n# Correlation matrix heatmap to understand the relationship between features\nplt.figure(figsize=(10, 8))\nsns.heatmap(df_train.corr(), annot=True, fmt='.2f')\nplt.title('Correlation Matrix')\nplt.show()\n\n# Pairplot to visualize the pairwise relationships between features\nsns.pairplot(df_train, hue='Survived')\nplt.title('Pairplot of Features')\nplt.show()"
+ },
+ "[{\"role\": \"system\", \"content\": \"You are an AI Python assistant. You will be given your previous implementation code of a task, runtime error results, and a hint to change the implementation appropriately. Write your full implementation \"}, {\"role\": \"user\", \"content\": \"\\nHere is an example for you.\\n\\nExample 1:\\n[previous impl]:\\n```python\\ndef add(a: int, b: int) -> int:\\n \\\"\\\"\\\"\\n Given integers a and b, return the total value of a and b.\\n \\\"\\\"\\\"\\n return a - b\\n```\\n\\n[runtime Error]:\\nTested passed:\\n\\nTests failed:\\nassert add(1, 2) == 3 # output: -1\\nassert add(1, 2) == 4 # output: -1\\n\\n[reflection on previous impl]:\\nThe implementation failed the test cases where the input integers are 1 and 2. The issue arises because the code does not add the two integers together, but instead subtracts the second integer from the first. To fix this issue, we should change the operator from `-` to `+` in the return statement. This will ensure that the function returns the correct output for the given input.\\n\\n[improved impl]:\\n```python\\ndef add(a: int, b: int) -> int:\\n \\\"\\\"\\\"\\n Given integers a and b, return the total value of a and b.\\n \\\"\\\"\\\"\\n return a + b\\n```\\n\\n[context]\\nSolve the problem in Python:\\ndef sort_array(arr):\\n \\\"\\\"\\\"\\n In this Kata, you have to sort an array of non-negative integers according to\\n number of ones in their binary representation in ascending order.\\n For similar number of ones, sort based on decimal value.\\n\\n It must be implemented like this:\\n >>> sort_array([1, 5, 2, 3, 4]) == [1, 2, 3, 4, 5]\\n >>> sort_array([-2, -3, -4, -5, -6]) == [-6, -5, -4, -3, -2]\\n >>> sort_array([1, 0, 2, 3, 4]) [0, 1, 2, 3, 4]\\n \\\"\\\"\\\"\\n\\n\\n[previous impl]\\n\\ndef sort_array(arr):\\n # Helper function to count the number of ones in the binary representation\\n def count_ones(n):\\n return bin(n).count('1')\\n \\n # Sort the array using a custom key function\\n # The key function returns a tuple (number of ones, value) for each element\\n # This ensures that if two elements have the same number of ones, they are sorted by their value\\n sorted_arr = sorted(arr, key=lambda x: (count_ones(x), x))\\n \\n return sorted_arr\\n```\\n\\n[runtime Error]\\n[user: Tested passed:\\n\\nTests failed:\\nassert sort_array([1, 5, 2, 3, 4]) == [1, 2, 3, 4, 5] # output: [1, 2, 4, 3, 5]\\n]\\n\\nAnalysis the error step by step, provide me improve method and code. Remember to follow [context] requirement. Don't forget write code for steps behind the error step.\\n[reflection on previous impl]:\\nxxx\\n\"}]": {
+ "reflection": "The implementation failed the test case where the input array is [1, 5, 2, 3, 4]. The issue arises because the code does not handle the sorting of elements with the same number of ones in their binary representation correctly. According to the context, for similar number of ones, the elements should be sorted based on their decimal value in ascending order. However, the output [1, 2, 4, 3, 5] shows that 3 and 4 are not in the correct order, indicating that the sorting by decimal value is not functioning as intended. To fix this issue, we should ensure that the sorting is stable, so that when two elements have the same number of ones, they maintain their relative order if their decimal values are already in ascending order.",
+ "improved_impl": "def sort_array(arr):\n # Helper function to count the number of ones in the binary representation\n def count_ones(n):\n return bin(n).count('1')\n \n # Sort the array using a custom key function\n # The key function returns a tuple (number of ones, value) for each element\n # This ensures that if two elements have the same number of ones, they are sorted by their value\n # We use a stable sorting algorithm to maintain the relative order of elements with the same number of ones\n sorted_arr = sorted(arr, key=lambda x: (count_ones(x), x), reverse=True)\n sorted_arr = sorted(sorted_arr, key=count_ones)\n \n return sorted_arr\n"
+ },
+ "[{\"role\": \"system\", \"content\": \"You are Code Interpreter, a world-class programmer that can complete any goal by executing code. Strictly follow the plan and generate code step by step. Each step of the code will be executed on the user's machine, and the user will provide the code execution results to you.**Notice: The code for the next step depends on the code for the previous step. Must reuse variables in the lastest other code directly, dont creat it again, it is very import for you. Use !pip install in a standalone block to install missing packages.Usually the libraries you need are already installed.Dont check if packages already imported.**\"}, {\"role\": \"user\", \"content\": \"\\n## User Requirement\\nRun data analysis on sklearn Iris dataset, include a plot\\n## Context\\n\\n## Current Plan\\n[\\n {\\n \\\"task_id\\\": \\\"1\\\",\\n \\\"dependent_task_ids\\\": [],\\n \\\"instruction\\\": \\\"Load the sklearn Iris dataset.\\\",\\n \\\"task_type\\\": \\\"other\\\",\\n \\\"code\\\": \\\"from sklearn.datasets import load_iris\\\\niris_data = load_iris()\\\",\\n \\\"result\\\": \\\"a successful run\\\",\\n \\\"is_success\\\": true,\\n \\\"is_finished\\\": true\\n },\\n {\\n \\\"task_id\\\": \\\"2\\\",\\n \\\"dependent_task_ids\\\": [\\n \\\"1\\\"\\n ],\\n \\\"instruction\\\": \\\"Perform exploratory data analysis on the Iris dataset.\\\",\\n \\\"task_type\\\": \\\"eda\\\",\\n \\\"code\\\": \\\"\\\",\\n \\\"result\\\": \\\"\\\",\\n \\\"is_success\\\": false,\\n \\\"is_finished\\\": false\\n },\\n {\\n \\\"task_id\\\": \\\"3\\\",\\n \\\"dependent_task_ids\\\": [\\n \\\"2\\\"\\n ],\\n \\\"instruction\\\": \\\"Create a plot visualizing the Iris dataset.\\\",\\n \\\"task_type\\\": \\\"other\\\",\\n \\\"code\\\": \\\"\\\",\\n \\\"result\\\": \\\"\\\",\\n \\\"is_success\\\": false,\\n \\\"is_finished\\\": false\\n }\\n]\\n## Current Task\\n{\\\"task_id\\\":\\\"2\\\",\\\"dependent_task_ids\\\":[\\\"1\\\"],\\\"instruction\\\":\\\"Perform exploratory data analysis on the Iris dataset.\\\",\\\"task_type\\\":\\\"eda\\\",\\\"code\\\":\\\"\\\",\\\"result\\\":\\\"\\\",\\\"is_success\\\":false,\\\"is_finished\\\":false}\\n\"}, {\"role\": \"user\", \"content\": \"\\n# Instruction\\nWrite complete code for 'Current Task'. And avoid duplicating code from finished tasks, such as repeated import of packages, reading data, etc.\\nSpecifically, \\n\\n# Capabilities\\n- You can utilize pre-defined tools in any code lines from 'Available Tools' in the form of Python Class.\\n- You can freely combine the use of any other public packages, like sklearn, numpy, pandas, etc..\\n\\n# Available Tools (can be empty):\\nEach Class tool is described in JSON format. When you call a tool, import the tool first.\\n{}\\n\\n# Constraints:\\n- Ensure the output new code is executable in the same Jupyter notebook with previous tasks code have been executed.\\n- Always prioritize using pre-defined tools for the same functionality.\\n\"}]": {
+ "code": "import pandas as pd\n\n# Convert the Iris dataset to a DataFrame for easier manipulation\niris_df = pd.DataFrame(data=iris_data.data, columns=iris_data.feature_names)\niris_df['target'] = iris_data.target\niris_df['target_names'] = iris_df['target'].apply(lambda x: iris_data.target_names[x])\n\n# Display basic information about the dataset\niris_df.info()\n\n# Display statistical summary of the dataset\niris_df.describe()\n\n# Display the first few rows of the dataset\ndisplay(iris_df.head())"
+ },
+ "[{\"role\": \"system\", \"content\": \"You are Code Interpreter, a world-class programmer that can complete any goal by executing code. Strictly follow the plan and generate code step by step. Each step of the code will be executed on the user's machine, and the user will provide the code execution results to you.**Notice: The code for the next step depends on the code for the previous step. Must reuse variables in the lastest other code directly, dont creat it again, it is very import for you. Use !pip install in a standalone block to install missing packages.Usually the libraries you need are already installed.Dont check if packages already imported.**\"}, {\"role\": \"user\", \"content\": \"\\n## User Requirement\\nRun data analysis on sklearn Iris dataset, include a plot\\n## Context\\n\\n## Current Plan\\n[\\n {\\n \\\"task_id\\\": \\\"1\\\",\\n \\\"dependent_task_ids\\\": [],\\n \\\"instruction\\\": \\\"Load the sklearn Iris dataset.\\\",\\n \\\"task_type\\\": \\\"other\\\",\\n \\\"code\\\": \\\"from sklearn.datasets import load_iris\\\\niris_data = load_iris()\\\",\\n \\\"result\\\": \\\"a successful run\\\",\\n \\\"is_success\\\": true,\\n \\\"is_finished\\\": true\\n },\\n {\\n \\\"task_id\\\": \\\"2\\\",\\n \\\"dependent_task_ids\\\": [\\n \\\"1\\\"\\n ],\\n \\\"instruction\\\": \\\"Perform exploratory data analysis on the Iris dataset.\\\",\\n \\\"task_type\\\": \\\"eda\\\",\\n \\\"code\\\": \\\"import pandas as pd\\\\n\\\\n# Convert the Iris dataset to a DataFrame for easier manipulation\\\\niris_df = pd.DataFrame(data=iris_data.data, columns=iris_data.feature_names)\\\\niris_df['target'] = iris_data.target\\\\niris_df['target_names'] = iris_df['target'].apply(lambda x: iris_data.target_names[x])\\\\n\\\\n# Display basic information about the dataset\\\\niris_df.info()\\\\n\\\\n# Display statistical summary of the dataset\\\\niris_df.describe()\\\\n\\\\n# Display the first few rows of the dataset\\\\ndisplay(iris_df.head())\\\",\\n \\\"result\\\": \\\"a successful run\\\",\\n \\\"is_success\\\": true,\\n \\\"is_finished\\\": true\\n },\\n {\\n \\\"task_id\\\": \\\"3\\\",\\n \\\"dependent_task_ids\\\": [\\n \\\"2\\\"\\n ],\\n \\\"instruction\\\": \\\"Create a plot visualizing the Iris dataset.\\\",\\n \\\"task_type\\\": \\\"other\\\",\\n \\\"code\\\": \\\"\\\",\\n \\\"result\\\": \\\"\\\",\\n \\\"is_success\\\": false,\\n \\\"is_finished\\\": false\\n }\\n]\\n## Current Task\\n{\\\"task_id\\\":\\\"3\\\",\\\"dependent_task_ids\\\":[\\\"2\\\"],\\\"instruction\\\":\\\"Create a plot visualizing the Iris dataset.\\\",\\\"task_type\\\":\\\"other\\\",\\\"code\\\":\\\"\\\",\\\"result\\\":\\\"\\\",\\\"is_success\\\":false,\\\"is_finished\\\":false}\\n\"}, {\"role\": \"user\", \"content\": \"\\n# Instruction\\nWrite complete code for 'Current Task'. And avoid duplicating code from finished tasks, such as repeated import of packages, reading data, etc.\\nSpecifically, \\n\\n# Capabilities\\n- You can utilize pre-defined tools in any code lines from 'Available Tools' in the form of Python Class.\\n- You can freely combine the use of any other public packages, like sklearn, numpy, pandas, etc..\\n\\n# Available Tools (can be empty):\\nEach Class tool is described in JSON format. When you call a tool, import the tool first.\\n{}\\n\\n# Constraints:\\n- Ensure the output new code is executable in the same Jupyter notebook with previous tasks code have been executed.\\n- Always prioritize using pre-defined tools for the same functionality.\\n\"}]": {
+ "code": "import matplotlib.pyplot as plt\nimport seaborn as sns\n\n# Set the style of seaborn\nsns.set_style('whitegrid')\n\n# Pairplot to visualize the relationships between features\nsns.pairplot(iris_df, hue='target_names', markers='+')\nplt.show()"
+ },
+ "\n## context\n\n\n-----\n\n## format example\n[CONTENT]\n{\n \"invoice\": \"False\"\n}\n[/CONTENT]\n\n## nodes: \": # \"\n- invoice: # if it's a invoice file, return True else False\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 \"invoice\": \"True\"\n}\n[/CONTENT]"
}
\ No newline at end of file
diff --git a/tests/data/search_rsp_cache.json b/tests/data/search_rsp_cache.json
index 822fb2069..7b4cc583c 100644
--- a/tests/data/search_rsp_cache.json
+++ b/tests/data/search_rsp_cache.json
@@ -875,5 +875,121 @@
"curl-cffi-POST-https://duckduckgo.com-{\"data\": {\"q\": \"Dataiku vs DataRobot features\"}}": "Dataiku vs DataRobot features at DuckDuckGo