Skip to content

Commit 9690ed1

Browse files
committed
fix(memoryFlush): guard transcript-size forced flush against repeated runs
The `forceFlushTranscriptBytes` path (introduced in d729ab2) bypasses the `memoryFlushCompactionCount` guard that prevents repeated flushes within the same compaction cycle. Once the session transcript exceeds 2 MB, memory flush fires on every single message — even when token count is well under the compaction threshold. Extract `hasAlreadyFlushedForCurrentCompaction()` from the inline guard in `shouldRunMemoryFlush` and apply it to both the token-based and the transcript-size trigger paths. Fixes #32317 Signed-off-by: HCL <[email protected]>
1 parent 53fd7f8 commit 9690ed1

File tree

3 files changed

+55
-4
lines changed

3 files changed

+55
-4
lines changed

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
resolveModelFallbackOptions,
3232
} from "./agent-runner-utils.js";
3333
import {
34+
hasAlreadyFlushedForCurrentCompaction,
3435
resolveMemoryFlushContextWindowTokens,
3536
resolveMemoryFlushPromptForRun,
3637
resolveMemoryFlushSettings,
@@ -437,7 +438,9 @@ export async function runMemoryFlushIfNeeded(params: {
437438
reserveTokensFloor: memoryFlushSettings.reserveTokensFloor,
438439
softThresholdTokens: memoryFlushSettings.softThresholdTokens,
439440
})) ||
440-
shouldForceFlushByTranscriptSize;
441+
(shouldForceFlushByTranscriptSize &&
442+
entry != null &&
443+
!hasAlreadyFlushedForCurrentCompaction(entry));
441444

442445
if (!shouldFlushMemory) {
443446
return entry ?? params.sessionEntry;

src/auto-reply/reply/memory-flush.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,22 @@ export function shouldRunMemoryFlush(params: {
161161
return false;
162162
}
163163

164-
const compactionCount = params.entry.compactionCount ?? 0;
165-
const lastFlushAt = params.entry.memoryFlushCompactionCount;
166-
if (typeof lastFlushAt === "number" && lastFlushAt === compactionCount) {
164+
if (hasAlreadyFlushedForCurrentCompaction(params.entry)) {
167165
return false;
168166
}
169167

170168
return true;
171169
}
170+
171+
/**
172+
* Returns true when a memory flush has already been performed for the current
173+
* compaction cycle. This prevents repeated flush runs within the same cycle —
174+
* important for both the token-based and transcript-size–based trigger paths.
175+
*/
176+
export function hasAlreadyFlushedForCurrentCompaction(
177+
entry: Pick<SessionEntry, "compactionCount" | "memoryFlushCompactionCount">,
178+
): boolean {
179+
const compactionCount = entry.compactionCount ?? 0;
180+
const lastFlushAt = entry.memoryFlushCompactionCount;
181+
return typeof lastFlushAt === "number" && lastFlushAt === compactionCount;
182+
}

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
import {
1818
DEFAULT_MEMORY_FLUSH_FORCE_TRANSCRIPT_BYTES,
1919
DEFAULT_MEMORY_FLUSH_SOFT_TOKENS,
20+
hasAlreadyFlushedForCurrentCompaction,
2021
resolveMemoryFlushContextWindowTokens,
2122
resolveMemoryFlushSettings,
2223
shouldRunMemoryFlush,
@@ -350,6 +351,42 @@ describe("shouldRunMemoryFlush", () => {
350351
});
351352
});
352353

354+
describe("hasAlreadyFlushedForCurrentCompaction", () => {
355+
it("returns true when memoryFlushCompactionCount matches compactionCount", () => {
356+
expect(
357+
hasAlreadyFlushedForCurrentCompaction({
358+
compactionCount: 3,
359+
memoryFlushCompactionCount: 3,
360+
}),
361+
).toBe(true);
362+
});
363+
364+
it("returns false when memoryFlushCompactionCount differs", () => {
365+
expect(
366+
hasAlreadyFlushedForCurrentCompaction({
367+
compactionCount: 3,
368+
memoryFlushCompactionCount: 2,
369+
}),
370+
).toBe(false);
371+
});
372+
373+
it("returns false when memoryFlushCompactionCount is undefined", () => {
374+
expect(
375+
hasAlreadyFlushedForCurrentCompaction({
376+
compactionCount: 1,
377+
}),
378+
).toBe(false);
379+
});
380+
381+
it("treats missing compactionCount as 0", () => {
382+
expect(
383+
hasAlreadyFlushedForCurrentCompaction({
384+
memoryFlushCompactionCount: 0,
385+
}),
386+
).toBe(true);
387+
});
388+
});
389+
353390
describe("resolveMemoryFlushContextWindowTokens", () => {
354391
it("falls back to agent config or default tokens", () => {
355392
expect(resolveMemoryFlushContextWindowTokens({ agentCfgContextTokens: 42_000 })).toBe(42_000);

0 commit comments

Comments
 (0)