feat: add disableTaskLists option to mode configuration

- Add optional disableTaskLists property to ModeConfig type schema
- Update tool description generation to conditionally exclude update_todo_list tool
- Modify isToolAllowedForMode to respect disableTaskLists setting
- Add comprehensive tests for the new functionality

Fixes #5693
This commit is contained in:
Roo Code 2025-07-14 14:28:08 +00:00
parent a163053430
commit 267ed33732
5 changed files with 189 additions and 3 deletions

View file

@ -70,6 +70,7 @@ export const modeConfigSchema = z.object({
customInstructions: z.string().optional(),
groups: groupEntryArraySchema,
source: z.enum(["global", "project"]).optional(),
disableTaskLists: z.boolean().optional(),
})
export type ModeConfig = z.infer<typeof modeConfigSchema>

View file

@ -0,0 +1,119 @@
// npx vitest run src/core/prompts/tools/__tests__/index.spec.ts
import type { ModeConfig } from "@roo-code/types"
import { getToolDescriptionsForMode } from "../index"
describe("getToolDescriptionsForMode", () => {
describe("disableTaskLists", () => {
it("excludes update_todo_list from tool descriptions when disableTaskLists is true", () => {
const customModes: ModeConfig[] = [
{
slug: "no-tasks-mode",
name: "No Tasks Mode",
roleDefinition: "A mode without task lists",
groups: ["read"] as const,
disableTaskLists: true,
},
]
const toolDescriptions = getToolDescriptionsForMode(
"no-tasks-mode",
"/test/cwd",
false, // supportsComputerUse
undefined, // codeIndexManager
undefined, // diffStrategy
undefined, // browserViewportSize
undefined, // mcpHub
customModes,
{}, // experiments
false, // partialReadsEnabled
{}, // settings
)
// Should not contain update_todo_list tool description
expect(toolDescriptions).not.toContain("update_todo_list")
expect(toolDescriptions).not.toContain("## update_todo_list")
// Should still contain other always available tools
expect(toolDescriptions).toContain("ask_followup_question")
expect(toolDescriptions).toContain("attempt_completion")
})
it("includes update_todo_list in tool descriptions when disableTaskLists is false", () => {
const customModes: ModeConfig[] = [
{
slug: "tasks-mode",
name: "Tasks Mode",
roleDefinition: "A mode with task lists",
groups: ["read"] as const,
disableTaskLists: false,
},
]
const toolDescriptions = getToolDescriptionsForMode(
"tasks-mode",
"/test/cwd",
false, // supportsComputerUse
undefined, // codeIndexManager
undefined, // diffStrategy
undefined, // browserViewportSize
undefined, // mcpHub
customModes,
{}, // experiments
false, // partialReadsEnabled
{}, // settings
)
// Should contain update_todo_list tool description
expect(toolDescriptions).toContain("## update_todo_list")
})
it("includes update_todo_list in tool descriptions when disableTaskLists is undefined", () => {
const customModes: ModeConfig[] = [
{
slug: "default-mode",
name: "Default Mode",
roleDefinition: "A mode with default task list behavior",
groups: ["read"] as const,
},
]
const toolDescriptions = getToolDescriptionsForMode(
"default-mode",
"/test/cwd",
false, // supportsComputerUse
undefined, // codeIndexManager
undefined, // diffStrategy
undefined, // browserViewportSize
undefined, // mcpHub
customModes,
{}, // experiments
false, // partialReadsEnabled
{}, // settings
)
// Should contain update_todo_list tool description by default
expect(toolDescriptions).toContain("## update_todo_list")
})
it("includes update_todo_list in built-in mode tool descriptions", () => {
const toolDescriptions = getToolDescriptionsForMode(
"code",
"/test/cwd",
false, // supportsComputerUse
undefined, // codeIndexManager
undefined, // diffStrategy
undefined, // browserViewportSize
undefined, // mcpHub
[], // customModes
{}, // experiments
false, // partialReadsEnabled
{}, // settings
)
// Built-in modes should always include update_todo_list
expect(toolDescriptions).toContain("## update_todo_list")
})
})
})

View file

@ -98,8 +98,14 @@ export function getToolDescriptionsForMode(
}
})
// Add always available tools
ALWAYS_AVAILABLE_TOOLS.forEach((tool) => tools.add(tool))
// Add always available tools, but check for mode-specific exclusions
ALWAYS_AVAILABLE_TOOLS.forEach((tool) => {
// Check if update_todo_list should be excluded for this mode
if (tool === "update_todo_list" && config.disableTaskLists) {
return // Skip adding this tool
}
tools.add(tool)
})
// Conditionally exclude codebase_search if feature is disabled or not configured
if (

View file

@ -128,6 +128,59 @@ describe("mode-validator", () => {
expect(isToolAllowedForMode("apply_diff", codeMode, [], requirements)).toBe(false)
})
})
describe("disableTaskLists", () => {
it("disallows update_todo_list when disableTaskLists is true", () => {
const customModes: ModeConfig[] = [
{
slug: "no-tasks-mode",
name: "No Tasks Mode",
roleDefinition: "A mode without task lists",
groups: ["read"] as const,
disableTaskLists: true,
},
]
// Should not allow update_todo_list tool
expect(isToolAllowedForMode("update_todo_list", "no-tasks-mode", customModes)).toBe(false)
// Should still allow other always available tools
expect(isToolAllowedForMode("ask_followup_question", "no-tasks-mode", customModes)).toBe(true)
expect(isToolAllowedForMode("attempt_completion", "no-tasks-mode", customModes)).toBe(true)
})
it("allows update_todo_list when disableTaskLists is false", () => {
const customModes: ModeConfig[] = [
{
slug: "tasks-mode",
name: "Tasks Mode",
roleDefinition: "A mode with task lists",
groups: ["read"] as const,
disableTaskLists: false,
},
]
// Should allow update_todo_list tool
expect(isToolAllowedForMode("update_todo_list", "tasks-mode", customModes)).toBe(true)
})
it("allows update_todo_list when disableTaskLists is undefined", () => {
const customModes: ModeConfig[] = [
{
slug: "default-mode",
name: "Default Mode",
roleDefinition: "A mode with default task list behavior",
groups: ["read"] as const,
},
]
// Should allow update_todo_list tool by default
expect(isToolAllowedForMode("update_todo_list", "default-mode", customModes)).toBe(true)
})
it("allows update_todo_list in built-in modes", () => {
// Built-in modes should always allow update_todo_list
expect(isToolAllowedForMode("update_todo_list", codeMode, [])).toBe(true)
expect(isToolAllowedForMode("update_todo_list", architectMode, [])).toBe(true)
expect(isToolAllowedForMode("update_todo_list", askMode, [])).toBe(true)
})
})
})
describe("validateToolUse", () => {

View file

@ -231,8 +231,15 @@ export function isToolAllowedForMode(
toolParams?: Record<string, any>, // All tool parameters
experiments?: Record<string, boolean>,
): boolean {
// Always allow these tools
// Always allow these tools, but check for mode-specific exclusions
if (ALWAYS_AVAILABLE_TOOLS.includes(tool as any)) {
// Check if update_todo_list should be excluded for this mode
if (tool === "update_todo_list") {
const mode = getModeBySlug(modeSlug, customModes)
if (mode?.disableTaskLists) {
return false
}
}
return true
}
if (experiments && Object.values(EXPERIMENT_IDS).includes(tool as ExperimentId)) {