Add before_compact hook event (closes #281) (#285)

* Add before_compact hook event (closes #281)

* Add compact hook event and documentation

- Add compact event that fires after compaction completes
- Update hooks.md with lifecycle diagram, field docs, and example
- Add CHANGELOG entry
- Add comprehensive test coverage (10 tests) for before_compact and compact events
- Tests cover: event emission, cancellation, custom entry, error handling, multiple hooks
This commit is contained in:
Nico Bailon 2025-12-24 02:26:29 -08:00 committed by GitHub
parent 20b24cf5a4
commit 1e1a92ea47
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 700 additions and 36 deletions

View file

@ -321,6 +321,49 @@ export async function generateSummary(
return textContent;
}
// ============================================================================
// Compaction Preparation (for hooks)
// ============================================================================
export interface CompactionPreparation {
cutPoint: CutPointResult;
messagesToSummarize: AppMessage[];
tokensBefore: number;
boundaryStart: number;
}
export function prepareCompaction(entries: SessionEntry[], settings: CompactionSettings): CompactionPreparation | null {
if (entries.length > 0 && entries[entries.length - 1].type === "compaction") {
return null;
}
let prevCompactionIndex = -1;
for (let i = entries.length - 1; i >= 0; i--) {
if (entries[i].type === "compaction") {
prevCompactionIndex = i;
break;
}
}
const boundaryStart = prevCompactionIndex + 1;
const boundaryEnd = entries.length;
const lastUsage = getLastAssistantUsage(entries);
const tokensBefore = lastUsage ? calculateContextTokens(lastUsage) : 0;
const cutPoint = findCutPoint(entries, boundaryStart, boundaryEnd, settings.keepRecentTokens);
const historyEnd = cutPoint.isSplitTurn ? cutPoint.turnStartIndex : cutPoint.firstKeptEntryIndex;
const messagesToSummarize: AppMessage[] = [];
for (let i = boundaryStart; i < historyEnd; i++) {
const entry = entries[i];
if (entry.type === "message") {
messagesToSummarize.push(entry.message);
}
}
return { cutPoint, messagesToSummarize, tokensBefore, boundaryStart };
}
// ============================================================================
// Main compaction function
// ============================================================================