@@ -48,6 +48,7 @@ import {
4848 type LegacySessionModelState ,
4949 type LegacySetSessionModelRequest ,
5050 type LegacySetSessionModelResponse ,
51+ GOAL_CONTROL_METHOD ,
5152 isExtMethodRequest ,
5253 LEGACY_SET_SESSION_MODEL_METHOD ,
5354} from "./AcpExtensions" ;
@@ -86,6 +87,8 @@ export interface ThreadGoalSnapshot {
8687 objective : string ;
8788 status : ThreadGoalStatus ;
8889 tokenBudget : number | null ;
90+ timeUsedSeconds : number ;
91+ controlMethod : typeof GOAL_CONTROL_METHOD ;
8992}
9093
9194export interface SessionState {
@@ -255,6 +258,18 @@ export class CodexAcpServer {
255258 }
256259 case LEGACY_SET_SESSION_MODEL_METHOD :
257260 return await this . unstable_setSessionModel ( this . parseLegacySetSessionModelParams ( methodRequest . params ) ) ;
261+ case GOAL_CONTROL_METHOD : {
262+ const sessionState = this . sessions . get ( methodRequest . params . sessionId ) ;
263+ if ( ! sessionState ) {
264+ throw RequestError . invalidParams ( undefined , `Unknown session: ${ methodRequest . params . sessionId } ` ) ;
265+ }
266+ if ( methodRequest . params . action === "pause" ) {
267+ await this . runWithProcessCheck ( ( ) => this . codexAcpClient . setGoalStatus ( sessionState . sessionId , "paused" ) ) ;
268+ } else {
269+ await this . runWithProcessCheck ( ( ) => this . codexAcpClient . clearGoal ( sessionState . sessionId ) ) ;
270+ }
271+ return { } ;
272+ }
258273 }
259274 }
260275
@@ -443,6 +458,9 @@ export class CodexAcpServer {
443458 }
444459
445460 this . publishAvailableCommandsAsync ( sessionState ) ;
461+ if ( "sessionId" in request ) {
462+ this . publishCurrentGoalAsync ( sessionState ) ;
463+ }
446464 const sessionModelState : LegacySessionModelState = this . createModelState ( models , currentModelId ) ;
447465 const sessionModeState : SessionModeState = sessionState . agentMode . toSessionModeState ( ) ;
448466
@@ -879,6 +897,33 @@ export class CodexAcpServer {
879897 void this . availableCommands . publish ( sessionState ) ;
880898 }
881899
900+ private publishCurrentGoalAsync ( sessionState : SessionState ) : void {
901+ void this . publishCurrentGoal ( sessionState ) . catch ( ( err ) => {
902+ logger . error ( `Failed to publish current goal for session ${ sessionState . sessionId } ` , err ) ;
903+ } ) ;
904+ }
905+
906+ private async publishCurrentGoal ( sessionState : SessionState ) : Promise < void > {
907+ const goal = await this . runWithProcessCheck ( ( ) => this . codexAcpClient . getGoal ( sessionState . sessionId ) ) ;
908+ const snapshot : ThreadGoalSnapshot | null = goal === null ? null : {
909+ objective : goal . objective . trim ( ) ,
910+ status : goal . status ,
911+ tokenBudget : goal . tokenBudget ,
912+ timeUsedSeconds : goal . timeUsedSeconds ,
913+ controlMethod : GOAL_CONTROL_METHOD ,
914+ } ;
915+ sessionState . currentGoal = snapshot ;
916+ const session = new ACPSessionConnection ( this . connection , sessionState . sessionId ) ;
917+ await session . update ( {
918+ sessionUpdate : "session_info_update" ,
919+ _meta : {
920+ codex : {
921+ goal : snapshot ,
922+ } ,
923+ } ,
924+ } ) ;
925+ }
926+
882927 private findCurrentModel ( models : Model [ ] , currentModelId : string ) : Model | undefined {
883928 const modelId = ModelId . fromString ( currentModelId ) ;
884929 return models . find ( m => m . id === modelId . model ) ;
@@ -992,6 +1037,7 @@ export class CodexAcpServer {
9921037 }
9931038
9941039 await this . availableCommands . publish ( sessionState ) ;
1040+ await this . publishCurrentGoal ( sessionState ) ;
9951041 const sessionModelState : LegacySessionModelState = this . createModelState ( models , currentModelId ) ;
9961042 const sessionModeState : SessionModeState = sessionState . agentMode . toSessionModeState ( ) ;
9971043
0 commit comments