Skip to content
Merged
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
7 changes: 4 additions & 3 deletions src/core/task/tools/handlers/DiagnosticsScanToolHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { telemetryService } from "@/services/telemetry"
import { ToolResponse } from "../../index"
import { IFullyManagedTool } from "../ToolExecutorCoordinator"
import { ToolValidator } from "../ToolValidator"
import { coerceToStringArray } from "../utils/coerceArray"
import { TaskConfig } from "../types/TaskConfig"
import { StronglyTypedUIHelpers } from "../types/UIHelpers"

Expand All @@ -23,13 +24,13 @@ export class DiagnosticsScanToolHandler implements IFullyManagedTool {
constructor(private validator: ToolValidator) {}

getDescription(block: ToolUse): string {
const relPaths = Array.isArray(block.params.paths) ? block.params.paths : (block.params.paths ? [block.params.paths as string] : [])
const relPaths = coerceToStringArray(block.params.paths)
const pathsText = relPaths.length > 0 ? ` for ${relPaths.map((p) => `'${p}'`).join(", ")}` : ""
return `[${block.name}${pathsText}]`
}

async handlePartialBlock(block: ToolUse, uiHelpers: StronglyTypedUIHelpers): Promise<void> {
const relPaths = Array.isArray(block.params.paths) ? block.params.paths : (block.params.paths ? [block.params.paths as string] : [])
const relPaths = coerceToStringArray(block.params.paths)
const config = uiHelpers.getConfig()

const message = JSON.stringify({
Expand All @@ -55,7 +56,7 @@ export class DiagnosticsScanToolHandler implements IFullyManagedTool {
return await config.callbacks.sayAndCreateMissingParamError(this.name, "paths")
}

const relPaths = Array.isArray(block.params.paths) ? block.params.paths : (block.params.paths ? [block.params.paths as string] : [])
const relPaths = coerceToStringArray(block.params.paths)
if (relPaths.length === 0) {
config.taskState.consecutiveMistakeCount++
return await config.callbacks.sayAndCreateMissingParamError(this.name, "paths")
Expand Down
37 changes: 14 additions & 23 deletions src/core/task/tools/handlers/ExecuteCommandToolHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import type { IFullyManagedTool } from "../ToolExecutorCoordinator"
import type { ToolValidator } from "../ToolValidator"
import type { TaskConfig } from "../types/TaskConfig"
import type { StronglyTypedUIHelpers } from "../types/UIHelpers"
import { coerceToStringArray } from "../utils/coerceArray"
import { isSafeCommand } from "../utils/CommandSafetyChecker"
import { applyModelContentFixes } from "../utils/ModelContentProcessor"
import { ToolResultUtils } from "../utils/ToolResultUtils"
Expand Down Expand Up @@ -73,11 +74,7 @@ export class ExecuteCommandToolHandler implements IFullyManagedTool {
constructor(private validator: ToolValidator) {}

getDescription(block: ToolUse): string {
const commands = Array.isArray(block.params.commands)
? block.params.commands
: block.params.commands
? [block.params.commands as string]
: []
const commands = coerceToStringArray(block.params.commands)
const script = block.params.script as string | undefined
const language = block.params.language as string | undefined

Expand All @@ -99,23 +96,17 @@ export class ExecuteCommandToolHandler implements IFullyManagedTool {
return
}

const rawCommands = (block.params.commands as any) || []
const rawCommands = coerceToStringArray(block.params.commands)
const script = block.params.script as string | undefined
const language = (block.params.language as string | undefined) || "bash"

const commandsToProcess: { command: string; displayName?: string }[] = []
if (Array.isArray(rawCommands)) {
rawCommands.forEach((cmd: string) => {
if (cmd) {
commandsToProcess.push({
command: uiHelpers.removeClosingTag(block, "commands", cmd),
})
}
})
} else if (typeof rawCommands === "string" && rawCommands.trim() !== "") {
commandsToProcess.push({
command: uiHelpers.removeClosingTag(block, "commands", rawCommands),
})
for (const cmd of rawCommands) {
if (cmd) {
commandsToProcess.push({
command: uiHelpers.removeClosingTag(block, "commands", cmd),
})
}
}

if (script) {
Expand Down Expand Up @@ -158,7 +149,7 @@ export class ExecuteCommandToolHandler implements IFullyManagedTool {
}

async execute(config: TaskConfig, block: ToolUse): Promise<ToolResponse> {
const rawCommands = (block.params.commands as any) || []
const rawCommands = coerceToStringArray(block.params.commands)
const script = block.params.script as string | undefined
const language = (block.params.language as string | undefined) || "bash"

Expand Down Expand Up @@ -187,10 +178,10 @@ export class ExecuteCommandToolHandler implements IFullyManagedTool {
// Normalize to a list of commands
const commandsToProcess: { command: string; displayName?: string }[] = []

if (Array.isArray(rawCommands) && rawCommands.length > 0) {
rawCommands.forEach((cmd: string) => commandsToProcess.push({ command: cmd }))
} else if (typeof rawCommands === "string" && rawCommands.trim() !== "") {
commandsToProcess.push({ command: rawCommands })
for (const cmd of rawCommands) {
if (cmd) {
commandsToProcess.push({ command: cmd })
}
}

if (script) {
Expand Down
13 changes: 7 additions & 6 deletions src/core/task/tools/handlers/FindSymbolReferencesToolHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,23 @@ import type { ToolValidator } from "../ToolValidator"
import type { TaskConfig } from "../types/TaskConfig"
import type { StronglyTypedUIHelpers } from "../types/UIHelpers"
import { ToolResultUtils } from "../utils/ToolResultUtils"
import { coerceFirstStringArray } from "../utils/coerceArray"

export class FindSymbolReferencesToolHandler implements IFullyManagedTool {
readonly name = DiracDefaultTool.FIND_SYMBOL_REFERENCES

constructor(private validator: ToolValidator) {}

getDescription(block: ToolUse): string {
const relPaths = Array.isArray(block.params.paths) ? block.params.paths : (block.params.paths ? [block.params.paths as string] : (block.params.path ? [block.params.path as string] : []))
const symbols = Array.isArray(block.params.symbols) ? block.params.symbols : (block.params.symbols ? [block.params.symbols as string] : (block.params.symbol ? [block.params.symbol as string] : []))
const relPaths = coerceFirstStringArray(block.params.paths, block.params.path)
const symbols = coerceFirstStringArray(block.params.symbols, block.params.symbol)
const findType = (block.params.find_type as string) || "both"
return `[${block.name} for ${symbols.map((s) => `'${s}'`).join(", ")} in ${relPaths.map((p) => `'${p}'`).join(", ")}${findType !== "both" ? ` (type: ${findType})` : ""}]`
}

async handlePartialBlock(block: ToolUse, uiHelpers: StronglyTypedUIHelpers): Promise<void> {
const relPaths = Array.isArray(block.params.paths) ? block.params.paths : (block.params.paths ? [block.params.paths as string] : (block.params.path ? [block.params.path as string] : []))
const symbols = Array.isArray(block.params.symbols) ? block.params.symbols : (block.params.symbols ? [block.params.symbols as string] : (block.params.symbol ? [block.params.symbol as string] : []))
const relPaths = coerceFirstStringArray(block.params.paths, block.params.path)
const symbols = coerceFirstStringArray(block.params.symbols, block.params.symbol)

const config = uiHelpers.getConfig()
if (config.isSubagentExecution) {
Expand Down Expand Up @@ -60,8 +61,8 @@ export class FindSymbolReferencesToolHandler implements IFullyManagedTool {
}

async execute(config: TaskConfig, block: ToolUse): Promise<ToolResponse> {
const relPaths = Array.isArray(block.params.paths) ? block.params.paths : (block.params.paths ? [block.params.paths as string] : (block.params.path ? [block.params.path as string] : []))
const symbols = Array.isArray(block.params.symbols) ? block.params.symbols : (block.params.symbols ? [block.params.symbols as string] : (block.params.symbol ? [block.params.symbol as string] : []))
const relPaths = coerceFirstStringArray(block.params.paths, block.params.path)
const symbols = coerceFirstStringArray(block.params.symbols, block.params.symbol)
const findType = (block.params.find_type as "definition" | "reference" | "both") || "both"

const apiConfig = config.services.stateManager.getApiConfiguration()
Expand Down
7 changes: 4 additions & 3 deletions src/core/task/tools/handlers/GetFileSkeletonToolHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,20 @@ import type { ToolValidator } from "../ToolValidator"
import type { TaskConfig } from "../types/TaskConfig"
import type { StronglyTypedUIHelpers } from "../types/UIHelpers"
import { ToolResultUtils } from "../utils/ToolResultUtils"
import { coerceFirstStringArray } from "../utils/coerceArray"

export class GetFileSkeletonToolHandler implements IFullyManagedTool {
readonly name = DiracDefaultTool.GET_FILE_SKELETON

constructor(private validator: ToolValidator) {}

getDescription(block: ToolUse): string {
const relPaths = Array.isArray(block.params.paths) ? block.params.paths : (block.params.paths ? [block.params.paths as string] : (block.params.path ? [block.params.path as string] : []))
const relPaths = coerceFirstStringArray(block.params.paths, block.params.path)
return `[${block.name} for ${relPaths.map((p) => `'${p}'`).join(", ")}]`
}

async handlePartialBlock(block: ToolUse, uiHelpers: StronglyTypedUIHelpers): Promise<void> {
const relPaths = Array.isArray(block.params.paths) ? block.params.paths : (block.params.paths ? [block.params.paths as string] : (block.params.path ? [block.params.path as string] : []))
const relPaths = coerceFirstStringArray(block.params.paths, block.params.path)
const config = uiHelpers.getConfig()
if (config.isSubagentExecution) {
return
Expand All @@ -50,7 +51,7 @@ export class GetFileSkeletonToolHandler implements IFullyManagedTool {
}

async execute(config: TaskConfig, block: ToolUse): Promise<ToolResponse> {
const relPaths = Array.isArray(block.params.paths) ? block.params.paths : (block.params.paths ? [block.params.paths as string] : (block.params.path ? [block.params.path as string] : []))
const relPaths = coerceFirstStringArray(block.params.paths, block.params.path)
const apiConfig = config.services.stateManager.getApiConfiguration()
const currentMode = config.services.stateManager.getGlobalSettingsKey("mode")
const provider = (currentMode === "plan" ? apiConfig.planModeApiProvider : apiConfig.actModeApiProvider) as string
Expand Down
13 changes: 7 additions & 6 deletions src/core/task/tools/handlers/GetFunctionToolHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,21 @@ import type { ToolValidator } from "../ToolValidator"
import type { TaskConfig } from "../types/TaskConfig"
import type { StronglyTypedUIHelpers } from "../types/UIHelpers"
import { ToolResultUtils } from "../utils/ToolResultUtils"
import { coerceToStringArray, coerceFirstStringArray } from "../utils/coerceArray"

export class GetFunctionToolHandler implements IFullyManagedTool {
readonly name = DiracDefaultTool.GET_FUNCTION

constructor(private validator: ToolValidator) {}

getDescription(block: ToolUse): string {
const functionNames = Array.isArray(block.params.function_names) ? block.params.function_names : (block.params.function_names ? [block.params.function_names as string] : [])
const relPaths = Array.isArray(block.params.paths) ? block.params.paths : (block.params.paths ? [block.params.paths as string] : (block.params.path ? [block.params.path as string] : []))
const functionNames = coerceToStringArray(block.params.function_names)
const relPaths = coerceFirstStringArray(block.params.paths, block.params.path)
return `[${block.name} for '${functionNames.join(", ")}' in ${relPaths.map((p) => `'${p}'`).join(", ")}]`
}
async handlePartialBlock(block: ToolUse, uiHelpers: StronglyTypedUIHelpers): Promise<void> {
const relPaths = Array.isArray(block.params.paths) ? block.params.paths : (block.params.paths ? [block.params.paths as string] : (block.params.path ? [block.params.path as string] : []))
const functionNames = Array.isArray(block.params.function_names) ? block.params.function_names : (block.params.function_names ? [block.params.function_names as string] : [])
const relPaths = coerceFirstStringArray(block.params.paths, block.params.path)
const functionNames = coerceToStringArray(block.params.function_names)

const config = uiHelpers.getConfig()
if (config.isSubagentExecution) {
Expand Down Expand Up @@ -119,8 +120,8 @@ export class GetFunctionToolHandler implements IFullyManagedTool {


async execute(config: TaskConfig, block: ToolUse): Promise<ToolResponse> {
const relPaths = Array.isArray(block.params.paths) ? block.params.paths : (block.params.paths ? [block.params.paths as string] : (block.params.path ? [block.params.path as string] : []))
const functionNames = Array.isArray(block.params.function_names) ? block.params.function_names : (block.params.function_names ? [block.params.function_names as string] : [])
const relPaths = coerceFirstStringArray(block.params.paths, block.params.path)
const functionNames = coerceToStringArray(block.params.function_names)

const apiConfig = config.services.stateManager.getApiConfiguration()
const currentMode = config.services.stateManager.getGlobalSettingsKey("mode")
Expand Down
19 changes: 4 additions & 15 deletions src/core/task/tools/handlers/ListFilesToolHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import type { IFullyManagedTool } from "../ToolExecutorCoordinator"
import type { ToolValidator } from "../ToolValidator"
import type { TaskConfig } from "../types/TaskConfig"
import type { StronglyTypedUIHelpers } from "../types/UIHelpers"
import { coerceToStringArray } from "../utils/coerceArray"
import { ToolResultUtils } from "../utils/ToolResultUtils"

// Sprint 2 — task E: async-by-default list_files when recursive=true.
Expand All @@ -39,20 +40,12 @@ export class ListFilesToolHandler implements IFullyManagedTool {
constructor(private validator: ToolValidator) {}

getDescription(block: ToolUse): string {
const relPaths = Array.isArray(block.params.paths)
? block.params.paths
: block.params.paths
? [block.params.paths as string]
: []
const relPaths = coerceToStringArray(block.params.paths)
return `[${block.name} for ${relPaths.map((p) => `'${p}'`).join(", ")}]`
}

async handlePartialBlock(block: ToolUse, uiHelpers: StronglyTypedUIHelpers): Promise<void> {
const relPaths = Array.isArray(block.params.paths)
? block.params.paths
: block.params.paths
? [block.params.paths as string]
: []
const relPaths = coerceToStringArray(block.params.paths)

// Get config access for services
const config = uiHelpers.getConfig()
Expand Down Expand Up @@ -177,11 +170,7 @@ export class ListFilesToolHandler implements IFullyManagedTool {
}

async execute(config: TaskConfig, block: ToolUse): Promise<ToolResponse> {
const relPaths = Array.isArray(block.params.paths)
? block.params.paths
: block.params.paths
? [block.params.paths as string]
: []
const relPaths = coerceToStringArray(block.params.paths)
const recursiveRaw = block.params.recursive
const recursive = String(recursiveRaw ?? "").toLowerCase() === "true"

Expand Down
11 changes: 4 additions & 7 deletions src/core/task/tools/handlers/ReadFileToolHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type { IFullyManagedTool } from "../ToolExecutorCoordinator"
import type { ToolValidator } from "../ToolValidator"
import type { TaskConfig } from "../types/TaskConfig"
import type { StronglyTypedUIHelpers } from "../types/UIHelpers"
import { coerceToStringArray } from "../utils/coerceArray"
import { extractLastKnownHashFromHistory } from "../utils/extractLastKnownHash"
import { ToolResultUtils } from "../utils/ToolResultUtils"
import { sliceContentLines } from "./readFilePagination"
Expand Down Expand Up @@ -43,7 +44,7 @@ export class ReadFileToolHandler implements IFullyManagedTool {
constructor(private validator: ToolValidator) {}

getDescription(block: ToolUse): string {
const relPaths = Array.isArray(block.params.paths) ? block.params.paths : (block.params.paths ? [block.params.paths as string] : [])
const relPaths = coerceToStringArray(block.params.paths)
const range =
block.params.start_line || block.params.end_line
? ` lines ${block.params.start_line || 1}-${block.params.end_line || "?"}`
Expand All @@ -52,7 +53,7 @@ export class ReadFileToolHandler implements IFullyManagedTool {
}

async handlePartialBlock(block: ToolUse, uiHelpers: StronglyTypedUIHelpers): Promise<void> {
const relPaths = Array.isArray(block.params.paths) ? block.params.paths : (block.params.paths ? [block.params.paths as string] : [])
const relPaths = coerceToStringArray(block.params.paths)
const config = uiHelpers.getConfig()
if (config.isSubagentExecution) {
return
Expand Down Expand Up @@ -90,11 +91,7 @@ export class ReadFileToolHandler implements IFullyManagedTool {
}

async execute(config: TaskConfig, block: ToolUse): Promise<ToolResponse> {
const relPaths = Array.isArray(block.params.paths)
? block.params.paths
: block.params.paths
? [block.params.paths as string]
: []
const relPaths = coerceToStringArray(block.params.paths)
const startLineNum = block.params.start_line ? Number.parseInt(String(block.params.start_line)) : undefined
const endLineNum = block.params.end_line ? Number.parseInt(String(block.params.end_line)) : undefined
const rawOffset = (block.params as any).offset
Expand Down
19 changes: 4 additions & 15 deletions src/core/task/tools/handlers/RenameSymbolToolHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import type { ToolValidator } from "../ToolValidator"
import type { TaskConfig } from "../types/TaskConfig"
import type { StronglyTypedUIHelpers } from "../types/UIHelpers"
import { ToolResultUtils } from "../utils/ToolResultUtils"
import { coerceToStringArray } from "../utils/coerceArray"

export class RenameSymbolToolHandler implements IFullyManagedTool {
readonly name = DiracDefaultTool.RENAME_SYMBOL
Expand All @@ -35,11 +36,7 @@ export class RenameSymbolToolHandler implements IFullyManagedTool {
getDescription(block: ToolUse): string {
const existingSymbol = block.params.existing_symbol as string
const newSymbol = block.params.new_symbol as string
const paths = Array.isArray(block.params.paths)
? block.params.paths
: block.params.paths
? [block.params.paths as string]
: []
const paths = coerceToStringArray(block.params.paths)
return `[${block.name} for '${existingSymbol}' to '${newSymbol}' in ${paths.map((p) => `'${p}'`).join(", ")}]`
}

Expand All @@ -50,11 +47,7 @@ export class RenameSymbolToolHandler implements IFullyManagedTool {
(block.params.existing_symbol as string) || "",
)
const newSymbol = uiHelpers.removeClosingTag(block, "new_symbol", (block.params.new_symbol as string) || "")
const paths = Array.isArray(block.params.paths)
? block.params.paths
: block.params.paths
? [block.params.paths as string]
: []
const paths = coerceToStringArray(block.params.paths)

const config = uiHelpers.getConfig()
if (config.isSubagentExecution) {
Expand Down Expand Up @@ -83,11 +76,7 @@ export class RenameSymbolToolHandler implements IFullyManagedTool {
async execute(config: TaskConfig, block: ToolUse): Promise<ToolResponse> {
const existingSymbol = block.params.existing_symbol as string
const newSymbol = block.params.new_symbol as string
const relPaths = Array.isArray(block.params.paths)
? block.params.paths
: block.params.paths
? [block.params.paths as string]
: []
const relPaths = coerceToStringArray(block.params.paths)

if (!existingSymbol || !newSymbol || relPaths.length === 0) {
config.taskState.consecutiveMistakeCount++
Expand Down
11 changes: 2 additions & 9 deletions src/core/task/tools/handlers/SearchFilesToolHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import type { ToolValidator } from "../ToolValidator"
import type { TaskConfig } from "../types/TaskConfig"
import type { StronglyTypedUIHelpers } from "../types/UIHelpers"
import { ToolResultUtils } from "../utils/ToolResultUtils"
import { coerceFirstStringArray } from "../utils/coerceArray"

// Sprint 2 — task D: async-by-default search_files. Mirrors S2-C
// (ExecuteCommandToolHandler): if ripgrep finishes within ASYNC_FAST_PATH_MS
Expand All @@ -35,15 +36,7 @@ export class SearchFilesToolHandler implements IFullyManagedTool {

constructor(private validator: ToolValidator) {}
private getRelPaths(params: any): string[] {
return Array.isArray(params.paths)
? params.paths
: params.paths
? [params.paths as string]
: Array.isArray(params.path)
? params.path
: params.path
? [params.path as string]
: []
return coerceFirstStringArray(params.paths, params.path)
}

getDescription(block: ToolUse): string {
Expand Down
Loading
Loading