@@ -459,75 +459,61 @@ describe("runCodexAppServerAttempt turn watches", () => {
459459 } ) ;
460460
461461 it ( "keeps a progressing active turn alive beyond the original attempt timeout" , async ( ) => {
462- const harness = createStartedThreadHarness ( ) ;
463- const params = createParams (
464- path . join ( tempDir , "session.jsonl" ) ,
465- path . join ( tempDir , "workspace" ) ,
466- ) ;
467- params . timeoutMs = 100 ;
468462 const onRunProgress = vi . fn ( ) ;
469- params . onRunProgress = onRunProgress ;
470-
471- const run = runCodexAppServerAttempt ( params , {
472- turnCompletionIdleTimeoutMs : 300 ,
473- turnAssistantCompletionIdleTimeoutMs : 300 ,
474- turnTerminalIdleTimeoutMs : 300 ,
463+ const onTimeout = vi . fn ( ) ;
464+ const onAbort = vi . fn ( ) ;
465+ const controller = createCodexAttemptTurnWatchController ( {
466+ threadId : "thread-1" ,
467+ signal : new AbortController ( ) . signal ,
468+ getTurnId : ( ) => "turn-1" ,
469+ isCompleted : ( ) => false ,
470+ isTerminalTurnNotificationQueued : ( ) => false ,
471+ getActiveAppServerTurnRequests : ( ) => 0 ,
472+ getActiveTurnItemCount : ( ) => 0 ,
473+ turnCompletionIdleTimeoutMs : 1_000 ,
474+ turnAssistantCompletionIdleTimeoutMs : 1_000 ,
475+ turnAttemptIdleTimeoutMs : 300 ,
476+ turnTerminalIdleTimeoutMs : 1_000 ,
477+ interruptTimeoutMs : 5_000 ,
478+ onInterruptTurn : vi . fn ( ) ,
479+ onTimeout,
480+ onMarkTimedOut : vi . fn ( ) ,
481+ onAbort,
482+ onCompleted : vi . fn ( ) ,
483+ onResolveCompletion : vi . fn ( ) ,
484+ onRecordEvent : vi . fn ( ) ,
485+ onAttemptProgress : onRunProgress ,
486+ onProgressDiagnostic : vi . fn ( ) ,
475487 } ) ;
476- await harness . waitForMethod ( "turn/start" ) ;
477- await vi . waitFor (
478- ( ) =>
479- expect ( onRunProgress ) . toHaveBeenCalledWith (
480- expect . objectContaining ( { reason : "turn:start" } ) ,
481- ) ,
482- fastWait ,
483- ) ;
484488
485- await new Promise ( ( resolve ) => {
486- setTimeout ( resolve , 60 ) ;
487- } ) ;
488- await harness . notify ( {
489- method : "rawResponseItem/completed" ,
490- params : {
491- threadId : "thread-1" ,
492- turnId : "turn-1" ,
493- item : {
494- type : "message" ,
495- id : "raw-progress-1" ,
496- role : "assistant" ,
497- content : [ { type : "output_text" , text : "Still working." } ] ,
498- } ,
499- } ,
500- } ) ;
501- await new Promise ( ( resolve ) => {
502- setTimeout ( resolve , 60 ) ;
503- } ) ;
504- await harness . notify ( {
505- method : "rawResponseItem/completed" ,
506- params : {
507- threadId : "thread-1" ,
508- turnId : "turn-1" ,
509- item : {
510- type : "message" ,
511- id : "raw-progress-2" ,
512- role : "assistant" ,
513- content : [ { type : "output_text" , text : "Almost done." } ] ,
514- } ,
515- } ,
516- } ) ;
489+ vi . useFakeTimers ( ) ;
490+ try {
491+ controller . armAttemptIdleWatch ( ) ;
492+ controller . touchActivity ( "turn:start" , { attemptProgress : true } ) ;
517493
518- expect ( harness . request . mock . calls . some ( ( [ method ] ) => method === "turn/interrupt" ) ) . toBe ( false ) ;
519- await harness . completeTurn ( { threadId : "thread-1" , turnId : "turn-1" } ) ;
494+ await vi . advanceTimersByTimeAsync ( 200 ) ;
495+ controller . noteNotificationReceived ( "response.custom_tool_call_input.delta" , {
496+ attemptProgress : true ,
497+ } ) ;
520498
521- const result = await run ;
522- expect ( result . aborted ) . toBe ( false ) ;
523- expect ( result . timedOut ) . toBe ( false ) ;
524- expect ( result . promptError ) . toBeNull ( ) ;
525- expect ( harness . request . mock . calls . some ( ( [ method ] ) => method === "turn/interrupt" ) ) . toBe ( false ) ;
526- const progressReasons = onRunProgress . mock . calls . map ( ( [ info ] ) => info . reason ) ;
527- expect ( progressReasons ) . toContain ( "turn:start" ) ;
528- expect (
529- progressReasons . filter ( ( reason ) => reason === "notification:rawResponseItem/completed" ) ,
530- ) . toHaveLength ( 2 ) ;
499+ await vi . advanceTimersByTimeAsync ( 200 ) ;
500+ controller . noteNotificationReceived ( "response.custom_tool_call_input.delta" , {
501+ attemptProgress : true ,
502+ } ) ;
503+
504+ await vi . advanceTimersByTimeAsync ( 200 ) ;
505+
506+ expect ( onTimeout ) . not . toHaveBeenCalled ( ) ;
507+ expect ( onAbort ) . not . toHaveBeenCalled ( ) ;
508+ expect ( onRunProgress . mock . calls . map ( ( [ reason ] ) => reason ) ) . toEqual ( [
509+ "turn:start" ,
510+ "notification:response.custom_tool_call_input.delta" ,
511+ "notification:response.custom_tool_call_input.delta" ,
512+ ] ) ;
513+ } finally {
514+ controller . clearAllTimers ( ) ;
515+ vi . useRealTimers ( ) ;
516+ }
531517 } ) ;
532518
533519 it ( "does not count non-turn app-server requests as turn attempt progress" , async ( ) => {
0 commit comments