| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- import delay from "delay"
- import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../shared/tools"
- import { Task } from "../task/Task"
- import { defaultModeSlug, getModeBySlug } from "../../shared/modes"
- import { formatResponse } from "../prompts/responses"
- import { t } from "../../i18n"
- export async function newTaskTool(
- cline: Task,
- block: ToolUse,
- askApproval: AskApproval,
- handleError: HandleError,
- pushToolResult: PushToolResult,
- removeClosingTag: RemoveClosingTag,
- ) {
- const mode: string | undefined = block.params.mode
- const message: string | undefined = block.params.message
- try {
- if (block.partial) {
- const partialMessage = JSON.stringify({
- tool: "newTask",
- mode: removeClosingTag("mode", mode),
- message: removeClosingTag("message", message),
- })
- await cline.ask("tool", partialMessage, block.partial).catch(() => {})
- return
- } else {
- if (!mode) {
- cline.consecutiveMistakeCount++
- cline.recordToolError("new_task")
- pushToolResult(await cline.sayAndCreateMissingParamError("new_task", "mode"))
- return
- }
- if (!message) {
- cline.consecutiveMistakeCount++
- cline.recordToolError("new_task")
- pushToolResult(await cline.sayAndCreateMissingParamError("new_task", "message"))
- return
- }
- cline.consecutiveMistakeCount = 0
- // Un-escape one level of backslashes before '@' for hierarchical subtasks
- // Un-escape one level: \\@ -> \@ (removes one backslash for hierarchical subtasks)
- const unescapedMessage = message.replace(/\\\\@/g, "\\@")
- // Verify the mode exists
- const targetMode = getModeBySlug(mode, (await cline.providerRef.deref()?.getState())?.customModes)
- if (!targetMode) {
- pushToolResult(formatResponse.toolError(`Invalid mode: ${mode}`))
- return
- }
- const toolMessage = JSON.stringify({
- tool: "newTask",
- mode: targetMode.name,
- content: message,
- })
- const didApprove = await askApproval("tool", toolMessage)
- if (!didApprove) {
- return
- }
- const provider = cline.providerRef.deref()
- if (!provider) {
- return
- }
- if (cline.enableCheckpoints) {
- cline.checkpointSave(true)
- }
- // Preserve the current mode so we can resume with it later.
- cline.pausedModeSlug = (await provider.getState()).mode ?? defaultModeSlug
- // Switch mode first, then create new task instance.
- await provider.handleModeSwitch(mode)
- // Delay to allow mode change to take effect before next tool is executed.
- await delay(500)
- const newCline = await provider.initClineWithTask(unescapedMessage, undefined, cline)
- if (!newCline) {
- pushToolResult(t("tools:newTask.errors.policy_restriction"))
- return
- }
- cline.emit("taskSpawned", newCline.taskId)
- pushToolResult(`Successfully created new task in ${targetMode.name} mode with message: ${unescapedMessage}`)
- // Set the isPaused flag to true so the parent
- // task can wait for the sub-task to finish.
- cline.isPaused = true
- cline.emit("taskPaused")
- return
- }
- } catch (error) {
- await handleError("creating new task", error)
- return
- }
- }
|