Skip to content
Closed
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
21 changes: 18 additions & 3 deletions src/core/task/Task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1346,8 +1346,18 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
// the user hits max requests and denies resetting the count.
break
} else {
nextUserContent = [{ type: "text", text: formatResponse.noToolsUsed() }]
this.consecutiveMistakeCount++
// In Ask mode, we allow responses without tool usage since it's designed
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good fix: the code now checks task mode before pushing the no-tools-used error. In Ask mode, the loop breaks gracefully. Consider abstracting the check (e.g. a helper function isAskMode()) to reduce duplication.

// to provide direct answers, especially when using features like Google Gemini's grounding
const currentMode = await this.getTaskMode()
const isAskMode = currentMode === "ask"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing test coverage for this new behavior. This is a critical change that prevents infinite loops in Ask mode - we should have tests to ensure it works correctly and prevent regressions.

Consider adding tests that verify:

  • Ask mode allows responses without tool usage
  • Other modes still trigger the noToolsUsed() error
  • The consecutiveMistakeCount is not incremented in Ask mode

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have we considered if other modes might benefit from allowing responses without tool usage? The Orchestrator mode, for example, has an empty groups array and might face similar issues with certain LLM providers.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good idea, maybe not check explicit for Ask mode but maybe have a setting for Models with Grounding Mode?


if (!isAskMode) {
nextUserContent = [{ type: "text", text: formatResponse.noToolsUsed() }]
this.consecutiveMistakeCount++
} else {
// For Ask mode, end the loop gracefully without error
break
}
}
}
}
Expand Down Expand Up @@ -1781,7 +1791,12 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
// either use a tool or attempt_completion.
const didToolUse = this.assistantMessageContent.some((block) => block.type === "tool_use")

if (!didToolUse) {
// In Ask mode, we allow responses without tool usage since it's designed
// to provide direct answers, especially when using features like Google Gemini's grounding
const currentMode = await this.getTaskMode()
const isAskMode = currentMode === "ask"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic is duplicated from lines ~1349-1360. Consider extracting into a helper method to follow DRY principles:

Suggested change
const isAskMode = currentMode === "ask"
private async shouldAllowResponseWithoutToolUsage(): Promise<boolean> {
const currentMode = await this.getTaskMode()
return currentMode === "ask"
}

Then both locations could use:

if (!await this.shouldAllowResponseWithoutToolUsage()) {
    // Handle the error case
}


if (!didToolUse && !isAskMode) {
this.userMessageContent.push({ type: "text", text: formatResponse.noToolsUsed() })
this.consecutiveMistakeCount++
}
Expand Down
Loading