Skip to content

Commit 3293d78

Browse files
committed
feat: implement task resumption from web UI
- Add optional taskId field to StartNewTask IPC command - Update API handler to resume tasks when taskId is provided - Add handleStartTask method to ClineProvider for web UI integration - Ensure bridge service properly connects to resumed tasks - Fix message routing to correct task after resumption
1 parent 0d0bba2 commit 3293d78

File tree

3 files changed

+79
-0
lines changed

3 files changed

+79
-0
lines changed

packages/types/src/ipc.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export const taskCommandSchema = z.discriminatedUnion("commandName", [
5858
text: z.string(),
5959
images: z.array(z.string()).optional(),
6060
newTab: z.boolean().optional(),
61+
taskId: z.string().optional(), // Optional taskId for resuming existing tasks
6162
}),
6263
}),
6364
z.object({

src/core/webview/ClineProvider.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,71 @@ export class ClineProvider
744744
return task
745745
}
746746

747+
/**
748+
* Handles starting a task with optional resumption support.
749+
* This method is called by the ExtensionBridgeService when receiving StartTask commands from the web UI.
750+
*
751+
* @param payload - The task payload containing text, images, and optional taskId for resumption
752+
*/
753+
public async handleStartTask(payload: { text: string; images?: string[]; taskId?: string }): Promise<void> {
754+
if (payload.taskId) {
755+
// Attempt to resume existing task
756+
try {
757+
const { historyItem } = await this.getTaskWithId(payload.taskId)
758+
if (historyItem) {
759+
this.log(`Resuming task ${payload.taskId} from web UI`)
760+
761+
// Clear any current tasks and restore the specific task
762+
await this.initClineWithHistoryItem(historyItem)
763+
764+
// Ensure the webview shows the chat interface
765+
await this.postMessageToWebview({ type: "action", action: "chatButtonClicked" })
766+
767+
// Update state to reflect the new current task
768+
await this.postStateToWebview()
769+
770+
// Ensure bridge service is connected to the resumed task
771+
const resumedTask = this.getCurrentCline()
772+
if (resumedTask) {
773+
try {
774+
const { ExtensionBridgeService } = await import("@roo-code/cloud")
775+
const bridgeService = ExtensionBridgeService.getInstance()
776+
if (bridgeService && !resumedTask.bridgeService) {
777+
resumedTask.bridgeService = bridgeService
778+
await bridgeService.subscribeToTask(resumedTask)
779+
this.log(`Bridge service connected to resumed task ${payload.taskId}`)
780+
}
781+
} catch (error) {
782+
this.log(`Failed to connect bridge service to resumed task: ${error}`)
783+
}
784+
}
785+
786+
// The user's new message (payload.text) will be sent through the normal message flow
787+
// after the task is restored and ready
788+
if (payload.text) {
789+
// Give a small delay to ensure the task is fully restored
790+
setTimeout(async () => {
791+
await this.postMessageToWebview({
792+
type: "invoke",
793+
invoke: "sendMessage",
794+
text: payload.text,
795+
images: payload.images,
796+
})
797+
}, 200)
798+
}
799+
800+
this.log(`Task ${payload.taskId} successfully resumed and is now active`)
801+
return
802+
}
803+
} catch (error) {
804+
this.log(`Failed to resume task ${payload.taskId}: ${error}. Creating new task instead.`)
805+
}
806+
}
807+
808+
// Create new task (normal flow)
809+
await this.initClineWithTask(payload.text, payload.images)
810+
}
811+
747812
public async initClineWithHistoryItem(historyItem: HistoryItem & { rootTask?: Task; parentTask?: Task }) {
748813
await this.removeClineFromStack()
749814

src/extension/api.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,25 @@ export class API extends EventEmitter<RooCodeEvents> implements RooCodeAPI {
9797
text,
9898
images,
9999
newTab,
100+
taskId,
100101
}: {
101102
configuration: RooCodeSettings
102103
text?: string
103104
images?: string[]
104105
newTab?: boolean
106+
taskId?: string
105107
}) {
108+
// If taskId is provided, attempt to resume the task
109+
if (taskId) {
110+
const isInHistory = await this.isTaskInHistory(taskId)
111+
if (isInHistory) {
112+
await this.resumeTask(taskId)
113+
return taskId
114+
}
115+
// If task is not found in history, continue with creating a new task
116+
this.log(`[API] Task ${taskId} not found in history, creating new task`)
117+
}
118+
106119
let provider: ClineProvider
107120

108121
if (newTab) {

0 commit comments

Comments
 (0)