Skip to content

Commit 5bb8283

Browse files
committed
Keep the failed-summary marker as the only LLM fallback
Prefix-stable compaction still uses one extractive shape on LLM failure, but dropping the CL-6906 marker made a lossy stub look like a real handoff summary. Restore the marker and keep the first summary turn byte-identical across later successful passes.
1 parent 4c36bd2 commit 5bb8283

2 files changed

Lines changed: 8 additions & 5 deletions

File tree

‎src/context-compactor.test.ts‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {
66
formatPlan,
77
classifyTaskBoundary,
88
buildLLMTurnSummary,
9-
buildTurnSummary,
109
COMPACTED_PREFIX,
1110
COMPACT_SPACER_TEXT,
1211
type SessionMetadata,
@@ -675,7 +674,7 @@ describe("createPruningCompactor — prefix-stable summaries (CL-6914)", () => {
675674
const output1 = (await compactor.apply(turns, mockStrategyCtx)).output;
676675
expect(firstText(output1[0]!)).toContain("Turns compacted:");
677676
expect(firstText(output1[0]!)).not.toContain("UNIQUE_SUCCESS_SUMMARY");
678-
expect(firstText(output1[0]!)).not.toContain("Model summary unavailable");
677+
expect(firstText(output1[0]!)).toContain("Model summary unavailable");
679678

680679
const output2 = (await compactor.apply(grow(output1, 16, "ok"), mockStrategyCtx)).output;
681680
expect(firstText(output2[0]!)).toBe(firstText(output1[0]!));

‎src/session/summarizer.ts‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,12 @@ export function createModelSummarizer(
201201
const maxChars = options.maxChars ?? 4000;
202202

203203
return async (turns, ctx) => {
204-
const fallback = (): string => buildTurnSummary(turns, maxChars);
204+
// The marker tells the model (and anyone reading a transcript) that the
205+
// compacted region is a lossy stats stub, not a real handoff summary.
206+
const fallback = (reason: string): string =>
207+
`[Model summary unavailable (${reason}); deterministic fallback]\n${buildTurnSummary(turns, maxChars)}`;
205208
try {
209+
206210
const promptTurns: ConversationTurn[] = [
207211
{
208212
role: "system",
@@ -219,14 +223,14 @@ export function createModelSummarizer(
219223
const text = await complete(promptTurns, options.getSource(), signal);
220224
if (text.length === 0) {
221225
logger.warn("compaction summary call returned empty text; using deterministic fallback");
222-
return fallback();
226+
return fallback("empty model output");
223227
}
224228
return text.length > maxChars ? text.slice(0, maxChars) : text;
225229
} catch (error) {
226230
logger.warn("compaction summary call failed; using deterministic fallback: {error}", {
227231
error: error instanceof Error ? error.message : String(error),
228232
});
229-
return fallback();
233+
return fallback("summary call failed");
230234
}
231235
};
232236
}

0 commit comments

Comments
 (0)