feat(hooks): emit compaction lifecycle hooks#16788
Conversation
|
@greptileai i addressed your one issue on duplicate comment in the docs/readme. The PR should be ready to merge, can you please update your PR score? |
bfc1ccb to
f92900f
Compare
85d9ced to
95c3953
Compare
🔒 Aisle Security AnalysisWe found 1 potential security issue(s) in this PR:
1. 🟡 Compaction awaits hook handlers while holding session write lock and lane, enabling deadlock/DoS
DescriptionIn This creates an availability risk:
Vulnerable flow (lock held across awaited hooks):
Vulnerable code: const sessionLock = await acquireSessionWriteLock({
sessionFile: params.sessionFile,
maxHoldMs: resolveSessionLockMaxHoldFromTimeout({ timeoutMs: EMBEDDED_COMPACTION_TIMEOUT_MS }),
});
try {
// ...
await triggerInternalHook(hookEvent);
// ...
await hookRunner.runBeforeCompaction(...);
// ...
await triggerInternalHook(hookEvent);
await hookRunner.runAfterCompaction(...);
} finally {
await sessionLock.release();
}Impact: a slow/malicious plugin (or internal hook) can cause denial of service, prolonged lock contention, and potential deadlocks within the agent’s command lanes. RecommendationReduce the lock/lane hold time and add bounded hook execution. Option A (preferred): move hooks outside the session write lock
Option B: keep hooks but enforce timeouts and isolation
Example timeout wrapper: import { withTimeout } from "../../node-host/with-timeout.js";
async function runHookWithTimeout<T>(label: string, fn: () => Promise<T>): Promise<T | undefined> {
try {
return await withTimeout(fn, 2_000, label);
} catch (err) {
log.warn(`${label} timed out/failed`, { errorMessage: String(err) });
return undefined;
}
}
await runHookWithTimeout("session:compact:before", () => triggerInternalHook(hookEvent));
await runHookWithTimeout("before_compaction", () => hookRunner.runBeforeCompaction(event, ctx));Option C: prevent lane re-entrancy deadlocks
Analyzed PR: #16788 at commit Last updated on: 2026-03-06T03:08:58Z |
afe2aa0 to
d05f01f
Compare
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
d05f01f to
cbea3da
Compare
Why
Compaction is a critical lifecycle boundary for observability and guardrails, but runtime hook visibility was incomplete. This PR adds explicit compaction lifecycle emissions so operators and plugins can reliably track pre/post compaction state. lobster-biscuit
Split Context
This PR was split from closed umbrella PR #9761: #9761.
Detailed Changes
session:compact:beforesession:compact:afterbefore_compactionafter_compactionRelated Links, Issues and Resolutions
Greptile Summary
Adds internal (
session:compact:before,session:compact:after) and plugin (before_compaction,after_compaction) hook emissions to the compaction flow with count/token metadata. The implementation correctly passes context includingsessionId,agentId,sessionKey,workspaceDir, andmessageProviderto plugin hooks, addressing previous concerns about missingsessionId. The PR also includes a subtle bug fix changingcwd: resolvedWorkspacetocwd: effectiveWorkspaceto properly respect sandbox settings.compactedCountcorrectly measures total reduction from validated transcript through both history limiting and compactionsessionIdin plugin context have been resolvedConfidence Score: 4/5
sessionIdhave been addressed. The change fromresolvedWorkspacetoeffectiveWorkspaceis a legitimate bug fix. Hook payloads intentionally omit full message snapshots per design decisions documented in TODOs. Loses one point only due to the documentation formatting issue already flagged in previous threads (missing blank line before heading).Last reviewed commit: 85d9ced