Use plan/act mode

This commit is contained in:
Saoud Rizwan 2025-01-20 00:29:25 -08:00
parent a88504e4fe
commit df31f6bfeb
9 changed files with 82 additions and 55 deletions

View file

@ -98,6 +98,8 @@ export class Cline {
conversationHistoryDeletedRange?: [number, number]
isInitialized = false
private advisorProblem?: string
isAwaitingPlanResponse = false
didRespondToPlanAskBySwitchingMode = false
// streaming
isWaitingForFirstChunk = false
@ -751,8 +753,6 @@ export class Cline {
this.apiConversationHistory = []
await this.providerRef.deref()?.postStateToWebview()
await this.providerRef.deref()?.switchToTaskMode()
await this.say("text", task, images)
this.isInitialized = true
@ -994,8 +994,8 @@ export class Cline {
type: "text",
text:
`[TASK RESUMPTION] ${
this.chatSettings?.mode === "chat"
? `This task was interrupted ${agoText}. The conversation may have been incomplete. Be aware that the project state may have changed since then. The current working directory is now '${cwd.toPosix()}'.\n\nNote: If you previously attempted a tool use that the user did not provide a result for, you should assume the tool use was not successful. However you are in CHAT MODE, so rather than continuing the task, you must respond to the user's message.`
this.chatSettings?.mode === "plan"
? `This task was interrupted ${agoText}. The conversation may have been incomplete. Be aware that the project state may have changed since then. The current working directory is now '${cwd.toPosix()}'.\n\nNote: If you previously attempted a tool use that the user did not provide a result for, you should assume the tool use was not successful. However you are in PLAN MODE, so rather than continuing the task, you must respond to the user's message.`
: `This task was interrupted ${agoText}. It may or may not be complete, so please reassess the task context. Be aware that the project state may have changed since then. The current working directory is now '${cwd.toPosix()}'. If the task has not been completed, retry the last step before interruption and proceed with completing the task.\n\nNote: If you previously attempted a tool use that the user did not provide a result for, you should assume the tool use was not successful and assess whether you should retry. If the last tool was a browser_action, the browser has been closed and you must launch a new browser if needed.`
}${
wasRecent
@ -1003,8 +1003,10 @@ export class Cline {
: ""
}` +
(responseText
? `\n\n${this.chatSettings?.mode === "chat" ? "New message to respond to with chat_mode_response tool (be sure to provide your response in the <response> parameter)" : "New instructions for task continuation"}:\n<user_message>\n${responseText}\n</user_message>`
: ""),
? `\n\n${this.chatSettings?.mode === "plan" ? "New message to respond to with plan_mode_response tool (be sure to provide your response in the <response> parameter)" : "New instructions for task continuation"}:\n<user_message>\n${responseText}\n</user_message>`
: this.chatSettings.mode === "plan"
? "(The user did not provide a new message. Consider asking them how they'd like you to proceed, or to switch to Act mode to continue with the task.)"
: ""),
})
if (responseImages && responseImages.length > 0) {
@ -1525,8 +1527,8 @@ export class Cline {
return `[${block.name} for '${block.params.problem}']`
case "ask_followup_question":
return `[${block.name} for '${block.params.question}']`
case "chat_mode_response":
return `[${block.name} for '${block.params.response}']`
case "plan_mode_response":
return `[${block.name}]`
case "attempt_completion":
return `[${block.name}]`
}
@ -2729,18 +2731,18 @@ export class Cline {
break
}
}
case "chat_mode_response": {
case "plan_mode_response": {
const response: string | undefined = block.params.response
try {
if (block.partial) {
await this.ask("chat_mode_response", removeClosingTag("response", response), block.partial).catch(
await this.ask("plan_mode_response", removeClosingTag("response", response), block.partial).catch(
() => {},
)
break
} else {
if (!response) {
this.consecutiveMistakeCount++
pushToolResult(await this.sayAndCreateMissingParamError("chat_mode_response", "response"))
pushToolResult(await this.sayAndCreateMissingParamError("plan_mode_response", "response"))
// await this.saveCheckpoint()
break
}
@ -2753,9 +2755,23 @@ export class Cline {
// })
// }
const { text, images } = await this.ask("chat_mode_response", response, false)
await this.say("user_feedback", text ?? "", images)
pushToolResult(formatResponse.toolResult(`<user_message>\n${text}\n</user_message>`, images))
this.isAwaitingPlanResponse = true
const { text, images } = await this.ask("plan_mode_response", response, false)
this.isAwaitingPlanResponse = false
if (this.didRespondToPlanAskBySwitchingMode) {
// await this.say("user_feedback", text ?? "", images)
pushToolResult(
formatResponse.toolResult(
`[The user has switched to ACT MODE, so you may now proceed with the task.]`,
images,
),
)
} else {
await this.say("user_feedback", text ?? "", images)
pushToolResult(formatResponse.toolResult(`<user_message>\n${text}\n</user_message>`, images))
}
// await this.saveCheckpoint()
break
}
@ -3471,13 +3487,14 @@ export class Cline {
}
details += "\n\n# Current Mode"
if (this.chatSettings.mode === "chat") {
details += "\nCHAT MODE"
if (this.chatSettings.mode === "plan") {
details += "\nPLAN MODE"
details += '\nSee "## What is PLAN MODE?" above for more information about what to do in this mode.'
details +=
'\n(Remember: You now only have access to the chat_mode_response tool. If it seems the user wants you to use tools only available in TASK MODE, you should ask the user to "toggle to Task mode" - they will have to manually do this themselves with the Task/Chat toggle button below.)'
'\n(Remember: You now only have access to the plan_mode_response tool. If it seems the user wants you to use tools only available in ACT MODE, you should ask the user to "toggle to Act mode" - they will have to manually do this themselves with the Plan/Act toggle button below. You do not have the ability to switch to ACT MODE yourself, and must wait for the user to do it themselves once they are satisfied with the plan.)'
} else {
details += "\nTASK MODE"
details += "\n(Remember: You cannot use the chat_mode_response tool.)"
details += "\nACT MODE"
details += "\n(Remember: You cannot use the plan_mode_response tool.)"
}
return `<environment_details>\n${details.trim()}\n</environment_details>`

View file

@ -21,7 +21,7 @@ export const toolUseNames = [
"access_mcp_resource",
"consult_advisor",
"ask_followup_question",
"chat_mode_response",
"plan_mode_response",
"attempt_completion",
] as const

View file

@ -243,14 +243,14 @@ Your final result description here
<command>Command to demonstrate result (optional)</command>
</attempt_completion>
## chat_mode_response
Description: Respond to the user's inquiry with a clear answer. This tool should be used when you need to provide a response to a question or statement. This tool is only available in CHAT MODE. The environment_details will specify the current mode, if it is not chat mode then you should not use this tool.
## plan_mode_response
Description: Respond to the user's inquiry with a clear answer in an effort to plan a solution to the user's task. This tool should be used when you need to provide a response to a question or statement from the user about how you plan to accomplish the task. This tool is only available in PLAN MODE. The environment_details will specify the current mode, if it is not PLAN MODE then you should not use this tool. Depending on the user's message, you may ask questions to get clarification about the user's request, architect a solution to the task, and to brainstorm ideas with the user. For example, if the user's task is to create a website, you may start by asking some clarifying questions, then present a detailed plan for how you will accomplish the task given the context, and perhaps engage in a back and forth to finalize the details before the user switches you to ACT MODE to implement the solution.
Parameters:
- response: (required) The response to provide to the user. This should be a clear answer that addresses the user's inquiry.
- response: (required) The response to provide to the user.
Usage:
<chat_mode_response>
<plan_mode_response>
<response>Your response here</response>
</chat_mode_response>
</plan_mode_response>
# Tool Use Examples
@ -905,17 +905,26 @@ Remember: While you should attempt to solve problems with your own reasoning fir
====
TASK MODE V.S. CHAT MODE
ACT MODE V.S. PLAN MODE
In each user message, the environment_details will specify the current mode. There are two modes:
- TASK MODE: In this mode, you have access to all tools EXCEPT the chat_mode_response tool.
- ACT MODE: In this mode, you have access to all tools EXCEPT the plan_mode_response tool.
- In task mode, you use tools to accomplish the user's task. Once you've completed the user's task, you use the attempt_completion tool to present the result of the task to the user.
- CHAT MODE: In this mode, you ONLY have access to the chat_mode_response tool.
- In chat mode, you should immediately use the chat_mode_response tool to deliver your response, rather than using <thinking> tags to analyze when to respond. Do not talk about using chat_mode_response - just use it directly to share your thoughts and provide helpful answers.
- PLAN MODE: In this special mode, you ONLY have access to the plan_mode_response tool.
- In plan mode, you should immediately use the plan_mode_response tool to deliver your response, rather than using <thinking> tags to analyze when to respond. Do not talk about using plan_mode_response - just use it directly to share your thoughts and provide helpful answers.
You should only use tools that are available in the current mode.
## What is PLAN MODE?
- While you are usually in ACT MODE, the user may switch to PLAN MODE in order to have a back and forth with you to plan how to best accomplish the task.
- When starting in PLAN MODE, ask the user some clarifying questions to get a better understanding of the task. (Generally three questions are enough to get the conversation started, but you may ask more questions if needed.)
- Make sure to wait for the user's response to your questions before moving on in creating a plan.
- Once you've gained more context about the user's request, you should architect and a detailed plan for how you will accomplish the task.
- Then you might ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and plan the best way to accomplish it.
- Finally once it seems like you've reached a good plan, ask the user to switch you back to ACT MODE to implement the solution.
====
CAPABILITIES

View file

@ -486,12 +486,23 @@ export class ClineProvider implements vscode.WebviewViewProvider {
break
case "chatSettings":
if (message.chatSettings) {
const didSwitchToActMode = message.chatSettings.mode === "act"
await this.updateGlobalState("chatSettings", message.chatSettings)
await this.postStateToWebview()
if (this.cline) {
this.cline.updateChatSettings(message.chatSettings)
if (this.cline.isAwaitingPlanResponse && didSwitchToActMode) {
this.cline.didRespondToPlanAskBySwitchingMode = true
// this is necessary for the webview to update accordingly, but Cline instance will not send text back as feedback message
await this.postMessageToWebview({
type: "invoke",
invoke: "sendMessage",
text: "[Proceeding with the task...]",
})
} else {
this.cancelTask()
}
}
await this.postStateToWebview()
this.cancelTask()
}
break
// case "relaunchChromeDebugMode":
@ -673,16 +684,6 @@ export class ClineProvider implements vscode.WebviewViewProvider {
}
}
async switchToTaskMode() {
const { chatSettings } = await this.getState()
chatSettings.mode = "task"
await this.updateGlobalState("chatSettings", chatSettings)
if (this.cline) {
this.cline.updateChatSettings(chatSettings)
}
await this.postStateToWebview()
}
async updateCustomInstructions(instructions?: string) {
// User may be clearing the field
await this.updateGlobalState("customInstructions", instructions || undefined)

View file

@ -1,7 +1,7 @@
export interface ChatSettings {
mode: "task" | "chat"
mode: "plan" | "act"
}
export const DEFAULT_CHAT_SETTINGS: ChatSettings = {
mode: "task",
mode: "act",
}

View file

@ -69,7 +69,7 @@ export interface ClineMessage {
export type ClineAsk =
| "followup"
| "chat_mode_response"
| "plan_mode_response"
| "command"
| "command_output"
| "completion_result"

View file

@ -1270,7 +1270,7 @@ export const ChatRowContent = ({ message, isExpanded, onToggleExpand, lastModifi
</div>
</>
)
case "chat_mode_response":
case "plan_mode_response":
return (
<div style={{}}>
<Markdown markdown={message.text} />

View file

@ -75,13 +75,13 @@ const SwitchContainer = styled.div<{ disabled: boolean }>`
margin-left: -10px; // compensate for the transform so flex spacing works
`
const Slider = styled.div<{ isChat: boolean }>`
const Slider = styled.div<{ isAct: boolean }>`
position: absolute;
height: 100%;
width: 50%;
background-color: var(--vscode-badge-background);
transition: transform 0.2s ease;
transform: translateX(${(props) => (props.isChat ? "100%" : "0%")});
transform: translateX(${(props) => (props.isAct ? "100%" : "0%")});
`
const ButtonGroup = styled.div`
@ -597,7 +597,7 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
const onModeToggle = useCallback(() => {
if (textAreaDisabled) return
const newMode = chatSettings.mode === "chat" ? "task" : "chat"
const newMode = chatSettings.mode === "plan" ? "act" : "plan"
vscode.postMessage({
type: "chatSettings",
chatSettings: {
@ -1008,9 +1008,9 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
</ButtonGroup>
<SwitchContainer disabled={textAreaDisabled} onClick={onModeToggle}>
<Slider isChat={chatSettings.mode === "chat"} />
<SwitchOption isActive={chatSettings.mode === "task"}>Task</SwitchOption>
<SwitchOption isActive={chatSettings.mode === "chat"}>Chat</SwitchOption>
<Slider isAct={chatSettings.mode === "act"} />
<SwitchOption isActive={chatSettings.mode === "plan"}>Plan</SwitchOption>
<SwitchOption isActive={chatSettings.mode === "act"}>Act</SwitchOption>
</SwitchContainer>
</ControlsContainer>
</div>

View file

@ -103,9 +103,9 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
// setPrimaryButtonText(undefined)
// setSecondaryButtonText(undefined)
break
case "chat_mode_response":
case "plan_mode_response":
setTextAreaDisabled(isPartial)
setClineAsk("chat_mode_response")
setClineAsk("plan_mode_response")
setEnableButtons(false)
// setPrimaryButtonText(undefined)
// setSecondaryButtonText(undefined)
@ -174,7 +174,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
setTextAreaDisabled(false)
setClineAsk("resume_task")
setEnableButtons(true)
setPrimaryButtonText("Resume")
setPrimaryButtonText("Resume Task")
setSecondaryButtonText(undefined)
setDidClickCancel(false) // special case where we reset the cancel button state
break
@ -278,7 +278,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
} else if (clineAsk) {
switch (clineAsk) {
case "followup":
case "chat_mode_response":
case "plan_mode_response":
case "tool":
case "browser_action_launch":
case "command": // user can provide feedback to a tool or command use