feat: add query-context smart tool selection

- Add ToolSelectionAnalyzer class for intelligent tool filtering
- Analyze query complexity (simple/moderate/complex)
- Detect tool mentions and group needs
- Score tools based on relevance (0-1 scale)
- Select 6-12 most relevant tools per query
- Add configuration settings for the feature
- Include comprehensive unit tests

Fixes #9117
This commit is contained in:
Roo Code 2025-11-08 08:04:04 +00:00
parent e98f4b9057
commit 7e456cb22d
7 changed files with 765 additions and 2 deletions

View file

@ -182,6 +182,11 @@ const baseProviderSettingsSchema = z.object({
// Model verbosity.
verbosity: verbosityLevelsSchema.optional(),
// Smart tool selection.
smartToolSelectionEnabled: z.boolean().optional(),
smartToolSelectionMinTools: z.number().min(1).max(20).optional(),
smartToolSelectionMaxTools: z.number().min(1).max(20).optional(),
})
// Several of the providers share common model config properties.

View file

@ -62,6 +62,7 @@ async function generatePrompt(
settings?: SystemPromptSettings,
todoList?: TodoItem[],
modelId?: string,
userQuery?: string,
): Promise<string> {
if (!context) {
throw new Error("Extension context is required for generating system prompt")
@ -108,6 +109,7 @@ ${getToolDescriptionsForMode(
settings,
enableMcpServerCreation,
modelId,
userQuery,
)}
${getToolUseGuidelinesSection(codeIndexManager)}
@ -153,6 +155,7 @@ export const SYSTEM_PROMPT = async (
settings?: SystemPromptSettings,
todoList?: TodoItem[],
modelId?: string,
userQuery?: string,
): Promise<string> => {
if (!context) {
throw new Error("Extension context is required for generating system prompt")
@ -225,5 +228,6 @@ ${customInstructions}`
settings,
todoList,
modelId,
userQuery,
)
}

View file

@ -0,0 +1,308 @@
import { describe, it, expect, beforeEach } from "vitest"
import { ToolSelectionAnalyzer, SmartToolSelectionConfig } from "./ToolSelectionAnalyzer"
import type { ModeConfig, ToolName, ToolGroup } from "@roo-code/types"
describe("ToolSelectionAnalyzer", () => {
let analyzer: ToolSelectionAnalyzer
beforeEach(() => {
analyzer = new ToolSelectionAnalyzer()
})
const createModeConfig = (groups: ToolGroup[]): ModeConfig => ({
slug: "test",
name: "Test Mode",
roleDefinition: "Test role",
groups: groups as any, // Groups can be string or tuple format
})
const createAvailableTools = (tools: ToolName[]): Set<ToolName> => new Set(tools)
describe("query analysis", () => {
it("should detect simple queries", () => {
const simpleQueries = [
"what does this function do?",
"explain this code",
"what is the purpose of this file?",
"can you summarize this?",
]
const modeConfig = createModeConfig(["read"])
const availableTools = createAvailableTools([
"read_file",
"list_files",
"search_files",
"list_code_definition_names",
"ask_followup_question",
"attempt_completion",
])
simpleQueries.forEach((query) => {
const selected = analyzer.selectTools(query, modeConfig, availableTools)
expect(selected.length).toBeGreaterThanOrEqual(6)
expect(selected.length).toBeLessThanOrEqual(8)
// Should include essential read tools
expect(selected).toContain("read_file")
expect(selected).toContain("list_files")
})
})
it("should detect complex queries", () => {
const complexQueries = [
"refactor the entire authentication system to use JWT tokens",
"implement a comprehensive logging system across all modules",
"redesign the database schema and migrate all existing data",
"build a complete REST API with authentication and rate limiting",
]
const modeConfig = createModeConfig(["read", "edit"])
const availableTools = createAvailableTools([
"read_file",
"write_to_file",
"apply_diff",
"list_files",
"search_files",
"execute_command",
"ask_followup_question",
"attempt_completion",
])
complexQueries.forEach((query) => {
const selected = analyzer.selectTools(query, modeConfig, availableTools)
expect(selected.length).toBeGreaterThanOrEqual(8)
expect(selected.length).toBeLessThanOrEqual(12)
// Should include both read and edit tools
expect(selected).toContain("read_file")
expect(selected).toContain("write_to_file")
expect(selected).toContain("apply_diff")
})
})
})
describe("tool-specific queries", () => {
it("should prioritize mentioned tools", () => {
const query = "run npm test and show me the results"
const modeConfig = createModeConfig(["read", "command"])
const availableTools = createAvailableTools([
"read_file",
"list_files",
"execute_command",
"ask_followup_question",
"attempt_completion",
])
const selected = analyzer.selectTools(query, modeConfig, availableTools)
// execute_command should be included and highly ranked (top 5) due to explicit mention
expect(selected).toContain("execute_command")
const executeIndex = selected.indexOf("execute_command")
expect(executeIndex).toBeGreaterThanOrEqual(0)
expect(executeIndex).toBeLessThan(5) // Within top 5 is still highly ranked
})
it("should detect file operations", () => {
const query = "create a new config file with the settings I provided"
const modeConfig = createModeConfig(["read", "edit"])
const availableTools = createAvailableTools([
"read_file",
"write_to_file",
"apply_diff",
"list_files",
"search_files",
"ask_followup_question",
"attempt_completion",
])
const selected = analyzer.selectTools(query, modeConfig, availableTools)
// write_to_file should be highly ranked
expect(selected.slice(0, 3)).toContain("write_to_file")
})
it("should detect search operations", () => {
const query = "find all places where the API key is used"
const modeConfig = createModeConfig(["read"])
const availableTools = createAvailableTools([
"read_file",
"list_files",
"search_files",
"list_code_definition_names",
"ask_followup_question",
"attempt_completion",
])
const selected = analyzer.selectTools(query, modeConfig, availableTools)
// search_files should be included and highly ranked (top 5) due to explicit search intent
expect(selected).toContain("search_files")
const searchIndex = selected.indexOf("search_files")
expect(searchIndex).toBeGreaterThanOrEqual(0)
expect(searchIndex).toBeLessThan(5) // Within top 5 is still highly ranked
})
})
describe("settings configuration", () => {
it("should respect minimum tools setting", () => {
const query = "simple task"
const modeConfig = createModeConfig(["read"])
const availableTools = createAvailableTools([
"read_file",
"list_files",
"ask_followup_question",
"attempt_completion",
])
const customAnalyzer = new ToolSelectionAnalyzer({
enabled: true,
minTools: 3,
maxTools: 12,
})
const selected = customAnalyzer.selectTools(query, modeConfig, availableTools)
expect(selected.length).toBeGreaterThanOrEqual(3)
})
it("should respect maximum tools setting", () => {
const query = "complex refactoring task involving multiple systems"
const modeConfig = createModeConfig(["read", "edit", "command"])
const availableTools = createAvailableTools([
"read_file",
"write_to_file",
"apply_diff",
"insert_content",
"list_files",
"search_files",
"list_code_definition_names",
"execute_command",
"ask_followup_question",
"attempt_completion",
"switch_mode",
"new_task",
"update_todo_list",
])
const customAnalyzer = new ToolSelectionAnalyzer({
enabled: true,
minTools: 6,
maxTools: 8,
})
const selected = customAnalyzer.selectTools(query, modeConfig, availableTools)
expect(selected.length).toBeLessThanOrEqual(8)
})
it("should return all tools when smart selection is disabled", () => {
const query = "some task"
const modeConfig = createModeConfig(["read"])
const availableTools = createAvailableTools([
"read_file",
"list_files",
"search_files",
"ask_followup_question",
"attempt_completion",
])
const disabledAnalyzer = new ToolSelectionAnalyzer({
enabled: false,
})
const selected = disabledAnalyzer.selectTools(query, modeConfig, availableTools)
expect(selected.length).toBe(availableTools.size)
expect(selected.sort()).toEqual(Array.from(availableTools).sort())
})
})
describe("essential tools", () => {
it("should always include ask_followup_question and attempt_completion", () => {
const queries = ["simple query", "complex refactoring", "create a file", "run tests"]
const modeConfig = createModeConfig(["read", "edit"])
const availableTools = createAvailableTools([
"read_file",
"write_to_file",
"list_files",
"ask_followup_question",
"attempt_completion",
])
queries.forEach((query) => {
const selected = analyzer.selectTools(query, modeConfig, availableTools)
expect(selected).toContain("ask_followup_question")
expect(selected).toContain("attempt_completion")
})
})
})
describe("empty or invalid inputs", () => {
it("should handle empty query gracefully", () => {
const query = ""
const modeConfig = createModeConfig(["read"])
const availableTools = createAvailableTools([
"read_file",
"list_files",
"ask_followup_question",
"attempt_completion",
])
const selected = analyzer.selectTools(query, modeConfig, availableTools)
expect(selected.length).toBeGreaterThan(0)
expect(selected).toContain("ask_followup_question")
expect(selected).toContain("attempt_completion")
})
it("should handle empty available tools", () => {
const query = "do something"
const modeConfig = createModeConfig(["read"])
const availableTools = createAvailableTools([])
const selected = analyzer.selectTools(query, modeConfig, availableTools)
expect(selected).toEqual([])
})
})
describe("tool scoring", () => {
it("should score tools based on query relevance", () => {
const query = "write a test file for the authentication module"
const modeConfig = createModeConfig(["read", "edit"])
const availableTools = createAvailableTools([
"read_file",
"write_to_file",
"apply_diff",
"list_files",
"search_files",
"execute_command",
"ask_followup_question",
"attempt_completion",
])
const selected = analyzer.selectTools(query, modeConfig, availableTools)
// write_to_file should be highly ranked for "write a test file"
const writeIndex = selected.indexOf("write_to_file")
expect(writeIndex).toBeGreaterThanOrEqual(0)
expect(writeIndex).toBeLessThan(4) // Should be in top 4 tools
// read_file should also be included for context
expect(selected).toContain("read_file")
})
it("should handle multiple tool mentions in query", () => {
const query = "read the config file, update it, and run the build command"
const modeConfig = createModeConfig(["read", "edit", "command"])
const availableTools = createAvailableTools([
"read_file",
"write_to_file",
"apply_diff",
"execute_command",
"list_files",
"search_files",
"ask_followup_question",
"attempt_completion",
])
const selected = analyzer.selectTools(query, modeConfig, availableTools)
// Should include all mentioned operations
expect(selected).toContain("read_file")
expect(selected).toContain("apply_diff") // for "update"
expect(selected).toContain("execute_command") // for "run"
})
})
})

View file

@ -0,0 +1,394 @@
import type { ToolName, ToolGroup, ModeConfig } from "@roo-code/types"
import { TOOL_GROUPS, ALWAYS_AVAILABLE_TOOLS } from "../../../shared/tools"
import { getGroupName } from "../../../shared/modes"
/**
* Configuration for smart tool selection
*/
export interface SmartToolSelectionConfig {
enabled?: boolean
minTools?: number
maxTools?: number
defaultComplexityThreshold?: number
}
/**
* Result of query analysis
*/
interface QueryAnalysis {
complexity: "simple" | "moderate" | "complex"
mentionedTools: Set<ToolName>
mentionedGroups: Set<ToolGroup>
isReadOnly: boolean
needsEditing: boolean
needsCommandExecution: boolean
needsBrowser: boolean
needsMcp: boolean
confidence: number
}
/**
* Tool relevance score
*/
interface ToolScore {
tool: ToolName
score: number
reason: string
}
/**
* Patterns for detecting tool mentions in queries
*/
const TOOL_MENTION_PATTERNS: Record<string, { groups: ToolGroup[]; tools?: ToolName[]; keywords: RegExp }> = {
mcp: {
groups: ["mcp"],
keywords: /\b(mcp|server|github\s+mcp|database\s+mcp|use\s+mcp)\b/i,
},
browser: {
groups: ["browser"],
keywords:
/\b(browser|website|web\s+page|localhost|chrome|firefox|test\s+in\s+browser|check\s+the\s+(website|browser))\b/i,
},
command: {
groups: ["command"],
keywords: /\b(run|execute|npm|yarn|pnpm|test|install|dependencies|cli|command|terminal|shell)\b/i,
},
edit: {
groups: ["edit"],
keywords: /\b(fix|refactor|modify|change|update|write|create|add|remove|delete|implement|code)\b/i,
},
read: {
groups: ["read"],
keywords: /\b(explain|what\s+does|understand|analyze|show|describe|look\s+at|read|view|check)\b/i,
},
}
/**
* Complexity indicators in queries
*/
const COMPLEXITY_INDICATORS = {
simple: [
/^(what|how|why|when|where|who)\s+/i,
/\b(explain|describe|show|tell\s+me)\b/i,
/\b(typo|spelling|rename)\b/i,
/\b(single|one|this)\s+\w+/i,
],
complex: [
/\b(entire|whole|all|complete|full|system|architecture|refactor)\b/i,
/\b(multiple|several|many|various)\b/i,
/\b(and|also|then|after|before|while)\b.*\b(and|also|then|after|before|while)\b/i, // Multiple conjunctions
/\b(implement|create|build|design|develop)\s+\w+\s+(system|module|feature)/i,
],
}
/**
* Analyzer for smart tool selection based on query context
*/
export class ToolSelectionAnalyzer {
private config: SmartToolSelectionConfig
private recentMessages: string[] = []
private maxMessageHistory = 5
constructor(config: SmartToolSelectionConfig = {}) {
this.config = {
enabled: config.enabled ?? true,
minTools: config.minTools ?? 6,
maxTools: config.maxTools ?? 12,
defaultComplexityThreshold: config.defaultComplexityThreshold ?? 0.7,
}
}
/**
* Add a message to the conversation history
*/
public addMessage(message: string): void {
this.recentMessages.push(message)
if (this.recentMessages.length > this.maxMessageHistory) {
this.recentMessages.shift()
}
}
/**
* Clear the conversation history
*/
public clearHistory(): void {
this.recentMessages = []
}
/**
* Analyze a query to determine its characteristics
*/
private analyzeQuery(query: string): QueryAnalysis {
const lowerQuery = query.toLowerCase()
const analysis: QueryAnalysis = {
complexity: "moderate",
mentionedTools: new Set(),
mentionedGroups: new Set(),
isReadOnly: false,
needsEditing: false,
needsCommandExecution: false,
needsBrowser: false,
needsMcp: false,
confidence: 0.5,
}
// Check for explicit tool/group mentions
for (const [key, pattern] of Object.entries(TOOL_MENTION_PATTERNS)) {
if (pattern.keywords.test(query)) {
pattern.groups.forEach((group) => analysis.mentionedGroups.add(group))
if (pattern.tools) {
pattern.tools.forEach((tool) => analysis.mentionedTools.add(tool))
}
// Set specific needs based on mentions
switch (key) {
case "mcp":
analysis.needsMcp = true
break
case "browser":
analysis.needsBrowser = true
break
case "command":
analysis.needsCommandExecution = true
break
case "edit":
analysis.needsEditing = true
break
case "read":
analysis.isReadOnly = !analysis.needsEditing // Only read-only if not also editing
break
}
}
}
// Determine complexity
const simpleCount = COMPLEXITY_INDICATORS.simple.filter((pattern) => pattern.test(query)).length
const complexCount = COMPLEXITY_INDICATORS.complex.filter((pattern) => pattern.test(query)).length
if (complexCount > 1 || query.length > 500) {
analysis.complexity = "complex"
analysis.confidence = Math.min(0.9, 0.6 + complexCount * 0.1)
} else if (simpleCount > 1 && complexCount === 0 && query.length < 100) {
analysis.complexity = "simple"
analysis.confidence = Math.min(0.9, 0.6 + simpleCount * 0.1)
} else {
analysis.complexity = "moderate"
analysis.confidence = 0.7
}
// If no editing keywords found but query seems to be about making changes
if (!analysis.needsEditing && /\b(fix|update|change|modify|add|remove)\b/i.test(query)) {
analysis.needsEditing = true
analysis.isReadOnly = false
}
// Adjust based on conversation history
if (this.recentMessages.length > 0) {
const recentContext = this.recentMessages.join(" ").toLowerCase()
if (/\b(debug|error|issue|problem|bug)\b/i.test(recentContext)) {
// In debugging context, likely need read and command tools
analysis.needsCommandExecution = true
analysis.confidence = Math.min(0.95, analysis.confidence + 0.1)
}
if (/\b(implement|create|build|write)\b/i.test(recentContext)) {
// In implementation context, likely need editing tools
analysis.needsEditing = true
analysis.isReadOnly = false
}
}
return analysis
}
/**
* Score tools based on query analysis
*/
private scoreTools(availableTools: Set<ToolName>, analysis: QueryAnalysis, modeConfig: ModeConfig): ToolScore[] {
const scores: ToolScore[] = []
for (const tool of availableTools) {
let score = 0
let reason = ""
// Always include essential tools with high score
if (ALWAYS_AVAILABLE_TOOLS.includes(tool)) {
score = 0.9
reason = "essential tool"
}
// Explicitly mentioned tools get highest score
else if (analysis.mentionedTools.has(tool)) {
score = 1.0
reason = "explicitly mentioned"
}
// Tools in mentioned groups get high score
else {
// Find which group this tool belongs to
let toolGroup: ToolGroup | undefined
for (const [groupName, groupConfig] of Object.entries(TOOL_GROUPS)) {
if (groupConfig.tools.includes(tool)) {
toolGroup = groupName as ToolGroup
break
}
}
if (toolGroup && analysis.mentionedGroups.has(toolGroup)) {
score = 0.85
reason = `part of mentioned ${toolGroup} group`
} else {
// Score based on query characteristics
switch (tool) {
case "read_file":
case "list_files":
case "search_files":
case "list_code_definition_names":
score = analysis.isReadOnly ? 0.8 : 0.6
reason = analysis.isReadOnly ? "read-only query" : "may need to read files"
break
case "write_to_file":
case "apply_diff":
case "insert_content":
score = analysis.needsEditing ? 0.8 : analysis.isReadOnly ? 0.1 : 0.3
reason = analysis.needsEditing ? "editing needed" : "editing tool"
break
case "execute_command":
score = analysis.needsCommandExecution ? 0.85 : 0.2
reason = analysis.needsCommandExecution ? "command execution needed" : "command tool"
break
case "browser_action":
score = analysis.needsBrowser ? 0.9 : 0.1
reason = analysis.needsBrowser ? "browser interaction needed" : "browser tool"
break
case "use_mcp_tool":
case "access_mcp_resource":
score = analysis.needsMcp ? 0.9 : 0.1
reason = analysis.needsMcp ? "MCP needed" : "MCP tool"
break
case "codebase_search":
score = analysis.complexity === "complex" ? 0.7 : 0.4
reason = "codebase search"
break
case "fetch_instructions":
score = 0.3 // Lower priority unless specifically needed
reason = "instruction fetcher"
break
default:
score = 0.5
reason = "general tool"
}
}
}
// Adjust score based on complexity
if (score > 0.1 && score < 0.9) {
if (analysis.complexity === "simple") {
score *= 0.8 // Reduce score for non-essential tools in simple queries
} else if (analysis.complexity === "complex") {
score *= 1.1 // Boost score for complex queries
}
score = Math.min(1.0, score)
}
scores.push({ tool, score, reason })
}
return scores
}
/**
* Select tools based on query context
*/
public selectTools(
query: string,
modeConfig: ModeConfig,
availableTools: Set<ToolName>,
customModes?: ModeConfig[],
): ToolName[] {
// If feature is disabled, return all available tools
if (!this.config.enabled) {
return Array.from(availableTools)
}
// Add query to history
this.addMessage(query)
// Analyze the query
const analysis = this.analyzeQuery(query)
// Score all available tools
const scores = this.scoreTools(availableTools, analysis, modeConfig)
// Sort by score (descending)
scores.sort((a, b) => b.score - a.score)
// Determine how many tools to include
let targetCount = this.config.minTools!
if (analysis.complexity === "simple") {
targetCount = this.config.minTools!
} else if (analysis.complexity === "moderate") {
targetCount = Math.floor((this.config.minTools! + this.config.maxTools!) / 2)
} else {
targetCount = this.config.maxTools!
}
// Always include tools with score >= threshold
const threshold = this.config.defaultComplexityThreshold!
const selectedTools = new Set<ToolName>()
const highScoreTools = scores.filter((s) => s.score >= threshold)
for (const { tool } of highScoreTools) {
selectedTools.add(tool)
}
// If we have fewer tools than minimum, add more based on score
let i = highScoreTools.length
while (selectedTools.size < targetCount && i < scores.length) {
selectedTools.add(scores[i].tool)
i++
}
// Ensure we always have essential tools
for (const tool of ALWAYS_AVAILABLE_TOOLS) {
if (availableTools.has(tool)) {
selectedTools.add(tool)
}
}
// Log selection for debugging (in development)
if (process.env.NODE_ENV === "development") {
console.log("Smart Tool Selection:", {
query: query.substring(0, 100),
analysis,
selectedCount: selectedTools.size,
totalAvailable: availableTools.size,
topScores: scores
.slice(0, 10)
.map((s) => ({ tool: s.tool, score: s.score.toFixed(2), reason: s.reason })),
})
}
return Array.from(selectedTools)
}
}
// Singleton instance
let analyzerInstance: ToolSelectionAnalyzer | undefined
/**
* Get or create the singleton ToolSelectionAnalyzer instance
*/
export function getToolSelectionAnalyzer(config?: SmartToolSelectionConfig): ToolSelectionAnalyzer {
if (!analyzerInstance) {
analyzerInstance = new ToolSelectionAnalyzer(config)
} else if (config) {
// Update config if provided
analyzerInstance = new ToolSelectionAnalyzer(config)
}
return analyzerInstance
}

View file

@ -5,6 +5,7 @@ import { McpHub } from "../../../services/mcp/McpHub"
import { Mode, getModeConfig, isToolAllowedForMode, getGroupName } from "../../../shared/modes"
import { ToolArgs } from "./types"
import { getToolSelectionAnalyzer, type SmartToolSelectionConfig } from "./ToolSelectionAnalyzer"
import { getExecuteCommandDescription } from "./execute-command"
import { getReadFileDescription } from "./read-file"
import { getSimpleReadFileDescription } from "./simple-read-file"
@ -74,6 +75,7 @@ export function getToolDescriptionsForMode(
settings?: Record<string, any>,
enableMcpServerCreation?: boolean,
modelId?: string,
userQuery?: string,
): string {
const config = getModeConfig(mode, customModes)
const args: ToolArgs = {
@ -141,8 +143,24 @@ export function getToolDescriptionsForMode(
tools.delete("run_slash_command")
}
// Map tool descriptions for allowed tools
const descriptions = Array.from(tools).map((toolName) => {
// Apply smart tool selection if enabled and query is provided
let selectedTools = Array.from(tools)
if (userQuery && settings?.smartToolSelection !== false) {
const smartSelectionConfig: SmartToolSelectionConfig = {
enabled: settings?.smartToolSelection?.enabled ?? true,
minTools: settings?.smartToolSelection?.minTools ?? 6,
maxTools: settings?.smartToolSelection?.maxTools ?? 12,
defaultComplexityThreshold: settings?.smartToolSelection?.threshold ?? 0.7,
}
const analyzer = getToolSelectionAnalyzer(smartSelectionConfig)
const modeConfig = getModeConfig(mode, customModes)
selectedTools = analyzer.selectTools(userQuery, modeConfig, tools as Set<ToolName>, customModes)
}
// Map tool descriptions for selected tools
const descriptions = selectedTools.map((toolName) => {
const descriptionFn = toolDescriptionMap[toolName]
if (!descriptionFn) {
return undefined

View file

@ -6,4 +6,8 @@ export interface SystemPromptSettings {
todoListEnabled: boolean
useAgentRules: boolean
newTaskRequireTodos: boolean
// Smart tool selection settings
smartToolSelectionEnabled?: boolean
smartToolSelectionMinTools?: number
smartToolSelectionMaxTools?: number
}

View file

@ -2553,6 +2553,31 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
apiConfiguration,
} = state ?? {}
// Extract the most recent user query from the conversation history
let userQuery: string | undefined
if (this.apiConversationHistory.length > 0) {
// Find the last user message in the conversation
const lastUserMessage = [...this.apiConversationHistory].reverse().find((msg) => msg.role === "user")
if (lastUserMessage && Array.isArray(lastUserMessage.content)) {
// Extract text content from the user message
const textContents = lastUserMessage.content
.filter((block) => block.type === "text")
.map((block) => (block as any).text || "")
// Combine all text content to form the query
if (textContents.length > 0) {
userQuery = textContents.join(" ").trim()
// Remove task tags if present
userQuery = userQuery.replace(/<\/?task>/g, "").trim()
// Limit length to prevent overly long queries
if (userQuery.length > 500) {
userQuery = userQuery.substring(0, 500) + "..."
}
}
}
}
return await (async () => {
const provider = this.providerRef.deref()
@ -2595,9 +2620,14 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
newTaskRequireTodos: vscode.workspace
.getConfiguration("roo-cline")
.get<boolean>("newTaskRequireTodos", false),
// Smart tool selection configuration
smartToolSelectionEnabled: apiConfiguration?.smartToolSelectionEnabled ?? true,
smartToolSelectionMinTools: apiConfiguration?.smartToolSelectionMinTools ?? 6,
smartToolSelectionMaxTools: apiConfiguration?.smartToolSelectionMaxTools ?? 12,
},
undefined, // todoList
this.api.getModel().id,
userQuery, // Pass the extracted user query for smart tool selection
)
})()
}