@@ -25,6 +25,8 @@ type CompactionEndEvent =
2525 aborted ?: unknown ;
2626 } ;
2727
28+ // Unknown reasons come from external runtimes or older sessions. Treat them as
29+ // threshold compaction so logs and event payloads stay on the closed reason set.
2830function normalizeCompactionReason ( reason : unknown ) : CompactionReason {
2931 return reason === "manual" || reason === "threshold" || reason === "overflow"
3032 ? reason
@@ -35,6 +37,7 @@ function compactionLogKind(reason: CompactionReason): string {
3537 return reason === "manual" ? "manual compaction" : "auto-compaction" ;
3638}
3739
40+ /** Handles compaction start events from an embedded agent session. */
3841export function handleCompactionStart (
3942 ctx : EmbeddedAgentSubscribeContext ,
4043 evt : CompactionStartEvent ,
@@ -60,7 +63,8 @@ export function handleCompactionStart(
6063 data : { phase : "start" } ,
6164 } ) ;
6265
63- // Run before_compaction plugin hook (fire-and-forget)
66+ // Hooks are fire-and-forget so compaction state updates and liveness pauses
67+ // cannot be delayed by plugin work.
6468 const hookRunner = getGlobalHookRunner ( ) ;
6569 if ( hookRunner ?. hasHooks ( "before_compaction" ) ) {
6670 void hookRunner
@@ -80,15 +84,15 @@ export function handleCompactionStart(
8084 }
8185}
8286
87+ /** Handles compaction completion, retry, and incomplete events. */
8388export function handleCompactionEnd ( ctx : EmbeddedAgentSubscribeContext , evt : CompactionEndEvent ) {
8489 const reason = normalizeCompactionReason ( evt . reason ) ;
8590 const kind = compactionLogKind ( reason ) ;
8691 ctx . state . compactionInFlight = false ;
8792 const willRetry = Boolean ( evt . willRetry ) ;
88- // Increment counter whenever compaction actually produced a result,
89- // regardless of willRetry. Overflow-triggered compaction sets willRetry=true
90- // (the framework retries the LLM request), but the compaction itself succeeded
91- // and context was trimmed — the counter must reflect that. (#38905)
93+ // Increment counter whenever compaction actually produced a result, regardless
94+ // of willRetry. Overflow-triggered compaction retries the LLM request after
95+ // trimming context, and the persisted count must reflect that successful trim.
9296 const hasResult = evt . result != null ;
9397 const wasAborted = Boolean ( evt . aborted ) ;
9498 if ( hasResult && ! wasAborted ) {
@@ -149,7 +153,8 @@ export function handleCompactionEnd(ctx: EmbeddedAgentSubscribeContext, evt: Com
149153 data : { phase : "end" , willRetry, completed : hasResult && ! wasAborted } ,
150154 } ) ;
151155
152- // Run after_compaction plugin hook (fire-and-forget)
156+ // after_compaction runs only once the run will not retry, matching the visible
157+ // post-compaction session state plugin authors observe.
153158 if ( ! willRetry ) {
154159 const hookRunnerEnd = getGlobalHookRunner ( ) ;
155160 if ( hookRunnerEnd ?. hasHooks ( "after_compaction" ) ) {
@@ -169,6 +174,7 @@ export function handleCompactionEnd(ctx: EmbeddedAgentSubscribeContext, evt: Com
169174 }
170175}
171176
177+ /** Lazily reconciles persisted compaction count after a successful compaction. */
172178export async function reconcileSessionStoreCompactionCountAfterSuccess ( params : {
173179 sessionKey ?: string ;
174180 agentId ?: string ;
@@ -181,6 +187,8 @@ export async function reconcileSessionStoreCompactionCountAfterSuccess(params: {
181187 return reconcile ( params ) ;
182188}
183189
190+ // Compaction rewrites history, so assistant usage snapshots can refer to the
191+ // old context. Keep the usage field shape but zero it for fresh accounting.
184192function clearStaleAssistantUsageOnSessionMessages ( ctx : EmbeddedAgentSubscribeContext ) : void {
185193 const messages = ctx . params . session . messages ;
186194 if ( ! Array . isArray ( messages ) ) {
@@ -194,8 +202,6 @@ function clearStaleAssistantUsageOnSessionMessages(ctx: EmbeddedAgentSubscribeCo
194202 if ( candidate . role !== "assistant" ) {
195203 continue ;
196204 }
197- // session runtime expects assistant usage to exist when computing context usage.
198- // Reset stale snapshots to zeros instead of deleting the field.
199205 candidate . usage = makeZeroUsageSnapshot ( ) ;
200206 }
201207}
0 commit comments