Skip to content
Closed
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
50 changes: 41 additions & 9 deletions src/core/prompts/responses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.`
Expand Down Expand Up @@ -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) =>
Expand Down Expand Up @@ -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:

Expand All @@ -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()
35 changes: 32 additions & 3 deletions src/core/task/Task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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++
}
}
Expand Down Expand Up @@ -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++
}

Expand Down Expand Up @@ -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 {
Expand Down
Loading