Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 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
18 changes: 13 additions & 5 deletions src/core/assistant-message/presentAssistantMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export async function presentAssistantMessage(cline: Task) {

switch (block.type) {
case "text": {
if (cline.didRejectTool || cline.didAlreadyUseTool) {
if (cline.didRejectTool) {
break
}

Expand Down Expand Up @@ -235,8 +235,9 @@ export async function presentAssistantMessage(cline: Task) {
break
}

if (cline.didAlreadyUseTool) {
if (cline.didAlreadyUseTool && block.name !== "update_todo_list") {
// Ignore any content after a tool has already been used.
// Exception: update_todo_list can be used multiple times
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.`,
Expand All @@ -256,8 +257,10 @@ 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
// message. Exception: update_todo_list can be used multiple times.
if (block.name !== "update_todo_list") {
cline.didAlreadyUseTool = true
}
}

const askApproval = async (
Expand Down Expand Up @@ -551,7 +554,12 @@ 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 && block.type !== "tool_use") ||
(cline.didAlreadyUseTool && block.type === "tool_use" && block.name !== "update_todo_list")
) {
// 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
8 changes: 7 additions & 1 deletion src/core/task/Task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1427,7 +1427,13 @@ 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) {
// Exception: update_todo_list can be used multiple times
// Check if any update_todo_list is being processed (partial or complete)
const hasUpdateTodoList = this.assistantMessageContent.some(
(block) => block.type === "tool_use" && block.name === "update_todo_list",
)

if (this.didAlreadyUseTool && !hasUpdateTodoList) {
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.]"
break
Expand Down