@@ -378,18 +378,44 @@ export class CodexAcpClient {
378378 this . codexClient . onElicitationRequest ( sessionId , elicitationHandler ) ;
379379 }
380380
381+ disposeSession ( sessionId : string ) : void {
382+ this . codexClient . clearSessionHandlers ( sessionId ) ;
383+ }
384+
385+ async closeSession ( sessionId : string ) : Promise < void > {
386+ await this . codexClient . threadUnsubscribe ( { threadId : sessionId } ) ;
387+ }
388+
381389 async sendPrompt (
382390 request : acp . PromptRequest ,
383391 agentMode : AgentMode ,
384392 modelId : ModelId ,
385393 serviceTier : ServiceTier | null ,
386394 disableSummary : boolean ,
387395 cwd : string ,
396+ onTurnStarted ?: ( turnId : string ) => void ,
397+ onTurnStartRequested ?: ( ) => void ,
398+ isCancelled ?: ( ) => boolean ,
399+ cancellation ?: Promise < TurnCompletedNotification > ,
388400 ) : Promise < TurnCompletedNotification > {
389401 const input = buildPromptItems ( request . prompt ) ;
390402 const effort = modelId . effort as ReasoningEffort | null ; //TODO remove unsafe conversion
391403
392- await this . refreshSkills ( cwd , request . _meta ) ;
404+ if ( cancellation ) {
405+ const refreshResult = await Promise . race ( [
406+ this . refreshSkills ( cwd , request . _meta ) . then ( ( ) => null ) ,
407+ cancellation ,
408+ ] ) ;
409+ if ( refreshResult !== null ) {
410+ return refreshResult ;
411+ }
412+ } else {
413+ await this . refreshSkills ( cwd , request . _meta ) ;
414+ }
415+ if ( isCancelled ?.( ) ) {
416+ return createInterruptedTurnCompleted ( request . sessionId , "cancelled-before-turn" ) ;
417+ }
418+ onTurnStartRequested ?.( ) ;
393419 return await this . codexClient . runTurn ( {
394420 threadId : request . sessionId ,
395421 input : input ,
@@ -399,7 +425,7 @@ export class CodexAcpClient {
399425 effort : effort ,
400426 model : modelId . model ,
401427 serviceTier : serviceTier ,
402- } ) ;
428+ } , onTurnStarted , cancellation ) ;
403429 }
404430
405431 async listSkills ( params ?: SkillsListParams ) : Promise < SkillsListResponse > {
@@ -524,6 +550,10 @@ export class CodexAcpClient {
524550 } ) ;
525551 }
526552
553+ resolveInterruptedTurn ( params : { threadId : string , turnId : string } ) : void {
554+ this . codexClient . resolveTurnInterrupted ( params . threadId , params . turnId ) ;
555+ }
556+
527557 async fetchAvailableModels ( ) : Promise < Model [ ] > {
528558 const models : Model [ ] = [ ] ;
529559 let cursor : string | null = null ;
@@ -575,6 +605,21 @@ export type SessionMetadataWithThread = SessionMetadata & {
575605 thread : Thread ,
576606}
577607
608+ function createInterruptedTurnCompleted ( threadId : string , turnId : string ) : TurnCompletedNotification {
609+ return {
610+ threadId,
611+ turn : {
612+ id : turnId ,
613+ items : [ ] ,
614+ status : "interrupted" ,
615+ error : null ,
616+ startedAt : null ,
617+ completedAt : null ,
618+ durationMs : null ,
619+ } ,
620+ } ;
621+ }
622+
578623function buildPromptItems ( prompt : acp . ContentBlock [ ] ) : UserInput [ ] {
579624 return prompt . map ( ( block ) : UserInput | null => {
580625 switch ( block . type ) {
0 commit comments