From aa1f36664e14469990744102d9d2275929b170b9 Mon Sep 17 00:00:00 2001 From: HarryZhou <2373256746@qq.com> Date: Fri, 7 Aug 2026 19:35:05 +0800 Subject: [PATCH 1/2] fix(goal-loop): resume auto-continue after session compaction After a compaction the recent message tail can still end on the same assistant message that an in-flight continuation claim points at, so the idle driver's claim dedupe suppressed the post-compaction continuation and the goal loop stalled until the user nudged it. Invalidate the continuation claim on session.compacted so the next idle issues a fresh continuation against the compacted context. Adds a reproduction test: claim set for the latest assistant turn, then session.compacted, then idle -> exactly one continuation prompt. --- CHANGELOG.md | 6 ++++++ src/goal-plugin.js | 6 ++++++ test/goal-plugin.test.js | 43 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a716e5d..30ee415 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Unreleased +- Fix goal auto-continue stalling after session compaction: a continuation + claim for a pre-compaction source turn could match the still-visible tail + assistant message after compaction and suppress the post-compaction + continuation until the user nudged the goal. The claim is now invalidated on + `session.compacted`, so the loop resumes on the next idle. + ## 0.8.0 — 2026-08-06 Both new options in this release were contributed by diff --git a/src/goal-plugin.js b/src/goal-plugin.js index e611188..b4a52ae 100644 --- a/src/goal-plugin.js +++ b/src/goal-plugin.js @@ -5331,6 +5331,12 @@ async function createGoalPlugin({ client, directory } = {}, pluginOptions = {}) if (!goal) return goal.messageIDs = new Set() goal.totalTokens = 0 + // Compaction rewrites the context: a continuation claim for a + // pre-compaction source turn must not suppress the post-compaction + // continuation (the recent tail can still end on the same assistant + // message, which would otherwise stall the goal loop until the user + // nudges it). + goal.continuationClaim = null await persist(sessionID) return } diff --git a/test/goal-plugin.test.js b/test/goal-plugin.test.js index eba8348..dd0f0e1 100644 --- a/test/goal-plugin.test.js +++ b/test/goal-plugin.test.js @@ -4363,6 +4363,49 @@ test("totalTokens resets to zero after session compaction", async () => { assert.equal(currentGoal(session).totalTokens, 45_000, "post-compaction tokens accumulate from zero") }) +test("auto-continue fires after compaction despite a pre-compaction continuation claim", async () => { + const calls = [] + const client = { + app: { log: async () => {} }, + session: { + messages: async () => ({ + data: [pluginContinuationMessage(), message("did a step")], + }), + promptAsync: async (input) => { + calls.push(input) + return {} + }, + }, + } + const hooks = await GoalPlugin( + { client }, + { persistState: false, minDelayMs: 1, noToolCallTurnsBeforePause: 0 }, + ) + await hooks["command.execute.before"]( + { command: "goal", sessionID: "session-1", arguments: "ship it" }, + { parts: [] }, + ) + const goal = currentGoal("session-1") + goal.turnCount = 1 + goal.lastContinueAt = Date.now() - 10 + // A continuation was claimed for the latest assistant turn right before the + // compaction interrupted it; after compaction the recent tail still ends on + // that same assistant message, so the stale claim must not suppress the + // post-compaction continuation. + goal.continuationClaim = { runId: goal.runId, sourceAssistantMessageID: "msg-assistant" } + + await hooks.event({ + event: { type: "session.compacted", properties: { sessionID: "session-1" } }, + }) + + await hooks.event({ + event: { type: "session.status", properties: { sessionID: "session-1", status: { type: "idle" } } }, + }) + + assert.equal(calls.length, 1) + assert.equal(currentGoal("session-1").stopped, false) +}) + test("parses --max-duration-ms flag directly", () => { const parsed = parseGoalArguments("fix tests --max-duration-ms 90000", normalizeOptions()) assert.equal(parsed.condition, "fix tests") From 076af37447e1359ceb6aabcc26644306cc095d57 Mon Sep 17 00:00:00 2001 From: HarryZhou <2373256746@qq.com> Date: Fri, 7 Aug 2026 19:38:40 +0800 Subject: [PATCH 2/2] ci: retrigger after flaky Windows lease test (simultaneous stale observers)