From 048863e03991a3b49429a77827da2f96b32889f9 Mon Sep 17 00:00:00 2001 From: Piotr Rogowski Date: Sun, 26 Jan 2025 08:31:07 +0100 Subject: [PATCH 01/32] Do not exclude whole project dir when listing in case where project is places inside excluded dir (like /tmp or ~/tmp) --- src/services/glob/list-files.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/glob/list-files.ts b/src/services/glob/list-files.ts index 8578b914d7..c7e3d41cf0 100644 --- a/src/services/glob/list-files.ts +++ b/src/services/glob/list-files.ts @@ -34,7 +34,7 @@ export async function listFiles(dirPath: string, recursive: boolean, limit: numb "pkg", "Pods", ".*", // '!**/.*' excludes hidden directories, while '!**/.*/**' excludes only their contents. This way we are at least aware of the existence of hidden directories. - ].map((dir) => `**/${dir}/**`) + ].map((dir) => `${dirPath}/**/${dir}/**`) const options = { cwd: dirPath, From 1cd90a655b0db197b6dd248e854eef366d148849 Mon Sep 17 00:00:00 2001 From: kohii Date: Sun, 2 Feb 2025 10:17:57 +0900 Subject: [PATCH 02/32] feat: Add Kotlin support in list_code_definition_names --- esbuild.js | 1 + .../tree-sitter/__tests__/index.test.ts | 6 ++++ .../__tests__/languageParser.test.ts | 11 ++++++++ src/services/tree-sitter/index.ts | 3 ++ src/services/tree-sitter/languageParser.ts | 6 ++++ src/services/tree-sitter/queries/index.ts | 1 + src/services/tree-sitter/queries/kotlin.ts | 28 +++++++++++++++++++ 7 files changed, 56 insertions(+) create mode 100644 src/services/tree-sitter/queries/kotlin.ts diff --git a/esbuild.js b/esbuild.js index 8b203076e4..7907dd1c39 100644 --- a/esbuild.js +++ b/esbuild.js @@ -52,6 +52,7 @@ const copyWasmFiles = { "java", "php", "swift", + "kotlin", ] languages.forEach((lang) => { diff --git a/src/services/tree-sitter/__tests__/index.test.ts b/src/services/tree-sitter/__tests__/index.test.ts index 4a5782dcb1..8372e7e580 100644 --- a/src/services/tree-sitter/__tests__/index.test.ts +++ b/src/services/tree-sitter/__tests__/index.test.ts @@ -169,6 +169,8 @@ describe("Tree-sitter Service", () => { "/test/path/main.rs", "/test/path/program.cpp", "/test/path/code.go", + "/test/path/app.kt", + "/test/path/script.kts", ] ;(listFiles as jest.Mock).mockResolvedValue([mockFiles, new Set()]) @@ -197,6 +199,8 @@ describe("Tree-sitter Service", () => { rs: { parser: mockParser, query: mockQuery }, cpp: { parser: mockParser, query: mockQuery }, go: { parser: mockParser, query: mockQuery }, + kt: { parser: mockParser, query: mockQuery }, + kts: { parser: mockParser, query: mockQuery }, }) ;(fs.readFile as jest.Mock).mockResolvedValue("function test() {}") @@ -207,6 +211,8 @@ describe("Tree-sitter Service", () => { expect(result).toContain("main.rs") expect(result).toContain("program.cpp") expect(result).toContain("code.go") + expect(result).toContain("app.kt") + expect(result).toContain("script.kts") }) it("should normalize paths in output", async () => { diff --git a/src/services/tree-sitter/__tests__/languageParser.test.ts b/src/services/tree-sitter/__tests__/languageParser.test.ts index 1b92d81b6b..54271e30e8 100644 --- a/src/services/tree-sitter/__tests__/languageParser.test.ts +++ b/src/services/tree-sitter/__tests__/languageParser.test.ts @@ -92,6 +92,17 @@ describe("Language Parser", () => { expect(parsers.hpp).toBeDefined() }) + it("should handle Kotlin files correctly", async () => { + const files = ["test.kt", "test.kts"] + const parsers = await loadRequiredLanguageParsers(files) + + expect(ParserMock.Language.load).toHaveBeenCalledWith(expect.stringContaining("tree-sitter-kotlin.wasm")) + expect(parsers.kt).toBeDefined() + expect(parsers.kts).toBeDefined() + expect(parsers.kt.query).toBeDefined() + expect(parsers.kts.query).toBeDefined() + }) + it("should throw error for unsupported file extensions", async () => { const files = ["test.unsupported"] diff --git a/src/services/tree-sitter/index.ts b/src/services/tree-sitter/index.ts index 83e02ac615..5b48da885d 100644 --- a/src/services/tree-sitter/index.ts +++ b/src/services/tree-sitter/index.ts @@ -73,6 +73,9 @@ function separateFiles(allFiles: string[]): { filesToParse: string[]; remainingF "java", "php", "swift", + // Kotlin + "kt", + "kts", ].map((e) => `.${e}`) const filesToParse = allFiles.filter((file) => extensions.includes(path.extname(file))).slice(0, 50) // 50 files max const remainingFiles = allFiles.filter((file) => !filesToParse.includes(file)) diff --git a/src/services/tree-sitter/languageParser.ts b/src/services/tree-sitter/languageParser.ts index 2d791b39a8..f256b0b62a 100644 --- a/src/services/tree-sitter/languageParser.ts +++ b/src/services/tree-sitter/languageParser.ts @@ -13,6 +13,7 @@ import { javaQuery, phpQuery, swiftQuery, + kotlinQuery, } from "./queries" export interface LanguageParser { @@ -120,6 +121,11 @@ export async function loadRequiredLanguageParsers(filesToParse: string[]): Promi language = await loadLanguage("swift") query = language.query(swiftQuery) break + case "kt": + case "kts": + language = await loadLanguage("kotlin") + query = language.query(kotlinQuery) + break default: throw new Error(`Unsupported language: ${ext}`) } diff --git a/src/services/tree-sitter/queries/index.ts b/src/services/tree-sitter/queries/index.ts index 889210a8e5..818eacca01 100644 --- a/src/services/tree-sitter/queries/index.ts +++ b/src/services/tree-sitter/queries/index.ts @@ -10,3 +10,4 @@ export { default as cQuery } from "./c" export { default as csharpQuery } from "./c-sharp" export { default as goQuery } from "./go" export { default as swiftQuery } from "./swift" +export { default as kotlinQuery } from "./kotlin" diff --git a/src/services/tree-sitter/queries/kotlin.ts b/src/services/tree-sitter/queries/kotlin.ts new file mode 100644 index 0000000000..61eb112448 --- /dev/null +++ b/src/services/tree-sitter/queries/kotlin.ts @@ -0,0 +1,28 @@ +/* +- class declarations (including interfaces) +- function declarations +- object declarations +- property declarations +- type alias declarations +*/ +export default ` +(class_declaration + (type_identifier) @name.definition.class +) @definition.class + +(function_declaration + (simple_identifier) @name.definition.function +) @definition.function + +(object_declaration + (type_identifier) @name.definition.object +) @definition.object + +(property_declaration + (simple_identifier) @name.definition.property +) @definition.property + +(type_alias + (type_identifier) @name.definition.type +) @definition.type +` From fbf65bfc6c1eeef107e9aa27245ea7bd64a5adf7 Mon Sep 17 00:00:00 2001 From: axb Date: Wed, 12 Feb 2025 17:32:55 +0800 Subject: [PATCH 03/32] Reduce the probability of errors when the model tries to fix the problem due to mismatched line numbers after applying diff --- src/core/mentions/index.ts | 4 ++-- src/integrations/diagnostics/index.ts | 10 +++++++--- src/integrations/editor/DiffViewProvider.ts | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/core/mentions/index.ts b/src/core/mentions/index.ts index cf5bdeaae0..cf87241f23 100644 --- a/src/core/mentions/index.ts +++ b/src/core/mentions/index.ts @@ -186,9 +186,9 @@ async function getFileOrFolderContent(mentionPath: string, cwd: string): Promise } } -function getWorkspaceProblems(cwd: string): string { +async function getWorkspaceProblems(cwd: string): Promise { const diagnostics = vscode.languages.getDiagnostics() - const result = diagnosticsToProblemsString( + const result = await diagnosticsToProblemsString( diagnostics, [vscode.DiagnosticSeverity.Error, vscode.DiagnosticSeverity.Warning], cwd, diff --git a/src/integrations/diagnostics/index.ts b/src/integrations/diagnostics/index.ts index ad4ee7755c..2d829f26e7 100644 --- a/src/integrations/diagnostics/index.ts +++ b/src/integrations/diagnostics/index.ts @@ -70,11 +70,12 @@ export function getNewDiagnostics( // // - New error in file3 (1:1) // will return empty string if no problems with the given severity are found -export function diagnosticsToProblemsString( +export async function diagnosticsToProblemsString( diagnostics: [vscode.Uri, vscode.Diagnostic[]][], severities: vscode.DiagnosticSeverity[], cwd: string, -): string { +): Promise { + const documents = new Map() let result = "" for (const [uri, fileDiagnostics] of diagnostics) { const problems = fileDiagnostics.filter((d) => severities.includes(d.severity)) @@ -100,7 +101,10 @@ export function diagnosticsToProblemsString( } const line = diagnostic.range.start.line + 1 // VSCode lines are 0-indexed const source = diagnostic.source ? `${diagnostic.source} ` : "" - result += `\n- [${source}${label}] Line ${line}: ${diagnostic.message}` + const document = documents.get(uri) || (await vscode.workspace.openTextDocument(uri)) + documents.set(uri, document) + const lineContent = document.lineAt(diagnostic.range.start.line).text + result += `\n- [${source}${label}] ${line} | ${lineContent} : ${diagnostic.message}` } } } diff --git a/src/integrations/editor/DiffViewProvider.ts b/src/integrations/editor/DiffViewProvider.ts index ee24d7db4e..8f7e387c7a 100644 --- a/src/integrations/editor/DiffViewProvider.ts +++ b/src/integrations/editor/DiffViewProvider.ts @@ -172,7 +172,7 @@ export class DiffViewProvider { initial fix is usually correct and it may just take time for linters to catch up. */ const postDiagnostics = vscode.languages.getDiagnostics() - const newProblems = diagnosticsToProblemsString( + const newProblems = await diagnosticsToProblemsString( getNewDiagnostics(this.preDiagnostics, postDiagnostics), [ vscode.DiagnosticSeverity.Error, // only including errors since warnings can be distracting (if user wants to fix warnings they can use the @problems mention) From 1456db95028f90b75bb521ad036a6fcc9d7bdd45 Mon Sep 17 00:00:00 2001 From: ShayBC Date: Sat, 8 Mar 2025 06:01:49 +0200 Subject: [PATCH 04/32] added approve finish task button and auto approve button for subtasks --- src/core/Cline.ts | 26 +++++++++++++++++-- src/shared/ExtensionMessage.ts | 3 +++ src/shared/WebviewMessage.ts | 1 + .../src/components/chat/AutoApproveMenu.tsx | 16 ++++++++++++ webview-ui/src/components/chat/ChatRow.tsx | 12 +++++++++ webview-ui/src/components/chat/ChatView.tsx | 5 +++- .../src/context/ExtensionStateContext.tsx | 2 ++ 7 files changed, 62 insertions(+), 3 deletions(-) diff --git a/src/core/Cline.ts b/src/core/Cline.ts index 51fb5265d4..c3e90d4300 100644 --- a/src/core/Cline.ts +++ b/src/core/Cline.ts @@ -1414,6 +1414,18 @@ export class Cline { return true } + const askFinishSubTaskApproval = async () => { + // ask the user to approve this task has completed, and he has reviewd it, and we can declare task is finished + // and return control to the parent task to continue running the rest of the sub-tasks + const toolMessage = JSON.stringify({ + tool: "finishTask", + content: + "Task completed! You can review the results and suggest any corrections or next steps. If everything looks good, confirm to continue with the next task.", + }) + + return await askApproval("tool", toolMessage) + } + const handleError = async (action: string, error: Error) => { const errorString = `Error ${action}: ${JSON.stringify(serializeError(error))}` await this.say( @@ -2941,8 +2953,13 @@ export class Cline { if (lastMessage && lastMessage.ask !== "command") { // havent sent a command message yet so first send completion_result then command await this.say("completion_result", result, undefined, false) - telemetryService.captureTaskCompleted(this.taskId) + // telemetryService.captureTaskCompleted(this.taskId) if (this.isSubTask) { + const didApprove = await askFinishSubTaskApproval() + if (!didApprove) { + break + } + // tell the provider to remove the current subtask and resume the previous task in the stack await this.providerRef .deref() @@ -2966,8 +2983,13 @@ export class Cline { commandResult = execCommandResult } else { await this.say("completion_result", result, undefined, false) - telemetryService.captureTaskCompleted(this.taskId) + // telemetryService.captureTaskCompleted(this.taskId) if (this.isSubTask) { + const didApprove = await askFinishSubTaskApproval() + if (!didApprove) { + break + } + // tell the provider to remove the current subtask and resume the previous task in the stack await this.providerRef .deref() diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index 98ff9b36e1..dcdaf017f3 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -109,6 +109,7 @@ export interface ExtensionState { alwaysAllowMcp?: boolean alwaysApproveResubmit?: boolean alwaysAllowModeSwitch?: boolean + alwaysAllowFinishTask?: boolean browserToolEnabled?: boolean requestDelaySeconds: number rateLimitSeconds: number // Minimum time between successive requests (0 = disabled) @@ -168,6 +169,7 @@ export type ClineAsk = | "mistake_limit_reached" | "browser_action_launch" | "use_mcp_server" + | "finishTask" export type ClineSay = | "task" @@ -207,6 +209,7 @@ export interface ClineSayTool { | "searchFiles" | "switchMode" | "newTask" + | "finishTask" path?: string diff?: string content?: string diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index 10af6f7a94..086701a43f 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -48,6 +48,7 @@ export interface WebviewMessage { | "alwaysAllowBrowser" | "alwaysAllowMcp" | "alwaysAllowModeSwitch" + | "alwaysAllowFinishTask" | "playSound" | "soundEnabled" | "soundVolume" diff --git a/webview-ui/src/components/chat/AutoApproveMenu.tsx b/webview-ui/src/components/chat/AutoApproveMenu.tsx index 161f3032b0..02f75cd28a 100644 --- a/webview-ui/src/components/chat/AutoApproveMenu.tsx +++ b/webview-ui/src/components/chat/AutoApproveMenu.tsx @@ -30,6 +30,8 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => { setAlwaysAllowMcp, alwaysAllowModeSwitch, setAlwaysAllowModeSwitch, + alwaysAllowFinishTask, + setAlwaysAllowFinishTask, alwaysApproveResubmit, setAlwaysApproveResubmit, autoApprovalEnabled, @@ -81,6 +83,13 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => { description: "Allows automatic switching between different AI modes and creating new tasks without requiring approval.", }, + { + id: "finishTask", + label: "Finish subtasks tasks", + shortName: "Finish", + enabled: alwaysAllowFinishTask ?? false, + description: "Allows automatic completeing a sub-task without requiring user review or approval.", + }, { id: "retryRequests", label: "Retry failed requests", @@ -136,6 +145,12 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => { vscode.postMessage({ type: "alwaysAllowModeSwitch", bool: newValue }) }, [alwaysAllowModeSwitch, setAlwaysAllowModeSwitch]) + const handleFinishTaskChange = useCallback(() => { + const newValue = !(alwaysAllowFinishTask ?? false) + setAlwaysAllowFinishTask(newValue) + vscode.postMessage({ type: "alwaysAllowFinishTask", bool: newValue }) + }, [alwaysAllowFinishTask, setAlwaysAllowFinishTask]) + const handleRetryChange = useCallback(() => { const newValue = !(alwaysApproveResubmit ?? false) setAlwaysApproveResubmit(newValue) @@ -150,6 +165,7 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => { useBrowser: handleBrowserChange, useMcp: handleMcpChange, switchModes: handleModeSwitchChange, + finishTask: handleFinishTaskChange, retryRequests: handleRetryChange, } diff --git a/webview-ui/src/components/chat/ChatRow.tsx b/webview-ui/src/components/chat/ChatRow.tsx index 1533bba3a8..6f19df665e 100644 --- a/webview-ui/src/components/chat/ChatRow.tsx +++ b/webview-ui/src/components/chat/ChatRow.tsx @@ -459,6 +459,18 @@ export const ChatRowContent = ({ ) + case "finishTask": + return ( + <> +
+ {toolIcon("new-file")} + Roo wants to finish this task +
+
+ {tool.content} +
+ + ) default: return null } diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index 35e63dd332..0f352819ef 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -61,6 +61,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie setMode, autoApprovalEnabled, alwaysAllowModeSwitch, + alwaysAllowFinishTask, customModes, telemetrySetting, } = useExtensionState() @@ -642,7 +643,8 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie (alwaysAllowModeSwitch && message.ask === "tool" && (JSON.parse(message.text || "{}")?.tool === "switchMode" || - JSON.parse(message.text || "{}")?.tool === "newTask")) + JSON.parse(message.text || "{}")?.tool === "newTask")) || + (alwaysAllowFinishTask && message.ask === "finishTask") ) }, [ @@ -657,6 +659,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie alwaysAllowMcp, isMcpToolAlwaysAllowed, alwaysAllowModeSwitch, + alwaysAllowFinishTask, ], ) diff --git a/webview-ui/src/context/ExtensionStateContext.tsx b/webview-ui/src/context/ExtensionStateContext.tsx index c4daf426ca..aa132919c0 100644 --- a/webview-ui/src/context/ExtensionStateContext.tsx +++ b/webview-ui/src/context/ExtensionStateContext.tsx @@ -31,6 +31,7 @@ export interface ExtensionStateContextType extends ExtensionState { setAlwaysAllowBrowser: (value: boolean) => void setAlwaysAllowMcp: (value: boolean) => void setAlwaysAllowModeSwitch: (value: boolean) => void + setAlwaysAllowFinishTask: (value: boolean) => void setBrowserToolEnabled: (value: boolean) => void setShowRooIgnoredFiles: (value: boolean) => void setShowAnnouncement: (value: boolean) => void @@ -247,6 +248,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode setAlwaysAllowBrowser: (value) => setState((prevState) => ({ ...prevState, alwaysAllowBrowser: value })), setAlwaysAllowMcp: (value) => setState((prevState) => ({ ...prevState, alwaysAllowMcp: value })), setAlwaysAllowModeSwitch: (value) => setState((prevState) => ({ ...prevState, alwaysAllowModeSwitch: value })), + setAlwaysAllowFinishTask: (value) => setState((prevState) => ({ ...prevState, alwaysAllowFinishTask: value })), setShowAnnouncement: (value) => setState((prevState) => ({ ...prevState, shouldShowAnnouncement: value })), setAllowedCommands: (value) => setState((prevState) => ({ ...prevState, allowedCommands: value })), setSoundEnabled: (value) => setState((prevState) => ({ ...prevState, soundEnabled: value })), From 27624a25a54be1f124ab5f7e765e7cb0b62c97a0 Mon Sep 17 00:00:00 2001 From: ShayBC Date: Sat, 8 Mar 2025 16:25:45 +0200 Subject: [PATCH 05/32] fixed the missing case of cmd execution at the end of a subyask and added auto aprove option for finish task (and continue to the next task) --- src/core/Cline.ts | 33 ++++++------------- src/core/webview/ClineProvider.ts | 7 ++++ src/shared/globalState.ts | 1 + .../src/components/chat/AutoApproveMenu.tsx | 6 ++-- webview-ui/src/components/chat/ChatView.tsx | 8 ++++- .../settings/AutoApproveSettings.tsx | 14 ++++++++ .../src/components/settings/SettingsView.tsx | 3 ++ 7 files changed, 45 insertions(+), 27 deletions(-) diff --git a/src/core/Cline.ts b/src/core/Cline.ts index c3e90d4300..cd1ce7031d 100644 --- a/src/core/Cline.ts +++ b/src/core/Cline.ts @@ -2953,19 +2953,7 @@ export class Cline { if (lastMessage && lastMessage.ask !== "command") { // havent sent a command message yet so first send completion_result then command await this.say("completion_result", result, undefined, false) - // telemetryService.captureTaskCompleted(this.taskId) - if (this.isSubTask) { - const didApprove = await askFinishSubTaskApproval() - if (!didApprove) { - break - } - - // tell the provider to remove the current subtask and resume the previous task in the stack - await this.providerRef - .deref() - ?.finishSubTask(`Task complete: ${lastMessage?.text}`) - break - } + telemetryService.captureTaskCompleted(this.taskId) } // complete command message @@ -2983,19 +2971,18 @@ export class Cline { commandResult = execCommandResult } else { await this.say("completion_result", result, undefined, false) - // telemetryService.captureTaskCompleted(this.taskId) - if (this.isSubTask) { - const didApprove = await askFinishSubTaskApproval() - if (!didApprove) { - break - } + telemetryService.captureTaskCompleted(this.taskId) + } - // tell the provider to remove the current subtask and resume the previous task in the stack - await this.providerRef - .deref() - ?.finishSubTask(`Task complete: ${lastMessage?.text}`) + if (this.isSubTask) { + const didApprove = await askFinishSubTaskApproval() + if (!didApprove) { break } + + // tell the provider to remove the current subtask and resume the previous task in the stack + await this.providerRef.deref()?.finishSubTask(`Task complete: ${lastMessage?.text}`) + break } // we already sent completion_result says, an empty string asks relinquishes control over button and field diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 70feb45c2f..cc0b6f4f04 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -984,6 +984,10 @@ export class ClineProvider implements vscode.WebviewViewProvider { await this.updateGlobalState("alwaysAllowModeSwitch", message.bool) await this.postStateToWebview() break + case "alwaysAllowFinishTask": + await this.updateGlobalState("alwaysAllowFinishTask", message.bool) + await this.postStateToWebview() + break case "askResponse": this.getCurrentCline()?.handleWebviewAskResponse( message.askResponse!, @@ -2177,6 +2181,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { alwaysAllowBrowser, alwaysAllowMcp, alwaysAllowModeSwitch, + alwaysAllowFinishTask, soundEnabled, diffEnabled, enableCheckpoints, @@ -2224,6 +2229,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { alwaysAllowBrowser: alwaysAllowBrowser ?? false, alwaysAllowMcp: alwaysAllowMcp ?? false, alwaysAllowModeSwitch: alwaysAllowModeSwitch ?? false, + alwaysAllowFinishTask: alwaysAllowFinishTask ?? false, uriScheme: vscode.env.uriScheme, currentTaskItem: this.getCurrentCline()?.taskId ? (taskHistory || []).find((item: HistoryItem) => item.id === this.getCurrentCline()?.taskId) @@ -2385,6 +2391,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { alwaysAllowBrowser: stateValues.alwaysAllowBrowser ?? false, alwaysAllowMcp: stateValues.alwaysAllowMcp ?? false, alwaysAllowModeSwitch: stateValues.alwaysAllowModeSwitch ?? false, + alwaysAllowFinishTask: stateValues.alwaysAllowFinishTask ?? false, taskHistory: stateValues.taskHistory, allowedCommands: stateValues.allowedCommands, soundEnabled: stateValues.soundEnabled ?? false, diff --git a/src/shared/globalState.ts b/src/shared/globalState.ts index bfd24f4298..739fa11dad 100644 --- a/src/shared/globalState.ts +++ b/src/shared/globalState.ts @@ -40,6 +40,7 @@ export const GLOBAL_STATE_KEYS = [ "alwaysAllowBrowser", "alwaysAllowMcp", "alwaysAllowModeSwitch", + "alwaysAllowFinishTask", "taskHistory", "openAiBaseUrl", "openAiModelId", diff --git a/webview-ui/src/components/chat/AutoApproveMenu.tsx b/webview-ui/src/components/chat/AutoApproveMenu.tsx index 02f75cd28a..fba97f6c7d 100644 --- a/webview-ui/src/components/chat/AutoApproveMenu.tsx +++ b/webview-ui/src/components/chat/AutoApproveMenu.tsx @@ -85,10 +85,10 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => { }, { id: "finishTask", - label: "Finish subtasks tasks", - shortName: "Finish", + label: "Continue to next task", + shortName: "Continue", enabled: alwaysAllowFinishTask ?? false, - description: "Allows automatic completeing a sub-task without requiring user review or approval.", + description: "Allow tasks to end execution and continue to the next task, without user review or approval.", }, { id: "retryRequests", diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index 0f352819ef..b92604e157 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -149,6 +149,10 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie setPrimaryButtonText("Save") setSecondaryButtonText("Reject") break + case "finishTask": + setPrimaryButtonText("Approve & Continue to the next Task") + setSecondaryButtonText(undefined) + break default: setPrimaryButtonText("Approve") setSecondaryButtonText("Reject") @@ -644,7 +648,9 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie message.ask === "tool" && (JSON.parse(message.text || "{}")?.tool === "switchMode" || JSON.parse(message.text || "{}")?.tool === "newTask")) || - (alwaysAllowFinishTask && message.ask === "finishTask") + (alwaysAllowFinishTask && + message.ask === "tool" && + JSON.parse(message.text || "{}")?.tool === "finishTask") ) }, [ diff --git a/webview-ui/src/components/settings/AutoApproveSettings.tsx b/webview-ui/src/components/settings/AutoApproveSettings.tsx index b2da2cab75..1c8e6c9ea9 100644 --- a/webview-ui/src/components/settings/AutoApproveSettings.tsx +++ b/webview-ui/src/components/settings/AutoApproveSettings.tsx @@ -18,6 +18,7 @@ type AutoApproveSettingsProps = HTMLAttributes & { requestDelaySeconds: number alwaysAllowMcp?: boolean alwaysAllowModeSwitch?: boolean + alwaysAllowFinishTask?: boolean alwaysAllowExecute?: boolean allowedCommands?: string[] setCachedStateField: SetCachedStateField @@ -32,6 +33,7 @@ export const AutoApproveSettings = ({ requestDelaySeconds, alwaysAllowMcp, alwaysAllowModeSwitch, + alwaysAllowFinishTask, alwaysAllowExecute, allowedCommands, setCachedStateField, @@ -180,6 +182,18 @@ export const AutoApproveSettings = ({

+
+ setCachedStateField("alwaysAllowFinishTask", e.target.checked)}> + Always approve finish & continue to next task + +

+ Automatically approve tasks to finish execution and continue to the next task, without user + review or approval +

+
+
(({ onDone }, alwaysAllowExecute, alwaysAllowMcp, alwaysAllowModeSwitch, + alwaysAllowFinishTask, alwaysAllowWrite, alwaysApproveResubmit, browserToolEnabled, @@ -184,6 +185,7 @@ const SettingsView = forwardRef(({ onDone }, vscode.postMessage({ type: "currentApiConfigName", text: currentApiConfigName }) vscode.postMessage({ type: "updateExperimental", values: experiments }) vscode.postMessage({ type: "alwaysAllowModeSwitch", bool: alwaysAllowModeSwitch }) + vscode.postMessage({ type: "alwaysAllowFinishTask", bool: alwaysAllowFinishTask }) vscode.postMessage({ type: "upsertApiConfiguration", text: currentApiConfigName, apiConfiguration }) vscode.postMessage({ type: "telemetrySetting", text: telemetrySetting }) setChangeDetected(false) @@ -364,6 +366,7 @@ const SettingsView = forwardRef(({ onDone }, requestDelaySeconds={requestDelaySeconds} alwaysAllowMcp={alwaysAllowMcp} alwaysAllowModeSwitch={alwaysAllowModeSwitch} + alwaysAllowFinishTask={alwaysAllowFinishTask} alwaysAllowExecute={alwaysAllowExecute} allowedCommands={allowedCommands} setCachedStateField={setCachedStateField} From 80139d88d7d7ab3baee492955a7380ade17550cc Mon Sep 17 00:00:00 2001 From: axb Date: Sun, 9 Mar 2025 00:02:40 +0800 Subject: [PATCH 06/32] support tool progress status --- src/core/Cline.ts | 26 ++++++++++++++++++- .../diff/strategies/multi-search-replace.ts | 23 ++++++++++++++++ src/core/diff/types.ts | 5 ++++ src/shared/ExtensionMessage.ts | 5 ++++ webview-ui/src/components/chat/ChatRow.tsx | 1 + .../src/components/common/CodeAccordian.tsx | 13 ++++++++++ 6 files changed, 72 insertions(+), 1 deletion(-) diff --git a/src/core/Cline.ts b/src/core/Cline.ts index fd8ce3e9a2..232a8f4de7 100644 --- a/src/core/Cline.ts +++ b/src/core/Cline.ts @@ -48,6 +48,7 @@ import { ClineSay, ClineSayBrowserAction, ClineSayTool, + ToolProgressStatus, } from "../shared/ExtensionMessage" import { getApiMetrics } from "../shared/getApiMetrics" import { HistoryItem } from "../shared/HistoryItem" @@ -408,6 +409,7 @@ export class Cline { type: ClineAsk, text?: string, partial?: boolean, + progressStatus?: ToolProgressStatus, ): Promise<{ response: ClineAskResponse; text?: string; images?: string[] }> { // If this Cline instance was aborted by the provider, then the only thing keeping us alive is a promise still running in the background, in which case we don't want to send its result to the webview as it is attached to a new instance of Cline now. So we can safely ignore the result of any active promises, and this class will be deallocated. (Although we set Cline = undefined in provider, that simply removes the reference to this instance, but the instance is still alive until this promise resolves or rejects.) if (this.abort) { @@ -423,6 +425,7 @@ export class Cline { // existing partial message, so update it lastMessage.text = text lastMessage.partial = partial + lastMessage.progressStatus = progressStatus // todo be more efficient about saving and posting only new data or one whole message at a time so ignore partial for saves, and only post parts of partial message instead of whole array in new listener // await this.saveClineMessages() // await this.providerRef.deref()?.postStateToWebview() @@ -460,6 +463,8 @@ export class Cline { // lastMessage.ts = askTs lastMessage.text = text lastMessage.partial = false + lastMessage.progressStatus = progressStatus + await this.saveClineMessages() // await this.providerRef.deref()?.postStateToWebview() await this.providerRef @@ -511,6 +516,7 @@ export class Cline { images?: string[], partial?: boolean, checkpoint?: Record, + progressStatus?: ToolProgressStatus, ): Promise { if (this.abort) { throw new Error(`Task: ${this.taskNumber} Roo Code instance aborted (#2)`) @@ -526,6 +532,7 @@ export class Cline { lastMessage.text = text lastMessage.images = images lastMessage.partial = partial + lastMessage.progressStatus = progressStatus await this.providerRef .deref() ?.postMessageToWebview({ type: "partialMessage", partialMessage: lastMessage }) @@ -545,6 +552,7 @@ export class Cline { lastMessage.text = text lastMessage.images = images lastMessage.partial = false + lastMessage.progressStatus = progressStatus // instead of streaming partialMessage events, we do a save and post like normal to persist to disk await this.saveClineMessages() @@ -1691,8 +1699,16 @@ export class Cline { try { if (block.partial) { // update gui message + let toolProgressStatus + if (this.diffStrategy && this.diffStrategy.getProgressStatus) { + toolProgressStatus = this.diffStrategy.getProgressStatus(block) + } + const partialMessage = JSON.stringify(sharedMessageProps) - await this.ask("tool", partialMessage, block.partial).catch(() => {}) + + await this.ask("tool", partialMessage, block.partial, toolProgressStatus).catch( + () => {}, + ) break } else { if (!relPath) { @@ -1787,6 +1803,14 @@ export class Cline { diff: diffContent, } satisfies ClineSayTool) + let toolProgressStatus + if (this.diffStrategy && this.diffStrategy.getProgressStatus) { + toolProgressStatus = this.diffStrategy.getProgressStatus(block, diffResult) + } + await this.ask("tool", completeMessage, block.partial, toolProgressStatus).catch( + () => {}, + ) + const didApprove = await askApproval("tool", completeMessage) if (!didApprove) { await this.diffViewProvider.revertChanges() // This likely handles closing the diff view diff --git a/src/core/diff/strategies/multi-search-replace.ts b/src/core/diff/strategies/multi-search-replace.ts index 99c22a31df..0462629b9b 100644 --- a/src/core/diff/strategies/multi-search-replace.ts +++ b/src/core/diff/strategies/multi-search-replace.ts @@ -1,6 +1,8 @@ import { DiffStrategy, DiffResult } from "../types" import { addLineNumbers, everyLineHasLineNumbers, stripLineNumbers } from "../../../integrations/misc/extract-text" import { distance } from "fastest-levenshtein" +import { ToolProgressStatus } from "../../../shared/ExtensionMessage" +import { ToolUse } from "../../assistant-message" const BUFFER_LINES = 40 // Number of extra context lines to show before and after matches @@ -362,4 +364,25 @@ Only use a single line of '=======' between search and replacement content, beca failParts: diffResults, } } + + getProgressStatus(toolUse: ToolUse, result?: DiffResult): ToolProgressStatus { + const diffContent = toolUse.params.diff + if (diffContent) { + if (toolUse.partial) { + if (diffContent.length < 1000 || (diffContent.length / 50) % 10 === 0) { + return { text: `progressing ${(diffContent.match(/SEARCH/g) || []).length} blocks...` } + } + } else if (result) { + const searchBlockCount = (diffContent.match(/SEARCH/g) || []).length + if (result.failParts) { + return { + text: `progressed ${searchBlockCount - result.failParts.length}/${searchBlockCount} blocks.`, + } + } else { + return { text: `progressed ${searchBlockCount} blocks.` } + } + } + } + return {} + } } diff --git a/src/core/diff/types.ts b/src/core/diff/types.ts index be6d8cd311..e12a47762d 100644 --- a/src/core/diff/types.ts +++ b/src/core/diff/types.ts @@ -2,6 +2,9 @@ * Interface for implementing different diff strategies */ +import { ToolProgressStatus } from "../../shared/ExtensionMessage" +import { ToolUse } from "../assistant-message" + export type DiffResult = | { success: true; content: string; failParts?: DiffResult[] } | ({ @@ -34,4 +37,6 @@ export interface DiffStrategy { * @returns A DiffResult object containing either the successful result or error details */ applyDiff(originalContent: string, diffContent: string, startLine?: number, endLine?: number): Promise + + getProgressStatus?(toolUse: ToolUse, result?: any): ToolProgressStatus } diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index 98ff9b36e1..0f65d17199 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -154,6 +154,7 @@ export interface ClineMessage { reasoning?: string conversationHistoryIndex?: number checkpoint?: Record + progressStatus?: ToolProgressStatus } export type ClineAsk = @@ -271,3 +272,7 @@ export interface HumanRelayCancelMessage { } export type ClineApiReqCancelReason = "streaming_failed" | "user_cancelled" + +export type ToolProgressStatus = { + text?: string +} diff --git a/webview-ui/src/components/chat/ChatRow.tsx b/webview-ui/src/components/chat/ChatRow.tsx index 1533bba3a8..41c5863c96 100644 --- a/webview-ui/src/components/chat/ChatRow.tsx +++ b/webview-ui/src/components/chat/ChatRow.tsx @@ -258,6 +258,7 @@ export const ChatRowContent = ({ Roo wants to edit this file:
void isLoading?: boolean + progressStatus?: ToolProgressStatus } /* @@ -32,6 +34,7 @@ const CodeAccordian = ({ isExpanded, onToggleExpand, isLoading, + progressStatus, }: CodeAccordianProps) => { const inferredLanguage = useMemo( () => code && (language ?? (path ? getLanguageFromPath(path) : undefined)), @@ -95,6 +98,16 @@ const CodeAccordian = ({ )}
+ {progressStatus && progressStatus.text && ( + + {progressStatus.text} + + )} )} From 4cf7754e655b069b05e30ee7255456b0babf3a65 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Sat, 8 Mar 2025 17:24:34 -0500 Subject: [PATCH 07/32] Strip BOM when applying diffs --- jest.config.js | 3 ++- package-lock.json | 22 ++++++++++++++++----- package.json | 3 ++- src/__mocks__/strip-bom.js | 13 ++++++++++++ src/integrations/editor/DiffViewProvider.ts | 9 +++++++-- 5 files changed, 41 insertions(+), 9 deletions(-) create mode 100644 src/__mocks__/strip-bom.js diff --git a/jest.config.js b/jest.config.js index dbe5ee54eb..c18b6e9eff 100644 --- a/jest.config.js +++ b/jest.config.js @@ -30,9 +30,10 @@ module.exports = { "^strip-ansi$": "/src/__mocks__/strip-ansi.js", "^default-shell$": "/src/__mocks__/default-shell.js", "^os-name$": "/src/__mocks__/os-name.js", + "^strip-bom$": "/src/__mocks__/strip-bom.js", }, transformIgnorePatterns: [ - "node_modules/(?!(@modelcontextprotocol|delay|p-wait-for|globby|serialize-error|strip-ansi|default-shell|os-name)/)", + "node_modules/(?!(@modelcontextprotocol|delay|p-wait-for|globby|serialize-error|strip-ansi|default-shell|os-name|strip-bom)/)", ], roots: ["/src", "/webview-ui/src"], modulePathIgnorePatterns: [".vscode-test"], diff --git a/package-lock.json b/package-lock.json index 3b8f47c2e2..7c8935b791 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,6 +51,7 @@ "sound-play": "^1.1.0", "string-similarity": "^4.0.4", "strip-ansi": "^7.1.0", + "strip-bom": "^5.0.0", "tmp": "^0.2.3", "tree-sitter-wasms": "^0.1.11", "turndown": "^7.2.0", @@ -10782,6 +10783,15 @@ "node": ">=8" } }, + "node_modules/jest-runtime/node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-simple-dot-reporter": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/jest-simple-dot-reporter/-/jest-simple-dot-reporter-1.0.5.tgz", @@ -14170,12 +14180,14 @@ } }, "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-5.0.0.tgz", + "integrity": "sha512-p+byADHF7SzEcVnLvc/r3uognM1hUhObuHXxJcgLCfD194XAkaLbjq3Wzb0N5G2tgIjH0dgT708Z51QxMeu60A==", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/strip-final-newline": { diff --git a/package.json b/package.json index 5ddd9320f1..926218b21c 100644 --- a/package.json +++ b/package.json @@ -265,8 +265,8 @@ "@anthropic-ai/sdk": "^0.37.0", "@anthropic-ai/vertex-sdk": "^0.7.0", "@aws-sdk/client-bedrock-runtime": "^3.706.0", - "@google/generative-ai": "^0.18.0", "@google-cloud/vertexai": "^1.9.3", + "@google/generative-ai": "^0.18.0", "@mistralai/mistralai": "^1.3.6", "@modelcontextprotocol/sdk": "^1.0.1", "@types/clone-deep": "^4.0.4", @@ -304,6 +304,7 @@ "sound-play": "^1.1.0", "string-similarity": "^4.0.4", "strip-ansi": "^7.1.0", + "strip-bom": "^5.0.0", "tmp": "^0.2.3", "tree-sitter-wasms": "^0.1.11", "turndown": "^7.2.0", diff --git a/src/__mocks__/strip-bom.js b/src/__mocks__/strip-bom.js new file mode 100644 index 0000000000..64bb0dac4f --- /dev/null +++ b/src/__mocks__/strip-bom.js @@ -0,0 +1,13 @@ +// Mock implementation of strip-bom +module.exports = function stripBom(string) { + if (typeof string !== "string") { + throw new TypeError("Expected a string") + } + + // Removes UTF-8 BOM + if (string.charCodeAt(0) === 0xfeff) { + return string.slice(1) + } + + return string +} diff --git a/src/integrations/editor/DiffViewProvider.ts b/src/integrations/editor/DiffViewProvider.ts index ee24d7db4e..5058ca0252 100644 --- a/src/integrations/editor/DiffViewProvider.ts +++ b/src/integrations/editor/DiffViewProvider.ts @@ -7,6 +7,7 @@ import { formatResponse } from "../../core/prompts/responses" import { DecorationController } from "./DecorationController" import * as diff from "diff" import { diagnosticsToProblemsString, getNewDiagnostics } from "../diagnostics" +import stripBom from "strip-bom" export const DIFF_VIEW_URI_SCHEME = "cline-diff" @@ -104,7 +105,7 @@ export class DiffViewProvider { const edit = new vscode.WorkspaceEdit() const rangeToReplace = new vscode.Range(0, 0, endLine + 1, 0) const contentToReplace = accumulatedLines.slice(0, endLine + 1).join("\n") + "\n" - edit.replace(document.uri, rangeToReplace, contentToReplace) + edit.replace(document.uri, rangeToReplace, stripBom(stripBom(contentToReplace))) await vscode.workspace.applyEdit(edit) // Update decorations this.activeLineController.setActiveLine(endLine) @@ -128,7 +129,11 @@ export class DiffViewProvider { } // Apply the final content const finalEdit = new vscode.WorkspaceEdit() - finalEdit.replace(document.uri, new vscode.Range(0, 0, document.lineCount, 0), accumulatedContent) + finalEdit.replace( + document.uri, + new vscode.Range(0, 0, document.lineCount, 0), + stripBom(stripBom(accumulatedContent)), + ) await vscode.workspace.applyEdit(finalEdit) // Clear all decorations at the end (after applying final edit) this.fadedOverlayController.clear() From 585d5aba5ac0f3188cdb7b8e78f22ab8d088efd7 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Sat, 8 Mar 2025 18:44:03 -0500 Subject: [PATCH 08/32] Strip all BOMs --- src/integrations/editor/DiffViewProvider.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/integrations/editor/DiffViewProvider.ts b/src/integrations/editor/DiffViewProvider.ts index 5058ca0252..2aab8f9115 100644 --- a/src/integrations/editor/DiffViewProvider.ts +++ b/src/integrations/editor/DiffViewProvider.ts @@ -105,7 +105,7 @@ export class DiffViewProvider { const edit = new vscode.WorkspaceEdit() const rangeToReplace = new vscode.Range(0, 0, endLine + 1, 0) const contentToReplace = accumulatedLines.slice(0, endLine + 1).join("\n") + "\n" - edit.replace(document.uri, rangeToReplace, stripBom(stripBom(contentToReplace))) + edit.replace(document.uri, rangeToReplace, this.stripAllBOMs(contentToReplace)) await vscode.workspace.applyEdit(edit) // Update decorations this.activeLineController.setActiveLine(endLine) @@ -132,7 +132,7 @@ export class DiffViewProvider { finalEdit.replace( document.uri, new vscode.Range(0, 0, document.lineCount, 0), - stripBom(stripBom(accumulatedContent)), + this.stripAllBOMs(accumulatedContent), ) await vscode.workspace.applyEdit(finalEdit) // Clear all decorations at the end (after applying final edit) @@ -341,6 +341,16 @@ export class DiffViewProvider { } } + private stripAllBOMs(input: string): string { + let result = input + let previous + do { + previous = result + result = stripBom(result) + } while (result !== previous) + return result + } + // close editor if open? async reset() { this.editType = undefined From 1c8071bbb371f019994c0bf7849ba37df2ef67e7 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Sat, 8 Mar 2025 22:55:04 -0500 Subject: [PATCH 09/32] Clean up the tool progress UX --- src/core/diff/strategies/multi-search-replace.ts | 12 +++++++----- src/shared/ExtensionMessage.ts | 1 + webview-ui/src/components/common/CodeAccordian.tsx | 14 ++++++-------- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/core/diff/strategies/multi-search-replace.ts b/src/core/diff/strategies/multi-search-replace.ts index 0462629b9b..bcf2f65430 100644 --- a/src/core/diff/strategies/multi-search-replace.ts +++ b/src/core/diff/strategies/multi-search-replace.ts @@ -368,18 +368,20 @@ Only use a single line of '=======' between search and replacement content, beca getProgressStatus(toolUse: ToolUse, result?: DiffResult): ToolProgressStatus { const diffContent = toolUse.params.diff if (diffContent) { + const icon = "diff-multiple" + const searchBlockCount = (diffContent.match(/SEARCH/g) || []).length if (toolUse.partial) { if (diffContent.length < 1000 || (diffContent.length / 50) % 10 === 0) { - return { text: `progressing ${(diffContent.match(/SEARCH/g) || []).length} blocks...` } + return { icon, text: `${searchBlockCount}` } } } else if (result) { - const searchBlockCount = (diffContent.match(/SEARCH/g) || []).length - if (result.failParts) { + if (result.failParts?.length) { return { - text: `progressed ${searchBlockCount - result.failParts.length}/${searchBlockCount} blocks.`, + icon, + text: `${searchBlockCount - result.failParts.length}/${searchBlockCount}`, } } else { - return { text: `progressed ${searchBlockCount} blocks.` } + return { icon, text: `${searchBlockCount}` } } } } diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index c051aab5a6..4e76b0abbc 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -277,5 +277,6 @@ export interface HumanRelayCancelMessage { export type ClineApiReqCancelReason = "streaming_failed" | "user_cancelled" export type ToolProgressStatus = { + icon?: string text?: string } diff --git a/webview-ui/src/components/common/CodeAccordian.tsx b/webview-ui/src/components/common/CodeAccordian.tsx index defafdc869..9d2f224ffb 100644 --- a/webview-ui/src/components/common/CodeAccordian.tsx +++ b/webview-ui/src/components/common/CodeAccordian.tsx @@ -99,14 +99,12 @@ const CodeAccordian = ({ )}
{progressStatus && progressStatus.text && ( - - {progressStatus.text} - + <> + {progressStatus.icon && } + + {progressStatus.text} + + )} From e10757d6fadabeaae58441ebbadfa3e7ec5e3e2b Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Sat, 8 Mar 2025 23:46:28 -0500 Subject: [PATCH 10/32] Iterate on subtasks UX --- src/core/Cline.ts | 2 +- src/core/webview/ClineProvider.ts | 14 ++++----- src/shared/ExtensionMessage.ts | 2 +- src/shared/WebviewMessage.ts | 2 +- src/shared/globalState.ts | 2 +- .../src/components/chat/AutoApproveMenu.tsx | 31 +++++++++---------- webview-ui/src/components/chat/ChatRow.tsx | 6 ++-- webview-ui/src/components/chat/ChatView.tsx | 13 ++++---- .../settings/AutoApproveSettings.tsx | 17 +++++----- .../src/components/settings/SettingsView.tsx | 6 ++-- .../src/context/ExtensionStateContext.tsx | 4 +-- 11 files changed, 47 insertions(+), 52 deletions(-) diff --git a/src/core/Cline.ts b/src/core/Cline.ts index be5306dd28..3d27a50255 100644 --- a/src/core/Cline.ts +++ b/src/core/Cline.ts @@ -1431,7 +1431,7 @@ export class Cline { const toolMessage = JSON.stringify({ tool: "finishTask", content: - "Task completed! You can review the results and suggest any corrections or next steps. If everything looks good, confirm to continue with the next task.", + "Subtask completed! You can review the results and suggest any corrections or next steps. If everything looks good, confirm to return the result to the parent task.", }) return await askApproval("tool", toolMessage) diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 90885cec43..657e4a9ab6 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -984,8 +984,8 @@ export class ClineProvider implements vscode.WebviewViewProvider { await this.updateGlobalState("alwaysAllowModeSwitch", message.bool) await this.postStateToWebview() break - case "alwaysAllowFinishTask": - await this.updateGlobalState("alwaysAllowFinishTask", message.bool) + case "alwaysAllowSubtasks": + await this.updateGlobalState("alwaysAllowSubtasks", message.bool) await this.postStateToWebview() break case "askResponse": @@ -997,9 +997,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { break case "clearTask": // clear task resets the current session and allows for a new task to be started, if this session is a subtask - it allows the parent task to be resumed - await this.finishSubTask( - `new_task finished with an error!, it was stopped and canceled by the user.`, - ) + await this.finishSubTask(`Task error: It was stopped and canceled by the user.`) await this.postStateToWebview() break case "didShowAnnouncement": @@ -2181,7 +2179,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { alwaysAllowBrowser, alwaysAllowMcp, alwaysAllowModeSwitch, - alwaysAllowFinishTask, + alwaysAllowSubtasks, soundEnabled, diffEnabled, enableCheckpoints, @@ -2229,7 +2227,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { alwaysAllowBrowser: alwaysAllowBrowser ?? false, alwaysAllowMcp: alwaysAllowMcp ?? false, alwaysAllowModeSwitch: alwaysAllowModeSwitch ?? false, - alwaysAllowFinishTask: alwaysAllowFinishTask ?? false, + alwaysAllowSubtasks: alwaysAllowSubtasks ?? false, uriScheme: vscode.env.uriScheme, currentTaskItem: this.getCurrentCline()?.taskId ? (taskHistory || []).find((item: HistoryItem) => item.id === this.getCurrentCline()?.taskId) @@ -2391,7 +2389,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { alwaysAllowBrowser: stateValues.alwaysAllowBrowser ?? false, alwaysAllowMcp: stateValues.alwaysAllowMcp ?? false, alwaysAllowModeSwitch: stateValues.alwaysAllowModeSwitch ?? false, - alwaysAllowFinishTask: stateValues.alwaysAllowFinishTask ?? false, + alwaysAllowSubtasks: stateValues.alwaysAllowSubtasks ?? false, taskHistory: stateValues.taskHistory, allowedCommands: stateValues.allowedCommands, soundEnabled: stateValues.soundEnabled ?? false, diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index 4e76b0abbc..b7e3d850cf 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -109,7 +109,7 @@ export interface ExtensionState { alwaysAllowMcp?: boolean alwaysApproveResubmit?: boolean alwaysAllowModeSwitch?: boolean - alwaysAllowFinishTask?: boolean + alwaysAllowSubtasks?: boolean browserToolEnabled?: boolean requestDelaySeconds: number rateLimitSeconds: number // Minimum time between successive requests (0 = disabled) diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index 086701a43f..216c7588d7 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -48,7 +48,7 @@ export interface WebviewMessage { | "alwaysAllowBrowser" | "alwaysAllowMcp" | "alwaysAllowModeSwitch" - | "alwaysAllowFinishTask" + | "alwaysAllowSubtasks" | "playSound" | "soundEnabled" | "soundVolume" diff --git a/src/shared/globalState.ts b/src/shared/globalState.ts index 739fa11dad..35e53bbe9c 100644 --- a/src/shared/globalState.ts +++ b/src/shared/globalState.ts @@ -40,7 +40,7 @@ export const GLOBAL_STATE_KEYS = [ "alwaysAllowBrowser", "alwaysAllowMcp", "alwaysAllowModeSwitch", - "alwaysAllowFinishTask", + "alwaysAllowSubtasks", "taskHistory", "openAiBaseUrl", "openAiModelId", diff --git a/webview-ui/src/components/chat/AutoApproveMenu.tsx b/webview-ui/src/components/chat/AutoApproveMenu.tsx index fba97f6c7d..692cf1d44c 100644 --- a/webview-ui/src/components/chat/AutoApproveMenu.tsx +++ b/webview-ui/src/components/chat/AutoApproveMenu.tsx @@ -30,8 +30,8 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => { setAlwaysAllowMcp, alwaysAllowModeSwitch, setAlwaysAllowModeSwitch, - alwaysAllowFinishTask, - setAlwaysAllowFinishTask, + alwaysAllowSubtasks, + setAlwaysAllowSubtasks, alwaysApproveResubmit, setAlwaysApproveResubmit, autoApprovalEnabled, @@ -77,18 +77,17 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => { }, { id: "switchModes", - label: "Switch modes & create tasks", + label: "Switch modes", shortName: "Modes", enabled: alwaysAllowModeSwitch ?? false, - description: - "Allows automatic switching between different AI modes and creating new tasks without requiring approval.", + description: "Allows automatic switching between different modes without requiring approval.", }, { - id: "finishTask", - label: "Continue to next task", - shortName: "Continue", - enabled: alwaysAllowFinishTask ?? false, - description: "Allow tasks to end execution and continue to the next task, without user review or approval.", + id: "subtasks", + label: "Create & complete subtasks", + shortName: "Subtasks", + enabled: alwaysAllowSubtasks ?? false, + description: "Allow creation and completion of subtasks without requiring approval.", }, { id: "retryRequests", @@ -145,11 +144,11 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => { vscode.postMessage({ type: "alwaysAllowModeSwitch", bool: newValue }) }, [alwaysAllowModeSwitch, setAlwaysAllowModeSwitch]) - const handleFinishTaskChange = useCallback(() => { - const newValue = !(alwaysAllowFinishTask ?? false) - setAlwaysAllowFinishTask(newValue) - vscode.postMessage({ type: "alwaysAllowFinishTask", bool: newValue }) - }, [alwaysAllowFinishTask, setAlwaysAllowFinishTask]) + const handleSubtasksChange = useCallback(() => { + const newValue = !(alwaysAllowSubtasks ?? false) + setAlwaysAllowSubtasks(newValue) + vscode.postMessage({ type: "alwaysAllowSubtasks", bool: newValue }) + }, [alwaysAllowSubtasks, setAlwaysAllowSubtasks]) const handleRetryChange = useCallback(() => { const newValue = !(alwaysApproveResubmit ?? false) @@ -165,7 +164,7 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => { useBrowser: handleBrowserChange, useMcp: handleMcpChange, switchModes: handleModeSwitchChange, - finishTask: handleFinishTaskChange, + subtasks: handleSubtasksChange, retryRequests: handleRetryChange, } diff --git a/webview-ui/src/components/chat/ChatRow.tsx b/webview-ui/src/components/chat/ChatRow.tsx index bb5237dd23..b19d67dc05 100644 --- a/webview-ui/src/components/chat/ChatRow.tsx +++ b/webview-ui/src/components/chat/ChatRow.tsx @@ -452,7 +452,7 @@ export const ChatRowContent = ({
{toolIcon("new-file")} - Roo wants to create a new task in {tool.mode} mode: + Roo wants to create a new subtask in {tool.mode} mode:
@@ -464,8 +464,8 @@ export const ChatRowContent = ({ return ( <>
- {toolIcon("new-file")} - Roo wants to finish this task + {toolIcon("checklist")} + Roo wants to finish this subtask
{tool.content} diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index b92604e157..5ac7f50559 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -61,7 +61,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie setMode, autoApprovalEnabled, alwaysAllowModeSwitch, - alwaysAllowFinishTask, + alwaysAllowSubtasks, customModes, telemetrySetting, } = useExtensionState() @@ -150,7 +150,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie setSecondaryButtonText("Reject") break case "finishTask": - setPrimaryButtonText("Approve & Continue to the next Task") + setPrimaryButtonText("Complete Subtask and Return") setSecondaryButtonText(undefined) break default: @@ -646,11 +646,10 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie (alwaysAllowMcp && message.ask === "use_mcp_server" && isMcpToolAlwaysAllowed(message)) || (alwaysAllowModeSwitch && message.ask === "tool" && - (JSON.parse(message.text || "{}")?.tool === "switchMode" || - JSON.parse(message.text || "{}")?.tool === "newTask")) || - (alwaysAllowFinishTask && + JSON.parse(message.text || "{}")?.tool === "switchMode") || + (alwaysAllowSubtasks && message.ask === "tool" && - JSON.parse(message.text || "{}")?.tool === "finishTask") + ["newTask", "finishTask"].includes(JSON.parse(message.text || "{}")?.tool)) ) }, [ @@ -665,7 +664,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie alwaysAllowMcp, isMcpToolAlwaysAllowed, alwaysAllowModeSwitch, - alwaysAllowFinishTask, + alwaysAllowSubtasks, ], ) diff --git a/webview-ui/src/components/settings/AutoApproveSettings.tsx b/webview-ui/src/components/settings/AutoApproveSettings.tsx index 1c8e6c9ea9..d26fc33a7c 100644 --- a/webview-ui/src/components/settings/AutoApproveSettings.tsx +++ b/webview-ui/src/components/settings/AutoApproveSettings.tsx @@ -18,7 +18,7 @@ type AutoApproveSettingsProps = HTMLAttributes & { requestDelaySeconds: number alwaysAllowMcp?: boolean alwaysAllowModeSwitch?: boolean - alwaysAllowFinishTask?: boolean + alwaysAllowSubtasks?: boolean alwaysAllowExecute?: boolean allowedCommands?: string[] setCachedStateField: SetCachedStateField @@ -33,7 +33,7 @@ export const AutoApproveSettings = ({ requestDelaySeconds, alwaysAllowMcp, alwaysAllowModeSwitch, - alwaysAllowFinishTask, + alwaysAllowSubtasks, alwaysAllowExecute, allowedCommands, setCachedStateField, @@ -175,22 +175,21 @@ export const AutoApproveSettings = ({ setCachedStateField("alwaysAllowModeSwitch", e.target.checked)}> - Always approve mode switching & task creation + Always approve mode switching

- Automatically switch between different AI modes and create new tasks without requiring approval + Automatically switch between different modes without requiring approval

setCachedStateField("alwaysAllowFinishTask", e.target.checked)}> - Always approve finish & continue to next task + checked={alwaysAllowSubtasks} + onChange={(e: any) => setCachedStateField("alwaysAllowSubtasks", e.target.checked)}> + Always approve creation & completion of subtasks

- Automatically approve tasks to finish execution and continue to the next task, without user - review or approval + Allow creation and completion of subtasks without requiring approval

diff --git a/webview-ui/src/components/settings/SettingsView.tsx b/webview-ui/src/components/settings/SettingsView.tsx index 550fa73ca8..7cafbd6663 100644 --- a/webview-ui/src/components/settings/SettingsView.tsx +++ b/webview-ui/src/components/settings/SettingsView.tsx @@ -63,7 +63,7 @@ const SettingsView = forwardRef(({ onDone }, alwaysAllowExecute, alwaysAllowMcp, alwaysAllowModeSwitch, - alwaysAllowFinishTask, + alwaysAllowSubtasks, alwaysAllowWrite, alwaysApproveResubmit, browserToolEnabled, @@ -185,7 +185,7 @@ const SettingsView = forwardRef(({ onDone }, vscode.postMessage({ type: "currentApiConfigName", text: currentApiConfigName }) vscode.postMessage({ type: "updateExperimental", values: experiments }) vscode.postMessage({ type: "alwaysAllowModeSwitch", bool: alwaysAllowModeSwitch }) - vscode.postMessage({ type: "alwaysAllowFinishTask", bool: alwaysAllowFinishTask }) + vscode.postMessage({ type: "alwaysAllowSubtasks", bool: alwaysAllowSubtasks }) vscode.postMessage({ type: "upsertApiConfiguration", text: currentApiConfigName, apiConfiguration }) vscode.postMessage({ type: "telemetrySetting", text: telemetrySetting }) setChangeDetected(false) @@ -366,7 +366,7 @@ const SettingsView = forwardRef(({ onDone }, requestDelaySeconds={requestDelaySeconds} alwaysAllowMcp={alwaysAllowMcp} alwaysAllowModeSwitch={alwaysAllowModeSwitch} - alwaysAllowFinishTask={alwaysAllowFinishTask} + alwaysAllowSubtasks={alwaysAllowSubtasks} alwaysAllowExecute={alwaysAllowExecute} allowedCommands={allowedCommands} setCachedStateField={setCachedStateField} diff --git a/webview-ui/src/context/ExtensionStateContext.tsx b/webview-ui/src/context/ExtensionStateContext.tsx index aa132919c0..8d16f2e0f0 100644 --- a/webview-ui/src/context/ExtensionStateContext.tsx +++ b/webview-ui/src/context/ExtensionStateContext.tsx @@ -31,7 +31,7 @@ export interface ExtensionStateContextType extends ExtensionState { setAlwaysAllowBrowser: (value: boolean) => void setAlwaysAllowMcp: (value: boolean) => void setAlwaysAllowModeSwitch: (value: boolean) => void - setAlwaysAllowFinishTask: (value: boolean) => void + setAlwaysAllowSubtasks: (value: boolean) => void setBrowserToolEnabled: (value: boolean) => void setShowRooIgnoredFiles: (value: boolean) => void setShowAnnouncement: (value: boolean) => void @@ -248,7 +248,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode setAlwaysAllowBrowser: (value) => setState((prevState) => ({ ...prevState, alwaysAllowBrowser: value })), setAlwaysAllowMcp: (value) => setState((prevState) => ({ ...prevState, alwaysAllowMcp: value })), setAlwaysAllowModeSwitch: (value) => setState((prevState) => ({ ...prevState, alwaysAllowModeSwitch: value })), - setAlwaysAllowFinishTask: (value) => setState((prevState) => ({ ...prevState, alwaysAllowFinishTask: value })), + setAlwaysAllowSubtasks: (value) => setState((prevState) => ({ ...prevState, alwaysAllowSubtasks: value })), setShowAnnouncement: (value) => setState((prevState) => ({ ...prevState, shouldShowAnnouncement: value })), setAllowedCommands: (value) => setState((prevState) => ({ ...prevState, allowedCommands: value })), setSoundEnabled: (value) => setState((prevState) => ({ ...prevState, soundEnabled: value })), From 91d16896b1457122fdfd3dc7e4045ecb1764e27c Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Sat, 8 Mar 2025 23:46:49 -0500 Subject: [PATCH 11/32] Changeset --- .changeset/modern-pillows-visit.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/modern-pillows-visit.md diff --git a/.changeset/modern-pillows-visit.md b/.changeset/modern-pillows-visit.md new file mode 100644 index 0000000000..4e5188175d --- /dev/null +++ b/.changeset/modern-pillows-visit.md @@ -0,0 +1,5 @@ +--- +"roo-cline": patch +--- + +v3.8.2 From 148e0560a1e0c6c70283d2c2c767b7fb6e125ba3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 9 Mar 2025 05:02:18 +0000 Subject: [PATCH 12/32] changeset version bump --- .changeset/modern-pillows-visit.md | 5 ----- .changeset/wild-dragons-leave.md | 5 ----- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 10 insertions(+), 13 deletions(-) delete mode 100644 .changeset/modern-pillows-visit.md delete mode 100644 .changeset/wild-dragons-leave.md diff --git a/.changeset/modern-pillows-visit.md b/.changeset/modern-pillows-visit.md deleted file mode 100644 index 4e5188175d..0000000000 --- a/.changeset/modern-pillows-visit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"roo-cline": patch ---- - -v3.8.2 diff --git a/.changeset/wild-dragons-leave.md b/.changeset/wild-dragons-leave.md deleted file mode 100644 index 05320a4aa2..0000000000 --- a/.changeset/wild-dragons-leave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"roo-cline": patch ---- - -Add o3-mini support to openai compatible diff --git a/CHANGELOG.md b/CHANGELOG.md index ff2aa8de27..ba5d4ca8a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Roo Code Changelog +## 3.8.2 + +### Patch Changes + +- v3.8.2 +- Add o3-mini support to openai compatible + ## [3.8.1] - 2025-03-07 - Show the reserved output tokens in the context window visualization diff --git a/package-lock.json b/package-lock.json index 7c8935b791..61b8eea298 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "roo-cline", - "version": "3.8.1", + "version": "3.8.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "roo-cline", - "version": "3.8.1", + "version": "3.8.2", "dependencies": { "@anthropic-ai/bedrock-sdk": "^0.10.2", "@anthropic-ai/sdk": "^0.37.0", diff --git a/package.json b/package.json index 926218b21c..c3adb234b3 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "displayName": "Roo Code (prev. Roo Cline)", "description": "A whole dev team of AI agents in your editor.", "publisher": "RooVeterinaryInc", - "version": "3.8.1", + "version": "3.8.2", "icon": "assets/icons/rocket.png", "galleryBanner": { "color": "#617A91", From f4df55f020b310ec002e361cfb996c20ee7c40bf Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Sun, 9 Mar 2025 00:04:30 -0500 Subject: [PATCH 13/32] Update CHANGELOG.md --- CHANGELOG.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba5d4ca8a7..ac03780cc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,12 @@ # Roo Code Changelog -## 3.8.2 +## [3.8.2] - 2025-03-08 -### Patch Changes - -- v3.8.2 -- Add o3-mini support to openai compatible +- Create an auto-approval toggle for subtask creation and completion (thanks @shaybc!) +- Show a progress indicator when using the multi-diff editing strategy (thanks @qdaxb!) +- Add o3-mini support to the OpenAI-compatible provider (thanks @yt3trees!) +- Fix encoding issue where unreadable characters were sometimes getting added to the beginning of files +- Fix issue where settings dropdowns were getting truncated in some cases ## [3.8.1] - 2025-03-07 From 2a08c7c3dbbcaac5fc8b005109a0929a1ed8e9ef Mon Sep 17 00:00:00 2001 From: Roo Code Date: Sat, 8 Mar 2025 22:05:27 -0700 Subject: [PATCH 14/32] feat: Add toggle for custom mode creation This commit adds a new setting to allow users to disable custom mode creation, which can help reduce token usage in Roo's prompts. Key changes: Add enableCustomModeCreation setting to global state Conditionally include custom modes documentation in prompt only when enabled Add UI toggle in PromptsView with explanatory text Default the setting to enabled (true) for backward compatibility Update necessary interfaces and message handlers for the new setting The setting is placed in PromptsView rather than SettingsView since it directly relates to the modes functionality managed in that component. --- src/core/prompts/sections/modes.ts | 16 +++++++- src/core/webview/ClineProvider.ts | 4 ++ src/shared/ExtensionMessage.ts | 1 + src/shared/WebviewMessage.ts | 1 + src/shared/globalState.ts | 1 + .../src/components/prompts/PromptsView.tsx | 40 ++++++++++++++++++- .../src/context/ExtensionStateContext.tsx | 5 +++ 7 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/core/prompts/sections/modes.ts b/src/core/prompts/sections/modes.ts index f3863870db..d561e47a84 100644 --- a/src/core/prompts/sections/modes.ts +++ b/src/core/prompts/sections/modes.ts @@ -11,12 +11,21 @@ export async function getModesSection(context: vscode.ExtensionContext): Promise // Get all modes with their overrides from extension state const allModes = await getAllModesWithPrompts(context) - return `==== + // Get enableCustomModeCreation setting from extension state + const enableCustomModeCreation = await context.globalState.get("enableCustomModeCreation") + // Default to true if undefined + const shouldEnableCustomModeCreation = enableCustomModeCreation !== undefined ? enableCustomModeCreation : true + + let modesContent = `==== MODES - These are the currently available modes: -${allModes.map((mode: ModeConfig) => ` * "${mode.name}" mode (${mode.slug}) - ${mode.roleDefinition.split(".")[0]}`).join("\n")} +${allModes.map((mode: ModeConfig) => ` * "${mode.name}" mode (${mode.slug}) - ${mode.roleDefinition.split(".")[0]}`).join("\n")}` + + // Only include custom modes documentation if the feature is enabled + if (shouldEnableCustomModeCreation) { + modesContent += ` - Custom modes can be configured in two ways: 1. Globally via '${customModesPath}' (created automatically on startup) @@ -56,4 +65,7 @@ Both files should follow this structure: } ] }` + } + + return modesContent } diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index e1d67b5a28..75689e2450 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -1476,6 +1476,10 @@ export class ClineProvider implements vscode.WebviewViewProvider { await this.updateGlobalState("enhancementApiConfigId", message.text) await this.postStateToWebview() break + case "enableCustomModeCreation": + await this.updateGlobalState("enableCustomModeCreation", message.bool ?? true) + await this.postStateToWebview() + break case "autoApprovalEnabled": await this.updateGlobalState("autoApprovalEnabled", message.bool ?? false) await this.postStateToWebview() diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index 98ff9b36e1..78c60acc97 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -128,6 +128,7 @@ export interface ExtensionState { terminalOutputLimit?: number mcpEnabled: boolean enableMcpServerCreation: boolean + enableCustomModeCreation?: boolean mode: Mode modeApiConfigs?: Record enhancementApiConfigId?: string diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index 10af6f7a94..37328cd95a 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -71,6 +71,7 @@ export interface WebviewMessage { | "terminalOutputLimit" | "mcpEnabled" | "enableMcpServerCreation" + | "enableCustomModeCreation" | "searchCommits" | "alwaysApproveResubmit" | "requestDelaySeconds" diff --git a/src/shared/globalState.ts b/src/shared/globalState.ts index bfd24f4298..579bf1df86 100644 --- a/src/shared/globalState.ts +++ b/src/shared/globalState.ts @@ -84,6 +84,7 @@ export const GLOBAL_STATE_KEYS = [ "enhancementApiConfigId", "experiments", // Map of experiment IDs to their enabled state "autoApprovalEnabled", + "enableCustomModeCreation", // Enable the ability to create custom modes "customModes", // Array of custom modes "unboundModelId", "requestyModelId", diff --git a/webview-ui/src/components/prompts/PromptsView.tsx b/webview-ui/src/components/prompts/PromptsView.tsx index ccf1e6d700..e14ce8f939 100644 --- a/webview-ui/src/components/prompts/PromptsView.tsx +++ b/webview-ui/src/components/prompts/PromptsView.tsx @@ -71,6 +71,8 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { preferredLanguage, setPreferredLanguage, customModes, + enableCustomModeCreation, + setEnableCustomModeCreation, } = useExtensionState() // Memoize modes to preserve array order @@ -341,6 +343,17 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { return () => document.removeEventListener("click", handleClickOutside) }, [showConfigMenu]) + // Add effect to sync enableCustomModeCreation with backend + useEffect(() => { + if (enableCustomModeCreation !== undefined) { + // Send the value to the extension's global state + vscode.postMessage({ + type: "enableCustomModeCreation", // Using dedicated message type + bool: enableCustomModeCreation, + }) + } + }, [enableCustomModeCreation]) + useEffect(() => { const handler = (event: MessageEvent) => { const message = event.data @@ -541,8 +554,33 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { in your workspace.
-
+ {/* + NOTE: This setting is placed in PromptsView rather than SettingsView since it + directly affects the functionality related to modes and custom mode creation, + which are managed in this component. This is an intentional deviation from + the standard pattern described in cline_docs/settings.md. + */} +
+ { + // Just update the local state through React context + // The React context will update the global state + setEnableCustomModeCreation(e.target.checked) + }}> + Enable Custom Mode Creation + +

+ When enabled, Roo can help you create project-level custom modes. You can disable this to + reduce Roo's token usage. +

+
e.stopPropagation()} className="flex justify-between items-center mb-3">

Modes

diff --git a/webview-ui/src/context/ExtensionStateContext.tsx b/webview-ui/src/context/ExtensionStateContext.tsx index c4daf426ca..3ed42b8586 100644 --- a/webview-ui/src/context/ExtensionStateContext.tsx +++ b/webview-ui/src/context/ExtensionStateContext.tsx @@ -52,6 +52,8 @@ export interface ExtensionStateContextType extends ExtensionState { setMcpEnabled: (value: boolean) => void enableMcpServerCreation: boolean setEnableMcpServerCreation: (value: boolean) => void + enableCustomModeCreation?: boolean + setEnableCustomModeCreation: (value: boolean) => void alwaysApproveResubmit?: boolean setAlwaysApproveResubmit: (value: boolean) => void requestDelaySeconds: number @@ -117,6 +119,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode checkpointStorage: "task", fuzzyMatchThreshold: 1.0, preferredLanguage: "English", + enableCustomModeCreation: true, writeDelayMs: 1000, browserViewportSize: "900x600", screenshotQuality: 75, @@ -273,6 +276,8 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode setCustomSupportPrompts: (value) => setState((prevState) => ({ ...prevState, customSupportPrompts: value })), setEnhancementApiConfigId: (value) => setState((prevState) => ({ ...prevState, enhancementApiConfigId: value })), + setEnableCustomModeCreation: (value) => + setState((prevState) => ({ ...prevState, enableCustomModeCreation: value })), setAutoApprovalEnabled: (value) => setState((prevState) => ({ ...prevState, autoApprovalEnabled: value })), setCustomModes: (value) => setState((prevState) => ({ ...prevState, customModes: value })), setMaxOpenTabsContext: (value) => setState((prevState) => ({ ...prevState, maxOpenTabsContext: value })), From f6efa2b589b5ebda5204c64cbca9eba346483c25 Mon Sep 17 00:00:00 2001 From: Hannes Rudolph <49103247+hannesrudolph@users.noreply.github.com> Date: Sat, 8 Mar 2025 22:31:10 -0700 Subject: [PATCH 15/32] Update src/core/prompts/sections/modes.ts Co-authored-by: Matt Rubens --- src/core/prompts/sections/modes.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/core/prompts/sections/modes.ts b/src/core/prompts/sections/modes.ts index d561e47a84..788c7d7ebe 100644 --- a/src/core/prompts/sections/modes.ts +++ b/src/core/prompts/sections/modes.ts @@ -12,9 +12,7 @@ export async function getModesSection(context: vscode.ExtensionContext): Promise const allModes = await getAllModesWithPrompts(context) // Get enableCustomModeCreation setting from extension state - const enableCustomModeCreation = await context.globalState.get("enableCustomModeCreation") - // Default to true if undefined - const shouldEnableCustomModeCreation = enableCustomModeCreation !== undefined ? enableCustomModeCreation : true + const shouldEnableCustomModeCreation = await context.globalState.get("enableCustomModeCreation") ?? true let modesContent = `==== From bb87b7896b595093da4d1731112fe00662a16575 Mon Sep 17 00:00:00 2001 From: Hannes Rudolph <49103247+hannesrudolph@users.noreply.github.com> Date: Sat, 8 Mar 2025 22:31:20 -0700 Subject: [PATCH 16/32] Update src/shared/globalState.ts Co-authored-by: Matt Rubens --- src/shared/globalState.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/globalState.ts b/src/shared/globalState.ts index 579bf1df86..fd21d1c669 100644 --- a/src/shared/globalState.ts +++ b/src/shared/globalState.ts @@ -84,7 +84,7 @@ export const GLOBAL_STATE_KEYS = [ "enhancementApiConfigId", "experiments", // Map of experiment IDs to their enabled state "autoApprovalEnabled", - "enableCustomModeCreation", // Enable the ability to create custom modes + "enableCustomModeCreation", // Enable the ability for Roo to create custom modes "customModes", // Array of custom modes "unboundModelId", "requestyModelId", From 74a0dcebf6b61ecb97fb512ae6a55360c5b0c92e Mon Sep 17 00:00:00 2001 From: Hannes Rudolph <49103247+hannesrudolph@users.noreply.github.com> Date: Sat, 8 Mar 2025 22:32:14 -0700 Subject: [PATCH 17/32] Update webview-ui/src/components/prompts/PromptsView.tsx Co-authored-by: Matt Rubens --- webview-ui/src/components/prompts/PromptsView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webview-ui/src/components/prompts/PromptsView.tsx b/webview-ui/src/components/prompts/PromptsView.tsx index e14ce8f939..11e64003d1 100644 --- a/webview-ui/src/components/prompts/PromptsView.tsx +++ b/webview-ui/src/components/prompts/PromptsView.tsx @@ -577,7 +577,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { marginTop: "5px", color: "var(--vscode-descriptionForeground)", }}> - When enabled, Roo can help you create project-level custom modes. You can disable this to + When enabled, Roo can help you create custom modes. You can disable this to reduce Roo's token usage.

From 47294dec564fd2a698b150dc3f6d3bd3e1fc4d0a Mon Sep 17 00:00:00 2001 From: Hannes Rudolph <49103247+hannesrudolph@users.noreply.github.com> Date: Sat, 8 Mar 2025 22:32:40 -0700 Subject: [PATCH 18/32] Update webview-ui/src/components/prompts/PromptsView.tsx Co-authored-by: Matt Rubens --- webview-ui/src/components/prompts/PromptsView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webview-ui/src/components/prompts/PromptsView.tsx b/webview-ui/src/components/prompts/PromptsView.tsx index 11e64003d1..7ea8bfba62 100644 --- a/webview-ui/src/components/prompts/PromptsView.tsx +++ b/webview-ui/src/components/prompts/PromptsView.tsx @@ -563,7 +563,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { */}
{ // Just update the local state through React context // The React context will update the global state From cc4f6dd6757d4b7daef0ddd3ea0ba5804a7e1547 Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Sat, 8 Mar 2025 22:40:43 -0700 Subject: [PATCH 19/32] style: Update margin styling for checkbox in PromptsView component --- webview-ui/src/components/prompts/PromptsView.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/webview-ui/src/components/prompts/PromptsView.tsx b/webview-ui/src/components/prompts/PromptsView.tsx index 7ea8bfba62..3561a80d10 100644 --- a/webview-ui/src/components/prompts/PromptsView.tsx +++ b/webview-ui/src/components/prompts/PromptsView.tsx @@ -561,7 +561,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { which are managed in this component. This is an intentional deviation from the standard pattern described in cline_docs/settings.md. */} -
+
{ @@ -577,8 +577,8 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { marginTop: "5px", color: "var(--vscode-descriptionForeground)", }}> - When enabled, Roo can help you create custom modes. You can disable this to - reduce Roo's token usage. + When enabled, Roo can help you create custom modes. You can disable this to reduce Roo's + token usage.

e.stopPropagation()} className="flex justify-between items-center mb-3"> From 68cfdc985e87bf55d1f3f04aee39469108fb76f1 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Sun, 9 Mar 2025 09:11:55 -0400 Subject: [PATCH 20/32] Fix the VSCode LM model picker --- .changeset/eleven-birds-doubt.md | 5 +++ .../src/components/settings/ApiOptions.tsx | 32 +++++++++++-------- 2 files changed, 23 insertions(+), 14 deletions(-) create mode 100644 .changeset/eleven-birds-doubt.md diff --git a/.changeset/eleven-birds-doubt.md b/.changeset/eleven-birds-doubt.md new file mode 100644 index 0000000000..977228c808 --- /dev/null +++ b/.changeset/eleven-birds-doubt.md @@ -0,0 +1,5 @@ +--- +"roo-cline": patch +--- + +Fix VS Code LM API model picker diff --git a/webview-ui/src/components/settings/ApiOptions.tsx b/webview-ui/src/components/settings/ApiOptions.tsx index c5a02dc117..f7982080c8 100644 --- a/webview-ui/src/components/settings/ApiOptions.tsx +++ b/webview-ui/src/components/settings/ApiOptions.tsx @@ -1076,27 +1076,31 @@ const ApiOptions = ({ Language Model {vsCodeLmModels.length > 0 ? ( - { - const valueStr = (e as DropdownOption)?.value + onValueChange={handleInputChange("vsCodeLmModelSelector", (valueStr) => { const [vendor, family] = valueStr.split("/") return { vendor, family } - })} - options={[ - { value: "", label: "Select a model..." }, - ...vsCodeLmModels.map((model) => ({ - value: `${model.vendor}/${model.family}`, - label: `${model.vendor} - ${model.family}`, - })), - ]} - className="w-full" - /> + })}> + + + + + + {vsCodeLmModels.map((model) => ( + + {`${model.vendor} - ${model.family}`} + + ))} + + + ) : (
The VS Code Language Model API allows you to run models provided by other VS Code From b57fcf2094c8a96a327caa271086f02259d36da3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 9 Mar 2025 13:46:40 +0000 Subject: [PATCH 21/32] changeset version bump --- .changeset/eleven-birds-doubt.md | 5 ----- CHANGELOG.md | 6 ++++++ package-lock.json | 4 ++-- package.json | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) delete mode 100644 .changeset/eleven-birds-doubt.md diff --git a/.changeset/eleven-birds-doubt.md b/.changeset/eleven-birds-doubt.md deleted file mode 100644 index 977228c808..0000000000 --- a/.changeset/eleven-birds-doubt.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"roo-cline": patch ---- - -Fix VS Code LM API model picker diff --git a/CHANGELOG.md b/CHANGELOG.md index ac03780cc8..248bdec9d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Roo Code Changelog +## 3.8.3 + +### Patch Changes + +- Fix VS Code LM API model picker + ## [3.8.2] - 2025-03-08 - Create an auto-approval toggle for subtask creation and completion (thanks @shaybc!) diff --git a/package-lock.json b/package-lock.json index 61b8eea298..6884f2e626 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "roo-cline", - "version": "3.8.2", + "version": "3.8.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "roo-cline", - "version": "3.8.2", + "version": "3.8.3", "dependencies": { "@anthropic-ai/bedrock-sdk": "^0.10.2", "@anthropic-ai/sdk": "^0.37.0", diff --git a/package.json b/package.json index c3adb234b3..e4adffd1d7 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "displayName": "Roo Code (prev. Roo Cline)", "description": "A whole dev team of AI agents in your editor.", "publisher": "RooVeterinaryInc", - "version": "3.8.2", + "version": "3.8.3", "icon": "assets/icons/rocket.png", "galleryBanner": { "color": "#617A91", From edec39b98ea05a1101e87b81619a6c7f7254f04f Mon Sep 17 00:00:00 2001 From: R00-B0T Date: Sun, 9 Mar 2025 13:47:05 +0000 Subject: [PATCH 22/32] Updating CHANGELOG.md format --- CHANGELOG.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 248bdec9d3..9c69784ac7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,6 @@ # Roo Code Changelog -## 3.8.3 - -### Patch Changes +## [3.8.3] - Fix VS Code LM API model picker From a05d7c1c8e65d9e0f086fb7101d33fb765da5a13 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Sun, 9 Mar 2025 09:51:44 -0400 Subject: [PATCH 23/32] Update CHANGELOG.md --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c69784ac7..7afcfae2d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Roo Code Changelog -## [3.8.3] +## [3.8.3] - 2025-03-09 -- Fix VS Code LM API model picker +- Fix VS Code LM API model picker truncation issue ## [3.8.2] - 2025-03-08 From 445066c430f52d5cb8f1da0cea833a8ec5f9961a Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Sun, 9 Mar 2025 15:56:23 -0600 Subject: [PATCH 24/32] refactor: Move custom mode creation setting to a more appropriate location in PromptsView component --- .../src/components/prompts/PromptsView.tsx | 55 ++++++++++--------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/webview-ui/src/components/prompts/PromptsView.tsx b/webview-ui/src/components/prompts/PromptsView.tsx index 3561a80d10..7303f7691d 100644 --- a/webview-ui/src/components/prompts/PromptsView.tsx +++ b/webview-ui/src/components/prompts/PromptsView.tsx @@ -555,32 +555,6 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
- {/* - NOTE: This setting is placed in PromptsView rather than SettingsView since it - directly affects the functionality related to modes and custom mode creation, - which are managed in this component. This is an intentional deviation from - the standard pattern described in cline_docs/settings.md. - */} -
- { - // Just update the local state through React context - // The React context will update the global state - setEnableCustomModeCreation(e.target.checked) - }}> - Enable Custom Mode Creation - -

- When enabled, Roo can help you create custom modes. You can disable this to reduce Roo's - token usage. -

-
e.stopPropagation()} className="flex justify-between items-center mb-3">

Modes

@@ -1048,6 +1022,35 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
)}
+ + {/* + NOTE: This setting is placed in PromptsView rather than SettingsView since it + directly affects the functionality related to modes and custom mode creation, + which are managed in this component. This is an intentional deviation from + the standard pattern described in cline_docs/settings.md. + */} +
+ { + // Just update the local state through React context + // The React context will update the global state + setEnableCustomModeCreation(e.target.checked) + }}> + Enable Custom Mode Creation + +

+ When enabled, Roo allows you to create custom modes using prompts like ‘Make me a custom + mode that…’. Disabling this reduces your system prompt by about 700 tokens when this feature + isn’t needed. When disabled you can still manually create custom prompts using the + button + above or by editing the related config JSON. +

+
Date: Sun, 9 Mar 2025 18:35:48 -0400 Subject: [PATCH 25/32] Revert "Clean up the tool progress UX" This reverts commit 1c8071bbb371f019994c0bf7849ba37df2ef67e7. --- src/core/diff/strategies/multi-search-replace.ts | 12 +++++------- src/shared/ExtensionMessage.ts | 1 - webview-ui/src/components/common/CodeAccordian.tsx | 14 ++++++++------ 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/core/diff/strategies/multi-search-replace.ts b/src/core/diff/strategies/multi-search-replace.ts index bcf2f65430..0462629b9b 100644 --- a/src/core/diff/strategies/multi-search-replace.ts +++ b/src/core/diff/strategies/multi-search-replace.ts @@ -368,20 +368,18 @@ Only use a single line of '=======' between search and replacement content, beca getProgressStatus(toolUse: ToolUse, result?: DiffResult): ToolProgressStatus { const diffContent = toolUse.params.diff if (diffContent) { - const icon = "diff-multiple" - const searchBlockCount = (diffContent.match(/SEARCH/g) || []).length if (toolUse.partial) { if (diffContent.length < 1000 || (diffContent.length / 50) % 10 === 0) { - return { icon, text: `${searchBlockCount}` } + return { text: `progressing ${(diffContent.match(/SEARCH/g) || []).length} blocks...` } } } else if (result) { - if (result.failParts?.length) { + const searchBlockCount = (diffContent.match(/SEARCH/g) || []).length + if (result.failParts) { return { - icon, - text: `${searchBlockCount - result.failParts.length}/${searchBlockCount}`, + text: `progressed ${searchBlockCount - result.failParts.length}/${searchBlockCount} blocks.`, } } else { - return { icon, text: `${searchBlockCount}` } + return { text: `progressed ${searchBlockCount} blocks.` } } } } diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index b7e3d850cf..0c20669ed1 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -277,6 +277,5 @@ export interface HumanRelayCancelMessage { export type ClineApiReqCancelReason = "streaming_failed" | "user_cancelled" export type ToolProgressStatus = { - icon?: string text?: string } diff --git a/webview-ui/src/components/common/CodeAccordian.tsx b/webview-ui/src/components/common/CodeAccordian.tsx index 9d2f224ffb..defafdc869 100644 --- a/webview-ui/src/components/common/CodeAccordian.tsx +++ b/webview-ui/src/components/common/CodeAccordian.tsx @@ -99,12 +99,14 @@ const CodeAccordian = ({ )}
{progressStatus && progressStatus.text && ( - <> - {progressStatus.icon && } - - {progressStatus.text} - - + + {progressStatus.text} + )}
From 183e47b1bd14a0432a6a167fe1e1e651e27059c1 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Sun, 9 Mar 2025 18:35:56 -0400 Subject: [PATCH 26/32] Revert "support tool progress status" This reverts commit 80139d88d7d7ab3baee492955a7380ade17550cc. --- src/core/Cline.ts | 26 +------------------ .../diff/strategies/multi-search-replace.ts | 23 ---------------- src/core/diff/types.ts | 5 ---- src/shared/ExtensionMessage.ts | 5 ---- webview-ui/src/components/chat/ChatRow.tsx | 1 - .../src/components/common/CodeAccordian.tsx | 13 ---------- 6 files changed, 1 insertion(+), 72 deletions(-) diff --git a/src/core/Cline.ts b/src/core/Cline.ts index 3d27a50255..3d1f980c7d 100644 --- a/src/core/Cline.ts +++ b/src/core/Cline.ts @@ -48,7 +48,6 @@ import { ClineSay, ClineSayBrowserAction, ClineSayTool, - ToolProgressStatus, } from "../shared/ExtensionMessage" import { getApiMetrics } from "../shared/getApiMetrics" import { HistoryItem } from "../shared/HistoryItem" @@ -409,7 +408,6 @@ export class Cline { type: ClineAsk, text?: string, partial?: boolean, - progressStatus?: ToolProgressStatus, ): Promise<{ response: ClineAskResponse; text?: string; images?: string[] }> { // If this Cline instance was aborted by the provider, then the only thing keeping us alive is a promise still running in the background, in which case we don't want to send its result to the webview as it is attached to a new instance of Cline now. So we can safely ignore the result of any active promises, and this class will be deallocated. (Although we set Cline = undefined in provider, that simply removes the reference to this instance, but the instance is still alive until this promise resolves or rejects.) if (this.abort) { @@ -425,7 +423,6 @@ export class Cline { // existing partial message, so update it lastMessage.text = text lastMessage.partial = partial - lastMessage.progressStatus = progressStatus // todo be more efficient about saving and posting only new data or one whole message at a time so ignore partial for saves, and only post parts of partial message instead of whole array in new listener // await this.saveClineMessages() // await this.providerRef.deref()?.postStateToWebview() @@ -463,8 +460,6 @@ export class Cline { // lastMessage.ts = askTs lastMessage.text = text lastMessage.partial = false - lastMessage.progressStatus = progressStatus - await this.saveClineMessages() // await this.providerRef.deref()?.postStateToWebview() await this.providerRef @@ -516,7 +511,6 @@ export class Cline { images?: string[], partial?: boolean, checkpoint?: Record, - progressStatus?: ToolProgressStatus, ): Promise { if (this.abort) { throw new Error(`Task: ${this.taskNumber} Roo Code instance aborted (#2)`) @@ -532,7 +526,6 @@ export class Cline { lastMessage.text = text lastMessage.images = images lastMessage.partial = partial - lastMessage.progressStatus = progressStatus await this.providerRef .deref() ?.postMessageToWebview({ type: "partialMessage", partialMessage: lastMessage }) @@ -552,7 +545,6 @@ export class Cline { lastMessage.text = text lastMessage.images = images lastMessage.partial = false - lastMessage.progressStatus = progressStatus // instead of streaming partialMessage events, we do a save and post like normal to persist to disk await this.saveClineMessages() @@ -1711,16 +1703,8 @@ export class Cline { try { if (block.partial) { // update gui message - let toolProgressStatus - if (this.diffStrategy && this.diffStrategy.getProgressStatus) { - toolProgressStatus = this.diffStrategy.getProgressStatus(block) - } - const partialMessage = JSON.stringify(sharedMessageProps) - - await this.ask("tool", partialMessage, block.partial, toolProgressStatus).catch( - () => {}, - ) + await this.ask("tool", partialMessage, block.partial).catch(() => {}) break } else { if (!relPath) { @@ -1815,14 +1799,6 @@ export class Cline { diff: diffContent, } satisfies ClineSayTool) - let toolProgressStatus - if (this.diffStrategy && this.diffStrategy.getProgressStatus) { - toolProgressStatus = this.diffStrategy.getProgressStatus(block, diffResult) - } - await this.ask("tool", completeMessage, block.partial, toolProgressStatus).catch( - () => {}, - ) - const didApprove = await askApproval("tool", completeMessage) if (!didApprove) { await this.diffViewProvider.revertChanges() // This likely handles closing the diff view diff --git a/src/core/diff/strategies/multi-search-replace.ts b/src/core/diff/strategies/multi-search-replace.ts index 0462629b9b..99c22a31df 100644 --- a/src/core/diff/strategies/multi-search-replace.ts +++ b/src/core/diff/strategies/multi-search-replace.ts @@ -1,8 +1,6 @@ import { DiffStrategy, DiffResult } from "../types" import { addLineNumbers, everyLineHasLineNumbers, stripLineNumbers } from "../../../integrations/misc/extract-text" import { distance } from "fastest-levenshtein" -import { ToolProgressStatus } from "../../../shared/ExtensionMessage" -import { ToolUse } from "../../assistant-message" const BUFFER_LINES = 40 // Number of extra context lines to show before and after matches @@ -364,25 +362,4 @@ Only use a single line of '=======' between search and replacement content, beca failParts: diffResults, } } - - getProgressStatus(toolUse: ToolUse, result?: DiffResult): ToolProgressStatus { - const diffContent = toolUse.params.diff - if (diffContent) { - if (toolUse.partial) { - if (diffContent.length < 1000 || (diffContent.length / 50) % 10 === 0) { - return { text: `progressing ${(diffContent.match(/SEARCH/g) || []).length} blocks...` } - } - } else if (result) { - const searchBlockCount = (diffContent.match(/SEARCH/g) || []).length - if (result.failParts) { - return { - text: `progressed ${searchBlockCount - result.failParts.length}/${searchBlockCount} blocks.`, - } - } else { - return { text: `progressed ${searchBlockCount} blocks.` } - } - } - } - return {} - } } diff --git a/src/core/diff/types.ts b/src/core/diff/types.ts index e12a47762d..be6d8cd311 100644 --- a/src/core/diff/types.ts +++ b/src/core/diff/types.ts @@ -2,9 +2,6 @@ * Interface for implementing different diff strategies */ -import { ToolProgressStatus } from "../../shared/ExtensionMessage" -import { ToolUse } from "../assistant-message" - export type DiffResult = | { success: true; content: string; failParts?: DiffResult[] } | ({ @@ -37,6 +34,4 @@ export interface DiffStrategy { * @returns A DiffResult object containing either the successful result or error details */ applyDiff(originalContent: string, diffContent: string, startLine?: number, endLine?: number): Promise - - getProgressStatus?(toolUse: ToolUse, result?: any): ToolProgressStatus } diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index 0c20669ed1..7487d338b1 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -155,7 +155,6 @@ export interface ClineMessage { reasoning?: string conversationHistoryIndex?: number checkpoint?: Record - progressStatus?: ToolProgressStatus } export type ClineAsk = @@ -275,7 +274,3 @@ export interface HumanRelayCancelMessage { } export type ClineApiReqCancelReason = "streaming_failed" | "user_cancelled" - -export type ToolProgressStatus = { - text?: string -} diff --git a/webview-ui/src/components/chat/ChatRow.tsx b/webview-ui/src/components/chat/ChatRow.tsx index b19d67dc05..259c03fa21 100644 --- a/webview-ui/src/components/chat/ChatRow.tsx +++ b/webview-ui/src/components/chat/ChatRow.tsx @@ -258,7 +258,6 @@ export const ChatRowContent = ({ Roo wants to edit this file:
void isLoading?: boolean - progressStatus?: ToolProgressStatus } /* @@ -34,7 +32,6 @@ const CodeAccordian = ({ isExpanded, onToggleExpand, isLoading, - progressStatus, }: CodeAccordianProps) => { const inferredLanguage = useMemo( () => code && (language ?? (path ? getLanguageFromPath(path) : undefined)), @@ -98,16 +95,6 @@ const CodeAccordian = ({ )}
- {progressStatus && progressStatus.text && ( - - {progressStatus.text} - - )}
)} From c9794d24525ebc1566f75f5e0b4bf6e757dba0d1 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Sun, 9 Mar 2025 18:36:42 -0400 Subject: [PATCH 27/32] Changeset --- .changeset/empty-bees-suffer.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/empty-bees-suffer.md diff --git a/.changeset/empty-bees-suffer.md b/.changeset/empty-bees-suffer.md new file mode 100644 index 0000000000..e3d87a51ad --- /dev/null +++ b/.changeset/empty-bees-suffer.md @@ -0,0 +1,5 @@ +--- +"roo-cline": patch +--- + +Revert tool progress for now From 6bcb39f0a1c1d066363edab18d77d6894f06b2e0 Mon Sep 17 00:00:00 2001 From: Hannes Rudolph <49103247+hannesrudolph@users.noreply.github.com> Date: Sun, 9 Mar 2025 16:45:47 -0600 Subject: [PATCH 28/32] Update webview-ui/src/components/prompts/PromptsView.tsx Co-authored-by: Matt Rubens --- webview-ui/src/components/prompts/PromptsView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webview-ui/src/components/prompts/PromptsView.tsx b/webview-ui/src/components/prompts/PromptsView.tsx index 7303f7691d..9307c0d7a8 100644 --- a/webview-ui/src/components/prompts/PromptsView.tsx +++ b/webview-ui/src/components/prompts/PromptsView.tsx @@ -1037,7 +1037,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { // The React context will update the global state setEnableCustomModeCreation(e.target.checked) }}> - Enable Custom Mode Creation + Enable Custom Mode Creation Through Prompts

Date: Sun, 9 Mar 2025 16:45:53 -0600 Subject: [PATCH 29/32] Update webview-ui/src/components/prompts/PromptsView.tsx Co-authored-by: Matt Rubens --- webview-ui/src/components/prompts/PromptsView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webview-ui/src/components/prompts/PromptsView.tsx b/webview-ui/src/components/prompts/PromptsView.tsx index 9307c0d7a8..6c69bc4229 100644 --- a/webview-ui/src/components/prompts/PromptsView.tsx +++ b/webview-ui/src/components/prompts/PromptsView.tsx @@ -1047,7 +1047,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { }}> When enabled, Roo allows you to create custom modes using prompts like ‘Make me a custom mode that…’. Disabling this reduces your system prompt by about 700 tokens when this feature - isn’t needed. When disabled you can still manually create custom prompts using the + button + isn’t needed. When disabled you can still manually create custom modes using the + button above or by editing the related config JSON.

From 6b0e377afc521e31de52d5f3b366ff0fe5269986 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Sun, 9 Mar 2025 19:42:33 -0400 Subject: [PATCH 30/32] v3.8.4 --- .changeset/sixty-ants-begin.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/sixty-ants-begin.md diff --git a/.changeset/sixty-ants-begin.md b/.changeset/sixty-ants-begin.md new file mode 100644 index 0000000000..5ef9e04868 --- /dev/null +++ b/.changeset/sixty-ants-begin.md @@ -0,0 +1,5 @@ +--- +"roo-cline": patch +--- + +v3.8.4 From 847d8f57f0022a39fad8edb8fca408f785dc0d22 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 9 Mar 2025 23:44:37 +0000 Subject: [PATCH 31/32] changeset version bump --- .changeset/empty-bees-suffer.md | 5 ----- .changeset/sixty-ants-begin.md | 5 ----- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 10 insertions(+), 13 deletions(-) delete mode 100644 .changeset/empty-bees-suffer.md delete mode 100644 .changeset/sixty-ants-begin.md diff --git a/.changeset/empty-bees-suffer.md b/.changeset/empty-bees-suffer.md deleted file mode 100644 index e3d87a51ad..0000000000 --- a/.changeset/empty-bees-suffer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"roo-cline": patch ---- - -Revert tool progress for now diff --git a/.changeset/sixty-ants-begin.md b/.changeset/sixty-ants-begin.md deleted file mode 100644 index 5ef9e04868..0000000000 --- a/.changeset/sixty-ants-begin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"roo-cline": patch ---- - -v3.8.4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 7afcfae2d9..ae74b346d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Roo Code Changelog +## 3.8.4 + +### Patch Changes + +- Revert tool progress for now +- v3.8.4 + ## [3.8.3] - 2025-03-09 - Fix VS Code LM API model picker truncation issue diff --git a/package-lock.json b/package-lock.json index 6884f2e626..cd961b0a21 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "roo-cline", - "version": "3.8.3", + "version": "3.8.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "roo-cline", - "version": "3.8.3", + "version": "3.8.4", "dependencies": { "@anthropic-ai/bedrock-sdk": "^0.10.2", "@anthropic-ai/sdk": "^0.37.0", diff --git a/package.json b/package.json index e4adffd1d7..b32a81071d 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "displayName": "Roo Code (prev. Roo Cline)", "description": "A whole dev team of AI agents in your editor.", "publisher": "RooVeterinaryInc", - "version": "3.8.3", + "version": "3.8.4", "icon": "assets/icons/rocket.png", "galleryBanner": { "color": "#617A91", From 831371cfa9d4354fe2d6f69c113bf3af78761d93 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Sun, 9 Mar 2025 19:47:22 -0400 Subject: [PATCH 32/32] Update CHANGELOG.md --- CHANGELOG.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae74b346d0..fd6a574dc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,9 @@ # Roo Code Changelog -## 3.8.4 +## [3.8.4] - 2025-03-09 -### Patch Changes - -- Revert tool progress for now -- v3.8.4 +- Roll back multi-diff progress indicator temporarily to fix a double-confirmation in saving edits +- Add an option in the prompts tab to save tokens by disabling the ability to ask Roo to create/edit custom modes for you (thanks @hannesrudolph!) ## [3.8.3] - 2025-03-09