/
outbreak
/
kilocode
Обзор
Документация
Войти
/
outbreak
/
kilocode
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/core/tools/NewTaskTool.ts
159 строк
5 KB
Hannes Rudolph
Metadata‑driven subtasks (no UI changes): automatic parent resume and single‑open safety (#9090)
28 ноя 2025, 07:18
Не верифицирован
28 ноя 2025, 07:18
9b5f639
Код
Авторство
О чём код?
import * as vscode from "vscode" import { TodoItem } from "@roo-code/types" import { Task } from "../task/Task" import { getModeBySlug } from "../../shared/modes" import { formatResponse } from "../prompts/responses" import { t } from "../../i18n" import { parseMarkdownChecklist } from "./UpdateTodoListTool" import { Package } from "../../shared/package" import { BaseTool, ToolCallbacks } from "./BaseTool" import type { ToolUse } from "../../shared/tools" interface NewTaskParams { mode: string message: string todos?: string } export class NewTaskTool extends BaseTool<"new_task"> { readonly name = "new_task" as const parseLegacy(params: Partial<Record<string, string>>): NewTaskParams { return { mode: params.mode || "", message: params.message || "", todos: params.todos, } } async execute(params: NewTaskParams, task: Task, callbacks: ToolCallbacks): Promise<void> { const { mode, message, todos } = params const { askApproval, handleError, pushToolResult, toolProtocol, toolCallId } = callbacks try { // Validate required parameters. if (!mode) { task.consecutiveMistakeCount++ task.recordToolError("new_task") task.didToolFailInCurrentTurn = true pushToolResult(await task.sayAndCreateMissingParamError("new_task", "mode")) return } if (!message) { task.consecutiveMistakeCount++ task.recordToolError("new_task") task.didToolFailInCurrentTurn = true pushToolResult(await task.sayAndCreateMissingParamError("new_task", "message")) return } // Get the VSCode setting for requiring todos. const provider = task.providerRef.deref() if (!provider) { pushToolResult(formatResponse.toolError("Provider reference lost")) return } const state = await provider.getState() // Use Package.name (dynamic at build time) as the VSCode configuration namespace. // Supports multiple extension variants (e.g., stable/nightly) without hardcoded strings. const requireTodos = vscode.workspace .getConfiguration(Package.name) .get<boolean>("newTaskRequireTodos", false) // Check if todos are required based on VSCode setting. // Note: `undefined` means not provided, empty string is valid. if (requireTodos && todos === undefined) { task.consecutiveMistakeCount++ task.recordToolError("new_task") task.didToolFailInCurrentTurn = true pushToolResult(await task.sayAndCreateMissingParamError("new_task", "todos")) return } // Parse todos if provided, otherwise use empty array let todoItems: TodoItem[] = [] if (todos) { try { todoItems = parseMarkdownChecklist(todos) } catch (error) { task.consecutiveMistakeCount++ task.recordToolError("new_task") task.didToolFailInCurrentTurn = true pushToolResult(formatResponse.toolError("Invalid todos format: must be a markdown checklist")) return } } task.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, state?.customModes) if (!targetMode) { pushToolResult(formatResponse.toolError(`Invalid mode: ${mode}`)) return } const toolMessage = JSON.stringify({ tool: "newTask", mode: targetMode.name, content: message, todos: todoItems, }) const didApprove = await askApproval("tool", toolMessage) if (!didApprove) { return } // Provider is guaranteed to be defined here due to earlier check. if (task.enableCheckpoints) { task.checkpointSave(true) } // Delegate parent and open child as sole active task const child = await (provider as any).delegateParentAndOpenChild({ parentTaskId: task.taskId, message: unescapedMessage, initialTodos: todoItems, mode, }) // Reflect delegation in tool result (no pause/unpause, no wait) pushToolResult(`Delegated to child task ${child.taskId}`) return } catch (error) { await handleError("creating new task", error) return } } override async handlePartial(task: Task, block: ToolUse<"new_task">): Promise<void> { const mode: string | undefined = block.params.mode const message: string | undefined = block.params.message const todos: string | undefined = block.params.todos const partialMessage = JSON.stringify({ tool: "newTask", mode: this.removeClosingTag("mode", mode, block.partial), content: this.removeClosingTag("message", message, block.partial), todos: this.removeClosingTag("todos", todos, block.partial), }) await task.ask("tool", partialMessage, block.partial).catch(() => {}) } } export const newTaskTool = new NewTaskTool()