diff --git a/examples/exp_pool/init_exp_pool/engineer_exps.py b/examples/exp_pool/init_exp_pool/engineer_exps.py index e494fdaa3..022a0c829 100644 --- a/examples/exp_pool/init_exp_pool/engineer_exps.py +++ b/examples/exp_pool/init_exp_pool/engineer_exps.py @@ -3,20 +3,19 @@ import json OBJ1 = [ { "role": "user", - "content": '\n# Data Structure\n\n\n# Current Plan\n{\'goal\': "Please write a 1024 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# Example\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 ReviewAndRewriteCode.run.\n\nPay close attention to the Example provided, you can reuse the example for your current situation if it fits.\nYou may use any of the available commands to create a plan or update the plan. You may output mutiple commands, they will be executed sequentially.\nIf you finish current task, you will automatically take the next task in the existing plan, use Plan.finish_task, DON\'T append a new task.\n\n# Your commands in a json array, in the following output format. If there is nothing to do, use the pass or end command:\nSome text indicating your thoughts, such as 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.\n```json\n[\n {\n "command_name": str,\n "args": {"arg_name": arg_value, ...}\n },\n ...\n]\n```\nNotice: your output JSON data section must start with **```json [**\n', + "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 ReviewAndRewriteCode.run.\n", } ] OBJ2 = [ { "role": "user", - "content": "Command Editor.read executed: file_path='/tmp/system_design.json' block_content=\"...\"\n\nCommand Editor.read executed: file_path='/tmp/project_schedule.json' block_content=\"...\"", + "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# Data Structure\n\n\n# Current Plan\n{\'goal\': "Please write a 1024 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# Example\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 ReviewAndRewriteCode.run.\n\nPay close attention to the Example provided, you can reuse the example for your current situation if it fits.\nYou may use any of the available commands to create a plan or update the plan. You may output mutiple commands, they will be executed sequentially.\nIf you finish current task, you will automatically take the next task in the existing plan, use Plan.finish_task, DON\'T append a new task.\n\n# Your commands in a json array, in the following output format. If there is nothing to do, use the pass or end command:\nSome text indicating your thoughts, such as 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.\n```json\n[\n {\n "command_name": str,\n "args": {"arg_name": arg_value, ...}\n },\n ...\n]\n```\nNotice: your output JSON data section must start with **```json [**\n', + "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 ReviewAndRewriteCode.run.\n", }, ] - REQ1 = json.dumps(OBJ1) REQ2 = json.dumps(OBJ2) diff --git a/examples/exp_pool/init_exp_pool/team_leader_exps.py b/examples/exp_pool/init_exp_pool/team_leader_exps.py index da0bc3d81..347faac45 100644 --- a/examples/exp_pool/init_exp_pool/team_leader_exps.py +++ b/examples/exp_pool/init_exp_pool/team_leader_exps.py @@ -3,19 +3,19 @@ import json OBJ1 = [ { "role": "user", - "content": "\n# Data Structure\n\n\n# Current Plan\n{'goal': \"from to {''}: Create a cli snake game using Python.\", 'tasks': []}\n\n# Current Task\n\n\n# Example\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\nPay close attention to the Example provided, you can reuse the example for your current situation if it fits.\nYou may use any of the available commands to create a plan or update the plan. You may output mutiple commands, they will be executed sequentially.\nIf you finish current task, you will automatically take the next task in the existing plan, use Plan.finish_task, DON'T append a new task.\n\n# Your commands in a json array, in the following output format. If there is nothing to do, use the pass or end command:\nSome text indicating your thoughts, such as 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.\n```json\n[\n {\n \"command_name\": str,\n \"args\": {\"arg_name\": arg_value, ...}\n },\n ...\n]\n```\nNotice: your output JSON data section must start with **```json [**\n", + "content": "\n# Current Plan\n{'goal': \"from to {''}: 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", } ] OBJ2 = [ { "role": "user", - "content": "\n# Data Structure\n\n\n# Current Plan\n{'goal': \"from to {''}: 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# Example\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\nPay close attention to the Example provided, you can reuse the example for your current situation if it fits.\nYou may use any of the available commands to create a plan or update the plan. You may output mutiple commands, they will be executed sequentially.\nIf you finish current task, you will automatically take the next task in the existing plan, use Plan.finish_task, DON'T append a new task.\n\n# Your commands in a json array, in the following output format. If there is nothing to do, use the pass or end command:\nSome text indicating your thoughts, such as 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.\n```json\n[\n {\n \"command_name\": str,\n \"args\": {\"arg_name\": arg_value, ...}\n },\n ...\n]\n```\nNotice: your output JSON data section must start with **```json [**\n", + "content": "\n# Current Plan\n{'goal': \"from to {''}: 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", } ] OBJ4 = [ { "role": "user", - "content": "\n# Data Structure\n\n\n# Current Plan\n{'goal': \"from to {''}: how does the project go?\", 'tasks': []}\n\n# Current Task\n\n\n# Example\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\nPay close attention to the Example provided, you can reuse the example for your current situation if it fits.\nYou may use any of the available commands to create a plan or update the plan. You may output mutiple commands, they will be executed sequentially.\nIf you finish current task, you will automatically take the next task in the existing plan, use Plan.finish_task, DON'T append a new task.\n\n# Your commands in a json array, in the following output format. If there is nothing to do, use the pass or end command:\nSome text indicating your thoughts, such as 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.\n```json\n[\n {\n \"command_name\": str,\n \"args\": {\"arg_name\": arg_value, ...}\n },\n ...\n]\n```\nNotice: your output JSON data section must start with **```json [**\n", + "content": "\n# Current Plan\n{'goal': \"from to {''}: 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", } ] @@ -88,7 +88,7 @@ Explanation: The requirement is about software development. Assign each tasks to { "command_name": "RoleZero.reply_to_human", "args": { - "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", + "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" } }, { @@ -120,7 +120,7 @@ Explanation: DON'T decompose requirement if it is a DATA-RELATED task, assign a { "command_name": "RoleZero.reply_to_human", "args": { - "content": "I have assigned the task to David. He will break down the task further by himself and starts solving it.", + "content": "I have assigned the task to David. He will break down the task further by himself and starts solving it." } }, { @@ -139,15 +139,15 @@ Explanation: You received a message from Alice, the Product Manager, that she ha }, { "command_name": "TeamLeader.publish_message", - "args": { - "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.", - "send_to": "Bob" - } + "args": { + "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.", + "send_to": "Bob" + } }, { "command_name": "RoleZero.reply_to_human", "args": { - "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.", + "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." } }, { @@ -163,7 +163,7 @@ Explanation: The user is asking for a general update on the project status. Give { "command_name": "RoleZero.reply_to_human", "args": { - "content": "The team is currently working on ... We have completed ...", + "content": "The team is currently working on ... We have completed ..." } }, { diff --git a/metagpt/exp_pool/context_builders/action_node.py b/metagpt/exp_pool/context_builders/action_node.py index ade157822..a3362875c 100644 --- a/metagpt/exp_pool/context_builders/action_node.py +++ b/metagpt/exp_pool/context_builders/action_node.py @@ -1,5 +1,6 @@ """Action Node context builder.""" +from typing import Any from metagpt.exp_pool.context_builders.base import BaseContextBuilder @@ -17,17 +18,12 @@ Consider **Experiences** to generate a better answer. class ActionNodeContextBuilder(BaseContextBuilder): - async def build(self, **kwargs) -> str: + async def build(self, req: Any) -> str: """Builds the action node context string. - Args: - **kwargs: Arbitrary keyword arguments, expecting 'req' as a key. - - Returns: - str: The formatted context string using the request and formatted experiences. - If no experiences are available, returns the request as is. + If there are no experiences, returns the original `req`; + otherwise returns context with `req` and formatted experiences. """ - req = kwargs.get("req", "") exps = self.format_exps() return ACTION_NODE_CONTEXT_TEMPLATE.format(req=req, exps=exps) if exps else req diff --git a/metagpt/exp_pool/context_builders/base.py b/metagpt/exp_pool/context_builders/base.py index d1133c2da..f937f5c7b 100644 --- a/metagpt/exp_pool/context_builders/base.py +++ b/metagpt/exp_pool/context_builders/base.py @@ -16,8 +16,11 @@ class BaseContextBuilder(BaseModel, ABC): exps: list[Experience] = [] @abstractmethod - async def build(self, **kwargs) -> Any: - """Build context from parameters.""" + async def build(self, req: Any) -> Any: + """Build context from req. + + Do not modify `req`. If modification is necessary, use copy.deepcopy to create a copy first. + """ def format_exps(self) -> str: """Format experiences into a numbered list of strings. diff --git a/metagpt/exp_pool/context_builders/role_zero.py b/metagpt/exp_pool/context_builders/role_zero.py index 6407314ac..2ee469661 100644 --- a/metagpt/exp_pool/context_builders/role_zero.py +++ b/metagpt/exp_pool/context_builders/role_zero.py @@ -1,34 +1,36 @@ """RoleZero context builder.""" +import copy import re +from typing import Any from metagpt.exp_pool.context_builders.base import BaseContextBuilder class RoleZeroContextBuilder(BaseContextBuilder): - async def build(self, **kwargs) -> list[dict]: - """Builds the context by updating the req with formatted experiences. + async def build(self, req: Any) -> list[dict]: + """Builds the role zero context string. - Args: - **kwargs: Arbitrary keyword arguments, expecting 'req' as a key. - - Returns: - list[dict]: The updated request with formatted experiences or the original request if no experiences are available. + Note: + 1. The expected format for `req`, e.g., [{...}, {"role": "user", "content": "context"}, {"role": "user", "content": "context exp part"}]. + 2. Returns the original `req` if it is empty, incorrectly formatted or there are no experiences. + 3. Creates a copy of req and replaces the example content in the copied req with actual experiences. """ - req = kwargs.get("req", []) - if not req: + if not req or len(req) < 2: return req exps = self.format_exps() if not exps: return req - req[-1]["content"] = self.replace_example_content(req[-1].get("content", ""), exps) + req_copy = copy.deepcopy(req) - return req + req_copy[-2]["content"] = self.replace_example_content(req_copy[-2].get("content", ""), exps) + + return req_copy def replace_example_content(self, text: str, new_example_content: str) -> str: - return self.replace_content_between_markers(text, "# Example", "# Instruction", new_example_content) + return self.replace_content_between_markers(text, "# Example", "# Available Commands", new_example_content) @staticmethod def replace_content_between_markers(text: str, start_marker: str, end_marker: str, new_content: str) -> str: diff --git a/metagpt/exp_pool/context_builders/simple.py b/metagpt/exp_pool/context_builders/simple.py index 565855664..d7b8d0be9 100644 --- a/metagpt/exp_pool/context_builders/simple.py +++ b/metagpt/exp_pool/context_builders/simple.py @@ -1,6 +1,8 @@ """Simple context builder.""" +from typing import Any + from metagpt.exp_pool.context_builders.base import BaseContextBuilder SIMPLE_CONTEXT_TEMPLATE = """ @@ -20,5 +22,5 @@ Consider **Experiences** to generate a better answer. class SimpleContextBuilder(BaseContextBuilder): - async def build(self, **kwargs) -> str: - return SIMPLE_CONTEXT_TEMPLATE.format(req=kwargs.get("req", ""), exps=self.format_exps()) + async def build(self, req: Any) -> str: + return SIMPLE_CONTEXT_TEMPLATE.format(req=req, exps=self.format_exps()) diff --git a/metagpt/exp_pool/decorator.py b/metagpt/exp_pool/decorator.py index 0a9a83818..566127f59 100644 --- a/metagpt/exp_pool/decorator.py +++ b/metagpt/exp_pool/decorator.py @@ -200,7 +200,7 @@ class ExpCacheHandler(BaseModel): async def _build_context(self) -> str: self.context_builder.exps = self._exps - return await self.context_builder.build(**self.kwargs) + return await self.context_builder.build(self.kwargs["req"]) async def _execute_function(self): self.kwargs["req"] = await self._build_context() diff --git a/metagpt/exp_pool/serializers/role_zero.py b/metagpt/exp_pool/serializers/role_zero.py index 82a32e36b..f5363b1ff 100644 --- a/metagpt/exp_pool/serializers/role_zero.py +++ b/metagpt/exp_pool/serializers/role_zero.py @@ -3,7 +3,6 @@ import copy import json -from metagpt.exp_pool.context_builders import RoleZeroContextBuilder from metagpt.exp_pool.serializers.simple import SimpleSerializer @@ -11,14 +10,15 @@ class RoleZeroSerializer(SimpleSerializer): def serialize_req(self, req: list[dict]) -> str: """Serialize the request for database storage, ensuring it is a string. - This function does not modify `req`; it only extracts the necessary content from `req` because `req` may be very lengthy and could cause embedding errors. + Only extracts the necessary content from `req` because `req` may be very lengthy and could cause embedding errors. Args: req (list[dict]): The request to be serialized. Example: [ {"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}, - {"role": "user", "content": "..."}, + {"role": "user", "content": "context"}, + {"role": "user", "content": "context exp part"}, ] Returns: @@ -28,12 +28,12 @@ class RoleZeroSerializer(SimpleSerializer): return "" filtered_req = self._filter_req(req) - self._clean_last_entry_content(filtered_req) + filtered_req.append(req[-1]) return json.dumps(filtered_req) def _filter_req(self, req: list[dict]) -> list[dict]: - """Filter the request to include only necessary items and the last entry. + """Filter the `req` to include only necessary items. Args: req (list[dict]): The original request. @@ -45,20 +45,5 @@ class RoleZeroSerializer(SimpleSerializer): filtered_req = [ copy.deepcopy(item) for item in req if "Command Editor.read executed: file_path" in item["content"] ] - filtered_req.append(copy.deepcopy(req[-1])) return filtered_req - - def _clean_last_entry_content(self, req: list[dict]): - """Modifies the content of the last element in the request to remove unnecessary sections, making the request more concise.""" - - last_content = req[-1]["content"] - - last_content = RoleZeroContextBuilder.replace_content_between_markers( - last_content, "# Data Structure", "# Current Plan", "" - ) - last_content = RoleZeroContextBuilder.replace_content_between_markers( - last_content, "# Example", "# Instruction", "" - ) - - req[-1]["content"] = last_content diff --git a/metagpt/prompts/di/role_zero.py b/metagpt/prompts/di/role_zero.py index 8f4a8804e..436ad7cdd 100644 --- a/metagpt/prompts/di/role_zero.py +++ b/metagpt/prompts/di/role_zero.py @@ -8,7 +8,16 @@ Note: 2. 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. 3. Each time you finish a task, use RoleZero.reply_to_human to report your progress. """ +CMD_PROMPT_EXP_PART = """ +# Current Plan +{plan_status} +# Current Task +{current_task} + +# Instruction +{instruction} +""" CMD_PROMPT = """ # Data Structure class Task(BaseModel): @@ -18,21 +27,14 @@ class Task(BaseModel): task_type: str = "" assignee: str = "" +# Example +{example} + # Available Commands {available_commands} Special Command: Use {{"command_name": "end"}} to do nothing or indicate completion of all requirements and the end of actions. -# Current Plan -{plan_status} - -# Current Task -{current_task} - -# Example -{example} - -# Instruction -{instruction} +{cmd_prompt_exp_part} Pay close attention to the Example provided, you can reuse the example for your current situation if it fits. You may use any of the available commands to create a plan or update the plan. You may output mutiple commands, they will be executed sequentially. diff --git a/metagpt/roles/di/role_zero.py b/metagpt/roles/di/role_zero.py index 59c58861f..5b002d994 100644 --- a/metagpt/roles/di/role_zero.py +++ b/metagpt/roles/di/role_zero.py @@ -16,6 +16,7 @@ from metagpt.exp_pool.serializers import RoleZeroSerializer from metagpt.logs import logger from metagpt.prompts.di.role_zero import ( CMD_PROMPT, + CMD_PROMPT_EXP_PART, JSON_REPAIR_PROMPT, ROLE_INSTRUCTION, ) @@ -144,13 +145,14 @@ class RoleZero(Role): tool_info = json.dumps({tool.name: tool.schemas for tool in tools}) ### Make Decision Dynamically ### - prompt = self.cmd_prompt.format( + cmd_prompt_exp_part = CMD_PROMPT_EXP_PART.format( plan_status=plan_status, current_task=current_task, - example=example, - available_commands=tool_info, instruction=self.instruction.strip(), ) + prompt = self.cmd_prompt.format( + example=example, available_commands=tool_info, cmd_prompt_exp_part=cmd_prompt_exp_part + ) memory = self.rc.memory.get(self.memory_k) if not self.browser.is_empty_page: pattern = re.compile(r"Command Browser\.(\w+) executed") @@ -158,16 +160,24 @@ class RoleZero(Role): if pattern.match(msg.content): memory.insert(index, UserMessage(cause_by="browser", content=await self.browser.view())) break - context = self.llm.format_msg(memory + [UserMessage(content=prompt)]) - # print(*context, sep="\n" + "*" * 5 + "\n") + req = self.llm.format_msg(memory + [UserMessage(content=prompt), UserMessage(content=cmd_prompt_exp_part)]) async with ThoughtReporter(enable_llm_stream=True): - self.command_rsp = await self.llm_cached_aask(req=context, system_msgs=self.system_msg) + self.command_rsp = await self.llm_cached_aask(req=req, system_msgs=self.system_msg) self.rc.memory.add(AIMessage(content=self.command_rsp)) return True @exp_cache(context_builder=RoleZeroContextBuilder(), serializer=RoleZeroSerializer()) async def llm_cached_aask(self, *, req: list[dict], system_msgs: list[str]) -> str: + """Use `exp_cache` to automatically manage experiences. + + The `RoleZeroContextBuilder` attempts to add experiences to `req`. + The `RoleZeroSerializer` extracts essential parts of `req` for the experience pool, trimming lengthy entries to retain only necessary parts. + """ + # Remove the "cmd_prompt_exp_part", it is only used within the exp_cache decorator. + if req: + req.pop() + return await self.llm.aask(req, system_msgs=system_msgs) async def _act(self) -> Message: diff --git a/tests/metagpt/exp_pool/test_context_builders/test_rolezero_context_builder.py b/tests/metagpt/exp_pool/test_context_builders/test_rolezero_context_builder.py index 611d68211..a95566ed1 100644 --- a/tests/metagpt/exp_pool/test_context_builders/test_rolezero_context_builder.py +++ b/tests/metagpt/exp_pool/test_context_builders/test_rolezero_context_builder.py @@ -25,27 +25,31 @@ class TestRoleZeroContextBuilder: async def test_build_with_experiences(self, context_builder, mocker): mocker.patch.object(BaseContextBuilder, "format_exps", return_value="Formatted experiences") mocker.patch.object(RoleZeroContextBuilder, "replace_example_content", return_value="Updated content") - req = [{"content": "Original content"}] + req = [{"content": "Original content 1"}, {"content": "Original content exp part"}] result = await context_builder.build(req=req) - assert result == [{"content": "Updated content"}] + assert result == [{"content": "Updated content"}, {"content": "Original content exp part"}] def test_replace_example_content(self, context_builder, mocker): mocker.patch.object(RoleZeroContextBuilder, "replace_content_between_markers", return_value="Replaced content") result = context_builder.replace_example_content("Original text", "New example content") assert result == "Replaced content" context_builder.replace_content_between_markers.assert_called_once_with( - "Original text", "# Example", "# Instruction", "New example content" + "Original text", "# Example", "# Available Commands", "New example content" ) def test_replace_content_between_markers(self): - text = "Start\n# Example\nOld content\n# Instruction\nEnd" + text = "Start\n# Example\nOld content\n# Available Commands\nEnd" new_content = "New content" - result = RoleZeroContextBuilder.replace_content_between_markers(text, "# Example", "# Instruction", new_content) - expected = "Start\n# Example\nNew content\n\n# Instruction\nEnd" + result = RoleZeroContextBuilder.replace_content_between_markers( + text, "# Example", "# Available Commands", new_content + ) + expected = "Start\n# Example\nNew content\n\n# Available Commands\nEnd" assert result == expected def test_replace_content_between_markers_no_match(self): text = "Start\nNo markers\nEnd" new_content = "New content" - result = RoleZeroContextBuilder.replace_content_between_markers(text, "# Example", "# Instruction", new_content) + result = RoleZeroContextBuilder.replace_content_between_markers( + text, "# Example", "# Available Commands", new_content + ) assert result == text diff --git a/tests/metagpt/exp_pool/test_context_builders/test_simple_context_builder.py b/tests/metagpt/exp_pool/test_context_builders/test_simple_context_builder.py index b6d0f642e..cf1a42f27 100644 --- a/tests/metagpt/exp_pool/test_context_builders/test_simple_context_builder.py +++ b/tests/metagpt/exp_pool/test_context_builders/test_simple_context_builder.py @@ -13,7 +13,7 @@ class TestSimpleContextBuilder: return SimpleContextBuilder() @pytest.mark.asyncio - async def test_build_with_experiences(self, context_builder, mocker): + async def test_build_with_experiences(self, mocker, context_builder: SimpleContextBuilder): # Mock the format_exps method mock_exps = "Mocked experiences" mocker.patch.object(BaseContextBuilder, "format_exps", return_value=mock_exps) @@ -25,7 +25,7 @@ class TestSimpleContextBuilder: assert result == expected @pytest.mark.asyncio - async def test_build_without_experiences(self, context_builder, mocker): + async def test_build_without_experiences(self, mocker, context_builder: SimpleContextBuilder): # Mock the format_exps method to return an empty string mocker.patch.object(BaseContextBuilder, "format_exps", return_value="") @@ -36,12 +36,12 @@ class TestSimpleContextBuilder: assert result == expected @pytest.mark.asyncio - async def test_build_without_req(self, context_builder, mocker): + async def test_build_without_req(self, mocker, context_builder: SimpleContextBuilder): # Mock the format_exps method mock_exps = "Mocked experiences" mocker.patch.object(BaseContextBuilder, "format_exps", return_value=mock_exps) - result = await context_builder.build() + result = await context_builder.build(req="") expected = SIMPLE_CONTEXT_TEMPLATE.format(req="", exps=mock_exps) assert result == expected diff --git a/tests/metagpt/exp_pool/test_serializers/test_role_zero.py b/tests/metagpt/exp_pool/test_serializers/test_role_zero.py index 4c1f3daf3..d4525d535 100644 --- a/tests/metagpt/exp_pool/test_serializers/test_role_zero.py +++ b/tests/metagpt/exp_pool/test_serializers/test_role_zero.py @@ -7,71 +7,42 @@ from metagpt.exp_pool.serializers import RoleZeroSerializer class TestRoleZeroSerializer: @pytest.fixture - def serializer(self): + def serializer(self) -> RoleZeroSerializer: return RoleZeroSerializer() + @pytest.fixture + def last_item(self) -> dict: + return { + "role": "user", + "content": "# Current Plan\nsome plan\n# Current Plan\nsome plan\n# Instruction\nsome instruction", + } + + @pytest.fixture + def sample_req(self): + return [{"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}] + def test_serialize_req_empty_input(self, serializer: RoleZeroSerializer): assert serializer.serialize_req([]) == "" - def test_serialize_req_with_content(self, serializer: RoleZeroSerializer): + def test_serialize_req_with_content(self, serializer: RoleZeroSerializer, last_item: dict): req = [ - {"content": "Command Editor.read executed: file_path=test.py"}, - {"content": "Some other content"}, - { - "content": "# Data Structure\nsome data\n# Current Plan\nsome plan\n# Example\nsome example\n# Instruction\nsome instruction" - }, + {"role": "user", "content": "Command Editor.read executed: file_path=test.py"}, + {"role": "assistant", "content": "Some other content"}, + last_item, ] expected_output = json.dumps( - [ - {"content": "Command Editor.read executed: file_path=test.py"}, - { - "content": "# Data Structure\n\n\n# Current Plan\nsome plan\n# Example\n\n\n# Instruction\nsome instruction" - }, - ] + [{"role": "user", "content": "Command Editor.read executed: file_path=test.py"}, last_item] ) assert serializer.serialize_req(req) == expected_output def test_filter_req(self, serializer: RoleZeroSerializer): req = [ - {"content": "Command Editor.read executed: file_path=test1.py"}, - {"content": "Some other content"}, - {"content": "Command Editor.read executed: file_path=test2.py"}, - {"content": "Final content"}, + {"role": "user", "content": "Command Editor.read executed: file_path=test1.py"}, + {"role": "assistant", "content": "Some other content"}, + {"role": "user", "content": "Command Editor.read executed: file_path=test2.py"}, + {"role": "assistant", "content": "Final content"}, ] filtered_req = serializer._filter_req(req) - assert len(filtered_req) == 3 + assert len(filtered_req) == 2 assert filtered_req[0]["content"] == "Command Editor.read executed: file_path=test1.py" assert filtered_req[1]["content"] == "Command Editor.read executed: file_path=test2.py" - assert filtered_req[2]["content"] == "Final content" - - def test_clean_last_entry_content(self, serializer: RoleZeroSerializer): - req = [ - {"content": "Some content"}, - { - "content": "# Data Structure\nsome data\n# Current Plan\nsome plan\n# Example\nsome example\n# Instruction\nsome instruction" - }, - ] - serializer._clean_last_entry_content(req) - expected_content = ( - "# Data Structure\n\n\n# Current Plan\nsome plan\n# Example\n\n\n# Instruction\nsome instruction" - ) - assert req[-1]["content"] == expected_content - - def test_integration(self, serializer: RoleZeroSerializer): - req = [ - {"content": "Command Editor.read executed: file_path=test.py"}, - {"content": "Some other content"}, - { - "content": "# Data Structure\nsome data\n# Current Plan\nsome plan\n# Example\nsome example\n# Instruction\nsome instruction" - }, - ] - result = serializer.serialize_req(req) - expected_output = json.dumps( - [ - {"content": "Command Editor.read executed: file_path=test.py"}, - { - "content": "# Data Structure\n\n\n# Current Plan\nsome plan\n# Example\n\n\n# Instruction\nsome instruction" - }, - ] - ) - assert result == expected_output