@@ -601,6 +601,7 @@ export class AcpStructuredSession implements StructuredSessionHandle {
601601 private currentAttention : ThreadAttention = "none" ;
602602 private spawnReady : Promise < void > = Promise . resolve ( ) ;
603603 private currentTurnId : string | undefined ;
604+ private stableSessionRef : SessionRef | undefined ;
604605 /**
605606 * True while a `connection.prompt()` call is in flight (between issue and
606607 * resolution). Used together with `pendingPromptInterrupt` to close the
@@ -635,6 +636,7 @@ export class AcpStructuredSession implements StructuredSessionHandle {
635636 * and let normal mapping resume once the load completes.
636637 */
637638 private isReplayingHistory = false ;
639+ private replayHistoryUntil = 0 ;
638640
639641 private constructor (
640642 child : ChildProcess ,
@@ -677,11 +679,12 @@ export class AcpStructuredSession implements StructuredSessionHandle {
677679 }
678680
679681 private emitCurrentState ( listener : StructuredSessionListener ) : void {
682+ const sessionRef = this . currentSessionRef ( ) ;
680683 listener . onUpdate ( {
681684 status : this . currentStatus ,
682685 attention : this . currentAttention ,
683686 ...( this . currentConfig ? { config : this . currentConfig } : { } ) ,
684- ...( this . sessionId ? { sessionRef : createKnownSessionRef ( this . sessionId ) } : { } ) ,
687+ ...( sessionRef ? { sessionRef } : { } ) ,
685688 ...( this . currentSlashCommands !== undefined
686689 ? { slashCommands : this . currentSlashCommands }
687690 : { } ) ,
@@ -693,15 +696,29 @@ export class AcpStructuredSession implements StructuredSessionHandle {
693696 return ;
694697 }
695698 this . currentSlashCommands = commands ;
699+ const sessionRef = this . currentSessionRef ( ) ;
696700 this . emitListenerUpdate ( {
697701 status : this . currentStatus ,
698702 attention : this . currentAttention ,
699703 ...( this . currentConfig ? { config : this . currentConfig } : { } ) ,
700- ...( this . sessionId ? { sessionRef : createKnownSessionRef ( this . sessionId ) } : { } ) ,
704+ ...( sessionRef ? { sessionRef } : { } ) ,
701705 slashCommands : commands ,
702706 } ) ;
703707 }
704708
709+ private currentSessionRef ( ) : SessionRef | undefined {
710+ if ( ! this . sessionId ) return undefined ;
711+ if ( this . stableSessionRef ?. providerSessionId !== this . sessionId ) {
712+ this . stableSessionRef = createKnownSessionRef ( this . sessionId ) ;
713+ }
714+ return this . stableSessionRef ;
715+ }
716+
717+ private adoptSessionRef ( sessionRef : SessionRef ) : void {
718+ this . sessionId = sessionRef . providerSessionId ;
719+ this . stableSessionRef = sessionRef ;
720+ }
721+
705722 private rememberSessionOptions ( availableModeIds : string [ ] , configOptions : unknown ) : void {
706723 this . availableModeIds = availableModeIds ;
707724 this . currentConfigOptions = Array . isArray ( configOptions ) ? configOptions : [ ] ;
@@ -976,17 +993,19 @@ export class AcpStructuredSession implements StructuredSessionHandle {
976993 if ( sessionRef ) {
977994 console . log ( "[acp] loading session:" , sessionRef . providerSessionId ) ;
978995 this . isReplayingHistory = true ;
996+ this . replayHistoryUntil = Infinity ;
979997 try {
980998 const result = await this . connection . loadSession ( {
981999 sessionId : sessionRef . providerSessionId ,
9821000 cwd : this . cwd ,
9831001 mcpServers : [ ] ,
9841002 } ) ;
985- this . sessionId = sessionRef . providerSessionId ;
1003+ this . adoptSessionRef ( sessionRef ) ;
9861004 availableModeIds = result . modes ?. availableModes ?. map ( ( m ) => m . id ) ?? [ ] ;
9871005 configOptions = result . configOptions ?? [ ] ;
9881006 } finally {
9891007 this . isReplayingHistory = false ;
1008+ this . replayHistoryUntil = Date . now ( ) + 500 ;
9901009 }
9911010 } else {
9921011 console . log ( "[acp] creating new session in" , this . cwd ) ;
@@ -995,6 +1014,7 @@ export class AcpStructuredSession implements StructuredSessionHandle {
9951014 mcpServers : [ ] ,
9961015 } ) ;
9971016 this . sessionId = result . sessionId ;
1017+ this . stableSessionRef = createKnownSessionRef ( result . sessionId ) ;
9981018 availableModeIds = result . modes ?. availableModes ?. map ( ( m ) => m . id ) ?? [ ] ;
9991019 configOptions = result . configOptions ?? [ ] ;
10001020 console . log ( "[acp] session created:" , this . sessionId , "modes:" , availableModeIds ) ;
@@ -1003,7 +1023,9 @@ export class AcpStructuredSession implements StructuredSessionHandle {
10031023 this . rememberSessionOptions ( availableModeIds , configOptions ) ;
10041024 await this . applyTurnConfig ( config ) ;
10051025
1006- this . launchOptions = { ...this . launchOptions , resumeThreadId : this . sessionId } ;
1026+ if ( this . sessionId ) {
1027+ this . launchOptions = { ...this . launchOptions , resumeThreadId : this . sessionId } ;
1028+ }
10071029 return this . sessionId ! ;
10081030 }
10091031
@@ -1306,7 +1328,7 @@ export class AcpStructuredSession implements StructuredSessionHandle {
13061328 // `session/update` notifications. Lightcode already has those messages
13071329 // in its own DB, so we skip canonical mapping for the replay window to
13081330 // avoid duplicating every message in the chat pane.
1309- if ( ! this . isReplayingHistory ) {
1331+ if ( ! this . isReplayingHistory && Date . now ( ) >= ( this . replayHistoryUntil || 0 ) ) {
13101332 const events = mapAcpSessionUpdate ( params , this . ensureMapperState ( ) ) ;
13111333 if ( events . length > 0 ) this . emitRuntimeEvents ( events ) ;
13121334 } else {
@@ -1358,14 +1380,15 @@ export class AcpStructuredSession implements StructuredSessionHandle {
13581380 const nextConfig = applyAcpModeUpdateToConfig ( this . currentConfig , update . currentModeId ) ;
13591381 if ( ! isThreadConfigEqual ( this . currentConfig , nextConfig ) ) {
13601382 this . currentConfig = nextConfig ;
1383+ const sessionRef = this . currentSessionRef ( ) ;
13611384 // Mode-change confirmations are metadata, not turn boundaries —
13621385 // preserve the live status so the renderer's working-time clock
13631386 // doesn't reset when the agent echoes back a setSessionMode call.
13641387 this . emitListenerUpdate ( {
13651388 status : this . currentStatus ,
13661389 attention : this . currentAttention ,
13671390 config : nextConfig ,
1368- ...( this . sessionId ? { sessionRef : createKnownSessionRef ( this . sessionId ) } : { } ) ,
1391+ ...( sessionRef ? { sessionRef } : { } ) ,
13691392 } ) ;
13701393 }
13711394 }
@@ -1381,11 +1404,12 @@ export class AcpStructuredSession implements StructuredSessionHandle {
13811404 ) {
13821405 const nextConfig = { ...this . currentConfig , effort : thoughtLevelConfig . currentValue } ;
13831406 this . currentConfig = nextConfig ;
1407+ const sessionRef = this . currentSessionRef ( ) ;
13841408 this . emitListenerUpdate ( {
13851409 status : this . currentStatus ,
13861410 attention : this . currentAttention ,
13871411 config : nextConfig ,
1388- ...( this . sessionId ? { sessionRef : createKnownSessionRef ( this . sessionId ) } : { } ) ,
1412+ ...( sessionRef ? { sessionRef } : { } ) ,
13891413 } ) ;
13901414 }
13911415 }
0 commit comments