Skip to content

Commit ef7ac52

Browse files
authored
Merge pull request #3771 from tw-yshuang/fix/atlas-pending-continuation-race
fix(atlas): block continuation while delegated tasks are pending
2 parents b43f849 + 56e4044 commit ef7ac52

2 files changed

Lines changed: 41 additions & 1 deletion

File tree

src/hooks/atlas/boulder-continuation-injector.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,44 @@ describe("injectBoulderContinuation", () => {
9191
expect(sessionState.lastContinuationInjectedAt).toBe(123)
9292
})
9393

94+
test("#given a background task is still pending session creation #when injector checks again #then it still skips continuation", async () => {
95+
// given
96+
registerAgentName("atlas")
97+
const promptAsyncMock = mock(async (_request: unknown) => undefined)
98+
const messagesMock = mock(async () => ({ data: [] }))
99+
const sessionState = { promptFailureCount: 1, lastContinuationInjectedAt: 456 }
100+
101+
const ctx = {
102+
directory: "/tmp",
103+
client: {
104+
session: {
105+
messages: messagesMock,
106+
promptAsync: promptAsyncMock,
107+
},
108+
},
109+
} as unknown as PluginInput
110+
111+
// when
112+
const result = await injectBoulderContinuation({
113+
ctx,
114+
sessionID: "ses_test_pending",
115+
planName: "test-plan",
116+
remaining: 1,
117+
total: 2,
118+
agent: "atlas",
119+
backgroundManager: {
120+
getTasksByParentSession: () => [{ status: "pending" }],
121+
} as unknown as Parameters<typeof injectBoulderContinuation>[0]["backgroundManager"],
122+
sessionState,
123+
})
124+
125+
// then
126+
expect(result).toBe("skipped_background_tasks")
127+
expect(promptAsyncMock).not.toHaveBeenCalled()
128+
expect(sessionState.promptFailureCount).toBe(1)
129+
expect(sessionState.lastContinuationInjectedAt).toBe(456)
130+
})
131+
94132
test("#given the continuation agent is unavailable #when injector runs #then it reports skipped agent unavailable without prompting", async () => {
95133
// given
96134
const promptAsyncMock = mock(async (_request: unknown) => undefined)

src/hooks/atlas/boulder-continuation-injector.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import type { SessionState } from "./types"
1313

1414
export type BoulderContinuationResult = "injected" | "skipped_background_tasks" | "skipped_agent_unavailable" | "failed"
1515

16+
const ACTIVE_BACKGROUND_TASK_STATUSES = new Set(["pending", "running"])
17+
1618
export async function injectBoulderContinuation(input: {
1719
ctx: PluginInput
1820
sessionID: string
@@ -41,7 +43,7 @@ export async function injectBoulderContinuation(input: {
4143
} = input
4244

4345
const hasRunningBgTasks = backgroundManager
44-
? backgroundManager.getTasksByParentSession(sessionID).some((t: { status: string }) => t.status === "running")
46+
? backgroundManager.getTasksByParentSession(sessionID).some((t: { status: string }) => ACTIVE_BACKGROUND_TASK_STATUSES.has(t.status))
4547
: false
4648

4749
if (hasRunningBgTasks) {

0 commit comments

Comments
 (0)