mirror of
https://github.com/FoundationAgents/MetaGPT.git
synced 2026-04-27 01:36:29 +02:00
Merge branch 'fix/use_template_bad_case' into 'mgx_ops'
修复使用框架产生的Bad Cases See merge request pub/MetaGPT!398
This commit is contained in:
commit
ebea2c07d9
6 changed files with 69 additions and 78 deletions
|
|
@ -27,41 +27,6 @@ Note:
|
|||
6. To avoid syntax errors when editing files multiple times, consider opening the file to view the surrounding code related to the error line and make modifications based on this context.
|
||||
7. Ensure to observe the currently open file and the current working directory, which is displayed right after the open file. The open file might be in a different directory than the working directory. Remember, commands like 'create' open files and might alter the current open file.
|
||||
8. Effectively using Use search commands (`search_dir`, `search_file`, `find_file`) and navigation commands (`open_file`, `goto_line`) to locate and modify files efficiently. The Editor tool can fully satisfy the requirements. Follow these steps and considerations for optimal results:
|
||||
**General Search Guidelines:**
|
||||
- Ensure you are in the repository's root directory before starting your search.
|
||||
- Always double-check the current working directory and the currently open file to avoid confusion.
|
||||
- Avoid repeating failed search commands without modifications to improve efficiency.
|
||||
|
||||
**Strategies for Searching and Navigating Files:**
|
||||
|
||||
1. **If you know the file's location:**
|
||||
- Use the `open_file` command directly to open the file.
|
||||
- Use `search_file` to find the `search_term` within the currently open file.
|
||||
- Alternatively, use the `goto_line` command to jump to the specified line.
|
||||
- **Boundary Consideration:** Ensure the file path is correctly specified and accessible.
|
||||
|
||||
2. **If you know the filename but not the exact location:**
|
||||
- Use `find_file` to locate the file in the directory.
|
||||
- Use `open_file` to open the file once located.
|
||||
- Use `search_file` to find the `search_term` within the file.
|
||||
- Use `goto_line` to jump to the specified line if needed.
|
||||
- **Boundary Consideration:** Handle cases where the file may exist in multiple directories by verifying the correct path before opening.
|
||||
|
||||
3. **If you know the symbol but not the file's location:**
|
||||
- Use "search_dir" to find files containing the symbol within the directory.
|
||||
- Review the search results to identify the relevant file(s).
|
||||
- Use `open_file` to open the identified file.
|
||||
- Use `search_file` to locate the `search_term` within the open file.
|
||||
- Use `goto_line` to jump to the specified line.
|
||||
- **Boundary Consideration:** Be thorough in reviewing multiple search results to ensure you open the correct file. Consider using more specific search terms if initial searches return too many results.
|
||||
|
||||
**Search Tips:**
|
||||
- The `<search_term>` for `search_dir`, `find_file`, or `search_file` should be an existing class name, function name, or file name.
|
||||
- Enclose terms like `def` or `class` in quotes when searching for functions or classes (e.g., `search_dir 'def apow'` or `search_file 'class Pow'`).
|
||||
- Use wildcard characters (`*`, `?`) in search terms to broaden or narrow down your search scope.
|
||||
- If search commands return too many results, refine your search criteria or use more specific terms.
|
||||
- If a search command fails, modify the search criteria, check for search_term or paths, and then try again.
|
||||
- Based on feedback of observation or Terminal command in trajectory to guide adjustments in your search strategy.
|
||||
|
||||
9. When the edit fails, try to enlarge the range of code.
|
||||
10. You must use the Editor.open_file command to open a file before using the Editor tool's edit command to modify it. When you open a file, any currently open file will be automatically closed.
|
||||
|
|
@ -70,7 +35,7 @@ Note:
|
|||
12. If you choose Editor.insert_content_at_line, you must ensure that there is no duplication between the inserted content and the original code. If there is overlap between the new code and the original code, use Editor.edit_file_by_replace instead.
|
||||
13. If you choose Editor.edit_file_by_replace, the original code that needs to be replaced must start at the beginning of the line and end at the end of the line
|
||||
14. When not specified, you should write files in a folder named "{{project_name}}". The project name is the name of the project which meets the user's requirements.
|
||||
15. When provided system design or project schedule, you MUST read them first before making a plan, then adhere to them in your implementation, especially in the programming language, package, or framework. You MUST implement all code files prescribed in the system design or project schedule. You can create a plan first with each task corresponding to implementing one code file.
|
||||
15. When provided system design or project schedule, you MUST read them first before making a plan, then adhere to them in your implementation, especially in the programming language, package, or framework. You MUST implement all code files prescribed in the system design or project schedule.
|
||||
16. When planning, initially list the files for coding, then outline all coding tasks based on the file organization in your first response.
|
||||
17. If you plan to read a file, do not include other plans in the same response.
|
||||
18. Write only one code file each time and provide its full implementation.
|
||||
|
|
@ -82,10 +47,12 @@ Note:
|
|||
24. Follow the Sytem Design and Project Schedule if exists. Otherwise, use default template folder of Vite, React, MUI and Tailwind CSS. The React template is in the "{react_template_path}" and Vue template is in the "{vue_template_path}". If the template does not exist, use native HTML.
|
||||
25. When writing Vue/React project:
|
||||
25.1. Create the project folder first. Use cmd " mkdir -p {{project_name}} "
|
||||
25.2. Copy a Vue/React template to your project and view all files. This must be a single respond. Use cmd "cp -r {{template_folder}}/* {{workspace}}/{{project_name}}/ && cd {{workspace}}/{{project_name}} && pwd && tree -f".
|
||||
25.3. Read the content of each file and use the write_new_code command to rewrite the code. Be sure you are in the {{project_name}}.
|
||||
25.4. After finish the project. use "pnpm install" and "pnpm run build" to build the project and then use Deployer.deploy_to_public to deploy the project to the public.
|
||||
25.2. Copy a Vue/React template to your project folder, move into it and list the file in it. This must be a single respond. Use cmd "cp -r {{template_folder}}/* {{workspace}}/{{project_name}}/ && cd {{workspace}}/{{project_name}} && pwd && tree -f".
|
||||
25.3. User Editor.read to read the content of files in the src and read the index.html in the project root before making a plan.
|
||||
25.4. List the files that you need to rewrite and create when making a plan. Indicate clearly what file to rewrite or create in each task. "index.html" and all files in the src folder always must be rewritten. Use Tailwind CSS for styling. Notice that you are in {{project_name}}.
|
||||
25.5. After finish the project. use "pnpm install && pnpm run build" to build the project and then deploy the project to the public using the dist folder which contains the built project.
|
||||
26. Engineer2.write_new_code is used to write or rewrite the code, which will modify the whole file. Editor.edit_file_by_replace is used to edit a small part of the file.
|
||||
27. Deploye the project to the public after you install and build the project, there will be a folder named "dist" in the current directory after the build.
|
||||
""".format(
|
||||
vue_template_path=VUE_TEMPLATE_PATH.absolute(),
|
||||
react_template_path=REACT_TEMPLATE_PATH.absolute(),
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ CMD_EXPERIENCE_MASK = f"""
|
|||
CMD_PROMPT = (
|
||||
CMD_EXPERIENCE_MASK
|
||||
+ """
|
||||
# Tool State
|
||||
{current_state}
|
||||
|
||||
# Current Plan
|
||||
|
|
@ -74,9 +75,9 @@ You may use any of the available commands to create a plan or update the plan. Y
|
|||
If you finish current task, you will automatically take the next task in the existing plan, use Plan.finish_current_task, DON'T append a new task.
|
||||
Review the latest plan's outcome, focusing on achievements. If your completed task matches the current, consider it finished.
|
||||
Using Editor.insert_content_at_line and Editor.edit_file_by_replace more than once in the current command list is forbidden. Because the command is mutually exclusive and will change the line number after execution.
|
||||
In your response, include at least one command.
|
||||
In your response, include at least one command. If you want to stop, use {{"command_name":"end"}} command.
|
||||
|
||||
# Your commands in a json array, in the following output format with correct command_name and args. If there is nothing to do, use the pass or end command:
|
||||
# Your commands in a json array, in the following output format with correct command_name and args.
|
||||
Some text indicating your thoughts before JSON is required, such as what tasks have been completed, what tasks are next, how you should update the plan status, respond to inquiry, or seek for help. Then a json array of commands. You must output ONE and ONLY ONE json array. DON'T output multiple json arrays with thoughts between them.
|
||||
Output should adhere to the following format.
|
||||
```json
|
||||
|
|
@ -244,14 +245,14 @@ Reply : The herb names have been successfully extracted. A total of 8 herb names
|
|||
------------
|
||||
|
||||
Carefully review the history and respond to the user in the expected language to meet their requirements.
|
||||
If you have any deliverables that are helpful in explaining the results (such as files, metrics, quantitative results, etc.), provide brief descriptions of them.
|
||||
If you have any deliverables that are helpful in explaining the results (such as deployment URL, files, metrics, quantitative results, etc.), provide brief descriptions of them.
|
||||
Your reply must be concise.
|
||||
You must respond in {respond_language}
|
||||
Directly output your reply content. Do not add any output format.
|
||||
"""
|
||||
SUMMARY_PROMPT = """
|
||||
Summarize what you have accomplished lately. Be concise.
|
||||
If you produce any deliverables, include their short descriptions and file paths. If there are any metrics or quantitative results, include them, too.
|
||||
If you produce any deliverables, include their short descriptions and file paths. If there are any metrics, url or quantitative results, include them, too.
|
||||
If the deliverable is code, only output the file path.
|
||||
"""
|
||||
|
||||
|
|
|
|||
|
|
@ -141,8 +141,17 @@ class Engineer2(RoleZero):
|
|||
return f"The file {path} has been successfully created, with content:\n{code}"
|
||||
|
||||
async def _deploy_to_public(self, dist_dir):
|
||||
"""fix the dist_dir path to absolute path before deploying"""
|
||||
dist_dir = self.editor._try_fix_path(dist_dir)
|
||||
"""fix the dist_dir path to absolute path before deploying
|
||||
Args:
|
||||
dist_dir (str): The dist directory of the web project after run build. This must be an absolute path.
|
||||
"""
|
||||
# Try to fix the path with the editor's working directory.
|
||||
if not Path(dist_dir).is_absolute():
|
||||
default_dir = self.editor._try_fix_path(dist_dir)
|
||||
if not default_dir.exists():
|
||||
raise ValueError("dist_dir must be an absolute path.")
|
||||
else:
|
||||
dist_dir = default_dir
|
||||
return await self.deployer.deploy_to_public(dist_dir)
|
||||
|
||||
async def _eval_terminal_run(self, cmd):
|
||||
|
|
|
|||
|
|
@ -845,20 +845,11 @@ Explanation: This is a project that needs to be implemented using Vue.js. Theref
|
|||
|
||||
## example 3
|
||||
User Requirement: Writing code.
|
||||
The template is :
|
||||
├── public
|
||||
├── src
|
||||
│ ├── App.jsx
|
||||
│ ├── index.css
|
||||
│ └── main.jsx
|
||||
└── vite.config.js
|
||||
|
||||
Here's the plan:
|
||||
[Optional] Read the original file in the template if they exist.
|
||||
[Optional] Obtain images before coding.
|
||||
1. **Task 1**: Rewrite `App.jsx` - This file will contain the Vue structure necessary for the game's UI, the game logic and UI interactions.
|
||||
2. **Task 2**: Rewrite `style.css` - This file will define the CSS styles to make the game visually appealing and responsive. Default use tailwindcss.
|
||||
3. **Task 3**: Rewrite `main.js` - This file is the main entry of Vue project, including the main Vue instance, global styles, and the router.
|
||||
Here's the Plan
|
||||
1. Rewrite the code index.html and the code in src folder. Specifically, this includes the index.html, src/main.jsx, src/index.css, and src/App.jsx. which is the main structure file, entry point of the project, the global style file, and the main component. All these files must Use Tailwind CSS for styling
|
||||
2. Create new files when needed. In the current ecommerce website project, I need to create homepage.jsx, product.jsx.
|
||||
3. Install, build and deploy after the project is finished.
|
||||
If the project is a Vue or React Project, install the dependencies after finishing project. And then deploy the project to the public.
|
||||
```json
|
||||
[
|
||||
|
|
@ -867,7 +858,7 @@ If the project is a Vue or React Project, install the dependencies after finishi
|
|||
"args": {
|
||||
"task_id": "1",
|
||||
"dependent_task_ids": [],
|
||||
"instruction": "Read the original file in the template if they exist.",
|
||||
"instruction": "Rewrite the index.html file with the project title and main entry point.",
|
||||
"assignee": "Alex"
|
||||
}
|
||||
},
|
||||
|
|
@ -875,8 +866,8 @@ If the project is a Vue or React Project, install the dependencies after finishi
|
|||
"command_name": "Plan.append_task",
|
||||
"args": {
|
||||
"task_id": "2",
|
||||
"dependent_task_ids": [],
|
||||
"instruction": "Create the App.vue file with the game's UI, the game logic and UI interactions, the style will implemented in the global style file using Tailwind CSS.",
|
||||
"dependent_task_ids": ["1"],
|
||||
"instruction": "Rewrite the src/App.jsx file, which is the main component. Use Tailwind CSS for styling",
|
||||
"assignee": "Alex"
|
||||
}
|
||||
},
|
||||
|
|
@ -885,7 +876,7 @@ If the project is a Vue or React Project, install the dependencies after finishi
|
|||
"args": {
|
||||
"task_id": "3",
|
||||
"dependent_task_ids": ["2"],
|
||||
"instruction": "Create the style.css file with Tailwind CSS for the 2048 Game.",
|
||||
"instruction": "Rewrite the src/style.css file with Tailwind CSS.",
|
||||
"assignee": "Alex"
|
||||
}
|
||||
},
|
||||
|
|
@ -894,7 +885,7 @@ If the project is a Vue or React Project, install the dependencies after finishi
|
|||
"args": {
|
||||
"task_id": "4",
|
||||
"dependent_task_ids": ["2","3"],
|
||||
"instruction": "Create the main.js, which will include the main Vue instance, global styles, and the router.",
|
||||
"instruction": "Rewrite the src/main.js, which will include the main Vue instance, global styles, and the router.",
|
||||
"assignee": "Alex"
|
||||
}
|
||||
},
|
||||
|
|
@ -902,6 +893,24 @@ If the project is a Vue or React Project, install the dependencies after finishi
|
|||
"command_name": "Plan.append_task",
|
||||
"args": {
|
||||
"task_id": "5",
|
||||
"dependent_task_ids": ["2","3","4"],
|
||||
"instruction": "Create the src/homepage.jsx, which will include the homepage content. Use Tailwind CSS for styling",
|
||||
"assignee": "Alex"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command_name": "Plan.append_task",
|
||||
"args": {
|
||||
"task_id": "6",
|
||||
"dependent_task_ids": ["2","3","4","5"],
|
||||
"instruction": "Create the src/product.js, which will include the product detail page. Use Tailwind CSS for styling",
|
||||
"assignee": "Alex"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command_name": "Plan.append_task",
|
||||
"args": {
|
||||
"task_id": "7",
|
||||
"dependent_task_ids": [],
|
||||
"instruction": "Install the necessary dependencies, configure the project structure and deploy it to the public",
|
||||
"assignee": "Alex"
|
||||
|
|
@ -928,7 +937,7 @@ Explanation: Take on one task, such as writing or rewriting a file. Upon complet
|
|||
]
|
||||
```
|
||||
## example 5
|
||||
Explanation: The project have been completed. And this project is a Vue/React Project,so i will deploy the project to the public.
|
||||
Explanation: The project have been completed. This project is Vue/React Project, I will install and build the project to create static dist folder in the current project folder.
|
||||
|
||||
```json
|
||||
[
|
||||
|
|
@ -940,13 +949,13 @@ Explanation: The project have been completed. And this project is a Vue/React Pr
|
|||
}
|
||||
]
|
||||
## example 6
|
||||
Explanation: After install the project. I will deploy the project to the public.
|
||||
Explanation: After install and build the project, static dist is created in the current project folder. I will deploy the project to the public.
|
||||
```json
|
||||
[
|
||||
{
|
||||
"command_name": "Deployer.deploy_to_public,
|
||||
"args": {
|
||||
"dist_dir": "{{project_path}}/dist"
|
||||
"dist_dir": "/example/dist"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -792,19 +792,21 @@ class Editor(BaseModel):
|
|||
("last", last_replaced_line_number, last_replaced_line_content),
|
||||
]
|
||||
for position, line_number, line_content in check_list:
|
||||
if lines[line_number - 1].rstrip() != line_content:
|
||||
if line_number > len(lines) or lines[line_number - 1].rstrip() != line_content:
|
||||
start = max(1, line_number - 3)
|
||||
end = min(total_lines, line_number + 3)
|
||||
context = "\n".join(
|
||||
[
|
||||
f'The {line_number:03d} line is "{lines[line_number-1].rstrip()}"'
|
||||
for line_number in range(start, end + 1)
|
||||
f'The {cur_line_number:03d} line is "{lines[cur_line_number-1].rstrip()}"'
|
||||
for cur_line_number in range(start, end + 1)
|
||||
]
|
||||
)
|
||||
mismatch_error += LINE_NUMBER_AND_CONTENT_MISMATCH.format(
|
||||
position=position,
|
||||
line_number=line_number,
|
||||
true_content=lines[line_number - 1].rstrip(),
|
||||
true_content=lines[line_number - 1].rstrip()
|
||||
if line_number - 1 < len(lines)
|
||||
else "OUT OF FILE RANGE!",
|
||||
fake_content=line_content.replace("\n", "\\n"),
|
||||
context=context.strip(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import asyncio
|
||||
import os
|
||||
import re
|
||||
from asyncio import Queue
|
||||
from asyncio.subprocess import PIPE, STDOUT
|
||||
from typing import Optional
|
||||
|
||||
from metagpt.config2 import Config
|
||||
from metagpt.const import DEFAULT_WORKSPACE_ROOT, SWE_SETUP_PATH
|
||||
from metagpt.const import SWE_SETUP_PATH
|
||||
from metagpt.logs import logger
|
||||
from metagpt.tools.tool_registry import register_tool
|
||||
from metagpt.utils.report import END_MARKER_VALUE, TerminalReporter
|
||||
|
|
@ -28,8 +29,9 @@ class Terminal:
|
|||
self.process: Optional[asyncio.subprocess.Process] = None
|
||||
# The cmd in forbidden_terminal_commands will be replace by pass ana return the advise. example:{"cmd":"forbidden_reason/advice"}
|
||||
self.forbidden_commands = {
|
||||
"npm run dev": "Use Deployer.deploy_to_public instead.",
|
||||
"pnpm run dev": "Use Deployer.deploy_to_public instead.",
|
||||
"run dev": "Use Deployer.deploy_to_public instead.",
|
||||
# serve cmd have a space behind it,
|
||||
"serve ": "Use Deployer.deploy_to_public instead.",
|
||||
}
|
||||
|
||||
async def _start_process(self):
|
||||
|
|
@ -38,8 +40,6 @@ class Terminal:
|
|||
*self.shell_command, stdin=PIPE, stdout=PIPE, stderr=STDOUT, executable="bash", env=os.environ.copy()
|
||||
)
|
||||
await self._check_state()
|
||||
# Goto the default directory
|
||||
await self.run_command(f"cd {DEFAULT_WORKSPACE_ROOT.absolute()}")
|
||||
|
||||
async def _check_state(self):
|
||||
"""
|
||||
|
|
@ -67,11 +67,14 @@ class Terminal:
|
|||
|
||||
output = ""
|
||||
# Remove forbidden commands
|
||||
commands = re.split(r"\s*&&\s*", cmd)
|
||||
for cmd_name, reason in self.forbidden_commands.items():
|
||||
# "true" is a pass command in linux terminal.
|
||||
if cmd_name in cmd:
|
||||
cmd = cmd.replace(cmd_name, "true")
|
||||
output += f"Failed to execut {cmd_name}. {reason}\n"
|
||||
for index, command in enumerate(commands):
|
||||
if cmd_name in command:
|
||||
output += f"Failed to execut {command}. {reason}\n"
|
||||
commands[index] = "true"
|
||||
cmd = " && ".join(commands)
|
||||
|
||||
# Send the command
|
||||
self.process.stdin.write((cmd + self.command_terminator).encode())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue