Skip to content

Commit 9732faa

Browse files
Kaspreclaude
andcommitted
fix(memory): memoryFlush fires every compaction cycle instead of every other
After a memoryFlush during compaction, memoryFlushCompactionCount was reassigned to the post-increment compactionCount, locking both counters to the same value. The dedup gate hasAlreadyFlushedForCurrentCompaction then saw equal values and skipped the next flush. Fix: stop reassigning memoryFlushCompactionCount to the post-increment value. The counter stays at N (pre-increment); after incrementCompactionCount, compactionCount becomes N+1. Next cycle, N !== N+1, flush fires. Closes #12590. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent d3eeadb commit 9732faa

2 files changed

Lines changed: 37 additions & 5 deletions

File tree

src/auto-reply/reply/agent-runner-memory.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -791,13 +791,13 @@ export async function runMemoryFlushIfNeeded(params: {
791791
return result;
792792
},
793793
});
794-
let memoryFlushCompactionCount =
794+
const memoryFlushCompactionCount =
795795
activeSessionEntry?.compactionCount ??
796796
(params.sessionKey ? activeSessionStore?.[params.sessionKey]?.compactionCount : 0) ??
797797
0;
798798
if (memoryCompactionCompleted) {
799799
const previousSessionId = activeSessionEntry?.sessionId ?? params.followupRun.run.sessionId;
800-
const nextCount = await memoryDeps.incrementCompactionCount({
800+
await memoryDeps.incrementCompactionCount({
801801
cfg: params.cfg,
802802
sessionEntry: activeSessionEntry,
803803
sessionStore: activeSessionStore,
@@ -823,9 +823,10 @@ export async function runMemoryFlushIfNeeded(params: {
823823
});
824824
}
825825
}
826-
if (typeof nextCount === "number") {
827-
memoryFlushCompactionCount = nextCount;
828-
}
826+
// Do NOT reassign memoryFlushCompactionCount to the post-increment value.
827+
// Keeping it at the pre-increment value ensures the next compaction cycle
828+
// sees different counters, allowing memoryFlush to fire every cycle
829+
// instead of every other. See #12590.
829830
}
830831
if (params.storePath && params.sessionKey) {
831832
try {

src/auto-reply/reply/reply-state.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,37 @@ describe("shouldRunMemoryFlush", () => {
292292
).toBe(true);
293293
});
294294

295+
it("triggers on every compaction cycle when flush records pre-increment count (#12590)", () => {
296+
const params = {
297+
contextWindowTokens: 100_000,
298+
reserveTokensFloor: 5_000,
299+
softThresholdTokens: 2_000,
300+
};
301+
302+
// Cycle 1: compactionCount=1, no prior flush → triggers
303+
expect(
304+
shouldRunMemoryFlush({ entry: { totalTokens: 95_000, compactionCount: 1 }, ...params }),
305+
).toBe(true);
306+
307+
// After flush records compactionCount=1, compaction increments to 2.
308+
// Cycle 2: compactionCount=2, memoryFlushCompactionCount=1 → triggers
309+
expect(
310+
shouldRunMemoryFlush({
311+
entry: { totalTokens: 95_000, compactionCount: 2, memoryFlushCompactionCount: 1 },
312+
...params,
313+
}),
314+
).toBe(true);
315+
316+
// After flush records compactionCount=2, compaction increments to 3.
317+
// Cycle 3: compactionCount=3, memoryFlushCompactionCount=2 → triggers
318+
expect(
319+
shouldRunMemoryFlush({
320+
entry: { totalTokens: 95_000, compactionCount: 3, memoryFlushCompactionCount: 2 },
321+
...params,
322+
}),
323+
).toBe(true);
324+
});
325+
295326
it("ignores stale cached totals", () => {
296327
expect(
297328
shouldRunMemoryFlush({

0 commit comments

Comments
 (0)