@@ -4,12 +4,16 @@ import { Anthropic } from "@anthropic-ai/sdk"
44
55import type { ToolName , ClineAsk , ToolProgressStatus } from "@roo-code/types"
66import { TelemetryService } from "@roo-code/telemetry"
7+ import { customToolRegistry } from "@roo-code/core"
8+
9+ import { t } from "../../i18n"
710
811import { defaultModeSlug , getModeBySlug } from "../../shared/modes"
912import type { ToolParamName , ToolResponse , ToolUse , McpToolUse } from "../../shared/tools"
10- import { Package } from "../../shared/package "
11- import { t } from "../../i18n"
13+ import { experiments , EXPERIMENT_IDS } from "../../shared/experiments "
14+
1215import { AskIgnoredError } from "../task/AskIgnoredError"
16+ import { Task } from "../task/Task"
1317
1418import { fetchInstructionsTool } from "../tools/FetchInstructionsTool"
1519import { listFilesTool } from "../tools/ListFilesTool"
@@ -30,17 +34,14 @@ import { askFollowupQuestionTool } from "../tools/AskFollowupQuestionTool"
3034import { switchModeTool } from "../tools/SwitchModeTool"
3135import { attemptCompletionTool , AttemptCompletionCallbacks } from "../tools/AttemptCompletionTool"
3236import { newTaskTool } from "../tools/NewTaskTool"
33-
3437import { updateTodoListTool } from "../tools/UpdateTodoListTool"
3538import { runSlashCommandTool } from "../tools/RunSlashCommandTool"
3639import { generateImageTool } from "../tools/GenerateImageTool"
37-
38- import { formatResponse } from "../prompts/responses"
40+ import { applyDiffTool as applyDiffToolClass } from "../tools/ApplyDiffTool"
3941import { validateToolUse } from "../tools/validateToolUse"
40- import { Task } from "../task/Task"
4142import { codebaseSearchTool } from "../tools/CodebaseSearchTool"
42- import { experiments , EXPERIMENT_IDS } from "../../shared/experiments"
43- import { applyDiffTool as applyDiffToolClass } from "../tools/ApplyDiffTool "
43+
44+ import { formatResponse } from "../prompts/responses "
4445
4546/**
4647 * Processes and presents assistant message content to the user interface.
@@ -353,7 +354,7 @@ export async function presentAssistantMessage(cline: Task) {
353354 case "tool_use" : {
354355 // Fetch state early so it's available for toolDescription and validation
355356 const state = await cline . providerRef . deref ( ) ?. getState ( )
356- const { mode, customModes, experiments : stateExperiments , apiConfiguration } = state ?? { }
357+ const { mode, customModes, experiments : stateExperiments } = state ?? { }
357358
358359 const toolDescription = ( ) : string => {
359360 switch ( block . name ) {
@@ -731,6 +732,8 @@ export async function presentAssistantMessage(cline: Task) {
731732 // This prevents the stream from being interrupted with "Response interrupted by tool use result"
732733 // which would cause the extension to appear to hang
733734 const errorContent = formatResponse . toolError ( error . message , toolProtocol )
735+ console . error ( `[presentAssistantMessage] errorContent: ${ errorContent } ` )
736+
734737 if ( toolProtocol === TOOL_PROTOCOL . NATIVE && toolCallId ) {
735738 // For native protocol, push tool_result directly without setting didAlreadyUseTool
736739 cline . userMessageContent . push ( {
@@ -743,6 +746,7 @@ export async function presentAssistantMessage(cline: Task) {
743746 // For XML protocol, use the standard pushToolResult
744747 pushToolResult ( errorContent )
745748 }
749+
746750 break
747751 }
748752 }
@@ -1043,9 +1047,8 @@ export async function presentAssistantMessage(cline: Task) {
10431047 } )
10441048 break
10451049 default : {
1046- // Handle unknown/invalid tool names
1050+ // Handle unknown/invalid tool names OR custom tools
10471051 // This is critical for native protocol where every tool_use MUST have a tool_result
1048- // Note: This case should rarely be reached since validateToolUse now checks for unknown tools
10491052
10501053 // CRITICAL: Don't process partial blocks for unknown tools - just let them stream in.
10511054 // If we try to show errors for partial blocks, we'd show the error on every streaming chunk,
@@ -1054,6 +1057,45 @@ export async function presentAssistantMessage(cline: Task) {
10541057 break
10551058 }
10561059
1060+ const customTool = customToolRegistry . get ( block . name )
1061+
1062+ if ( customTool ) {
1063+ try {
1064+ console . log ( `executing customTool -> ${ JSON . stringify ( customTool , null , 2 ) } ` )
1065+ let customToolArgs
1066+
1067+ if ( customTool . parameters ) {
1068+ try {
1069+ customToolArgs = customTool . parameters . parse ( block . nativeArgs || block . params || { } )
1070+ console . log ( `customToolArgs -> ${ JSON . stringify ( customToolArgs , null , 2 ) } ` )
1071+ } catch ( parseParamsError ) {
1072+ const message = `Custom tool "${ block . name } " argument validation failed: ${ parseParamsError . message } `
1073+ console . error ( message )
1074+ cline . consecutiveMistakeCount ++
1075+ await cline . say ( "error" , message )
1076+ pushToolResult ( formatResponse . toolError ( message , toolProtocol ) )
1077+ break
1078+ }
1079+ }
1080+
1081+ console . log ( `${ customTool . name } .execute() -> ${ JSON . stringify ( customToolArgs , null , 2 ) } ` )
1082+
1083+ const result = await customTool . execute ( customToolArgs , {
1084+ mode : mode ?? defaultModeSlug ,
1085+ task : cline ,
1086+ } )
1087+
1088+ pushToolResult ( result )
1089+ cline . consecutiveMistakeCount = 0
1090+ } catch ( executionError : any ) {
1091+ cline . consecutiveMistakeCount ++
1092+ await handleError ( `executing custom tool "${ block . name } "` , executionError )
1093+ }
1094+
1095+ break
1096+ }
1097+
1098+ // Not a custom tool - handle as unknown tool error
10571099 const errorMessage = `Unknown tool "${ block . name } ". This tool does not exist. Please use one of the available tools.`
10581100 cline . consecutiveMistakeCount ++
10591101 cline . recordToolError ( block . name as ToolName , errorMessage )
0 commit comments