mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
feat: add individual tool controls to reduce token usage
- Add disabledTools configuration to global settings schema - Update tool system to filter out disabled tools from system prompt - Create ToolSettings UI component for toggling tools on/off - Add tool settings section to settings view with wrench icon - Update message handlers to persist disabled tools state - Add comprehensive tests for disabled tools functionality - Ensure always-available tools cannot be disabled Fixes #5963
This commit is contained in:
parent
1b12108172
commit
7267fe0299
13 changed files with 400 additions and 2 deletions
|
|
@ -72,6 +72,8 @@ export const globalSettingsSchema = z.object({
|
|||
autoCondenseContextPercent: z.number().optional(),
|
||||
maxConcurrentFileReads: z.number().optional(),
|
||||
|
||||
disabledTools: z.array(z.string()).optional(),
|
||||
|
||||
browserToolEnabled: z.boolean().optional(),
|
||||
browserViewportSize: z.string().optional(),
|
||||
screenshotQuality: z.number().optional(),
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ ${getToolDescriptionsForMode(
|
|||
experiments,
|
||||
partialReadsEnabled,
|
||||
settings,
|
||||
settings?.disabledTools,
|
||||
)}
|
||||
|
||||
${getToolUseGuidelinesSection(codeIndexManager)}
|
||||
|
|
|
|||
231
src/core/prompts/tools/__tests__/index.spec.ts
Normal file
231
src/core/prompts/tools/__tests__/index.spec.ts
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
// npx vitest core/prompts/tools/__tests__/index.spec.ts
|
||||
|
||||
import { describe, it, expect } from "vitest"
|
||||
import { getToolDescriptionsForMode } from "../index"
|
||||
import { defaultModeSlug } from "../../../../shared/modes"
|
||||
|
||||
describe("getToolDescriptionsForMode", () => {
|
||||
const mockCwd = "/test/path"
|
||||
const supportsComputerUse = false
|
||||
|
||||
it("should return tool descriptions for a given mode", () => {
|
||||
const result = getToolDescriptionsForMode(
|
||||
defaultModeSlug,
|
||||
mockCwd,
|
||||
supportsComputerUse,
|
||||
undefined, // codeIndexManager
|
||||
undefined, // diffStrategy
|
||||
undefined, // browserViewportSize
|
||||
undefined, // mcpHub
|
||||
undefined, // customModes
|
||||
undefined, // experiments
|
||||
undefined, // partialReadsEnabled
|
||||
undefined, // settings
|
||||
undefined, // disabledTools
|
||||
)
|
||||
|
||||
expect(result).toBeTruthy()
|
||||
expect(result).toContain("# Tools")
|
||||
|
||||
// Check that it includes some expected tools from architect mode
|
||||
expect(result).toContain("read_file")
|
||||
expect(result).toContain("write_to_file")
|
||||
expect(result).toContain("list_files")
|
||||
// Note: execute_command is not in architect mode
|
||||
})
|
||||
|
||||
it("should filter out disabled tools", () => {
|
||||
const disabledTools = ["read_file", "write_to_file"]
|
||||
const result = getToolDescriptionsForMode(
|
||||
defaultModeSlug,
|
||||
mockCwd,
|
||||
supportsComputerUse,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
disabledTools,
|
||||
)
|
||||
|
||||
// Check that disabled tools are not included
|
||||
expect(result).not.toContain("## read_file")
|
||||
expect(result).not.toContain("## write_to_file")
|
||||
|
||||
// Check that other tools are still included
|
||||
expect(result).toContain("## list_files")
|
||||
expect(result).toContain("## search_files")
|
||||
})
|
||||
|
||||
it("should not filter out always-available tools even if disabled", () => {
|
||||
const disabledTools = ["ask_followup_question", "attempt_completion"]
|
||||
const result = getToolDescriptionsForMode(
|
||||
defaultModeSlug,
|
||||
mockCwd,
|
||||
supportsComputerUse,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
disabledTools,
|
||||
)
|
||||
|
||||
// These tools should always be available
|
||||
expect(result).toContain("## ask_followup_question")
|
||||
expect(result).toContain("## attempt_completion")
|
||||
})
|
||||
|
||||
it("should handle empty disabled tools array", () => {
|
||||
const disabledTools: string[] = []
|
||||
const resultWithEmpty = getToolDescriptionsForMode(
|
||||
defaultModeSlug,
|
||||
mockCwd,
|
||||
supportsComputerUse,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
disabledTools,
|
||||
)
|
||||
const resultWithoutDisabled = getToolDescriptionsForMode(
|
||||
defaultModeSlug,
|
||||
mockCwd,
|
||||
supportsComputerUse,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
)
|
||||
|
||||
// Should return the same tools
|
||||
expect(resultWithEmpty).toEqual(resultWithoutDisabled)
|
||||
})
|
||||
|
||||
it("should handle undefined disabled tools", () => {
|
||||
const resultWithUndefined = getToolDescriptionsForMode(
|
||||
defaultModeSlug,
|
||||
mockCwd,
|
||||
supportsComputerUse,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
)
|
||||
const resultWithoutDisabled = getToolDescriptionsForMode(
|
||||
defaultModeSlug,
|
||||
mockCwd,
|
||||
supportsComputerUse,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
)
|
||||
|
||||
// Should return the same tools
|
||||
expect(resultWithUndefined).toEqual(resultWithoutDisabled)
|
||||
})
|
||||
|
||||
it("should filter out multiple disabled tools correctly", () => {
|
||||
const disabledTools = ["read_file", "write_to_file", "list_files", "search_files"]
|
||||
const result = getToolDescriptionsForMode(
|
||||
defaultModeSlug,
|
||||
mockCwd,
|
||||
supportsComputerUse,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
disabledTools,
|
||||
)
|
||||
|
||||
// Check that all disabled tools are filtered out
|
||||
disabledTools.forEach((tool) => {
|
||||
expect(result).not.toContain(`## ${tool}`)
|
||||
})
|
||||
|
||||
// Check that some other tools are still included
|
||||
expect(result).toContain("# Tools")
|
||||
// Always available tools should still be there
|
||||
expect(result).toContain("## ask_followup_question")
|
||||
})
|
||||
|
||||
it("should handle invalid tool names in disabled list", () => {
|
||||
const disabledTools = ["invalid_tool", "another_invalid", "read_file"]
|
||||
const result = getToolDescriptionsForMode(
|
||||
defaultModeSlug,
|
||||
mockCwd,
|
||||
supportsComputerUse,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
disabledTools,
|
||||
)
|
||||
|
||||
// Should still filter out valid disabled tools
|
||||
expect(result).not.toContain("## read_file")
|
||||
|
||||
// Invalid tools should not affect the result
|
||||
expect(result).toContain("## write_to_file")
|
||||
expect(result).toContain("## list_files")
|
||||
})
|
||||
|
||||
it("should work with code mode that has execute_command", () => {
|
||||
const disabledTools = ["execute_command"]
|
||||
const result = getToolDescriptionsForMode(
|
||||
"code", // code mode has the command group
|
||||
mockCwd,
|
||||
supportsComputerUse,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
disabledTools,
|
||||
)
|
||||
|
||||
// execute_command should be filtered out
|
||||
expect(result).not.toContain("## execute_command")
|
||||
|
||||
// Other tools should still be included
|
||||
expect(result).toContain("## read_file")
|
||||
expect(result).toContain("## write_to_file")
|
||||
})
|
||||
})
|
||||
|
|
@ -61,6 +61,7 @@ export function getToolDescriptionsForMode(
|
|||
experiments?: Record<string, boolean>,
|
||||
partialReadsEnabled?: boolean,
|
||||
settings?: Record<string, any>,
|
||||
disabledTools?: string[],
|
||||
): string {
|
||||
const config = getModeConfig(mode, customModes)
|
||||
const args: ToolArgs = {
|
||||
|
|
@ -109,6 +110,16 @@ export function getToolDescriptionsForMode(
|
|||
tools.delete("codebase_search")
|
||||
}
|
||||
|
||||
// Filter out disabled tools (except always-available tools)
|
||||
if (disabledTools && disabledTools.length > 0) {
|
||||
disabledTools.forEach((tool) => {
|
||||
// Don't filter out always-available tools
|
||||
if (!ALWAYS_AVAILABLE_TOOLS.includes(tool as any)) {
|
||||
tools.delete(tool)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Map tool descriptions for allowed tools
|
||||
const descriptions = Array.from(tools).map((toolName) => {
|
||||
const descriptionFn = toolDescriptionMap[toolName]
|
||||
|
|
|
|||
|
|
@ -1624,6 +1624,7 @@ export class Task extends EventEmitter<ClineEvents> {
|
|||
language,
|
||||
maxConcurrentFileReads,
|
||||
maxReadFileLine,
|
||||
disabledTools,
|
||||
} = state ?? {}
|
||||
|
||||
return await (async () => {
|
||||
|
|
@ -1652,6 +1653,7 @@ export class Task extends EventEmitter<ClineEvents> {
|
|||
maxReadFileLine !== -1,
|
||||
{
|
||||
maxConcurrentFileReads,
|
||||
disabledTools,
|
||||
},
|
||||
)
|
||||
})()
|
||||
|
|
|
|||
|
|
@ -1440,6 +1440,7 @@ export class ClineProvider
|
|||
alwaysAllowFollowupQuestions,
|
||||
followupAutoApproveTimeoutMs,
|
||||
diagnosticsEnabled,
|
||||
disabledTools,
|
||||
} = await this.getState()
|
||||
|
||||
const telemetryKey = process.env.POSTHOG_API_KEY
|
||||
|
|
@ -1561,6 +1562,7 @@ export class ClineProvider
|
|||
alwaysAllowFollowupQuestions: alwaysAllowFollowupQuestions ?? false,
|
||||
followupAutoApproveTimeoutMs: followupAutoApproveTimeoutMs ?? 60000,
|
||||
diagnosticsEnabled: diagnosticsEnabled ?? true,
|
||||
disabledTools: disabledTools ?? [],
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1726,6 +1728,7 @@ export class ClineProvider
|
|||
codebaseIndexSearchMinScore: stateValues.codebaseIndexConfig?.codebaseIndexSearchMinScore,
|
||||
},
|
||||
profileThresholds: stateValues.profileThresholds ?? {},
|
||||
disabledTools: stateValues.disabledTools ?? [],
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ export const generateSystemPrompt = async (provider: ClineProvider, message: Web
|
|||
language,
|
||||
maxReadFileLine,
|
||||
maxConcurrentFileReads,
|
||||
disabledTools,
|
||||
} = await provider.getState()
|
||||
|
||||
// Check experiment to determine which diff strategy to use
|
||||
|
|
@ -82,6 +83,7 @@ export const generateSystemPrompt = async (provider: ClineProvider, message: Web
|
|||
maxReadFileLine !== -1,
|
||||
{
|
||||
maxConcurrentFileReads,
|
||||
disabledTools,
|
||||
},
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1232,6 +1232,10 @@ export const webviewMessageHandler = async (
|
|||
await updateGlobalState("browserToolEnabled", message.bool ?? true)
|
||||
await provider.postStateToWebview()
|
||||
break
|
||||
case "disabledTools":
|
||||
await updateGlobalState("disabledTools", message.disabledTools ?? [])
|
||||
await provider.postStateToWebview()
|
||||
break
|
||||
case "language":
|
||||
changeLanguage(message.text ?? "en")
|
||||
await updateGlobalState("language", message.text as Language)
|
||||
|
|
|
|||
|
|
@ -189,6 +189,7 @@ export type ExtensionState = Pick<
|
|||
| "allowedCommands"
|
||||
| "deniedCommands"
|
||||
| "allowedMaxRequests"
|
||||
| "disabledTools"
|
||||
| "browserToolEnabled"
|
||||
| "browserViewportSize"
|
||||
| "screenshotQuality"
|
||||
|
|
|
|||
|
|
@ -153,6 +153,7 @@ export interface WebviewMessage {
|
|||
| "humanRelayResponse"
|
||||
| "humanRelayCancel"
|
||||
| "browserToolEnabled"
|
||||
| "disabledTools"
|
||||
| "codebaseIndexEnabled"
|
||||
| "telemetrySetting"
|
||||
| "showRooIgnoredFiles"
|
||||
|
|
@ -241,6 +242,7 @@ export interface WebviewMessage {
|
|||
visibility?: ShareVisibility // For share visibility
|
||||
hasContent?: boolean // For checkRulesDirectoryResult
|
||||
checkOnly?: boolean // For deleteCustomMode check
|
||||
disabledTools?: string[] // For disabling specific tools
|
||||
codeIndexSettings?: {
|
||||
// Global state settings
|
||||
codebaseIndexEnabled: boolean
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import {
|
|||
Info,
|
||||
MessageSquare,
|
||||
LucideIcon,
|
||||
Wrench,
|
||||
} from "lucide-react"
|
||||
|
||||
import type { ProviderSettings, ExperimentId } from "@roo-code/types"
|
||||
|
|
@ -65,6 +66,7 @@ import { LanguageSettings } from "./LanguageSettings"
|
|||
import { About } from "./About"
|
||||
import { Section } from "./Section"
|
||||
import PromptsSettings from "./PromptsSettings"
|
||||
import { ToolSettings } from "./ToolSettings"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
export const settingsTabsContainer = "flex flex-1 overflow-hidden [&.narrow_.tab-label]:hidden"
|
||||
|
|
@ -87,6 +89,7 @@ const sectionNames = [
|
|||
"contextManagement",
|
||||
"terminal",
|
||||
"prompts",
|
||||
"tools",
|
||||
"experimental",
|
||||
"language",
|
||||
"about",
|
||||
|
|
@ -177,6 +180,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
|
|||
alwaysAllowFollowupQuestions,
|
||||
alwaysAllowUpdateTodoList,
|
||||
followupAutoApproveTimeoutMs,
|
||||
disabledTools,
|
||||
} = cachedState
|
||||
|
||||
const apiConfiguration = useMemo(() => cachedState.apiConfiguration ?? {}, [cachedState.apiConfiguration])
|
||||
|
|
@ -333,6 +337,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
|
|||
vscode.postMessage({ type: "upsertApiConfiguration", text: currentApiConfigName, apiConfiguration })
|
||||
vscode.postMessage({ type: "telemetrySetting", text: telemetrySetting })
|
||||
vscode.postMessage({ type: "profileThresholds", values: profileThresholds })
|
||||
vscode.postMessage({ type: "disabledTools", values: disabledTools })
|
||||
setChangeDetected(false)
|
||||
}
|
||||
}
|
||||
|
|
@ -410,6 +415,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
|
|||
{ id: "contextManagement", icon: Database },
|
||||
{ id: "terminal", icon: SquareTerminal },
|
||||
{ id: "prompts", icon: MessageSquare },
|
||||
{ id: "tools", icon: Wrench },
|
||||
{ id: "experimental", icon: FlaskConical },
|
||||
{ id: "language", icon: Globe },
|
||||
{ id: "about", icon: Info },
|
||||
|
|
@ -698,6 +704,11 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
|
|||
/>
|
||||
)}
|
||||
|
||||
{/* Tools Section */}
|
||||
{activeTab === "tools" && (
|
||||
<ToolSettings disabledTools={disabledTools} setCachedStateField={setCachedStateField} />
|
||||
)}
|
||||
|
||||
{/* Experimental Section */}
|
||||
{activeTab === "experimental" && (
|
||||
<ExperimentalSettings setExperimentEnabled={setExperimentEnabled} experiments={experiments} />
|
||||
|
|
|
|||
123
webview-ui/src/components/settings/ToolSettings.tsx
Normal file
123
webview-ui/src/components/settings/ToolSettings.tsx
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
|
||||
import { Wrench } from "lucide-react"
|
||||
import { HTMLAttributes, useMemo } from "react"
|
||||
|
||||
import { useAppTranslation } from "@/i18n/TranslationContext"
|
||||
|
||||
import { Section } from "./Section"
|
||||
import { SectionHeader } from "./SectionHeader"
|
||||
import { SetCachedStateField } from "./types"
|
||||
|
||||
type ToolSettingsProps = HTMLAttributes<HTMLDivElement> & {
|
||||
disabledTools?: string[]
|
||||
setCachedStateField: SetCachedStateField<"disabledTools">
|
||||
}
|
||||
|
||||
// Tool display names mapping
|
||||
const TOOL_DISPLAY_NAMES: Record<string, string> = {
|
||||
execute_command: "Run commands",
|
||||
read_file: "Read files",
|
||||
fetch_instructions: "Fetch instructions",
|
||||
write_to_file: "Write files",
|
||||
apply_diff: "Apply changes",
|
||||
search_files: "Search files",
|
||||
list_files: "List files",
|
||||
list_code_definition_names: "List definitions",
|
||||
browser_action: "Use a browser",
|
||||
use_mcp_tool: "Use MCP tools",
|
||||
access_mcp_resource: "Access MCP resources",
|
||||
ask_followup_question: "Ask questions",
|
||||
attempt_completion: "Complete tasks",
|
||||
switch_mode: "Switch modes",
|
||||
new_task: "Create new task",
|
||||
insert_content: "Insert content",
|
||||
search_and_replace: "Search and replace",
|
||||
codebase_search: "Codebase search",
|
||||
update_todo_list: "Update todo list",
|
||||
}
|
||||
|
||||
// Tools that are always available and cannot be disabled
|
||||
const ALWAYS_AVAILABLE_TOOLS = [
|
||||
"ask_followup_question",
|
||||
"attempt_completion",
|
||||
"switch_mode",
|
||||
"new_task",
|
||||
"update_todo_list",
|
||||
]
|
||||
|
||||
// Tool groups for better organization
|
||||
const TOOL_GROUPS = {
|
||||
"File Operations": [
|
||||
"read_file",
|
||||
"write_to_file",
|
||||
"search_files",
|
||||
"list_files",
|
||||
"list_code_definition_names",
|
||||
"codebase_search",
|
||||
],
|
||||
"Code Editing": ["apply_diff", "insert_content", "search_and_replace"],
|
||||
System: ["execute_command", "browser_action"],
|
||||
MCP: ["use_mcp_tool", "access_mcp_resource"],
|
||||
Other: ["fetch_instructions"],
|
||||
}
|
||||
|
||||
export const ToolSettings = ({ disabledTools = [], setCachedStateField, ...props }: ToolSettingsProps) => {
|
||||
const { t } = useAppTranslation()
|
||||
|
||||
const handleToolToggle = (toolName: string, enabled: boolean) => {
|
||||
if (enabled) {
|
||||
// Remove from disabled tools
|
||||
setCachedStateField(
|
||||
"disabledTools",
|
||||
disabledTools.filter((tool) => tool !== toolName),
|
||||
)
|
||||
} else {
|
||||
// Add to disabled tools
|
||||
setCachedStateField("disabledTools", [...disabledTools, toolName])
|
||||
}
|
||||
}
|
||||
|
||||
const isToolEnabled = (toolName: string) => !disabledTools.includes(toolName)
|
||||
|
||||
const toolGroups = useMemo(() => {
|
||||
return Object.entries(TOOL_GROUPS).map(([groupName, tools]) => ({
|
||||
name: groupName,
|
||||
tools: tools.filter((tool) => !ALWAYS_AVAILABLE_TOOLS.includes(tool)),
|
||||
}))
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div {...props}>
|
||||
<SectionHeader>
|
||||
<div className="flex items-center gap-2">
|
||||
<Wrench className="w-4" />
|
||||
<div>{t("settings:sections.tools")}</div>
|
||||
</div>
|
||||
</SectionHeader>
|
||||
|
||||
<Section>
|
||||
<div className="text-vscode-descriptionForeground text-sm mb-3">{t("settings:tools.description")}</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
{toolGroups.map(({ name, tools }) => (
|
||||
<div key={name}>
|
||||
<h4 className="font-medium mb-2">{name}</h4>
|
||||
<div className="space-y-1 pl-3">
|
||||
{tools.map((tool) => (
|
||||
<VSCodeCheckbox
|
||||
key={tool}
|
||||
checked={isToolEnabled(tool)}
|
||||
onChange={(e: any) => handleToolToggle(tool, e.target.checked)}>
|
||||
<span className="text-sm">{TOOL_DISPLAY_NAMES[tool] || tool}</span>
|
||||
</VSCodeCheckbox>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="text-vscode-descriptionForeground text-xs mt-3">{t("settings:tools.note")}</div>
|
||||
</Section>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -31,7 +31,8 @@
|
|||
"prompts": "Prompts",
|
||||
"experimental": "Experimental",
|
||||
"language": "Language",
|
||||
"about": "About Roo Code"
|
||||
"about": "About Roo Code",
|
||||
"tools": "Tools"
|
||||
},
|
||||
"prompts": {
|
||||
"description": "Configure support prompts that are used for quick actions like enhancing prompts, explaining code, and fixing issues. These prompts help Roo provide better assistance for common development tasks."
|
||||
|
|
@ -718,5 +719,9 @@
|
|||
"useCustomArn": "Use custom ARN..."
|
||||
},
|
||||
"includeMaxOutputTokens": "Include max output tokens",
|
||||
"includeMaxOutputTokensDescription": "Send max output tokens parameter in API requests. Some providers may not support this."
|
||||
"includeMaxOutputTokensDescription": "Send max output tokens parameter in API requests. Some providers may not support this.",
|
||||
"tools": {
|
||||
"description": "Disable specific tools to reduce token usage. Disabled tools won't be included in the system prompt.",
|
||||
"note": "Note: Some tools are always available and cannot be disabled (ask questions, complete tasks, switch modes, create new task, update todo list)."
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue