diff --git a/src/features/background-agent/manager.test.ts b/src/features/background-agent/manager.test.ts index 0fcb463e3..67b584d4b 100644 --- a/src/features/background-agent/manager.test.ts +++ b/src/features/background-agent/manager.test.ts @@ -218,6 +218,10 @@ function getRootDescendantCounts(manager: BackgroundManager): Map }).rootDescendantCounts } +function getPreStartDescendantReservations(manager: BackgroundManager): Set { + return (manager as unknown as { preStartDescendantReservations: Set }).preStartDescendantReservations +} + function getQueuesByKey( manager: BackgroundManager ): Map> { @@ -2526,6 +2530,46 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { expect(retryTask.status).toBe("pending") }) + test("should only roll back the failed task reservation once when siblings still exist", async () => { + // given + const concurrencyKey = "test-agent" + const task = createMockTask({ + id: "task-single-reservation-rollback", + sessionID: "session-single-reservation-rollback", + parentSessionID: "session-root", + status: "pending", + agent: "test-agent", + rootSessionID: "session-root", + }) + delete (task as Partial).sessionID + + const input = { + description: task.description, + prompt: task.prompt, + agent: task.agent, + parentSessionID: task.parentSessionID, + parentMessageID: task.parentMessageID, + } + + getTaskMap(manager).set(task.id, task) + getQueuesByKey(manager).set(concurrencyKey, [{ task, input }]) + getRootDescendantCounts(manager).set("session-root", 2) + getPreStartDescendantReservations(manager).add(task.id) + stubNotifyParentSession(manager) + + ;(manager as unknown as { + startTask: (item: { task: BackgroundTask; input: typeof input }) => Promise + }).startTask = async () => { + throw new Error("session create failed") + } + + // when + await processKeyForTest(manager, concurrencyKey) + + // then + expect(getRootDescendantCounts(manager).get("session-root")).toBe(1) + }) + test("should keep the next queued task when the first task is cancelled during session creation", async () => { // given const firstSessionID = "ses-first-cancelled-during-create" diff --git a/src/features/background-agent/manager.ts b/src/features/background-agent/manager.ts index d06d5fcaf..bd8ff2477 100644 --- a/src/features/background-agent/manager.ts +++ b/src/features/background-agent/manager.ts @@ -422,10 +422,6 @@ export class BackgroundManager { this.concurrencyManager.release(key) } - if (item.task.rootSessionID) { - this.unregisterRootDescendant(item.task.rootSessionID) - } - removeTaskToastTracking(item.task.id) // Abort the orphaned session if one was created before the error