77 type Implementation ,
88 type InitializeResponse as InitializeResult ,
99 type ListSessionsResponse as ListSessionsResult ,
10+ type LoadSessionResponse as LoadSessionResult ,
1011 type McpServer ,
1112 type NewSessionResponse as NewSessionResult ,
1213 type RequestPermissionRequest as PermissionRequest ,
@@ -15,6 +16,9 @@ import {
1516 type PromptResponse as PromptResult ,
1617 RequestError ,
1718 type RequestId ,
19+ type SessionConfigOption ,
20+ type SessionModelState ,
21+ type SessionModeState ,
1822 type SessionUpdate ,
1923} from "@agentclientprotocol/sdk" ;
2024import { ConnectionState } from "./models" ;
@@ -45,6 +49,7 @@ const ACP_METHODS = {
4549type ClientEventType =
4650 | "state_change"
4751 | "session_update"
52+ | "session_controls_update"
4853 | "error"
4954 | "permission_request" ;
5055
@@ -80,6 +85,9 @@ export class ACPClient {
8085 private _agentCapabilities : AgentCapabilities | null = null ;
8186 private _agentInfo : Implementation | null = null ;
8287 private _session : ACPSession | null = null ;
88+ private _sessionModes : SessionModeState | null = null ;
89+ private _sessionModels : SessionModelState | null = null ;
90+ private _sessionConfigOptions : SessionConfigOption [ ] = [ ] ;
8391
8492 get state ( ) : ConnectionState {
8593 return this . _state ;
@@ -97,6 +105,18 @@ export class ACPClient {
97105 return this . _session ;
98106 }
99107
108+ get sessionModes ( ) : SessionModeState | null {
109+ return this . _sessionModes ;
110+ }
111+
112+ get sessionModels ( ) : SessionModelState | null {
113+ return this . _sessionModels ;
114+ }
115+
116+ get sessionConfigOptions ( ) : SessionConfigOption [ ] {
117+ return this . _sessionConfigOptions ;
118+ }
119+
100120 get agentName ( ) : string {
101121 return this . _agentInfo ?. title || this . _agentInfo ?. name || "Agent" ;
102122 }
@@ -232,6 +252,7 @@ export class ACPClient {
232252 connection . newSession ( params as never ) ,
233253 ) ) as NewSessionResult ;
234254
255+ this . setSessionConfigurationState ( result ) ;
235256 this . _session ?. dispose ( ) ;
236257 this . _session = new ACPSession ( result . sessionId , cwd || "" ) ;
237258 return this . _session ;
@@ -255,18 +276,20 @@ export class ACPClient {
255276 this . _session = session ;
256277
257278 try {
258- await this . runWhileConnected (
279+ const result = ( await this . runWhileConnected (
259280 connection . loadSession ( {
260281 sessionId,
261282 cwd,
262283 mcpServers : mcpServers ?? [ ] ,
263284 } ) ,
264- ) ;
285+ ) ) as LoadSessionResult ;
286+ this . setSessionConfigurationState ( result ) ;
265287 return session ;
266288 } catch ( error ) {
267289 if ( this . _session === session ) {
268290 session . dispose ( ) ;
269291 this . _session = null ;
292+ this . clearSessionConfigurationState ( true ) ;
270293 }
271294 throw error ;
272295 }
@@ -338,6 +361,55 @@ export class ACPClient {
338361 return await this . prompt ( [ { type : "text" , text } ] ) ;
339362 }
340363
364+ async setSessionMode ( modeId : string ) : Promise < void > {
365+ this . ensureReady ( ) ;
366+ const sessionId = this . ensureSessionId ( ) ;
367+ const connection = this . getConnection ( ) ;
368+
369+ await this . runWhileConnected (
370+ connection . setSessionMode ( {
371+ sessionId,
372+ modeId,
373+ } ) ,
374+ ) ;
375+ this . updateSessionModeId ( modeId ) ;
376+ }
377+
378+ async setSessionModel ( modelId : string ) : Promise < void > {
379+ this . ensureReady ( ) ;
380+ const sessionId = this . ensureSessionId ( ) ;
381+ const connection = this . getConnection ( ) ;
382+
383+ await this . runWhileConnected (
384+ connection . unstable_setSessionModel ( {
385+ sessionId,
386+ modelId,
387+ } ) ,
388+ ) ;
389+ this . updateSessionModelId ( modelId ) ;
390+ }
391+
392+ async setSessionConfigOption ( configId : string , value : string ) : Promise < void > {
393+ this . ensureReady ( ) ;
394+ const sessionId = this . ensureSessionId ( ) ;
395+ const connection = this . getConnection ( ) ;
396+
397+ const result = await this . runWhileConnected (
398+ connection . setSessionConfigOption ( {
399+ sessionId,
400+ configId,
401+ value,
402+ } ) ,
403+ ) ;
404+
405+ if ( result . configOptions ) {
406+ this . setSessionConfigOptions ( result . configOptions ) ;
407+ return ;
408+ }
409+
410+ this . updateSessionConfigOptionValue ( configId , value ) ;
411+ }
412+
341413 cancel ( ) : void {
342414 if ( ! this . _session || ! this . connection ) return ;
343415
@@ -427,6 +499,7 @@ export class ACPClient {
427499 update : SessionUpdate ;
428500 } ) : Promise < void > {
429501 if ( this . _session && sessionId === this . _session . sessionId ) {
502+ this . handleSessionControlUpdate ( update ) ;
430503 this . _session . handleSessionUpdate ( update ) ;
431504 this . emit ( "session_update" , update ) ;
432505 }
@@ -510,11 +583,144 @@ export class ACPClient {
510583 }
511584 }
512585
586+ private setSessionConfigurationState ( {
587+ modes,
588+ models,
589+ configOptions,
590+ } : {
591+ modes ?: SessionModeState | null ;
592+ models ?: SessionModelState | null ;
593+ configOptions ?: SessionConfigOption [ ] | null ;
594+ } ) : void {
595+ this . _sessionModes = modes ?? null ;
596+ this . _sessionModels = models ?? null ;
597+ this . _sessionConfigOptions = this . normalizeConfigOptions ( configOptions ) ;
598+ this . emitSessionControlsUpdate ( ) ;
599+ }
600+
601+ private setSessionConfigOptions (
602+ configOptions : SessionConfigOption [ ] | null | undefined ,
603+ ) : void {
604+ this . _sessionConfigOptions = this . normalizeConfigOptions ( configOptions ) ;
605+ this . emitSessionControlsUpdate ( ) ;
606+ }
607+
608+ private updateSessionModeId ( modeId : string ) : void {
609+ if ( ! this . _sessionModes || this . _sessionModes . currentModeId === modeId )
610+ return ;
611+
612+ this . _sessionModes = {
613+ ...this . _sessionModes ,
614+ currentModeId : modeId ,
615+ } ;
616+ this . emitSessionControlsUpdate ( ) ;
617+ }
618+
619+ private updateSessionModelId ( modelId : string ) : void {
620+ if (
621+ ! this . _sessionModels ||
622+ this . _sessionModels . currentModelId === modelId
623+ ) {
624+ return ;
625+ }
626+
627+ this . _sessionModels = {
628+ ...this . _sessionModels ,
629+ currentModelId : modelId ,
630+ } ;
631+ this . emitSessionControlsUpdate ( ) ;
632+ }
633+
634+ private updateSessionConfigOptionValue (
635+ configId : string ,
636+ value : string ,
637+ ) : void {
638+ let didChange = false ;
639+ this . _sessionConfigOptions = this . _sessionConfigOptions . map ( ( option ) => {
640+ if ( option . id !== configId || option . currentValue === value ) {
641+ return option ;
642+ }
643+ didChange = true ;
644+ return {
645+ ...option ,
646+ currentValue : value ,
647+ } ;
648+ } ) ;
649+
650+ if ( didChange ) {
651+ this . emitSessionControlsUpdate ( ) ;
652+ }
653+ }
654+
655+ private handleSessionControlUpdate ( update : SessionUpdate ) : void {
656+ const updateKind = ( update as { sessionUpdate ?: string } ) . sessionUpdate ;
657+
658+ if ( updateKind === "current_mode_update" ) {
659+ const modeUpdate = update as {
660+ currentModeId ?: unknown ;
661+ modeId ?: unknown ;
662+ } ;
663+ const modeId =
664+ typeof modeUpdate . currentModeId === "string"
665+ ? modeUpdate . currentModeId
666+ : typeof modeUpdate . modeId === "string"
667+ ? modeUpdate . modeId
668+ : null ;
669+ if ( modeId ) {
670+ this . updateSessionModeId ( modeId ) ;
671+ }
672+ return ;
673+ }
674+
675+ if (
676+ updateKind === "config_option_update" ||
677+ updateKind === "config_options_update"
678+ ) {
679+ const configUpdate = update as { configOptions ?: unknown } ;
680+ if ( Array . isArray ( configUpdate . configOptions ) ) {
681+ this . setSessionConfigOptions (
682+ configUpdate . configOptions as SessionConfigOption [ ] ,
683+ ) ;
684+ }
685+ }
686+ }
687+
688+ private emitSessionControlsUpdate ( ) : void {
689+ this . emit ( "session_controls_update" , {
690+ modes : this . _sessionModes ,
691+ models : this . _sessionModels ,
692+ configOptions : this . _sessionConfigOptions ,
693+ } ) ;
694+ }
695+
696+ private normalizeConfigOptions (
697+ configOptions : SessionConfigOption [ ] | null | undefined ,
698+ ) : SessionConfigOption [ ] {
699+ return Array . isArray ( configOptions ) ? [ ...configOptions ] : [ ] ;
700+ }
701+
702+ private clearSessionConfigurationState ( emit = false ) : void {
703+ this . _sessionModes = null ;
704+ this . _sessionModels = null ;
705+ this . _sessionConfigOptions = [ ] ;
706+ if ( emit ) {
707+ this . emitSessionControlsUpdate ( ) ;
708+ }
709+ }
710+
711+ private ensureSessionId ( ) : string {
712+ if ( ! this . _session ) {
713+ throw new Error ( "No active session. Call newSession() first." ) ;
714+ }
715+ return this . _session . sessionId ;
716+ }
717+
513718 private disposeSessionState ( ) : void {
514719 this . _session ?. dispose ( ) ;
515720 this . _session = null ;
516721 this . _agentCapabilities = null ;
517722 this . _agentInfo = null ;
723+ this . clearSessionConfigurationState ( ) ;
518724 }
519725
520726 private handleTransportClosed ( reason ?: string ) : void {
0 commit comments