Skip to content

Commit eef6c03

Browse files
committed
feat: add custom error titles to all tool error reporting
- Updated generateImageTool.ts with 7 custom error titles - Updated executeCommandTool.ts with Command Timeout error title - Updated askFollowupQuestionTool.ts with XML Parse Error title - Updated useMcpToolTool.ts with 5 MCP-related error titles - Updated searchAndReplaceTool.ts with File Not Found and File Read Error titles - Fixed all related test files to match new error format with metadata parameter This ensures all error reporting across tools uses the new custom title feature for better error display in the UI.
1 parent 47c21fb commit eef6c03

File tree

7 files changed

+197
-17
lines changed

7 files changed

+197
-17
lines changed

src/core/tools/__tests__/generateImageTool.test.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,17 @@ describe("generateImageTool", () => {
277277
mockRemoveClosingTag,
278278
)
279279

280-
expect(mockCline.say).toHaveBeenCalledWith("error", expect.stringContaining("Input image not found"))
280+
expect(mockCline.say).toHaveBeenCalledWith(
281+
"error",
282+
expect.stringContaining("Input image not found"),
283+
undefined,
284+
undefined,
285+
undefined,
286+
undefined,
287+
{
288+
metadata: { title: "Input Image Not Found" },
289+
},
290+
)
281291
expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("Input image not found"))
282292
})
283293

@@ -302,7 +312,17 @@ describe("generateImageTool", () => {
302312
mockRemoveClosingTag,
303313
)
304314

305-
expect(mockCline.say).toHaveBeenCalledWith("error", expect.stringContaining("Unsupported image format"))
315+
expect(mockCline.say).toHaveBeenCalledWith(
316+
"error",
317+
expect.stringContaining("Unsupported image format"),
318+
undefined,
319+
undefined,
320+
undefined,
321+
undefined,
322+
{
323+
metadata: { title: "Unsupported Image Format" },
324+
},
325+
)
306326
expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("Unsupported image format"))
307327
})
308328
})

src/core/tools/__tests__/useMcpToolTool.spec.ts

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,17 @@ describe("useMcpToolTool", () => {
151151

152152
expect(mockTask.consecutiveMistakeCount).toBe(1)
153153
expect(mockTask.recordToolError).toHaveBeenCalledWith("use_mcp_tool")
154-
expect(mockTask.say).toHaveBeenCalledWith("error", expect.stringContaining("invalid JSON argument"))
154+
expect(mockTask.say).toHaveBeenCalledWith(
155+
"error",
156+
expect.stringContaining("invalid JSON argument"),
157+
undefined,
158+
undefined,
159+
undefined,
160+
undefined,
161+
{
162+
metadata: { title: "Invalid JSON Arguments" },
163+
},
164+
)
155165
expect(mockPushToolResult).toHaveBeenCalledWith("Tool error: Invalid args for test_server:test_tool")
156166
})
157167
})
@@ -343,7 +353,17 @@ describe("useMcpToolTool", () => {
343353

344354
expect(mockTask.consecutiveMistakeCount).toBe(1)
345355
expect(mockTask.recordToolError).toHaveBeenCalledWith("use_mcp_tool")
346-
expect(mockTask.say).toHaveBeenCalledWith("error", expect.stringContaining("does not exist"))
356+
expect(mockTask.say).toHaveBeenCalledWith(
357+
"error",
358+
expect.stringContaining("does not exist"),
359+
undefined,
360+
undefined,
361+
undefined,
362+
undefined,
363+
{
364+
metadata: { title: "MCP Tool Not Found" },
365+
},
366+
)
347367
// Check that the error message contains available tools
348368
expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("existing-tool-1"))
349369
expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("existing-tool-2"))
@@ -390,7 +410,17 @@ describe("useMcpToolTool", () => {
390410

391411
expect(mockTask.consecutiveMistakeCount).toBe(1)
392412
expect(mockTask.recordToolError).toHaveBeenCalledWith("use_mcp_tool")
393-
expect(mockTask.say).toHaveBeenCalledWith("error", expect.stringContaining("does not exist"))
413+
expect(mockTask.say).toHaveBeenCalledWith(
414+
"error",
415+
expect.stringContaining("does not exist"),
416+
undefined,
417+
undefined,
418+
undefined,
419+
undefined,
420+
{
421+
metadata: { title: "MCP Tool Not Found" },
422+
},
423+
)
394424
expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("No tools available"))
395425
})
396426

