mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-07 08:26:51 +00:00
Fixes #4900: MCP Tool reminders enforce the wrong syntax
- Modified formatResponse.noToolsUsed() and formatResponse.missingToolParameterError() to accept optional hasMcpTools parameter - Added getToolUseInstructionsReminder() function that provides correct syntax based on tool type - When MCP tools are available, shows proper use_mcp_tool format instead of generic XML format - Added hasMcpToolsAvailable() method to Task class to detect when MCP servers with tools are connected - Updated all call sites to pass MCP tool availability information - Maintains backward compatibility with legacy toolUseInstructionsReminder constant This prevents the infinite loop where AI tries wrong MCP syntax and gets corrected with wrong format.
This commit is contained in:
parent
2e2f83be60
commit
ba0d081bf2
2 changed files with 73 additions and 12 deletions
|
|
@ -18,23 +18,23 @@ export const formatResponse = {
|
|||
rooIgnoreError: (path: string) =>
|
||||
`Access to ${path} is blocked by the .rooignore file settings. You must try to continue in the task without using this file, or ask the user to update the .rooignore file.`,
|
||||
|
||||
noToolsUsed: () =>
|
||||
noToolsUsed: (hasMcpTools?: boolean) =>
|
||||
`[ERROR] You did not use a tool in your previous response! Please retry with a tool use.
|
||||
|
||||
${toolUseInstructionsReminder}
|
||||
${getToolUseInstructionsReminder(hasMcpTools)}
|
||||
|
||||
# Next Steps
|
||||
|
||||
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, if you have not completed the task and do not need additional information, then proceed with the next step of the task.
|
||||
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, if you have not completed the task and do not need additional information, then proceed with the next step of the task.
|
||||
(This is an automated message, so do not respond to it conversationally.)`,
|
||||
|
||||
tooManyMistakes: (feedback?: string) =>
|
||||
`You seem to be having trouble proceeding. The user has provided the following feedback to help guide you:\n<feedback>\n${feedback}\n</feedback>`,
|
||||
|
||||
missingToolParameterError: (paramName: string) =>
|
||||
`Missing value for required parameter '${paramName}'. Please retry with complete response.\n\n${toolUseInstructionsReminder}`,
|
||||
missingToolParameterError: (paramName: string, hasMcpTools?: boolean) =>
|
||||
`Missing value for required parameter '${paramName}'. Please retry with complete response.\n\n${getToolUseInstructionsReminder(hasMcpTools)}`,
|
||||
|
||||
lineCountTruncationError: (actualLineCount: number, isNewFile: boolean, diffStrategyEnabled: boolean = false) => {
|
||||
const truncationMessage = `Note: Your response may have been truncated because it exceeded your output limit. You wrote ${actualLineCount} lines of content, but the line_count parameter was either missing or not included in your response.`
|
||||
|
|
@ -66,7 +66,7 @@ Otherwise, if you have not completed the task and do not need additional informa
|
|||
`RECOMMENDED APPROACH:\n` +
|
||||
`${existingFileApproaches.join("\n")}\n`
|
||||
|
||||
return `${isNewFile ? newFileGuidance : existingFileGuidance}\n${toolUseInstructionsReminder}`
|
||||
return `${isNewFile ? newFileGuidance : existingFileGuidance}\n${getToolUseInstructionsReminder()}`
|
||||
},
|
||||
|
||||
invalidMcpToolArgumentError: (serverName: string, toolName: string) =>
|
||||
|
|
@ -190,7 +190,34 @@ const formatImagesIntoBlocks = (images?: string[]): Anthropic.ImageBlockParam[]
|
|||
: []
|
||||
}
|
||||
|
||||
const toolUseInstructionsReminder = `# Reminder: Instructions for Tool Use
|
||||
const getToolUseInstructionsReminder = (hasMcpTools?: boolean) => {
|
||||
if (hasMcpTools) {
|
||||
return `# Reminder: Instructions for MCP Tool Use
|
||||
|
||||
MCP tools must be called using the use_mcp_tool format:
|
||||
|
||||
<use_mcp_tool>
|
||||
<server_name>server name here</server_name>
|
||||
<tool_name>tool name here</tool_name>
|
||||
<arguments>
|
||||
{
|
||||
"param1": "value1",
|
||||
"param2": "value2"
|
||||
}
|
||||
</arguments>
|
||||
</use_mcp_tool>
|
||||
|
||||
For regular tools, use the standard XML format:
|
||||
|
||||
<actual_tool_name>
|
||||
<parameter1_name>value1</parameter1_name>
|
||||
<parameter2_name>value2</parameter2_name>
|
||||
...
|
||||
</actual_tool_name>
|
||||
|
||||
Always use the correct format for the type of tool you are calling.`
|
||||
} else {
|
||||
return `# Reminder: Instructions for Tool Use
|
||||
|
||||
Tool uses are formatted using XML-style tags. The tool name itself becomes the XML tag name. Each parameter is enclosed within its own set of tags. Here's the structure:
|
||||
|
||||
|
|
@ -209,3 +236,8 @@ I have completed the task...
|
|||
</attempt_completion>
|
||||
|
||||
Always use the actual tool name as the XML tag name for proper parsing and execution.`
|
||||
}
|
||||
}
|
||||
|
||||
// Legacy constant for backward compatibility
|
||||
const toolUseInstructionsReminder = getToolUseInstructionsReminder()
|
||||
|
|
|
|||
|
|
@ -709,7 +709,8 @@ export class Task extends EventEmitter<ClineEvents> {
|
|||
relPath ? ` for '${relPath.toPosix()}'` : ""
|
||||
} without value for required parameter '${paramName}'. Retrying...`,
|
||||
)
|
||||
return formatResponse.toolError(formatResponse.missingToolParameterError(paramName))
|
||||
const hasMcpTools = await this.hasMcpToolsAvailable()
|
||||
return formatResponse.toolError(formatResponse.missingToolParameterError(paramName, hasMcpTools))
|
||||
}
|
||||
|
||||
// Start / Abort / Resume
|
||||
|
|
@ -1128,7 +1129,8 @@ export class Task extends EventEmitter<ClineEvents> {
|
|||
// the user hits max requests and denies resetting the count.
|
||||
break
|
||||
} else {
|
||||
nextUserContent = [{ type: "text", text: formatResponse.noToolsUsed() }]
|
||||
const hasMcpTools = await this.hasMcpToolsAvailable()
|
||||
nextUserContent = [{ type: "text", text: formatResponse.noToolsUsed(hasMcpTools) }]
|
||||
this.consecutiveMistakeCount++
|
||||
}
|
||||
}
|
||||
|
|
@ -1517,7 +1519,8 @@ export class Task extends EventEmitter<ClineEvents> {
|
|||
const didToolUse = this.assistantMessageContent.some((block) => block.type === "tool_use")
|
||||
|
||||
if (!didToolUse) {
|
||||
this.userMessageContent.push({ type: "text", text: formatResponse.noToolsUsed() })
|
||||
const hasMcpTools = await this.hasMcpToolsAvailable()
|
||||
this.userMessageContent.push({ type: "text", text: formatResponse.noToolsUsed(hasMcpTools) })
|
||||
this.consecutiveMistakeCount++
|
||||
}
|
||||
|
||||
|
|
@ -1622,6 +1625,32 @@ export class Task extends EventEmitter<ClineEvents> {
|
|||
})()
|
||||
}
|
||||
|
||||
private async hasMcpToolsAvailable(): Promise<boolean> {
|
||||
try {
|
||||
const { mcpEnabled } = (await this.providerRef.deref()?.getState()) ?? {}
|
||||
if (!(mcpEnabled ?? true)) {
|
||||
return false
|
||||
}
|
||||
|
||||
const provider = this.providerRef.deref()
|
||||
if (!provider) {
|
||||
return false
|
||||
}
|
||||
|
||||
const mcpHub = await McpServerManager.getInstance(provider.context, provider)
|
||||
if (!mcpHub) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if there are any connected MCP servers with tools
|
||||
const servers = mcpHub.getServers()
|
||||
return servers.some((server) => server.tools && server.tools.length > 0)
|
||||
} catch (error) {
|
||||
console.error("Error checking MCP tools availability:", error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
public async *attemptApiRequest(retryAttempt: number = 0): ApiStream {
|
||||
const state = await this.providerRef.deref()?.getState()
|
||||
const {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue