@@ -10,10 +10,10 @@ import { BugIndicatingError, ErrorNoTelemetry } from '../../../../base/common/er
1010import { Emitter , Event } from '../../../../base/common/event.js' ;
1111import { MarkdownString } from '../../../../base/common/htmlContent.js' ;
1212import { Iterable } from '../../../../base/common/iterator.js' ;
13- import { Disposable , DisposableMap , DisposableStore , IDisposable , IReference , MutableDisposable , ReferenceCollection } from '../../../../base/common/lifecycle.js' ;
13+ import { Disposable , DisposableMap , DisposableStore , IDisposable , MutableDisposable } from '../../../../base/common/lifecycle.js' ;
1414import { revive } from '../../../../base/common/marshalling.js' ;
1515import { Schemas } from '../../../../base/common/network.js' ;
16- import { autorun , derived , IObservable , ObservableMap } from '../../../../base/common/observable.js' ;
16+ import { autorun , derived , IObservable } from '../../../../base/common/observable.js' ;
1717import { StopWatch } from '../../../../base/common/stopwatch.js' ;
1818import { isDefined } from '../../../../base/common/types.js' ;
1919import { URI } from '../../../../base/common/uri.js' ;
@@ -29,8 +29,8 @@ import { IWorkspaceContextService } from '../../../../platform/workspace/common/
2929import { IExtensionService } from '../../../services/extensions/common/extensions.js' ;
3030import { IMcpService } from '../../mcp/common/mcpTypes.js' ;
3131import { IChatAgentCommand , IChatAgentData , IChatAgentHistoryEntry , IChatAgentRequest , IChatAgentResult , IChatAgentService } from './chatAgents.js' ;
32- import { IChatEditingSession } from './chatEditingService.js' ;
3332import { ChatModel , ChatRequestModel , ChatRequestRemovalReason , IChatModel , IChatRequestModel , IChatRequestVariableData , IChatResponseModel , IExportableChatData , ISerializableChatData , ISerializableChatDataIn , ISerializableChatsData , normalizeSerializableChatData , toChatHistoryContent , updateRanges } from './chatModel.js' ;
33+ import { ChatModelStore , IStartSessionProps } from './chatModelStore.js' ;
3434import { chatAgentLeader , ChatRequestAgentPart , ChatRequestAgentSubcommandPart , ChatRequestSlashCommandPart , ChatRequestTextPart , chatSubcommandLeader , getPromptText , IParsedChatRequest } from './chatParserTypes.js' ;
3535import { ChatRequestParser } from './chatRequestParser.js' ;
3636import { ChatMcpServersStarting , IChatCompleteResponse , IChatDetail , IChatFollowup , IChatModelReference , IChatProgress , IChatSendRequestData , IChatSendRequestOptions , IChatSendRequestResponseState , IChatService , IChatSessionContext , IChatTransferredSessionData , IChatUserActionEvent } from './chatService.js' ;
@@ -71,91 +71,7 @@ class CancellableRequest implements IDisposable {
7171 }
7272}
7373
74- interface IStartSessionProps {
75- readonly initialData ?: IExportableChatData | ISerializableChatData ;
76- readonly location : ChatAgentLocation ;
77- readonly token : CancellationToken ;
78- readonly sessionResource : URI ;
79- readonly sessionId ?: string ;
80- readonly canUseTools : boolean ;
81- readonly transferEditingSession ?: IChatEditingSession ;
82- }
83-
84- interface ChatModelStoreDelegate {
85- createModel : ( props : IStartSessionProps ) => ChatModel ;
86- willDisposeModel : ( model : ChatModel ) => Promise < void > ;
87- }
88-
89- class ChatModelStore extends ReferenceCollection < ChatModel > implements IDisposable {
90- private readonly _models = new ObservableMap < string , ChatModel > ( ) ;
91-
92- constructor (
93- private readonly delegate : ChatModelStoreDelegate ,
94- @ILogService private readonly logService : ILogService ,
95- ) {
96- super ( ) ;
97- }
98-
99- public get observable ( ) {
100- return this . _models . observable ;
101- }
102-
103- public values ( ) : Iterable < ChatModel > {
104- return this . _models . values ( ) ;
105- }
106-
107- public get ( uri : URI ) : ChatModel | undefined {
108- return this . _models . get ( this . toKey ( uri ) ) ;
109- }
110-
111- public has ( uri : URI ) : boolean {
112- return this . _models . has ( this . toKey ( uri ) ) ;
113- }
114-
115- public acquireExisting ( uri : URI ) : IReference < ChatModel > | undefined {
116- const key = this . toKey ( uri ) ;
117- if ( ! this . _models . has ( key ) ) {
118- return undefined ;
119- }
120- return this . acquire ( key ) ;
121- }
122-
123- public acquireOrCreate ( props : IStartSessionProps ) : IReference < ChatModel > {
124- return this . acquire ( this . toKey ( props . sessionResource ) , props ) ;
125- }
126-
127- protected createReferencedObject ( key : string , props ?: IStartSessionProps ) : ChatModel {
128- if ( ! props ) {
129- throw new Error ( `No start session props provided for chat session ${ key } ` ) ;
130- }
131-
132- this . logService . trace ( `Creating chat session ${ key } ` ) ;
133- const model = this . delegate . createModel ( props ) ;
134- if ( model . sessionResource . toString ( ) !== key ) {
135- throw new Error ( `Chat session key mismatch for ${ key } ` ) ;
136- }
137- this . _models . set ( key , model ) ;
138- return model ;
139- }
140-
141- protected async destroyReferencedObject ( key : string , object : ChatModel ) : Promise < void > {
142- try {
143- await this . delegate . willDisposeModel ( object ) ;
144- } finally {
145- this . logService . trace ( `Disposing chat session ${ key } ` ) ;
146- this . _models . delete ( key ) ;
147- object . dispose ( ) ;
148- }
149- }
15074
151- private toKey ( uri : URI ) : string {
152- return uri . toString ( ) ;
153- }
154-
155- dispose ( ) : void {
156- this . _models . forEach ( model => model . dispose ( ) ) ;
157- }
158- }
15975
16076class DisposableResourceMap < T extends IDisposable > extends Disposable {
16177
@@ -214,6 +130,13 @@ export class ChatService extends Disposable implements IChatService {
214130
215131 readonly requestInProgressObs : IObservable < boolean > ;
216132
133+ /**
134+ * For test use only
135+ */
136+ waitForModelDisposals ( ) : Promise < void > {
137+ return this . _sessionModels . waitForModelDisposals ( ) ;
138+ }
139+
217140 public get edits2Enabled ( ) : boolean {
218141 return this . configurationService . getValue ( ChatConfiguration . Edits2Enabled ) ;
219142 }
@@ -239,17 +162,15 @@ export class ChatService extends Disposable implements IChatService {
239162 super ( ) ;
240163
241164 this . _sessionModels = this . _register ( instantiationService . createInstance ( ChatModelStore , {
242- createModel : props => this . _startSession ( props ) ,
243- willDisposeModel : async model => {
244- if ( this . _persistChats ) {
245- const localSessionId = LocalChatSessionUri . parseLocalSessionId ( model . sessionResource ) ;
246- if ( localSessionId && ( model . initialLocation === ChatAgentLocation . Chat ) ) {
247- // Always preserve sessions that have custom titles, even if empty
248- if ( model . getRequests ( ) . length === 0 && ! model . customTitle ) {
249- this . _chatSessionStore . deleteSession ( localSessionId ) ;
250- } else {
251- this . _chatSessionStore . storeSessions ( [ model ] ) ;
252- }
165+ createModel : ( props : IStartSessionProps ) => this . _startSession ( props ) ,
166+ willDisposeModel : async ( model : ChatModel ) => {
167+ const localSessionId = LocalChatSessionUri . parseLocalSessionId ( model . sessionResource ) ;
168+ if ( localSessionId && ( model . initialLocation === ChatAgentLocation . Chat ) ) {
169+ // Always preserve sessions that have custom titles, even if empty
170+ if ( model . getRequests ( ) . length === 0 && ! model . customTitle ) {
171+ await this . _chatSessionStore . deleteSession ( localSessionId ) ;
172+ } else {
173+ await this . _chatSessionStore . storeSessions ( [ model ] ) ;
253174 }
254175 }
255176 }
@@ -295,14 +216,6 @@ export class ChatService extends Disposable implements IChatService {
295216 } ) ;
296217 }
297218
298- private _persistChats = true ;
299- /**
300- * For test only
301- */
302- setChatPersistanceEnabled ( enabled : boolean ) : void {
303- this . _persistChats = enabled ;
304- }
305-
306219 public get editingSessions ( ) {
307220 return [ ...this . _sessionModels . values ( ) ] . map ( v => v . editingSession ) . filter ( isDefined ) ;
308221 }
@@ -312,10 +225,6 @@ export class ChatService extends Disposable implements IChatService {
312225 }
313226
314227 private saveState ( ) : void {
315- if ( ! this . _persistChats ) {
316- return ;
317- }
318-
319228 const liveChats = Array . from ( this . _sessionModels . values ( ) )
320229 . filter ( session => {
321230 if ( ! LocalChatSessionUri . parseLocalSessionId ( session . sessionResource ) ) {
0 commit comments