mirror of
https://github.com/FoundationAgents/MetaGPT.git
synced 2026-06-14 15:25:17 +02:00
Merge branch 'main' into reasoning
This commit is contained in:
commit
08587f392f
339 changed files with 22997 additions and 1437 deletions
15
examples/cr.py
Normal file
15
examples/cr.py
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import fire
|
||||
|
||||
from metagpt.roles.di.engineer2 import Engineer2
|
||||
from metagpt.tools.libs.cr import CodeReview
|
||||
|
||||
|
||||
async def main(msg):
|
||||
role = Engineer2(tools=["Plan", "Editor:write,read", "RoleZero", "ValidateAndRewriteCode", "CodeReview"])
|
||||
cr = CodeReview()
|
||||
role.tool_execution_map.update({"CodeReview.review": cr.review, "CodeReview.fix": cr.fix})
|
||||
await role.run(msg)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
fire.Fire(main)
|
||||
BIN
examples/data/di/dog.jpg
Normal file
BIN
examples/data/di/dog.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
examples/data/di/receipt_shopping.jpg
Normal file
BIN
examples/data/di/receipt_shopping.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
24
examples/data/exp_pool/engineer_exps.json
Normal file
24
examples/data/exp_pool/engineer_exps.json
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
[
|
||||
{
|
||||
"req": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "\n# Current Plan\n{'goal': \"Please write a 1048 game using JavaScript and HTML code without using any frameworks, user can play with keyboard. Refer to the system design located at '/tmp/system_design.json' and the project schedule at '/tmp/project_schedule.json' for detailed information.\", 'tasks': []}\n\n# Current Task\n\n\n# Instruction\nBased on the context, write a plan or modify an existing plan to achieve the goal. A plan consists of one to 3 tasks.\nIf plan is created, you should track the progress and update the plan accordingly, such as Plan.finish_current_task, Plan.append_task, Plan.reset_task, Plan.replace_task, etc.\nWhen presented a current task, tackle the task using the available commands.\nPay close attention to new user message, review the conversation history, use RoleZero.reply_to_human to respond to new user requirement.\nNote:\n1. If you keeping encountering errors, unexpected situation, or you are not sure of proceeding, use RoleZero.ask_human to ask for help.\n2. Carefully review your progress at the current task, if your actions so far has not fulfilled the task instruction, you should continue with current task. Otherwise, finish current task.\n3. Each time you finish a task, use RoleZero.reply_to_human to report your progress.\n4. Each time you write a code in your response, write with the Editor directly without preparing a repetitive code block beforehand.\n5. Take on ONE task and write ONE code file in each response. DON'T attempt all tasks in one response.\n6. When not specified, you should write files in a folder named \"src\". If you know the project path, then write in a \"src\" folder under the project path.\n7. 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.\n8. Write at most one file per task, do your best to implement THE ONLY ONE FILE. CAREFULLY CHECK THAT YOU DONT MISS ANY NECESSARY CLASS/FUNCTION IN THIS FILE.\n9. COMPLETE CODE: Your code will be part of the entire project, so please implement complete, reliable, reusable code snippets.\n10. When provided system 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.\n11. Write out EVERY CODE DETAIL, DON'T LEAVE TODO.\n12. To modify code in a file, read the entire file, make changes, and update the file with the complete code, ensuring that no line numbers are included in the final write.\n13. When a system design or project schedule is provided, at the end of the plan, add a CodeRview Task for each file; for example, if there are three files, add three CodeRview Tasks. For each CodeRview Task, just call ValidateAndRewriteCode.run.\n"
|
||||
}
|
||||
],
|
||||
"resp": "\nExplanation: To begin the task of creating a 2048 game using JavaScript and HTML, I need to first read the system design and project schedule documents to understand the specific requirements and architecture outlined for the game development.\n\n```json\n[\n {\n \"command_name\": \"Editor.read\",\n \"args\": {\n \"path\": \"/tmp/system_design.json\"\n }\n },\n {\n \"command_name\": \"Editor.read\",\n \"args\": {\n \"path\": \"/tmp/project_schedule.json\"\n }\n }\n]\n```\n"
|
||||
},
|
||||
{
|
||||
"req": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Command Editor.read executed: file_path='/tmp/system_design.json' block_content='001|{\"Implementation approach\":\"We will implement the 2048 game using plain JavaScript and HTML, ensuring no frameworks are used. The game logic will handle tile movements, merging, and game state updates. The UI will be simple and clean, with a responsive design to fit different screen sizes. We will use CSS for styling and ensure the game is playable with keyboard arrow keys. The game will display the current score, have a restart button, and show a game over message when no more moves are possible.\",\"File list\":[\"index.html\",\"style.css\",\"script.js\"],\"Data structures and interfaces\":\"\\\\nclassDiagram\\\\n class Game {\\\\n -grid: int[][]\\\\n -score: int\\\\n +init(): void\\\\n +move(direction: str): void\\\\n +merge(direction: str): void\\\\n +isGameOver(): bool\\\\n +restart(): void\\\\n }\\\\n class UI {\\\\n -game: Game\\\\n +init(): void\\\\n +update(): void\\\\n +showGameOver(): void\\\\n +bindEvents(): void\\\\n }\\\\n Game --> UI\\\\n\",\"Program call flow\":\"\\\\nsequenceDiagram\\\\n participant U as UI\\\\n participant G as Game\\\\n U->>G: init()\\\\n G-->>U: return\\\\n U->>U: bindEvents()\\\\n U->>G: move(direction)\\\\n G->>G: merge(direction)\\\\n G->>U: update()\\\\n U->>U: update()\\\\n U->>G: isGameOver()\\\\n G-->>U: return bool\\\\n alt Game Over\\\\n U->>U: showGameOver()\\\\n end\\\\n U->>G: restart()\\\\n G-->>U: return\\\\n\",\"Anything UNCLEAR\":\"Clarify if there are any specific design preferences or additional features required beyond the basic 2048 game functionality.\"}\\n'\n\nCommand Editor.read executed: file_path='/tmp/project_schedule.json' block_content='001|{\"Required packages\":[\"No third-party dependencies required\"],\"Required Other language third-party packages\":[\"No third-party dependencies required\"],\"Logic Analysis\":[[\"script.js\",\"Contains Game and UI classes, and their methods: init, move, merge, isGameOver, restart, update, showGameOver, bindEvents\"],[\"index.html\",\"Contains the HTML structure for the game UI\"],[\"style.css\",\"Contains the CSS styles for the game UI\"]],\"Task list\":[\"index.html\",\"style.css\",\"script.js\"],\"Full API spec\":\"\",\"Shared Knowledge\":\"The `script.js` file will contain the core game logic and UI handling. The `index.html` file will provide the structure for the game, and `style.css` will handle the styling.\",\"Anything UNCLEAR\":\"Clarify if there are any specific design preferences or additional features required beyond the basic 2048 game functionality.\"}\\n'"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "\n# Current Plan\n{'goal': \"Please write a 1048 game using JavaScript and HTML code without using any frameworks, user can play with keyboard. Refer to the system design located at '/tmp/system_design.json' and the project schedule at '/tmp/project_schedule.json' for detailed information.\", 'tasks': []}\n\n# Current Task\n\n\n# Instruction\nBased on the context, write a plan or modify an existing plan to achieve the goal. A plan consists of one to 3 tasks.\nIf plan is created, you should track the progress and update the plan accordingly, such as Plan.finish_current_task, Plan.append_task, Plan.reset_task, Plan.replace_task, etc.\nWhen presented a current task, tackle the task using the available commands.\nPay close attention to new user message, review the conversation history, use RoleZero.reply_to_human to respond to new user requirement.\nNote:\n1. If you keeping encountering errors, unexpected situation, or you are not sure of proceeding, use RoleZero.ask_human to ask for help.\n2. Carefully review your progress at the current task, if your actions so far has not fulfilled the task instruction, you should continue with current task. Otherwise, finish current task.\n3. Each time you finish a task, use RoleZero.reply_to_human to report your progress.\n4. Each time you write a code in your response, write with the Editor directly without preparing a repetitive code block beforehand.\n5. Take on ONE task and write ONE code file in each response. DON'T attempt all tasks in one response.\n6. When not specified, you should write files in a folder named \"src\". If you know the project path, then write in a \"src\" folder under the project path.\n7. 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.\n8. Write at most one file per task, do your best to implement THE ONLY ONE FILE. CAREFULLY CHECK THAT YOU DONT MISS ANY NECESSARY CLASS/FUNCTION IN THIS FILE.\n9. COMPLETE CODE: Your code will be part of the entire project, so please implement complete, reliable, reusable code snippets.\n10. When provided system 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.\n11. Write out EVERY CODE DETAIL, DON'T LEAVE TODO.\n12. To modify code in a file, read the entire file, make changes, and update the file with the complete code, ensuring that no line numbers are included in the final write.\n13. When a system design or project schedule is provided, at the end of the plan, add a CodeRview Task for each file; for example, if there are three files, add three CodeRview Tasks. For each CodeRview Task, just call ValidateAndRewriteCode.run.\n"
|
||||
}
|
||||
],
|
||||
"resp": "\nExplanation: Based on the system design and project schedule, I will create a plan to implement the 2048 game. The plan will consist of tasks to create the necessary files (`index.html`, `style.css`, and `script.js`) and review each file to ensure they meet the design specifications.\n\nHere's the plan:\n\n1. **Task 1**: Create `index.html` - This file will contain the HTML structure necessary for the game's UI.\n2. **Task 2**: Create `style.css` - This file will define the CSS styles to make the game visually appealing and responsive.\n3. **Task 3**: Create `script.js` - This file will contain the JavaScript code for the game logic and UI interactions.\n4. **Code Review Tasks**: Review each file to ensure they meet the project requirements and adhere to the system design.\n\nLet's start by appending the first task to the plan.\n\n```json\n[\n {\n \"command_name\": \"Plan.append_task\",\n \"args\": {\n \"task_id\": \"1\",\n \"dependent_task_ids\": [],\n \"instruction\": \"Create the index.html file with the basic HTML structure for the 2048 game.\",\n \"assignee\": \"Alex\"\n }\n },\n {\n \"command_name\": \"Plan.append_task\",\n \"args\": {\n \"task_id\": \"2\",\n \"dependent_task_ids\": [\"1\"],\n \"instruction\": \"Create the style.css file with the necessary CSS to style the 2048 game.\",\n \"assignee\": \"Alex\"\n }\n },\n {\n \"command_name\": \"Plan.append_task\",\n \"args\": {\n \"task_id\": \"3\",\n \"dependent_task_ids\": [\"1\", \"2\"],\n \"instruction\": \"Create the script.js file containing the JavaScript logic for the 2048 game.\",\n \"assignee\": \"Alex\"\n }\n },\n {\n \"command_name\": \"Plan.append_task\",\n \"args\": {\n \"task_id\": \"4\",\n \"dependent_task_ids\": [\"1\"],\n \"instruction\": \"Use ValidateAndRewriteCode to review the code in index.html to ensure it meets the design specifications.\",\n \"assignee\": \"Alex\"\n }\n },\n {\n \"command_name\": \"Plan.append_task\",\n \"args\": {\n \"task_id\": \"5\",\n \"dependent_task_ids\": [\"2\"],\n \"instruction\": \"Use ValidateAndRewriteCode to review the code in style.css to ensure it meets the design specifications.\",\n \"assignee\": \"Alex\"\n }\n },\n {\n \"command_name\": \"Plan.append_task\",\n \"args\": {\n \"task_id\": \"6\",\n \"dependent_task_ids\": [\"3\"],\n \"instruction\": \"Use ValidateAndRewriteCode to review the code in script.js to ensure it meets the design specifications.\",\n \"assignee\": \"Alex\"\n }\n }\n]\n```\n"
|
||||
}
|
||||
]
|
||||
22
examples/data/exp_pool/team_leader_exps.json
Normal file
22
examples/data/exp_pool/team_leader_exps.json
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
[{
|
||||
"req": [{
|
||||
"role": "user",
|
||||
"content": "\n# Current Plan\n{'goal': \"from to {'<all>'}: Write a 1024 game using JavaScript and HTML code without using any frameworks, user can play with keyboard.\", 'tasks': []}\n\n# Current Task\n\n\n# Instruction\nYou are a team leader, and you are responsible for drafting tasks and routing tasks to your team members.\nYour team member:\nTim: Team Leader, \nAlice: Product Manager, efficiently create a successful product that meets market demands and user expectations\nBob: Architect, design a concise, usable, complete software system\nEve: Project Manager, break down tasks according to PRD/technical design, generate a task list, and analyze task dependencies to start with the prerequisite modules\nAlex: Engineer, Take on game, app, and web development\nDavid: DataAnalyst, Take on any data-related tasks, such as data analysis, machine learning, deep learning, web browsing, web scraping, web searching, web deployment, terminal operation, git and github operation, etc.\n\nYou should NOT assign consecutive tasks to the same team member, instead, assign an aggregated task (or the complete requirement) and let the team member to decompose it.\nWhen creating a new plan involving multiple members, create all tasks at once.\nIf plan is created, you should track the progress based on team member feedback message, and update plan accordingly, such as Plan.finish_current_task, Plan.reset_task, Plan.replace_task, etc.\nYou should use TeamLeader.publish_team_message to team members, asking them to start their task. DONT omit any necessary info such as path, link, environment, programming language, framework, requirement, constraint from original content to team members because you are their sole info source.\nPay close attention to new user message, review the conversation history, use RoleZero.reply_to_human to respond to the user directly, DON'T ask your team members.\n\nNote:\n1. If the requirement is a pure DATA-RELATED requirement, such as bug fixes, issue reporting, environment setup, terminal operations, pip install, web browsing, web scraping, web searching, web imitation, data science, data analysis, machine learning, deep learning, text-to-image etc. DON'T decompose it, assign a single task with the original user requirement as instruction directly to Data Analyst.\n2. If the requirement is developing a software, game, app, or website, excluding the above data-related tasks, you should decompose the requirement into multiple tasks and assign them to different team members based on their expertise, usually the sequence of Product Manager -> Architect -> Project Manager -> Engineer -> (optional: QaEngine if present) -> (optional: DataAnalyst if user requests deployment), each assigned ONE task. When publishing message to Product Manager, you should directly copy the full original user requirement.\n3. If the requirement contains both DATA-RELATED part mentioned in 1 and software development part mentioned in 2, you should decompose the software development part and assign them to different team members based on their expertise, and assign the DATA-RELATED part to Data Analyst David directly.\n4. If the requirement is a common-sense, logical, or math problem, you should respond directly without assigning any task to team members.\n5. If you think the requirement is not clear or ambiguous, you should ask the user for clarification immediately. Assign tasks only after all info is clear.\n6. It is helpful for Engineer to have both the system design and the project schedule for writing the code, so include paths of both files (if available) and remind Engineer to definitely read them when publishing message to Engineer.\n7. If the requirement is writing a TRD and software framework, you should assign it to Architect. When publishing message to Architect, you should directly copy the full original user requirement.\n"
|
||||
}],
|
||||
"resp": "\nExplanation: The requirement is about software development. Assign each tasks to a different team member based on their expertise. When publishing message to Product Manager, we copy original user requirement directly to ensure no information loss.\n```json\n[\n {\n \"command_name\": \"Plan.append_task\",\n \"args\": {\n \"task_id\": \"1\",\n \"dependent_task_ids\": [],\n \"instruction\": \"Create a product requirement document (PRD) outlining the features, user interface, and user experience of the CLI python snake game.\",\n \"assignee\": \"Alice\"\n }\n },\n {\n \"command_name\": \"Plan.append_task\",\n \"args\": {\n \"task_id\": \"2\",\n \"dependent_task_ids\": [\"1\"],\n \"instruction\": \"Design the software architecture for the CLI snake game, including the choice of programming language, libraries, and data flow.\",\n \"assignee\": \"Bob\"\n }\n },\n {\n \"command_name\": \"Plan.append_task\",\n \"args\": {\n \"task_id\": \"3\",\n \"dependent_task_ids\": [\"2\"],\n \"instruction\": \"Break down the architecture into manageable tasks, identify task dependencies, and prepare a detailed task list for implementation.\",\n \"assignee\": \"Eve\"\n }\n },\n {\n \"command_name\": \"Plan.append_task\",\n \"args\": {\n \"task_id\": \"4\",\n \"dependent_task_ids\": [\"3\"],\n \"instruction\": \"Implement the core game logic for the CLI snake game, including snake movement, food generation, and score tracking.\",\n \"assignee\": \"Alex\"\n }\n },\n {\n \"command_name\": \"Plan.append_task\",\n \"args\": {\n \"task_id\": \"5\",\n \"dependent_task_ids\": [\"4\"],\n \"instruction\": \"Write comprehensive tests for the game logic and user interface to ensure functionality and reliability.\",\n \"assignee\": \"Edward\"\n }\n },\n {\n \"command_name\": \"TeamLeader.publish_message\",\n \"args\": {\n \"content\": \"Create a cli snake game using Python\",\n \"send_to\": \"Alice\"\n }\n },\n {\n \"command_name\": \"RoleZero.reply_to_human\",\n \"args\": {\n \"content\": \"I have assigned the tasks to the team members. Alice will create the PRD, Bob will design the software architecture, Eve will break down the architecture into tasks, Alex will implement the core game logic, and Edward will write comprehensive tests. The team will work on the project accordingly\"\n }\n },\n {\n \"command_name\": \"end\"\n }\n]\n```\n"
|
||||
}, {
|
||||
"req": [{
|
||||
"role": "user",
|
||||
"content": "\n# Current Plan\n{'goal': \"from to {'<all>'}: Run data analysis on sklearn Wine recognition dataset, include a plot, and train a model to predict wine class (20% as validation), and show validation accuracy.\", 'tasks': []}\n\n# Current Task\n\n\n# Instruction\nYou are a team leader, and you are responsible for drafting tasks and routing tasks to your team members.\nYour team member:\nTim: Team Leader, \nAlice: Product Manager, efficiently create a successful product that meets market demands and user expectations\nBob: Architect, design a concise, usable, complete software system\nEve: Project Manager, break down tasks according to PRD/technical design, generate a task list, and analyze task dependencies to start with the prerequisite modules\nAlex: Engineer, Take on game, app, and web development\nDavid: DataAnalyst, Take on any data-related tasks, such as data analysis, machine learning, deep learning, web browsing, web scraping, web searching, web deployment, terminal operation, git and github operation, etc.\n\nYou should NOT assign consecutive tasks to the same team member, instead, assign an aggregated task (or the complete requirement) and let the team member to decompose it.\nWhen creating a new plan involving multiple members, create all tasks at once.\nIf plan is created, you should track the progress based on team member feedback message, and update plan accordingly, such as Plan.finish_current_task, Plan.reset_task, Plan.replace_task, etc.\nYou should use TeamLeader.publish_team_message to team members, asking them to start their task. DONT omit any necessary info such as path, link, environment, programming language, framework, requirement, constraint from original content to team members because you are their sole info source.\nPay close attention to new user message, review the conversation history, use RoleZero.reply_to_human to respond to the user directly, DON'T ask your team members.\n\nNote:\n1. If the requirement is a pure DATA-RELATED requirement, such as bug fixes, issue reporting, environment setup, terminal operations, pip install, web browsing, web scraping, web searching, web imitation, data science, data analysis, machine learning, deep learning, text-to-image etc. DON'T decompose it, assign a single task with the original user requirement as instruction directly to Data Analyst.\n2. If the requirement is developing a software, game, app, or website, excluding the above data-related tasks, you should decompose the requirement into multiple tasks and assign them to different team members based on their expertise, usually the sequence of Product Manager -> Architect -> Project Manager -> Engineer -> (optional: QaEngine if present) -> (optional: DataAnalyst if user requests deployment), each assigned ONE task. When publishing message to Product Manager, you should directly copy the full original user requirement.\n3. If the requirement contains both DATA-RELATED part mentioned in 1 and software development part mentioned in 2, you should decompose the software development part and assign them to different team members based on their expertise, and assign the DATA-RELATED part to Data Analyst David directly.\n4. If the requirement is a common-sense, logical, or math problem, you should respond directly without assigning any task to team members.\n5. If you think the requirement is not clear or ambiguous, you should ask the user for clarification immediately. Assign tasks only after all info is clear.\n6. It is helpful for Engineer to have both the system design and the project schedule for writing the code, so include paths of both files (if available) and remind Engineer to definitely read them when publishing message to Engineer.\n7. If the requirement is writing a TRD and software framework, you should assign it to Architect. When publishing message to Architect, you should directly copy the full original user requirement.\n"
|
||||
}],
|
||||
"resp": "\nExplanation: DON'T decompose requirement if it is a DATA-RELATED task, assign a single task directly to Data Analyst David. He will manage the decomposition and implementation.\n```json\n[\n {\n \"command_name\": \"Plan.append_task\",\n \"args\": {\n \"task_id\": \"1\",\n \"dependent_task_ids\": [],\n \"instruction\": \"Run data analysis on sklearn Wine recognition dataset, include a plot, and train a model to predict wine class (20% as validation), and show validation accuracy.\",\n \"assignee\": \"David\"\n }\n },\n {\n \"command_name\": \"TeamLeader.publish_message\",\n \"args\": {\n \"content\": \"Run data analysis on sklearn Wine recognition dataset, include a plot, and train a model to predict wine class (20% as validation), and show validation accuracy.\",\n \"send_to\": \"David\"\n }\n },\n {\n \"command_name\": \"RoleZero.reply_to_human\",\n \"args\": {\n \"content\": \"I have assigned the task to David. He will break down the task further by himself and starts solving it.\"\n }\n },\n {\n \"command_name\": \"end\"\n }\n]\n```\n"
|
||||
}, {
|
||||
"req": "Conversation History:\n[\n ...,\n {'role': 'assistant', 'content': 'from Alice(Product Manager) to {'Bob'}: {'docs': {'20240424153821.json': {'root_path': 'docs/prd', 'filename': '20240424153821.json', 'content': '{\"Language\":\"en_us\",\"Programming Language\":\"Python\",\"Original Requirements\":\"create a cli snake game\",\"Project Name\":\"snake_game\",\"Product Goals\":[\"Develop an intuitive and addictive snake game\",...], ...}}}}},\n]\n",
|
||||
"resp": "\nExplanation: You received a message from Alice, the Product Manager, that she has completed the PRD, use Plan.finish_current_task to mark her task as finished and moves the plan to the next task. Based on plan status, next task is for Bob (Architect), publish a message asking him to start. The message content should contain important path info.\n```json\n[\n {\n \"command_name\": \"Plan.finish_current_task\",\n \"args\": {}\n },\n {\n \"command_name\": \"TeamLeader.publish_message\",\n \"args\": {\n \"content\": \"Please design the software architecture for the snake game based on the PRD created by Alice. The PRD is at 'docs/prd/20240424153821.json'. Include the choice of programming language, libraries, and data flow, etc.\",\n \"send_to\": \"Bob\"\n }\n },\n {\n \"command_name\": \"RoleZero.reply_to_human\",\n \"args\": {\n \"content\": \"Alice has completed the PRD. I have marked her task as finished and sent the PRD to Bob. Bob will work on the software architecture.\"\n }\n },\n {\n \"command_name\": \"end\"\n }\n]\n```\n"
|
||||
}, {
|
||||
"req": [{
|
||||
"role": "user",
|
||||
"content": "\n# Current Plan\n{'goal': \"from to {'<all>'}: how does the project go?\", 'tasks': []}\n\n# Current Task\n\n\n# Instruction\nYou are a team leader, and you are responsible for drafting tasks and routing tasks to your team members.\nYour team member:\nTim: Team Leader, \nAlice: Product Manager, efficiently create a successful product that meets market demands and user expectations\nBob: Architect, design a concise, usable, complete software system\nEve: Project Manager, break down tasks according to PRD/technical design, generate a task list, and analyze task dependencies to start with the prerequisite modules\nAlex: Engineer, Take on game, app, and web development\nDavid: DataAnalyst, Take on any data-related tasks, such as data analysis, machine learning, deep learning, web browsing, web scraping, web searching, web deployment, terminal operation, git and github operation, etc.\n\nYou should NOT assign consecutive tasks to the same team member, instead, assign an aggregated task (or the complete requirement) and let the team member to decompose it.\nWhen creating a new plan involving multiple members, create all tasks at once.\nIf plan is created, you should track the progress based on team member feedback message, and update plan accordingly, such as Plan.finish_current_task, Plan.reset_task, Plan.replace_task, etc.\nYou should use TeamLeader.publish_team_message to team members, asking them to start their task. DONT omit any necessary info such as path, link, environment, programming language, framework, requirement, constraint from original content to team members because you are their sole info source.\nPay close attention to new user message, review the conversation history, use RoleZero.reply_to_human to respond to the user directly, DON'T ask your team members.\n\nNote:\n1. If the requirement is a pure DATA-RELATED requirement, such as bug fixes, issue reporting, environment setup, terminal operations, pip install, web browsing, web scraping, web searching, web imitation, data science, data analysis, machine learning, deep learning, text-to-image etc. DON'T decompose it, assign a single task with the original user requirement as instruction directly to Data Analyst.\n2. If the requirement is developing a software, game, app, or website, excluding the above data-related tasks, you should decompose the requirement into multiple tasks and assign them to different team members based on their expertise, usually the sequence of Product Manager -> Architect -> Project Manager -> Engineer -> (optional: QaEngine if present) -> (optional: DataAnalyst if user requests deployment), each assigned ONE task. When publishing message to Product Manager, you should directly copy the full original user requirement.\n3. If the requirement contains both DATA-RELATED part mentioned in 1 and software development part mentioned in 2, you should decompose the software development part and assign them to different team members based on their expertise, and assign the DATA-RELATED part to Data Analyst David directly.\n4. If the requirement is a common-sense, logical, or math problem, you should respond directly without assigning any task to team members.\n5. If you think the requirement is not clear or ambiguous, you should ask the user for clarification immediately. Assign tasks only after all info is clear.\n6. It is helpful for Engineer to have both the system design and the project schedule for writing the code, so include paths of both files (if available) and remind Engineer to definitely read them when publishing message to Engineer.\n7. If the requirement is writing a TRD and software framework, you should assign it to Architect. When publishing message to Architect, you should directly copy the full original user requirement.\n"
|
||||
}],
|
||||
"resp": "\nExplanation: The user is asking for a general update on the project status. Give a straight answer about the current task the team is working on and provide a summary of the completed tasks.\n```json\n[\n {\n \"command_name\": \"RoleZero.reply_to_human\",\n \"args\": {\n \"content\": \"The team is currently working on ... We have completed ...\"\n }\n },\n {\n \"command_name\": \"end\"\n }\n]\n```\n"
|
||||
}]
|
||||
Binary file not shown.
|
|
@ -1,6 +1,7 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from metagpt.roles.di.data_interpreter import DataInterpreter
|
||||
from metagpt.tools.libs.web_scraping import view_page_element_to_scrape
|
||||
|
||||
|
||||
async def main():
|
||||
|
|
@ -10,7 +11,7 @@ async def main():
|
|||
prompt = f"""This is a collection of arxiv urls: '{urls}' .
|
||||
Record each article, remove duplicates by title (they may have multiple tags), filter out papers related to
|
||||
large language model / agent / llm, print top 100 and visualize the word count of the titles"""
|
||||
di = DataInterpreter(react_mode="react", tools=["scrape_web_playwright"])
|
||||
di = DataInterpreter(react_mode="react", tools=[view_page_element_to_scrape.__name__])
|
||||
|
||||
await di.run(prompt)
|
||||
|
||||
|
|
|
|||
65
examples/di/atomization_capacity_plan.py
Normal file
65
examples/di/atomization_capacity_plan.py
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import fire
|
||||
|
||||
from metagpt.logs import logger
|
||||
from metagpt.roles.di.team_leader import TeamLeader
|
||||
|
||||
|
||||
async def main():
|
||||
tl = TeamLeader()
|
||||
logger.info("\n=== Adding Initial Tasks ===")
|
||||
tl.planner.plan.append_task(
|
||||
task_id="T1", dependent_task_ids=[], instruction="Create Product Requirements Document (PRD)", assignee="Alice"
|
||||
)
|
||||
tl.planner.plan.append_task(
|
||||
task_id="T2", dependent_task_ids=["T1"], instruction="Design System Architecture", assignee="Bob"
|
||||
)
|
||||
|
||||
# 1. Add Development Tasks
|
||||
logger.info("\n=== Adding Development Tasks ===")
|
||||
tl.planner.plan.append_task(
|
||||
task_id="T3", dependent_task_ids=["T2"], instruction="Implement Core Function Modules", assignee="Alex"
|
||||
)
|
||||
|
||||
tl.planner.plan.append_task(
|
||||
task_id="T4", dependent_task_ids=["T2"], instruction="Implement User Interface", assignee="Alex"
|
||||
)
|
||||
|
||||
# 2. Complete Some Tasks
|
||||
logger.info("\n=== Execute and Complete Tasks ===")
|
||||
logger.info(f"Current Task: {tl.planner.plan.current_task.instruction}")
|
||||
tl.planner.plan.finish_current_task() # Complete T1
|
||||
|
||||
logger.info(f"Current Task: {tl.planner.plan.current_task.instruction}")
|
||||
tl.planner.plan.finish_current_task() # Complete T2
|
||||
|
||||
# 3. Replace Tasks
|
||||
logger.info("\n=== Replace Task ===")
|
||||
tl.planner.plan.replace_task(
|
||||
task_id="T3",
|
||||
new_dependent_task_ids=["T2"],
|
||||
new_instruction="Implement Core Function Modules (Add New Features)",
|
||||
new_assignee="Senior_Developer",
|
||||
)
|
||||
|
||||
# 4. Add Testing Tasks
|
||||
logger.info("\n=== Add Testing Tasks ===")
|
||||
tl.planner.plan.append_task(
|
||||
task_id="T5", dependent_task_ids=["T3", "T4"], instruction="Execute Integration Tests", assignee="Edward"
|
||||
)
|
||||
|
||||
# 5. Reset Task Demonstration
|
||||
logger.info("\n=== Reset Task ===")
|
||||
logger.info("Reset Task T3 (This will also reset T5 which depends on it)")
|
||||
tl.planner.plan.reset_task("T3")
|
||||
|
||||
# Display Final Status
|
||||
logger.info("\n=== Final Status ===")
|
||||
logger.info(f"Completed Tasks: {len([t for t in tl.planner.plan.tasks if t.is_finished])}")
|
||||
logger.info(f"Current Task: {tl.planner.plan.current_task.instruction}")
|
||||
logger.info("All Tasks:")
|
||||
for task in tl.planner.plan.tasks:
|
||||
logger.info(f"- {task.task_id}: {task.instruction} (Completed: {task.is_finished})")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
fire.Fire(main)
|
||||
22
examples/di/automated_planning_of_tasks.py
Normal file
22
examples/di/automated_planning_of_tasks.py
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import fire
|
||||
|
||||
from metagpt.logs import logger
|
||||
from metagpt.roles.di.team_leader import TeamLeader
|
||||
|
||||
|
||||
async def main():
|
||||
# Create an instance of TeamLeader
|
||||
tl = TeamLeader()
|
||||
|
||||
# Update the plan with the goal to create a 2048 game
|
||||
# This will auto generate tasks needed to accomplish the goal
|
||||
await tl.planner.update_plan(goal="create a 2048 game.")
|
||||
|
||||
# Iterate through all tasks in the plan
|
||||
# Log each task's ID, instruction and completion status
|
||||
for task in tl.planner.plan.tasks:
|
||||
logger.info(f"- {task.task_id}: {task.instruction} (Completed: {task.is_finished})")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
fire.Fire(main)
|
||||
|
|
@ -6,16 +6,18 @@
|
|||
"""
|
||||
|
||||
from metagpt.roles.di.data_interpreter import DataInterpreter
|
||||
from metagpt.tools.libs.web_scraping import view_page_element_to_scrape
|
||||
|
||||
PAPER_LIST_REQ = """"
|
||||
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*
|
||||
and save it to a csv file. paper title must include `multiagent` or `large language model`.
|
||||
**Notice: view the page element before writing scraping code**
|
||||
"""
|
||||
|
||||
ECOMMERCE_REQ = """
|
||||
Get products data from website https://scrapeme.live/shop/ and save it as a csv file.
|
||||
**Notice: Firstly parse the web page encoding and the text HTML structure;
|
||||
The first page product name, price, product URL, and image URL must be saved in the csv;**
|
||||
The first page product name, price, product URL, and image URL must be saved in the csv.
|
||||
**Notice: view the page element before writing scraping code**
|
||||
"""
|
||||
|
||||
NEWS_36KR_REQ = """从36kr创投平台https://pitchhub.36kr.com/financing-flash 所有初创企业融资的信息, **注意: 这是一个中文网站**;
|
||||
|
|
@ -25,11 +27,12 @@ NEWS_36KR_REQ = """从36kr创投平台https://pitchhub.36kr.com/financing-flash
|
|||
3. 反思*快讯的html内容示例*中的规律, 设计正则匹配表达式来获取*`快讯`*的标题、链接、时间;
|
||||
4. 筛选最近3天的初创企业融资*`快讯`*, 以list[dict]形式打印前5个。
|
||||
5. 将全部结果存在本地csv中
|
||||
**Notice: view the page element before writing scraping code**
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
di = DataInterpreter(tools=["scrape_web_playwright"])
|
||||
di = DataInterpreter(tools=[view_page_element_to_scrape.__name__])
|
||||
|
||||
await di.run(ECOMMERCE_REQ)
|
||||
|
||||
|
|
|
|||
40
examples/di/data_analyst_write_code.py
Normal file
40
examples/di/data_analyst_write_code.py
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import fire
|
||||
|
||||
from metagpt.logs import logger
|
||||
from metagpt.roles.di.data_analyst import DataAnalyst
|
||||
|
||||
|
||||
async def main():
|
||||
# Create an instance of DataAnalyst role
|
||||
analyst = DataAnalyst()
|
||||
|
||||
# Set the main goal for the planner - constructing a 2D array
|
||||
analyst.planner.plan.goal = "construct a two-dimensional array"
|
||||
|
||||
# Add a specific task to the planner with detailed parameters:
|
||||
# - task_id: Unique identifier for the task
|
||||
# - dependent_task_ids: List of tasks that need to be completed before this one (empty in this case)
|
||||
# - instruction: Description of what needs to be done
|
||||
# - assignee: Who will execute the task (David)
|
||||
# - task_type: Category of the task (DATA_ANALYSIS)
|
||||
analyst.planner.plan.append_task(
|
||||
task_id="1",
|
||||
dependent_task_ids=[],
|
||||
instruction="construct a two-dimensional array",
|
||||
assignee="David",
|
||||
task_type="DATA_ANALYSIS",
|
||||
)
|
||||
|
||||
# Execute the code generation and execution for creating a 2D array
|
||||
# The write_and_exec_code method will:
|
||||
# 1. Generate the necessary code for creating a 2D array
|
||||
# 2. Execute the generated code
|
||||
# 3. Return the result
|
||||
result = await analyst.write_and_exec_code("construct a two-dimensional array")
|
||||
|
||||
# Log the result of the code execution
|
||||
logger.info(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
fire.Fire(main)
|
||||
32
examples/di/fix_github_issue.py
Normal file
32
examples/di/fix_github_issue.py
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
"""This example is from a real issue from MetaGPT: https://github.com/geekan/MetaGPT/issues/1067 with corresponding bugfix as https://github.com/geekan/MetaGPT/pull/1069
|
||||
We demonstrate that DataInterpreter has the capability to fix such issues.
|
||||
Prerequisite: You need to manually add the bug back to your local file metagpt/utils/repair_llm_raw_output.py to test DataInterpreter's debugging ability. For detail, please check the issue and PR link above.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
|
||||
from metagpt.roles.di.data_interpreter import DataInterpreter
|
||||
|
||||
REQ = """
|
||||
# Requirement
|
||||
Below is a github issue, solve it. Use Editor to search for the function, understand it, and modify the relevant code.
|
||||
Write a new test file test.py with Editor and use Terminal to python the test file to ensure you have fixed the issue.
|
||||
When writing test.py, you should import the function from the file you modified and test it with the given input.
|
||||
Notice: Don't write all codes in one response, each time, just write code for one step.
|
||||
|
||||
# Issue
|
||||
>> s = "-1"
|
||||
>> print(extract_state_value_from_output(s))
|
||||
>> 1
|
||||
The extract_state_value_from_output function will process -1 into 1,
|
||||
resulted in an infinite loop for the react mode.
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
di = DataInterpreter(tools=["Terminal", "Editor"], react_mode="react")
|
||||
await di.run(REQ)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
|
|
@ -11,10 +11,10 @@ from metagpt.roles.di.data_interpreter import DataInterpreter
|
|||
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.
|
||||
Firstly, open the page and take a screenshot of the page.
|
||||
Secondly, convert the image to a webpage including HTML, CSS and JS in one go.
|
||||
Note: All required dependencies and environments have been fully installed and configured."""
|
||||
di = DataInterpreter(tools=["GPTvGenerator"])
|
||||
di = DataInterpreter(tools=["GPTvGenerator", "Browser"])
|
||||
|
||||
await di.run(prompt)
|
||||
|
||||
|
|
|
|||
38
examples/di/interacting_with_human.py
Normal file
38
examples/di/interacting_with_human.py
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import fire
|
||||
|
||||
from metagpt.environment.mgx.mgx_env import MGXEnv
|
||||
from metagpt.logs import logger
|
||||
from metagpt.roles.di.team_leader import TeamLeader
|
||||
from metagpt.schema import Message
|
||||
|
||||
|
||||
async def main():
|
||||
# Initialize the MetaGPT environment
|
||||
env = MGXEnv()
|
||||
# Add a TeamLeader role to the environment
|
||||
env.add_roles([TeamLeader()])
|
||||
|
||||
# Get input from human user about what they want to do
|
||||
human_rsp = await env.ask_human("What do you want to do?")
|
||||
|
||||
# Log the human response for tracking
|
||||
logger.info(human_rsp)
|
||||
# Create and publish a message with the human response in the environment
|
||||
env.publish_message(Message(content=human_rsp, role="user"))
|
||||
|
||||
# Get the TeamLeader role instance named 'Mike'
|
||||
tl = env.get_role("Mike")
|
||||
# Execute the TeamLeader's tasks
|
||||
await tl.run()
|
||||
|
||||
# Log information about each task in the TeamLeader's plan
|
||||
for task in tl.planner.plan.tasks:
|
||||
logger.info(f"- {task.task_id}: {task.instruction} (Completed: {task.is_finished})")
|
||||
|
||||
# Send an empty response back to the human and log it
|
||||
resp = await env.reply_to_human("")
|
||||
logger.info(resp)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
fire.Fire(main)
|
||||
|
|
@ -1,17 +1,17 @@
|
|||
from metagpt.const import EXAMPLE_DATA_PATH
|
||||
from metagpt.roles.di.data_interpreter import DataInterpreter
|
||||
|
||||
|
||||
async def main():
|
||||
# Notice: pip install metagpt[ocr] before using this example
|
||||
image_path = "image.jpg"
|
||||
image_path = EXAMPLE_DATA_PATH / "di/receipt_shopping.jpg"
|
||||
language = "English"
|
||||
requirement = f"""This is a {language} receipt image.
|
||||
Your goal is to perform OCR on images using PaddleOCR, output text content from the OCR results and discard
|
||||
coordinates and confidence levels, then recognize the total amount from ocr text content, and finally save as table.
|
||||
coordinates and confidence levels, then recognize the total amount from ocr text content, and finally save as csv table.
|
||||
Image path: {image_path}.
|
||||
NOTE: The environments for Paddle and PaddleOCR are all ready and has been fully installed."""
|
||||
di = DataInterpreter()
|
||||
|
||||
di = DataInterpreter(react_mode="react")
|
||||
await di.run(requirement)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import asyncio
|
||||
|
||||
from metagpt.const import DEFAULT_WORKSPACE_ROOT, EXAMPLE_DATA_PATH
|
||||
from metagpt.roles.di.data_interpreter import DataInterpreter
|
||||
|
||||
|
||||
|
|
@ -9,7 +10,7 @@ async def main(requirement: str = ""):
|
|||
|
||||
|
||||
if __name__ == "__main__":
|
||||
image_path = "/your/path/to/the/image.jpeg"
|
||||
save_path = "/your/intended/save/path/for/image_rm_bg.png"
|
||||
image_path = EXAMPLE_DATA_PATH / "di/dog.jpg"
|
||||
save_path = DEFAULT_WORKSPACE_ROOT / "image_rm_bg.png"
|
||||
requirement = f"This is a image, you need to use python toolkit rembg to remove the background of the image and save the result. image path:{image_path}; save path:{save_path}."
|
||||
asyncio.run(main(requirement))
|
||||
|
|
|
|||
19
examples/di/run_flask.py
Normal file
19
examples/di/run_flask.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import asyncio
|
||||
|
||||
from metagpt.roles.di.data_interpreter import DataInterpreter
|
||||
|
||||
USE_GOT_REPO_REQ = """
|
||||
Write a service using Flask, create a conda environment and run it, and call the service's interface for validation.
|
||||
Notice: Don't write all codes in one response, each time, just write code for one step.
|
||||
"""
|
||||
# If you have created a conda environment, you can say:
|
||||
# I have created the conda environment '{env_name}', please use this environment to execute.
|
||||
|
||||
|
||||
async def main():
|
||||
di = DataInterpreter(tools=["Terminal", "Editor"])
|
||||
await di.run(USE_GOT_REPO_REQ)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
39
examples/di/software_company.py
Normal file
39
examples/di/software_company.py
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import fire
|
||||
|
||||
from metagpt.roles.di.data_interpreter import DataInterpreter
|
||||
|
||||
|
||||
async def main():
|
||||
prompt = """
|
||||
This is a software requirement:
|
||||
```text
|
||||
write a snake game
|
||||
```
|
||||
---
|
||||
1. Writes a PRD based on software requirements.
|
||||
2. Writes a design to the project repository, based on the PRD of the project.
|
||||
3. Writes a project plan to the project repository, based on the design of the project.
|
||||
4. Writes codes to the project repository, based on the project plan of the project.
|
||||
5. Run QA test on the project repository.
|
||||
6. Stage and commit changes for the project repository using Git.
|
||||
Note: All required dependencies and environments have been fully installed and configured.
|
||||
"""
|
||||
di = DataInterpreter(
|
||||
tools=[
|
||||
"WritePRD",
|
||||
"WriteDesign",
|
||||
"WritePlan",
|
||||
"WriteCode",
|
||||
"RunCode",
|
||||
"DebugError",
|
||||
# "git_archive",
|
||||
]
|
||||
)
|
||||
|
||||
await di.run(prompt)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
fire.Fire(main)
|
||||
29
examples/di/use_browser.py
Normal file
29
examples/di/use_browser.py
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import asyncio
|
||||
|
||||
from metagpt.roles.di.data_interpreter import DataInterpreter
|
||||
|
||||
MG_LLM_CONFIG_REQ = """
|
||||
This is a link to the doc site of MetaGPT project: https://docs.deepwisdom.ai/main/en/
|
||||
Check where you can go to on the site and try to find out the list of LLM APIs supported by MetaGPT.
|
||||
Don't write all codes in one response, each time, just write code for one step.
|
||||
"""
|
||||
|
||||
PAPER_LIST_REQ = """"
|
||||
At https://papercopilot.com/statistics/iclr-statistics/iclr-2024-statistics/,
|
||||
find the first paper whose title includes `multiagent`, open it and summarize its abstract.
|
||||
Don't write all codes in one response, each time, just write code for one step.
|
||||
"""
|
||||
|
||||
DESCRIBE_GITHUB_ISSUE_REQ = """
|
||||
Visit https://github.com/geekan/MetaGPT, navigate to Issues page, open the first issue related to DataInterpreter, then summarize what the issue is in one sentence.
|
||||
Don't write all codes in one response, each time, just write code for one step.
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
di = DataInterpreter(tools=["Browser"], react_mode="react")
|
||||
await di.run(MG_LLM_CONFIG_REQ)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
19
examples/di/use_github_repo.py
Normal file
19
examples/di/use_github_repo.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import asyncio
|
||||
|
||||
from metagpt.roles.di.data_interpreter import DataInterpreter
|
||||
|
||||
USE_GOT_REPO_REQ = """
|
||||
This is a link to the GOT github repo: https://github.com/spcl/graph-of-thoughts.git.
|
||||
Clone it, read the README to understand the usage, install it, and finally run the quick start example.
|
||||
**Note the config for LLM is at `config/config_got.json`, it's outside the repo path, before using it, you need to copy it into graph-of-thoughts.
|
||||
** Don't write all codes in one response, each time, just write code for one step.
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
di = DataInterpreter(tools=["Terminal"])
|
||||
await di.run(USE_GOT_REPO_REQ)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
20
examples/exp_pool/README.md
Normal file
20
examples/exp_pool/README.md
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# Experience Pool
|
||||
|
||||
## Prerequisites
|
||||
- Ensure the RAG module is installed: https://docs.deepwisdom.ai/main/en/guide/in_depth_guides/rag_module.html
|
||||
- Set embedding: https://docs.deepwisdom.ai/main/en/guide/in_depth_guides/rag_module.html
|
||||
- Set `enabled`、`enable_read` and `enable_write` to `true` in the `exp_pool` section of `config2.yaml`
|
||||
|
||||
## Example Files
|
||||
|
||||
### 1. decorator.py
|
||||
Showcases the implementation of the `@exp_cache` decorator.
|
||||
|
||||
### 2. init_exp_pool.py
|
||||
Demonstrates the process of initializing the experience pool.
|
||||
|
||||
### 3. manager.py
|
||||
Illustrates CRUD (Create, Read, Update, Delete) operations for managing experiences in the pool.
|
||||
|
||||
### 4. scorer.py
|
||||
Outlines methods for evaluating and scoring experiences within the pool.
|
||||
28
examples/exp_pool/decorator.py
Normal file
28
examples/exp_pool/decorator.py
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
"""
|
||||
This script demonstrates how to automatically store experiences using @exp_cache and query the stored experiences.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import uuid
|
||||
|
||||
from metagpt.exp_pool import exp_cache, get_exp_manager
|
||||
from metagpt.logs import logger
|
||||
|
||||
|
||||
@exp_cache()
|
||||
async def produce(req=""):
|
||||
return f"{req} {uuid.uuid4().hex}"
|
||||
|
||||
|
||||
async def main():
|
||||
req = "Water"
|
||||
|
||||
resp = await produce(req=req)
|
||||
logger.info(f"The response of `produce({req})` is: {resp}")
|
||||
|
||||
exps = await get_exp_manager().query_exps(req)
|
||||
logger.info(f"Find experiences: {exps}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
97
examples/exp_pool/init_exp_pool.py
Normal file
97
examples/exp_pool/init_exp_pool.py
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
"""Init experience pool.
|
||||
|
||||
Put some useful experiences into the experience pool.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from metagpt.const import EXAMPLE_DATA_PATH
|
||||
from metagpt.exp_pool import get_exp_manager
|
||||
from metagpt.exp_pool.schema import EntryType, Experience, Metric, Score
|
||||
from metagpt.logs import logger
|
||||
from metagpt.utils.common import aread
|
||||
|
||||
|
||||
async def load_file(filepath) -> list[dict]:
|
||||
"""Asynchronously loads and parses a JSON file.
|
||||
|
||||
Args:
|
||||
filepath: Path to the JSON file.
|
||||
|
||||
Returns:
|
||||
A list of dictionaries parsed from the JSON file.
|
||||
"""
|
||||
|
||||
return json.loads(await aread(filepath))
|
||||
|
||||
|
||||
async def add_exp(req: str, resp: str, tag: str, metric: Metric = None):
|
||||
"""Adds a new experience to the experience pool.
|
||||
|
||||
Args:
|
||||
req: The request string.
|
||||
resp: The response string.
|
||||
tag: A tag for categorizing the experience.
|
||||
metric: Optional metric for the experience. Defaults to a score of 10.
|
||||
|
||||
"""
|
||||
|
||||
exp = Experience(
|
||||
req=req,
|
||||
resp=resp,
|
||||
entry_type=EntryType.MANUAL,
|
||||
tag=tag,
|
||||
metric=metric or Metric(score=Score(val=10, reason="Manual")),
|
||||
)
|
||||
exp_manager = get_exp_manager()
|
||||
exp_manager.is_writable = True
|
||||
|
||||
exp_manager.create_exp(exp)
|
||||
logger.info(f"New experience created for the request `{req[:10]}`.")
|
||||
|
||||
|
||||
async def add_exps(exps: list, tag: str):
|
||||
"""Adds multiple experiences to the experience pool.
|
||||
|
||||
Args:
|
||||
exps: A list of experience dictionaries.
|
||||
tag: A tag for categorizing the experiences.
|
||||
|
||||
"""
|
||||
tasks = [
|
||||
add_exp(req=exp["req"] if isinstance(exp["req"], str) else json.dumps(exp["req"]), resp=exp["resp"], tag=tag)
|
||||
for exp in exps
|
||||
]
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
|
||||
async def add_exps_from_file(tag: str, filepath: Path):
|
||||
"""Loads experiences from a file and adds them to the experience pool.
|
||||
|
||||
Args:
|
||||
tag: A tag for categorizing the experiences.
|
||||
filepath: Path to the file containing experiences.
|
||||
|
||||
"""
|
||||
|
||||
exps = await load_file(filepath)
|
||||
await add_exps(exps, tag)
|
||||
|
||||
|
||||
def query_exps_count():
|
||||
"""Queries and logs the total count of experiences in the pool."""
|
||||
exp_manager = get_exp_manager()
|
||||
count = exp_manager.get_exps_count()
|
||||
logger.info(f"Experiences Count: {count}")
|
||||
|
||||
|
||||
async def main():
|
||||
await add_exps_from_file("TeamLeader.llm_cached_aask", EXAMPLE_DATA_PATH / "exp_pool/team_leader_exps.json")
|
||||
await add_exps_from_file("Engineer2.llm_cached_aask", EXAMPLE_DATA_PATH / "exp_pool/engineer_exps.json")
|
||||
query_exps_count()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
85
examples/exp_pool/load_exps_from_log.py
Normal file
85
examples/exp_pool/load_exps_from_log.py
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
"""Load and save experiences from the log file."""
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from metagpt.exp_pool import get_exp_manager
|
||||
from metagpt.exp_pool.schema import LOG_NEW_EXPERIENCE_PREFIX, Experience
|
||||
from metagpt.logs import logger
|
||||
|
||||
|
||||
def load_exps(log_file_path: str) -> list[Experience]:
|
||||
"""Loads experiences from a log file.
|
||||
|
||||
Args:
|
||||
log_file_path (str): The path to the log file.
|
||||
|
||||
Returns:
|
||||
list[Experience]: A list of Experience objects loaded from the log file.
|
||||
"""
|
||||
|
||||
if not Path(log_file_path).exists():
|
||||
logger.warning(f"`load_exps` called with a non-existent log file path: {log_file_path}")
|
||||
return
|
||||
|
||||
exps = []
|
||||
with open(log_file_path, "r") as log_file:
|
||||
for line in log_file:
|
||||
if LOG_NEW_EXPERIENCE_PREFIX in line:
|
||||
json_str = line.split(LOG_NEW_EXPERIENCE_PREFIX, 1)[1].strip()
|
||||
exp_data = json.loads(json_str)
|
||||
|
||||
exp = Experience(**exp_data)
|
||||
exps.append(exp)
|
||||
|
||||
logger.info(f"Loaded {len(exps)} experiences from log file: {log_file_path}")
|
||||
|
||||
return exps
|
||||
|
||||
|
||||
def save_exps(exps: list[Experience]):
|
||||
"""Saves a list of experiences to the experience pool.
|
||||
|
||||
Args:
|
||||
exps (list[Experience]): The list of experiences to save.
|
||||
"""
|
||||
|
||||
if not exps:
|
||||
logger.warning("`save_exps` called with an empty list of experiences.")
|
||||
return
|
||||
|
||||
manager = get_exp_manager()
|
||||
manager.is_writable = True
|
||||
|
||||
manager.create_exps(exps)
|
||||
logger.info(f"Saved {len(exps)} experiences.")
|
||||
|
||||
|
||||
def get_log_file_path() -> str:
|
||||
"""Retrieves the path to the log file.
|
||||
|
||||
Returns:
|
||||
str: The path to the log file.
|
||||
|
||||
Raises:
|
||||
ValueError: If the log file path cannot be found.
|
||||
"""
|
||||
|
||||
handlers = logger._core.handlers
|
||||
|
||||
for handler in handlers.values():
|
||||
if "log" in handler._name:
|
||||
return handler._name[1:-1]
|
||||
|
||||
raise ValueError("Log file not found")
|
||||
|
||||
|
||||
def main():
|
||||
log_file_path = get_log_file_path()
|
||||
|
||||
exps = load_exps(log_file_path)
|
||||
save_exps(exps)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
31
examples/exp_pool/manager.py
Normal file
31
examples/exp_pool/manager.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
"""
|
||||
Demonstrate the creation and querying of experiences.
|
||||
|
||||
This script creates a new experience, logs its creation, and then queries for experiences matching the same request.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
|
||||
from metagpt.exp_pool import get_exp_manager
|
||||
from metagpt.exp_pool.schema import EntryType, Experience
|
||||
from metagpt.logs import logger
|
||||
|
||||
|
||||
async def main():
|
||||
# Define the simple request and response
|
||||
req = "Simple req"
|
||||
resp = "Simple resp"
|
||||
|
||||
# Add the new experience
|
||||
exp = Experience(req=req, resp=resp, entry_type=EntryType.MANUAL)
|
||||
exp_manager = get_exp_manager()
|
||||
exp_manager.create_exp(exp)
|
||||
logger.info(f"New experience created for the request `{req}`.")
|
||||
|
||||
# Query for experiences matching the request
|
||||
exps = await exp_manager.query_exps(req)
|
||||
logger.info(f"Got experiences: {exps}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
44
examples/exp_pool/scorer.py
Normal file
44
examples/exp_pool/scorer.py
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import asyncio
|
||||
|
||||
from metagpt.exp_pool.scorers import SimpleScorer
|
||||
|
||||
# Request to implement quicksort in Python
|
||||
REQ = "Write a program to implement quicksort in python."
|
||||
|
||||
# First response: Quicksort implementation without base case
|
||||
RESP1 = """
|
||||
def quicksort(arr):
|
||||
return quicksort([x for x in arr[1:] if x <= arr[0]]) + [arr[0]] + quicksort([x for x in arr[1:] if x > arr[0]])
|
||||
"""
|
||||
|
||||
# Second response: Quicksort implementation with base case
|
||||
RESP2 = """
|
||||
def quicksort(arr):
|
||||
if len(arr) <= 1:
|
||||
return arr
|
||||
return quicksort([x for x in arr[1:] if x <= arr[0]]) + [arr[0]] + quicksort([x for x in arr[1:] if x > arr[0]])
|
||||
"""
|
||||
|
||||
|
||||
async def simple():
|
||||
"""Evaluates two quicksort implementations using SimpleScorer.
|
||||
|
||||
Example:
|
||||
{
|
||||
"val": 3,
|
||||
"reason": "The response attempts to implement quicksort but contains a critical flaw: it lacks a base case to terminate the recursion, which will lead to a maximum recursion depth exceeded error for non-empty lists. Additionally, the function does not handle empty lists properly. A correct implementation should include a base case to handle lists of length 0 or 1."
|
||||
}
|
||||
"""
|
||||
|
||||
scorer = SimpleScorer()
|
||||
|
||||
await scorer.evaluate(req=REQ, resp=RESP1)
|
||||
await scorer.evaluate(req=REQ, resp=RESP2)
|
||||
|
||||
|
||||
async def main():
|
||||
await simple()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
125
examples/mgx_write_project_framework.py
Normal file
125
examples/mgx_write_project_framework.py
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
@Time : 2024/6/13
|
||||
@Author : mashenquan
|
||||
@File : write_project_framework.py
|
||||
@Desc : The implementation of RFC243. https://deepwisdom.feishu.cn/wiki/QobGwPkImijoyukBUKHcrYetnBb
|
||||
"""
|
||||
import asyncio
|
||||
import json
|
||||
import uuid
|
||||
from json import JSONDecodeError
|
||||
from pathlib import Path
|
||||
from typing import Dict, List
|
||||
|
||||
import typer
|
||||
from pydantic import BaseModel
|
||||
|
||||
from metagpt.config2 import Config
|
||||
from metagpt.const import DEFAULT_WORKSPACE_ROOT
|
||||
from metagpt.context import Context
|
||||
from metagpt.environment import Environment
|
||||
from metagpt.environment.mgx.mgx_env import MGXEnv
|
||||
from metagpt.logs import logger
|
||||
from metagpt.roles import Architect
|
||||
from metagpt.roles.di.team_leader import TeamLeader
|
||||
from metagpt.schema import AIMessage, UserMessage
|
||||
from metagpt.strategy.experience_retriever import TRDToolExpRetriever
|
||||
from metagpt.utils.common import aread
|
||||
|
||||
app = typer.Typer(add_completion=False)
|
||||
|
||||
|
||||
class EnvBuilder(BaseModel):
|
||||
context: Context
|
||||
user_requirements: List[str]
|
||||
actors: Dict[str, str]
|
||||
technical_constraint: str
|
||||
output_dir: Path
|
||||
|
||||
def build(self) -> Environment:
|
||||
env = MGXEnv(context=self.context)
|
||||
team_leader = TeamLeader()
|
||||
architect = Architect(experience_retriever=TRDToolExpRetriever())
|
||||
|
||||
# Prepare context
|
||||
use_case_actors = "".join([f"- {v}: {k}\n" for k, v in self.actors.items()])
|
||||
msg = """
|
||||
The content of "Actor, System, External System" provides an explanation of actors and systems that appear in UML Use Case diagram.
|
||||
## Actor, System, External System
|
||||
{use_case_actors}
|
||||
"""
|
||||
architect.rc.memory.add(AIMessage(content=msg.format(use_case_actors=use_case_actors)))
|
||||
|
||||
# Prepare technical requirements
|
||||
msg = """
|
||||
"Additional Technical Requirements" specifies the additional technical requirements that the generated software framework code must meet.
|
||||
## Additional Technical Requirements
|
||||
{technical_requirements}
|
||||
"""
|
||||
architect.rc.memory.add(AIMessage(content=msg.format(technical_requirements=self.technical_constraint)))
|
||||
|
||||
env.add_roles([team_leader, architect])
|
||||
return env
|
||||
|
||||
|
||||
async def develop(
|
||||
context: Context,
|
||||
user_requirement_filename: str,
|
||||
actors_filename: str,
|
||||
constraint_filename: str,
|
||||
output_dir: str,
|
||||
):
|
||||
output_dir = Path(output_dir) if output_dir else DEFAULT_WORKSPACE_ROOT / uuid.uuid4().hex
|
||||
|
||||
v = await aread(filename=user_requirement_filename)
|
||||
try:
|
||||
user_requirements = json.loads(v)
|
||||
except JSONDecodeError:
|
||||
user_requirements = [v]
|
||||
v = await aread(filename=actors_filename)
|
||||
actors = json.loads(v)
|
||||
technical_constraint = await aread(filename=constraint_filename)
|
||||
env_builder = EnvBuilder(
|
||||
context=context,
|
||||
user_requirements=user_requirements,
|
||||
actors=actors,
|
||||
technical_constraint=technical_constraint,
|
||||
output_dir=output_dir,
|
||||
)
|
||||
env = env_builder.build()
|
||||
msg = """
|
||||
Given the user requirement of "User Requirements", write out the software framework.
|
||||
## User Requirements
|
||||
{user_requirements}
|
||||
"""
|
||||
env.publish_message(
|
||||
UserMessage(content=msg.format(user_requirements="\n".join(user_requirements)), send_to="Bob"),
|
||||
user_defined_recipient="Bob",
|
||||
)
|
||||
|
||||
while not env.is_idle:
|
||||
await env.run()
|
||||
|
||||
|
||||
@app.command()
|
||||
def startup(
|
||||
user_requirement_filename: str = typer.Argument(..., help="The filename of the user requirements."),
|
||||
actors_filename: str = typer.Argument(..., help="The filename of UML use case actors description."),
|
||||
llm_config: str = typer.Option(default="", help="Low-cost LLM config"),
|
||||
constraint_filename: str = typer.Option(default="", help="What technical dependency constraints are."),
|
||||
output_dir: str = typer.Option(default="", help="Output directory."),
|
||||
):
|
||||
if llm_config and Path(llm_config).exists():
|
||||
config = Config.from_yaml_file(Path(llm_config))
|
||||
else:
|
||||
logger.info("GPT 4 turbo is recommended")
|
||||
config = Config.default()
|
||||
ctx = Context(config=config)
|
||||
|
||||
asyncio.run(develop(ctx, user_requirement_filename, actors_filename, constraint_filename, output_dir))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app()
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""RAG benchmark pipeline"""
|
||||
|
||||
import asyncio
|
||||
|
|
|
|||
|
|
@ -1,72 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import asyncio
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
import typer
|
||||
|
||||
from metagpt.actions.rebuild_class_view import RebuildClassView
|
||||
from metagpt.actions.rebuild_sequence_view import RebuildSequenceView
|
||||
from metagpt.context import Context
|
||||
from metagpt.llm import LLM
|
||||
from metagpt.logs import logger
|
||||
from metagpt.utils.git_repository import GitRepository
|
||||
from metagpt.utils.project_repo import ProjectRepo
|
||||
|
||||
app = typer.Typer(add_completion=False, pretty_exceptions_show_locals=False)
|
||||
|
||||
|
||||
@app.command("", help="Python project reverse engineering.")
|
||||
def startup(
|
||||
project_root: str = typer.Argument(
|
||||
default="",
|
||||
help="Specify the root directory of the existing project for reverse engineering.",
|
||||
),
|
||||
output_dir: str = typer.Option(default="", help="Specify the output directory path for reverse engineering."),
|
||||
):
|
||||
package_root = Path(project_root)
|
||||
if not package_root.exists():
|
||||
raise FileNotFoundError(f"{project_root} not exists")
|
||||
if not _is_python_package_root(package_root):
|
||||
raise FileNotFoundError(f'There are no "*.py" files under "{project_root}".')
|
||||
init_file = package_root / "__init__.py" # used by pyreverse
|
||||
init_file_exists = init_file.exists()
|
||||
if not init_file_exists:
|
||||
init_file.touch()
|
||||
|
||||
if not output_dir:
|
||||
output_dir = package_root / "../reverse_engineering_output"
|
||||
logger.info(f"output dir:{output_dir}")
|
||||
try:
|
||||
asyncio.run(reverse_engineering(package_root, Path(output_dir)))
|
||||
finally:
|
||||
if not init_file_exists:
|
||||
init_file.unlink(missing_ok=True)
|
||||
tmp_dir = package_root / "__dot__"
|
||||
if tmp_dir.exists():
|
||||
shutil.rmtree(tmp_dir, ignore_errors=True)
|
||||
|
||||
|
||||
def _is_python_package_root(package_root: Path) -> bool:
|
||||
for file_path in package_root.iterdir():
|
||||
if file_path.is_file():
|
||||
if file_path.suffix == ".py":
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
async def reverse_engineering(package_root: Path, output_dir: Path):
|
||||
ctx = Context()
|
||||
ctx.git_repo = GitRepository(output_dir)
|
||||
ctx.repo = ProjectRepo(ctx.git_repo)
|
||||
action = RebuildClassView(name="ReverseEngineering", i_context=str(package_root), llm=LLM(), context=ctx)
|
||||
await action.run()
|
||||
|
||||
action = RebuildSequenceView(name="ReverseEngineering", llm=LLM(), context=ctx)
|
||||
await action.run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app()
|
||||
27
examples/search_enhanced_qa.py
Normal file
27
examples/search_enhanced_qa.py
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
"""
|
||||
This script demonstrates how to use the SearchEnhancedQA action to answer questions
|
||||
by leveraging web search results. It showcases a simple example of querying about
|
||||
the current weather in Beijing.
|
||||
|
||||
The SearchEnhancedQA action combines web search capabilities with natural language
|
||||
processing to provide informative answers to user queries.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
|
||||
from metagpt.actions.search_enhanced_qa import SearchEnhancedQA
|
||||
|
||||
|
||||
async def main():
|
||||
"""Runs a sample query through SearchEnhancedQA and prints the result."""
|
||||
|
||||
action = SearchEnhancedQA()
|
||||
|
||||
query = "What is the weather like in Beijing today?"
|
||||
answer = await action.run(query)
|
||||
|
||||
print(f"The answer to '{query}' is:\n\n{answer}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
25
examples/serialize_model.py
Normal file
25
examples/serialize_model.py
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
from metagpt.environment.mgx.mgx_env import MGXEnv
|
||||
from metagpt.logs import logger
|
||||
|
||||
|
||||
def main():
|
||||
"""Demonstrates serialization and deserialization using SerializationMixin.
|
||||
|
||||
This example creates an instance of MGXEnv, serializes it to a file,
|
||||
and then deserializes it back to an instance.
|
||||
|
||||
If executed correctly, the following log messages will be output:
|
||||
MGXEnv serialization successful. File saved at: /.../workspace/storage/MGXEnv.json
|
||||
MGXEnv deserialization successful. Instance created from file: /.../workspace/storage/MGXEnv.json
|
||||
The instance is MGXEnv()
|
||||
"""
|
||||
|
||||
env = MGXEnv()
|
||||
env.serialize()
|
||||
|
||||
env: MGXEnv = MGXEnv.deserialize()
|
||||
logger.info(f"The instance is {repr(env)}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
from pathlib import Path
|
||||
|
||||
import chainlit as cl
|
||||
from init_setup import ChainlitEnv
|
||||
|
||||
|
|
@ -67,8 +69,8 @@ async def startup(message: cl.Message) -> None:
|
|||
|
||||
await company.run(n_round=5)
|
||||
|
||||
workdir = company.env.context.git_repo.workdir
|
||||
files = company.env.context.git_repo.get_files(workdir)
|
||||
workdir = Path(company.env.context.config.project_path)
|
||||
files = [file.name for file in workdir.iterdir() if file.is_file()]
|
||||
files = "\n".join([f"{workdir}/{file}" for file in files if not file.startswith(".git")])
|
||||
|
||||
await cl.Message(
|
||||
|
|
|
|||
|
|
@ -5,15 +5,22 @@ Author: garylin2099
|
|||
"""
|
||||
import asyncio
|
||||
|
||||
from metagpt.context import Context
|
||||
from metagpt.environment.mgx.mgx_env import MGXEnv
|
||||
from metagpt.logs import logger
|
||||
from metagpt.roles.di.team_leader import TeamLeader
|
||||
from metagpt.roles.product_manager import ProductManager
|
||||
from metagpt.schema import Message
|
||||
|
||||
|
||||
async def main():
|
||||
msg = "Write a PRD for a snake game"
|
||||
context = Context() # Used to share repo path information between multiple actions within the role.
|
||||
role = ProductManager(context=context)
|
||||
env = MGXEnv()
|
||||
env.add_roles([TeamLeader(), ProductManager()])
|
||||
env.publish_message(Message(content=msg, role="user"))
|
||||
tl = env.get_role("Mike")
|
||||
await tl.run()
|
||||
|
||||
role = env.get_role("Alice")
|
||||
result = await role.run(msg)
|
||||
logger.info(result.content[:100])
|
||||
|
||||
|
|
|
|||
24
examples/write_design.py
Normal file
24
examples/write_design.py
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import asyncio
|
||||
|
||||
from metagpt.environment.mgx.mgx_env import MGXEnv
|
||||
from metagpt.logs import logger
|
||||
from metagpt.roles.architect import Architect
|
||||
from metagpt.roles.di.team_leader import TeamLeader
|
||||
from metagpt.schema import Message
|
||||
|
||||
|
||||
async def main():
|
||||
msg = "Write a TRD for a snake game"
|
||||
env = MGXEnv()
|
||||
env.add_roles([TeamLeader(), Architect()])
|
||||
env.publish_message(Message(content=msg, role="user"))
|
||||
tl = env.get_role("Mike")
|
||||
await tl.run()
|
||||
|
||||
role = env.get_role("Bob")
|
||||
result = await role.run(msg)
|
||||
logger.info(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
42
examples/write_game_code.py
Normal file
42
examples/write_game_code.py
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import asyncio
|
||||
import time
|
||||
|
||||
from metagpt.environment.mgx.mgx_env import MGXEnv
|
||||
from metagpt.roles.di.engineer2 import Engineer2
|
||||
from metagpt.roles.di.team_leader import TeamLeader
|
||||
from metagpt.schema import Message
|
||||
|
||||
|
||||
async def main(requirement="", user_defined_recipient="", enable_human_input=False, allow_idle_time=30):
|
||||
env = MGXEnv()
|
||||
env.add_roles([TeamLeader(), Engineer2()])
|
||||
|
||||
msg = Message(content=requirement)
|
||||
env.attach_images(msg) # attach image content if applicable
|
||||
|
||||
if user_defined_recipient:
|
||||
msg.send_to = {user_defined_recipient}
|
||||
env.publish_message(msg, user_defined_recipient=user_defined_recipient)
|
||||
else:
|
||||
env.publish_message(msg)
|
||||
|
||||
allow_idle_time = allow_idle_time if enable_human_input else 1
|
||||
start_time = time.time()
|
||||
while time.time() - start_time < allow_idle_time:
|
||||
if not env.is_idle:
|
||||
await env.run()
|
||||
start_time = time.time() # reset start time
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
requirement = "Write code for a 2048 game"
|
||||
user_defined_recipient = ""
|
||||
|
||||
asyncio.run(
|
||||
main(
|
||||
requirement=requirement,
|
||||
user_defined_recipient=user_defined_recipient,
|
||||
enable_human_input=False,
|
||||
allow_idle_time=60,
|
||||
)
|
||||
)
|
||||
|
|
@ -50,9 +50,9 @@ async def generate_novel():
|
|||
"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())
|
||||
novel_node = await ActionNode.from_pydantic(Novel).fill(req=instruction, llm=LLM())
|
||||
chap_node = await ActionNode.from_pydantic(Chapters).fill(
|
||||
context=f"### instruction\n{instruction}\n### novel\n{novel_node.content}", llm=LLM()
|
||||
req=f"### instruction\n{instruction}\n### novel\n{novel_node.content}", llm=LLM()
|
||||
)
|
||||
print(chap_node.instruct_content)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue