Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/chat/test/common/mockChatSessionsService.ts
5281 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 { CancellationToken } from '../../../../../base/common/cancellation.js';
7
import { AsyncEmitter, Emitter } from '../../../../../base/common/event.js';
8
import { IDisposable } from '../../../../../base/common/lifecycle.js';
9
import { ResourceMap } from '../../../../../base/common/map.js';
10
import { ThemeIcon } from '../../../../../base/common/themables.js';
11
import { URI } from '../../../../../base/common/uri.js';
12
import { IChatAgentAttachmentCapabilities } from '../../common/participants/chatAgents.js';
13
import { IChatModel } from '../../common/model/chatModel.js';
14
import { IChatService } from '../../common/chatService/chatService.js';
15
import { IChatSession, IChatSessionContentProvider, IChatSessionItemController, IChatSessionItem, IChatSessionOptionsWillNotifyExtensionEvent, IChatSessionProviderOptionGroup, IChatSessionProviderOptionItem, IChatSessionsExtensionPoint, IChatSessionsService } from '../../common/chatSessionsService.js';
16
import { Target } from '../../common/promptSyntax/service/promptsService.js';
17
18
export class MockChatSessionsService implements IChatSessionsService {
19
_serviceBrand: undefined;
20
21
private readonly _onDidChangeSessionOptions = new Emitter<URI>();
22
readonly onDidChangeSessionOptions = this._onDidChangeSessionOptions.event;
23
private readonly _onDidChangeItemsProviders = new Emitter<{ readonly chatSessionType: string }>();
24
readonly onDidChangeItemsProviders = this._onDidChangeItemsProviders.event;
25
26
private readonly _onDidChangeSessionItems = new Emitter<{ readonly chatSessionType: string }>();
27
readonly onDidChangeSessionItems = this._onDidChangeSessionItems.event;
28
29
private readonly _onDidChangeAvailability = new Emitter<void>();
30
readonly onDidChangeAvailability = this._onDidChangeAvailability.event;
31
32
private readonly _onDidChangeInProgress = new Emitter<void>();
33
readonly onDidChangeInProgress = this._onDidChangeInProgress.event;
34
35
private readonly _onDidChangeContentProviderSchemes = new Emitter<{ readonly added: string[]; readonly removed: string[] }>();
36
readonly onDidChangeContentProviderSchemes = this._onDidChangeContentProviderSchemes.event;
37
38
private readonly _onDidChangeOptionGroups = new Emitter<string>();
39
readonly onDidChangeOptionGroups = this._onDidChangeOptionGroups.event;
40
41
private readonly _onRequestNotifyExtension = new AsyncEmitter<IChatSessionOptionsWillNotifyExtensionEvent>();
42
readonly onRequestNotifyExtension = this._onRequestNotifyExtension.event;
43
44
private sessionItemControllers = new Map<string, { readonly controller: IChatSessionItemController; readonly initialRefresh: Promise<void> }>();
45
private contentProviders = new Map<string, IChatSessionContentProvider>();
46
private contributions: IChatSessionsExtensionPoint[] = [];
47
private optionGroups = new Map<string, IChatSessionProviderOptionGroup[]>();
48
private sessionOptions = new ResourceMap<Map<string, string>>();
49
private inProgress = new Map<string, number>();
50
private onChange = () => { };
51
52
// For testing: allow triggering events
53
fireDidChangeItemsProviders(event: { chatSessionType: string }): void {
54
this._onDidChangeItemsProviders.fire(event);
55
}
56
57
fireDidChangeSessionItems(chatSessionType: string): void {
58
this._onDidChangeSessionItems.fire({ chatSessionType });
59
}
60
61
fireDidChangeAvailability(): void {
62
this._onDidChangeAvailability.fire();
63
}
64
65
fireDidChangeInProgress(): void {
66
this._onDidChangeInProgress.fire();
67
}
68
69
registerChatSessionItemController(chatSessionType: string, controller: IChatSessionItemController): IDisposable {
70
this.sessionItemControllers.set(chatSessionType, { controller, initialRefresh: controller.refresh(CancellationToken.None) });
71
return {
72
dispose: () => {
73
this.sessionItemControllers.delete(chatSessionType);
74
}
75
};
76
}
77
78
getAllChatSessionContributions(): IChatSessionsExtensionPoint[] {
79
return this.contributions;
80
}
81
82
getChatSessionContribution(chatSessionType: string): IChatSessionsExtensionPoint | undefined {
83
return this.contributions.find(contrib => contrib.type === chatSessionType);
84
}
85
86
setContributions(contributions: IChatSessionsExtensionPoint[]): void {
87
this.contributions = contributions;
88
}
89
90
async activateChatSessionItemProvider(chatSessionType: string): Promise<void> {
91
// Noop, nothing to activate
92
}
93
94
getIconForSessionType(chatSessionType: string): ThemeIcon | URI | undefined {
95
const contribution = this.contributions.find(c => c.type === chatSessionType);
96
return contribution?.icon && typeof contribution.icon === 'string' ? ThemeIcon.fromId(contribution.icon) : undefined;
97
}
98
99
getWelcomeTitleForSessionType(chatSessionType: string): string | undefined {
100
return this.contributions.find(c => c.type === chatSessionType)?.welcomeTitle;
101
}
102
103
getWelcomeMessageForSessionType(chatSessionType: string): string | undefined {
104
return this.contributions.find(c => c.type === chatSessionType)?.welcomeMessage;
105
}
106
107
getInputPlaceholderForSessionType(chatSessionType: string): string | undefined {
108
return this.contributions.find(c => c.type === chatSessionType)?.inputPlaceholder;
109
}
110
111
getChatSessionItems(providerTypeFilter: readonly string[] | undefined, token: CancellationToken): Promise<Array<{ readonly chatSessionType: string; readonly items: readonly IChatSessionItem[] }>> {
112
return Promise.all(
113
Array.from(this.sessionItemControllers.entries())
114
.filter(([chatSessionType]) => !providerTypeFilter || providerTypeFilter.includes(chatSessionType))
115
.map(async ([chatSessionType, controllerEntry]) => {
116
await controllerEntry.initialRefresh; // ensure initial refresh is done
117
return ({
118
chatSessionType: chatSessionType,
119
items: controllerEntry.controller.items
120
});
121
}));
122
}
123
124
async refreshChatSessionItems(providerTypeFilter: readonly string[] | undefined, token: CancellationToken): Promise<void> {
125
await Promise.all(
126
Array.from(this.sessionItemControllers.entries())
127
.filter(([chatSessionType]) => !providerTypeFilter || providerTypeFilter.includes(chatSessionType))
128
.map(async ([_chatSessionType, controllerEntry]) => {
129
await controllerEntry.controller.refresh(token);
130
}));
131
}
132
133
reportInProgress(chatSessionType: string, count: number): void {
134
this.inProgress.set(chatSessionType, count);
135
this._onDidChangeInProgress.fire();
136
}
137
138
getInProgress(): { displayName: string; count: number }[] {
139
return Array.from(this.inProgress.entries()).map(([displayName, count]) => ({ displayName, count }));
140
}
141
142
registerChatSessionContentProvider(chatSessionType: string, provider: IChatSessionContentProvider): IDisposable {
143
this.contentProviders.set(chatSessionType, provider);
144
this._onDidChangeContentProviderSchemes.fire({ added: [chatSessionType], removed: [] });
145
return {
146
dispose: () => {
147
this.contentProviders.delete(chatSessionType);
148
}
149
};
150
}
151
152
async canResolveContentProvider(chatSessionType: string): Promise<boolean> {
153
return this.contentProviders.has(chatSessionType);
154
}
155
156
async getOrCreateChatSession(sessionResource: URI, token: CancellationToken): Promise<IChatSession> {
157
const provider = this.contentProviders.get(sessionResource.scheme);
158
if (!provider) {
159
throw new Error(`No content provider for ${sessionResource.scheme}`);
160
}
161
return provider.provideChatSessionContent(sessionResource, token);
162
}
163
164
async canResolveChatSession(chatSessionResource: URI): Promise<boolean> {
165
return this.contentProviders.has(chatSessionResource.scheme);
166
}
167
168
getOptionGroupsForSessionType(chatSessionType: string): IChatSessionProviderOptionGroup[] | undefined {
169
return this.optionGroups.get(chatSessionType);
170
}
171
172
setOptionGroupsForSessionType(chatSessionType: string, handle: number, optionGroups?: IChatSessionProviderOptionGroup[]): void {
173
if (optionGroups) {
174
this.optionGroups.set(chatSessionType, optionGroups);
175
} else {
176
this.optionGroups.delete(chatSessionType);
177
}
178
}
179
180
async notifySessionOptionsChange(sessionResource: URI, updates: ReadonlyArray<{ optionId: string; value: string | IChatSessionProviderOptionItem }>): Promise<void> {
181
await this._onRequestNotifyExtension.fireAsync({ sessionResource, updates }, CancellationToken.None);
182
}
183
184
getSessionOption(sessionResource: URI, optionId: string): string | undefined {
185
return this.sessionOptions.get(sessionResource)?.get(optionId);
186
}
187
188
setSessionOption(sessionResource: URI, optionId: string, value: string): boolean {
189
if (!this.sessionOptions.has(sessionResource)) {
190
this.sessionOptions.set(sessionResource, new Map());
191
}
192
this.sessionOptions.get(sessionResource)!.set(optionId, value);
193
return true;
194
}
195
196
hasAnySessionOptions(resource: URI): boolean {
197
return this.sessionOptions.has(resource) && this.sessionOptions.get(resource)!.size > 0;
198
}
199
200
getCapabilitiesForSessionType(chatSessionType: string): IChatAgentAttachmentCapabilities | undefined {
201
return this.contributions.find(c => c.type === chatSessionType)?.capabilities;
202
}
203
204
getCustomAgentTargetForSessionType(chatSessionType: string): Target {
205
return this.contributions.find(c => c.type === chatSessionType)?.customAgentTarget ?? Target.Undefined;
206
}
207
208
getContentProviderSchemes(): string[] {
209
return Array.from(this.contentProviders.keys());
210
}
211
212
getInProgressSessionDescription(chatModel: IChatModel): string | undefined {
213
return undefined;
214
}
215
216
registerChatModelChangeListeners(chatService: IChatService, chatSessionType: string, onChange: () => void): IDisposable {
217
// Store the emitter so tests can trigger it
218
this.onChange = onChange;
219
return {
220
dispose: () => {
221
}
222
};
223
}
224
225
// Helper method for tests to trigger progress events
226
triggerProgressEvent(): void {
227
if (this.onChange) {
228
this.onChange();
229
}
230
}
231
}
232
233