Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
c3c3874
subtasks alpha version (still in development)
Feb 22, 2025
87f6ac4
pass last message of a subtask to parent task
Feb 23, 2025
20f9073
Change response to be a user message
mrubens Feb 23, 2025
655930c
added getClineStackSize() to ClineProvider and fixed its tests
Feb 23, 2025
0176599
added task no indicator + improved deleteTask code
Feb 24, 2025
dcde2e0
Merge branch 'main' of https://github.com/RooVetGit/Roo-Code into sbc…
Feb 25, 2025
8dc8ec3
Fix dependencies and update TaskHeader
Feb 25, 2025
4744f7f
fixed ClineProvider.test.ts to include cline.getTaskNumber and cline.…
Feb 25, 2025
1ff403d
fixed 2 more places in ClineProvider.test that needed cline mocks (se…
Feb 25, 2025
36cfa31
try to fix test
Feb 26, 2025
4095c16
Merge branch 'main' of https://github.com/RooVetGit/Roo-Code into sbc…
Feb 26, 2025
a8d1fbb
Merge pull request #1 from RooVetGit/main
shaybc Feb 26, 2025
bf710fb
Merge branch 'main' into sbc_add_subtasks
Feb 26, 2025
73c7fe7
refactored ClineProvider.test
Feb 26, 2025
f835b8c
Merge remote-tracking branch 'upstream/main' into sbc_add_subtasks
Feb 26, 2025
c8b78dc
add support ro save paused tasks mode and change back to it once the …
Feb 27, 2025
03e0aa5
Resolved merge conflicts in Cline.ts and ClineProvider.ts
Feb 28, 2025
5651b35
added logs, error handling, and added console.log to the provider log…
Feb 28, 2025
b1dae21
removed cline instance type check to allow mocks
Feb 28, 2025
2c81366
added connection between task to its parent and root parent + adjuste…
Feb 28, 2025
c04adc6
added error message back to the parent task in cases user stops, canc…
Feb 28, 2025
41ddb7d
Resolved merge conflicts
Feb 28, 2025
997f7bb
Improve error handling and messaging in Cline class and ClineProvider…
Mar 1, 2025
c8ec2b6
Merge remote-tracking branch 'upstream/main' into sbc_add_subtasks
Mar 1, 2025
4418519
added 500ms delay after modeSwitch to avoid a bug of running subtask …
Mar 1, 2025
b7be8ba
Merge remote-tracking branch 'upstream/main' into sbc_add_subtasks
Mar 1, 2025
5bc1e50
Resolved merge conflicts
Mar 5, 2025
30d630f
Resolved merge conflicts
Mar 5, 2025
9658363
Resolved merge conflicts
Mar 5, 2025
279df6e
Merge remote-tracking branch 'origin/main' into sbc_add_subtasks
mrubens Mar 5, 2025
d4f0f53
Merge remote-tracking branch 'origin/main' into sbc_add_subtasks
mrubens Mar 5, 2025
8d2ba12
Update src/core/Cline.ts
mrubens Mar 5, 2025
426e03b
Update src/core/Cline.ts
mrubens Mar 5, 2025
a9d971e
Update src/core/webview/ClineProvider.ts
mrubens Mar 5, 2025
b46da7b
Revert README changes
mrubens Mar 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/activate/registerCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const registerCommands = (options: RegisterCommandOptions) => {
const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOptions) => {
return {
"roo-cline.plusButtonClicked": async () => {
await provider.clearTask()
await provider.removeClineFromStack()
await provider.postStateToWebview()
await provider.postMessageToWebview({ type: "action", action: "chatButtonClicked" })
},
Expand Down
75 changes: 74 additions & 1 deletion src/core/Cline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ type UserContent = Array<

export class Cline {
readonly taskId: string
// a flag that indicated if this Cline instance is a subtask (on finish return control to parent task)
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
api: ApiHandler
private terminalManager: TerminalManager
private urlContentFetcher: UrlContentFetcher
Expand Down Expand Up @@ -160,6 +164,12 @@ export class Cline {
}
}

// a helper function to set the private member isSubTask to true
// and by that set this Cline instance to be a subtask (on finish return control to parent task)
setSubTask() {
this.isSubTask = true
}

// Add method to update diffStrategy
async updateDiffStrategy(experimentalDiffStrategy?: boolean) {
// If not provided, get from current state
Expand Down Expand Up @@ -480,6 +490,39 @@ export class Cline {
])
}

async resumePausedTask(lastMessage?: string) {
// release this Cline instance from paused state
this.isPaused = false

// This adds the completion message to conversation history
await this.say("text", `new_task finished successfully! ${lastMessage ?? "Please continue to the next task."}`)

await this.addToApiConversationHistory({
role: "user",
content: [
{
type: "text",
text: `[new_task completed] Result: ${lastMessage ?? "Please continue to the next task."}`,
},
],
})

try {
// Resume parent task
await this.ask("resume_task")
} catch (error) {
if (error.message === "Current ask promise was ignored") {
// ignore the ignored promise, since it was performed by launching a subtask and it probably took more then 1 sec,
// also set the didAlreadyUseTool flag to indicate that the tool was already used, and there is no need to relaunch it
this.didAlreadyUseTool = true
} else {
// Handle error appropriately
console.error("Failed to resume task:", error)
throw error
}
}
}

private async resumeTaskFromHistory() {
const modifiedClineMessages = await this.getSavedClineMessages()

Expand Down Expand Up @@ -2553,10 +2596,12 @@ export class Cline {
const provider = this.providerRef.deref()
if (provider) {
await provider.handleModeSwitch(mode)
await provider.initClineWithTask(message)
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
this.isPaused = true
} else {
pushToolResult(
formatResponse.toolError("Failed to create new task: provider not available"),
Expand Down Expand Up @@ -2648,6 +2693,10 @@ 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)
if (this.isSubTask) {
// tell the provider to remove the current subtask and resume the previous task in the stack
this.providerRef.deref()?.finishSubTask(lastMessage?.text)
}
}

// complete command message
Expand All @@ -2665,6 +2714,10 @@ export class Cline {
commandResult = execCommandResult
} else {
await this.say("completion_result", result, undefined, false)
if (this.isSubTask) {
// tell the provider to remove the current subtask and resume the previous task in the stack
this.providerRef.deref()?.finishSubTask(lastMessage?.text)
}
}

// we already sent completion_result says, an empty string asks relinquishes control over button and field
Expand Down Expand Up @@ -2740,6 +2793,20 @@ export class Cline {
}
}

// this function checks if this Cline instance is set to pause state and wait for being resumed,
// this is used when a sub-task is launched and the parent task is waiting for it to finish
async waitForResume() {
// wait until isPaused is false
await new Promise<void>((resolve) => {
const interval = setInterval(() => {
if (!this.isPaused) {
clearInterval(interval)
resolve()
}
}, 1000) // TBD: the 1 sec should be added to the settings, also should add a timeout to prevent infinit wait
})
}

async recursivelyMakeClineRequests(
userContent: UserContent,
includeFileDetails: boolean = false,
Expand Down Expand Up @@ -2779,6 +2846,12 @@ export class Cline {
await this.checkpointSave({ isFirst: true })
}

// 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) {
await this.waitForResume()
}

// 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
// for the best UX we show a placeholder api_req_started message with a loading spinner as this happens
await this.say(
Expand Down
Loading