diff --git a/src/core/assistant-message/presentAssistantMessage.ts b/src/core/assistant-message/presentAssistantMessage.ts index ef2bb049630..1e749e21c94 100644 --- a/src/core/assistant-message/presentAssistantMessage.ts +++ b/src/core/assistant-message/presentAssistantMessage.ts @@ -80,7 +80,7 @@ export async function presentAssistantMessage(cline: Task) { switch (block.type) { case "text": { - if (cline.didRejectTool || cline.didAlreadyUseTool) { + if (cline.didRejectTool || cline.didAlreadyUseTool > 0) { break } @@ -212,11 +212,18 @@ export async function presentAssistantMessage(cline: Task) { break } - if (cline.didAlreadyUseTool) { + if (cline.didAlreadyUseTool > 4) { // Ignore any content after a tool has already been used. cline.userMessageContent.push({ type: "text", - text: `Tool [${block.name}] was not executed because a tool has already been used in this message. Only one tool may be used per message. You must assess the first tool's result before proceeding to use the next tool.`, + text: `Tool [${block.name}] was not executed because too many tools have already been used in this message. Only five tools may be used per message. You must assess the first tool's result before proceeding to use the next tool.`, + }) + + break + } else if (cline.didAlreadyUseTool > 0 && block.name === "attempt_completion") { + cline.userMessageContent.push({ + type: "text", + text: `Tool [attempt_completion] was not executed because attempt_completion cannot use with other tools.`, }) break @@ -234,7 +241,7 @@ export async function presentAssistantMessage(cline: Task) { // Once a tool result has been collected, ignore all other tool // uses since we should only ever present one tool result per // message. - cline.didAlreadyUseTool = true + cline.didAlreadyUseTool++ } const askApproval = async ( @@ -491,7 +498,7 @@ export async function presentAssistantMessage(cline: Task) { // skip execution since `didRejectTool` and iterate until `contentIndex` is // set to message length and it sets userMessageContentReady to true itself // (instead of preemptively doing it in iterator). - if (!block.partial || cline.didRejectTool || cline.didAlreadyUseTool) { + if (!block.partial || cline.didRejectTool || cline.didAlreadyUseTool > 4) { // Block is finished streaming and executing. if (cline.currentStreamingContentIndex === cline.assistantMessageContent.length - 1) { // It's okay that we increment if !didCompleteReadingStream, it'll diff --git a/src/core/prompts/sections/tool-use.ts b/src/core/prompts/sections/tool-use.ts index b75e4dad921..8a78dcc40b9 100644 --- a/src/core/prompts/sections/tool-use.ts +++ b/src/core/prompts/sections/tool-use.ts @@ -3,7 +3,7 @@ export function getSharedToolUseSection(): string { TOOL USE -You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use. +You have access to a set of tools that are executed upon the user's approval. You can use up to five tools in a single message to reduce the number of interaction rounds, and will receive the results of those tool use in the user's response. Read and write tools should not be used simultaneously in one request. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use. # Tool Use Formatting @@ -15,11 +15,21 @@ Tool uses are formatted using XML-style tags. The tool name itself becomes the X ... -For example, to use the read_file tool: + +value1 +value2 +... + + +For example, to use two read_file tools: src/main.js + +src/index.js + + Always use the actual tool name as the XML tag name for proper parsing and execution.` } diff --git a/src/core/prompts/tools/new-task.ts b/src/core/prompts/tools/new-task.ts index 7301b7b422d..66b7be18cf4 100644 --- a/src/core/prompts/tools/new-task.ts +++ b/src/core/prompts/tools/new-task.ts @@ -3,6 +3,7 @@ import { ToolArgs } from "./types" export function getNewTaskDescription(_args: ToolArgs): string { return `## new_task Description: This will let you create a new task instance in the chosen mode using your provided message. +IMPORTANT: This tool can only be called once per message. Parameters: - mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect"). diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index edee92388a6..e3b9f83ee89 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -183,7 +183,7 @@ export class Task extends EventEmitter { userMessageContent: (Anthropic.TextBlockParam | Anthropic.ImageBlockParam)[] = [] userMessageContentReady = false didRejectTool = false - didAlreadyUseTool = false + didAlreadyUseTool = 0 didCompleteReadingStream = false constructor({ @@ -1178,7 +1178,7 @@ export class Task extends EventEmitter { this.userMessageContent = [] this.userMessageContentReady = false this.didRejectTool = false - this.didAlreadyUseTool = false + this.didAlreadyUseTool = 0 this.presentAssistantMessageLocked = false this.presentAssistantMessageHasPendingUpdates = false @@ -1260,9 +1260,9 @@ export class Task extends EventEmitter { // get generation details. // UPDATE: It's better UX to interrupt the request at the // cost of the API cost not being retrieved. - if (this.didAlreadyUseTool) { + if (this.didAlreadyUseTool > 4) { assistantMessage += - "\n\n[Response interrupted by a tool use result. Only one tool may be used at a time and should be placed at the end of the message.]" + "\n\n[Response interrupted by a tool use result. Only five tools may be used at a time and should be placed at the end of the message.]" break } } diff --git a/src/core/tools/newTaskTool.ts b/src/core/tools/newTaskTool.ts index 38b4cbf3021..e6a2537ea3c 100644 --- a/src/core/tools/newTaskTool.ts +++ b/src/core/tools/newTaskTool.ts @@ -88,6 +88,9 @@ export async function newTaskTool( cline.isPaused = true cline.emit("taskPaused") + // no tool should be used after new task tool + cline.didAlreadyUseTool += 5 + return } } catch (error) {