New Horizons (#2747)

* new task tool added

* small fix

* fixed numbering

* system prompt
This commit is contained in:
pashpashpash 2025-04-08 17:20:30 -07:00 committed by GitHub
parent be120e85be
commit 4c72bd96ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 188 additions and 4 deletions

View File

@ -0,0 +1,5 @@
---
"claude-dev": minor
---
Added a new task tool to cline's arsenal

View File

@ -82,6 +82,7 @@ Cline has access to the following tools for various tasks:
4. **Interaction Tools**
- `ask_followup_question`: Ask user for clarification
- `attempt_completion`: Present final results
- `new_task`: Start a new task with preloaded context
Each tool has specific parameters and usage patterns. Here are some examples:
@ -114,6 +115,21 @@ Each tool has specific parameters and usage patterns. Here are some examples:
</execute_command>
```
- Start a new task with context (new_task):
```xml
<new_task>
<context>
We've completed the backend API with these endpoints:
- GET /api/tasks
- POST /api/tasks
- PUT /api/tasks/:id
- DELETE /api/tasks/:id
Now we need to implement the React frontend.
</context>
</new_task>
```
## Common Tasks
1. **Create a New Component**

View File

@ -23,6 +23,7 @@ export const toolUseNames = [
"plan_mode_respond",
"load_mcp_documentation",
"attempt_completion",
"new_task",
] as const
// Converts array of tool call names into a union type ("execute_command" | "read_file" | ...)
@ -49,6 +50,7 @@ export const toolParamNames = [
"options",
"response",
"result",
"context",
] as const
export type ToolParamName = (typeof toolParamNames)[number]

View File

@ -209,6 +209,9 @@ Otherwise, if you have not completed the task and do not need additional informa
clineRulesFileInstructions: (cwd: string, content: string) =>
`# .clinerules\n\nThe following is provided by a root-level .clinerules file where the user has specified instructions for this working directory (${cwd.toPosix()})\n\n${content}`,
newTaskContext: (context: string) =>
`Cline wants to start a new task with the following context:\n\n${context}\n\nClick "Start New Task" to start a new task with this context preloaded.`,
}
// to avoid circular dependency

View File

