mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-10-06 02:47:56 +00:00
fix: prevent task abortion when resuming via IPC/bridge (#10892)
This commit is contained in:
parent
94459adba1
commit
13e090ef81
3 changed files with 34 additions and 28 deletions
|
|
@ -1546,7 +1546,10 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
|
||||
this.emit(RooCodeEventName.TaskUserMessage, this.taskId)
|
||||
|
||||
provider.postMessageToWebview({ type: "invoke", invoke: "sendMessage", text, images })
|
||||
// Handle the message directly instead of routing through the webview.
|
||||
// This avoids a race condition where the webview's message state hasn't
|
||||
// hydrated yet, causing it to interpret the message as a new task request.
|
||||
this.handleWebviewAskResponse("messageResponse", text, images)
|
||||
} else {
|
||||
console.error("[Task#submitUserMessage] Provider reference lost")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1523,7 +1523,7 @@ describe("Cline", () => {
|
|||
})
|
||||
|
||||
describe("submitUserMessage", () => {
|
||||
it("should always route through webview sendMessage invoke", async () => {
|
||||
it("should call handleWebviewAskResponse directly", async () => {
|
||||
const task = new Task({
|
||||
provider: mockProvider,
|
||||
apiConfiguration: mockApiConfig,
|
||||
|
|
@ -1531,6 +1531,9 @@ describe("Cline", () => {
|
|||
startTask: false,
|
||||
})
|
||||
|
||||
// Spy on handleWebviewAskResponse
|
||||
const handleResponseSpy = vi.spyOn(task, "handleWebviewAskResponse")
|
||||
|
||||
// Set up some existing messages to simulate an ongoing conversation
|
||||
task.clineMessages = [
|
||||
{
|
||||
|
|
@ -1544,13 +1547,10 @@ describe("Cline", () => {
|
|||
// Call submitUserMessage
|
||||
task.submitUserMessage("test message", ["image1.png"])
|
||||
|
||||
// Verify postMessageToWebview was called with sendMessage invoke
|
||||
expect(mockProvider.postMessageToWebview).toHaveBeenCalledWith({
|
||||
type: "invoke",
|
||||
invoke: "sendMessage",
|
||||
text: "test message",
|
||||
images: ["image1.png"],
|
||||
})
|
||||
// Verify handleWebviewAskResponse was called directly (not webview)
|
||||
expect(handleResponseSpy).toHaveBeenCalledWith("messageResponse", "test message", ["image1.png"])
|
||||
// Should NOT route through webview anymore
|
||||
expect(mockProvider.postMessageToWebview).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("should handle empty messages gracefully", async () => {
|
||||
|
|
@ -1561,18 +1561,21 @@ describe("Cline", () => {
|
|||
startTask: false,
|
||||
})
|
||||
|
||||
// Spy on handleWebviewAskResponse
|
||||
const handleResponseSpy = vi.spyOn(task, "handleWebviewAskResponse")
|
||||
|
||||
// Call with empty text and no images
|
||||
task.submitUserMessage("", [])
|
||||
|
||||
// Should not call postMessageToWebview for empty messages
|
||||
expect(mockProvider.postMessageToWebview).not.toHaveBeenCalled()
|
||||
// Should not call handleWebviewAskResponse for empty messages
|
||||
expect(handleResponseSpy).not.toHaveBeenCalled()
|
||||
|
||||
// Call with whitespace only
|
||||
task.submitUserMessage(" ", [])
|
||||
expect(mockProvider.postMessageToWebview).not.toHaveBeenCalled()
|
||||
expect(handleResponseSpy).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("should route through webview for both new and existing tasks", async () => {
|
||||
it("should call handleWebviewAskResponse for both new and existing task states", async () => {
|
||||
const task = new Task({
|
||||
provider: mockProvider,
|
||||
apiConfiguration: mockApiConfig,
|
||||
|
|
@ -1580,19 +1583,17 @@ describe("Cline", () => {
|
|||
startTask: false,
|
||||
})
|
||||
|
||||
// Spy on handleWebviewAskResponse
|
||||
const handleResponseSpy = vi.spyOn(task, "handleWebviewAskResponse")
|
||||
|
||||
// Test with no messages (new task scenario)
|
||||
task.clineMessages = []
|
||||
task.submitUserMessage("new task", ["image1.png"])
|
||||
|
||||
expect(mockProvider.postMessageToWebview).toHaveBeenCalledWith({
|
||||
type: "invoke",
|
||||
invoke: "sendMessage",
|
||||
text: "new task",
|
||||
images: ["image1.png"],
|
||||
})
|
||||
expect(handleResponseSpy).toHaveBeenCalledWith("messageResponse", "new task", ["image1.png"])
|
||||
|
||||
// Clear mock
|
||||
mockProvider.postMessageToWebview.mockClear()
|
||||
handleResponseSpy.mockClear()
|
||||
|
||||
// Test with existing messages (ongoing task scenario)
|
||||
task.clineMessages = [
|
||||
|
|
@ -1605,12 +1606,7 @@ describe("Cline", () => {
|
|||
]
|
||||
task.submitUserMessage("follow-up message", ["image2.png"])
|
||||
|
||||
expect(mockProvider.postMessageToWebview).toHaveBeenCalledWith({
|
||||
type: "invoke",
|
||||
invoke: "sendMessage",
|
||||
text: "follow-up message",
|
||||
images: ["image2.png"],
|
||||
})
|
||||
expect(handleResponseSpy).toHaveBeenCalledWith("messageResponse", "follow-up message", ["image2.png"])
|
||||
})
|
||||
|
||||
it("should handle undefined provider gracefully", async () => {
|
||||
|
|
@ -1621,6 +1617,9 @@ describe("Cline", () => {
|
|||
startTask: false,
|
||||
})
|
||||
|
||||
// Spy on handleWebviewAskResponse
|
||||
const handleResponseSpy = vi.spyOn(task, "handleWebviewAskResponse")
|
||||
|
||||
// Simulate weakref returning undefined
|
||||
Object.defineProperty(task, "providerRef", {
|
||||
value: { deref: () => undefined },
|
||||
|
|
@ -1635,7 +1634,7 @@ describe("Cline", () => {
|
|||
task.submitUserMessage("test message")
|
||||
|
||||
expect(consoleErrorSpy).toHaveBeenCalledWith("[Task#submitUserMessage] Provider reference lost")
|
||||
expect(mockProvider.postMessageToWebview).not.toHaveBeenCalled()
|
||||
expect(handleResponseSpy).not.toHaveBeenCalled()
|
||||
|
||||
// Restore console.error
|
||||
consoleErrorSpy.mockRestore()
|
||||
|
|
|
|||
|
|
@ -862,7 +862,11 @@ export class ClineProvider
|
|||
this.webviewDisposables.push(configDisposable)
|
||||
|
||||
// If the extension is starting a new session, clear previous task state.
|
||||
await this.removeClineFromStack()
|
||||
// But don't clear if there's already an active task (e.g., resumed via IPC/bridge).
|
||||
const currentTask = this.getCurrentTask()
|
||||
if (!currentTask || currentTask.abandoned || currentTask.abort) {
|
||||
await this.removeClineFromStack()
|
||||
}
|
||||
}
|
||||
|
||||
public async createTaskWithHistoryItem(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue