refactor team leader, use RoleZero framework

This commit is contained in:
garylin2099 2024-06-04 20:59:21 +08:00
parent beaf11cc89
commit c6b28643bd
7 changed files with 158 additions and 178 deletions

View file

@ -0,0 +1,6 @@
from metagpt.prompts.di.role_zero import ROLE_INSTRUCTION
ENGINEER2_INSTRUCTION = (
ROLE_INSTRUCTION
+ "4. Each time you write a code in your response, write with the Editor directly without preparing a repetitive code block beforehand."
)

View file

@ -1,3 +1,14 @@
ROLE_INSTRUCTION = """
Based on the context, write a plan or modify an existing plan to achieve the goal. A plan consists of one to 3 tasks.
If 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.
When presented a current task, tackle the task using the available commands.
Pay close attention to new user message, review the conversation history, use RoleZero.reply_to_human to respond to new user requirement.
Note:
1. If you keeping encountering errors, unexpected situation, or you are not sure of proceeding, use RoleZero.ask_human to ask for help.
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 = """
# Data Structure
class Task(BaseModel):
@ -20,18 +31,10 @@ Special Command: Use {{"command_name": "pass"}} to do nothing and {{"command_nam
# Example
{example}
# Instructions
Based on the context, write a plan or modify an existing plan to achieve the goal. A plan consists of one to 3 tasks.
If 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.
When presented a current task, tackle the task using the available commands.
Pay close attention to new user message, review the conversation history, use MGXEnv.reply_to_human to respond to new user requirement.
Note:
1. If you keeping encountering errors, unexpected situation, or you are not sure of proceeding, use MGXEnv.ask_human to ask for help.
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 MGXEnv.reply_to_human to report your progress.
4. Each time you write a code in your response, write with the Editor directly without preparing a repetitive code block beforehand.
Pay close attention to the Example provided, you can reuse the example for your current situation if it fits.
# Instruction
{instruction}
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.
If 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.

View file

@ -4,62 +4,27 @@ When drafting and routing tasks, ALWAYS include necessary or important info insi
Each time you do something, reply to human letting them know what you did.
"""
CMD_PROMPT = """
# Data Structure
class Task(BaseModel):
task_id: str = ""
dependent_task_ids: list[str] = []
instruction: str = ""
task_type: str = ""
assignee: str = ""
# Team Member Info
{team_info}
# Available Commands
{available_commands}
# Current Plan
{plan_status}
# Example
{example}
# Instructions
TL_INSTRUCTION = """
You are a team leader, and you are responsible for drafting tasks and routing tasks to your team members.
Your team member:
{team_info}
You 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.
When creating a new plan involving multiple members, create all tasks at once.
If plan is created, you should track the progress based on team member feedback message, and update plan accordingly, such as finish_current_task, reset_task, replace_task, etc.
You should publish_message to team members, asking them to start their task.
Pay close attention to new user message, review the conversation history, use reply_to_human to respond to the user directly, DON'T ask your team members.
If 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.
You should use TeamLeader.publish_team_message to team members, asking them to start their task.
Pay 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.
Note:
1. 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.
2. 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.
3. 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.
Pay close attention to the Example provided
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.
If you finish current task, you will automatically take the next task in the existing plan, use finish_task, DON'T append a new task.
# Your commands in a json array, in the following output format, always output a json array, if there is nothing to do, use the pass command:
Some text indicating your thoughts, such as how you categorize the requirement based on Note (is it 1., 2., or 3.?) or how you should update the plan status. Then a json array of commands.
```json
[
{{
"command_name": str,
"args": {{"arg_name": arg_value, ...}}
}},
...
]
```
"""
FINISH_CURRENT_TASK_CMD = """
```json
[
{
"command_name": "finish_current_task",
"command_name": "Plan.finish_current_task",
"args": {{}}
}
```

View file

@ -4,34 +4,32 @@ import asyncio
from pydantic import model_validator
from metagpt.prompts.di.engineer2 import ENGINEER2_INSTRUCTION
from metagpt.roles.di.role_zero import RoleZero
from metagpt.tools.libs.editor import Editor
from test3 import design_doc_2048, design_doc_snake, task_doc_2048, task_doc_snake
def dummy_func(**kwargs):
pass
class Engineer2(RoleZero):
name: str = "Alex"
profile: str = "Engineer"
goal: str = ""
tools: str = ["Plan", "Editor:write,read,write_content", "MGXEnv:ask_human,reply_to_human"]
goal: str = "Take on game, app, and web development"
tools: str = ["Plan", "Editor:write,read,write_content", "RoleZero"]
instruction: str = ENGINEER2_INSTRUCTION
editor: Editor = Editor()
@model_validator(mode="after")
def set_tool_execution_map(self) -> "RoleZero":
self.tool_execute_map = {
def set_tool_execution(self) -> "RoleZero":
self.tool_execution_map = {
"Plan.append_task": self.planner.plan.append_task,
"Plan.reset_task": self.planner.plan.reset_task,
"Plan.replace_task": self.planner.plan.replace_task,
"Editor.write": self.editor.write,
"Editor.write_content": self.editor.write_content,
"Editor.read": self.editor.read,
"MGXEnv.ask_human": dummy_func,
"MGXEnv.reply_to_human": dummy_func,
"RoleZero.ask_human": self.ask_human,
"RoleZero.reply_to_human": self.reply_to_human,
}
return self
@ -70,6 +68,7 @@ Found this issue, TypeError: generate_new_position() missing 1 required position
Write code review for the codes (food.py, game.py, main.py, snake.py, ui.py) under under /Users/gary/Files/temp/workspace/snake_game_bugs/src.
Then correct any issues you find. You can review all code in one time, and solve issues in one time.
"""
CASUAL_CHAT = """what's your name?"""
if __name__ == "__main__":
engineer2 = Engineer2()

View file

@ -9,22 +9,28 @@ from pydantic import model_validator
from metagpt.actions import Action
from metagpt.actions.di.run_command import RunCommand
from metagpt.environment.mgx.mgx_env import MGXEnv
from metagpt.logs import logger
from metagpt.prompts.di.role_zero import CMD_PROMPT
from metagpt.prompts.di.role_zero import CMD_PROMPT, ROLE_INSTRUCTION
from metagpt.roles import Role
from metagpt.schema import Message
from metagpt.strategy.experience_retriever import KeywordExpRetriever
from metagpt.strategy.experience_retriever import DummyExpRetriever, ExpRetriever
from metagpt.strategy.planner import Planner
from metagpt.tools.tool_recommend import BM25ToolRecommender, ToolRecommender
from metagpt.tools.tool_registry import register_tool
from metagpt.utils.common import CodeParser
@register_tool(include_functions=["ask_human", "reply_to_human"])
class RoleZero(Role):
"""A role serving as the basis for other MGX roles."""
name: str = "Zero"
profile: str = "RoleZero"
goal: str = ""
system_msg: str = ""
system_msg: list[str] = None # Use None to conform to the default value at llm.aask
cmd_prompt: str = CMD_PROMPT
instruction: str = ROLE_INSTRUCTION
react_mode: Literal["react"] = "react"
max_react_loop: int = 20 # used for react mode
@ -37,6 +43,9 @@ class RoleZero(Role):
tools: list[str] = [] # Use special symbol ["<all>"] to indicate use of all registered tools
tool_recommender: ToolRecommender = None
tool_execution_map: dict[str, callable] = {}
special_tool_commands: list[str] = ["Plan.finish_current_task", "end"]
experience_retriever: ExpRetriever = DummyExpRetriever()
@model_validator(mode="after")
def set_plan_and_tool(self) -> "RoleZero":
@ -56,30 +65,23 @@ class RoleZero(Role):
return self
@model_validator(mode="after")
def set_tool_execution_map(self) -> "RoleZero":
def set_tool_execution(self) -> "RoleZero":
raise NotImplementedError
async def _think(self) -> bool:
"""Useful in 'react' mode. Use LLM to decide whether and what to do next."""
### 0. Preparation ###
if not self.rc.todo and not self.rc.news:
return False
self._set_state(0)
example = ""
if not self.planner.plan.goal:
self.user_requirement = self.get_memories()[-1].content
self.planner.plan.goal = self.user_requirement
example = KeywordExpRetriever().retrieve(self.user_requirement)
else:
self.rc.memory.add_batch(self.rc.news)
# TODO: implement experience retrieval in multi-round setting
# if self.planner.plan.current_task:
# experience = KeywordExpRetriever().retrieve(self.planner.plan.current_task.instruction, exp_type="task")
# if experience and experience not in [msg.content for msg in self.rc.memory.get()]:
# exp_msg = Message(content=experience, role="assistant")
# self.rc.memory.add(exp_msg)
# example = KeywordExpRetriever().retrieve(self.planner.plan.current_task.instruction, exp_type="task")
### 1. Experience ###
example = self._retrieve_experience()
### 2. Plan Status ###
plan_status = self.planner.plan.model_dump(include=["goal", "tasks"])
for task in plan_status["tasks"]:
task.pop("code")
@ -92,20 +94,21 @@ class RoleZero(Role):
else ""
)
### 3. Tool/Command Info ###
tools = await self.tool_recommender.recommend_tools()
tool_info = json.dumps({tool.name: tool.schemas for tool in tools})
### Make Decision ###
prompt = self.cmd_prompt.format(
plan_status=plan_status,
current_task=current_task,
example=example,
available_commands=tool_info,
instruction=self.instruction.strip(),
)
context = self.llm.format_msg(self.rc.memory.get(self.memory_k) + [Message(content=prompt, role="user")])
print(*context, sep="\n" + "*" * 5 + "\n")
self.command_rsp = await self.llm.aask(context)
self.command_rsp = await self.llm.aask(context, system_msgs=self.system_msg)
self.rc.memory.add(Message(content=self.command_rsp, role="assistant"))
return True
@ -121,7 +124,12 @@ class RoleZero(Role):
return error_msg
outputs = await self._run_commands(commands)
self.rc.memory.add(Message(content=outputs, role="user"))
return Message(content="Task completed", role="assistant", sent_from=self._setting, cause_by=RunCommand)
return Message(
content=f"Complete run with outputs: {outputs}",
role="assistant",
sent_from=self._setting,
cause_by=RunCommand,
)
async def _react(self) -> Message:
actions_taken = 0
@ -146,8 +154,8 @@ class RoleZero(Role):
if await self._run_special_command(cmd):
continue
# run command as specified by tool_execute_map
if cmd["command_name"] in self.tool_execute_map:
tool_obj = self.tool_execute_map[cmd["command_name"]]
if cmd["command_name"] in self.tool_execution_map:
tool_obj = self.tool_execution_map[cmd["command_name"]]
output = f"Command {cmd['command_name']} executed"
try:
if inspect.iscoroutinefunction(tool_obj):
@ -171,7 +179,7 @@ class RoleZero(Role):
async def _run_special_command(self, cmd) -> bool:
"""command requiring special check or parsing"""
is_special_cmd = cmd["command_name"] in ["Plan.finish_current_task", "Common.end"]
is_special_cmd = cmd["command_name"] in self.special_tool_commands
if cmd["command_name"] == "Plan.finish_current_task" and not self.planner.plan.is_plan_finished():
# task_result = TaskResult(code=str(commands), result=outputs, is_success=is_success)
@ -182,3 +190,24 @@ class RoleZero(Role):
self._set_state(-1)
return is_special_cmd
def _retrieve_experience(self) -> str:
"""Default implementation of experience retrieval. Can be overwritten in subclasses."""
context = [str(msg) for msg in self.rc.memory.get(self.memory_k)]
context = "\n\n".join(context)
example = self.experience_retriever.retrieve(context=context)
return example
async def ask_human(self, question: str) -> str:
"""Use this when you fail the current task or if you are unsure of the situation encountered. Your response should contain a brief summary of your situation, ended with a clear and concise question."""
# NOTE: Can be overwritten in remote setting
if not isinstance(self.rc.env, MGXEnv):
return "Not in MGXEnv, command will not be executed."
return await self.rc.env.get_human_input(question, sent_from=self)
async def reply_to_human(self, content: str) -> str:
"""Reply to human user with the content provided. Use this when you have a clear answer or solution to the user's question."""
# NOTE: Can be overwritten in remote setting
if not isinstance(self.rc.env, MGXEnv):
return "Not in MGXEnv, command will not be executed."
return await self.rc.env.reply_to_human(content, sent_from=self)

View file

@ -1,99 +1,70 @@
from __future__ import annotations
import json
from pydantic import model_validator
from metagpt.actions.di.run_command import RunCommand
from metagpt.prompts.di.team_leader import (
CMD_PROMPT,
FINISH_CURRENT_TASK_CMD,
SYSTEM_PROMPT,
TL_INSTRUCTION,
)
from metagpt.roles import Role
from metagpt.schema import Message, TaskResult
from metagpt.strategy.experience_retriever import SimpleExpRetriever
from metagpt.strategy.planner import Planner
from metagpt.strategy.thinking_command import (
Command,
prepare_command_prompt,
run_commands,
)
from metagpt.utils.common import CodeParser
from metagpt.roles.di.role_zero import RoleZero
from metagpt.schema import Message
from metagpt.strategy.experience_retriever import ExpRetriever, SimpleExpRetriever
from metagpt.tools.tool_registry import register_tool
class TeamLeader(Role):
@register_tool(include_functions=["publish_team_message"])
class TeamLeader(RoleZero):
name: str = "Tim"
profile: str = "Team Leader"
task_result: TaskResult = None
available_commands: list[Command] = [
Command.APPEND_TASK,
Command.RESET_TASK,
Command.REPLACE_TASK,
Command.FINISH_CURRENT_TASK,
Command.PUBLISH_MESSAGE,
Command.ASK_HUMAN,
Command.REPLY_TO_HUMAN,
Command.PASS,
]
commands: list[dict] = [] # issued commands to be executed
system_msg: list[str] = [SYSTEM_PROMPT]
max_react_loop: int = 1 # TeamLeader only reacts once each time
tools: list[str] = ["Plan", "RoleZero", "TeamLeader"]
experience_retriever: ExpRetriever = SimpleExpRetriever()
@model_validator(mode="after")
def set_plan(self) -> "TeamLeader":
self.planner = Planner(goal=self.goal, working_memory=self.rc.working_memory, auto_run=True)
def set_tool_execution(self) -> "RoleZero":
self.tool_execution_map = {
"Plan.append_task": self.planner.plan.append_task,
"Plan.reset_task": self.planner.plan.reset_task,
"Plan.replace_task": self.planner.plan.replace_task,
"RoleZero.ask_human": self.ask_human,
"RoleZero.reply_to_human": self.reply_to_human,
"TeamLeader.publish_team_message": self.publish_team_message,
}
return self
async def _think(self) -> bool:
"""Useful in 'react' mode. Use LLM to decide whether and what to do next."""
if not self.planner.plan.goal:
user_requirement = self.get_memories()[-1].content
self.planner.plan.goal = user_requirement
plan_status = self.planner.plan.model_dump(include=["goal", "tasks"])
for task in plan_status["tasks"]:
task.pop("code")
task.pop("result")
def set_instruction(self):
team_info = ""
for role in self.rc.env.roles.values():
if role.profile == "TeamLeader":
continue
# if role.profile == "Team Leader":
# continue
team_info += f"{role.name}: {role.profile}, {role.goal}\n"
example = SimpleExpRetriever().retrieve()
self.instruction = TL_INSTRUCTION.format(team_info=team_info)
prompt = CMD_PROMPT.format(
plan_status=plan_status,
team_info=team_info,
example=example,
available_commands=prepare_command_prompt(self.available_commands),
)
context = self.llm.format_msg(self.get_memories(k=10) + [Message(content=prompt, role="user")])
async def _think(self) -> bool:
self.set_instruction()
return await super()._think()
rsp = await self.llm.aask(context, system_msgs=[SYSTEM_PROMPT])
self.commands = json.loads(CodeParser.parse_code(text=rsp))
self.rc.memory.add(Message(content=rsp, role="assistant"))
return True
async def _act(self) -> Message:
"""Useful in 'react' mode. Return a Message conforming to Role._act interface."""
await run_commands(self, self.commands, self.rc.memory)
self.task_result = TaskResult(result="Success", is_success=True)
msg = Message(content="Commands executed", send_to="no one") # a dummy message to conform to the interface
self.rc.memory.add(msg)
return msg
def publish_message(self, msg):
"""If the role belongs to env, then the role's messages will be broadcast to env"""
def publish_message(self, msg, send_to="no one"):
"""Overwrite Role.publish_message, send to no one if called within Role.run, send to the specified role if called dynamically."""
if not msg:
return
if not self.rc.env:
# If env does not exist, do not publish the message
return
msg.sent_from = self.profile
msg.cause_by = RunCommand
msg.send_to = send_to
self.rc.env.publish_message(msg, publicer=self.profile)
def publish_team_message(self, content: str, send_to: str):
"""
Publish a message to a team member, use member name to fill send_to args. You may copy the full original content or add additional information from upstream. This will make team members start their work.
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.
"""
self.publish_message(Message(content=content), send_to=send_to)
def finish_current_task(self):
self.planner.plan.finish_current_task()
self.rc.memory.add(Message(content=FINISH_CURRENT_TASK_CMD, role="assistant"))

View file

@ -10,6 +10,13 @@ class ExpRetriever(BaseModel):
raise NotImplementedError
class DummyExpRetriever(ExpRetriever):
"""A dummy experience retriever that returns empty string."""
def retrieve(self, context: str = "") -> str:
return ""
class SimpleExpRetriever(ExpRetriever):
"""A simple experience retriever that returns manually crafted examples."""
@ -20,7 +27,7 @@ class SimpleExpRetriever(ExpRetriever):
```json
[
{
"command_name": "append_task",
"command_name": "Plan.append_task",
"args": {
"task_id": "1",
"dependent_task_ids": [],
@ -29,7 +36,7 @@ class SimpleExpRetriever(ExpRetriever):
}
},
{
"command_name": "append_task",
"command_name": "Plan.append_task",
"args": {
"task_id": "2",
"dependent_task_ids": ["1"],
@ -38,7 +45,7 @@ class SimpleExpRetriever(ExpRetriever):
}
},
{
"command_name": "append_task",
"command_name": "Plan.append_task",
"args": {
"task_id": "3",
"dependent_task_ids": ["2"],
@ -47,7 +54,7 @@ class SimpleExpRetriever(ExpRetriever):
}
},
{
"command_name": "append_task",
"command_name": "Plan.append_task",
"args": {
"task_id": "4",
"dependent_task_ids": ["3"],
@ -56,7 +63,7 @@ class SimpleExpRetriever(ExpRetriever):
}
},
{
"command_name": "append_task",
"command_name": "Plan.append_task",
"args": {
"task_id": "5",
"dependent_task_ids": ["4"],
@ -65,14 +72,14 @@ class SimpleExpRetriever(ExpRetriever):
}
},
{
"command_name": "publish_message",
"command_name": "TeamLeader.publish_message",
"args": {
"content": "Create a cli snake game using Python",
"send_to": "Alice"
}
},
{
"command_name": "reply_to_human",
"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",
}
@ -86,7 +93,7 @@ class SimpleExpRetriever(ExpRetriever):
```json
[
{
"command_name": "append_task",
"command_name": "Plan.append_task",
"args": {
"task_id": "1",
"dependent_task_ids": [],
@ -95,14 +102,14 @@ class SimpleExpRetriever(ExpRetriever):
}
},
{
"command_name": "publish_message",
"command_name": "TeamLeader.publish_message",
"args": {
"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.",
"send_to": "David"
}
},
{
"command_name": "reply_to_human",
"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.",
}
@ -116,22 +123,22 @@ class SimpleExpRetriever(ExpRetriever):
...,
{'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",...], ...}}}}},
]
Explanation: You received a message from Alice, the Product Manager, that she has completed the PRD, use 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.
Explanation: 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.
```json
[
{
"command_name": "finish_current_task",
"command_name": "Plan.finish_current_task",
"args": {}
},
{
"command_name": "publish_message",
"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"
}
},
{
"command_name": "reply_to_human",
"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.",
}
@ -145,7 +152,7 @@ class SimpleExpRetriever(ExpRetriever):
```json
[
{
"command_name": "reply_to_human",
"command_name": "RoleZero.reply_to_human",
"args": {
"content": "The team is currently working on ... We have completed ...",
}
@ -180,7 +187,7 @@ Explanation: Launching a service requires Terminal tool with daemon mode, write
```json
[
{
"command_name": "append_task",
"command_name": "Plan.append_task",
"args": {
"task_id": "1",
"dependent_task_ids": [],
@ -189,7 +196,7 @@ Explanation: Launching a service requires Terminal tool with daemon mode, write
}
},
{
"command_name": "append_task",
"command_name": "Plan.append_task",
"args": {
"task_id": "2",
"dependent_task_ids": ["1"],
@ -198,7 +205,7 @@ Explanation: Launching a service requires Terminal tool with daemon mode, write
}
},
{
"command_name": "append_task",
"command_name": "Plan.append_task",
"args": {
"task_id": "3",
"dependent_task_ids": ["2"],
@ -216,7 +223,7 @@ Explanation: The requirement is to fix an issue in an existing repository. The p
```json
[
{
"command_name": "append_task",
"command_name": "Plan.append_task",
"args": {
"task_id": "1",
"dependent_task_ids": [],
@ -225,7 +232,7 @@ Explanation: The requirement is to fix an issue in an existing repository. The p
}
},
{
"command_name": "append_task",
"command_name": "Plan.append_task",
"args": {
"task_id": "2",
"dependent_task_ids": ["1"],
@ -234,7 +241,7 @@ Explanation: The requirement is to fix an issue in an existing repository. The p
}
},
{
"command_name": "append_task",
"command_name": "Plan.append_task",
"args": {
"task_id": "3",
"dependent_task_ids": ["2"],
@ -243,7 +250,7 @@ Explanation: The requirement is to fix an issue in an existing repository. The p
}
},
{
"command_name": "append_task",
"command_name": "Plan.append_task",
"args": {
"task_id": "4",
"dependent_task_ids": ["3"],
@ -252,7 +259,7 @@ Explanation: The requirement is to fix an issue in an existing repository. The p
}
},
{
"command_name": "append_task",
"command_name": "Plan.append_task",
"args": {
"task_id": "5",
"dependent_task_ids": ["4"],