Merge pull request #3065 from code-yeongyu/fix/issue-2984-v2
fix: reset consecutiveFailures on abort so session recovers after user cancel
This commit is contained in:
@@ -1270,7 +1270,7 @@ describe("todo-continuation-enforcer", () => {
|
||||
expect(promptCalls).toHaveLength(0)
|
||||
})
|
||||
|
||||
test("should inject when abort flag is stale (>3s old)", async () => {
|
||||
test("should keep skipping after cancel even when the abort window is stale", async () => {
|
||||
fakeTimers.restore()
|
||||
// given - session with incomplete todos and old abort timestamp
|
||||
const sessionID = "main-stale-abort"
|
||||
@@ -1299,8 +1299,7 @@ describe("todo-continuation-enforcer", () => {
|
||||
|
||||
await wait(3000)
|
||||
|
||||
// then - continuation injected (abort flag is stale)
|
||||
expect(promptCalls.length).toBeGreaterThan(0)
|
||||
expect(promptCalls).toHaveLength(0)
|
||||
}, { timeout: 15000 })
|
||||
|
||||
test("should clear abort flag on user message activity", async () => {
|
||||
@@ -1343,6 +1342,44 @@ describe("todo-continuation-enforcer", () => {
|
||||
expect(promptCalls.length).toBeGreaterThan(0)
|
||||
}, { timeout: 15000 })
|
||||
|
||||
test("should reset failure state and keep skipping after a cancelled run", async () => {
|
||||
fakeTimers.restore()
|
||||
const sessionID = "main-reset-after-cancel"
|
||||
setMainSession(sessionID)
|
||||
mockMessages = [
|
||||
{ info: { id: "msg-1", role: "user" } },
|
||||
{ info: { id: "msg-2", role: "assistant" } },
|
||||
]
|
||||
|
||||
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
|
||||
|
||||
await hook.handler({
|
||||
event: { type: "session.idle", properties: { sessionID } },
|
||||
})
|
||||
|
||||
await wait(2500)
|
||||
expect(promptCalls.length).toBeGreaterThan(0)
|
||||
|
||||
promptCalls.length = 0
|
||||
|
||||
await hook.handler({
|
||||
event: {
|
||||
type: "session.error",
|
||||
properties: { sessionID, error: { name: "MessageAbortedError" } },
|
||||
},
|
||||
})
|
||||
|
||||
await wait(3100)
|
||||
|
||||
await hook.handler({
|
||||
event: { type: "session.idle", properties: { sessionID } },
|
||||
})
|
||||
|
||||
await wait(2500)
|
||||
|
||||
expect(promptCalls).toHaveLength(0)
|
||||
}, { timeout: 15000 })
|
||||
|
||||
test("should clear abort flag on assistant message activity", async () => {
|
||||
fakeTimers.restore()
|
||||
// given - session with abort detected
|
||||
@@ -1866,4 +1903,64 @@ describe("todo-continuation-enforcer", () => {
|
||||
expect(promptCalls).toHaveLength(0)
|
||||
})
|
||||
|
||||
test("should reset consecutiveFailures after user-initiated abort and resume after fresh activity [regression #2984]", async () => {
|
||||
fakeTimers.restore()
|
||||
const sessionID = "main-abort-recovery"
|
||||
setMainSession(sessionID)
|
||||
const mockInput = createMockPluginInput()
|
||||
mockInput.client.session.todo = async () => ({
|
||||
data: [
|
||||
{ id: "1", content: "Write tests", status: "pending", priority: "high" },
|
||||
],
|
||||
})
|
||||
|
||||
let shouldFail = true
|
||||
let promptCallCount = 0
|
||||
mockInput.client.session.promptAsync = async (_opts: PromptRequestOptions) => {
|
||||
promptCallCount++
|
||||
if (shouldFail) {
|
||||
throw new Error("promptAsync failed (3ms) unknown error")
|
||||
}
|
||||
promptCalls.push({
|
||||
sessionID: _opts.path.id,
|
||||
agent: _opts.body.agent,
|
||||
model: _opts.body.model,
|
||||
text: _opts.body.parts[0].text,
|
||||
})
|
||||
}
|
||||
|
||||
const hook = createTodoContinuationEnforcer(mockInput, {})
|
||||
|
||||
await hook.handler({ event: { type: "session.idle", properties: { sessionID } } })
|
||||
await wait(2500)
|
||||
expect(promptCallCount).toBe(1)
|
||||
|
||||
await hook.handler({
|
||||
event: {
|
||||
type: "session.error",
|
||||
properties: { sessionID, error: { name: "MessageAbortedError" } },
|
||||
},
|
||||
})
|
||||
|
||||
shouldFail = false
|
||||
await wait(9000)
|
||||
await hook.handler({ event: { type: "session.idle", properties: { sessionID } } })
|
||||
await wait(2500)
|
||||
expect(promptCallCount).toBe(1)
|
||||
|
||||
await hook.handler({
|
||||
event: {
|
||||
type: "message.updated",
|
||||
properties: { info: { sessionID, role: "user" } },
|
||||
},
|
||||
})
|
||||
|
||||
await hook.handler({ event: { type: "session.idle", properties: { sessionID } } })
|
||||
await wait(2500)
|
||||
|
||||
expect(promptCallCount).toBe(2)
|
||||
expect(promptCalls).toHaveLength(1)
|
||||
}, { timeout: 20000 })
|
||||
|
||||
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user