@ -233,6 +233,20 @@ Your final result description here
<command>Command to demonstrate result (optional)</command>
</attempt_completion>
## new_task
Description: Request to create a new task with preloaded context. The user will be presented with a preview of the context and can choose to create a new task or keep chatting in the current conversation. The user may choose to start a new task at any point.
Parameters:
- context: (required) The context to preload the new task with. This should include:
* Comprehensively explain what has been accomplished in the current task - mention specific file names that are relevant
* The specific next steps or focus for the new task - mention specific file names that are relevant
* Any critical information needed to continue the work
* Clear indication of how this new task relates to the overall workflow
* This should be akin to a long handoff file, enough for a totally new developer to be able to pick up where you left off and know exactly what to do next and which files to look at.
Usage:
<new_task>
<context>context to preload new task with</context>
</new_task>
## plan_mode_respond
Description: Respond to the user's inquiry 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:
@ -284,7 +298,25 @@ Usage:
</content>
</write_to_file>
## Example 3: Requesting to make targeted edits to a file
## Example 3: Creating a new task
<new_task>
<context>
Authentication System Implementation:
- We've implemented the basic user model with email/password
- Password hashing is working with bcrypt
- Login endpoint is functional with proper validation
- JWT token generation is implemented
Next Steps:
- Implement refresh token functionality
- Add token validation middleware
- Create password reset flow
- Implement role-based access control
</context>
</new_task>
## Example 4: Requesting to make targeted edits to a file
<replace_in_file>
<path>src/components/App.tsx</path>
@ -319,7 +351,7 @@ return (
</diff>
</replace_in_file>
## Example 4: Requesting to use an MCP tool
## Example 5: Requesting to use an MCP tool
<use_mcp_tool>
<server_name>weather-server</server_name>
@ -332,7 +364,7 @@ return (
</arguments>
</use_mcp_tool>
## Example 5: Another example of using an MCP tool (where the server name is a unique identifier such as a URL)
## Example 6: Another example of using an MCP tool (where the server name is a unique identifier such as a URL)
<use_mcp_tool>
<server_name>github.com/modelcontextprotocol/servers/tree/main/src/github</server_name>

View File

@ -1482,6 +1482,8 @@ export class Task {
return `[${block.name}]`
case "attempt_completion":
return `[${block.name}]`
case "new_task":
return `[${block.name} for creating a new task]`
}
}
@ -2750,6 +2752,51 @@ export class Task {
break
}
}
case "new_task": {
const context: string | undefined = block.params.context
try {
if (block.partial) {
await this.ask("new_task", removeClosingTag("context", context), block.partial).catch(() => {})
break
} else {
if (!context) {
this.consecutiveMistakeCount++
pushToolResult(await this.sayAndCreateMissingParamError("new_task", "context"))
break
}
this.consecutiveMistakeCount = 0
if (this.autoApprovalSettings.enabled && this.autoApprovalSettings.enableNotifications) {
showSystemNotification({
subtitle: "Cline wants to start a new task...",
message: "Cline is suggesting to start a new task with preloaded context.",
})
}
const { text, images } = await this.ask("new_task", context, false)
// If the user provided a response, treat it as feedback
if (text || images?.length) {
await this.say("user_feedback", text ?? "", images)
pushToolResult(
formatResponse.toolResult(
`The user provided feedback instead of creating a new task:\n<feedback>\n${text}\n</feedback>`,
images,
),
)
} else {
// If no response, the user clicked the "Create New Task" button
pushToolResult(
formatResponse.toolResult(`The user has created a new task with the provided context.`),
)
}
break
}
} catch (error) {
await handleError("creating new task", error)
break
}
}
case "plan_mode_respond": {
const response: string | undefined = block.params.response
const optionsRaw: string | undefined = block.params.options

View File

@ -169,6 +169,7 @@ export type ClineAsk =
| "auto_approval_max_req_reached"
| "browser_action_launch"
| "use_mcp_server"
| "new_task"
export type ClineSay =
| "task"
@ -256,6 +257,10 @@ export interface ClineAskQuestion {
selected?: string
}
export interface ClineAskNewTask {
context: string
}
export interface ClineApiReqInfo {
request?: string
tokensIn?: number

View File

@ -0,0 +1,27 @@
import * as assert from "assert"
import { ClineMessage } from "../shared/ExtensionMessage"
import { formatResponse } from "../core/prompts/responses"
suite("New Task Tool Tests", () => {
test("formatResponse.newTaskContext formats context correctly", () => {
const context = "This is a test context for a new task"
const result = formatResponse.newTaskContext(context)
assert.strictEqual(
result,
`Cline wants to create a new task with the following context:\n\nThis is a test context for a new task\n\nClick "Create New Task" to start a new task with this context preloaded in Plan Mode.`,
)
})
test("ClineAskNewTask interface exists", () => {
// This is a type check test, it will fail at compile time if the interface doesn't exist
const message: ClineMessage = {
ts: Date.now(),
type: "ask",
ask: "new_task",
text: JSON.stringify({ context: "Test context" }),
}
assert.ok(message)
})
})

View File

@ -30,6 +30,7 @@ import { OptionsButtons } from "@/components/chat/OptionsButtons"
import { highlightMentions } from "./TaskHeader"
import SuccessButton from "@/components/common/SuccessButton"
import TaskFeedbackButtons from "@/components/chat/TaskFeedbackButtons"
import NewTaskPreview from "./NewTaskPreview"
import McpResourceRow from "@/components/mcp/configuration/tabs/installed/server-row/McpResourceRow"
const ChatRowContainer = styled.div`
@ -1248,6 +1249,21 @@ export const ChatRowContent = ({ message, isExpanded, onToggleExpand, lastModifi
</div>
</>
)
case "new_task":
return (
<>
<div style={headerStyle}>
<span
className="codicon codicon-new-file"
style={{
color: normalColor,
marginBottom: "-1.5px",
}}></span>
<span style={{ color: normalColor, fontWeight: "bold" }}>Cline wants to start a new task:</span>
</div>
<NewTaskPreview context={message.text || ""} />
</>
)
case "plan_mode_respond": {
let response: string | undefined
let options: string[] | undefined

View File

@ -195,6 +195,13 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
setSecondaryButtonText(undefined)
setDidClickCancel(false)
break
case "new_task":
setTextAreaDisabled(isPartial)
setClineAsk("new_task")
setEnableButtons(!isPartial)
setPrimaryButtonText("Start New Task with Context")
setSecondaryButtonText(undefined)
break
}
break
case "say":
@ -296,6 +303,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
case "resume_task":
case "resume_completed_task":
case "mistake_limit_reached":
case "new_task": // user can provide feedback or reject the new task suggestion
vscode.postMessage({
type: "askResponse",
askResponse: "messageResponse",
@ -361,6 +369,13 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
// extension waiting for feedback. but we can just present a new task button
startNewTask()
break
case "new_task":
console.info("new task button clicked!", { lastMessage, messages, clineAsk, text })
vscode.postMessage({
type: "newTask",
text: lastMessage?.text,
})
break
}
setTextAreaDisabled(true)
setClineAsk(undefined)
@ -369,7 +384,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
// setSecondaryButtonText(undefined)
disableAutoScrollRef.current = false
},
[clineAsk, startNewTask],
[clineAsk, startNewTask, lastMessage],
)
const handleSecondaryButtonClick = useCallback(

View File

@ -0,0 +1,16 @@
import React from "react"
import MarkdownBlock from "../common/MarkdownBlock"
interface NewTaskPreviewProps {
context: string
}
const NewTaskPreview: React.FC<NewTaskPreviewProps> = ({ context }) => {
return (
<div className="bg-[var(--vscode-badge-background)] text-[var(--vscode-badge-foreground)] rounded-[3px] p-[9px] pt-0 border-t-8 border-[var(--vscode-charts-green)]">
<MarkdownBlock markdown={context} />
</div>
)
}
export default NewTaskPreview