Skip to content

Commit d8c2eb7

Browse files
committed
Start cleaning up IChatSessionsService
Trying to clean up this interface a little since it currently exposes a lot of methods
1 parent 6997605 commit d8c2eb7

File tree

9 files changed

+75
-62
lines changed

9 files changed

+75
-62
lines changed

src/vs/workbench/api/browser/mainThreadChatSessions.ts

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import { raceCancellationError } from '../../../base/common/async.js';
77
import { CancellationToken } from '../../../base/common/cancellation.js';
88
import { Emitter, Event } from '../../../base/common/event.js';
9-
import { Disposable, DisposableMap } from '../../../base/common/lifecycle.js';
9+
import { Disposable, DisposableMap, DisposableStore, IDisposable } from '../../../base/common/lifecycle.js';
1010
import { revive } from '../../../base/common/marshalling.js';
1111
import { URI, UriComponents } from '../../../base/common/uri.js';
1212
import { localize } from '../../../nls.js';
@@ -27,8 +27,11 @@ import { ExtHostChatSessionsShape, ExtHostContext, IChatProgressDto, MainContext
2727

2828
@extHostNamedCustomer(MainContext.MainThreadChatSessions)
2929
export class MainThreadChatSessions extends Disposable implements MainThreadChatSessionsShape {
30-
private readonly _itemProvidersRegistrations = this._register(new DisposableMap<number>());
31-
private readonly _contentProvidersRegisterations = this._register(new DisposableMap<number>());
30+
private readonly _itemProvidersRegistrations = this._register(new DisposableMap<number, IDisposable & {
31+
readonly provider: IChatSessionItemProvider;
32+
readonly onDidChangeItems: Emitter<void>;
33+
}>());
34+
private readonly _contentProvidersRegistrations = this._register(new DisposableMap<number>());
3235

3336
// Store progress emitters for active sessions: key is `${handle}_${sessionId}_${requestId}`
3437
private readonly _activeProgressEmitters = new Map<string, Emitter<IChatProgress[]>>();
@@ -56,17 +59,25 @@ export class MainThreadChatSessions extends Disposable implements MainThreadChat
5659

5760
$registerChatSessionItemProvider(handle: number, chatSessionType: string): void {
5861
// Register the provider handle - this tracks that a provider exists
62+
const disposables = new DisposableStore();
63+
const changeEmitter = disposables.add(new Emitter<void>());
64+
5965
const provider: IChatSessionItemProvider = {
6066
chatSessionType,
67+
onDidChangeChatSessionItems: changeEmitter.event,
6168
provideChatSessionItems: (token) => this._provideChatSessionItems(handle, token)
6269
};
70+
disposables.add(this._chatSessionsService.registerChatSessionItemProvider(provider));
6371

64-
this._itemProvidersRegistrations.set(handle, this._chatSessionsService.registerChatSessionItemProvider(provider));
72+
this._itemProvidersRegistrations.set(handle, {
73+
dispose: () => disposables.dispose(),
74+
provider,
75+
onDidChangeItems: changeEmitter,
76+
});
6577
}
6678

67-
$onDidChangeChatSessionItems(chatSessionType: string): void {
68-
// Notify the provider that its chat session items have changed
69-
this._chatSessionsService.notifySessionItemsChange(chatSessionType);
79+
$onDidChangeChatSessionItems(handle: number): void {
80+
this._itemProvidersRegistrations.get(handle)?.onDidChangeItems.fire();
7081
}
7182

7283
private async _provideChatSessionItems(handle: number, token: CancellationToken): Promise<IChatSessionItem[]> {
@@ -171,15 +182,14 @@ export class MainThreadChatSessions extends Disposable implements MainThreadChat
171182

172183
$registerChatSessionContentProvider(handle: number, chatSessionType: string): void {
173184
const provider: IChatSessionContentProvider = {
174-
chatSessionType,
175185
provideChatSessionContent: (id, token) => this._provideChatSessionContent(handle, id, token)
176186
};
177187

178-
this._contentProvidersRegisterations.set(handle, this._chatSessionsService.registerChatSessionContentProvider(provider));
188+
this._contentProvidersRegistrations.set(handle, this._chatSessionsService.registerChatSessionContentProvider(chatSessionType, provider));
179189
}
180190

181191
$unregisterChatSessionContentProvider(handle: number): void {
182-
this._contentProvidersRegisterations.deleteAndDispose(handle);
192+
this._contentProvidersRegistrations.deleteAndDispose(handle);
183193
}
184194

185195
async $handleProgressChunk(handle: number, sessionId: string, requestId: string, chunks: (IChatProgressDto | [IChatProgressDto, number])[]): Promise<void> {

src/vs/workbench/api/common/extHost.protocol.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3137,7 +3137,7 @@ export interface ChatSessionDto {
31373137
export interface MainThreadChatSessionsShape extends IDisposable {
31383138
$registerChatSessionItemProvider(handle: number, chatSessionType: string): void;
31393139
$unregisterChatSessionItemProvider(handle: number): void;
3140-
$onDidChangeChatSessionItems(chatSessionType: string): void;
3140+
$onDidChangeChatSessionItems(handle: number): void;
31413141

31423142
$registerChatSessionContentProvider(handle: number, chatSessionType: string): void;
31433143
$unregisterChatSessionContentProvider(handle: number): void;

src/vs/workbench/api/common/extHostChatSessions.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,22 @@ class ExtHostChatSession {
4646
}
4747

4848
export class ExtHostChatSessions extends Disposable implements ExtHostChatSessionsShape {
49+
private static _sessionHandlePool = 0;
4950

5051
private readonly _proxy: Proxied<MainThreadChatSessionsShape>;
51-
private readonly _chatSessionItemProviders = new Map<number, { provider: vscode.ChatSessionItemProvider; extension: IExtensionDescription; disposable: DisposableStore }>();
52-
private readonly _chatSessionContentProviders = new Map<number, { provider: vscode.ChatSessionContentProvider; extension: IExtensionDescription; disposable: DisposableStore }>();
52+
private readonly _chatSessionItemProviders = new Map<number, {
53+
readonly provider: vscode.ChatSessionItemProvider;
54+
readonly extension: IExtensionDescription;
55+
readonly disposable: DisposableStore;
56+
}>();
57+
private readonly _chatSessionContentProviders = new Map<number, {
58+
readonly provider: vscode.ChatSessionContentProvider;
59+
readonly extension: IExtensionDescription;
60+
readonly disposable: DisposableStore;
61+
}>();
5362
private _nextChatSessionItemProviderHandle = 0;
5463
private _nextChatSessionContentProviderHandle = 0;
55-
private _sessionMap: Map<string, vscode.ChatSessionItem> = new Map();
56-
private static _sessionHandlePool = 0;
64+
private readonly _sessionMap: Map<string, vscode.ChatSessionItem> = new Map();
5765

5866
constructor(
5967
private readonly commands: ExtHostCommands,
@@ -90,7 +98,7 @@ export class ExtHostChatSessions extends Disposable implements ExtHostChatSessio
9098
this._proxy.$registerChatSessionItemProvider(handle, chatSessionType);
9199
if (provider.onDidChangeChatSessionItems) {
92100
disposables.add(provider.onDidChangeChatSessionItems(() => {
93-
this._proxy.$onDidChangeChatSessionItems(chatSessionType);
101+
this._proxy.$onDidChangeChatSessionItems(handle);
94102
}));
95103
}
96104
return {

src/vs/workbench/contrib/chat/browser/actions/chatActions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,7 @@ export function registerChatActions() {
567567
// Use the new Promise-based API to get chat sessions
568568
const cancellationToken = new CancellationTokenSource();
569569
try {
570-
const providers = chatSessionsService.getChatSessionContributions();
570+
const providers = chatSessionsService.getAllChatSessionContributions();
571571
const providerNSessions: { providerType: string; session: IChatSessionItem }[] = [];
572572

573573
for (const provider of providers) {

src/vs/workbench/contrib/chat/browser/chatEditor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ export class ChatEditor extends EditorPane {
131131
const identifier = ChatSessionUri.parse(input.resource);
132132
if (identifier) {
133133
await this.chatSessionsService.canResolveContentProvider(input.resource.authority);
134-
const contributions = this.chatSessionsService.getChatSessionContributions();
134+
const contributions = this.chatSessionsService.getAllChatSessionContributions();
135135
const contribution = contributions.find(c => c.type === identifier.chatSessionType);
136136
if (contribution) {
137137
this.widget.lockToCodingAgent(contribution.name, contribution.displayName);

src/vs/workbench/contrib/chat/browser/chatSessions.contribution.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,8 @@ export class ChatSessionsService extends Disposable implements IChatSessionsServ
138138
this._evaluateAvailability();
139139
}));
140140
}
141-
public registerContribution(contribution: IChatSessionsExtensionPoint): IDisposable {
141+
142+
private registerContribution(contribution: IChatSessionsExtensionPoint): IDisposable {
142143
if (this._contributions.has(contribution.type)) {
143144
this._logService.warn(`Chat session contribution with id '${contribution.type}' is already registered.`);
144145
return { dispose: () => { } };
@@ -279,13 +280,13 @@ export class ChatSessionsService extends Disposable implements IChatSessionsServ
279280
return disposable;
280281
}
281282

282-
getChatSessionContributions(): IChatSessionsExtensionPoint[] {
283+
getAllChatSessionContributions(): IChatSessionsExtensionPoint[] {
283284
return Array.from(this._contributions.values()).filter(contribution =>
284285
this._isContributionAvailable(contribution)
285286
);
286287
}
287288

288-
getChatSessionItemProviders(): IChatSessionItemProvider[] {
289+
getAllChatSessionItemProviders(): IChatSessionItemProvider[] {
289290
return [...this._itemsProviders.values()].filter(provider => {
290291
// Check if the provider's corresponding contribution is available
291292
const contribution = this._contributions.get(provider.chatSessionType);
@@ -309,10 +310,6 @@ export class ChatSessionsService extends Disposable implements IChatSessionsServ
309310
return this._itemsProviders.has(chatViewType);
310311
}
311312

312-
public notifySessionItemsChange(chatSessionType: string): void {
313-
this._onDidChangeSessionItems.fire(chatSessionType);
314-
}
315-
316313
async canResolveContentProvider(chatViewType: string) {
317314
await this._extensionService.whenInstalledExtensionsRegistered();
318315
const contribution = this._contributions.get(chatViewType);
@@ -349,8 +346,15 @@ export class ChatSessionsService extends Disposable implements IChatSessionsServ
349346
this._itemsProviders.set(chatSessionType, provider);
350347
this._onDidChangeItemsProviders.fire(provider);
351348

349+
const disposables = new DisposableStore();
350+
disposables.add(provider.onDidChangeChatSessionItems(() => {
351+
this._onDidChangeSessionItems.fire(chatSessionType);
352+
}));
353+
352354
return {
353355
dispose: () => {
356+
disposables.dispose();
357+
354358
const provider = this._itemsProviders.get(chatSessionType);
355359
if (provider) {
356360
this._itemsProviders.delete(chatSessionType);
@@ -360,15 +364,15 @@ export class ChatSessionsService extends Disposable implements IChatSessionsServ
360364
};
361365
}
362366

363-
registerChatSessionContentProvider(provider: IChatSessionContentProvider): IDisposable {
364-
this._contentProviders.set(provider.chatSessionType, provider);
367+
registerChatSessionContentProvider(chatSessionType: string, provider: IChatSessionContentProvider): IDisposable {
368+
this._contentProviders.set(chatSessionType, provider);
365369
return {
366370
dispose: () => {
367-
this._contentProviders.delete(provider.chatSessionType);
371+
this._contentProviders.delete(chatSessionType);
368372

369373
// Remove all sessions that were created by this provider
370374
for (const [key, session] of this._sessions) {
371-
if (session.chatSessionType === provider.chatSessionType) {
375+
if (session.chatSessionType === chatSessionType) {
372376
session.dispose();
373377
this._sessions.delete(key);
374378
}
@@ -407,10 +411,6 @@ export class ChatSessionsService extends Disposable implements IChatSessionsServ
407411
const sessionKey = `${chatSessionType}_${id}`;
408412
this._sessions.delete(sessionKey);
409413
}
410-
411-
public get hasChatSessionItemProviders(): boolean {
412-
return this._itemsProviders.size > 0;
413-
}
414414
}
415415

416416
registerSingleton(IChatSessionsService, ChatSessionsService, InstantiationType.Delayed);

src/vs/workbench/contrib/chat/browser/chatSessions.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import { IViewsService } from '../../../services/views/common/viewsService.js';
5252
import { ThemeIcon } from '../../../../base/common/themables.js';
5353
import { IChatEditorOptions } from './chatEditor.js';
5454
import { ChatSessionUri } from '../common/chatUri.js';
55+
import { coalesce } from '../../../../base/common/arrays.js';
5556

5657
export const VIEWLET_ID = 'workbench.view.chat.sessions';
5758

@@ -122,6 +123,8 @@ class LocalChatSessionsProvider extends Disposable implements IChatSessionItemPr
122123
private readonly _onDidChange = this._register(new Emitter<void>());
123124
readonly onDidChange: Event<void> = this._onDidChange.event;
124125

126+
readonly onDidChangeChatSessionItems = Event.None;
127+
125128
// Track the current editor set to detect actual new additions
126129
private currentEditorSet = new Set<string>();
127130

@@ -391,17 +394,16 @@ class ChatSessionsViewPaneContainer extends ViewPaneContainer {
391394
return title;
392395
}
393396

394-
private getAllChatSessionProviders(): IChatSessionItemProvider[] {
395-
if (this.localProvider) {
396-
return [this.localProvider, ...this.chatSessionsService.getChatSessionItemProviders()];
397-
} else {
398-
return this.chatSessionsService.getChatSessionItemProviders();
399-
}
397+
private getAllChatSessionItemProviders(): IChatSessionItemProvider[] {
398+
return coalesce([
399+
this.localProvider,
400+
...this.chatSessionsService.getAllChatSessionItemProviders()
401+
]);
400402
}
401403

402404
private refreshProviderTree(chatSessionType: string): void {
403405
// Find the provider with the matching chatSessionType
404-
const providers = this.getAllChatSessionProviders();
406+
const providers = this.getAllChatSessionItemProviders();
405407
const targetProvider = providers.find(provider => provider.chatSessionType === chatSessionType);
406408

407409
if (targetProvider) {
@@ -416,9 +418,9 @@ class ChatSessionsViewPaneContainer extends ViewPaneContainer {
416418

417419
private async updateViewRegistration(): Promise<void> {
418420
// prepare all chat session providers
419-
const contributions = await this.chatSessionsService.getChatSessionContributions();
421+
const contributions = this.chatSessionsService.getAllChatSessionContributions();
420422
await Promise.all(contributions.map(contrib => this.chatSessionsService.canResolveItemProvider(contrib.type)));
421-
const currentProviders = this.getAllChatSessionProviders();
423+
const currentProviders = this.getAllChatSessionItemProviders();
422424
const currentProviderIds = new Set(currentProviders.map(p => p.chatSessionType));
423425

424426
// Find views that need to be unregistered (providers that are no longer available)
@@ -444,7 +446,7 @@ class ChatSessionsViewPaneContainer extends ViewPaneContainer {
444446

445447
private async registerViews(extensionPointContributions: IChatSessionsExtensionPoint[]) {
446448
const container = Registry.as<IViewContainersRegistry>(Extensions.ViewContainersRegistry).get(VIEWLET_ID);
447-
const providers = this.getAllChatSessionProviders();
449+
const providers = this.getAllChatSessionItemProviders();
448450

449451
if (container && providers.length > 0) {
450452
const viewDescriptorsToRegister: IViewDescriptor[] = [];
@@ -716,7 +718,7 @@ class SessionsViewPane extends ViewPane {
716718
}
717719

718720
private getProviderDisplayName(): string {
719-
const contributions = this.chatSessionsService.getChatSessionContributions();
721+
const contributions = this.chatSessionsService.getAllChatSessionContributions();
720722
const contribution = contributions.find(c => c.type === this.provider.chatSessionType);
721723
if (contribution) {
722724
return contribution.displayName;

src/vs/workbench/contrib/chat/common/chatModel.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,12 @@ import { IRange } from '../../../../editor/common/core/range.js';
2020
import { OffsetRange } from '../../../../editor/common/core/ranges/offsetRange.js';
2121
import { TextEdit } from '../../../../editor/common/languages.js';
2222
import { localize } from '../../../../nls.js';
23-
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
2423
import { ILogService } from '../../../../platform/log/common/log.js';
2524
import { CellUri, ICellEditOperation } from '../../notebook/common/notebookCommon.js';
2625
import { IChatAgentCommand, IChatAgentData, IChatAgentResult, IChatAgentService, reviveSerializedAgent } from './chatAgents.js';
2726
import { IChatEditingService, IChatEditingSession } from './chatEditingService.js';
2827
import { ChatRequestTextPart, IParsedChatRequest, reviveParsedChatRequest } from './chatParserTypes.js';
29-
import { ChatAgentVoteDirection, ChatAgentVoteDownReason, IChatAgentMarkdownContentWithVulnerability, IChatCodeCitation, IChatClearToPreviousToolInvocation, IChatCommandButton, IChatConfirmation, IChatContentInlineReference, IChatContentReference, IChatEditingSessionAction, IChatElicitationRequest, IChatExtensionsContent, IChatFollowup, IChatLocationData, IChatMarkdownContent, IChatMultiDiffData, IChatNotebookEdit, IChatPrepareToolInvocationPart, IChatProgress, IChatProgressMessage, IChatPullRequestContent, IChatResponseCodeblockUriPart, IChatResponseProgressFileTreeData, IChatTask, IChatTaskSerialized, IChatTextEdit, IChatThinkingPart, IChatToolInvocation, IChatToolInvocationSerialized, IChatTreeData, IChatUndoStop, IChatUsedContext, IChatWarningMessage, isIUsedContext, ChatResponseClearToPreviousToolInvocationReason } from './chatService.js';
28+
import { ChatAgentVoteDirection, ChatAgentVoteDownReason, ChatResponseClearToPreviousToolInvocationReason, IChatAgentMarkdownContentWithVulnerability, IChatClearToPreviousToolInvocation, IChatCodeCitation, IChatCommandButton, IChatConfirmation, IChatContentInlineReference, IChatContentReference, IChatEditingSessionAction, IChatElicitationRequest, IChatExtensionsContent, IChatFollowup, IChatLocationData, IChatMarkdownContent, IChatMultiDiffData, IChatNotebookEdit, IChatPrepareToolInvocationPart, IChatProgress, IChatProgressMessage, IChatPullRequestContent, IChatResponseCodeblockUriPart, IChatResponseProgressFileTreeData, IChatTask, IChatTaskSerialized, IChatTextEdit, IChatThinkingPart, IChatToolInvocation, IChatToolInvocationSerialized, IChatTreeData, IChatUndoStop, IChatUsedContext, IChatWarningMessage, isIUsedContext } from './chatService.js';
3029
import { IChatRequestVariableEntry } from './chatVariableEntries.js';
3130
import { ChatAgentLocation, ChatModeKind } from './constants.js';
3231

@@ -992,12 +991,6 @@ export interface IChatModel extends IDisposable {
992991
toJSON(): ISerializableChatData;
993992
}
994993

995-
export const IChatModelService = createDecorator<IChatModelService>('chatModelService');
996-
997-
export interface IChatModelService {
998-
readonly _serviceBrand: undefined;
999-
}
1000-
1001994
export interface ISerializableChatsData {
1002995
[sessionId: string]: ISerializableChatData;
1003996
}

src/vs/workbench/contrib/chat/common/chatSessionsService.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,29 +54,29 @@ export interface ChatSession extends IDisposable {
5454

5555
export interface IChatSessionItemProvider {
5656
readonly chatSessionType: string;
57+
readonly onDidChangeChatSessionItems: Event<void>;
5758
provideChatSessionItems(token: CancellationToken): Promise<IChatSessionItem[]>;
5859
}
5960

6061
export interface IChatSessionContentProvider {
61-
readonly chatSessionType: string;
62-
provideChatSessionContent(id: string, token: CancellationToken): Promise<ChatSession>;
62+
provideChatSessionContent(sessionId: string, token: CancellationToken): Promise<ChatSession>;
6363
}
6464

6565
export interface IChatSessionsService {
6666
readonly _serviceBrand: undefined;
67+
6768
readonly onDidChangeItemsProviders: Event<IChatSessionItemProvider>;
6869
readonly onDidChangeSessionItems: Event<string>;
6970
readonly onDidChangeAvailability: Event<void>;
70-
registerContribution(contribution: IChatSessionsExtensionPoint): IDisposable;
71-
getChatSessionContributions(): IChatSessionsExtensionPoint[];
72-
canResolveItemProvider(chatSessionType: string): Promise<boolean>;
73-
canResolveContentProvider(chatSessionType: string): Promise<boolean>;
74-
getChatSessionItemProviders(): IChatSessionItemProvider[];
71+
7572
registerChatSessionItemProvider(provider: IChatSessionItemProvider): IDisposable;
76-
registerChatSessionContentProvider(provider: IChatSessionContentProvider): IDisposable;
77-
hasChatSessionItemProviders: boolean;
73+
getAllChatSessionContributions(): IChatSessionsExtensionPoint[];
74+
canResolveItemProvider(chatSessionType: string): Promise<boolean>;
75+
getAllChatSessionItemProviders(): IChatSessionItemProvider[];
7876
provideChatSessionItems(chatSessionType: string, token: CancellationToken): Promise<IChatSessionItem[]>;
79-
notifySessionItemsChange(chatSessionType: string): void;
77+
78+
registerChatSessionContentProvider(chatSessionType: string, provider: IChatSessionContentProvider): IDisposable;
79+
canResolveContentProvider(chatSessionType: string): Promise<boolean>;
8080
provideChatSessionContent(chatSessionType: string, id: string, token: CancellationToken): Promise<ChatSession>;
8181
}
8282

0 commit comments

Comments
 (0)