@@ -2050,6 +2050,20 @@ describe("agent event handler", () => {
20502050 expect ( fallbackPayload . runId ) . toBe ( "run-fallback-client" ) ;
20512051 expect ( fallbackPayload . data ?. phase ) . toBe ( "fallback" ) ;
20522052
2053+ vi . advanceTimersByTime ( 100 ) ;
2054+
2055+ expect ( chatRunState . registry . peek ( "run-fallback-retry" ) ) . toEqual ( {
2056+ sessionKey : "session-fallback" ,
2057+ clientRunId : "run-fallback-client" ,
2058+ } ) ;
2059+ expect (
2060+ chatBroadcastCalls ( broadcast ) . some (
2061+ ( [ , payload ] ) => ( payload as { state ?: string } ) . state === "error" ,
2062+ ) ,
2063+ ) . toBe ( false ) ;
2064+ expect ( clearAgentRunContext ) . not . toHaveBeenCalled ( ) ;
2065+ expect ( agentRunSeq . get ( "run-fallback-retry" ) ) . toBe ( 3 ) ;
2066+
20532067 emitLifecycleEnd ( handler , "run-fallback-retry" , 4 ) ;
20542068
20552069 expect (
@@ -2172,6 +2186,52 @@ describe("agent event handler", () => {
21722186 ) . toBe ( true ) ;
21732187 } ) ;
21742188
2189+ it ( "keeps deferred lifecycle-error cleanup across phase-less lifecycle events" , ( ) => {
2190+ vi . useFakeTimers ( ) ;
2191+ const { broadcast, clearAgentRunContext, agentRunSeq, handler } = createHarness ( {
2192+ resolveSessionKeyForRun : ( ) => "session-terminal-error" ,
2193+ lifecycleErrorRetryGraceMs : 100 ,
2194+ } ) ;
2195+ registerAgentRunContext ( "run-terminal-late-lifecycle" , {
2196+ sessionKey : "session-terminal-error" ,
2197+ } ) ;
2198+
2199+ handler ( {
2200+ runId : "run-terminal-late-lifecycle" ,
2201+ seq : 1 ,
2202+ stream : "lifecycle" ,
2203+ ts : Date . now ( ) ,
2204+ data : { phase : "start" } ,
2205+ } ) ;
2206+ handler ( {
2207+ runId : "run-terminal-late-lifecycle" ,
2208+ seq : 2 ,
2209+ stream : "lifecycle" ,
2210+ ts : Date . now ( ) ,
2211+ data : { phase : "error" , error : "request timed out" } ,
2212+ } ) ;
2213+ handler ( {
2214+ runId : "run-terminal-late-lifecycle" ,
2215+ seq : 3 ,
2216+ stream : "lifecycle" ,
2217+ ts : Date . now ( ) ,
2218+ data : { msg : "status update" } ,
2219+ } ) ;
2220+
2221+ vi . advanceTimersByTime ( 100 ) ;
2222+
2223+ const finalPayload = chatBroadcastCalls ( broadcast ) . at ( - 1 ) ?. [ 1 ] as {
2224+ state ?: string ;
2225+ runId ?: string ;
2226+ errorMessage ?: string ;
2227+ } ;
2228+ expect ( finalPayload . state ) . toBe ( "error" ) ;
2229+ expect ( finalPayload . runId ) . toBe ( "run-terminal-late-lifecycle" ) ;
2230+ expect ( finalPayload . errorMessage ) . toContain ( "request timed out" ) ;
2231+ expect ( clearAgentRunContext ) . toHaveBeenCalledWith ( "run-terminal-late-lifecycle" ) ;
2232+ expect ( agentRunSeq . has ( "run-terminal-late-lifecycle" ) ) . toBe ( false ) ;
2233+ } ) ;
2234+
21752235 it ( "cancels deferred lifecycle-error cleanup when the run restarts" , ( ) => {
21762236 vi . useFakeTimers ( ) ;
21772237 const { broadcast, clearAgentRunContext, agentRunSeq, handler } = createHarness ( {
0 commit comments