diff --git a/cli/pkg/cli/config/settings_renderer.go b/cli/pkg/cli/config/settings_renderer.go index 307d59b88f..ef8ab9148c 100644 --- a/cli/pkg/cli/config/settings_renderer.go +++ b/cli/pkg/cli/config/settings_renderer.go @@ -189,7 +189,7 @@ func renderAutoApprovalSettings(value interface{}, censor bool) error { } } } else { - // Print other fields normally (enabled, maxRequests, enableNotifications, favorites) + // Print other fields normally (enabled, enableNotifications, favorites) fmt.Printf(" %s: %s\n", camelToKebab(key), formatValue(val, key, censor)) } } diff --git a/cli/pkg/cli/handlers/ask_handlers.go b/cli/pkg/cli/handlers/ask_handlers.go index 50aade1b5d..a2423a7de8 100644 --- a/cli/pkg/cli/handlers/ask_handlers.go +++ b/cli/pkg/cli/handlers/ask_handlers.go @@ -52,8 +52,6 @@ func (h *AskHandler) Handle(msg *types.ClineMessage, dc *DisplayContext) error { return h.handleResumeCompletedTask(msg, dc) case string(types.AskTypeMistakeLimitReached): return h.handleMistakeLimitReached(msg, dc) - case string(types.AskTypeAutoApprovalMaxReached): - return h.handleAutoApprovalMaxReached(msg, dc) case string(types.AskTypeBrowserActionLaunch): return h.handleBrowserActionLaunch(msg, dc) case string(types.AskTypeUseMcpServer): @@ -255,25 +253,6 @@ func (h *AskHandler) handleMistakeLimitReached(msg *types.ClineMessage, dc *Disp return dc.Renderer.RenderMessage("ERROR", fmt.Sprintf("Mistake Limit Reached: %s. Approval required.", msg.Text), true) } -// handleAutoApprovalMaxReached handles auto-approval max reached -func (h *AskHandler) handleAutoApprovalMaxReached(msg *types.ClineMessage, dc *DisplayContext) error { - if dc.SystemRenderer != nil { - details := make(map[string]string) - if msg.Text != "" { - details["reason"] = msg.Text - } - dc.SystemRenderer.RenderError( - "warning", - "Auto-Approval Limit Reached", - "The maximum number of auto-approved requests has been reached. Manual approval is now required.", - details, - ) - fmt.Printf("\n**Approval required to continue.**\n") - return nil - } - return dc.Renderer.RenderMessage("WARNING", fmt.Sprintf("Auto-approval limit reached: %s. Approval required.", msg.Text), true) -} - // handleBrowserActionLaunch handles browser action launch requests func (h *AskHandler) handleBrowserActionLaunch(msg *types.ClineMessage, dc *DisplayContext) error { url := strings.TrimSpace(msg.Text) diff --git a/cli/pkg/cli/task/manager.go b/cli/pkg/cli/task/manager.go index 13ca606e0e..a51ad62769 100644 --- a/cli/pkg/cli/task/manager.go +++ b/cli/pkg/cli/task/manager.go @@ -282,7 +282,6 @@ func (m *Manager) CheckSendEnabled(ctx context.Context) error { errorTypes := []string{ string(types.AskTypeAPIReqFailed), // "api_req_failed" string(types.AskTypeMistakeLimitReached), // "mistake_limit_reached" - string(types.AskTypeAutoApprovalMaxReached), // "auto_approval_max_req_reached" } isError := false @@ -1243,7 +1242,6 @@ func (m *Manager) UpdateTaskAutoApprovalAction(ctx context.Context, actionKey st settings := &cline.Settings{ AutoApprovalSettings: &cline.AutoApprovalSettings{ - Enabled: boolPtr(true), Actions: &cline.AutoApprovalActions{}, }, } diff --git a/cli/pkg/cli/task/settings_parser.go b/cli/pkg/cli/task/settings_parser.go index 286bd99efb..35287d7866 100644 --- a/cli/pkg/cli/task/settings_parser.go +++ b/cli/pkg/cli/task/settings_parser.go @@ -416,18 +416,6 @@ func setNestedField(settings *cline.Settings, parentField string, childFields ma func setAutoApprovalSettings(settings *cline.AutoApprovalSettings, fields map[string]string) error { for key, value := range fields { switch key { - case "enabled": - val, err := parseBool(value) - if err != nil { - return err - } - settings.Enabled = boolPtr(val) - case "max_requests": - val, err := parseInt32(value) - if err != nil { - return err - } - settings.MaxRequests = int32Ptr(val) case "enable_notifications": val, err := parseBool(value) if err != nil { diff --git a/cli/pkg/cli/types/messages.go b/cli/pkg/cli/types/messages.go index fac10f238c..b869327918 100644 --- a/cli/pkg/cli/types/messages.go +++ b/cli/pkg/cli/types/messages.go @@ -37,17 +37,16 @@ const ( type AskType string const ( - AskTypeFollowup AskType = "followup" - AskTypePlanModeRespond AskType = "plan_mode_respond" - AskTypeCommand AskType = "command" - AskTypeCommandOutput AskType = "command_output" - AskTypeCompletionResult AskType = "completion_result" - AskTypeTool AskType = "tool" - AskTypeAPIReqFailed AskType = "api_req_failed" - AskTypeResumeTask AskType = "resume_task" - AskTypeResumeCompletedTask AskType = "resume_completed_task" - AskTypeMistakeLimitReached AskType = "mistake_limit_reached" - AskTypeAutoApprovalMaxReached AskType = "auto_approval_max_req_reached" + AskTypeFollowup AskType = "followup" + AskTypePlanModeRespond AskType = "plan_mode_respond" + AskTypeCommand AskType = "command" + AskTypeCommandOutput AskType = "command_output" + AskTypeCompletionResult AskType = "completion_result" + AskTypeTool AskType = "tool" + AskTypeAPIReqFailed AskType = "api_req_failed" + AskTypeResumeTask AskType = "resume_task" + AskTypeResumeCompletedTask AskType = "resume_completed_task" + AskTypeMistakeLimitReached AskType = "mistake_limit_reached" AskTypeBrowserActionLaunch AskType = "browser_action_launch" AskTypeUseMcpServer AskType = "use_mcp_server" AskTypeNewTask AskType = "new_task" @@ -247,8 +246,6 @@ func convertProtoAskType(askType cline.ClineAsk) string { return string(AskTypeResumeCompletedTask) case cline.ClineAsk_MISTAKE_LIMIT_REACHED: return string(AskTypeMistakeLimitReached) - case cline.ClineAsk_AUTO_APPROVAL_MAX_REQ_REACHED: - return string(AskTypeAutoApprovalMaxReached) case cline.ClineAsk_BROWSER_ACTION_LAUNCH: return string(AskTypeBrowserActionLaunch) case cline.ClineAsk_USE_MCP_SERVER: diff --git a/proto/cline/state.proto b/proto/cline/state.proto index 1444c4c9f3..8c17f97235 100644 --- a/proto/cline/state.proto +++ b/proto/cline/state.proto @@ -46,11 +46,8 @@ message AutoApprovalActions { // Auto approval settings for task execution message AutoApprovalSettings { int32 version = 1; - optional bool enabled = 2; - AutoApprovalActions actions = 3; - optional int32 max_requests = 4; - optional bool enable_notifications = 5; - repeated string favorites = 6; + AutoApprovalActions actions = 2; + optional bool enable_notifications = 3; } message Secrets { @@ -283,11 +280,8 @@ message ResetStateRequest { message AutoApprovalSettingsRequest { Metadata metadata = 1; int32 version = 2; - bool enabled = 3; - AutoApprovalActions actions = 4; - int32 max_requests = 5; - bool enable_notifications = 6; - repeated string favorites = 7; + AutoApprovalActions actions = 3; + bool enable_notifications = 4; } enum TelemetrySettingEnum { diff --git a/proto/cline/ui.proto b/proto/cline/ui.proto index 78b8e04186..68b4059424 100644 --- a/proto/cline/ui.proto +++ b/proto/cline/ui.proto @@ -26,13 +26,12 @@ enum ClineAsk { RESUME_TASK = 7; RESUME_COMPLETED_TASK = 8; MISTAKE_LIMIT_REACHED = 9; - AUTO_APPROVAL_MAX_REQ_REACHED = 10; - BROWSER_ACTION_LAUNCH = 11; - USE_MCP_SERVER = 12; - NEW_TASK = 13; - CONDENSE = 14; - REPORT_BUG = 15; - SUMMARIZE_TASK = 16; + BROWSER_ACTION_LAUNCH = 10; + USE_MCP_SERVER = 11; + NEW_TASK = 12; + CONDENSE = 13; + REPORT_BUG = 14; + SUMMARIZE_TASK = 15; } // Enum for ClineSay types diff --git a/src/core/controller/state/updateAutoApprovalSettings.ts b/src/core/controller/state/updateAutoApprovalSettings.ts index c66be3eaa1..c53901c39e 100644 --- a/src/core/controller/state/updateAutoApprovalSettings.ts +++ b/src/core/controller/state/updateAutoApprovalSettings.ts @@ -19,10 +19,7 @@ export async function updateAutoApprovalSettings(controller: Controller, request const settings = { ...currentSettings, ...(request.version !== undefined && { version: request.version }), - ...(request.enabled !== undefined && { enabled: request.enabled }), - ...(request.maxRequests !== undefined && { maxRequests: request.maxRequests }), ...(request.enableNotifications !== undefined && { enableNotifications: request.enableNotifications }), - ...(request.favorites && request.favorites.length > 0 && { favorites: request.favorites }), actions: { ...currentSettings.actions, ...(request.actions @@ -31,16 +28,6 @@ export async function updateAutoApprovalSettings(controller: Controller, request }, } - if (controller.task) { - const maxRequestsChanged = - controller.stateManager.getGlobalSettingsKey("autoApprovalSettings").maxRequests !== settings.maxRequests - - // Reset counter if max requests limit changed - if (maxRequestsChanged) { - controller.task.resetConsecutiveAutoApprovedRequestsCount() - } - } - controller.stateManager.setGlobalState("autoApprovalSettings", settings) await controller.postStateToWebview() diff --git a/src/core/controller/state/updateSettingsCli.ts b/src/core/controller/state/updateSettingsCli.ts index a335dc6b3e..83fccf4a6f 100644 --- a/src/core/controller/state/updateSettingsCli.ts +++ b/src/core/controller/state/updateSettingsCli.ts @@ -87,13 +87,9 @@ export async function updateSettingsCli(controller: Controller, request: UpdateS const mergedSettings = { ...currentAutoApprovalSettings, ...(autoApprovalSettings.version !== undefined && { version: autoApprovalSettings.version }), - ...(autoApprovalSettings.enabled !== undefined && { enabled: autoApprovalSettings.enabled }), - ...(autoApprovalSettings.maxRequests !== undefined && { maxRequests: autoApprovalSettings.maxRequests }), ...(autoApprovalSettings.enableNotifications !== undefined && { enableNotifications: autoApprovalSettings.enableNotifications, }), - ...(autoApprovalSettings.favorites && - autoApprovalSettings.favorites.length > 0 && { favorites: autoApprovalSettings.favorites }), actions: { ...currentAutoApprovalSettings.actions, ...(autoApprovalSettings.actions diff --git a/src/core/controller/state/updateTaskSettings.ts b/src/core/controller/state/updateTaskSettings.ts index 6a754862ac..cc422e4482 100644 --- a/src/core/controller/state/updateTaskSettings.ts +++ b/src/core/controller/state/updateTaskSettings.ts @@ -76,13 +76,9 @@ export async function updateTaskSettings(controller: Controller, request: Update const mergedSettings = { ...currentAutoApprovalSettings, ...(autoApprovalSettings.version !== undefined && { version: autoApprovalSettings.version }), - ...(autoApprovalSettings.enabled !== undefined && { enabled: autoApprovalSettings.enabled }), - ...(autoApprovalSettings.maxRequests !== undefined && { maxRequests: autoApprovalSettings.maxRequests }), ...(autoApprovalSettings.enableNotifications !== undefined && { enableNotifications: autoApprovalSettings.enableNotifications, }), - ...(autoApprovalSettings.favorites && - autoApprovalSettings.favorites.length > 0 && { favorites: autoApprovalSettings.favorites }), actions: { ...currentAutoApprovalSettings.actions, ...(autoApprovalSettings.actions diff --git a/src/core/controller/task/newTask.ts b/src/core/controller/task/newTask.ts index dac00549a7..4bfdc1b594 100644 --- a/src/core/controller/task/newTask.ts +++ b/src/core/controller/task/newTask.ts @@ -43,13 +43,9 @@ export async function newTask(controller: Controller, request: NewTaskRequest): return { ...globalSettings, ...(incomingSettings.version !== undefined && { version: incomingSettings.version }), - ...(incomingSettings.enabled !== undefined && { enabled: incomingSettings.enabled }), - ...(incomingSettings.maxRequests !== undefined && { maxRequests: incomingSettings.maxRequests }), ...(incomingSettings.enableNotifications !== undefined && { enableNotifications: incomingSettings.enableNotifications, }), - ...(incomingSettings.favorites && - incomingSettings.favorites.length > 0 && { favorites: incomingSettings.favorites }), actions: { ...globalSettings.actions, ...(incomingSettings.actions diff --git a/src/core/prompts/responses.ts b/src/core/prompts/responses.ts index 00c012bbb3..04d5b8e455 100644 --- a/src/core/prompts/responses.ts +++ b/src/core/prompts/responses.ts @@ -42,9 +42,6 @@ Otherwise, if you have not completed the task and do not need additional informa tooManyMistakes: (feedback?: string) => `You seem to be having trouble proceeding. The user has provided the following feedback to help guide you:\n\n${feedback}\n`, - autoApprovalMaxReached: (feedback?: string) => - `Auto-approval limit reached. The user has provided the following feedback to help guide you:\n\n${feedback}\n`, - missingToolParameterError: (paramName: string) => `Missing value for required parameter '${paramName}'. Please retry with complete response.\n\n${toolUseInstructionsReminder}`, diff --git a/src/core/task/TaskState.ts b/src/core/task/TaskState.ts index fdb44ae059..d234cd47b5 100644 --- a/src/core/task/TaskState.ts +++ b/src/core/task/TaskState.ts @@ -39,9 +39,6 @@ export class TaskState { didAlreadyUseTool = false didEditFile: boolean = false - // Consecutive request tracking - consecutiveAutoApprovedRequestsCount: number = 0 - // Error tracking consecutiveMistakeCount: number = 0 didAutomaticallyRetryFailedApiRequest = false diff --git a/src/core/task/index.ts b/src/core/task/index.ts index 3d5c17d3a0..e43cd60cec 100644 --- a/src/core/task/index.ts +++ b/src/core/task/index.ts @@ -497,10 +497,6 @@ export class Task { ) } - public resetConsecutiveAutoApprovedRequestsCount(): void { - this.taskState.consecutiveAutoApprovedRequestsCount = 0 - } - // Communicate with webview // partial has three valid states true (partial message), false (completion of partial message), undefined (individual complete message) @@ -1130,7 +1126,6 @@ export class Task { includeFileDetails = false // we only need file details the first time // The way this agentic loop works is that cline will be given a task that he then calls tools to complete. unless there's an attempt_completion call, we keep responding back to him with his tool's responses until he either attempt_completion or does not use anymore tools. If he does not use anymore tools, we ask him to consider if he's completed the task and then call attempt_completion, otherwise proceed with completing the task. - // There is a MAX_REQUESTS_PER_TASK limit to prevent infinite requests, but Cline is prompted to finish the task as efficiently as he can. //const totalCost = this.calculateApiCost(totalInputTokens, totalOutputTokens) if (didEndLoop) { @@ -2171,7 +2166,7 @@ export class Task { if (this.taskState.consecutiveMistakeCount >= this.stateManager.getGlobalSettingsKey("maxConsecutiveMistakes")) { const autoApprovalSettings = this.stateManager.getGlobalSettingsKey("autoApprovalSettings") - if (autoApprovalSettings.enabled && autoApprovalSettings.enableNotifications) { + if (autoApprovalSettings.enableNotifications) { showSystemNotification({ subtitle: "Error", message: "Cline is having trouble. Would you like to continue the task?", @@ -2215,57 +2210,6 @@ export class Task { this.taskState.autoRetryAttempts = 0 // need to reset this if the user chooses to manually retry after the mistake limit is reached } - const autoApprovalSettings = this.stateManager.getGlobalSettingsKey("autoApprovalSettings") - - if ( - !this.stateManager.getGlobalSettingsKey("yoloModeToggled") && - autoApprovalSettings.enabled && - this.taskState.consecutiveAutoApprovedRequestsCount >= autoApprovalSettings.maxRequests - ) { - if (autoApprovalSettings.enableNotifications) { - showSystemNotification({ - subtitle: "Max Requests Reached", - message: `Cline has auto-approved ${autoApprovalSettings.maxRequests.toString()} API requests.`, - }) - } - const { response, text, images, files } = await this.ask( - "auto_approval_max_req_reached", - `Cline has auto-approved ${autoApprovalSettings.maxRequests.toString()} API requests. Would you like to reset the count and proceed with the task?`, - ) - // if we get past the promise it means the user approved and did not start a new task - this.taskState.consecutiveAutoApprovedRequestsCount = 0 - - // Process user feedback if provided - if (response === "messageResponse") { - // Display the user's message in the chat UI - await this.say("user_feedback", text, images, files) - - // This userContent is for the *next* API call. - const feedbackUserContent: UserContent = [] - feedbackUserContent.push({ - type: "text", - text: formatResponse.autoApprovalMaxReached(text), - }) - if (images && images.length > 0) { - feedbackUserContent.push(...formatResponse.imageBlocks(images)) - } - - let fileContentString = "" - if (files && files.length > 0) { - fileContentString = await processFilesIntoText(files) - } - - if (fileContentString) { - feedbackUserContent.push({ - type: "text", - text: fileContentString, - }) - } - - userContent = feedbackUserContent - } - } - // get previous api req's index to check token usage and determine if we need to truncate conversation history const previousApiReqIndex = findLastIndex(this.messageStateHandler.getClineMessages(), (m) => m.say === "api_req_started") diff --git a/src/core/task/tools/autoApprove.ts b/src/core/task/tools/autoApprove.ts index f6d3092f84..4346a1cefc 100644 --- a/src/core/task/tools/autoApprove.ts +++ b/src/core/task/tools/autoApprove.ts @@ -62,30 +62,28 @@ export class AutoApprove { const autoApprovalSettings = this.stateManager.getGlobalSettingsKey("autoApprovalSettings") - if (autoApprovalSettings.enabled) { - switch (toolName) { - case ClineDefaultTool.FILE_READ: - case ClineDefaultTool.LIST_FILES: - case ClineDefaultTool.LIST_CODE_DEF: - case ClineDefaultTool.SEARCH: - return [autoApprovalSettings.actions.readFiles, autoApprovalSettings.actions.readFilesExternally ?? false] - case ClineDefaultTool.NEW_RULE: - case ClineDefaultTool.FILE_NEW: - case ClineDefaultTool.FILE_EDIT: - return [autoApprovalSettings.actions.editFiles, autoApprovalSettings.actions.editFilesExternally ?? false] - case ClineDefaultTool.BASH: - return [ - autoApprovalSettings.actions.executeSafeCommands ?? false, - autoApprovalSettings.actions.executeAllCommands ?? false, - ] - case ClineDefaultTool.BROWSER: - return autoApprovalSettings.actions.useBrowser - case ClineDefaultTool.WEB_FETCH: - return autoApprovalSettings.actions.useBrowser - case ClineDefaultTool.MCP_ACCESS: - case ClineDefaultTool.MCP_USE: - return autoApprovalSettings.actions.useMcp - } + switch (toolName) { + case ClineDefaultTool.FILE_READ: + case ClineDefaultTool.LIST_FILES: + case ClineDefaultTool.LIST_CODE_DEF: + case ClineDefaultTool.SEARCH: + return [autoApprovalSettings.actions.readFiles, autoApprovalSettings.actions.readFilesExternally ?? false] + case ClineDefaultTool.NEW_RULE: + case ClineDefaultTool.FILE_NEW: + case ClineDefaultTool.FILE_EDIT: + return [autoApprovalSettings.actions.editFiles, autoApprovalSettings.actions.editFilesExternally ?? false] + case ClineDefaultTool.BASH: + return [ + autoApprovalSettings.actions.executeSafeCommands ?? false, + autoApprovalSettings.actions.executeAllCommands ?? false, + ] + case ClineDefaultTool.BROWSER: + return autoApprovalSettings.actions.useBrowser + case ClineDefaultTool.WEB_FETCH: + return autoApprovalSettings.actions.useBrowser + case ClineDefaultTool.MCP_ACCESS: + case ClineDefaultTool.MCP_USE: + return autoApprovalSettings.actions.useMcp } return false } diff --git a/src/core/task/tools/handlers/AccessMcpResourceHandler.ts b/src/core/task/tools/handlers/AccessMcpResourceHandler.ts index da81517433..cdc3a285df 100644 --- a/src/core/task/tools/handlers/AccessMcpResourceHandler.ts +++ b/src/core/task/tools/handlers/AccessMcpResourceHandler.ts @@ -4,7 +4,7 @@ import { ClineAsk, ClineAskUseMcpServer } from "@shared/ExtensionMessage" import { telemetryService } from "@/services/telemetry" import { ClineDefaultTool } from "@/shared/tools" import type { ToolResponse } from "../../index" -import { showNotificationForApprovalIfAutoApprovalEnabled } from "../../utils" +import { showNotificationForApproval } from "../../utils" import type { IFullyManagedTool } from "../ToolExecutorCoordinator" import type { TaskConfig } from "../types/TaskConfig" import type { StronglyTypedUIHelpers } from "../types/UIHelpers" @@ -73,9 +73,6 @@ export class AccessMcpResourceHandler implements IFullyManagedTool { // Auto-approval flow await config.callbacks.removeLastPartialMessageIfExistsWithType("ask", "use_mcp_server") await config.callbacks.say("use_mcp_server", completeMessage, undefined, undefined, false) - if (!config.yoloModeToggled) { - config.taskState.consecutiveAutoApprovedRequestsCount++ - } // Capture telemetry telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, true, true) @@ -84,11 +81,7 @@ export class AccessMcpResourceHandler implements IFullyManagedTool { const notificationMessage = `Cline wants to access ${uri || "unknown resource"} on ${server_name || "unknown server"}` // Show notification - showNotificationForApprovalIfAutoApprovalEnabled( - notificationMessage, - config.autoApprovalSettings.enabled, - config.autoApprovalSettings.enableNotifications, - ) + showNotificationForApproval(notificationMessage, config.autoApprovalSettings.enableNotifications) await config.callbacks.removeLastPartialMessageIfExistsWithType("say", "use_mcp_server") diff --git a/src/core/task/tools/handlers/ApplyPatchHandler.ts b/src/core/task/tools/handlers/ApplyPatchHandler.ts index 45bdad4d4a..4306d6c306 100644 --- a/src/core/task/tools/handlers/ApplyPatchHandler.ts +++ b/src/core/task/tools/handlers/ApplyPatchHandler.ts @@ -9,7 +9,7 @@ import { telemetryService } from "@/services/telemetry" import { ClineDefaultTool } from "@/shared/tools" import { isLocatedInWorkspace } from "@/utils/path" import type { ToolResponse } from "../../index" -import { showNotificationForApprovalIfAutoApprovalEnabled } from "../../utils" +import { showNotificationForApproval } from "../../utils" import type { IFullyManagedTool } from "../ToolExecutorCoordinator" import type { ToolValidator } from "../ToolValidator" import type { TaskConfig } from "../types/TaskConfig" @@ -946,15 +946,13 @@ export class ApplyPatchHandler implements IFullyManagedTool { if (shouldAutoApprove) { await config.callbacks.say("tool", messageStr, undefined, undefined, false) - config.taskState.consecutiveAutoApprovedRequestsCount++ telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, true, true) return true } const fileCount = Object.keys(JSON.parse(messageStr).content.match(/\d+/)?.[0] || "0").length - showNotificationForApprovalIfAutoApprovalEnabled( + showNotificationForApproval( `Cline wants to apply a patch to ${fileCount} file(s)`, - config.autoApprovalSettings.enabled, config.autoApprovalSettings.enableNotifications, ) diff --git a/src/core/task/tools/handlers/AskFollowupQuestionToolHandler.ts b/src/core/task/tools/handlers/AskFollowupQuestionToolHandler.ts index 72938ba8ef..6918fb7dbd 100644 --- a/src/core/task/tools/handlers/AskFollowupQuestionToolHandler.ts +++ b/src/core/task/tools/handlers/AskFollowupQuestionToolHandler.ts @@ -40,8 +40,8 @@ export class AskFollowupQuestionToolHandler implements IToolHandler, IPartialBlo } config.taskState.consecutiveMistakeCount = 0 - // Show notification if auto-approval is enabled - if (config.autoApprovalSettings.enabled && config.autoApprovalSettings.enableNotifications) { + // Show notification if enabled + if (config.autoApprovalSettings.enableNotifications) { showSystemNotification({ subtitle: "Cline has a question...", message: question.replace(/\n/g, " "), diff --git a/src/core/task/tools/handlers/AttemptCompletionHandler.ts b/src/core/task/tools/handlers/AttemptCompletionHandler.ts index 335050bcde..1b33cee8c9 100644 --- a/src/core/task/tools/handlers/AttemptCompletionHandler.ts +++ b/src/core/task/tools/handlers/AttemptCompletionHandler.ts @@ -52,8 +52,8 @@ export class AttemptCompletionHandler implements IToolHandler, IPartialBlockHand config.taskState.consecutiveMistakeCount = 0 - // Show notification if auto-approval is enabled - if (config.autoApprovalSettings.enabled && config.autoApprovalSettings.enableNotifications) { + // Show notification if enabled + if (config.autoApprovalSettings.enableNotifications) { showSystemNotification({ subtitle: "Task Completed", message: result.replace(/\n/g, " "), diff --git a/src/core/task/tools/handlers/BrowserToolHandler.ts b/src/core/task/tools/handlers/BrowserToolHandler.ts index 51477876b4..7803a90c8c 100644 --- a/src/core/task/tools/handlers/BrowserToolHandler.ts +++ b/src/core/task/tools/handlers/BrowserToolHandler.ts @@ -3,7 +3,7 @@ import { ClineDefaultTool } from "@/shared/tools" import { ToolUse } from "../../../assistant-message" import { formatResponse } from "../../../prompts/responses" import { ToolResponse } from "../.." -import { showNotificationForApprovalIfAutoApprovalEnabled } from "../../utils" +import { showNotificationForApproval } from "../../utils" import type { IFullyManagedTool } from "../ToolExecutorCoordinator" import type { TaskConfig } from "../types/TaskConfig" import type { StronglyTypedUIHelpers } from "../types/UIHelpers" @@ -92,14 +92,10 @@ export class BrowserToolHandler implements IFullyManagedTool { if (autoApprover.shouldAutoApproveTool(block.name)) { await config.callbacks.removeLastPartialMessageIfExistsWithType("ask", "browser_action_launch") await config.callbacks.say("browser_action_launch", url, undefined, undefined, false) - if (!config.yoloModeToggled) { - config.taskState.consecutiveAutoApprovedRequestsCount++ - } } else { - // Show notification for approval if auto approval enabled - showNotificationForApprovalIfAutoApprovalEnabled( + // Show notification for approval if enabled + showNotificationForApproval( `Cline wants to use a browser and launch ${url}`, - config.autoApprovalSettings.enabled, config.autoApprovalSettings.enableNotifications, ) await config.callbacks.removeLastPartialMessageIfExistsWithType("say", "browser_action_launch") diff --git a/src/core/task/tools/handlers/CondenseHandler.ts b/src/core/task/tools/handlers/CondenseHandler.ts index 0794aef07f..acfd777525 100644 --- a/src/core/task/tools/handlers/CondenseHandler.ts +++ b/src/core/task/tools/handlers/CondenseHandler.ts @@ -30,8 +30,8 @@ export class CondenseHandler implements IToolHandler, IPartialBlockHandler { config.taskState.consecutiveMistakeCount = 0 - // Show notification if auto-approval is enabled - if (config.autoApprovalSettings.enabled && config.autoApprovalSettings.enableNotifications) { + // Show notification if enabled + if (config.autoApprovalSettings.enableNotifications) { showSystemNotification({ subtitle: "Cline wants to condense the conversation...", message: `Cline is suggesting to condense your conversation with: ${context}`, diff --git a/src/core/task/tools/handlers/ExecuteCommandToolHandler.ts b/src/core/task/tools/handlers/ExecuteCommandToolHandler.ts index 4e6702ff75..40eb248c9d 100644 --- a/src/core/task/tools/handlers/ExecuteCommandToolHandler.ts +++ b/src/core/task/tools/handlers/ExecuteCommandToolHandler.ts @@ -9,7 +9,7 @@ import { fixModelHtmlEscaping } from "@utils/string" import { telemetryService } from "@/services/telemetry" import { ClineDefaultTool } from "@/shared/tools" import type { ToolResponse } from "../../index" -import { showNotificationForApprovalIfAutoApprovalEnabled } from "../../utils" +import { showNotificationForApproval } from "../../utils" import type { IFullyManagedTool } from "../ToolExecutorCoordinator" import type { ToolValidator } from "../ToolValidator" import type { TaskConfig } from "../types/TaskConfig" @@ -153,16 +153,12 @@ export class ExecuteCommandToolHandler implements IFullyManagedTool { // Auto-approve flow await config.callbacks.removeLastPartialMessageIfExistsWithType("ask", "command") await config.callbacks.say("command", actualCommand, undefined, undefined, false) - if (!config.yoloModeToggled) { - config.taskState.consecutiveAutoApprovedRequestsCount++ - } didAutoApprove = true telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, true, true, workspaceContext) } else { // Manual approval flow - showNotificationForApprovalIfAutoApprovalEnabled( + showNotificationForApproval( `Cline wants to execute a command: ${actualCommand}`, - config.autoApprovalSettings.enabled, config.autoApprovalSettings.enableNotifications, ) diff --git a/src/core/task/tools/handlers/ListCodeDefinitionNamesToolHandler.ts b/src/core/task/tools/handlers/ListCodeDefinitionNamesToolHandler.ts index 68591f46c1..940219179e 100644 --- a/src/core/task/tools/handlers/ListCodeDefinitionNamesToolHandler.ts +++ b/src/core/task/tools/handlers/ListCodeDefinitionNamesToolHandler.ts @@ -6,7 +6,7 @@ import { formatResponse } from "@/core/prompts/responses" import { telemetryService } from "@/services/telemetry" import { ClineDefaultTool } from "@/shared/tools" import type { ToolResponse } from "../../index" -import { showNotificationForApprovalIfAutoApprovalEnabled } from "../../utils" +import { showNotificationForApproval } from "../../utils" import type { IFullyManagedTool } from "../ToolExecutorCoordinator" import type { ToolValidator } from "../ToolValidator" import type { TaskConfig } from "../types/TaskConfig" @@ -81,9 +81,6 @@ export class ListCodeDefinitionNamesToolHandler implements IFullyManagedTool { // Auto-approval flow await config.callbacks.removeLastPartialMessageIfExistsWithType("ask", "tool") await config.callbacks.say("tool", completeMessage, undefined, undefined, false) - if (!config.yoloModeToggled) { - config.taskState.consecutiveAutoApprovedRequestsCount++ - } // Capture telemetry telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, true, true) @@ -92,11 +89,7 @@ export class ListCodeDefinitionNamesToolHandler implements IFullyManagedTool { const notificationMessage = `Cline wants to analyze code definitions in ${getWorkspaceBasename(absolutePath, "ListCodeDefinitionNamesToolHandler.notification")}` // Show notification - showNotificationForApprovalIfAutoApprovalEnabled( - notificationMessage, - config.autoApprovalSettings.enabled, - config.autoApprovalSettings.enableNotifications, - ) + showNotificationForApproval(notificationMessage, config.autoApprovalSettings.enableNotifications) await config.callbacks.removeLastPartialMessageIfExistsWithType("say", "tool") diff --git a/src/core/task/tools/handlers/ListFilesToolHandler.ts b/src/core/task/tools/handlers/ListFilesToolHandler.ts index 33b865ddb5..aa51cc690d 100644 --- a/src/core/task/tools/handlers/ListFilesToolHandler.ts +++ b/src/core/task/tools/handlers/ListFilesToolHandler.ts @@ -7,7 +7,7 @@ import { arePathsEqual, getReadablePath, isLocatedInWorkspace } from "@utils/pat import { telemetryService } from "@/services/telemetry" import { ClineDefaultTool } from "@/shared/tools" import type { ToolResponse } from "../../index" -import { showNotificationForApprovalIfAutoApprovalEnabled } from "../../utils" +import { showNotificationForApproval } from "../../utils" import type { IFullyManagedTool } from "../ToolExecutorCoordinator" import type { ToolValidator } from "../ToolValidator" import type { TaskConfig } from "../types/TaskConfig" @@ -98,9 +98,6 @@ export class ListFilesToolHandler implements IFullyManagedTool { // Auto-approval flow await config.callbacks.removeLastPartialMessageIfExistsWithType("ask", "tool") await config.callbacks.say("tool", completeMessage, undefined, undefined, false) - if (!config.yoloModeToggled) { - config.taskState.consecutiveAutoApprovedRequestsCount++ - } // Capture telemetry telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, true, true, workspaceContext) @@ -109,11 +106,7 @@ export class ListFilesToolHandler implements IFullyManagedTool { const notificationMessage = `Cline wants to view directory ${getWorkspaceBasename(absolutePath, "ListFilesToolHandler.notification")}/` // Show notification - showNotificationForApprovalIfAutoApprovalEnabled( - notificationMessage, - config.autoApprovalSettings.enabled, - config.autoApprovalSettings.enableNotifications, - ) + showNotificationForApproval(notificationMessage, config.autoApprovalSettings.enableNotifications) await config.callbacks.removeLastPartialMessageIfExistsWithType("say", "tool") diff --git a/src/core/task/tools/handlers/NewTaskHandler.ts b/src/core/task/tools/handlers/NewTaskHandler.ts index 6a0906bd64..fc6029b80f 100644 --- a/src/core/task/tools/handlers/NewTaskHandler.ts +++ b/src/core/task/tools/handlers/NewTaskHandler.ts @@ -35,8 +35,8 @@ export class NewTaskHandler implements IToolHandler, IPartialBlockHandler { config.taskState.consecutiveMistakeCount = 0 - // Show notification if auto-approval is enabled - if (config.autoApprovalSettings.enabled && config.autoApprovalSettings.enableNotifications) { + // Show notification if enabled + if (config.autoApprovalSettings.enableNotifications) { showSystemNotification({ subtitle: "Cline wants to start a new task...", message: `Cline is suggesting to start a new task with: ${context}`, diff --git a/src/core/task/tools/handlers/ReadFileToolHandler.ts b/src/core/task/tools/handlers/ReadFileToolHandler.ts index 8033724a1a..46ce1b2d18 100644 --- a/src/core/task/tools/handlers/ReadFileToolHandler.ts +++ b/src/core/task/tools/handlers/ReadFileToolHandler.ts @@ -8,7 +8,7 @@ import { telemetryService } from "@/services/telemetry" import { ClineSayTool } from "@/shared/ExtensionMessage" import { ClineDefaultTool } from "@/shared/tools" import type { ToolResponse } from "../../index" -import { showNotificationForApprovalIfAutoApprovalEnabled } from "../../utils" +import { showNotificationForApproval } from "../../utils" import type { IFullyManagedTool } from "../ToolExecutorCoordinator" import type { ToolValidator } from "../ToolValidator" import type { TaskConfig } from "../types/TaskConfig" @@ -96,9 +96,6 @@ export class ReadFileToolHandler implements IFullyManagedTool { // Auto-approval flow await config.callbacks.removeLastPartialMessageIfExistsWithType("ask", "tool") await config.callbacks.say("tool", completeMessage, undefined, undefined, false) - if (!config.yoloModeToggled) { - config.taskState.consecutiveAutoApprovedRequestsCount++ - } // Capture telemetry telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, true, true, workspaceContext) @@ -107,11 +104,7 @@ export class ReadFileToolHandler implements IFullyManagedTool { const notificationMessage = `Cline wants to read ${getWorkspaceBasename(absolutePath, "ReadFileToolHandler.notification")}` // Show notification - showNotificationForApprovalIfAutoApprovalEnabled( - notificationMessage, - config.autoApprovalSettings.enabled, - config.autoApprovalSettings.enableNotifications, - ) + showNotificationForApproval(notificationMessage, config.autoApprovalSettings.enableNotifications) await config.callbacks.removeLastPartialMessageIfExistsWithType("say", "tool") diff --git a/src/core/task/tools/handlers/ReportBugHandler.ts b/src/core/task/tools/handlers/ReportBugHandler.ts index 161fa150aa..9cc31ae588 100644 --- a/src/core/task/tools/handlers/ReportBugHandler.ts +++ b/src/core/task/tools/handlers/ReportBugHandler.ts @@ -64,8 +64,8 @@ export class ReportBugHandler implements IToolHandler, IPartialBlockHandler { config.taskState.consecutiveMistakeCount = 0 - // Show notification if auto-approval is enabled - if (config.autoApprovalSettings.enabled && config.autoApprovalSettings.enableNotifications) { + // Show notification if enabled + if (config.autoApprovalSettings.enableNotifications) { showSystemNotification({ subtitle: "Cline wants to create a github issue...", message: `Cline is suggesting to create a github issue with the title: ${title}`, diff --git a/src/core/task/tools/handlers/SearchFilesToolHandler.ts b/src/core/task/tools/handlers/SearchFilesToolHandler.ts index 0bf6ba82ad..26f3d1328e 100644 --- a/src/core/task/tools/handlers/SearchFilesToolHandler.ts +++ b/src/core/task/tools/handlers/SearchFilesToolHandler.ts @@ -10,7 +10,7 @@ import { telemetryService } from "@/services/telemetry" import { ClineSayTool } from "@/shared/ExtensionMessage" import { ClineDefaultTool } from "@/shared/tools" import type { ToolResponse } from "../../index" -import { showNotificationForApprovalIfAutoApprovalEnabled } from "../../utils" +import { showNotificationForApproval } from "../../utils" import type { IFullyManagedTool } from "../ToolExecutorCoordinator" import type { ToolValidator } from "../ToolValidator" import type { TaskConfig } from "../types/TaskConfig" @@ -304,9 +304,6 @@ export class SearchFilesToolHandler implements IFullyManagedTool { // Auto-approval flow await config.callbacks.removeLastPartialMessageIfExistsWithType("ask", "tool") await config.callbacks.say("tool", completeMessage, undefined, undefined, false) - if (!config.yoloModeToggled) { - config.taskState.consecutiveAutoApprovedRequestsCount++ - } // Capture telemetry telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, true, true, workspaceContext) @@ -315,11 +312,7 @@ export class SearchFilesToolHandler implements IFullyManagedTool { const notificationMessage = `Cline wants to search files for ${regex}` // Show notification - showNotificationForApprovalIfAutoApprovalEnabled( - notificationMessage, - config.autoApprovalSettings.enabled, - config.autoApprovalSettings.enableNotifications, - ) + showNotificationForApproval(notificationMessage, config.autoApprovalSettings.enableNotifications) await config.callbacks.removeLastPartialMessageIfExistsWithType("say", "tool") diff --git a/src/core/task/tools/handlers/SummarizeTaskHandler.ts b/src/core/task/tools/handlers/SummarizeTaskHandler.ts index 530986bbc6..8fc1ee0b58 100644 --- a/src/core/task/tools/handlers/SummarizeTaskHandler.ts +++ b/src/core/task/tools/handlers/SummarizeTaskHandler.ts @@ -102,9 +102,6 @@ export class SummarizeTaskHandler implements IToolHandler, IPartialBlockHandler const { absolutePath, displayPath } = typeof pathResult === "string" ? { absolutePath: pathResult, displayPath: relPath } : pathResult - // Increment counter for successful auto-approved read - config.taskState.consecutiveAutoApprovedRequestsCount++ - // Read file content, we dont allow images to be read here // This throws if an image or if we can't read the file, implicitly skipping const fileContent = await extractFileContent(absolutePath, false) diff --git a/src/core/task/tools/handlers/UseMcpToolHandler.ts b/src/core/task/tools/handlers/UseMcpToolHandler.ts index 4e7f566ddd..226711fd0d 100644 --- a/src/core/task/tools/handlers/UseMcpToolHandler.ts +++ b/src/core/task/tools/handlers/UseMcpToolHandler.ts @@ -4,7 +4,7 @@ import { ClineAsk, ClineAskUseMcpServer } from "@shared/ExtensionMessage" import { telemetryService } from "@/services/telemetry" import { ClineDefaultTool } from "@/shared/tools" import type { ToolResponse } from "../../index" -import { showNotificationForApprovalIfAutoApprovalEnabled } from "../../utils" +import { showNotificationForApproval } from "../../utils" import type { IFullyManagedTool } from "../ToolExecutorCoordinator" import type { TaskConfig } from "../types/TaskConfig" import type { StronglyTypedUIHelpers } from "../types/UIHelpers" @@ -88,9 +88,6 @@ export class UseMcpToolHandler implements IFullyManagedTool { // Auto-approval flow await config.callbacks.removeLastPartialMessageIfExistsWithType("ask", "use_mcp_server") await config.callbacks.say("use_mcp_server", completeMessage, undefined, undefined, false) - if (!config.yoloModeToggled) { - config.taskState.consecutiveAutoApprovedRequestsCount++ - } // Capture telemetry telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, true, true) @@ -99,11 +96,7 @@ export class UseMcpToolHandler implements IFullyManagedTool { const notificationMessage = `Cline wants to use ${tool_name || "unknown tool"} on ${server_name || "unknown server"}` // Show notification - showNotificationForApprovalIfAutoApprovalEnabled( - notificationMessage, - config.autoApprovalSettings.enabled, - config.autoApprovalSettings.enableNotifications, - ) + showNotificationForApproval(notificationMessage, config.autoApprovalSettings.enableNotifications) await config.callbacks.removeLastPartialMessageIfExistsWithType("say", "use_mcp_server") diff --git a/src/core/task/tools/handlers/WebFetchToolHandler.ts b/src/core/task/tools/handlers/WebFetchToolHandler.ts index 4ce8b85324..50a1785c60 100644 --- a/src/core/task/tools/handlers/WebFetchToolHandler.ts +++ b/src/core/task/tools/handlers/WebFetchToolHandler.ts @@ -5,7 +5,7 @@ import { telemetryService } from "@/services/telemetry" import { ToolUse } from "../../../assistant-message" import { formatResponse } from "../../../prompts/responses" import { ToolResponse } from "../.." -import { showNotificationForApprovalIfAutoApprovalEnabled } from "../../utils" +import { showNotificationForApproval } from "../../utils" import type { IFullyManagedTool } from "../ToolExecutorCoordinator" import type { TaskConfig } from "../types/TaskConfig" import type { StronglyTypedUIHelpers } from "../types/UIHelpers" @@ -59,15 +59,11 @@ export class WebFetchToolHandler implements IFullyManagedTool { // Auto-approve flow await config.callbacks.removeLastPartialMessageIfExistsWithType("ask", "tool") await config.callbacks.say("tool", completeMessage, undefined, undefined, false) - if (!config.yoloModeToggled) { - config.taskState.consecutiveAutoApprovedRequestsCount++ - } telemetryService.captureToolUsage(config.ulid, "web_fetch", config.api.getModel().id, true, true) } else { // Manual approval flow - showNotificationForApprovalIfAutoApprovalEnabled( + showNotificationForApproval( `Cline wants to fetch content from ${url}`, - config.autoApprovalSettings.enabled, config.autoApprovalSettings.enableNotifications, ) await config.callbacks.removeLastPartialMessageIfExistsWithType("say", "tool") diff --git a/src/core/task/tools/handlers/WriteToFileToolHandler.ts b/src/core/task/tools/handlers/WriteToFileToolHandler.ts index 247ea497bf..1ef49fb380 100644 --- a/src/core/task/tools/handlers/WriteToFileToolHandler.ts +++ b/src/core/task/tools/handlers/WriteToFileToolHandler.ts @@ -12,7 +12,7 @@ import { fixModelHtmlEscaping, removeInvalidChars } from "@utils/string" import { telemetryService } from "@/services/telemetry" import { ClineDefaultTool } from "@/shared/tools" import type { ToolResponse } from "../../index" -import { showNotificationForApprovalIfAutoApprovalEnabled } from "../../utils" +import { showNotificationForApproval } from "../../utils" import type { IFullyManagedTool } from "../ToolExecutorCoordinator" import type { ToolValidator } from "../ToolValidator" import type { TaskConfig } from "../types/TaskConfig" @@ -167,9 +167,6 @@ export class WriteToFileToolHandler implements IFullyManagedTool { // Auto-approval flow await config.callbacks.removeLastPartialMessageIfExistsWithType("ask", "tool") await config.callbacks.say("tool", completeMessage, undefined, undefined, false) - if (!config.yoloModeToggled) { - config.taskState.consecutiveAutoApprovedRequestsCount++ - } // Capture telemetry telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, true, true, workspaceContext) @@ -181,11 +178,7 @@ export class WriteToFileToolHandler implements IFullyManagedTool { const notificationMessage = `Cline wants to ${fileExists ? "edit" : "create"} ${getWorkspaceBasename(relPath, "WriteToFile.notification")}` // Show notification - showNotificationForApprovalIfAutoApprovalEnabled( - notificationMessage, - config.autoApprovalSettings.enabled, - config.autoApprovalSettings.enableNotifications, - ) + showNotificationForApproval(notificationMessage, config.autoApprovalSettings.enableNotifications) await config.callbacks.removeLastPartialMessageIfExistsWithType("say", "tool") diff --git a/src/core/task/tools/types/UIHelpers.ts b/src/core/task/tools/types/UIHelpers.ts index b93ccde7e3..78935debfc 100644 --- a/src/core/task/tools/types/UIHelpers.ts +++ b/src/core/task/tools/types/UIHelpers.ts @@ -3,7 +3,7 @@ import type { ClineDefaultTool } from "@shared/tools" import type { ClineAskResponse } from "@shared/WebviewMessage" import { telemetryService } from "@/services/telemetry" import type { ToolParamName, ToolUse } from "../../../assistant-message" -import { showNotificationForApprovalIfAutoApprovalEnabled } from "../../utils" +import { showNotificationForApproval } from "../../utils" import { removeClosingTag } from "../utils/ToolConstants" import type { TaskConfig } from "./TaskConfig" @@ -61,11 +61,7 @@ export function createUIHelpers(config: TaskConfig): StronglyTypedUIHelpers { telemetryService.captureToolUsage(config.ulid, toolName, config.api.getModel().id, autoApproved, approved) }, showNotificationIfEnabled: (message: string) => { - showNotificationForApprovalIfAutoApprovalEnabled( - message, - config.autoApprovalSettings.enabled, - config.autoApprovalSettings.enableNotifications, - ) + showNotificationForApproval(message, config.autoApprovalSettings.enableNotifications) }, getConfig: () => config, } diff --git a/src/core/task/utils.ts b/src/core/task/utils.ts index 3b97f0934e..d28c01e6bd 100644 --- a/src/core/task/utils.ts +++ b/src/core/task/utils.ts @@ -5,12 +5,8 @@ import { ClineApiReqCancelReason, ClineApiReqInfo } from "@/shared/ExtensionMess import { calculateApiCostAnthropic } from "@/utils/cost" import { MessageStateHandler } from "./message-state" -export const showNotificationForApprovalIfAutoApprovalEnabled = ( - message: string, - autoApprovalSettingsEnabled: boolean, - notificationsEnabled: boolean, -) => { - if (autoApprovalSettingsEnabled && notificationsEnabled) { +export const showNotificationForApproval = (message: string, notificationsEnabled: boolean) => { + if (notificationsEnabled) { showSystemNotification({ subtitle: "Approval Required", message, diff --git a/src/services/test/TestServer.ts b/src/services/test/TestServer.ts index 726aa8a705..7c9e928970 100644 --- a/src/services/test/TestServer.ts +++ b/src/services/test/TestServer.ts @@ -54,7 +54,6 @@ async function updateAutoApprovalSettings(controller?: Controller) { // Enable all actions const updatedSettings: AutoApprovalSettings = { ...(autoApprovalSettings || DEFAULT_AUTO_APPROVAL_SETTINGS), - enabled: true, actions: { readFiles: true, readFilesExternally: true, @@ -65,7 +64,6 @@ async function updateAutoApprovalSettings(controller?: Controller) { useBrowser: false, // Keep browser disabled for tests useMcp: false, // Keep MCP disabled for tests }, - maxRequests: 10000, // Increase max requests for tests } controller?.stateManager.setGlobalState("autoApprovalSettings", updatedSettings) diff --git a/src/shared/AutoApprovalSettings.ts b/src/shared/AutoApprovalSettings.ts index dc667df32f..7ea185e231 100644 --- a/src/shared/AutoApprovalSettings.ts +++ b/src/shared/AutoApprovalSettings.ts @@ -1,8 +1,15 @@ export interface AutoApprovalSettings { // Version for race condition prevention (incremented on every change) version: number - // Whether auto-approval is enabled + // Legacy field - kept for backward compatibility with older extension versions + // Auto-approve is now always enabled by default enabled: boolean + // Legacy field - kept for backward compatibility with older extension versions + // Favorites feature has been removed + favorites: string[] + // Legacy field - kept for backward compatibility with older extension versions + // Max requests limit feature has been removed + maxRequests: number // Individual action permissions actions: { readFiles: boolean // Read files and directories in the working directory @@ -15,14 +22,14 @@ export interface AutoApprovalSettings { useMcp: boolean // Use MCP servers } // Global settings - maxRequests: number // Maximum number of auto-approved requests enableNotifications: boolean // Show notifications for approval and task completion - favorites: string[] // IDs of actions favorited by the user for quick access } export const DEFAULT_AUTO_APPROVAL_SETTINGS: AutoApprovalSettings = { version: 1, - enabled: true, + enabled: true, // Legacy field - always true by default + favorites: [], // Legacy field - kept as empty array + maxRequests: 20, // Legacy field - kept for backward compatibility actions: { readFiles: true, readFilesExternally: false, @@ -31,9 +38,7 @@ export const DEFAULT_AUTO_APPROVAL_SETTINGS: AutoApprovalSettings = { executeSafeCommands: true, executeAllCommands: false, useBrowser: false, - useMcp: false, + useMcp: true, }, - maxRequests: 20, enableNotifications: false, - favorites: ["enableAutoApprove", "readFiles", "editFiles"], } diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index 3d442d5fcb..d69cc7b7b0 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -128,7 +128,6 @@ export type ClineAsk = | "resume_task" | "resume_completed_task" | "mistake_limit_reached" - | "auto_approval_max_req_reached" | "browser_action_launch" | "use_mcp_server" | "new_task" diff --git a/src/shared/proto-conversions/cline-message.ts b/src/shared/proto-conversions/cline-message.ts index 4f04bcbda2..33fdb751a9 100644 --- a/src/shared/proto-conversions/cline-message.ts +++ b/src/shared/proto-conversions/cline-message.ts @@ -19,7 +19,6 @@ function convertClineAskToProtoEnum(ask: AppClineAsk | undefined): ClineAsk | un resume_task: ClineAsk.RESUME_TASK, resume_completed_task: ClineAsk.RESUME_COMPLETED_TASK, mistake_limit_reached: ClineAsk.MISTAKE_LIMIT_REACHED, - auto_approval_max_req_reached: ClineAsk.AUTO_APPROVAL_MAX_REQ_REACHED, browser_action_launch: ClineAsk.BROWSER_ACTION_LAUNCH, use_mcp_server: ClineAsk.USE_MCP_SERVER, new_task: ClineAsk.NEW_TASK, @@ -53,7 +52,6 @@ function convertProtoEnumToClineAsk(ask: ClineAsk): AppClineAsk | undefined { [ClineAsk.RESUME_TASK]: "resume_task", [ClineAsk.RESUME_COMPLETED_TASK]: "resume_completed_task", [ClineAsk.MISTAKE_LIMIT_REACHED]: "mistake_limit_reached", - [ClineAsk.AUTO_APPROVAL_MAX_REQ_REACHED]: "auto_approval_max_req_reached", [ClineAsk.BROWSER_ACTION_LAUNCH]: "browser_action_launch", [ClineAsk.USE_MCP_SERVER]: "use_mcp_server", [ClineAsk.NEW_TASK]: "new_task", diff --git a/webview-ui/src/App.stories.tsx b/webview-ui/src/App.stories.tsx index 4ea183b6c4..7699a7ff31 100644 --- a/webview-ui/src/App.stories.tsx +++ b/webview-ui/src/App.stories.tsx @@ -400,8 +400,6 @@ export const AutoApprovalEnabled: Story = { autoApprovalSettings: { ...DEFAULT_AUTO_APPROVAL_SETTINGS, enabled: true, - maxRequestsPerTask: 10, - maxRequestsPerHour: 50, }, }), ], @@ -626,13 +624,6 @@ export const NewTaskWithContext = quickStory( "Start a new task with the current conversation context", "Shows new task creation with context preservation option.", ) -export const AutoApprovalMaxReached = quickStory( - "Auto-approval Limit", - "auto_approval_max_req_reached", - "Cline has auto-approved 5 API requests. Would you like to reset the count and proceed with the task?", - "Shows auto-approval limit reached state with Proceed/Start New Task options.", - "Cline has auto-approved 5 API requests. Would you like to reset the count and proceed with the task?", -) export const ApiRequestActive: Story = { decorators: [ createStoryDecorator({ diff --git a/webview-ui/src/components/chat/ChatRow.tsx b/webview-ui/src/components/chat/ChatRow.tsx index 79ca4332ca..1ebdd559af 100644 --- a/webview-ui/src/components/chat/ChatRow.tsx +++ b/webview-ui/src/components/chat/ChatRow.tsx @@ -396,16 +396,6 @@ export const ChatRowContent = memo( }}>, Cline is having trouble..., ] - case "auto_approval_max_req_reached": - return [ - , - Maximum Requests Reached, - ] case "command": return [ - case "auto_approval_max_req_reached": - return case "completion_result": if (message.text) { const hasChanges = message.text.endsWith(COMPLETION_RESULT_CHANGES_FLAG) ?? false diff --git a/webview-ui/src/components/chat/ErrorRow.stories.tsx b/webview-ui/src/components/chat/ErrorRow.stories.tsx index c4ddee86fe..5db70cfd59 100644 --- a/webview-ui/src/components/chat/ErrorRow.stories.tsx +++ b/webview-ui/src/components/chat/ErrorRow.stories.tsx @@ -71,7 +71,7 @@ export const Default: Story = { argTypes: { errorType: { control: { type: "select" }, - options: ["error", "mistake_limit_reached", "auto_approval_max_req_reached", "diff_error", "clineignore_error"], + options: ["error", "mistake_limit_reached", "diff_error", "clineignore_error"], description: "Type of error to display", }, message: { diff --git a/webview-ui/src/components/chat/ErrorRow.test.tsx b/webview-ui/src/components/chat/ErrorRow.test.tsx index 1a81d09fcb..92679e9a04 100644 --- a/webview-ui/src/components/chat/ErrorRow.test.tsx +++ b/webview-ui/src/components/chat/ErrorRow.test.tsx @@ -54,13 +54,6 @@ describe("ErrorRow", () => { expect(screen.getByText("Mistake limit reached")).toBeInTheDocument() }) - it("renders auto approval max requests error", () => { - const maxReqMessage = { ...mockMessage, text: "Max requests reached" } - render() - - expect(screen.getByText("Max requests reached")).toBeInTheDocument() - }) - it("renders diff error", () => { render() diff --git a/webview-ui/src/components/chat/ErrorRow.tsx b/webview-ui/src/components/chat/ErrorRow.tsx index d3d12e1f0d..22b73dba43 100644 --- a/webview-ui/src/components/chat/ErrorRow.tsx +++ b/webview-ui/src/components/chat/ErrorRow.tsx @@ -9,7 +9,7 @@ const _errorColor = "var(--vscode-errorForeground)" interface ErrorRowProps { message: ClineMessage - errorType: "error" | "mistake_limit_reached" | "auto_approval_max_req_reached" | "diff_error" | "clineignore_error" + errorType: "error" | "mistake_limit_reached" | "diff_error" | "clineignore_error" apiRequestFailedMessage?: string apiReqStreamingFailedMessage?: string } @@ -21,7 +21,6 @@ const ErrorRow = memo(({ message, errorType, apiRequestFailedMessage, apiReqStre switch (errorType) { case "error": case "mistake_limit_reached": - case "auto_approval_max_req_reached": // Handle API request errors with special error parsing if (apiRequestFailedMessage || apiReqStreamingFailedMessage) { // FIXME: ClineError parsing should not be applied to non-Cline providers, but it seems we're using clineErrorMessage below in the default error display diff --git a/webview-ui/src/components/chat/auto-approve-menu/AutoApproveBar.tsx b/webview-ui/src/components/chat/auto-approve-menu/AutoApproveBar.tsx index d01847c397..ae47d29925 100644 --- a/webview-ui/src/components/chat/auto-approve-menu/AutoApproveBar.tsx +++ b/webview-ui/src/components/chat/auto-approve-menu/AutoApproveBar.tsx @@ -1,47 +1,40 @@ -import { useMemo, useRef, useState } from "react" -import { CODE_BLOCK_BG_COLOR } from "@/components/common/CodeBlock" +import { StringRequest } from "@shared/proto/cline/common" +import { useRef, useState } from "react" import { useExtensionState } from "@/context/ExtensionStateContext" -import { useAutoApproveActions } from "@/hooks/useAutoApproveActions" +import { UiServiceClient } from "@/services/grpc-client" import { getAsVar, VSC_TITLEBAR_INACTIVE_FOREGROUND } from "@/utils/vscStyles" -import AutoApproveMenuItem from "./AutoApproveMenuItem" import AutoApproveModal from "./AutoApproveModal" -import { ACTION_METADATA, NOTIFICATIONS_SETTING } from "./constants" +import { ACTION_METADATA } from "./constants" interface AutoApproveBarProps { style?: React.CSSProperties } const AutoApproveBar = ({ style }: AutoApproveBarProps) => { - const { autoApprovalSettings } = useExtensionState() - const { isChecked, isFavorited, updateAction } = useAutoApproveActions() + const { autoApprovalSettings, yoloModeToggled, navigateToSettings } = useExtensionState() const [isModalVisible, setIsModalVisible] = useState(false) const buttonRef = useRef(null) - const favorites = useMemo(() => autoApprovalSettings.favorites || [], [autoApprovalSettings.favorites]) + const handleNavigateToFeatures = async (e: React.MouseEvent) => { + e.preventDefault() + e.stopPropagation() - // Render a favorited item with a checkbox - const renderFavoritedItem = (favId: string) => { - const actions = [...ACTION_METADATA.flatMap((a) => [a, a.subAction]), NOTIFICATIONS_SETTING] - const action = actions.find((a) => a?.id === favId) - if (!action) { - return null - } + navigateToSettings() - return ( - - ) + setTimeout(async () => { + try { + await UiServiceClient.scrollToSettings(StringRequest.create({ value: "features" })) + } catch (error) { + console.error("Error scrolling to features settings:", error) + } + }, 300) } - const getQuickAccessItems = () => { - const notificationsEnabled = autoApprovalSettings.enableNotifications + const getEnabledActionsText = () => { + const baseClasses = isModalVisible + ? "text-foreground truncate" + : "text-muted-foreground group-hover:text-foreground truncate" const enabledActionsNames = Object.keys(autoApprovalSettings.actions).filter( (key) => autoApprovalSettings.actions[key as keyof typeof autoApprovalSettings.actions], ) @@ -49,51 +42,126 @@ const AutoApproveBar = ({ style }: AutoApproveBarProps) => { return ACTION_METADATA.flatMap((a) => [a, a.subAction]).find((a) => a?.id === action) }) - const minusFavorites = enabledActions.filter((action) => !favorites.includes(action?.id ?? "") && action?.shortName) + // Filter out parent actions if their subaction is also enabled (show only subaction) + const actionsToShow = enabledActions.filter((action) => { + if (!action?.shortName) { + return false + } - if (notificationsEnabled) { - minusFavorites.push(NOTIFICATIONS_SETTING) + // If this is a parent action and its subaction is enabled, skip it + if (action.subAction?.id && enabledActionsNames.includes(action.subAction.id)) { + return false + } + + return true + }) + + if (actionsToShow.length === 0) { + return None } - return [ - ...favorites.map((favId) => renderFavoritedItem(favId)), - minusFavorites.length > 0 ? ( - - ✓ - - ) : null, - ...minusFavorites.map((action, index) => ( - - {action?.shortName} - {index < minusFavorites.length - 1 && ","} - - )), - ] + return ( + + {actionsToShow.map((action, index) => ( + + {action?.shortName} + {index < actionsToShow.length - 1 && ", "} + + ))} + + ) + } + + const borderColor = `color-mix(in srgb, ${getAsVar(VSC_TITLEBAR_INACTIVE_FOREGROUND)} 20%, transparent)` + const borderGradient = `linear-gradient(to bottom, ${borderColor} 0%, transparent 50%)` + const bgGradient = `linear-gradient(to bottom, color-mix(in srgb, var(--vscode-sideBar-background) 96%, white) 0%, transparent 80%)` + + // If YOLO mode is enabled, show disabled message + if (yoloModeToggled) { + return ( +
+ {/* Left border gradient */} +
+ {/* Right border gradient */} +
+ +
+
Auto-approve: YOLO
+
+ YOLO mode is enabled.{" "} + + Disable it in Settings + + . +
+
+
+ ) } return (
+ {/* Left border gradient */}
+ {/* Right border gradient */} +
+ +
{ setIsModalVisible((prev) => !prev) }} ref={buttonRef}> -
- Auto-approve: - {getQuickAccessItems()} +
+ Auto-approve: + {getEnabledActionsText()}
{isModalVisible ? ( @@ -106,7 +174,6 @@ const AutoApproveBar = ({ style }: AutoApproveBarProps) => { ACTION_METADATA={ACTION_METADATA} buttonRef={buttonRef} isVisible={isModalVisible} - NOTIFICATIONS_SETTING={NOTIFICATIONS_SETTING} setIsVisible={setIsModalVisible} />
diff --git a/webview-ui/src/components/chat/auto-approve-menu/AutoApproveMenuItem.tsx b/webview-ui/src/components/chat/auto-approve-menu/AutoApproveMenuItem.tsx index 274d506ba9..5eb01af7d3 100644 --- a/webview-ui/src/components/chat/auto-approve-menu/AutoApproveMenuItem.tsx +++ b/webview-ui/src/components/chat/auto-approve-menu/AutoApproveMenuItem.tsx @@ -8,11 +8,9 @@ import { ActionMetadata } from "./types" interface AutoApproveMenuItemProps { action: ActionMetadata isChecked: (action: ActionMetadata) => boolean - isFavorited?: (action: ActionMetadata) => boolean onToggle: (action: ActionMetadata, checked: boolean) => Promise - onToggleFavorite?: (actionId: string) => Promise - condensed?: boolean showIcon?: boolean + disabled?: boolean } const SubOptionAnimateIn = styled.div<{ show: boolean }>` @@ -30,72 +28,40 @@ const ActionButtonContainer = styled.div` padding: 2px; ` -const AutoApproveMenuItem = ({ - action, - isChecked, - isFavorited, - onToggle, - onToggleFavorite, - condensed = false, - showIcon = true, -}: AutoApproveMenuItemProps) => { +const AutoApproveMenuItem = ({ action, isChecked, onToggle, showIcon = true, disabled = false }: AutoApproveMenuItemProps) => { const checked = isChecked(action) - const favorited = isFavorited?.(action) const onChange = async (e: Event) => { + if (disabled) { + return + } e.stopPropagation() await onToggle(action, !checked) } const content = ( -
+
{action.description} - {action.subAction && !condensed && ( + {action.subAction && ( - + )}
diff --git a/webview-ui/src/components/chat/auto-approve-menu/AutoApproveModal.tsx b/webview-ui/src/components/chat/auto-approve-menu/AutoApproveModal.tsx index 26872e9205..1632641d93 100644 --- a/webview-ui/src/components/chat/auto-approve-menu/AutoApproveModal.tsx +++ b/webview-ui/src/components/chat/auto-approve-menu/AutoApproveModal.tsx @@ -1,12 +1,9 @@ -import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react" -import { XIcon } from "lucide-react" +import { StringRequest } from "@shared/proto/cline/common" import React, { useEffect, useRef, useState } from "react" -import { useClickAway, useWindowSize } from "react-use" -import { CODE_BLOCK_BG_COLOR } from "@/components/common/CodeBlock" -import { Button } from "@/components/ui/button" -import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip" +import { useClickAway } from "react-use" import { useExtensionState } from "@/context/ExtensionStateContext" import { useAutoApproveActions } from "@/hooks/useAutoApproveActions" +import { UiServiceClient } from "@/services/grpc-client" import { getAsVar, VSC_TITLEBAR_INACTIVE_FOREGROUND } from "@/utils/vscStyles" import AutoApproveMenuItem from "./AutoApproveMenuItem" import { ActionMetadata } from "./types" @@ -18,24 +15,31 @@ interface AutoApproveModalProps { setIsVisible: (visible: boolean) => void buttonRef: React.RefObject ACTION_METADATA: ActionMetadata[] - NOTIFICATIONS_SETTING: ActionMetadata } -const AutoApproveModal: React.FC = ({ - isVisible, - setIsVisible, - buttonRef, - ACTION_METADATA, - NOTIFICATIONS_SETTING, -}) => { - const { autoApprovalSettings } = useExtensionState() - const { isChecked, isFavorited, toggleFavorite, updateAction, updateMaxRequests } = useAutoApproveActions() +const AutoApproveModal: React.FC = ({ isVisible, setIsVisible, buttonRef, ACTION_METADATA }) => { + const { navigateToSettings } = useExtensionState() + const { isChecked, updateAction } = useAutoApproveActions() + + const handleNotificationsLinkClick = async (e: React.MouseEvent) => { + e.preventDefault() + e.stopPropagation() + + // Navigate to settings + navigateToSettings() + + // Scroll to general section + setTimeout(async () => { + try { + await UiServiceClient.scrollToSettings(StringRequest.create({ value: "general" })) + } catch (error) { + console.error("Error scrolling to general settings:", error) + } + }, 300) + } const modalRef = useRef(null) const itemsContainerRef = useRef(null) - const { width: viewportWidth, height: viewportHeight } = useWindowSize() - const [arrowPosition, setArrowPosition] = useState(0) - const [menuPosition, setMenuPosition] = useState(0) const [containerWidth, setContainerWidth] = useState(0) useClickAway(modalRef, (e) => { @@ -46,18 +50,6 @@ const AutoApproveModal: React.FC = ({ setIsVisible(false) }) - // Calculate positions for modal and arrow - useEffect(() => { - if (isVisible && buttonRef.current) { - const buttonRect = buttonRef.current.getBoundingClientRect() - const buttonCenter = buttonRect.left + buttonRect.width / 2 - const rightPosition = document.documentElement.clientWidth - buttonCenter - 5 - - setArrowPosition(rightPosition) - setMenuPosition(buttonRect.top + 1) - } - }, [isVisible, viewportWidth, viewportHeight, buttonRef]) - // Track container width for responsive layout useEffect(() => { if (!isVisible) { @@ -89,152 +81,46 @@ const AutoApproveModal: React.FC = ({ return null } - // Calculate safe positioning to prevent overflow while preserving original position - const calculateModalStyle = () => { - // Original positioning: bottom: calc(100vh - ${menuPosition}px + 6px) - const originalBottom = viewportHeight - menuPosition + 6 - - // Calculate the available space from the button to the top of the viewport - const availableSpace = viewportHeight - originalBottom - - // Set a minimum top margin to prevent the modal from touching the top edge - const minTopMargin = 15 - - // Calculate the maximum height the modal can have - // Use the full available space minus the top margin, but also respect the original constraint - const maxAvailableHeight = availableSpace - minTopMargin - const originalMaxHeight = viewportHeight - 100 - - // Use the smaller of the two to ensure we don't overflow but still use full height when possible - let finalMaxHeight: number - - if (menuPosition <= minTopMargin) { - // Button is very close to the top, use all available space - finalMaxHeight = maxAvailableHeight - } else { - // Normal case: use the original max height unless it would cause overflow - finalMaxHeight = Math.min(originalMaxHeight, maxAvailableHeight) - } - - return { - bottom: `${originalBottom}px`, - maxHeight: `${Math.max(finalMaxHeight, 200)}px`, // Ensure minimum usable height - background: CODE_BLOCK_BG_COLOR, - overscrollBehavior: "contain" as const, - } - } - return ( -
+
+ {/* Expanded menu content - renders directly below the bar */}
+ className="overflow-y-auto pb-3 px-3.5 overscroll-contain" + style={{ + maxHeight: "60vh", + }}> +
setIsVisible(false)}> + Let Cline take these actions without asking for approval.{" "} + + Configure notification settings + +
+
- {/* Scrollable content container */} -
-
- - - Auto-approve allows Cline to perform the following actions without asking for permission. Please - use with caution and only enable if you understand the risks. - - -
Auto-approve Settings
-
-
- -
+ columnCount: containerWidth > breakpoint ? 2 : 1, + columnGap: "4px", + }}> + {/* Vertical separator line - only visible in two-column mode */} + {containerWidth > breakpoint && ( +
+ )} -
- Actions: -
- -
breakpoint ? 2 : 1, - columnGap: "4px", - }}> - {/* Vertical separator line - only visible in two-column mode */} - {containerWidth > breakpoint && ( -
- )} - - {/* All items in a single list - CSS Grid will handle the column distribution */} - {ACTION_METADATA.map((action) => ( - - ))} -
- -
- Quick Settings: -
- - - - - - Cline will automatically make this many API requests before asking for approval to proceed with the - task. - - -
- - Max Requests: - { - const input = e.target as HTMLInputElement - // Remove any non-numeric characters - input.value = input.value.replace(/[^0-9]/g, "") - const value = parseInt(input.value) - if (!Number.isNaN(value) && value > 0) { - await updateMaxRequests(value) - } - }} - onKeyDown={(e) => { - // Prevent non-numeric keys (except for backspace, delete, arrows) - if ( - !/^\d$/.test(e.key) && - !["Backspace", "Delete", "ArrowLeft", "ArrowRight"].includes(e.key) - ) { - e.preventDefault() - } - }} - value={autoApprovalSettings.maxRequests.toString()} - /> -
-
-
+ {/* All items in a single list - CSS Grid will handle the column distribution */} + {ACTION_METADATA.map((action) => ( + + ))}
diff --git a/webview-ui/src/components/chat/auto-approve-menu/constants.ts b/webview-ui/src/components/chat/auto-approve-menu/constants.ts index 43104a37d6..3cf741b05c 100644 --- a/webview-ui/src/components/chat/auto-approve-menu/constants.ts +++ b/webview-ui/src/components/chat/auto-approve-menu/constants.ts @@ -1,20 +1,6 @@ import { ActionMetadata } from "./types" export const ACTION_METADATA: ActionMetadata[] = [ - { - id: "enableAutoApprove", - label: "Enable auto-approve", - shortName: "Enabled", - description: "Toggle the auto-approve feature on or off.", - icon: "codicon-play-circle", - }, - { - id: "enableAll", - label: "Toggle all", - shortName: "All", - description: "Toggle all actions on or off.", - icon: "codicon-checklist", - }, { id: "readFiles", label: "Read project files", diff --git a/webview-ui/src/components/chat/auto-approve-menu/types.ts b/webview-ui/src/components/chat/auto-approve-menu/types.ts index 43ed450bdf..f6063900e5 100644 --- a/webview-ui/src/components/chat/auto-approve-menu/types.ts +++ b/webview-ui/src/components/chat/auto-approve-menu/types.ts @@ -1,7 +1,7 @@ import { AutoApprovalSettings } from "@shared/AutoApprovalSettings" export interface ActionMetadata { - id: keyof AutoApprovalSettings["actions"] | "enableNotifications" | "enableAll" | "enableAutoApprove" + id: keyof AutoApprovalSettings["actions"] | "enableNotifications" label: string shortName: string description: string diff --git a/webview-ui/src/components/chat/chat-view/hooks/useMessageHandlers.ts b/webview-ui/src/components/chat/chat-view/hooks/useMessageHandlers.ts index 04ad728906..c5b1694139 100644 --- a/webview-ui/src/components/chat/chat-view/hooks/useMessageHandlers.ts +++ b/webview-ui/src/components/chat/chat-view/hooks/useMessageHandlers.ts @@ -62,7 +62,6 @@ export function useMessageHandlers(messages: ClineMessage[], chatState: ChatStat case "resume_task": case "resume_completed_task": case "mistake_limit_reached": - case "auto_approval_max_req_reached": case "api_req_failed": case "new_task": case "condense": diff --git a/webview-ui/src/components/chat/chat-view/shared/buttonConfig.test.ts b/webview-ui/src/components/chat/chat-view/shared/buttonConfig.test.ts index dfac8c8e6b..af0fcbcf36 100644 --- a/webview-ui/src/components/chat/chat-view/shared/buttonConfig.test.ts +++ b/webview-ui/src/components/chat/chat-view/shared/buttonConfig.test.ts @@ -24,7 +24,7 @@ describe("getButtonConfig", () => { // Test error recovery states describe("Error Recovery States", () => { - const errorStates = ["api_req_failed", "mistake_limit_reached", "auto_approval_max_req_reached"] + const errorStates = ["api_req_failed", "mistake_limit_reached"] errorStates.forEach((errorState) => { it(`returns correct config for ${errorState}`, () => { diff --git a/webview-ui/src/components/chat/chat-view/shared/buttonConfig.ts b/webview-ui/src/components/chat/chat-view/shared/buttonConfig.ts index a2c351358d..2d1d86bcec 100644 --- a/webview-ui/src/components/chat/chat-view/shared/buttonConfig.ts +++ b/webview-ui/src/components/chat/chat-view/shared/buttonConfig.ts @@ -47,14 +47,6 @@ export const BUTTON_CONFIGS: Record = { primaryAction: "proceed", secondaryAction: "new_task", }, - auto_approval_max_req_reached: { - sendingDisabled: false, - enableButtons: true, - primaryText: "Proceed", - secondaryText: "Start New Task", - primaryAction: "proceed", - secondaryAction: "new_task", - }, // Tool approval states - most common during task execution tool_approve: { @@ -207,7 +199,7 @@ export const BUTTON_CONFIGS: Record = { }, } -const errorTypes = ["api_req_failed", "mistake_limit_reached", "auto_approval_max_req_reached"] +const errorTypes = ["api_req_failed", "mistake_limit_reached"] /** * Determines button configuration based on message type and state @@ -235,8 +227,6 @@ export function getButtonConfig(message: ClineMessage | undefined, _mode: Mode = return BUTTON_CONFIGS.api_req_failed case "mistake_limit_reached": return BUTTON_CONFIGS.mistake_limit_reached - case "auto_approval_max_req_reached": - return BUTTON_CONFIGS.auto_approval_max_req_reached // Tool approval (most common) case "tool": { diff --git a/webview-ui/src/components/mcp/configuration/tabs/installed/server-row/McpToolRow.tsx b/webview-ui/src/components/mcp/configuration/tabs/installed/server-row/McpToolRow.tsx index 04fcc6a51a..758cf07f33 100644 --- a/webview-ui/src/components/mcp/configuration/tabs/installed/server-row/McpToolRow.tsx +++ b/webview-ui/src/components/mcp/configuration/tabs/installed/server-row/McpToolRow.tsx @@ -50,7 +50,7 @@ const McpToolRow = ({ tool, serverName }: McpToolRowProps) => { {tool.name}
- {serverName && autoApprovalSettings.enabled && autoApprovalSettings.actions.useMcp && ( + {serverName && autoApprovalSettings.actions.useMcp && ( Auto-approve diff --git a/webview-ui/src/components/mcp/configuration/tabs/installed/server-row/ServerRow.tsx b/webview-ui/src/components/mcp/configuration/tabs/installed/server-row/ServerRow.tsx index fcf6bf4291..4523372ea2 100644 --- a/webview-ui/src/components/mcp/configuration/tabs/installed/server-row/ServerRow.tsx +++ b/webview-ui/src/components/mcp/configuration/tabs/installed/server-row/ServerRow.tsx @@ -340,16 +340,17 @@ const ServerRow = ({ flexDirection: "column", gap: "8px", width: "100%", + paddingTop: "8px", }}> {server.tools.map((tool) => ( ))} - {server.name && autoApprovalSettings.enabled && autoApprovalSettings.actions.useMcp && ( + {server.name && autoApprovalSettings.actions.useMcp && ( tool.autoApprove)} data-tool="all-tools" onChange={handleAutoApproveChange} - style={{ marginBottom: -10 }}> + style={{ marginTop: "4px", marginBottom: "4px" }}> Auto-approve all tools )} @@ -374,6 +375,7 @@ const ServerRow = ({ flexDirection: "column", gap: "8px", width: "100%", + paddingTop: "8px", }}> {[...(server.resourceTemplates || []), ...(server.resources || [])].map((item) => (

- EXPERIMENTAL & DANGEROUS: This mode disables safety checks and user confirmations. Cline will - automatically approve all actions without asking. Use with extreme caution. + This mode disables safety checks and user confirmations. Cline will automatically approve all actions + without asking. This special mode does not use plan mode or ask questions, and it is recommended to + enable all auto-approve actions instead.

diff --git a/webview-ui/src/components/settings/sections/GeneralSettingsSection.tsx b/webview-ui/src/components/settings/sections/GeneralSettingsSection.tsx index 0eeb1dd23a..478b7d5e33 100644 --- a/webview-ui/src/components/settings/sections/GeneralSettingsSection.tsx +++ b/webview-ui/src/components/settings/sections/GeneralSettingsSection.tsx @@ -1,4 +1,5 @@ import { VSCodeCheckbox, VSCodeLink } from "@vscode/webview-ui-toolkit/react" +import { updateAutoApproveSettings } from "@/components/chat/auto-approve-menu/AutoApproveSettingsAPI" import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip" import { useExtensionState } from "@/context/ExtensionStateContext" import PreferredLanguageSetting from "../PreferredLanguageSetting" @@ -10,7 +11,7 @@ interface GeneralSettingsSectionProps { } const GeneralSettingsSection = ({ renderSectionHeader }: GeneralSettingsSectionProps) => { - const { telemetrySetting, remoteConfigSettings } = useExtensionState() + const { telemetrySetting, remoteConfigSettings, autoApprovalSettings } = useExtensionState() return (
@@ -18,6 +19,25 @@ const GeneralSettingsSection = ({ renderSectionHeader }: GeneralSettingsSectionP
+
+ { + const checked = e.target.checked === true + await updateAutoApproveSettings({ + ...autoApprovalSettings, + version: (autoApprovalSettings.version ?? 1) + 1, + enableNotifications: checked, + }) + }}> + Enable notifications + + +

+ Receive system notifications when Cline requires approval to proceed or when a task is completed. +

+
+