@@ -59,7 +59,11 @@ import type { Settings } from "../config/settings.js";
5959import { resolveEffortForRole } from "../provider/reasoning-effort.js" ;
6060import { isCodexProviderName } from "../config/codex-providers.js" ;
6161import { buildDispatchBrief , type TaskIntent } from "./report.js" ;
62- import { DEFAULT_CANCEL_REASON , type SubAgentSessionStore } from "./session-store.js" ;
62+ import {
63+ DEFAULT_CANCEL_REASON ,
64+ type AgentLifecycleStatus ,
65+ type SubAgentSessionStore ,
66+ } from "./session-store.js" ;
6367import { projectWaitStatus , type WaitJSONStatus } from "./lifecycle.js" ;
6468import type {
6569 NestedDispatchDeps ,
@@ -103,13 +107,23 @@ interface FleetOverlay {
103107 forceInterrupted ?: boolean ;
104108 /** Frozen wait status after collect. Later session completed must not resurrect this mailbox. */
105109 frozenStatus ?: WaitJSONStatus ;
110+ /** Last wait projection seen while the session still existed. */
111+ lastWaitStatus ?: WaitJSONStatus ;
106112 tombstoned ?: boolean ;
107113 hint ?: string ;
108114}
109115
110116const RECOVERY_HINT =
111117 "Report evicted to bound fleet memory; recover full detail via read_agent_trace(agent_id)." ;
112118
119+ function waitStatusFromVerbLifecycle (
120+ status : AgentLifecycleStatus | undefined ,
121+ ) : WaitJSONStatus | undefined {
122+ if ( status === "completed" ) return "done" ;
123+ if ( status === "interrupted" || status === "shutdown" ) return "interrupted" ;
124+ return undefined ;
125+ }
126+
113127/** Payload cap: uncollected pinned terminal records still holding a report. */
114128export const MAX_FLEET_RECORDS = 200 ;
115129
@@ -124,15 +138,22 @@ class FleetMailbox {
124138
125139 constructor ( sessions : SubAgentSessionStore ) {
126140 this . sessions = sessions ;
127- sessions ?. subscribe ( ( ) => this . enforceCap ( ) ) ;
141+ sessions ?. subscribe ( ( ) => {
142+ this . rememberLiveWaitStatuses ( ) ;
143+ this . enforceCap ( ) ;
144+ } ) ;
128145 }
129146
130147 register ( id : string ) : void {
131148 const existing = this . records . get ( id ) ;
132149 // start() drops pinCounts on call-id reuse. Re-pin whenever the overlay
133150 // thought it still held a pin, so wait cannot desync against an empty map.
134151 if ( existing ?. pinHeld === true ) this . sessions . unpin ( id ) ;
135- this . records . set ( id , { pinHeld : true } ) ;
152+ const wait = this . sessionWaitStatus ( id ) ;
153+ this . records . set ( id , {
154+ pinHeld : true ,
155+ ...( wait !== undefined ? { lastWaitStatus : wait } : { } ) ,
156+ } ) ;
136157 this . sessions . pin ( id ) ;
137158 this . enforceCap ( ) ;
138159 }
@@ -204,6 +225,17 @@ class FleetMailbox {
204225 return this . snapshot ( id ) ;
205226 }
206227
228+ private rememberLiveWaitStatuses ( ) : void {
229+ for ( const [ id , overlay ] of this . records ) {
230+ const wait = this . sessionWaitStatus ( id ) ;
231+ if ( wait !== undefined ) overlay . lastWaitStatus = wait ;
232+ }
233+ }
234+
235+ private waitStatusFromEvicted ( id : string ) : WaitJSONStatus | undefined {
236+ return waitStatusFromVerbLifecycle ( this . sessions . evictedLifecycle ( id ) ) ;
237+ }
238+
207239 private sessionWaitStatus ( id : string ) : WaitJSONStatus | undefined {
208240 const session = this . sessions ?. get ( id ) ;
209241 if ( session === undefined ) return undefined ;
@@ -213,7 +245,16 @@ class FleetMailbox {
213245 private projectedStatus ( id : string , overlay : FleetOverlay ) : WaitJSONStatus {
214246 if ( overlay . frozenStatus !== undefined ) return overlay . frozenStatus ;
215247 if ( overlay . forceInterrupted === true ) return "interrupted" ;
216- return this . sessionWaitStatus ( id ) ?? "interrupted" ;
248+ const live = this . sessionWaitStatus ( id ) ;
249+ if ( live !== undefined ) {
250+ overlay . lastWaitStatus = live ;
251+ return live ;
252+ }
253+ const last = overlay . lastWaitStatus ;
254+ if ( last !== undefined && last !== "running" ) return last ;
255+ const evicted = this . waitStatusFromEvicted ( id ) ;
256+ if ( evicted !== undefined && evicted !== "running" ) return evicted ;
257+ return "interrupted" ;
217258 }
218259
219260 snapshot ( id : string ) : FleetRecord {
@@ -229,7 +270,7 @@ class FleetMailbox {
229270 ) {
230271 overlay . tombstoned = true ;
231272 overlay . hint = RECOVERY_HINT ;
232- overlay . frozenStatus = "interrupted" ;
273+ overlay . frozenStatus = this . projectedStatus ( id , overlay ) ;
233274 if ( overlay . pinHeld === true ) {
234275 overlay . pinHeld = false ;
235276 this . sessions . unpin ( id ) ;
0 commit comments