Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/conversationStore/node/conversationStore.ts
13399 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { IChatSessionService } from '../../../platform/chat/common/chatSessionService';
7
import { createServiceIdentifier } from '../../../util/common/services';
8
import { TimeoutTimer } from '../../../util/vs/base/common/async';
9
import { Disposable, DisposableMap } from '../../../util/vs/base/common/lifecycle';
10
import { LRUCache } from '../../../util/vs/base/common/map';
11
import { Conversation } from '../../prompt/common/conversation';
12
13
export const IConversationStore = createServiceIdentifier<IConversationStore>('IConversationStore');
14
15
export interface IConversationStore {
16
readonly _serviceBrand: undefined;
17
18
addConversation(responseId: string, conversation: Conversation): void;
19
getConversation(responseId: string): Conversation | undefined;
20
lastConversation: Conversation | undefined;
21
}
22
23
const CLEANUP_TIMEOUT_MS = 10 * 60 * 1000; // 10 minutes
24
25
export class ConversationStore extends Disposable implements IConversationStore {
26
readonly _serviceBrand: undefined;
27
28
private readonly conversationMap: LRUCache<string, Conversation>;
29
private readonly pendingCleanups: DisposableMap<string, TimeoutTimer> = this._register(new DisposableMap());
30
31
constructor(
32
@IChatSessionService chatSessionService: IChatSessionService,
33
) {
34
super();
35
this.conversationMap = new LRUCache<string, Conversation>(1000);
36
this._register(chatSessionService.onDidDisposeChatSession(sessionId => {
37
this._scheduleSessionCleanup(sessionId);
38
}));
39
}
40
41
addConversation(responseId: string, conversation: Conversation): void {
42
this.conversationMap.set(responseId, conversation);
43
this.pendingCleanups.deleteAndDispose(conversation.sessionId);
44
}
45
46
getConversation(responseId: string): Conversation | undefined {
47
const conversation = this.conversationMap.get(responseId);
48
if (conversation) {
49
this.pendingCleanups.deleteAndDispose(conversation.sessionId);
50
}
51
return conversation;
52
}
53
54
get lastConversation(): Conversation | undefined {
55
const conversation = this.conversationMap.last;
56
if (conversation) {
57
this.pendingCleanups.deleteAndDispose(conversation.sessionId);
58
}
59
return conversation;
60
}
61
62
private _scheduleSessionCleanup(sessionId: string): void {
63
let timer = this.pendingCleanups.get(sessionId);
64
if (!timer) {
65
timer = new TimeoutTimer();
66
this.pendingCleanups.set(sessionId, timer);
67
}
68
timer.cancelAndSet(() => {
69
this._cleanupSession(sessionId);
70
}, CLEANUP_TIMEOUT_MS);
71
}
72
73
private _cleanupSession(sessionId: string): void {
74
this.pendingCleanups.deleteAndDispose(sessionId);
75
const keysToDelete: string[] = [];
76
this.conversationMap.forEach((conversation, responseId) => {
77
if (conversation.sessionId === sessionId) {
78
keysToDelete.push(responseId);
79
}
80
});
81
for (const key of keysToDelete) {
82
this.conversationMap.delete(key);
83
}
84
}
85
}
86
87