From 4bf0a43964e8d5109bbe679470a5bf6e553c6495 Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Wed, 6 Aug 2025 15:48:43 -0700 Subject: [PATCH 01/12] feat: add optional todos parameter to new_task tool with experimental setting (#6329) - Add optional todos parameter to new_task tool for hierarchical task planning - Implement experimental setting to optionally require todos parameter - Add clean state-based UI rendering to avoid spurious messages - Export and reuse parseMarkdownChecklist function - Add comprehensive test coverage for both optional and required modes - Maintain full backward compatibility (todos optional by default) --- packages/types/src/experiment.ts | 9 +- src/core/prompts/tools/new-task.ts | 17 +- src/core/task/Task.ts | 17 +- src/core/tools/__tests__/newTaskTool.spec.ts | 420 +++++++++++++++++- src/core/tools/newTaskTool.ts | 47 +- src/core/tools/updateTodoListTool.ts | 2 +- src/core/webview/ClineProvider.ts | 9 +- src/shared/ExtensionMessage.ts | 2 + src/shared/__tests__/experiments.spec.ts | 3 + src/shared/experiments.ts | 2 + src/shared/tools.ts | 2 +- webview-ui/src/components/chat/ChatView.tsx | 15 +- .../src/context/ExtensionStateContext.tsx | 1 + .../__tests__/ExtensionStateContext.spec.tsx | 2 + webview-ui/src/i18n/locales/en/settings.json | 4 + 15 files changed, 534 insertions(+), 18 deletions(-) diff --git a/packages/types/src/experiment.ts b/packages/types/src/experiment.ts index 6574124629..35f6cbaf48 100644 --- a/packages/types/src/experiment.ts +++ b/packages/types/src/experiment.ts @@ -6,7 +6,13 @@ import type { Keys, Equals, AssertEqual } from "./type-fu.js" * ExperimentId */ -export const experimentIds = ["powerSteering", "multiFileApplyDiff", "preventFocusDisruption", "assistantMessageParser"] as const +export const experimentIds = [ + "powerSteering", + "multiFileApplyDiff", + "preventFocusDisruption", + "assistantMessageParser", + "newTaskRequireTodos", +] as const export const experimentIdsSchema = z.enum(experimentIds) @@ -21,6 +27,7 @@ export const experimentsSchema = z.object({ multiFileApplyDiff: z.boolean().optional(), preventFocusDisruption: z.boolean().optional(), assistantMessageParser: z.boolean().optional(), + newTaskRequireTodos: z.boolean().optional(), }) export type Experiments = z.infer diff --git a/src/core/prompts/tools/new-task.ts b/src/core/prompts/tools/new-task.ts index 7301b7b422..37a0a7783e 100644 --- a/src/core/prompts/tools/new-task.ts +++ b/src/core/prompts/tools/new-task.ts @@ -2,22 +2,35 @@ import { ToolArgs } from "./types" export function getNewTaskDescription(_args: ToolArgs): string { return `## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message. +Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. +- todos: (optional by default, can be required via experimental setting) The initial todo list in markdown checklist format for the new task. + Note: The 'todos' parameter can be configured to be required through the experimental setting 'newTaskRequireTodos'. Usage: your-mode-slug-here Your initial instructions here + +[ ] First task to complete +[ ] Second task to complete +[ ] Third task to complete + Example: code -Implement a new feature for the application. +Implement user authentication + +[ ] Set up auth middleware +[ ] Create login endpoint +[ ] Add session management +[ ] Write tests + ` } diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index 34f3218236..002493b7e8 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -123,6 +123,7 @@ export type TaskOptions = { parentTask?: Task taskNumber?: number onCreated?: (task: Task) => void + initialTodos?: TodoItem[] } export class Task extends EventEmitter implements TaskLike { @@ -287,6 +288,7 @@ export class Task extends EventEmitter implements TaskLike { parentTask, taskNumber = -1, onCreated, + initialTodos, }: TaskOptions) { super() @@ -370,11 +372,16 @@ export class Task extends EventEmitter implements TaskLike { this.toolRepetitionDetector = new ToolRepetitionDetector(this.consecutiveMistakeLimit) + // Initialize todo list if provided + if (initialTodos && initialTodos.length > 0) { + this.todoList = initialTodos + } + onCreated?.(this) if (startTask) { if (task || images) { - this.startTask(task, images) + this.startTask(task, images, initialTodos) } else if (historyItem) { this.resumeTaskFromHistory() } else { @@ -1052,7 +1059,7 @@ export class Task extends EventEmitter implements TaskLike { // Start / Abort / Resume - private async startTask(task?: string, images?: string[]): Promise { + private async startTask(task?: string, images?: string[], initialTodos?: TodoItem[]): Promise { if (this.enableTaskBridge) { try { this.bridgeService = this.bridgeService || ExtensionBridgeService.getInstance() @@ -1075,9 +1082,13 @@ export class Task extends EventEmitter implements TaskLike { // messages from previous session). this.clineMessages = [] this.apiConversationHistory = [] - await this.providerRef.deref()?.postStateToWebview() + + // The todo list is already set in the constructor if initialTodos were provided + // No need to add any messages - the todoList property is already set await this.say("text", task, images) + + await this.providerRef.deref()?.postStateToWebview() this.isInitialized = true let imageBlocks: Anthropic.ImageBlockParam[] = formatResponse.imageBlocks(images) diff --git a/src/core/tools/__tests__/newTaskTool.spec.ts b/src/core/tools/__tests__/newTaskTool.spec.ts index 8680a60035..621a9b4f0e 100644 --- a/src/core/tools/__tests__/newTaskTool.spec.ts +++ b/src/core/tools/__tests__/newTaskTool.spec.ts @@ -8,12 +8,48 @@ vi.mock("../../../shared/modes", () => ({ defaultModeSlug: "ask", })) +vi.mock("../../../shared/experiments", () => ({ + experiments: { + isEnabled: vi.fn(), + }, + EXPERIMENT_IDS: { + NEW_TASK_REQUIRE_TODOS: "newTaskRequireTodos", + }, +})) + vi.mock("../../prompts/responses", () => ({ formatResponse: { toolError: vi.fn((msg: string) => `Tool Error: ${msg}`), }, })) +vi.mock("../updateTodoListTool", () => ({ + parseMarkdownChecklist: vi.fn((md: string) => { + // Simple mock implementation + const lines = md.split("\n").filter((line) => line.trim()) + return lines.map((line, index) => { + let status = "pending" + let content = line + + if (line.includes("[x]") || line.includes("[X]")) { + status = "completed" + content = line.replace(/^\[x\]\s*/i, "") + } else if (line.includes("[-]") || line.includes("[~]")) { + status = "in_progress" + content = line.replace(/^\[-\]\s*/, "").replace(/^\[~\]\s*/, "") + } else { + content = line.replace(/^\[\s*\]\s*/, "") + } + + return { + id: `todo-${index}`, + content, + status, + } + }) + }), +})) + // Define a minimal type for the resolved value type MockClineInstance = { taskId: string } @@ -22,7 +58,9 @@ const mockAskApproval = vi.fn() const mockHandleError = vi.fn() const mockPushToolResult = vi.fn() const mockRemoveClosingTag = vi.fn((_name: string, value: string | undefined) => value ?? "") -const mockCreateTask = vi.fn<() => Promise>().mockResolvedValue({ taskId: "mock-subtask-id" }) +const mockCreateTask = vi + .fn<(text?: string, images?: string[], parentTask?: any, options?: any) => Promise>() + .mockResolvedValue({ taskId: "mock-subtask-id" }) const mockEmit = vi.fn() const mockRecordToolError = vi.fn() const mockSayAndCreateMissingParamError = vi.fn() @@ -49,6 +87,7 @@ const mockCline = { import { newTaskTool } from "../newTaskTool" import type { ToolUse } from "../../../shared/tools" import { getModeBySlug } from "../../../shared/modes" +import { experiments } from "../../../shared/experiments" describe("newTaskTool", () => { beforeEach(() => { @@ -63,6 +102,8 @@ describe("newTaskTool", () => { }) // Default valid mode mockCline.consecutiveMistakeCount = 0 mockCline.isPaused = false + // Default: experimental setting is disabled + vi.mocked(experiments.isEnabled).mockReturnValue(false) }) it("should correctly un-escape \\\\@ to \\@ in the message passed to the new task", async () => { @@ -72,6 +113,7 @@ describe("newTaskTool", () => { params: { mode: "code", message: "Review this: \\\\@file1.txt and also \\\\\\\\@file2.txt", // Input with \\@ and \\\\@ + todos: "[ ] First task\n[ ] Second task", }, partial: false, } @@ -93,6 +135,12 @@ describe("newTaskTool", () => { "Review this: \\@file1.txt and also \\\\\\@file2.txt", // Unit Test Expectation: \\@ -> \@, \\\\@ -> \\\\@ undefined, mockCline, + expect.objectContaining({ + initialTodos: expect.arrayContaining([ + expect.objectContaining({ content: "First task" }), + expect.objectContaining({ content: "Second task" }), + ]), + }), ) // Verify side effects @@ -109,6 +157,7 @@ describe("newTaskTool", () => { params: { mode: "code", message: "This is already unescaped: \\@file1.txt", + todos: "[ ] Test todo", }, partial: false, } @@ -126,6 +175,9 @@ describe("newTaskTool", () => { "This is already unescaped: \\@file1.txt", // Expected: \@ remains \@ undefined, mockCline, + expect.objectContaining({ + initialTodos: expect.any(Array), + }), ) }) @@ -136,6 +188,7 @@ describe("newTaskTool", () => { params: { mode: "code", message: "A normal mention @file1.txt", + todos: "[ ] Test todo", }, partial: false, } @@ -153,6 +206,9 @@ describe("newTaskTool", () => { "A normal mention @file1.txt", // Expected: @ remains @ undefined, mockCline, + expect.objectContaining({ + initialTodos: expect.any(Array), + }), ) }) @@ -163,6 +219,7 @@ describe("newTaskTool", () => { params: { mode: "code", message: "Mix: @file0.txt, \\@file1.txt, \\\\@file2.txt, \\\\\\\\@file3.txt", + todos: "[ ] Test todo", }, partial: false, } @@ -180,8 +237,367 @@ describe("newTaskTool", () => { "Mix: @file0.txt, \\@file1.txt, \\@file2.txt, \\\\\\@file3.txt", // Unit Test Expectation: @->@, \@->\@, \\@->\@, \\\\@->\\\\@ undefined, mockCline, + expect.objectContaining({ + initialTodos: expect.any(Array), + }), + ) + }) + + it("should handle missing todos parameter gracefully (backward compatibility)", async () => { + const block: ToolUse = { + type: "tool_use", + name: "new_task", + params: { + mode: "code", + message: "Test message", + // todos missing - should work for backward compatibility + }, + partial: false, + } + + await newTaskTool( + mockCline as any, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + ) + + // Should NOT error when todos is missing + expect(mockSayAndCreateMissingParamError).not.toHaveBeenCalledWith("new_task", "todos") + expect(mockCline.consecutiveMistakeCount).toBe(0) + expect(mockCline.recordToolError).not.toHaveBeenCalledWith("new_task") + + // Should create task with empty todos array + expect(mockCreateTask).toHaveBeenCalledWith( + "Test message", + undefined, + mockCline, + expect.objectContaining({ + initialTodos: [], + }), + ) + + // Should complete successfully + expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("Successfully created new task")) + }) + + it("should work with todos parameter when provided", async () => { + const block: ToolUse = { + type: "tool_use", + name: "new_task", + params: { + mode: "code", + message: "Test message with todos", + todos: "[ ] First task\n[ ] Second task", + }, + partial: false, + } + + await newTaskTool( + mockCline as any, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + ) + + // Should parse and include todos when provided + expect(mockCreateTask).toHaveBeenCalledWith( + "Test message with todos", + undefined, + mockCline, + expect.objectContaining({ + initialTodos: expect.arrayContaining([ + expect.objectContaining({ content: "First task" }), + expect.objectContaining({ content: "Second task" }), + ]), + }), + ) + + expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("Successfully created new task")) + }) + + it("should error when mode parameter is missing", async () => { + const block: ToolUse = { + type: "tool_use", + name: "new_task", + params: { + // mode missing + message: "Test message", + todos: "[ ] Test todo", + }, + partial: false, + } + + await newTaskTool( + mockCline as any, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + ) + + expect(mockSayAndCreateMissingParamError).toHaveBeenCalledWith("new_task", "mode") + expect(mockCline.consecutiveMistakeCount).toBe(1) + expect(mockCline.recordToolError).toHaveBeenCalledWith("new_task") + }) + + it("should error when message parameter is missing", async () => { + const block: ToolUse = { + type: "tool_use", + name: "new_task", + params: { + mode: "code", + // message missing + todos: "[ ] Test todo", + }, + partial: false, + } + + await newTaskTool( + mockCline as any, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + ) + + expect(mockSayAndCreateMissingParamError).toHaveBeenCalledWith("new_task", "message") + expect(mockCline.consecutiveMistakeCount).toBe(1) + expect(mockCline.recordToolError).toHaveBeenCalledWith("new_task") + }) + + it("should parse todos with different statuses correctly", async () => { + const block: ToolUse = { + type: "tool_use", + name: "new_task", + params: { + mode: "code", + message: "Test message", + todos: "[ ] Pending task\n[x] Completed task\n[-] In progress task", + }, + partial: false, + } + + await newTaskTool( + mockCline as any, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + ) + + expect(mockCreateTask).toHaveBeenCalledWith( + "Test message", + undefined, + mockCline, + expect.objectContaining({ + initialTodos: expect.arrayContaining([ + expect.objectContaining({ content: "Pending task", status: "pending" }), + expect.objectContaining({ content: "Completed task", status: "completed" }), + expect.objectContaining({ content: "In progress task", status: "in_progress" }), + ]), + }), ) }) - // Add more tests for error handling (missing params, invalid mode, approval denied) if needed + describe("experimental setting: newTaskRequireTodos", () => { + it("should NOT require todos when experimental setting is disabled (default)", async () => { + // Ensure experimental setting is disabled + vi.mocked(experiments.isEnabled).mockReturnValue(false) + + const block: ToolUse = { + type: "tool_use", + name: "new_task", + params: { + mode: "code", + message: "Test message", + // todos missing - should work when setting is disabled + }, + partial: false, + } + + await newTaskTool( + mockCline as any, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + ) + + // Should NOT error when todos is missing and setting is disabled + expect(mockSayAndCreateMissingParamError).not.toHaveBeenCalledWith("new_task", "todos") + expect(mockCline.consecutiveMistakeCount).toBe(0) + expect(mockCline.recordToolError).not.toHaveBeenCalledWith("new_task") + + // Should create task with empty todos array + expect(mockCreateTask).toHaveBeenCalledWith( + "Test message", + undefined, + mockCline, + expect.objectContaining({ + initialTodos: [], + }), + ) + + // Should complete successfully + expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("Successfully created new task")) + }) + + it("should REQUIRE todos when experimental setting is enabled", async () => { + // Enable experimental setting + vi.mocked(experiments.isEnabled).mockReturnValue(true) + + const block: ToolUse = { + type: "tool_use", + name: "new_task", + params: { + mode: "code", + message: "Test message", + // todos missing - should error when setting is enabled + }, + partial: false, + } + + await newTaskTool( + mockCline as any, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + ) + + // Should error when todos is missing and setting is enabled + expect(mockSayAndCreateMissingParamError).toHaveBeenCalledWith("new_task", "todos") + expect(mockCline.consecutiveMistakeCount).toBe(1) + expect(mockCline.recordToolError).toHaveBeenCalledWith("new_task") + + // Should NOT create task + expect(mockCreateTask).not.toHaveBeenCalled() + expect(mockPushToolResult).not.toHaveBeenCalledWith( + expect.stringContaining("Successfully created new task"), + ) + }) + + it("should work with todos when experimental setting is enabled", async () => { + // Enable experimental setting + vi.mocked(experiments.isEnabled).mockReturnValue(true) + + const block: ToolUse = { + type: "tool_use", + name: "new_task", + params: { + mode: "code", + message: "Test message", + todos: "[ ] First task\n[ ] Second task", + }, + partial: false, + } + + await newTaskTool( + mockCline as any, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + ) + + // Should NOT error when todos is provided and setting is enabled + expect(mockSayAndCreateMissingParamError).not.toHaveBeenCalledWith("new_task", "todos") + expect(mockCline.consecutiveMistakeCount).toBe(0) + + // Should create task with parsed todos + expect(mockCreateTask).toHaveBeenCalledWith( + "Test message", + undefined, + mockCline, + expect.objectContaining({ + initialTodos: expect.arrayContaining([ + expect.objectContaining({ content: "First task" }), + expect.objectContaining({ content: "Second task" }), + ]), + }), + ) + + // Should complete successfully + expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("Successfully created new task")) + }) + + it("should work with empty todos string when experimental setting is enabled", async () => { + // Enable experimental setting + vi.mocked(experiments.isEnabled).mockReturnValue(true) + + const block: ToolUse = { + type: "tool_use", + name: "new_task", + params: { + mode: "code", + message: "Test message", + todos: "", // Empty string should be accepted + }, + partial: false, + } + + await newTaskTool( + mockCline as any, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + ) + + // Should NOT error when todos is empty string and setting is enabled + expect(mockSayAndCreateMissingParamError).not.toHaveBeenCalledWith("new_task", "todos") + expect(mockCline.consecutiveMistakeCount).toBe(0) + + // Should create task with empty todos array + expect(mockCreateTask).toHaveBeenCalledWith( + "Test message", + undefined, + mockCline, + expect.objectContaining({ + initialTodos: [], + }), + ) + + // Should complete successfully + expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("Successfully created new task")) + }) + + it("should check experimental setting with correct experiment ID", async () => { + const block: ToolUse = { + type: "tool_use", + name: "new_task", + params: { + mode: "code", + message: "Test message", + }, + partial: false, + } + + await newTaskTool( + mockCline as any, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + ) + + // Verify that experiments.isEnabled was called with correct experiment ID + expect(experiments.isEnabled).toHaveBeenCalledWith(expect.any(Object), "newTaskRequireTodos") + }) + }) + + // Add more tests for error handling (invalid mode, approval denied) if needed }) diff --git a/src/core/tools/newTaskTool.ts b/src/core/tools/newTaskTool.ts index dbe08cbae8..188bb47290 100644 --- a/src/core/tools/newTaskTool.ts +++ b/src/core/tools/newTaskTool.ts @@ -1,12 +1,14 @@ import delay from "delay" -import { RooCodeEventName } from "@roo-code/types" +import { RooCodeEventName, TodoItem } from "@roo-code/types" 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" +import { parseMarkdownChecklist } from "./updateTodoListTool" +import { experiments as Experiments, EXPERIMENT_IDS } from "../../shared/experiments" export async function newTaskTool( cline: Task, @@ -18,6 +20,7 @@ export async function newTaskTool( ) { const mode: string | undefined = block.params.mode const message: string | undefined = block.params.message + const todos: string | undefined = block.params.todos try { if (block.partial) { @@ -25,11 +28,13 @@ export async function newTaskTool( tool: "newTask", mode: removeClosingTag("mode", mode), content: removeClosingTag("message", message), + todos: removeClosingTag("todos", todos), }) await cline.ask("tool", partialMessage, block.partial).catch(() => {}) return } else { + // Validate required parameters if (!mode) { cline.consecutiveMistakeCount++ cline.recordToolError("new_task") @@ -44,6 +49,33 @@ export async function newTaskTool( return } + // Get the experimental setting for requiring todos + const provider = cline.providerRef.deref() + const state = await provider?.getState() + const requireTodos = Experiments.isEnabled(state?.experiments ?? {}, EXPERIMENT_IDS.NEW_TASK_REQUIRE_TODOS) + + // Check if todos are required based on experimental setting + // Note: undefined means not provided, empty string is valid + if (requireTodos && todos === undefined) { + cline.consecutiveMistakeCount++ + cline.recordToolError("new_task") + pushToolResult(await cline.sayAndCreateMissingParamError("new_task", "todos")) + return + } + + // Parse todos if provided, otherwise use empty array + let todoItems: TodoItem[] = [] + if (todos) { + try { + todoItems = parseMarkdownChecklist(todos) + } catch (error) { + cline.consecutiveMistakeCount++ + cline.recordToolError("new_task") + pushToolResult(formatResponse.toolError("Invalid todos format: must be a markdown checklist")) + return + } + } + cline.consecutiveMistakeCount = 0 // Un-escape one level of backslashes before '@' for hierarchical subtasks // Un-escape one level: \\@ -> \@ (removes one backslash for hierarchical subtasks) @@ -61,6 +93,7 @@ export async function newTaskTool( tool: "newTask", mode: targetMode.name, content: message, + todos: todoItems, }) const didApprove = await askApproval("tool", toolMessage) @@ -69,8 +102,7 @@ export async function newTaskTool( return } - const provider = cline.providerRef.deref() - + // Re-get provider reference (we already have it from above) if (!provider) { return } @@ -83,8 +115,9 @@ export async function newTaskTool( cline.pausedModeSlug = (await provider.getState()).mode ?? defaultModeSlug // Create new task instance first (this preserves parent's current mode in its history) - const newCline = await provider.createTask(unescapedMessage, undefined, cline) - + const newCline = await provider.createTask(unescapedMessage, undefined, cline, { + initialTodos: todoItems, + }) if (!newCline) { pushToolResult(t("tools:newTask.errors.policy_restriction")) return @@ -98,7 +131,9 @@ export async function newTaskTool( cline.emit(RooCodeEventName.TaskSpawned, newCline.taskId) - pushToolResult(`Successfully created new task in ${targetMode.name} mode with message: ${unescapedMessage}`) + pushToolResult( + `Successfully created new task in ${targetMode.name} mode with message: ${unescapedMessage} and ${todoItems.length} todo items`, + ) // Set the isPaused flag to true so the parent // task can wait for the sub-task to finish. diff --git a/src/core/tools/updateTodoListTool.ts b/src/core/tools/updateTodoListTool.ts index cbb90338d3..de96c3cc76 100644 --- a/src/core/tools/updateTodoListTool.ts +++ b/src/core/tools/updateTodoListTool.ts @@ -100,7 +100,7 @@ function normalizeStatus(status: string | undefined): TodoStatus { return "pending" } -function parseMarkdownChecklist(md: string): TodoItem[] { +export function parseMarkdownChecklist(md: string): TodoItem[] { if (typeof md !== "string") return [] const lines = md .split(/\r?\n/) diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 04d336d957..feccbcd353 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -757,7 +757,12 @@ export class ClineProvider options: Partial< Pick< TaskOptions, - "enableDiff" | "enableCheckpoints" | "fuzzyMatchThreshold" | "consecutiveMistakeLimit" | "experiments" + | "enableDiff" + | "enableCheckpoints" + | "fuzzyMatchThreshold" + | "consecutiveMistakeLimit" + | "experiments" + | "initialTodos" > > = {}, ) { @@ -791,6 +796,7 @@ export class ClineProvider taskNumber: this.clineStack.length + 1, onCreated: this.taskCreationCallback, enableTaskBridge: isRemoteControlEnabled(cloudUserInfo, remoteControlEnabled), + initialTodos: options.initialTodos, ...options, }) @@ -1790,6 +1796,7 @@ export class ClineProvider ? (taskHistory || []).find((item: HistoryItem) => item.id === this.getCurrentTask()?.taskId) : undefined, clineMessages: this.getCurrentTask()?.clineMessages || [], + currentTaskTodos: this.getCurrentTask()?.todoList || [], taskHistory: (taskHistory || []) .filter((item: HistoryItem) => item.ts && item.task) .sort((a: HistoryItem, b: HistoryItem) => b.ts - a.ts), diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index ebdc137432..dccc1f2af0 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -8,6 +8,7 @@ import type { Experiments, ClineMessage, MarketplaceItem, + TodoItem, } from "@roo-code/types" import type { CloudUserInfo, OrganizationAllowList, ShareVisibility } from "@roo-code/cloud" @@ -274,6 +275,7 @@ export type ExtensionState = Pick< version: string clineMessages: ClineMessage[] currentTaskItem?: HistoryItem + currentTaskTodos?: TodoItem[] // Initial todos for the current task apiConfiguration?: ProviderSettings uriScheme?: string shouldShowAnnouncement: boolean diff --git a/src/shared/__tests__/experiments.spec.ts b/src/shared/__tests__/experiments.spec.ts index 21401dc759..530e2061ec 100644 --- a/src/shared/__tests__/experiments.spec.ts +++ b/src/shared/__tests__/experiments.spec.ts @@ -30,6 +30,7 @@ describe("experiments", () => { multiFileApplyDiff: false, preventFocusDisruption: false, assistantMessageParser: false, + newTaskRequireTodos: false, } expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(false) }) @@ -40,6 +41,7 @@ describe("experiments", () => { multiFileApplyDiff: false, preventFocusDisruption: false, assistantMessageParser: false, + newTaskRequireTodos: false, } expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(true) }) @@ -50,6 +52,7 @@ describe("experiments", () => { multiFileApplyDiff: false, preventFocusDisruption: false, assistantMessageParser: false, + newTaskRequireTodos: false, } expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(false) }) diff --git a/src/shared/experiments.ts b/src/shared/experiments.ts index 4be89afa1a..1d968e3fc3 100644 --- a/src/shared/experiments.ts +++ b/src/shared/experiments.ts @@ -5,6 +5,7 @@ export const EXPERIMENT_IDS = { POWER_STEERING: "powerSteering", PREVENT_FOCUS_DISRUPTION: "preventFocusDisruption", ASSISTANT_MESSAGE_PARSER: "assistantMessageParser", + NEW_TASK_REQUIRE_TODOS: "newTaskRequireTodos", } as const satisfies Record type _AssertExperimentIds = AssertEqual>> @@ -20,6 +21,7 @@ export const experimentConfigsMap: Record = { POWER_STEERING: { enabled: false }, PREVENT_FOCUS_DISRUPTION: { enabled: false }, ASSISTANT_MESSAGE_PARSER: { enabled: false }, + NEW_TASK_REQUIRE_TODOS: { enabled: false }, } export const experimentDefault = Object.fromEntries( diff --git a/src/shared/tools.ts b/src/shared/tools.ts index 67972243fe..047c2fe351 100644 --- a/src/shared/tools.ts +++ b/src/shared/tools.ts @@ -155,7 +155,7 @@ export interface SwitchModeToolUse extends ToolUse { export interface NewTaskToolUse extends ToolUse { name: "new_task" - params: Partial, "mode" | "message">> + params: Partial, "mode" | "message" | "todos">> } export interface SearchAndReplaceToolUse extends ToolUse { diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index 3b77bbdb7d..d2a053b07f 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -87,6 +87,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction messages.at(0), [messages]) const latestTodos = useMemo(() => { + // First check if we have initial todos from the state (for new subtasks) + if (currentTaskTodos && currentTaskTodos.length > 0) { + // Check if there are any todo updates in messages + const messageBasedTodos = getLatestTodo(messages) + // If there are message-based todos, they take precedence (user has updated them) + if (messageBasedTodos && messageBasedTodos.length > 0) { + return messageBasedTodos + } + // Otherwise use the initial todos from state + return currentTaskTodos + } + // Fall back to extracting from messages return getLatestTodo(messages) - }, [messages]) + }, [messages, currentTaskTodos]) const modifiedMessages = useMemo(() => combineApiRequests(combineCommandSequences(messages.slice(1))), [messages]) diff --git a/webview-ui/src/context/ExtensionStateContext.tsx b/webview-ui/src/context/ExtensionStateContext.tsx index b0045977c3..2bdad7bd87 100644 --- a/webview-ui/src/context/ExtensionStateContext.tsx +++ b/webview-ui/src/context/ExtensionStateContext.tsx @@ -31,6 +31,7 @@ export interface ExtensionStateContextType extends ExtensionState { mcpServers: McpServer[] hasSystemPromptOverride?: boolean currentCheckpoint?: string + currentTaskTodos?: any[] // Initial todos for the current task filePaths: string[] openedTabs: Array<{ label: string; isActive: boolean; path?: string }> commands: Command[] diff --git a/webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx b/webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx index a688cac885..b19f152457 100644 --- a/webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx +++ b/webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx @@ -230,6 +230,7 @@ describe("mergeExtensionState", () => { multiFileApplyDiff: true, preventFocusDisruption: false, assistantMessageParser: false, + newTaskRequireTodos: false, } as Record, } @@ -248,6 +249,7 @@ describe("mergeExtensionState", () => { multiFileApplyDiff: true, preventFocusDisruption: false, assistantMessageParser: false, + newTaskRequireTodos: false, }) }) }) diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 4f70e437c2..7964479a38 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -716,6 +716,10 @@ "ASSISTANT_MESSAGE_PARSER": { "name": "Use new message parser", "description": "Enable the experimental streaming message parser that provides significant performance improvements for long assistant responses by processing messages more efficiently." + }, + "NEW_TASK_REQUIRE_TODOS": { + "name": "Require 'todos' list for new tasks", + "description": "When enabled, the new_task tool will require a todos parameter to be provided. This ensures all new tasks start with a clear list of objectives. When disabled (default), the todos parameter remains optional for backward compatibility." } }, "promptCaching": { From c7fe8f7bea489375a73568c5633683313183922b Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Wed, 6 Aug 2025 16:02:49 -0700 Subject: [PATCH 02/12] fix: update new_task tool example to include todos parameter - Updated the example in tool-use.ts to show the todos parameter - This prevents AI confusion about whether todos is a valid parameter - The example now demonstrates the complete tool usage pattern --- src/core/prompts/sections/tool-use.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/core/prompts/sections/tool-use.ts b/src/core/prompts/sections/tool-use.ts index ea27e5916a..434d2f8785 100644 --- a/src/core/prompts/sections/tool-use.ts +++ b/src/core/prompts/sections/tool-use.ts @@ -20,6 +20,12 @@ For example, to use the new_task tool: code Implement a new feature for the application. + +[ ] Design the feature architecture +[ ] Implement core functionality +[ ] Add error handling +[ ] Write tests + Always use the actual tool name as the XML tag name for proper parsing and execution.` From 3e0163006c8b9a8df86d5baf2ebdb0c6f7efa86a Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Wed, 6 Aug 2025 16:11:51 -0700 Subject: [PATCH 03/12] fix: make new_task tool definition dynamic based on experimental setting - Tool description now changes based on newTaskRequireTodos setting - When disabled: shows todos as (optional) - When enabled: shows todos as (required) with no mention of configuration - Added tests to verify dynamic behavior - Ensures AI models get unambiguous instructions based on current settings --- .../prompts/tools/__tests__/new-task.spec.ts | 98 +++++++++++++++++++ src/core/prompts/tools/new-task.ts | 10 +- 2 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 src/core/prompts/tools/__tests__/new-task.spec.ts diff --git a/src/core/prompts/tools/__tests__/new-task.spec.ts b/src/core/prompts/tools/__tests__/new-task.spec.ts new file mode 100644 index 0000000000..1d70d809a7 --- /dev/null +++ b/src/core/prompts/tools/__tests__/new-task.spec.ts @@ -0,0 +1,98 @@ +import { describe, it, expect } from "vitest" +import { getNewTaskDescription } from "../new-task" +import { ToolArgs } from "../types" + +describe("getNewTaskDescription", () => { + it("should show todos as optional when experiment is disabled", () => { + const args: ToolArgs = { + cwd: "/test", + supportsComputerUse: false, + experiments: { + newTaskRequireTodos: false, + }, + } + + const description = getNewTaskDescription(args) + + // Check that todos is marked as optional + expect(description).toContain("todos: (optional)") + expect(description).toContain("optional initial todo list") + + // Should not contain any mention of required + expect(description).not.toContain("todos: (required)") + }) + + it("should show todos as required when experiment is enabled", () => { + const args: ToolArgs = { + cwd: "/test", + supportsComputerUse: false, + experiments: { + newTaskRequireTodos: true, + }, + } + + const description = getNewTaskDescription(args) + + // Check that todos is marked as required + expect(description).toContain("todos: (required)") + expect(description).toContain("and initial todo list") + + // Should not contain any mention of optional for todos + expect(description).not.toContain("todos: (optional)") + expect(description).not.toContain("optional initial todo list") + }) + + it("should default to optional when experiments is undefined", () => { + const args: ToolArgs = { + cwd: "/test", + supportsComputerUse: false, + experiments: undefined, + } + + const description = getNewTaskDescription(args) + + // Check that todos is marked as optional by default + expect(description).toContain("todos: (optional)") + expect(description).toContain("optional initial todo list") + }) + + it("should default to optional when newTaskRequireTodos is undefined", () => { + const args: ToolArgs = { + cwd: "/test", + supportsComputerUse: false, + experiments: {}, + } + + const description = getNewTaskDescription(args) + + // Check that todos is marked as optional by default + expect(description).toContain("todos: (optional)") + expect(description).toContain("optional initial todo list") + }) + + it("should always include the example with todos", () => { + const argsWithExperimentOff: ToolArgs = { + cwd: "/test", + supportsComputerUse: false, + experiments: { + newTaskRequireTodos: false, + }, + } + + const argsWithExperimentOn: ToolArgs = { + cwd: "/test", + supportsComputerUse: false, + experiments: { + newTaskRequireTodos: true, + }, + } + + const descriptionOff = getNewTaskDescription(argsWithExperimentOff) + const descriptionOn = getNewTaskDescription(argsWithExperimentOn) + + // Both should include the example with todos + const examplePattern = /\s*\[\s*\]\s*Set up auth middleware/s + expect(descriptionOff).toMatch(examplePattern) + expect(descriptionOn).toMatch(examplePattern) + }) +}) diff --git a/src/core/prompts/tools/new-task.ts b/src/core/prompts/tools/new-task.ts index 37a0a7783e..f1806bb4e0 100644 --- a/src/core/prompts/tools/new-task.ts +++ b/src/core/prompts/tools/new-task.ts @@ -1,14 +1,16 @@ import { ToolArgs } from "./types" -export function getNewTaskDescription(_args: ToolArgs): string { +export function getNewTaskDescription(args: ToolArgs): string { + const todosRequired = args.experiments?.newTaskRequireTodos === true + const todosStatus = todosRequired ? "(required)" : "(optional)" + return `## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. +Description: This will let you create a new task instance in the chosen mode using your provided message${todosRequired ? " and initial todo list" : " and optional initial todo list"}. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. -- todos: (optional by default, can be required via experimental setting) The initial todo list in markdown checklist format for the new task. - Note: The 'todos' parameter can be configured to be required through the experimental setting 'newTaskRequireTodos'. +- todos: ${todosStatus} The initial todo list in markdown checklist format for the new task. Usage: From de00926308792c3e9c2867fa5fac6ab339d513c2 Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Wed, 6 Aug 2025 16:34:43 -0700 Subject: [PATCH 04/12] fix: add translations for newTaskRequireTodos experimental setting - Added translations for all 17 supported languages - Ensures consistent UI experience across all locales --- webview-ui/src/i18n/locales/ca/settings.json | 4 ++++ webview-ui/src/i18n/locales/de/settings.json | 4 ++++ webview-ui/src/i18n/locales/es/settings.json | 4 ++++ webview-ui/src/i18n/locales/fr/settings.json | 4 ++++ webview-ui/src/i18n/locales/hi/settings.json | 4 ++++ webview-ui/src/i18n/locales/id/settings.json | 4 ++++ webview-ui/src/i18n/locales/it/settings.json | 4 ++++ webview-ui/src/i18n/locales/ja/settings.json | 4 ++++ webview-ui/src/i18n/locales/ko/settings.json | 4 ++++ webview-ui/src/i18n/locales/nl/settings.json | 4 ++++ webview-ui/src/i18n/locales/pl/settings.json | 4 ++++ webview-ui/src/i18n/locales/pt-BR/settings.json | 4 ++++ webview-ui/src/i18n/locales/ru/settings.json | 4 ++++ webview-ui/src/i18n/locales/tr/settings.json | 4 ++++ webview-ui/src/i18n/locales/vi/settings.json | 4 ++++ webview-ui/src/i18n/locales/zh-CN/settings.json | 4 ++++ webview-ui/src/i18n/locales/zh-TW/settings.json | 4 ++++ 17 files changed, 68 insertions(+) diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index 97c5e39352..9a11006c2e 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -717,6 +717,10 @@ "ASSISTANT_MESSAGE_PARSER": { "name": "Utilitza el nou analitzador de missatges", "description": "Activa l'analitzador de missatges en streaming experimental que millora el rendiment en respostes llargues processant els missatges de manera més eficient." + }, + "NEW_TASK_REQUIRE_TODOS": { + "name": "Requerir la llista 'todos' per a noves tasques", + "description": "Quan estigui activat, l'eina new_task requerirà que es proporcioni un paràmetre 'todos'. Això garanteix que totes les noves tasques comencin amb una llista clara d'objectius. Quan estigui desactivat (per defecte), el paràmetre 'todos' continua sent opcional per a la compatibilitat amb versions anteriors." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index 2d699a0e96..b6844ed5a1 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -717,6 +717,10 @@ "ASSISTANT_MESSAGE_PARSER": { "name": "Neuen Nachrichtenparser verwenden", "description": "Aktiviere den experimentellen Streaming-Nachrichtenparser, der lange Antworten durch effizientere Verarbeitung spürbar schneller macht." + }, + "NEW_TASK_REQUIRE_TODOS": { + "name": "'todos'-Liste für neue Aufgaben anfordern", + "description": "Wenn aktiviert, erfordert das new_task-Tool die Angabe eines todos-Parameters. Dies stellt sicher, dass alle neuen Aufgaben mit einer klaren Zielliste beginnen. Wenn deaktiviert (Standard), bleibt der todos-Parameter aus Gründen der Abwärtskompatibilität optional." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index 7f22887ee1..9d99192fef 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -717,6 +717,10 @@ "ASSISTANT_MESSAGE_PARSER": { "name": "Usar el nuevo analizador de mensajes", "description": "Activa el analizador de mensajes en streaming experimental que mejora el rendimiento en respuestas largas procesando los mensajes de forma más eficiente." + }, + "NEW_TASK_REQUIRE_TODOS": { + "name": "Requerir lista de 'todos' para nuevas tareas", + "description": "Cuando está habilitado, la herramienta new_task requerirá que se proporcione un parámetro todos. Esto asegura que todas las nuevas tareas comiencen con una lista clara de objetivos. Cuando está deshabilitado (predeterminado), el parámetro todos permanece opcional por compatibilidad con versiones anteriores." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index c544673df6..0e17971655 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -717,6 +717,10 @@ "ASSISTANT_MESSAGE_PARSER": { "name": "Utiliser le nouveau parseur de messages", "description": "Active le parseur de messages en streaming expérimental qui accélère nettement les longues réponses en traitant les messages plus efficacement." + }, + "NEW_TASK_REQUIRE_TODOS": { + "name": "Exiger la liste 'todos' pour les nouvelles tâches", + "description": "Lorsqu'il est activé, l'outil new_task exigera qu'un paramètre todos soit fourni. Cela garantit que toutes les nouvelles tâches commencent avec une liste claire d'objectifs. Lorsqu'il est désactivé (par défaut), le paramètre todos reste facultatif pour la compatibilité descendante." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index 536d63d2a5..be6fab615a 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -718,6 +718,10 @@ "ASSISTANT_MESSAGE_PARSER": { "name": "नए मैसेज पार्सर का उपयोग करें", "description": "प्रायोगिक स्ट्रीमिंग मैसेज पार्सर सक्षम करें, जो लंबे उत्तरों के लिए संदेशों को अधिक कुशलता से प्रोसेस करके प्रदर्शन को बेहतर बनाता है।" + }, + "NEW_TASK_REQUIRE_TODOS": { + "name": "नए कार्यों के लिए 'todos' सूची की आवश्यकता है", + "description": "जब सक्षम किया जाता है, तो new_task टूल को todos पैरामीटर प्रदान करने की आवश्यकता होगी। यह सुनिश्चित करता है कि सभी नए कार्य स्पष्ट उद्देश्यों की सूची के साथ शुरू हों। जब अक्षम किया जाता है (डिफ़ॉल्ट), तो todos पैरामीटर पिछड़े संगतता के लिए वैकल्पिक रहता है।" } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index 672adb9eda..a8eb8f8d79 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -747,6 +747,10 @@ "ASSISTANT_MESSAGE_PARSER": { "name": "Gunakan parser pesan baru", "description": "Aktifkan parser pesan streaming eksperimental yang meningkatkan kinerja untuk respons panjang dengan memproses pesan lebih efisien." + }, + "NEW_TASK_REQUIRE_TODOS": { + "name": "Membutuhkan daftar 'todos' untuk tugas baru", + "description": "Ketika diaktifkan, alat new_task akan membutuhkan parameter todos untuk disediakan. Ini memastikan semua tugas baru dimulai dengan daftar tujuan yang jelas. Ketika dinonaktifkan (default), parameter todos tetap opsional untuk kompatibilitas mundur." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index a04258d398..ebd5683577 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -718,6 +718,10 @@ "ASSISTANT_MESSAGE_PARSER": { "name": "Usa il nuovo parser dei messaggi", "description": "Abilita il parser di messaggi in streaming sperimentale che migliora nettamente le risposte lunghe elaborando i messaggi in modo più efficiente." + }, + "NEW_TASK_REQUIRE_TODOS": { + "name": "Richiedi elenco 'todos' per nuove attività", + "description": "Quando abilitato, lo strumento new_task richiederà la fornitura di un parametro todos. Ciò garantisce che tutte le nuove attività inizino con un elenco chiaro di obiettivi. Quando disabilitato (impostazione predefinita), il parametro todos rimane facoltativo per la compatibilità con le versioni precedenti." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index 6c1859c85d..34b1bcd705 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -718,6 +718,10 @@ "ASSISTANT_MESSAGE_PARSER": { "name": "新しいメッセージパーサーを使う", "description": "実験的なストリーミングメッセージパーサーを有効にします。長い回答をより効率的に処理し、遅延を減らします。" + }, + "NEW_TASK_REQUIRE_TODOS": { + "name": "新しいタスクには'todos'リストを必須にする", + "description": "有効にすると、new_taskツールはtodosパラメータの提供が必須になります。これにより、すべての新しいタスクが明確な目的のリストで開始されることが保証されます。無効(デフォルト)の場合、下位互換性のためにtodosパラメータはオプションのままです。" } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index e77a806920..a3b9bf1d23 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -718,6 +718,10 @@ "ASSISTANT_MESSAGE_PARSER": { "name": "새 메시지 파서 사용", "description": "실험적 스트리밍 메시지 파서를 활성화합니다. 긴 응답을 더 효율적으로 처리해 지연을 줄입니다." + }, + "NEW_TASK_REQUIRE_TODOS": { + "name": "새 작업에 'todos' 목록 필요", + "description": "활성화하면 new_task 도구에 todos 매개변수를 제공해야 합니다. 이렇게 하면 모든 새 작업이 명확한 목표 목록으로 시작됩니다. 비활성화하면(기본값) 이전 버전과의 호환성을 위해 todos 매개변수는 선택 사항으로 유지됩니다." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index 42c1d97bdb..5b04b07001 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -718,6 +718,10 @@ "ASSISTANT_MESSAGE_PARSER": { "name": "Nieuwe berichtparser gebruiken", "description": "Schakel de experimentele streaming-berichtparser in die lange antwoorden sneller maakt door berichten efficiënter te verwerken." + }, + "NEW_TASK_REQUIRE_TODOS": { + "name": "'todos'-lijst vereisen voor nieuwe taken", + "description": "Wanneer ingeschakeld, vereist de new_task-tool dat een todos-parameter wordt opgegeven. Dit zorgt ervoor dat alle nieuwe taken beginnen met een duidelijke lijst met doelstellingen. Wanneer uitgeschakeld (standaard), blijft de todos-parameter optioneel voor achterwaartse compatibiliteit." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index f1abf9c79d..9f085259ee 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -718,6 +718,10 @@ "ASSISTANT_MESSAGE_PARSER": { "name": "Użyj nowego parsera wiadomości", "description": "Włącz eksperymentalny parser wiadomości w strumieniu, który przyspiesza długie odpowiedzi dzięki bardziej wydajnemu przetwarzaniu wiadomości." + }, + "NEW_TASK_REQUIRE_TODOS": { + "name": "Wymagaj listy 'todos' dla nowych zadań", + "description": "Gdy włączone, narzędzie new_task będzie wymagało podania parametru todos. Zapewnia to, że wszystkie nowe zadania rozpoczynają się od jasnej listy celów. Gdy wyłączone (domyślnie), parametr todos pozostaje opcjonalny dla zachowania kompatybilności wstecznej." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index c566ee1e2d..3b8a5e68eb 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -718,6 +718,10 @@ "ASSISTANT_MESSAGE_PARSER": { "name": "Usar o novo parser de mensagens", "description": "Ativa o parser de mensagens em streaming experimental que acelera respostas longas ao processar as mensagens de forma mais eficiente." + }, + "NEW_TASK_REQUIRE_TODOS": { + "name": "Exigir lista de 'todos' para novas tarefas", + "description": "Quando ativado, a ferramenta new_task exigirá que um parâmetro todos seja fornecido. Isso garante que todas as novas tarefas comecem com uma lista clara de objetivos. Quando desativado (padrão), o parâmetro todos permanece opcional para compatibilidade com versões anteriores." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index 98df1f0138..e85eee5319 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -718,6 +718,10 @@ "ASSISTANT_MESSAGE_PARSER": { "name": "Использовать новый парсер сообщений", "description": "Включите экспериментальный потоковый парсер сообщений, который ускоряет длинные ответы благодаря более эффективной обработке сообщений." + }, + "NEW_TASK_REQUIRE_TODOS": { + "name": "Требовать список 'todos' для новых задач", + "description": "Если включено, инструмент new_task будет требовать предоставления параметра todos. Это гарантирует, что все новые задачи начинаются с четкого списка целей. Когда отключено (по умолчанию), параметр todos остается необязательным для обратной совместимости." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index 4fb043a8a0..cad5c66842 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -718,6 +718,10 @@ "ASSISTANT_MESSAGE_PARSER": { "name": "Yeni mesaj ayrıştırıcıyı kullan", "description": "Uzun yanıtları daha verimli işleyerek hızlandıran deneysel akış mesaj ayrıştırıcısını etkinleştir." + }, + "NEW_TASK_REQUIRE_TODOS": { + "name": "Yeni görevler için 'todos' listesi gerektir", + "description": "Etkinleştirildiğinde, new_task aracı bir todos parametresi sağlanmasını gerektirir. Bu, tüm yeni görevlerin net bir hedef listesiyle başlamasını sağlar. Devre dışı bırakıldığında (varsayılan), todos parametresi geriye dönük uyumluluk için isteğe bağlı kalır." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index c9e6b5afbb..fb81fc2f9d 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -718,6 +718,10 @@ "ASSISTANT_MESSAGE_PARSER": { "name": "Dùng bộ phân tích tin nhắn mới", "description": "Bật bộ phân tích tin nhắn streaming thử nghiệm. Tính năng này tăng tốc phản hồi dài bằng cách xử lý tin nhắn hiệu quả hơn." + }, + "NEW_TASK_REQUIRE_TODOS": { + "name": "Yêu cầu danh sách 'todos' cho các nhiệm vụ mới", + "description": "Khi được bật, công cụ new_task sẽ yêu cầu cung cấp tham số todos. Điều này đảm bảo tất cả các nhiệm vụ mới bắt đầu với một danh sách mục tiêu rõ ràng. Khi bị tắt (mặc định), tham số todos vẫn là tùy chọn để tương thích ngược." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index cc16cf349d..ee24c828b4 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -718,6 +718,10 @@ "ASSISTANT_MESSAGE_PARSER": { "name": "使用新的消息解析器", "description": "启用实验性的流式消息解析器。通过更高效地处理消息,可显著提升长回复的性能。" + }, + "NEW_TASK_REQUIRE_TODOS": { + "name": "要求新任务提供 'todos' 列表", + "description": "启用后,new_task 工具将需要提供 todos 参数。这可以确保所有新任务都以明确的目标列表开始。禁用时(默认),todos 参数保持可选,以实现向后兼容。" } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index 791be9ac02..d5b8ec80a9 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -718,6 +718,10 @@ "ASSISTANT_MESSAGE_PARSER": { "name": "使用全新訊息解析器", "description": "啟用實驗性的串流訊息解析器。透過更有效率地處理訊息,能顯著提升長回覆的效能。" + }, + "NEW_TASK_REQUIRE_TODOS": { + "name": "要求新工作提供 'todos' 列表", + "description": "啟用後,new_task 工具將需要提供 todos 參數。這可以確保所有新工作都以明確的目標列表開始。停用時(預設),todos 參數保持可選,以實現向後相容。" } }, "promptCaching": { From 7b9fce5b789208548e49d864560e40f4c0ea7d2a Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Wed, 6 Aug 2025 16:44:09 -0700 Subject: [PATCH 05/12] test: update snapshots for new_task tool example with todos parameter - Updated 13 snapshot files to reflect the new tool-use example - All tests now pass with the updated example format --- .../architect-mode-prompt.snap | 22 +++++++++++++++++-- .../ask-mode-prompt.snap | 22 +++++++++++++++++-- .../mcp-server-creation-disabled.snap | 22 +++++++++++++++++-- .../mcp-server-creation-enabled.snap | 22 +++++++++++++++++-- .../partial-reads-enabled.snap | 22 +++++++++++++++++-- .../consistent-system-prompt.snap | 22 +++++++++++++++++-- .../with-computer-use-support.snap | 22 +++++++++++++++++-- .../with-diff-enabled-false.snap | 22 +++++++++++++++++-- .../system-prompt/with-diff-enabled-true.snap | 22 +++++++++++++++++-- .../with-diff-enabled-undefined.snap | 22 +++++++++++++++++-- .../with-different-viewport-size.snap | 22 +++++++++++++++++-- .../system-prompt/with-mcp-hub-provided.snap | 22 +++++++++++++++++-- .../system-prompt/with-undefined-mcp-hub.snap | 22 +++++++++++++++++-- 13 files changed, 260 insertions(+), 26 deletions(-) diff --git a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/architect-mode-prompt.snap b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/architect-mode-prompt.snap index cfec773b44..aa2010ab17 100644 --- a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/architect-mode-prompt.snap +++ b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/architect-mode-prompt.snap @@ -27,6 +27,12 @@ For example, to use the new_task tool: code Implement a new feature for the application. + +[ ] Design the feature architecture +[ ] Implement core functionality +[ ] Add error handling +[ ] Write tests + Always use the actual tool name as the XML tag name for proper parsing and execution. @@ -332,22 +338,34 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message. +Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. +- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here + +[ ] First task to complete +[ ] Second task to complete +[ ] Third task to complete + Example: code -Implement a new feature for the application. +Implement user authentication + +[ ] Set up auth middleware +[ ] Create login endpoint +[ ] Add session management +[ ] Write tests + diff --git a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/ask-mode-prompt.snap b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/ask-mode-prompt.snap index 0289fc2200..4732c66553 100644 --- a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/ask-mode-prompt.snap +++ b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/ask-mode-prompt.snap @@ -27,6 +27,12 @@ For example, to use the new_task tool: code Implement a new feature for the application. + +[ ] Design the feature architecture +[ ] Implement core functionality +[ ] Add error handling +[ ] Write tests + Always use the actual tool name as the XML tag name for proper parsing and execution. @@ -229,22 +235,34 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message. +Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. +- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here + +[ ] First task to complete +[ ] Second task to complete +[ ] Third task to complete + Example: code -Implement a new feature for the application. +Implement user authentication + +[ ] Set up auth middleware +[ ] Create login endpoint +[ ] Add session management +[ ] Write tests + diff --git a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-disabled.snap b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-disabled.snap index f16c11a97f..0dbaa101d0 100644 --- a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-disabled.snap +++ b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-disabled.snap @@ -27,6 +27,12 @@ For example, to use the new_task tool: code Implement a new feature for the application. + +[ ] Design the feature architecture +[ ] Implement core functionality +[ ] Add error handling +[ ] Write tests + Always use the actual tool name as the XML tag name for proper parsing and execution. @@ -331,22 +337,34 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message. +Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. +- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here + +[ ] First task to complete +[ ] Second task to complete +[ ] Third task to complete + Example: code -Implement a new feature for the application. +Implement user authentication + +[ ] Set up auth middleware +[ ] Create login endpoint +[ ] Add session management +[ ] Write tests + diff --git a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-enabled.snap b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-enabled.snap index 168dd87d59..28ccd20bf7 100644 --- a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-enabled.snap +++ b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-enabled.snap @@ -27,6 +27,12 @@ For example, to use the new_task tool: code Implement a new feature for the application. + +[ ] Design the feature architecture +[ ] Implement core functionality +[ ] Add error handling +[ ] Write tests + Always use the actual tool name as the XML tag name for proper parsing and execution. @@ -381,22 +387,34 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message. +Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. +- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here + +[ ] First task to complete +[ ] Second task to complete +[ ] Third task to complete + Example: code -Implement a new feature for the application. +Implement user authentication + +[ ] Set up auth middleware +[ ] Create login endpoint +[ ] Add session management +[ ] Write tests + diff --git a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/partial-reads-enabled.snap b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/partial-reads-enabled.snap index bafff056b5..8c69f89721 100644 --- a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/partial-reads-enabled.snap +++ b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/partial-reads-enabled.snap @@ -27,6 +27,12 @@ For example, to use the new_task tool: code Implement a new feature for the application. + +[ ] Design the feature architecture +[ ] Implement core functionality +[ ] Add error handling +[ ] Write tests + Always use the actual tool name as the XML tag name for proper parsing and execution. @@ -337,22 +343,34 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message. +Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. +- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here + +[ ] First task to complete +[ ] Second task to complete +[ ] Third task to complete + Example: code -Implement a new feature for the application. +Implement user authentication + +[ ] Set up auth middleware +[ ] Create login endpoint +[ ] Add session management +[ ] Write tests + diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/consistent-system-prompt.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/consistent-system-prompt.snap index cfec773b44..aa2010ab17 100644 --- a/src/core/prompts/__tests__/__snapshots__/system-prompt/consistent-system-prompt.snap +++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/consistent-system-prompt.snap @@ -27,6 +27,12 @@ For example, to use the new_task tool: code Implement a new feature for the application. + +[ ] Design the feature architecture +[ ] Implement core functionality +[ ] Add error handling +[ ] Write tests + Always use the actual tool name as the XML tag name for proper parsing and execution. @@ -332,22 +338,34 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message. +Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. +- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here + +[ ] First task to complete +[ ] Second task to complete +[ ] Third task to complete + Example: code -Implement a new feature for the application. +Implement user authentication + +[ ] Set up auth middleware +[ ] Create login endpoint +[ ] Add session management +[ ] Write tests + diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-computer-use-support.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-computer-use-support.snap index fb1fb5c77e..0f3a116ab0 100644 --- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-computer-use-support.snap +++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-computer-use-support.snap @@ -27,6 +27,12 @@ For example, to use the new_task tool: code Implement a new feature for the application. + +[ ] Design the feature architecture +[ ] Implement core functionality +[ ] Add error handling +[ ] Write tests + Always use the actual tool name as the XML tag name for proper parsing and execution. @@ -385,22 +391,34 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message. +Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. +- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here + +[ ] First task to complete +[ ] Second task to complete +[ ] Third task to complete + Example: code -Implement a new feature for the application. +Implement user authentication + +[ ] Set up auth middleware +[ ] Create login endpoint +[ ] Add session management +[ ] Write tests + diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-false.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-false.snap index cfec773b44..aa2010ab17 100644 --- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-false.snap +++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-false.snap @@ -27,6 +27,12 @@ For example, to use the new_task tool: code Implement a new feature for the application. + +[ ] Design the feature architecture +[ ] Implement core functionality +[ ] Add error handling +[ ] Write tests + Always use the actual tool name as the XML tag name for proper parsing and execution. @@ -332,22 +338,34 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message. +Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. +- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here + +[ ] First task to complete +[ ] Second task to complete +[ ] Third task to complete + Example: code -Implement a new feature for the application. +Implement user authentication + +[ ] Set up auth middleware +[ ] Create login endpoint +[ ] Add session management +[ ] Write tests + diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-true.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-true.snap index 7c0108ff75..813378962a 100644 --- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-true.snap +++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-true.snap @@ -27,6 +27,12 @@ For example, to use the new_task tool: code Implement a new feature for the application. + +[ ] Design the feature architecture +[ ] Implement core functionality +[ ] Add error handling +[ ] Write tests + Always use the actual tool name as the XML tag name for proper parsing and execution. @@ -420,22 +426,34 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message. +Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. +- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here + +[ ] First task to complete +[ ] Second task to complete +[ ] Third task to complete + Example: code -Implement a new feature for the application. +Implement user authentication + +[ ] Set up auth middleware +[ ] Create login endpoint +[ ] Add session management +[ ] Write tests + diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-undefined.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-undefined.snap index cfec773b44..aa2010ab17 100644 --- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-undefined.snap +++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-undefined.snap @@ -27,6 +27,12 @@ For example, to use the new_task tool: code Implement a new feature for the application. + +[ ] Design the feature architecture +[ ] Implement core functionality +[ ] Add error handling +[ ] Write tests + Always use the actual tool name as the XML tag name for proper parsing and execution. @@ -332,22 +338,34 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message. +Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. +- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here + +[ ] First task to complete +[ ] Second task to complete +[ ] Third task to complete + Example: code -Implement a new feature for the application. +Implement user authentication + +[ ] Set up auth middleware +[ ] Create login endpoint +[ ] Add session management +[ ] Write tests + diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-different-viewport-size.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-different-viewport-size.snap index bf764fdf83..231925264f 100644 --- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-different-viewport-size.snap +++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-different-viewport-size.snap @@ -27,6 +27,12 @@ For example, to use the new_task tool: code Implement a new feature for the application. + +[ ] Design the feature architecture +[ ] Implement core functionality +[ ] Add error handling +[ ] Write tests + Always use the actual tool name as the XML tag name for proper parsing and execution. @@ -385,22 +391,34 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message. +Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. +- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here + +[ ] First task to complete +[ ] Second task to complete +[ ] Third task to complete + Example: code -Implement a new feature for the application. +Implement user authentication + +[ ] Set up auth middleware +[ ] Create login endpoint +[ ] Add session management +[ ] Write tests + diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-mcp-hub-provided.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-mcp-hub-provided.snap index 168dd87d59..28ccd20bf7 100644 --- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-mcp-hub-provided.snap +++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-mcp-hub-provided.snap @@ -27,6 +27,12 @@ For example, to use the new_task tool: code Implement a new feature for the application. + +[ ] Design the feature architecture +[ ] Implement core functionality +[ ] Add error handling +[ ] Write tests + Always use the actual tool name as the XML tag name for proper parsing and execution. @@ -381,22 +387,34 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message. +Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. +- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here + +[ ] First task to complete +[ ] Second task to complete +[ ] Third task to complete + Example: code -Implement a new feature for the application. +Implement user authentication + +[ ] Set up auth middleware +[ ] Create login endpoint +[ ] Add session management +[ ] Write tests + diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-undefined-mcp-hub.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-undefined-mcp-hub.snap index cfec773b44..aa2010ab17 100644 --- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-undefined-mcp-hub.snap +++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-undefined-mcp-hub.snap @@ -27,6 +27,12 @@ For example, to use the new_task tool: code Implement a new feature for the application. + +[ ] Design the feature architecture +[ ] Implement core functionality +[ ] Add error handling +[ ] Write tests + Always use the actual tool name as the XML tag name for proper parsing and execution. @@ -332,22 +338,34 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message. +Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. +- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here + +[ ] First task to complete +[ ] Second task to complete +[ ] Third task to complete + Example: code -Implement a new feature for the application. +Implement user authentication + +[ ] Set up auth middleware +[ ] Create login endpoint +[ ] Add session management +[ ] Write tests + From 75f5e12c5db8a35e8fb12865cf9765943efeb557 Mon Sep 17 00:00:00 2001 From: Hannes Rudolph Date: Wed, 6 Aug 2025 17:56:04 -0600 Subject: [PATCH 06/12] Update src/core/tools/newTaskTool.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/core/tools/newTaskTool.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/tools/newTaskTool.ts b/src/core/tools/newTaskTool.ts index 188bb47290..da42bda7d9 100644 --- a/src/core/tools/newTaskTool.ts +++ b/src/core/tools/newTaskTool.ts @@ -102,7 +102,6 @@ export async function newTaskTool( return } - // Re-get provider reference (we already have it from above) if (!provider) { return } From c8a4b504a9540ca2ac99559d2249298dad93aaa0 Mon Sep 17 00:00:00 2001 From: Merge Resolver Date: Tue, 19 Aug 2025 17:43:54 -0600 Subject: [PATCH 07/12] fix: address PR review comments - Replace any[] with TodoItem[] type in ExtensionStateContext.tsx for better type safety - Remove redundant initialTodos parameter from startTask call in Task.ts (todos already set in constructor) - Improve code clarity in newTaskTool.ts by checking provider reference early and reusing state # Conflicts: # src/core/task/Task.ts # webview-ui/src/context/ExtensionStateContext.tsx --- src/core/task/Task.ts | 4 ++-- src/core/tools/newTaskTool.ts | 12 +++++++----- webview-ui/src/context/ExtensionStateContext.tsx | 3 ++- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index 002493b7e8..1796dba5de 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -381,7 +381,7 @@ export class Task extends EventEmitter implements TaskLike { if (startTask) { if (task || images) { - this.startTask(task, images, initialTodos) + this.startTask(task, images) } else if (historyItem) { this.resumeTaskFromHistory() } else { @@ -1059,7 +1059,7 @@ export class Task extends EventEmitter implements TaskLike { // Start / Abort / Resume - private async startTask(task?: string, images?: string[], initialTodos?: TodoItem[]): Promise { + private async startTask(task?: string, images?: string[]): Promise { if (this.enableTaskBridge) { try { this.bridgeService = this.bridgeService || ExtensionBridgeService.getInstance() diff --git a/src/core/tools/newTaskTool.ts b/src/core/tools/newTaskTool.ts index da42bda7d9..7fab7e56e8 100644 --- a/src/core/tools/newTaskTool.ts +++ b/src/core/tools/newTaskTool.ts @@ -51,7 +51,11 @@ export async function newTaskTool( // Get the experimental setting for requiring todos const provider = cline.providerRef.deref() - const state = await provider?.getState() + if (!provider) { + pushToolResult(formatResponse.toolError("Provider reference lost")) + return + } + const state = await provider.getState() const requireTodos = Experiments.isEnabled(state?.experiments ?? {}, EXPERIMENT_IDS.NEW_TASK_REQUIRE_TODOS) // Check if todos are required based on experimental setting @@ -82,7 +86,7 @@ export async function newTaskTool( const unescapedMessage = message.replace(/\\\\@/g, "\\@") // Verify the mode exists - const targetMode = getModeBySlug(mode, (await cline.providerRef.deref()?.getState())?.customModes) + const targetMode = getModeBySlug(mode, state?.customModes) if (!targetMode) { pushToolResult(formatResponse.toolError(`Invalid mode: ${mode}`)) @@ -102,9 +106,7 @@ export async function newTaskTool( return } - if (!provider) { - return - } + // Provider is guaranteed to be defined here due to earlier check if (cline.enableCheckpoints) { cline.checkpointSave(true) diff --git a/webview-ui/src/context/ExtensionStateContext.tsx b/webview-ui/src/context/ExtensionStateContext.tsx index 2bdad7bd87..e632b27a31 100644 --- a/webview-ui/src/context/ExtensionStateContext.tsx +++ b/webview-ui/src/context/ExtensionStateContext.tsx @@ -6,6 +6,7 @@ import { type CustomModePrompts, type ModeConfig, type ExperimentId, + type TodoItem, } from "@roo-code/types" import { type OrganizationAllowList, ORGANIZATION_ALLOW_ALL } from "@roo/cloud" @@ -31,7 +32,7 @@ export interface ExtensionStateContextType extends ExtensionState { mcpServers: McpServer[] hasSystemPromptOverride?: boolean currentCheckpoint?: string - currentTaskTodos?: any[] // Initial todos for the current task + currentTaskTodos?: TodoItem[] // Initial todos for the current task filePaths: string[] openedTabs: Array<{ label: string; isActive: boolean; path?: string }> commands: Command[] From ed0abcd86940bfc3480257e94c022acd5ecceccd Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Wed, 6 Aug 2025 18:01:18 -0700 Subject: [PATCH 08/12] fix: revert order of operations in startTask to fix integration test timeout The change in order of operations (calling say() before postStateToWebview()) was causing the XML content file test to timeout. Reverting to the original order fixes the issue. --- src/core/task/Task.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index 1796dba5de..75f152c214 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -1086,9 +1086,9 @@ export class Task extends EventEmitter implements TaskLike { // The todo list is already set in the constructor if initialTodos were provided // No need to add any messages - the todoList property is already set - await this.say("text", task, images) - await this.providerRef.deref()?.postStateToWebview() + + await this.say("text", task, images) this.isInitialized = true let imageBlocks: Anthropic.ImageBlockParam[] = formatResponse.imageBlocks(images) From f7012c7c7ff3e12cb587d3f5593f61527abac5a2 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Thu, 7 Aug 2025 15:35:44 +0000 Subject: [PATCH 09/12] fix: hide todos parameter from new_task tool prompt when experiment is disabled - Modified getNewTaskDescription to completely omit todos parameter when experiment is off - Updated tests to verify todos parameter is not shown at all when disabled - Ensures tool prompt remains unchanged when experimental setting is disabled - Maintains backward compatibility while providing cleaner prompt interface --- .../prompts/tools/__tests__/new-task.spec.ts | 57 ++++++++++++------- src/core/prompts/tools/new-task.ts | 29 +++++++++- 2 files changed, 64 insertions(+), 22 deletions(-) diff --git a/src/core/prompts/tools/__tests__/new-task.spec.ts b/src/core/prompts/tools/__tests__/new-task.spec.ts index 1d70d809a7..4a87eb9840 100644 --- a/src/core/prompts/tools/__tests__/new-task.spec.ts +++ b/src/core/prompts/tools/__tests__/new-task.spec.ts @@ -3,7 +3,7 @@ import { getNewTaskDescription } from "../new-task" import { ToolArgs } from "../types" describe("getNewTaskDescription", () => { - it("should show todos as optional when experiment is disabled", () => { + it("should not show todos parameter at all when experiment is disabled", () => { const args: ToolArgs = { cwd: "/test", supportsComputerUse: false, @@ -14,12 +14,18 @@ describe("getNewTaskDescription", () => { const description = getNewTaskDescription(args) - // Check that todos is marked as optional - expect(description).toContain("todos: (optional)") - expect(description).toContain("optional initial todo list") + // Check that todos parameter is not mentioned at all + expect(description).not.toContain("todos:") + expect(description).not.toContain("todo list") + expect(description).not.toContain("") + expect(description).not.toContain("") - // Should not contain any mention of required - expect(description).not.toContain("todos: (required)") + // Should have a simple example without todos + expect(description).toContain("Implement a new feature for the application") + + // Should still have mode and message as required + expect(description).toContain("mode: (required)") + expect(description).toContain("message: (required)") }) it("should show todos as required when experiment is enabled", () => { @@ -40,9 +46,14 @@ describe("getNewTaskDescription", () => { // Should not contain any mention of optional for todos expect(description).not.toContain("todos: (optional)") expect(description).not.toContain("optional initial todo list") + + // Should include todos in the example + expect(description).toContain("") + expect(description).toContain("") + expect(description).toContain("Set up auth middleware") }) - it("should default to optional when experiments is undefined", () => { + it("should not show todos parameter when experiments is undefined", () => { const args: ToolArgs = { cwd: "/test", supportsComputerUse: false, @@ -51,12 +62,14 @@ describe("getNewTaskDescription", () => { const description = getNewTaskDescription(args) - // Check that todos is marked as optional by default - expect(description).toContain("todos: (optional)") - expect(description).toContain("optional initial todo list") + // Check that todos parameter is not shown by default + expect(description).not.toContain("todos:") + expect(description).not.toContain("todo list") + expect(description).not.toContain("") + expect(description).not.toContain("") }) - it("should default to optional when newTaskRequireTodos is undefined", () => { + it("should not show todos parameter when newTaskRequireTodos is undefined", () => { const args: ToolArgs = { cwd: "/test", supportsComputerUse: false, @@ -65,12 +78,14 @@ describe("getNewTaskDescription", () => { const description = getNewTaskDescription(args) - // Check that todos is marked as optional by default - expect(description).toContain("todos: (optional)") - expect(description).toContain("optional initial todo list") + // Check that todos parameter is not shown by default + expect(description).not.toContain("todos:") + expect(description).not.toContain("todo list") + expect(description).not.toContain("") + expect(description).not.toContain("") }) - it("should always include the example with todos", () => { + it("should only include todos in example when experiment is enabled", () => { const argsWithExperimentOff: ToolArgs = { cwd: "/test", supportsComputerUse: false, @@ -90,9 +105,13 @@ describe("getNewTaskDescription", () => { const descriptionOff = getNewTaskDescription(argsWithExperimentOff) const descriptionOn = getNewTaskDescription(argsWithExperimentOn) - // Both should include the example with todos - const examplePattern = /\s*\[\s*\]\s*Set up auth middleware/s - expect(descriptionOff).toMatch(examplePattern) - expect(descriptionOn).toMatch(examplePattern) + // When experiment is off, should NOT include todos in example + const todosPattern = /\s*\[\s*\]\s*Set up auth middleware/s + expect(descriptionOff).not.toMatch(todosPattern) + expect(descriptionOff).not.toContain("") + + // When experiment is on, should include todos in example + expect(descriptionOn).toMatch(todosPattern) + expect(descriptionOn).toContain("") }) }) diff --git a/src/core/prompts/tools/new-task.ts b/src/core/prompts/tools/new-task.ts index f1806bb4e0..f9707daae2 100644 --- a/src/core/prompts/tools/new-task.ts +++ b/src/core/prompts/tools/new-task.ts @@ -2,15 +2,38 @@ import { ToolArgs } from "./types" export function getNewTaskDescription(args: ToolArgs): string { const todosRequired = args.experiments?.newTaskRequireTodos === true - const todosStatus = todosRequired ? "(required)" : "(optional)" + // When experiment is disabled, don't show todos parameter at all + if (!todosRequired) { + return `## new_task +Description: This will let you create a new task instance in the chosen mode using your provided message. + +Parameters: +- mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). +- message: (required) The initial user message or instructions for this new task. + +Usage: + +your-mode-slug-here +Your initial instructions here + + +Example: + +code +Implement a new feature for the application. + +` + } + + // When experiment is enabled, show todos as required return `## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message${todosRequired ? " and initial todo list" : " and optional initial todo list"}. +Description: This will let you create a new task instance in the chosen mode using your provided message and initial todo list. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. -- todos: ${todosStatus} The initial todo list in markdown checklist format for the new task. +- todos: (required) The initial todo list in markdown checklist format for the new task. Usage: From e9da4b9922dab5cdf5c9b9e0a89884340387f47e Mon Sep 17 00:00:00 2001 From: Roo Code Date: Thu, 7 Aug 2025 16:01:37 +0000 Subject: [PATCH 10/12] fix: update snapshots for new_task tool todos parameter - Updated snapshots in add-custom-instructions.spec.ts - Updated snapshots in system-prompt.spec.ts - All tests now passing with the new todos parameter documentation --- .../architect-mode-prompt.snap | 16 ++-------------- .../add-custom-instructions/ask-mode-prompt.snap | 16 ++-------------- .../mcp-server-creation-disabled.snap | 16 ++-------------- .../mcp-server-creation-enabled.snap | 16 ++-------------- .../partial-reads-enabled.snap | 16 ++-------------- .../system-prompt/consistent-system-prompt.snap | 16 ++-------------- .../system-prompt/with-computer-use-support.snap | 16 ++-------------- .../system-prompt/with-diff-enabled-false.snap | 16 ++-------------- .../system-prompt/with-diff-enabled-true.snap | 16 ++-------------- .../with-diff-enabled-undefined.snap | 16 ++-------------- .../with-different-viewport-size.snap | 16 ++-------------- .../system-prompt/with-mcp-hub-provided.snap | 16 ++-------------- .../system-prompt/with-undefined-mcp-hub.snap | 16 ++-------------- 13 files changed, 26 insertions(+), 182 deletions(-) diff --git a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/architect-mode-prompt.snap b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/architect-mode-prompt.snap index aa2010ab17..d67156ab98 100644 --- a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/architect-mode-prompt.snap +++ b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/architect-mode-prompt.snap @@ -338,34 +338,22 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. +Description: This will let you create a new task instance in the chosen mode using your provided message. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. -- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here - -[ ] First task to complete -[ ] Second task to complete -[ ] Third task to complete - Example: code -Implement user authentication - -[ ] Set up auth middleware -[ ] Create login endpoint -[ ] Add session management -[ ] Write tests - +Implement a new feature for the application. diff --git a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/ask-mode-prompt.snap b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/ask-mode-prompt.snap index 4732c66553..5deea1465d 100644 --- a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/ask-mode-prompt.snap +++ b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/ask-mode-prompt.snap @@ -235,34 +235,22 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. +Description: This will let you create a new task instance in the chosen mode using your provided message. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. -- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here - -[ ] First task to complete -[ ] Second task to complete -[ ] Third task to complete - Example: code -Implement user authentication - -[ ] Set up auth middleware -[ ] Create login endpoint -[ ] Add session management -[ ] Write tests - +Implement a new feature for the application. diff --git a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-disabled.snap b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-disabled.snap index 0dbaa101d0..f6cd169723 100644 --- a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-disabled.snap +++ b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-disabled.snap @@ -337,34 +337,22 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. +Description: This will let you create a new task instance in the chosen mode using your provided message. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. -- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here - -[ ] First task to complete -[ ] Second task to complete -[ ] Third task to complete - Example: code -Implement user authentication - -[ ] Set up auth middleware -[ ] Create login endpoint -[ ] Add session management -[ ] Write tests - +Implement a new feature for the application. diff --git a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-enabled.snap b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-enabled.snap index 28ccd20bf7..5a88719371 100644 --- a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-enabled.snap +++ b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-enabled.snap @@ -387,34 +387,22 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. +Description: This will let you create a new task instance in the chosen mode using your provided message. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. -- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here - -[ ] First task to complete -[ ] Second task to complete -[ ] Third task to complete - Example: code -Implement user authentication - -[ ] Set up auth middleware -[ ] Create login endpoint -[ ] Add session management -[ ] Write tests - +Implement a new feature for the application. diff --git a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/partial-reads-enabled.snap b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/partial-reads-enabled.snap index 8c69f89721..6d43d30e9a 100644 --- a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/partial-reads-enabled.snap +++ b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/partial-reads-enabled.snap @@ -343,34 +343,22 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. +Description: This will let you create a new task instance in the chosen mode using your provided message. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. -- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here - -[ ] First task to complete -[ ] Second task to complete -[ ] Third task to complete - Example: code -Implement user authentication - -[ ] Set up auth middleware -[ ] Create login endpoint -[ ] Add session management -[ ] Write tests - +Implement a new feature for the application. diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/consistent-system-prompt.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/consistent-system-prompt.snap index aa2010ab17..d67156ab98 100644 --- a/src/core/prompts/__tests__/__snapshots__/system-prompt/consistent-system-prompt.snap +++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/consistent-system-prompt.snap @@ -338,34 +338,22 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. +Description: This will let you create a new task instance in the chosen mode using your provided message. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. -- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here - -[ ] First task to complete -[ ] Second task to complete -[ ] Third task to complete - Example: code -Implement user authentication - -[ ] Set up auth middleware -[ ] Create login endpoint -[ ] Add session management -[ ] Write tests - +Implement a new feature for the application. diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-computer-use-support.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-computer-use-support.snap index 0f3a116ab0..6aec1a0651 100644 --- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-computer-use-support.snap +++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-computer-use-support.snap @@ -391,34 +391,22 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. +Description: This will let you create a new task instance in the chosen mode using your provided message. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. -- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here - -[ ] First task to complete -[ ] Second task to complete -[ ] Third task to complete - Example: code -Implement user authentication - -[ ] Set up auth middleware -[ ] Create login endpoint -[ ] Add session management -[ ] Write tests - +Implement a new feature for the application. diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-false.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-false.snap index aa2010ab17..d67156ab98 100644 --- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-false.snap +++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-false.snap @@ -338,34 +338,22 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. +Description: This will let you create a new task instance in the chosen mode using your provided message. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. -- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here - -[ ] First task to complete -[ ] Second task to complete -[ ] Third task to complete - Example: code -Implement user authentication - -[ ] Set up auth middleware -[ ] Create login endpoint -[ ] Add session management -[ ] Write tests - +Implement a new feature for the application. diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-true.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-true.snap index 813378962a..a8165dc4f2 100644 --- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-true.snap +++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-true.snap @@ -426,34 +426,22 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. +Description: This will let you create a new task instance in the chosen mode using your provided message. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. -- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here - -[ ] First task to complete -[ ] Second task to complete -[ ] Third task to complete - Example: code -Implement user authentication - -[ ] Set up auth middleware -[ ] Create login endpoint -[ ] Add session management -[ ] Write tests - +Implement a new feature for the application. diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-undefined.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-undefined.snap index aa2010ab17..d67156ab98 100644 --- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-undefined.snap +++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-undefined.snap @@ -338,34 +338,22 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. +Description: This will let you create a new task instance in the chosen mode using your provided message. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. -- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here - -[ ] First task to complete -[ ] Second task to complete -[ ] Third task to complete - Example: code -Implement user authentication - -[ ] Set up auth middleware -[ ] Create login endpoint -[ ] Add session management -[ ] Write tests - +Implement a new feature for the application. diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-different-viewport-size.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-different-viewport-size.snap index 231925264f..b0408f01b8 100644 --- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-different-viewport-size.snap +++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-different-viewport-size.snap @@ -391,34 +391,22 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. +Description: This will let you create a new task instance in the chosen mode using your provided message. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. -- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here - -[ ] First task to complete -[ ] Second task to complete -[ ] Third task to complete - Example: code -Implement user authentication - -[ ] Set up auth middleware -[ ] Create login endpoint -[ ] Add session management -[ ] Write tests - +Implement a new feature for the application. diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-mcp-hub-provided.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-mcp-hub-provided.snap index 28ccd20bf7..5a88719371 100644 --- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-mcp-hub-provided.snap +++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-mcp-hub-provided.snap @@ -387,34 +387,22 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. +Description: This will let you create a new task instance in the chosen mode using your provided message. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. -- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here - -[ ] First task to complete -[ ] Second task to complete -[ ] Third task to complete - Example: code -Implement user authentication - -[ ] Set up auth middleware -[ ] Create login endpoint -[ ] Add session management -[ ] Write tests - +Implement a new feature for the application. diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-undefined-mcp-hub.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-undefined-mcp-hub.snap index aa2010ab17..d67156ab98 100644 --- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-undefined-mcp-hub.snap +++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-undefined-mcp-hub.snap @@ -338,34 +338,22 @@ Example: Requesting to switch to code mode ## new_task -Description: This will let you create a new task instance in the chosen mode using your provided message and optional initial todo list. +Description: This will let you create a new task instance in the chosen mode using your provided message. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). - message: (required) The initial user message or instructions for this new task. -- todos: (optional) The initial todo list in markdown checklist format for the new task. Usage: your-mode-slug-here Your initial instructions here - -[ ] First task to complete -[ ] Second task to complete -[ ] Third task to complete - Example: code -Implement user authentication - -[ ] Set up auth middleware -[ ] Create login endpoint -[ ] Add session management -[ ] Write tests - +Implement a new feature for the application. From bbf71de2a4df90f7c8fd3a64efd36a3ddced9c58 Mon Sep 17 00:00:00 2001 From: Merge Resolver Date: Tue, 19 Aug 2025 18:21:48 -0600 Subject: [PATCH 11/12] feat: move newTaskRequireTodos from experimental to VSCode settings - Added newTaskRequireTodos as a VSCode configuration property in src/package.json - Added description in src/package.nls.json - Updated newTaskTool.ts to read from VSCode configuration instead of experiments - Removed NEW_TASK_REQUIRE_TODOS from experimental settings in src/shared/experiments.ts - Removed newTaskRequireTodos from packages/types/src/experiment.ts - Updated tests to use VSCode configuration mocking instead of experiments - Removed references from experiments test file - Maintains backward compatibility (defaults to false) --- packages/types/src/experiment.ts | 2 - src/core/tools/__tests__/newTaskTool.spec.ts | 78 +++++++++++++------- src/core/tools/newTaskTool.ts | 10 ++- src/package.json | 5 ++ src/package.nls.json | 3 +- src/shared/__tests__/experiments.spec.ts | 3 - src/shared/experiments.ts | 2 - 7 files changed, 63 insertions(+), 40 deletions(-) diff --git a/packages/types/src/experiment.ts b/packages/types/src/experiment.ts index 35f6cbaf48..3890e92ed7 100644 --- a/packages/types/src/experiment.ts +++ b/packages/types/src/experiment.ts @@ -11,7 +11,6 @@ export const experimentIds = [ "multiFileApplyDiff", "preventFocusDisruption", "assistantMessageParser", - "newTaskRequireTodos", ] as const export const experimentIdsSchema = z.enum(experimentIds) @@ -27,7 +26,6 @@ export const experimentsSchema = z.object({ multiFileApplyDiff: z.boolean().optional(), preventFocusDisruption: z.boolean().optional(), assistantMessageParser: z.boolean().optional(), - newTaskRequireTodos: z.boolean().optional(), }) export type Experiments = z.infer diff --git a/src/core/tools/__tests__/newTaskTool.spec.ts b/src/core/tools/__tests__/newTaskTool.spec.ts index 621a9b4f0e..1c883c6fe5 100644 --- a/src/core/tools/__tests__/newTaskTool.spec.ts +++ b/src/core/tools/__tests__/newTaskTool.spec.ts @@ -2,21 +2,21 @@ import type { AskApproval, HandleError } from "../../../shared/tools" +// Mock vscode module +vi.mock("vscode", () => ({ + workspace: { + getConfiguration: vi.fn(() => ({ + get: vi.fn(), + })), + }, +})) + // Mock other modules first - these are hoisted to the top vi.mock("../../../shared/modes", () => ({ getModeBySlug: vi.fn(), defaultModeSlug: "ask", })) -vi.mock("../../../shared/experiments", () => ({ - experiments: { - isEnabled: vi.fn(), - }, - EXPERIMENT_IDS: { - NEW_TASK_REQUIRE_TODOS: "newTaskRequireTodos", - }, -})) - vi.mock("../../prompts/responses", () => ({ formatResponse: { toolError: vi.fn((msg: string) => `Tool Error: ${msg}`), @@ -87,7 +87,7 @@ const mockCline = { import { newTaskTool } from "../newTaskTool" import type { ToolUse } from "../../../shared/tools" import { getModeBySlug } from "../../../shared/modes" -import { experiments } from "../../../shared/experiments" +import * as vscode from "vscode" describe("newTaskTool", () => { beforeEach(() => { @@ -102,8 +102,11 @@ describe("newTaskTool", () => { }) // Default valid mode mockCline.consecutiveMistakeCount = 0 mockCline.isPaused = false - // Default: experimental setting is disabled - vi.mocked(experiments.isEnabled).mockReturnValue(false) + // Default: VSCode setting is disabled + const mockGet = vi.fn().mockReturnValue(false) + vi.mocked(vscode.workspace.getConfiguration).mockReturnValue({ + get: mockGet, + } as any) }) it("should correctly un-escape \\\\@ to \\@ in the message passed to the new task", async () => { @@ -407,10 +410,13 @@ describe("newTaskTool", () => { ) }) - describe("experimental setting: newTaskRequireTodos", () => { - it("should NOT require todos when experimental setting is disabled (default)", async () => { - // Ensure experimental setting is disabled - vi.mocked(experiments.isEnabled).mockReturnValue(false) + describe("VSCode setting: newTaskRequireTodos", () => { + it("should NOT require todos when VSCode setting is disabled (default)", async () => { + // Ensure VSCode setting is disabled + const mockGet = vi.fn().mockReturnValue(false) + vi.mocked(vscode.workspace.getConfiguration).mockReturnValue({ + get: mockGet, + } as any) const block: ToolUse = { type: "tool_use", @@ -451,9 +457,12 @@ describe("newTaskTool", () => { expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("Successfully created new task")) }) - it("should REQUIRE todos when experimental setting is enabled", async () => { - // Enable experimental setting - vi.mocked(experiments.isEnabled).mockReturnValue(true) + it("should REQUIRE todos when VSCode setting is enabled", async () => { + // Enable VSCode setting + const mockGet = vi.fn().mockReturnValue(true) + vi.mocked(vscode.workspace.getConfiguration).mockReturnValue({ + get: mockGet, + } as any) const block: ToolUse = { type: "tool_use", @@ -487,9 +496,12 @@ describe("newTaskTool", () => { ) }) - it("should work with todos when experimental setting is enabled", async () => { - // Enable experimental setting - vi.mocked(experiments.isEnabled).mockReturnValue(true) + it("should work with todos when VSCode setting is enabled", async () => { + // Enable VSCode setting + const mockGet = vi.fn().mockReturnValue(true) + vi.mocked(vscode.workspace.getConfiguration).mockReturnValue({ + get: mockGet, + } as any) const block: ToolUse = { type: "tool_use", @@ -532,9 +544,12 @@ describe("newTaskTool", () => { expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("Successfully created new task")) }) - it("should work with empty todos string when experimental setting is enabled", async () => { - // Enable experimental setting - vi.mocked(experiments.isEnabled).mockReturnValue(true) + it("should work with empty todos string when VSCode setting is enabled", async () => { + // Enable VSCode setting + const mockGet = vi.fn().mockReturnValue(true) + vi.mocked(vscode.workspace.getConfiguration).mockReturnValue({ + get: mockGet, + } as any) const block: ToolUse = { type: "tool_use", @@ -574,7 +589,13 @@ describe("newTaskTool", () => { expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("Successfully created new task")) }) - it("should check experimental setting with correct experiment ID", async () => { + it("should check VSCode setting with correct configuration key", async () => { + const mockGet = vi.fn().mockReturnValue(false) + const mockGetConfiguration = vi.fn().mockReturnValue({ + get: mockGet, + } as any) + vi.mocked(vscode.workspace.getConfiguration).mockImplementation(mockGetConfiguration) + const block: ToolUse = { type: "tool_use", name: "new_task", @@ -594,8 +615,9 @@ describe("newTaskTool", () => { mockRemoveClosingTag, ) - // Verify that experiments.isEnabled was called with correct experiment ID - expect(experiments.isEnabled).toHaveBeenCalledWith(expect.any(Object), "newTaskRequireTodos") + // Verify that VSCode configuration was accessed correctly + expect(mockGetConfiguration).toHaveBeenCalledWith("roo-cline") + expect(mockGet).toHaveBeenCalledWith("newTaskRequireTodos", false) }) }) diff --git a/src/core/tools/newTaskTool.ts b/src/core/tools/newTaskTool.ts index 7fab7e56e8..2a3ab293b6 100644 --- a/src/core/tools/newTaskTool.ts +++ b/src/core/tools/newTaskTool.ts @@ -1,4 +1,5 @@ import delay from "delay" +import * as vscode from "vscode" import { RooCodeEventName, TodoItem } from "@roo-code/types" @@ -8,7 +9,6 @@ import { defaultModeSlug, getModeBySlug } from "../../shared/modes" import { formatResponse } from "../prompts/responses" import { t } from "../../i18n" import { parseMarkdownChecklist } from "./updateTodoListTool" -import { experiments as Experiments, EXPERIMENT_IDS } from "../../shared/experiments" export async function newTaskTool( cline: Task, @@ -49,16 +49,18 @@ export async function newTaskTool( return } - // Get the experimental setting for requiring todos + // Get the VSCode setting for requiring todos const provider = cline.providerRef.deref() if (!provider) { pushToolResult(formatResponse.toolError("Provider reference lost")) return } const state = await provider.getState() - const requireTodos = Experiments.isEnabled(state?.experiments ?? {}, EXPERIMENT_IDS.NEW_TASK_REQUIRE_TODOS) + const requireTodos = vscode.workspace + .getConfiguration("roo-cline") + .get("newTaskRequireTodos", false) - // Check if todos are required based on experimental setting + // Check if todos are required based on VSCode setting // Note: undefined means not provided, empty string is valid if (requireTodos && todos === undefined) { cline.consecutiveMistakeCount++ diff --git a/src/package.json b/src/package.json index d6c447db39..bf980f1064 100644 --- a/src/package.json +++ b/src/package.json @@ -398,6 +398,11 @@ "minimum": 0, "maximum": 3600, "description": "%settings.apiRequestTimeout.description%" + }, + "roo-cline.newTaskRequireTodos": { + "type": "boolean", + "default": false, + "description": "%settings.newTaskRequireTodos.description%" } } } diff --git a/src/package.nls.json b/src/package.nls.json index f1c132be65..a18887218a 100644 --- a/src/package.nls.json +++ b/src/package.nls.json @@ -39,5 +39,6 @@ "settings.enableCodeActions.description": "Enable Roo Code quick fixes", "settings.autoImportSettingsPath.description": "Path to a RooCode configuration file to automatically import on extension startup. Supports absolute paths and paths relative to the home directory (e.g. '~/Documents/roo-code-settings.json'). Leave empty to disable auto-import.", "settings.useAgentRules.description": "Enable loading of AGENTS.md files for agent-specific rules (see https://agent-rules.org/)", - "settings.apiRequestTimeout.description": "Maximum time in seconds to wait for API responses (0 = no timeout, 1-3600s, default: 600s). Higher values are recommended for local providers like LM Studio and Ollama that may need more processing time." + "settings.apiRequestTimeout.description": "Maximum time in seconds to wait for API responses (0 = no timeout, 1-3600s, default: 600s). Higher values are recommended for local providers like LM Studio and Ollama that may need more processing time.", + "settings.newTaskRequireTodos.description": "Require todos parameter when creating new tasks with the new_task tool" } diff --git a/src/shared/__tests__/experiments.spec.ts b/src/shared/__tests__/experiments.spec.ts index 530e2061ec..21401dc759 100644 --- a/src/shared/__tests__/experiments.spec.ts +++ b/src/shared/__tests__/experiments.spec.ts @@ -30,7 +30,6 @@ describe("experiments", () => { multiFileApplyDiff: false, preventFocusDisruption: false, assistantMessageParser: false, - newTaskRequireTodos: false, } expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(false) }) @@ -41,7 +40,6 @@ describe("experiments", () => { multiFileApplyDiff: false, preventFocusDisruption: false, assistantMessageParser: false, - newTaskRequireTodos: false, } expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(true) }) @@ -52,7 +50,6 @@ describe("experiments", () => { multiFileApplyDiff: false, preventFocusDisruption: false, assistantMessageParser: false, - newTaskRequireTodos: false, } expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(false) }) diff --git a/src/shared/experiments.ts b/src/shared/experiments.ts index 1d968e3fc3..4be89afa1a 100644 --- a/src/shared/experiments.ts +++ b/src/shared/experiments.ts @@ -5,7 +5,6 @@ export const EXPERIMENT_IDS = { POWER_STEERING: "powerSteering", PREVENT_FOCUS_DISRUPTION: "preventFocusDisruption", ASSISTANT_MESSAGE_PARSER: "assistantMessageParser", - NEW_TASK_REQUIRE_TODOS: "newTaskRequireTodos", } as const satisfies Record type _AssertExperimentIds = AssertEqual>> @@ -21,7 +20,6 @@ export const experimentConfigsMap: Record = { POWER_STEERING: { enabled: false }, PREVENT_FOCUS_DISRUPTION: { enabled: false }, ASSISTANT_MESSAGE_PARSER: { enabled: false }, - NEW_TASK_REQUIRE_TODOS: { enabled: false }, } export const experimentDefault = Object.fromEntries( From 1781044f8dfdc9e6656ab42377365ef1ba49b2f5 Mon Sep 17 00:00:00 2001 From: Merge Resolver Date: Tue, 19 Aug 2025 18:46:07 -0600 Subject: [PATCH 12/12] fix: make new_task tool description dynamically reflect VSCode setting - Updated new-task.ts to check args.settings instead of args.experiments - Added newTaskRequireTodos to SystemPromptSettings interface - Pass newTaskRequireTodos setting through Task.ts and generateSystemPrompt.ts - Updated all related tests to use settings instead of experiments - Fixed TypeScript errors in test files by adding newTaskRequireTodos property This ensures the tool description correctly shows todos parameter as required/optional based on the VSCode setting value, fixing the issue where Roo would try to use new_task without the todos parameter when it was required. --- .../prompts/__tests__/system-prompt.spec.ts | 3 + .../__tests__/custom-instructions.spec.ts | 72 ++++++++++++++++--- .../prompts/tools/__tests__/new-task.spec.ts | 32 ++++----- src/core/prompts/tools/new-task.ts | 6 +- src/core/prompts/types.ts | 1 + src/core/task/Task.ts | 3 + src/core/webview/generateSystemPrompt.ts | 3 + 7 files changed, 93 insertions(+), 27 deletions(-) diff --git a/src/core/prompts/__tests__/system-prompt.spec.ts b/src/core/prompts/__tests__/system-prompt.spec.ts index 4d5579408c..f2d5469da4 100644 --- a/src/core/prompts/__tests__/system-prompt.spec.ts +++ b/src/core/prompts/__tests__/system-prompt.spec.ts @@ -580,6 +580,7 @@ describe("SYSTEM_PROMPT", () => { maxConcurrentFileReads: 5, todoListEnabled: false, useAgentRules: true, + newTaskRequireTodos: false, } const prompt = await SYSTEM_PROMPT( @@ -612,6 +613,7 @@ describe("SYSTEM_PROMPT", () => { maxConcurrentFileReads: 5, todoListEnabled: true, useAgentRules: true, + newTaskRequireTodos: false, } const prompt = await SYSTEM_PROMPT( @@ -643,6 +645,7 @@ describe("SYSTEM_PROMPT", () => { maxConcurrentFileReads: 5, todoListEnabled: true, useAgentRules: true, + newTaskRequireTodos: false, } const prompt = await SYSTEM_PROMPT( diff --git a/src/core/prompts/sections/__tests__/custom-instructions.spec.ts b/src/core/prompts/sections/__tests__/custom-instructions.spec.ts index be9c25bcaa..49904465ab 100644 --- a/src/core/prompts/sections/__tests__/custom-instructions.spec.ts +++ b/src/core/prompts/sections/__tests__/custom-instructions.spec.ts @@ -535,7 +535,14 @@ describe("addCustomInstructions", () => { "global instructions", "/fake/path", "test-mode", - { settings: { maxConcurrentFileReads: 5, todoListEnabled: true, useAgentRules: true } }, + { + settings: { + maxConcurrentFileReads: 5, + todoListEnabled: true, + useAgentRules: true, + newTaskRequireTodos: false, + }, + }, ) expect(result).toContain("# Agent Rules Standard (AGENTS.md):") @@ -560,7 +567,14 @@ describe("addCustomInstructions", () => { "global instructions", "/fake/path", "test-mode", - { settings: { maxConcurrentFileReads: 5, todoListEnabled: true, useAgentRules: false } }, + { + settings: { + maxConcurrentFileReads: 5, + todoListEnabled: true, + useAgentRules: false, + newTaskRequireTodos: false, + }, + }, ) expect(result).not.toContain("# Agent Rules Standard (AGENTS.md):") @@ -614,7 +628,14 @@ describe("addCustomInstructions", () => { "global instructions", "/fake/path", "test-mode", - { settings: { maxConcurrentFileReads: 5, todoListEnabled: true, useAgentRules: true } }, + { + settings: { + maxConcurrentFileReads: 5, + todoListEnabled: true, + useAgentRules: true, + newTaskRequireTodos: false, + }, + }, ) expect(result).toContain("Global Instructions:\nglobal instructions") @@ -653,7 +674,14 @@ describe("addCustomInstructions", () => { "global instructions", "/fake/path", "test-mode", - { settings: { maxConcurrentFileReads: 5, todoListEnabled: true, useAgentRules: true } }, + { + settings: { + maxConcurrentFileReads: 5, + todoListEnabled: true, + useAgentRules: true, + newTaskRequireTodos: false, + }, + }, ) // Should contain both AGENTS.md and .roorules content @@ -714,7 +742,14 @@ describe("addCustomInstructions", () => { "global instructions", "/fake/path", "test-mode", - { settings: { maxConcurrentFileReads: 5, todoListEnabled: true, useAgentRules: true } }, + { + settings: { + maxConcurrentFileReads: 5, + todoListEnabled: true, + useAgentRules: true, + newTaskRequireTodos: false, + }, + }, ) expect(result).toContain("# Agent Rules Standard (AGENTS.md):") @@ -759,7 +794,14 @@ describe("addCustomInstructions", () => { "global instructions", "/fake/path", "test-mode", - { settings: { maxConcurrentFileReads: 5, todoListEnabled: true, useAgentRules: true } }, + { + settings: { + maxConcurrentFileReads: 5, + todoListEnabled: true, + useAgentRules: true, + newTaskRequireTodos: false, + }, + }, ) expect(result).toContain("# Agent Rules Standard (AGENTS.md):") @@ -806,7 +848,14 @@ describe("addCustomInstructions", () => { "global instructions", "/fake/path", "test-mode", - { settings: { maxConcurrentFileReads: 5, todoListEnabled: true, useAgentRules: true } }, + { + settings: { + maxConcurrentFileReads: 5, + todoListEnabled: true, + useAgentRules: true, + newTaskRequireTodos: false, + }, + }, ) expect(result).toContain("# Agent Rules Standard (AGENT.md):") @@ -845,7 +894,14 @@ describe("addCustomInstructions", () => { "global instructions", "/fake/path", "test-mode", - { settings: { maxConcurrentFileReads: 5, todoListEnabled: true, useAgentRules: true } }, + { + settings: { + maxConcurrentFileReads: 5, + todoListEnabled: true, + useAgentRules: true, + newTaskRequireTodos: false, + }, + }, ) // Should contain AGENTS.md content (preferred) and not AGENT.md diff --git a/src/core/prompts/tools/__tests__/new-task.spec.ts b/src/core/prompts/tools/__tests__/new-task.spec.ts index 4a87eb9840..b6379384d0 100644 --- a/src/core/prompts/tools/__tests__/new-task.spec.ts +++ b/src/core/prompts/tools/__tests__/new-task.spec.ts @@ -3,11 +3,11 @@ import { getNewTaskDescription } from "../new-task" import { ToolArgs } from "../types" describe("getNewTaskDescription", () => { - it("should not show todos parameter at all when experiment is disabled", () => { + it("should not show todos parameter at all when setting is disabled", () => { const args: ToolArgs = { cwd: "/test", supportsComputerUse: false, - experiments: { + settings: { newTaskRequireTodos: false, }, } @@ -28,11 +28,11 @@ describe("getNewTaskDescription", () => { expect(description).toContain("message: (required)") }) - it("should show todos as required when experiment is enabled", () => { + it("should show todos as required when setting is enabled", () => { const args: ToolArgs = { cwd: "/test", supportsComputerUse: false, - experiments: { + settings: { newTaskRequireTodos: true, }, } @@ -53,11 +53,11 @@ describe("getNewTaskDescription", () => { expect(description).toContain("Set up auth middleware") }) - it("should not show todos parameter when experiments is undefined", () => { + it("should not show todos parameter when settings is undefined", () => { const args: ToolArgs = { cwd: "/test", supportsComputerUse: false, - experiments: undefined, + settings: undefined, } const description = getNewTaskDescription(args) @@ -73,7 +73,7 @@ describe("getNewTaskDescription", () => { const args: ToolArgs = { cwd: "/test", supportsComputerUse: false, - experiments: {}, + settings: {}, } const description = getNewTaskDescription(args) @@ -85,32 +85,32 @@ describe("getNewTaskDescription", () => { expect(description).not.toContain("") }) - it("should only include todos in example when experiment is enabled", () => { - const argsWithExperimentOff: ToolArgs = { + it("should only include todos in example when setting is enabled", () => { + const argsWithSettingOff: ToolArgs = { cwd: "/test", supportsComputerUse: false, - experiments: { + settings: { newTaskRequireTodos: false, }, } - const argsWithExperimentOn: ToolArgs = { + const argsWithSettingOn: ToolArgs = { cwd: "/test", supportsComputerUse: false, - experiments: { + settings: { newTaskRequireTodos: true, }, } - const descriptionOff = getNewTaskDescription(argsWithExperimentOff) - const descriptionOn = getNewTaskDescription(argsWithExperimentOn) + const descriptionOff = getNewTaskDescription(argsWithSettingOff) + const descriptionOn = getNewTaskDescription(argsWithSettingOn) - // When experiment is off, should NOT include todos in example + // When setting is off, should NOT include todos in example const todosPattern = /\s*\[\s*\]\s*Set up auth middleware/s expect(descriptionOff).not.toMatch(todosPattern) expect(descriptionOff).not.toContain("") - // When experiment is on, should include todos in example + // When setting is on, should include todos in example expect(descriptionOn).toMatch(todosPattern) expect(descriptionOn).toContain("") }) diff --git a/src/core/prompts/tools/new-task.ts b/src/core/prompts/tools/new-task.ts index f9707daae2..0b15bc0ad9 100644 --- a/src/core/prompts/tools/new-task.ts +++ b/src/core/prompts/tools/new-task.ts @@ -1,9 +1,9 @@ import { ToolArgs } from "./types" export function getNewTaskDescription(args: ToolArgs): string { - const todosRequired = args.experiments?.newTaskRequireTodos === true + const todosRequired = args.settings?.newTaskRequireTodos === true - // When experiment is disabled, don't show todos parameter at all + // When setting is disabled, don't show todos parameter at all if (!todosRequired) { return `## new_task Description: This will let you create a new task instance in the chosen mode using your provided message. @@ -26,7 +26,7 @@ Example: ` } - // When experiment is enabled, show todos as required + // When setting is enabled, show todos as required return `## new_task Description: This will let you create a new task instance in the chosen mode using your provided message and initial todo list. diff --git a/src/core/prompts/types.ts b/src/core/prompts/types.ts index 3977ea98c5..d90b1b821a 100644 --- a/src/core/prompts/types.ts +++ b/src/core/prompts/types.ts @@ -5,4 +5,5 @@ export interface SystemPromptSettings { maxConcurrentFileReads: number todoListEnabled: boolean useAgentRules: boolean + newTaskRequireTodos: boolean } diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index 75f152c214..13a9d89978 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -2236,6 +2236,9 @@ export class Task extends EventEmitter implements TaskLike { maxConcurrentFileReads: maxConcurrentFileReads ?? 5, todoListEnabled: apiConfiguration?.todoListEnabled ?? true, useAgentRules: vscode.workspace.getConfiguration("roo-cline").get("useAgentRules") ?? true, + newTaskRequireTodos: vscode.workspace + .getConfiguration("roo-cline") + .get("newTaskRequireTodos", false), }, undefined, // todoList this.api.getModel().id, diff --git a/src/core/webview/generateSystemPrompt.ts b/src/core/webview/generateSystemPrompt.ts index 9b96dbedbb..a639d8a960 100644 --- a/src/core/webview/generateSystemPrompt.ts +++ b/src/core/webview/generateSystemPrompt.ts @@ -85,6 +85,9 @@ export const generateSystemPrompt = async (provider: ClineProvider, message: Web maxConcurrentFileReads: maxConcurrentFileReads ?? 5, todoListEnabled: apiConfiguration?.todoListEnabled ?? true, useAgentRules: vscode.workspace.getConfiguration("roo-cline").get("useAgentRules") ?? true, + newTaskRequireTodos: vscode.workspace + .getConfiguration("roo-cline") + .get("newTaskRequireTodos", false), }, )