fix: improve XML tool call error recovery with comprehensive guidance (#11106)

When models produce XML-style tool markup instead of using native tool
calling, the error message now includes explicit tool-use instructions
and next-step guidance (similar to noToolsUsed), making it much more
likely the model can self-correct on the next turn.

Changes:
- Add formatResponse.xmlToolCallError() with tool instructions reminder
- Use comprehensive error in presentAssistantMessage userMessageContent
- Improve error messages in BaseTool for missing nativeArgs
- Add dedicated test suite for xmlToolCallError()
This commit is contained in:
Roo Code 2026-02-15 17:18:04 +00:00
parent aaee5a2c02
commit 20083a6866
4 changed files with 73 additions and 7 deletions

View file

@ -300,22 +300,27 @@ export async function presentAssistantMessage(cline: Task) {
// A tool_use block without an id is invalid and cannot be executed.
const toolCallId = (block as any).id as string | undefined
if (!toolCallId) {
const errorMessage =
"Invalid tool call: missing tool_use.id. XML tool calls are no longer supported. Remove any XML tool markup (e.g. <read_file>...</read_file>) and use native tool calling instead."
const userFacingError =
"XML tool calls are no longer supported. Remove any XML tool markup (e.g. <read_file>...</read_file>) and use native tool calling instead."
// Record a tool error for visibility/telemetry. Use the reported tool name if present.
try {
if (
typeof (cline as any).recordToolError === "function" &&
typeof (block as any).name === "string"
) {
;(cline as any).recordToolError((block as any).name as ToolName, errorMessage)
;(cline as any).recordToolError((block as any).name as ToolName, userFacingError)
}
} catch {
// Best-effort only
}
cline.consecutiveMistakeCount++
await cline.say("error", errorMessage)
cline.userMessageContent.push({ type: "text", text: errorMessage })
await cline.say("error", userFacingError)
// Push comprehensive error with tool-use instructions so the model
// can self-correct on the next turn (see #11106).
cline.userMessageContent.push({
type: "text",
text: formatResponse.xmlToolCallError(),
})
cline.didAlreadyUseTool = true
break
}

View file

@ -0,0 +1,38 @@
// npx vitest core/prompts/__tests__/responses-xml-tool-call-error.spec.ts
import { formatResponse } from "../responses"
describe("formatResponse.xmlToolCallError", () => {
it("should return a string containing the XML error explanation", () => {
const result = formatResponse.xmlToolCallError()
expect(result).toContain("XML tool calls are no longer supported")
})
it("should include instruction to not embed XML tags in text", () => {
const result = formatResponse.xmlToolCallError()
expect(result).toContain("Do NOT embed tool invocations as XML tags")
})
it("should include tool use instructions reminder", () => {
const result = formatResponse.xmlToolCallError()
expect(result).toContain("Reminder: Instructions for Tool Use")
expect(result).toContain("native tool calling mechanism")
})
it("should include next steps guidance", () => {
const result = formatResponse.xmlToolCallError()
expect(result).toContain("Next Steps")
expect(result).toContain("attempt_completion")
expect(result).toContain("ask_followup_question")
})
it("should include the [ERROR] prefix", () => {
const result = formatResponse.xmlToolCallError()
expect(result).toMatch(/^\[ERROR\]/)
})
it("should include automated message notice", () => {
const result = formatResponse.xmlToolCallError()
expect(result).toContain("This is an automated message")
})
})

View file

@ -54,6 +54,24 @@ Otherwise, if you have not completed the task and do not need additional informa
(This is an automated message, so do not respond to it conversationally.)`
},
xmlToolCallError: () => {
const instructions = getToolInstructionsReminder()
return `[ERROR] XML tool calls are no longer supported. The model produced XML-style tool markup (e.g. <tool_name>...</tool_name>) instead of using the API's native tool calling mechanism.
Do NOT embed tool invocations as XML tags in your text response. Instead, use the platform's built-in function/tool calling feature to invoke tools.
${instructions}
# Next Steps
Please retry your previous action using proper native tool calls.
If you have completed the user's task, use the attempt_completion tool.
If you require additional information from the user, use the ask_followup_question tool.
Otherwise, proceed with the next step of the task using native tool calls.
(This is an automated message, so do not respond to it conversationally.)`
},
tooManyMistakes: (feedback?: string) =>
JSON.stringify({
status: "guidance",

View file

@ -142,10 +142,15 @@ export abstract class BaseTool<TName extends ToolName> {
})()
if (paramsText.includes("<") && paramsText.includes(">")) {
throw new Error(
"XML tool calls are no longer supported. Use native tool calling (nativeArgs) instead.",
"XML tool calls are no longer supported. " +
"Do not embed tool invocations as XML tags in your text response. " +
"Use the platform's native tool calling mechanism (nativeArgs) instead.",
)
}
throw new Error("Tool call is missing native arguments (nativeArgs).")
throw new Error(
"Tool call is missing native arguments (nativeArgs). " +
"Use the platform's native tool calling mechanism to invoke tools.",
)
}
} catch (error) {
console.error(`Error parsing parameters:`, error)