mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-06 08:18:39 +00:00
add support ro save paused tasks mode and change back to it once the task is resumed, also added subtasks logging
This commit is contained in:
parent
f835b8c3e2
commit
c8b78dc7bf
3 changed files with 41 additions and 12 deletions
|
|
@ -92,6 +92,7 @@ export class Cline {
|
|||
private isSubTask: boolean = false
|
||||
// a flag that indicated if this Cline instance is paused (waiting for provider to resume it after subtask completion)
|
||||
private isPaused: boolean = false
|
||||
private pausedModeSlug: string = defaultModeSlug
|
||||
api: ApiHandler
|
||||
private terminalManager: TerminalManager
|
||||
private urlContentFetcher: UrlContentFetcher
|
||||
|
|
@ -2642,15 +2643,24 @@ export class Cline {
|
|||
break
|
||||
}
|
||||
|
||||
// before switching roo mode (currently a global settings), save the current mode so we can
|
||||
// resume the parent task (this Cline instance) later with the same mode
|
||||
const currentMode =
|
||||
(await this.providerRef.deref()?.getState())?.mode ?? defaultModeSlug
|
||||
this.pausedModeSlug = currentMode
|
||||
|
||||
// Switch mode first, then create new task instance
|
||||
const provider = this.providerRef.deref()
|
||||
if (provider) {
|
||||
await provider.handleModeSwitch(mode)
|
||||
this.providerRef
|
||||
.deref()
|
||||
?.log(`[subtasks] Task: ${this.taskNumber} creating new task in '${mode}' mode`)
|
||||
await provider.initClineWithSubTask(message)
|
||||
pushToolResult(
|
||||
`Successfully created new task in ${targetMode.name} mode with message: ${message}`,
|
||||
)
|
||||
// pasue the current task and start the new task
|
||||
// set the isPaused flag to true so the parent task can wait for the sub-task to finish
|
||||
this.isPaused = true
|
||||
} else {
|
||||
pushToolResult(
|
||||
|
|
@ -2899,7 +2909,20 @@ export class Cline {
|
|||
// in this Cline request loop, we need to check if this cline (Task) instance has been asked to wait
|
||||
// for a sub-task (it has launched) to finish before continuing
|
||||
if (this.isPaused) {
|
||||
this.providerRef.deref()?.log(`[subtasks] Task: ${this.taskNumber} has paused`)
|
||||
await this.waitForResume()
|
||||
this.providerRef.deref()?.log(`[subtasks] Task: ${this.taskNumber} has resumed`)
|
||||
// waiting for resume is done, resume the task mode
|
||||
const currentMode = (await this.providerRef.deref()?.getState())?.mode ?? defaultModeSlug
|
||||
if (currentMode !== this.pausedModeSlug) {
|
||||
// the mode has changed, we need to switch back to the paused mode
|
||||
await this.providerRef.deref()?.handleModeSwitch(this.pausedModeSlug)
|
||||
this.providerRef
|
||||
.deref()
|
||||
?.log(
|
||||
`[subtasks] Task: ${this.taskNumber} has switched back to mode: '${this.pausedModeSlug}' from mode: '${currentMode}'`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// getting verbose details is an expensive operation, it uses globby to top-down build file structure of project which for large projects can take a few seconds
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||
// Adds a new Cline instance to clineStack, marking the start of a new task.
|
||||
// The instance is pushed to the top of the stack (LIFO order).
|
||||
// When the task is completed, the top instance is removed, reactivating the previous task.
|
||||
addClineToStack(cline: Cline): void {
|
||||
async addClineToStack(cline: Cline) {
|
||||
// if cline.getTaskNumber() is -1, it means it is a new task
|
||||
if (cline.getTaskNumber() === -1) {
|
||||
// increase last cline number by 1
|
||||
|
|
@ -107,6 +107,10 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||
}
|
||||
// push the cline instance to the stack
|
||||
this.clineStack.push(cline)
|
||||
// get the current mode
|
||||
const currentMode = (await this.getState()).mode
|
||||
// log the task number and the mode
|
||||
this.log(`[subtasks] Task: ${cline.getTaskNumber()} started at '${currentMode}' mode`)
|
||||
}
|
||||
|
||||
// Removes and destroys the top Cline instance (the current finished task), activating the previous one (resuming the parent task).
|
||||
|
|
@ -114,9 +118,11 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||
// pop the top Cline instance from the stack
|
||||
var clineToBeRemoved = this.clineStack.pop()
|
||||
if (clineToBeRemoved) {
|
||||
const removedTaskNumber = clineToBeRemoved.getTaskNumber()
|
||||
await clineToBeRemoved.abortTask()
|
||||
// make sure no reference kept, once promises end it will be garbage collected
|
||||
clineToBeRemoved = undefined
|
||||
this.log(`[subtasks] Task: ${removedTaskNumber} stopped`)
|
||||
}
|
||||
// if the stack is empty, reset the last task number
|
||||
if (this.clineStack.length === 0) {
|
||||
|
|
@ -417,7 +423,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||
images,
|
||||
experiments,
|
||||
})
|
||||
this.addClineToStack(newCline)
|
||||
await this.addClineToStack(newCline)
|
||||
}
|
||||
|
||||
public async initClineWithHistoryItem(historyItem: HistoryItem) {
|
||||
|
|
@ -449,7 +455,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||
})
|
||||
// get this cline task number id from the history item and set it to newCline
|
||||
newCline.setTaskNumber(historyItem.number)
|
||||
this.addClineToStack(newCline)
|
||||
await this.addClineToStack(newCline)
|
||||
}
|
||||
|
||||
public async postMessageToWebview(message: ExtensionMessage) {
|
||||
|
|
|
|||
|
|
@ -415,7 +415,7 @@ describe("ClineProvider", () => {
|
|||
const mockCline = new Cline() // Create a new mocked instance
|
||||
|
||||
// add the mock object to the stack
|
||||
provider.addClineToStack(mockCline)
|
||||
await provider.addClineToStack(mockCline)
|
||||
|
||||
// get the stack size before the abort call
|
||||
const stackSizeBeforeAbort = provider.getClineStackSize()
|
||||
|
|
@ -433,7 +433,7 @@ describe("ClineProvider", () => {
|
|||
expect(stackSizeBeforeAbort - stackSizeAfterAbort).toBe(1)
|
||||
})
|
||||
|
||||
test("addClineToStack adds multiple Cline instances to the stack", () => {
|
||||
test("addClineToStack adds multiple Cline instances to the stack", async () => {
|
||||
// Setup Cline instance with auto-mock from the top of the file
|
||||
const { Cline } = require("../../Cline") // Get the mocked class
|
||||
const mockCline1 = new Cline() // Create a new mocked instance
|
||||
|
|
@ -442,8 +442,8 @@ describe("ClineProvider", () => {
|
|||
Object.defineProperty(mockCline2, "taskId", { value: "test-task-id-2", writable: true })
|
||||
|
||||
// add Cline instances to the stack
|
||||
provider.addClineToStack(mockCline1)
|
||||
provider.addClineToStack(mockCline2)
|
||||
await provider.addClineToStack(mockCline1)
|
||||
await provider.addClineToStack(mockCline2)
|
||||
|
||||
// verify cline instances were added to the stack
|
||||
expect(provider.getClineStackSize()).toBe(2)
|
||||
|
|
@ -847,7 +847,7 @@ describe("ClineProvider", () => {
|
|||
const mockCline = new Cline() // Create a new mocked instance
|
||||
mockCline.clineMessages = mockMessages // Set test-specific messages
|
||||
mockCline.apiConversationHistory = mockApiHistory // Set API history
|
||||
provider.addClineToStack(mockCline) // Add the mocked instance to the stack
|
||||
await provider.addClineToStack(mockCline) // Add the mocked instance to the stack
|
||||
|
||||
// Mock getTaskWithId
|
||||
;(provider as any).getTaskWithId = jest.fn().mockResolvedValue({
|
||||
|
|
@ -894,7 +894,7 @@ describe("ClineProvider", () => {
|
|||
const mockCline = new Cline() // Create a new mocked instance
|
||||
mockCline.clineMessages = mockMessages
|
||||
mockCline.apiConversationHistory = mockApiHistory
|
||||
provider.addClineToStack(mockCline)
|
||||
await provider.addClineToStack(mockCline)
|
||||
|
||||
// Mock getTaskWithId
|
||||
;(provider as any).getTaskWithId = jest.fn().mockResolvedValue({
|
||||
|
|
@ -921,7 +921,7 @@ describe("ClineProvider", () => {
|
|||
const mockCline = new Cline() // Create a new mocked instance
|
||||
mockCline.clineMessages = [{ ts: 1000 }, { ts: 2000 }]
|
||||
mockCline.apiConversationHistory = [{ ts: 1000 }, { ts: 2000 }]
|
||||
provider.addClineToStack(mockCline)
|
||||
await provider.addClineToStack(mockCline)
|
||||
|
||||
// Trigger message deletion
|
||||
const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as jest.Mock).mock.calls[0][0]
|
||||
|
|
@ -1424,7 +1424,7 @@ describe("ClineProvider", () => {
|
|||
// Setup Cline instance with auto-mock from the top of the file
|
||||
const { Cline } = require("../../Cline") // Get the mocked class
|
||||
const mockCline = new Cline() // Create a new mocked instance
|
||||
provider.addClineToStack(mockCline)
|
||||
await provider.addClineToStack(mockCline)
|
||||
|
||||
const testApiConfig = {
|
||||
apiProvider: "anthropic" as const,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue