Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/types/src/mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
119 changes: 119 additions & 0 deletions src/core/prompts/tools/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
@@ -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")
})
})
})
10 changes: 8 additions & 2 deletions src/core/prompts/tools/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down
53 changes: 53 additions & 0 deletions src/core/tools/__tests__/validateToolUse.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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", () => {
Expand Down
9 changes: 8 additions & 1 deletion src/shared/modes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down