Skip to content
This repository was archived by the owner on May 15, 2026. It is now read-only.

Commit 8575297

Browse files
daniel-lxshannesrudolph
authored andcommitted
fix: make delegation reopen flow Roo v2-native (#11418)
1 parent cd96fa6 commit 8575297

4 files changed

Lines changed: 207 additions & 153 deletions

File tree

src/__tests__/history-resume-delegation.spec.ts

Lines changed: 33 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,10 @@ vi.mock("../core/task-persistence", async (importOriginal) => {
3838
saveTaskMessages: vi.fn().mockResolvedValue(undefined),
3939
}
4040
})
41-
vi.mock("../core/task-persistence/delegationMeta", () => ({
42-
readDelegationMeta: vi.fn().mockResolvedValue(null),
43-
saveDelegationMeta: vi.fn().mockResolvedValue(undefined),
44-
}))
4541

4642
import { ClineProvider } from "../core/webview/ClineProvider"
4743
import { readTaskMessages } from "../core/task-persistence/taskMessages"
48-
import { readApiMessages, saveApiMessages, saveTaskMessages } from "../core/task-persistence"
44+
import { readRooMessages, saveRooMessages, saveTaskMessages } from "../core/task-persistence"
4945

5046
describe("History resume delegation - parent metadata transitions", () => {
5147
beforeEach(() => {
@@ -91,7 +87,7 @@ describe("History resume delegation - parent metadata transitions", () => {
9187

9288
// Mock persistence reads to return empty arrays
9389
vi.mocked(readTaskMessages).mockResolvedValue([])
94-
vi.mocked(readApiMessages).mockResolvedValue([])
90+
vi.mocked(readRooMessages).mockResolvedValue([])
9591

9692
await (ClineProvider.prototype as any).reopenParentFromDelegation.call(provider, {
9793
parentTaskId: "parent-1",
@@ -161,7 +157,7 @@ describe("History resume delegation - parent metadata transitions", () => {
161157
const existingApiMessages = [{ role: "user", content: [{ type: "text", text: "Old request" }], ts: 50 }]
162158

163159
vi.mocked(readTaskMessages).mockResolvedValue(existingUiMessages as any)
164-
vi.mocked(readApiMessages).mockResolvedValue(existingApiMessages as any)
160+
vi.mocked(readRooMessages).mockResolvedValue(existingApiMessages as any)
165161

166162
await (ClineProvider.prototype as any).reopenParentFromDelegation.call(provider, {
167163
parentTaskId: "p1",
@@ -185,7 +181,7 @@ describe("History resume delegation - parent metadata transitions", () => {
185181
)
186182

187183
// Verify API history injection (user role message)
188-
expect(saveApiMessages).toHaveBeenCalledWith(
184+
expect(saveRooMessages).toHaveBeenCalledWith(
189185
expect.objectContaining({
190186
messages: expect.arrayContaining([
191187
expect.objectContaining({
@@ -207,11 +203,11 @@ describe("History resume delegation - parent metadata transitions", () => {
207203
const uiCall = vi.mocked(saveTaskMessages).mock.calls[0][0]
208204
expect(uiCall.messages).toHaveLength(2) // 1 original + 1 injected
209205

210-
const apiCall = vi.mocked(saveApiMessages).mock.calls[0][0]
206+
const apiCall = vi.mocked(saveRooMessages).mock.calls[0][0]
211207
expect(apiCall.messages).toHaveLength(2) // 1 original + 1 injected
212208
})
213209

214-
it("reopenParentFromDelegation injects tool_result when new_task tool_use exists in API history", async () => {
210+
it("reopenParentFromDelegation injects tool-result message when new_task tool_use exists in API history", async () => {
215211
const provider = {
216212
contextProxy: { globalStorageUri: { fsPath: "/storage" } },
217213
getTaskWithId: vi.fn().mockResolvedValue({
@@ -259,25 +255,27 @@ describe("History resume delegation - parent metadata transitions", () => {
259255
]
260256

261257
vi.mocked(readTaskMessages).mockResolvedValue(existingUiMessages as any)
262-
vi.mocked(readApiMessages).mockResolvedValue(existingApiMessages as any)
258+
vi.mocked(readRooMessages).mockResolvedValue(existingApiMessages as any)
263259

264260
await (ClineProvider.prototype as any).reopenParentFromDelegation.call(provider, {
265261
parentTaskId: "p-tool",
266262
childTaskId: "c-tool",
267263
completionResultSummary: "Subtask completed via tool_result",
268264
})
269265

270-
// Verify API history injection uses tool_result (not text fallback)
271-
expect(saveApiMessages).toHaveBeenCalledWith(
266+
// Verify API history injection uses tool-result (not text fallback)
267+
expect(saveRooMessages).toHaveBeenCalledWith(
272268
expect.objectContaining({
273269
messages: expect.arrayContaining([
274270
expect.objectContaining({
275-
role: "user",
271+
role: "tool",
276272
content: expect.arrayContaining([
277273
expect.objectContaining({
278-
type: "tool_result",
279-
tool_use_id: "toolu_abc123",
280-
content: expect.stringContaining("Subtask c-tool completed"),
274+
type: "tool-result",
275+
toolCallId: "toolu_abc123",
276+
output: expect.objectContaining({
277+
value: expect.stringContaining("Subtask c-tool completed"),
278+
}),
281279
}),
282280
]),
283281
}),
@@ -287,15 +285,15 @@ describe("History resume delegation - parent metadata transitions", () => {
287285
}),
288286
)
289287

290-
// Verify total message count: 2 original + 1 injected user message with tool_result
291-
const apiCall = vi.mocked(saveApiMessages).mock.calls[0][0]
288+
// Verify total message count: 2 original + 1 injected tool message with tool-result
289+
const apiCall = vi.mocked(saveRooMessages).mock.calls[0][0]
292290
expect(apiCall.messages).toHaveLength(3)
293291

294-
// Verify the injected message is a user message with tool_result type
295-
const injectedMsg = apiCall.messages[2]
296-
expect(injectedMsg.role).toBe("user")
297-
expect((injectedMsg.content[0] as any).type).toBe("tool_result")
298-
expect((injectedMsg.content[0] as any).tool_use_id).toBe("toolu_abc123")
292+
// Verify the injected message is a tool message with tool-result type
293+
const injectedMsg = apiCall.messages[2] as any
294+
expect(injectedMsg.role).toBe("tool")
295+
expect((injectedMsg.content[0] as any).type).toBe("tool-result")
296+
expect((injectedMsg.content[0] as any).toolCallId).toBe("toolu_abc123")
299297
})
300298

301299
it("reopenParentFromDelegation injects plain text when no new_task tool_use exists in API history", async () => {
@@ -332,18 +330,18 @@ describe("History resume delegation - parent metadata transitions", () => {
332330
const existingApiMessages = [{ role: "user", content: [{ type: "text", text: "Create a subtask" }], ts: 40 }]
333331

334332
vi.mocked(readTaskMessages).mockResolvedValue(existingUiMessages as any)
335-
vi.mocked(readApiMessages).mockResolvedValue(existingApiMessages as any)
333+
vi.mocked(readRooMessages).mockResolvedValue(existingApiMessages as any)
336334

337335
await (ClineProvider.prototype as any).reopenParentFromDelegation.call(provider, {
338336
parentTaskId: "p-no-tool",
339337
childTaskId: "c-no-tool",
340338
completionResultSummary: "Subtask completed without tool_use",
341339
})
342340

343-
const apiCall = vi.mocked(saveApiMessages).mock.calls[0][0]
341+
const apiCall = vi.mocked(saveRooMessages).mock.calls[0][0]
344342
// Should append a user text note
345343
expect(apiCall.messages).toHaveLength(2)
346-
const injected = apiCall.messages[1]
344+
const injected = apiCall.messages[1] as any
347345
expect(injected.role).toBe("user")
348346
expect((injected.content[0] as any).type).toBe("text")
349347
expect((injected.content[0] as any).text).toContain("Subtask c-no-tool completed")
@@ -383,7 +381,7 @@ describe("History resume delegation - parent metadata transitions", () => {
383381
} as unknown as ClineProvider
384382

385383
vi.mocked(readTaskMessages).mockResolvedValue([])
386-
vi.mocked(readApiMessages).mockResolvedValue([])
384+
vi.mocked(readRooMessages).mockResolvedValue([])
387385

388386
await (ClineProvider.prototype as any).reopenParentFromDelegation.call(provider, {
389387
parentTaskId: "parent-2",
@@ -427,7 +425,7 @@ describe("History resume delegation - parent metadata transitions", () => {
427425
} as unknown as ClineProvider
428426

429427
vi.mocked(readTaskMessages).mockResolvedValue([])
430-
vi.mocked(readApiMessages).mockResolvedValue([])
428+
vi.mocked(readRooMessages).mockResolvedValue([])
431429

432430
await (ClineProvider.prototype as any).reopenParentFromDelegation.call(provider, {
433431
parentTaskId: "p3",
@@ -505,7 +503,7 @@ describe("History resume delegation - parent metadata transitions", () => {
505503
} as unknown as ClineProvider
506504

507505
vi.mocked(readTaskMessages).mockResolvedValue([])
508-
vi.mocked(readApiMessages).mockResolvedValue([])
506+
vi.mocked(readRooMessages).mockResolvedValue([])
509507

510508
await expect(
511509
(ClineProvider.prototype as any).reopenParentFromDelegation.call(provider, {
@@ -564,7 +562,7 @@ describe("History resume delegation - parent metadata transitions", () => {
564562
} as unknown as ClineProvider
565563

566564
vi.mocked(readTaskMessages).mockResolvedValue([])
567-
vi.mocked(readApiMessages).mockResolvedValue([])
565+
vi.mocked(readRooMessages).mockResolvedValue([])
568566

569567
await (ClineProvider.prototype as any).reopenParentFromDelegation.call(provider, {
570568
parentTaskId: "p4",
@@ -628,7 +626,7 @@ describe("History resume delegation - parent metadata transitions", () => {
628626
} as unknown as ClineProvider
629627

630628
vi.mocked(readTaskMessages).mockResolvedValue([])
631-
vi.mocked(readApiMessages).mockResolvedValue([])
629+
vi.mocked(readRooMessages).mockResolvedValue([])
632630

633631
await (ClineProvider.prototype as any).reopenParentFromDelegation.call(provider, {
634632
parentTaskId: "parent-rpd02",
@@ -709,7 +707,7 @@ describe("History resume delegation - parent metadata transitions", () => {
709707
} as unknown as ClineProvider
710708

711709
vi.mocked(readTaskMessages).mockResolvedValue([])
712-
vi.mocked(readApiMessages).mockResolvedValue([])
710+
vi.mocked(readRooMessages).mockResolvedValue([])
713711

714712
await expect(
715713
(ClineProvider.prototype as any).reopenParentFromDelegation.call(provider, {
@@ -765,7 +763,7 @@ describe("History resume delegation - parent metadata transitions", () => {
765763

766764
// Mock read failures or empty returns
767765
vi.mocked(readTaskMessages).mockResolvedValue([])
768-
vi.mocked(readApiMessages).mockResolvedValue([])
766+
vi.mocked(readRooMessages).mockResolvedValue([])
769767

770768
await expect(
771769
(ClineProvider.prototype as any).reopenParentFromDelegation.call(provider, {
@@ -787,7 +785,7 @@ describe("History resume delegation - parent metadata transitions", () => {
787785
}),
788786
)
789787

790-
expect(saveApiMessages).toHaveBeenCalledWith(
788+
expect(saveRooMessages).toHaveBeenCalledWith(
791789
expect.objectContaining({
792790
messages: [
793791
expect.objectContaining({

src/__tests__/nested-delegation-resume.spec.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,21 @@ vi.mock("vscode", () => {
4343
vi.mock("../core/task-persistence/taskMessages", () => ({
4444
readTaskMessages: vi.fn().mockResolvedValue([]),
4545
}))
46-
vi.mock("../core/task-persistence", () => ({
47-
readApiMessages: vi.fn().mockResolvedValue([]),
48-
saveApiMessages: vi.fn().mockResolvedValue(undefined),
49-
saveTaskMessages: vi.fn().mockResolvedValue(undefined),
50-
}))
46+
vi.mock("../core/task-persistence", async (importOriginal) => {
47+
const actual = await importOriginal<typeof import("../core/task-persistence")>()
48+
return {
49+
...actual,
50+
readRooMessages: vi.fn().mockResolvedValue([]),
51+
saveRooMessages: vi.fn().mockResolvedValue(undefined),
52+
saveTaskMessages: vi.fn().mockResolvedValue(undefined),
53+
}
54+
})
5155

5256
import { attemptCompletionTool } from "../core/tools/AttemptCompletionTool"
5357
import { ClineProvider } from "../core/webview/ClineProvider"
5458
import type { Task } from "../core/task/Task"
5559
import { readTaskMessages } from "../core/task-persistence/taskMessages"
56-
import { readApiMessages, saveApiMessages, saveTaskMessages } from "../core/task-persistence"
60+
import { readRooMessages, saveRooMessages, saveTaskMessages } from "../core/task-persistence"
5761

5862
describe("Nested delegation resume (A → B → C)", () => {
5963
beforeEach(() => {
@@ -164,7 +168,7 @@ describe("Nested delegation resume (A → B → C)", () => {
164168

165169
// Empty histories for simplicity
166170
vi.mocked(readTaskMessages).mockResolvedValue([])
167-
vi.mocked(readApiMessages).mockResolvedValue([])
171+
vi.mocked(readRooMessages).mockResolvedValue([])
168172

169173
// Step 1: C completes -> should reopen B automatically
170174
const clineC = {
@@ -174,6 +178,7 @@ describe("Nested delegation resume (A → B → C)", () => {
174178
historyItem: { parentTaskId: "B" },
175179
providerRef: { deref: () => provider },
176180
say: vi.fn().mockResolvedValue(undefined),
181+
ask: vi.fn().mockResolvedValue({ response: "yesButtonClicked", text: undefined, images: undefined }),
177182
emit: vi.fn(),
178183
getTokenUsage: vi.fn(() => ({})),
179184
toolUsage: {},
@@ -221,6 +226,7 @@ describe("Nested delegation resume (A → B → C)", () => {
221226
historyItem: { parentTaskId: "A" },
222227
providerRef: { deref: () => provider },
223228
say: vi.fn().mockResolvedValue(undefined),
229+
ask: vi.fn().mockResolvedValue({ response: "yesButtonClicked", text: undefined, images: undefined }),
224230
emit: vi.fn(),
225231
getTokenUsage: vi.fn(() => ({})),
226232
toolUsage: {},

0 commit comments

Comments
 (0)