@@ -484,7 +514,17 @@ describe("useMcpToolTool", () => {
484514
// Assert
485515
expect(mockTask.consecutiveMistakeCount).toBe(1)
486516
expect(mockTask.recordToolError).toHaveBeenCalledWith("use_mcp_tool")
487-
expect(mockTask.say).toHaveBeenCalledWith("error", expect.stringContaining("not configured"))
517+
expect(mockTask.say).toHaveBeenCalledWith(
518+
"error",
519+
expect.stringContaining("not configured"),
520+
undefined,
521+
undefined,
522+
undefined,
523+
undefined,
524+
{
525+
metadata: { title: "MCP Server Not Found" },
526+
},
527+
)
488528
expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("s1"))
489529
expect(callToolMock).not.toHaveBeenCalled()
490530
expect(mockAskApproval).not.toHaveBeenCalled()
@@ -527,7 +567,17 @@ describe("useMcpToolTool", () => {
527567
// Assert
528568
expect(mockTask.consecutiveMistakeCount).toBe(1)
529569
expect(mockTask.recordToolError).toHaveBeenCalledWith("use_mcp_tool")
530-
expect(mockTask.say).toHaveBeenCalledWith("error", expect.stringContaining("not configured"))
570+
expect(mockTask.say).toHaveBeenCalledWith(
571+
"error",
572+
expect.stringContaining("not configured"),
573+
undefined,
574+
undefined,
575+
undefined,
576+
undefined,
577+
{
578+
metadata: { title: "MCP Server Not Found" },
579+
},
580+
)
531581
expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("No servers available"))
532582
expect(callToolMock).not.toHaveBeenCalled()
533583
expect(mockAskApproval).not.toHaveBeenCalled()

src/core/tools/askFollowupQuestionTool.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,17 @@ export async function askFollowupQuestionTool(
4848
} catch (error) {
4949
cline.consecutiveMistakeCount++
5050
cline.recordToolError("ask_followup_question")
51-
await cline.say("error", `Failed to parse operations: ${error.message}`)
51+
await cline.say(
52+
"error",
53+
`Failed to parse operations: ${error.message}`,
54+
undefined,
55+
undefined,
56+
undefined,
57+
undefined,
58+
{
59+
metadata: { title: "XML Parse Error" },
60+
},
61+
)
5262
pushToolResult(formatResponse.toolError("Invalid operations xml format"))
5363
return
5464
}

src/core/tools/executeCommandTool.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,17 @@ export async function executeCommand(
271271
if (isTimedOut) {
272272
const status: CommandExecutionStatus = { executionId, status: "timeout" }
273273
provider?.postMessageToWebview({ type: "commandExecutionStatus", text: JSON.stringify(status) })
274-
await task.say("error", t("common:errors:command_timeout", { seconds: commandExecutionTimeoutSeconds }))
274+
await task.say(
275+
"error",
276+
t("common:errors:command_timeout", { seconds: commandExecutionTimeoutSeconds }),
277+
undefined,
278+
undefined,
279+
undefined,
280+
undefined,
281+
{
282+
metadata: { title: "Command Timeout" },
283+
},
284+
)
275285
task.terminalProcess = undefined
276286

277287
return [

src/core/tools/generateImageTool.ts

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,17 @@ export async function generateImageTool(
7373
// Check if input image exists
7474
const inputImageExists = await fileExistsAtPath(inputImageFullPath)
7575
if (!inputImageExists) {
76-
await cline.say("error", `Input image not found: ${getReadablePath(cline.cwd, inputImagePath)}`)
76+
await cline.say(
77+
"error",
78+
`Input image not found: ${getReadablePath(cline.cwd, inputImagePath)}`,
79+
undefined,
80+
undefined,
81+
undefined,
82+
undefined,
83+
{
84+
metadata: { title: "Input Image Not Found" },
85+
},
86+
)
7787
pushToolResult(
7888
formatResponse.toolError(`Input image not found: ${getReadablePath(cline.cwd, inputImagePath)}`),
7989
)
@@ -99,6 +109,13 @@ export async function generateImageTool(
99109
await cline.say(
100110
"error",
101111
`Unsupported image format: ${imageExtension}. Supported formats: ${supportedFormats.join(", ")}`,
112+
undefined,
113+
undefined,
114+
undefined,
115+
undefined,
116+
{
117+
metadata: { title: "Unsupported Image Format" },
118+
},
102119
)
103120
pushToolResult(
104121
formatResponse.toolError(
@@ -115,6 +132,13 @@ export async function generateImageTool(
115132
await cline.say(
116133
"error",
117134
`Failed to read input image: ${error instanceof Error ? error.message : "Unknown error"}`,
135+
undefined,
136+
undefined,
137+
undefined,
138+
undefined,
139+
{
140+
metadata: { title: "Failed to Read Input Image" },
141+
},
118142
)
119143
pushToolResult(
120144
formatResponse.toolError(
@@ -135,6 +159,13 @@ export async function generateImageTool(
135159
await cline.say(
136160
"error",
137161
"OpenRouter API key is required for image generation. Please configure it in the Image Generation experimental settings.",
162+
undefined,
163+
undefined,
164+
undefined,
165+
undefined,
166+
{
167+
metadata: { title: "Missing API Key" },
168+
},
138169
)
139170
pushToolResult(
140171
formatResponse.toolError(
@@ -188,14 +219,26 @@ export async function generateImageTool(
188219
)
189220

190221
if (!result.success) {
191-
await cline.say("error", result.error || "Failed to generate image")
222+
await cline.say(
223+
"error",
224+
result.error || "Failed to generate image",
225+
undefined,
226+
undefined,
227+
undefined,
228+
undefined,
229+
{
230+
metadata: { title: "Image Generation Failed" },
231+
},
232+
)
192233
pushToolResult(formatResponse.toolError(result.error || "Failed to generate image"))
193234
return
194235
}
195236

196237
if (!result.imageData) {
197238
const errorMessage = "No image data received"
198-
await cline.say("error", errorMessage)
239+
await cline.say("error", errorMessage, undefined, undefined, undefined, undefined, {
240+
metadata: { title: "No Image Data" },
241+
})
199242
pushToolResult(formatResponse.toolError(errorMessage))
200243
return
201244
}
@@ -204,7 +247,9 @@ export async function generateImageTool(
204247
const base64Match = result.imageData.match(/^data:image\/(png|jpeg|jpg);base64,(.+)$/)
205248
if (!base64Match) {
206249
const errorMessage = "Invalid image format received"
207-
await cline.say("error", errorMessage)
250+
await cline.say("error", errorMessage, undefined, undefined, undefined, undefined, {
251+
metadata: { title: "Invalid Image Format" },
252+
})
208253
pushToolResult(formatResponse.toolError(errorMessage))
209254
return
210255
}

src/core/tools/searchAndReplaceTool.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,9 @@ export async function searchAndReplaceTool(
137137
const formattedError = formatResponse.toolError(
138138
`File does not exist at path: ${absolutePath}\nThe specified file could not be found. Please verify the file path and try again.`,
139139
)
140-
await cline.say("error", formattedError)
140+
await cline.say("error", formattedError, undefined, undefined, undefined, undefined, {
141+
metadata: { title: "File Not Found" },
142+
})
141143
pushToolResult(formattedError)
142144
return
143145
}
@@ -156,7 +158,9 @@ export async function searchAndReplaceTool(
156158
error instanceof Error ? error.message : String(error)
157159
}\nPlease verify file permissions and try again.`
158160
const formattedError = formatResponse.toolError(errorMessage)
159-
await cline.say("error", formattedError)
161+
await cline.say("error", formattedError, undefined, undefined, undefined, undefined, {
162+
metadata: { title: "File Read Error" },
163+
})
160164
pushToolResult(formattedError)
161165
return
162166
}

src/core/tools/useMcpToolTool.ts

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,17 @@ async function validateParams(
6262
} catch (error) {
6363
cline.consecutiveMistakeCount++
6464
cline.recordToolError("use_mcp_tool")
65-
await cline.say("error", t("mcp:errors.invalidJsonArgument", { toolName: params.tool_name }))
65+
await cline.say(
66+
"error",
67+
t("mcp:errors.invalidJsonArgument", { toolName: params.tool_name }),
68+
undefined,
69+
undefined,
70+
undefined,
71+
undefined,
72+
{
73+
metadata: { title: "Invalid JSON Arguments" },
74+
},
75+
)
6676

6777
pushToolResult(
6878
formatResponse.toolError(
@@ -109,7 +119,17 @@ async function validateToolExists(
109119

110120
cline.consecutiveMistakeCount++
111121
cline.recordToolError("use_mcp_tool")
112-
await cline.say("error", t("mcp:errors.serverNotFound", { serverName, availableServers }))
122+
await cline.say(
123+
"error",
124+
t("mcp:errors.serverNotFound", { serverName, availableServers }),
125+
undefined,
126+
undefined,
127+
undefined,
128+
undefined,
129+
{
130+
metadata: { title: "MCP Server Not Found" },
131+
},
132+
)
113133

114134
pushToolResult(formatResponse.unknownMcpServerError(serverName, availableServersArray))
115135
return { isValid: false, availableTools: [] }
@@ -127,6 +147,13 @@ async function validateToolExists(
127147
serverName,
128148
availableTools: "No tools available",
129149
}),
150+
undefined,
151+
undefined,
152+
undefined,
153+
undefined,
154+
{
155+
metadata: { title: "MCP Tool Not Found" },
156+
},
130157
)
131158

132159
pushToolResult(formatResponse.unknownMcpToolError(serverName, toolName, []))
@@ -149,6 +176,13 @@ async function validateToolExists(
149176
serverName,
150177
availableTools: availableToolNames.join(", "),
151178
}),
179+
undefined,
180+
undefined,
181+
undefined,
182+
undefined,
183+
{
184+
metadata: { title: "MCP Tool Not Found" },
185+
},
152186
)
153187

154188
pushToolResult(formatResponse.unknownMcpToolError(serverName, toolName, availableToolNames))
@@ -171,6 +205,13 @@ async function validateToolExists(
171205
availableTools:
172206
enabledToolNames.length > 0 ? enabledToolNames.join(", ") : "No enabled tools available",
173207
}),
208+
undefined,
209+
undefined,
210+
undefined,
211+
undefined,
212+
{
213+
metadata: { title: "MCP Tool Disabled" },
214+
},
174215
)
175216

176217
pushToolResult(formatResponse.unknownMcpToolError(serverName, toolName, enabledToolNames))

0 commit comments

Comments
 (0)