Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/chat/browser/chatSessions/chatSessionTracker.ts
3296 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 { Disposable } from '../../../../../base/common/lifecycle.js';
7
import { Emitter } from '../../../../../base/common/event.js';
8
import { GroupModelChangeKind } from '../../../../common/editor.js';
9
import { IEditorGroup, IEditorGroupsService } from '../../../../services/editor/common/editorGroupsService.js';
10
import { ChatEditorInput } from '../chatEditorInput.js';
11
import { EditorInput } from '../../../../common/editor/editorInput.js';
12
import { ChatSessionItemWithProvider, getChatSessionType, isChatSession } from './common.js';
13
import { ChatSessionStatus, IChatSessionItem, IChatSessionItemProvider } from '../../common/chatSessionsService.js';
14
import { ILocalChatSessionItem } from '../chatSessions.js';
15
import { IChatService } from '../../common/chatService.js';
16
import { Codicon } from '../../../../../base/common/codicons.js';
17
import { IChatModel } from '../../common/chatModel.js';
18
19
export class ChatSessionTracker extends Disposable {
20
private readonly _onDidChangeEditors = this._register(new Emitter<{ sessionType: string; kind: GroupModelChangeKind }>());
21
readonly onDidChangeEditors = this._onDidChangeEditors.event;
22
23
constructor(
24
@IEditorGroupsService private readonly editorGroupsService: IEditorGroupsService,
25
@IChatService private readonly chatService: IChatService
26
) {
27
super();
28
this.setupEditorTracking();
29
}
30
31
private setupEditorTracking(): void {
32
// Listen to all editor groups
33
this.editorGroupsService.groups.forEach(group => {
34
this.registerGroupListeners(group);
35
});
36
37
// Listen for new groups
38
this._register(this.editorGroupsService.onDidAddGroup(group => {
39
this.registerGroupListeners(group);
40
}));
41
}
42
43
private registerGroupListeners(group: IEditorGroup): void {
44
this._register(group.onDidModelChange(e => {
45
if (!isChatSession(e.editor)) {
46
return;
47
}
48
49
const editor = e.editor as ChatEditorInput;
50
const sessionType = getChatSessionType(editor);
51
52
// Emit targeted event for this session type
53
this._onDidChangeEditors.fire({ sessionType, kind: e.kind });
54
}));
55
}
56
57
public getLocalEditorsForSessionType(sessionType: string): ChatEditorInput[] {
58
const localEditors: ChatEditorInput[] = [];
59
60
this.editorGroupsService.groups.forEach(group => {
61
group.editors.forEach(editor => {
62
if (editor instanceof ChatEditorInput && getChatSessionType(editor) === sessionType) {
63
localEditors.push(editor);
64
}
65
});
66
});
67
68
return localEditors;
69
}
70
71
async getHybridSessionsForProvider(provider: IChatSessionItemProvider): Promise<IChatSessionItem[]> {
72
if (provider.chatSessionType === 'local') {
73
return []; // Local provider doesn't need hybrid sessions
74
}
75
76
const localEditors = this.getLocalEditorsForSessionType(provider.chatSessionType);
77
const hybridSessions: (ILocalChatSessionItem & ChatSessionItemWithProvider)[] = [];
78
79
localEditors.forEach((editor, index) => {
80
const group = this.findGroupForEditor(editor);
81
if (!group) {
82
return;
83
}
84
if (editor.options.ignoreInView) {
85
return;
86
}
87
88
let status: ChatSessionStatus | undefined;
89
let timestamp: number | undefined;
90
91
if (editor.sessionId) {
92
const model = this.chatService.getSession(editor.sessionId);
93
if (model) {
94
status = this.modelToStatus(model);
95
const requests = model.getRequests();
96
if (requests.length > 0) {
97
timestamp = requests[requests.length - 1].timestamp;
98
}
99
}
100
}
101
102
const hybridSession: ILocalChatSessionItem & ChatSessionItemWithProvider = {
103
id: `${provider.chatSessionType}-local-${index}`,
104
label: editor.getName(),
105
iconPath: Codicon.chatSparkle,
106
editor,
107
group,
108
sessionType: 'editor',
109
status,
110
provider,
111
timing: {
112
startTime: timestamp ?? Date.now()
113
}
114
};
115
116
hybridSessions.push(hybridSession);
117
});
118
119
return hybridSessions;
120
}
121
122
private findGroupForEditor(editor: EditorInput): IEditorGroup | undefined {
123
for (const group of this.editorGroupsService.groups) {
124
if (group.editors.includes(editor)) {
125
return group;
126
}
127
}
128
return undefined;
129
}
130
131
private modelToStatus(model: IChatModel): ChatSessionStatus | undefined {
132
if (model.requestInProgress) {
133
return ChatSessionStatus.InProgress;
134
}
135
const requests = model.getRequests();
136
if (requests.length > 0) {
137
const lastRequest = requests[requests.length - 1];
138
if (lastRequest?.response) {
139
if (lastRequest.response.isCanceled || lastRequest.response.result?.errorDetails) {
140
return ChatSessionStatus.Failed;
141
} else if (lastRequest.response.isComplete) {
142
return ChatSessionStatus.Completed;
143
} else {
144
return ChatSessionStatus.InProgress;
145
}
146
}
147
}
148
return undefined;
149
}
150
}
151
152