@@ -43,6 +43,7 @@ import { IEnvironmentService } from '../../../../../platform/environment/common/
43
43
import { VSBuffer } from '../../../../../base/common/buffer.js' ;
44
44
import { IOffsetEdit , ISingleOffsetEdit , OffsetEdit } from '../../../../../editor/common/core/offsetEdit.js' ;
45
45
import { ILogService } from '../../../../../platform/log/common/log.js' ;
46
+ import { IChatService } from '../../common/chatService.js' ;
46
47
47
48
const STORAGE_CONTENTS_FOLDER = 'contents' ;
48
49
const STORAGE_STATE_FILE = 'state.json' ;
@@ -56,8 +57,6 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio
56
57
* Contains the contents of a file when the AI first began doing edits to it.
57
58
*/
58
59
private readonly _initialFileContents = new ResourceMap < string > ( ) ;
59
- private readonly _snapshots = new Map < string , IChatEditingSessionSnapshot > ( ) ;
60
-
61
60
private readonly _filesToSkipCreating = new ResourceSet ( ) ;
62
61
63
62
private readonly _entriesObs = observableValue < readonly ChatEditingModifiedFileEntry [ ] > ( this , [ ] ) ;
@@ -144,6 +143,7 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio
144
143
@IChatAgentService private readonly _chatAgentService : IChatAgentService ,
145
144
@IEnvironmentService private readonly _environmentService : IEnvironmentService ,
146
145
@ILogService private readonly _logService : ILogService ,
146
+ @IChatService private readonly _chatService : IChatService ,
147
147
) {
148
148
super ( ) ;
149
149
@@ -211,10 +211,13 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio
211
211
}
212
212
}
213
213
214
+ private _findSnapshot ( requestId : string ) : IChatEditingSessionSnapshot | undefined {
215
+ return this . _linearHistory . get ( ) . find ( s => s . requestId === requestId ) ;
216
+ }
217
+
214
218
public createSnapshot ( requestId : string | undefined ) : void {
215
219
const snapshot = this . _createSnapshot ( requestId ) ;
216
220
if ( requestId ) {
217
- this . _snapshots . set ( requestId , snapshot ) ;
218
221
for ( const workingSetItem of this . _workingSet . keys ( ) ) {
219
222
this . _workingSet . set ( workingSetItem , { state : WorkingSetEntryState . Sent } ) ;
220
223
}
@@ -248,7 +251,7 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio
248
251
}
249
252
250
253
public async getSnapshotModel ( requestId : string , snapshotUri : URI ) : Promise < ITextModel | null > {
251
- const entries = this . _snapshots . get ( requestId ) ?. entries ;
254
+ const entries = this . _findSnapshot ( requestId ) ?. entries ;
252
255
if ( ! entries ) {
253
256
return null ;
254
257
}
@@ -262,7 +265,7 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio
262
265
}
263
266
264
267
public getSnapshot ( requestId : string , uri : URI ) {
265
- const snapshot = this . _snapshots . get ( requestId ) ;
268
+ const snapshot = this . _findSnapshot ( requestId ) ;
266
269
const snapshotEntries = snapshot ?. entries ;
267
270
return snapshotEntries ?. get ( uri ) ;
268
271
}
@@ -273,7 +276,7 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio
273
276
private _pendingSnapshot : IChatEditingSessionSnapshot | undefined ;
274
277
public async restoreSnapshot ( requestId : string | undefined ) : Promise < void > {
275
278
if ( requestId !== undefined ) {
276
- const snapshot = this . _snapshots . get ( requestId ) ;
279
+ const snapshot = this . _findSnapshot ( requestId ) ;
277
280
if ( snapshot ) {
278
281
if ( ! this . _pendingSnapshot ) {
279
282
// Create and save a pending snapshot
@@ -301,10 +304,7 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio
301
304
for ( const entry of this . _entriesObs . get ( ) ) {
302
305
const snapshotEntry = snapshot . entries . get ( entry . modifiedURI ) ;
303
306
if ( ! snapshotEntry ) {
304
- const initialContents = this . _initialFileContents . get ( entry . modifiedURI ) ;
305
- if ( typeof initialContents === 'string' ) {
306
- entry . resetToInitialValue ( initialContents ) ;
307
- }
307
+ entry . resetToInitialValue ( ) ;
308
308
entry . dispose ( ) ;
309
309
}
310
310
}
@@ -313,8 +313,7 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio
313
313
// Restore all entries from the snapshot
314
314
for ( const snapshotEntry of snapshot . entries . values ( ) ) {
315
315
const entry = await this . _getOrCreateModifiedFileEntry ( snapshotEntry . resource , snapshotEntry . telemetryInfo ) ;
316
- entry . restoreFromSnapshot ( snapshotEntry ) ;
317
- entriesArr . push ( entry ) ;
316
+ entry . restoreFromSnapshot ( snapshotEntry ) ; entriesArr . push ( entry ) ;
318
317
}
319
318
320
319
this . _entriesObs . set ( entriesArr , undefined ) ;
@@ -412,12 +411,14 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio
412
411
413
412
async _performStop ( ) : Promise < void > {
414
413
// Close out all open files
415
- await Promise . allSettled ( this . _editorGroupsService . groups . map ( async ( g ) => {
416
- return Promise . allSettled ( g . editors . map ( async ( e ) => {
417
- if ( e instanceof MultiDiffEditorInput || e instanceof DiffEditorInput && ( e . original . resource ?. scheme === ChatEditingModifiedFileEntry . scheme || e . original . resource ?. scheme === ChatEditingTextModelContentProvider . scheme ) ) {
414
+ const schemes = [ ChatEditingModifiedFileEntry . scheme , ChatEditingTextModelContentProvider . scheme ] ;
415
+ await Promise . allSettled ( this . _editorGroupsService . groups . flatMap ( async ( g ) => {
416
+ return g . editors . map ( async ( e ) => {
417
+ if ( ( e instanceof MultiDiffEditorInput && e . initialResources ?. some ( r => r . originalUri && schemes . indexOf ( r . originalUri . scheme ) !== - 1 ) )
418
+ || ( e instanceof DiffEditorInput && e . original . resource && schemes . indexOf ( e . original . resource . scheme ) !== - 1 ) ) {
418
419
await g . closeEditor ( e ) ;
419
420
}
420
- } ) ) ;
421
+ } ) ;
421
422
} ) ) ;
422
423
423
424
// delete the persisted editing session state
@@ -501,6 +502,8 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio
501
502
const previousSnapshot = linearHistory [ linearHistoryIndex - 1 ] ;
502
503
await this . restoreSnapshot ( previousSnapshot . requestId ) ;
503
504
this . _linearHistoryIndex . set ( linearHistoryIndex - 1 , undefined ) ;
505
+ this . _updateRequestHiddenState ( ) ;
506
+
504
507
}
505
508
506
509
async redoInteraction ( ) : Promise < void > {
@@ -515,6 +518,12 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio
515
518
}
516
519
await this . restoreSnapshot ( nextSnapshot . requestId ) ;
517
520
this . _linearHistoryIndex . set ( linearHistoryIndex + 1 , undefined ) ;
521
+ this . _updateRequestHiddenState ( ) ;
522
+ }
523
+
524
+ private _updateRequestHiddenState ( ) {
525
+ const hiddenRequestIds = this . _linearHistory . get ( ) . slice ( this . _linearHistoryIndex . get ( ) ) . map ( s => s . requestId ) . filter ( ( r ) : r is string => ! ! r ) ;
526
+ this . _chatService . getSession ( this . chatSessionId ) ?. disableRequests ( hiddenRequestIds ) ;
518
527
}
519
528
520
529
private async _acceptStreamingEditsStart ( ) : Promise < void > {
@@ -578,12 +587,11 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio
578
587
}
579
588
return existingEntry ;
580
589
}
581
-
582
- const originalContent = this . _initialFileContents . get ( resource ) ;
590
+ const initialContent = this . _initialFileContents . get ( resource ) ;
583
591
// This gets manually disposed in .dispose() or in .restoreSnapshot()
584
- const entry = await this . _createModifiedFileEntry ( resource , responseModel , false , originalContent ) ;
585
- if ( ! originalContent ) {
586
- this . _initialFileContents . set ( resource , entry . modifiedModel . getValue ( ) ) ;
592
+ const entry = await this . _createModifiedFileEntry ( resource , responseModel , false , initialContent ) ;
593
+ if ( ! initialContent ) {
594
+ this . _initialFileContents . set ( resource , entry . initialContent ) ;
587
595
}
588
596
// If an entry is deleted e.g. reverting a created file,
589
597
// remove it from the entries and don't show it in the working set anymore
@@ -602,19 +610,19 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio
602
610
return entry ;
603
611
}
604
612
605
- private async _createModifiedFileEntry ( resource : URI , responseModel : IModifiedEntryTelemetryInfo , mustExist = false , originalContent : string | undefined ) : Promise < ChatEditingModifiedFileEntry > {
613
+ private async _createModifiedFileEntry ( resource : URI , responseModel : IModifiedEntryTelemetryInfo , mustExist = false , initialContent : string | undefined ) : Promise < ChatEditingModifiedFileEntry > {
606
614
try {
607
615
const ref = await this . _textModelService . createModelReference ( resource ) ;
608
616
609
- return this . _instantiationService . createInstance ( ChatEditingModifiedFileEntry , ref , { collapse : ( transaction : ITransaction | undefined ) => this . _collapse ( resource , transaction ) } , responseModel , mustExist ? ChatEditKind . Created : ChatEditKind . Modified , originalContent ) ;
617
+ return this . _instantiationService . createInstance ( ChatEditingModifiedFileEntry , ref , { collapse : ( transaction : ITransaction | undefined ) => this . _collapse ( resource , transaction ) } , responseModel , mustExist ? ChatEditKind . Created : ChatEditKind . Modified , initialContent ) ;
610
618
} catch ( err ) {
611
619
if ( mustExist ) {
612
620
throw err ;
613
621
}
614
622
// this file does not exist yet, create it and try again
615
623
await this . _bulkEditService . apply ( { edits : [ { newResource : resource } ] } ) ;
616
624
this . _editorService . openEditor ( { resource, options : { inactive : true , preserveFocus : true , pinned : true } } ) ;
617
- return this . _createModifiedFileEntry ( resource , responseModel , true , originalContent ) ;
625
+ return this . _createModifiedFileEntry ( resource , responseModel , true , initialContent ) ;
618
626
}
619
627
}
620
628
@@ -680,15 +688,9 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio
680
688
681
689
this . _filesToSkipCreating . clear ( ) ;
682
690
this . _initialFileContents . clear ( ) ;
683
- this . _snapshots . clear ( ) ;
684
691
this . _pendingSnapshot = undefined ;
685
692
686
693
const snapshotsFromHistory = await Promise . all ( data . linearHistory . map ( deserializeChatEditingSessionSnapshot ) ) ;
687
- for ( const snapshot of snapshotsFromHistory ) {
688
- if ( snapshot . requestId ) {
689
- this . _snapshots . set ( snapshot . requestId , snapshot ) ;
690
- }
691
- }
692
694
data . filesToSkipCreating . forEach ( ( uriStr : string ) => {
693
695
this . _filesToSkipCreating . add ( URI . parse ( uriStr ) ) ;
694
696
} ) ;
@@ -700,6 +702,7 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio
700
702
const pendingSnapshot = await deserializeChatEditingSessionSnapshot ( data . pendingSnapshot ) ;
701
703
this . _restoreSnapshot ( pendingSnapshot ) ;
702
704
this . _state . set ( ChatEditingSessionState . Idle , undefined ) ;
705
+ this . _updateRequestHiddenState ( ) ;
703
706
return true ;
704
707
} catch ( e ) {
705
708
this . _logService . error ( `Error restoring chat editing session from ${ storageLocation . toString ( ) } ` , e ) ;
0 commit comments