Path: blob/main/extensions/copilot/src/extension/conversationStore/node/conversationStore.ts
13399 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { IChatSessionService } from '../../../platform/chat/common/chatSessionService';6import { createServiceIdentifier } from '../../../util/common/services';7import { TimeoutTimer } from '../../../util/vs/base/common/async';8import { Disposable, DisposableMap } from '../../../util/vs/base/common/lifecycle';9import { LRUCache } from '../../../util/vs/base/common/map';10import { Conversation } from '../../prompt/common/conversation';1112export const IConversationStore = createServiceIdentifier<IConversationStore>('IConversationStore');1314export interface IConversationStore {15readonly _serviceBrand: undefined;1617addConversation(responseId: string, conversation: Conversation): void;18getConversation(responseId: string): Conversation | undefined;19lastConversation: Conversation | undefined;20}2122const CLEANUP_TIMEOUT_MS = 10 * 60 * 1000; // 10 minutes2324export class ConversationStore extends Disposable implements IConversationStore {25readonly _serviceBrand: undefined;2627private readonly conversationMap: LRUCache<string, Conversation>;28private readonly pendingCleanups: DisposableMap<string, TimeoutTimer> = this._register(new DisposableMap());2930constructor(31@IChatSessionService chatSessionService: IChatSessionService,32) {33super();34this.conversationMap = new LRUCache<string, Conversation>(1000);35this._register(chatSessionService.onDidDisposeChatSession(sessionId => {36this._scheduleSessionCleanup(sessionId);37}));38}3940addConversation(responseId: string, conversation: Conversation): void {41this.conversationMap.set(responseId, conversation);42this.pendingCleanups.deleteAndDispose(conversation.sessionId);43}4445getConversation(responseId: string): Conversation | undefined {46const conversation = this.conversationMap.get(responseId);47if (conversation) {48this.pendingCleanups.deleteAndDispose(conversation.sessionId);49}50return conversation;51}5253get lastConversation(): Conversation | undefined {54const conversation = this.conversationMap.last;55if (conversation) {56this.pendingCleanups.deleteAndDispose(conversation.sessionId);57}58return conversation;59}6061private _scheduleSessionCleanup(sessionId: string): void {62let timer = this.pendingCleanups.get(sessionId);63if (!timer) {64timer = new TimeoutTimer();65this.pendingCleanups.set(sessionId, timer);66}67timer.cancelAndSet(() => {68this._cleanupSession(sessionId);69}, CLEANUP_TIMEOUT_MS);70}7172private _cleanupSession(sessionId: string): void {73this.pendingCleanups.deleteAndDispose(sessionId);74const keysToDelete: string[] = [];75this.conversationMap.forEach((conversation, responseId) => {76if (conversation.sessionId === sessionId) {77keysToDelete.push(responseId);78}79});80for (const key of keysToDelete) {81this.conversationMap.delete(key);82}83}84}858687