Skip to content

Commit 8ad8cfd

Browse files
committed
test(compaction): pin previous-summary restoration boundary
1 parent 558cffb commit 8ad8cfd

3 files changed

Lines changed: 14 additions & 10 deletions

File tree

src/agents/agent-hooks/compaction-safeguard.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2021,6 +2021,7 @@ describe("compaction-safeguard recent-turn preservation", () => {
20212021
const messages = requireArray(call.messages);
20222022
expect(JSON.stringify(messages[0])).toContain("<previous-compaction-summary>");
20232023
expect(JSON.stringify(messages[0])).toContain("Old duplicated section");
2024+
expect(result.compaction?.summary).not.toContain("Old duplicated section");
20242025
});
20252026

20262027
it("preserves the prior summary when staged summarization returns a generic fallback", async () => {

src/agents/compaction.circuit-breaker.test.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,14 +85,19 @@ describe("compaction staged fallback circuit breaker", () => {
8585
.mockResolvedValueOnce("oldest summary")
8686
.mockRejectedValueOnce(new Error("fetch failed"))
8787
.mockResolvedValueOnce("newest summary")
88-
.mockResolvedValueOnce("merged summary");
88+
.mockResolvedValueOnce("merged: oldest summary + newest summary");
8989

9090
// The oldest split carries whatever context the caller needs redistilled, and it
9191
// made it into the merge. Reporting a fallback here makes callers re-add it.
9292
await expect(summarize()).resolves.toEqual({
9393
kind: "summary",
94-
text: "merged summary",
94+
text: "merged: oldest summary + newest summary",
9595
});
9696
expect(agentSessionMocks.generateSummary).toHaveBeenCalledTimes(4);
97+
expect(agentSessionMocks.generateSummary.mock.calls[3]?.[0]).toEqual(
98+
expect.arrayContaining([
99+
expect.objectContaining({ content: expect.stringContaining("oldest summary") }),
100+
]),
101+
);
97102
});
98103
});

src/agents/compaction.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -413,11 +413,9 @@ export async function summarizeInStages(params: {
413413

414414
const partialSummaries: string[] = [];
415415
let consecutiveGenericFallbacks = 0;
416-
// Chunk 0 carries the oldest messages, which is where a caller puts context it needs
417-
// redistilled into the new summary. Only its degradation means that context never
418-
// reached the merge, so this — not "any chunk degraded" — is what the result kind
419-
// reports; otherwise a caller restoring lost context duplicates what the merge has.
420-
let firstChunkDegraded = false;
416+
// Caller-owned leading context lives in the oldest split. Only losing that
417+
// split requires restoration; later fallback placeholders remain in the merge.
418+
let oldestChunkDegraded = false;
421419
for (const [index, chunk] of plan.chunks.entries()) {
422420
const result = await summarizeWithFallbackResult({
423421
...params,
@@ -427,7 +425,7 @@ export async function summarizeInStages(params: {
427425
consecutiveGenericFallbacks =
428426
result.kind === "generic-fallback" ? consecutiveGenericFallbacks + 1 : 0;
429427
if (index === 0) {
430-
firstChunkDegraded = result.kind === "generic-fallback";
428+
oldestChunkDegraded = result.kind === "generic-fallback";
431429
}
432430

433431
// Keep one placeholder to mark the missing split, but stop before repeated
@@ -451,7 +449,7 @@ export async function summarizeInStages(params: {
451449
throw new Error("Compaction summary plan produced no summary");
452450
}
453451
return {
454-
kind: firstChunkDegraded ? "generic-fallback" : "summary",
452+
kind: oldestChunkDegraded ? "generic-fallback" : "summary",
455453
text: summary,
456454
};
457455
}
@@ -492,7 +490,7 @@ export async function summarizeInStages(params: {
492490
messages: summaryMessages,
493491
customInstructions: mergeInstructions,
494492
});
495-
return firstChunkDegraded && mergedResult.kind === "summary"
493+
return oldestChunkDegraded && mergedResult.kind === "summary"
496494
? { kind: "generic-fallback", text: mergedResult.text }
497495
: mergedResult;
498496
}

0 commit comments

Comments
 (0)