Skip to content

allow use five tools in one call #3840

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
17 changes: 12 additions & 5 deletions src/core/assistant-message/presentAssistantMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -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
Expand All @@ -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 (
Expand Down Expand Up @@ -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
Expand Down
14 changes: 12 additions & 2 deletions src/core/prompts/sections/tool-use.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -15,11 +15,21 @@ Tool uses are formatted using XML-style tags. The tool name itself becomes the X
...
</actual_tool_name>

For example, to use the read_file tool:
<actual_tool_name2>
<parameter1_name>value1</parameter1_name>
<parameter2_name>value2</parameter2_name>
...
</actual_tool_name2>

For example, to use two read_file tools:

<read_file>
<path>src/main.js</path>
</read_file>

<read_file>
<path>src/index.js</path>
</read_file>

Always use the actual tool name as the XML tag name for proper parsing and execution.`
}
1 change: 1 addition & 0 deletions src/core/prompts/tools/new-task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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").
Expand Down
8 changes: 4 additions & 4 deletions src/core/task/Task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ export class Task extends EventEmitter<ClineEvents> {
userMessageContent: (Anthropic.TextBlockParam | Anthropic.ImageBlockParam)[] = []
userMessageContentReady = false
didRejectTool = false
didAlreadyUseTool = false
didAlreadyUseTool = 0
didCompleteReadingStream = false

constructor({
Expand Down Expand Up @@ -1178,7 +1178,7 @@ export class Task extends EventEmitter<ClineEvents> {
this.userMessageContent = []
this.userMessageContentReady = false
this.didRejectTool = false
this.didAlreadyUseTool = false
this.didAlreadyUseTool = 0
this.presentAssistantMessageLocked = false
this.presentAssistantMessageHasPendingUpdates = false

Expand Down Expand Up @@ -1260,9 +1260,9 @@ export class Task extends EventEmitter<ClineEvents> {
// 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
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/core/tools/newTaskTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Loading