From 4fbcb2b5de98af53d62927cf9b2e4b7ccade2d4a Mon Sep 17 00:00:00 2001 From: Matt Bierner <12821956+mjbvz@users.noreply.github.com> Date: Thu, 12 Feb 2026 00:12:54 -0800 Subject: [PATCH 1/2] Slight chat session controller optimization - Add should not retransmit all items - Skip updates if they don't do anything --- .../api/common/extHostChatSessions.ts | 40 ++++++++++++++----- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/api/common/extHostChatSessions.ts b/src/vs/workbench/api/common/extHostChatSessions.ts index cec3c62b015..1e184be05e2 100644 --- a/src/vs/workbench/api/common/extHostChatSessions.ts +++ b/src/vs/workbench/api/common/extHostChatSessions.ts @@ -176,12 +176,17 @@ class ChatSessionItemImpl implements vscode.ChatSessionItem { } } +interface SessionCollectionListeners { + onItemsChanged(): void; + onItemChanged(item: vscode.ChatSessionItem): void; +} + class ChatSessionItemCollectionImpl implements vscode.ChatSessionItemCollection { readonly #items = new ResourceMap(); - #onItemsChanged: () => void; + readonly #callbacks: SessionCollectionListeners; - constructor(onItemsChanged: () => void) { - this.#onItemsChanged = onItemsChanged; + constructor(callbacks: SessionCollectionListeners) { + this.#callbacks = callbacks; } get size(): number { @@ -197,7 +202,7 @@ class ChatSessionItemCollectionImpl implements vscode.ChatSessionItemCollection for (const item of items) { this.#items.set(item.resource, item); } - this.#onItemsChanged(); + this.#callbacks.onItemsChanged(); } forEach(callback: (item: vscode.ChatSessionItem, collection: vscode.ChatSessionItemCollection) => unknown, thisArg?: any): void { @@ -207,13 +212,20 @@ class ChatSessionItemCollectionImpl implements vscode.ChatSessionItemCollection } add(item: vscode.ChatSessionItem): void { + const existing = this.#items.get(item.resource); + if (existing && existing === item) { + // We're adding the same item again + return; + } + this.#items.set(item.resource, item); - this.#onItemsChanged(); + this.#callbacks.onItemChanged(item); } delete(resource: vscode.Uri): void { - this.#items.delete(resource); - this.#onItemsChanged(); + if (this.#items.delete(resource)) { + this.#callbacks.onItemsChanged(); + } } get(resource: vscode.Uri): vscode.ChatSessionItem | undefined { @@ -324,8 +336,10 @@ export class ExtHostChatSessions extends Disposable implements ExtHostChatSessio const onDidChangeChatSessionItemStateEmitter = disposables.add(new Emitter()); - const collection = new ChatSessionItemCollectionImpl(() => { + const collection = new ChatSessionItemCollectionImpl({ // Noop for providers + onItemsChanged: () => { }, + onItemChanged: () => { } }); // Helper to push items to main thread @@ -400,7 +414,11 @@ export class ExtHostChatSessions extends Disposable implements ExtHostChatSessio void this._proxy.$setChatSessionItems(controllerHandle, items); }; - const collection = new ChatSessionItemCollectionImpl(onItemsChanged); + const onItemChanged = (item: vscode.ChatSessionItem) => { + void this._proxy.$updateChatSessionItem(controllerHandle, typeConvert.ChatSessionItem.from(item)); + }; + + const collection = new ChatSessionItemCollectionImpl({ onItemsChanged, onItemChanged }); const controller = Object.freeze({ id, @@ -420,7 +438,9 @@ export class ExtHostChatSessions extends Disposable implements ExtHostChatSessio } const item = new ChatSessionItemImpl(resource, label, () => { - void this._proxy.$updateChatSessionItem(controllerHandle, typeConvert.ChatSessionItem.from(item)); + if (collection.get(resource) === item) { + onItemChanged(item); + } }); return item; }, From a413cd55102f18036bc5f8bbcd9fa3c3ef9e0c24 Mon Sep 17 00:00:00 2001 From: Matt Bierner <12821956+mjbvz@users.noreply.github.com> Date: Thu, 12 Feb 2026 00:38:39 -0800 Subject: [PATCH 2/2] Fix add vs update confusion --- .../api/browser/mainThreadChatSessions.ts | 44 ++++++++----------- .../workbench/api/common/extHost.protocol.ts | 2 +- .../api/common/extHostChatSessions.ts | 20 +++++---- 3 files changed, 31 insertions(+), 35 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadChatSessions.ts b/src/vs/workbench/api/browser/mainThreadChatSessions.ts index da9a664e813..47bff4e1d83 100644 --- a/src/vs/workbench/api/browser/mainThreadChatSessions.ts +++ b/src/vs/workbench/api/browser/mainThreadChatSessions.ts @@ -354,13 +354,9 @@ class MainThreadChatSessionItemController extends Disposable implements IChatSes this._onDidChangeChatSessionItems.fire(); } - updateItem(item: IChatSessionItem): void { - if (this._items.has(item.resource)) { - this._items.set(item.resource, item); - this._onDidChangeChatSessionItems.fire(); - } else { - console.warn(`Item with resource ${item.resource.toString()} does not exist. Skipping update.`); - } + addOrUpdateItem(item: IChatSessionItem): void { + this._items.set(item.resource, item); + this._onDidChangeChatSessionItems.fire(); } fireOnDidChangeChatSessionItems(): void { @@ -440,8 +436,17 @@ export class MainThreadChatSessions extends Disposable implements MainThreadChat )); } + private getController(handle: number): MainThreadChatSessionItemController { + const registration = this._itemControllerRegistrations.get(handle); + if (!registration) { + throw new Error(`No chat session controller registered for handle ${handle}`); + } + return registration.controller; + } + $onDidChangeChatSessionItems(handle: number): void { - this._itemControllerRegistrations.get(handle)?.controller.fireOnDidChangeChatSessionItems(); + const controller = this.getController(handle); + controller.fireOnDidChangeChatSessionItems(); } private async _resolveSessionItem(item: Dto): Promise { @@ -474,31 +479,20 @@ export class MainThreadChatSessions extends Disposable implements MainThreadChat }; } - async $setChatSessionItems(handle: number, items: Dto[]): Promise { - const registration = this._itemControllerRegistrations.get(handle); - if (!registration) { - this._logService.warn(`No chat session controller registered for handle ${handle}`); - return; - } - + async $setChatSessionItems(controllerHandle: number, items: Dto[]): Promise { + const controller = this.getController(controllerHandle); const resolvedItems = await Promise.all(items.map(item => this._resolveSessionItem(item))); - registration.controller.setItems(resolvedItems); + controller.setItems(resolvedItems); } - async $updateChatSessionItem(controllerHandle: number, item: Dto): Promise { - const registration = this._itemControllerRegistrations.get(controllerHandle); - if (!registration) { - this._logService.warn(`No chat session controller registered for handle ${controllerHandle}`); - return; - } - + async $addOrUpdateChatSessionItem(controllerHandle: number, item: Dto): Promise { + const controller = this.getController(controllerHandle); const resolvedItem = await this._resolveSessionItem(item); - registration.controller.updateItem(resolvedItem); + controller.addOrUpdateItem(resolvedItem); } $onDidChangeChatSessionOptions(handle: number, sessionResourceComponents: UriComponents, updates: ReadonlyArray<{ optionId: string; value: string }>): void { const sessionResource = URI.revive(sessionResourceComponents); - this._chatSessionsService.notifySessionOptionsChange(sessionResource, updates); } diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 422aa1b5827..d12f99c0051 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -3418,7 +3418,7 @@ export interface MainThreadChatSessionsShape extends IDisposable { $registerChatSessionItemController(handle: number, chatSessionType: string): void; $unregisterChatSessionItemController(handle: number): void; $setChatSessionItems(handle: number, items: Dto[]): Promise; - $updateChatSessionItem(handle: number, item: Dto): Promise; + $addOrUpdateChatSessionItem(handle: number, item: Dto): Promise; $onDidChangeChatSessionItems(handle: number): void; $onDidCommitChatSessionItem(handle: number, original: UriComponents, modified: UriComponents): void; $registerChatSessionContentProvider(handle: number, chatSessionScheme: string): void; diff --git a/src/vs/workbench/api/common/extHostChatSessions.ts b/src/vs/workbench/api/common/extHostChatSessions.ts index 1e184be05e2..8868ad66110 100644 --- a/src/vs/workbench/api/common/extHostChatSessions.ts +++ b/src/vs/workbench/api/common/extHostChatSessions.ts @@ -178,7 +178,7 @@ class ChatSessionItemImpl implements vscode.ChatSessionItem { interface SessionCollectionListeners { onItemsChanged(): void; - onItemChanged(item: vscode.ChatSessionItem): void; + onItemAddedOrUpdated(item: vscode.ChatSessionItem): void; } class ChatSessionItemCollectionImpl implements vscode.ChatSessionItemCollection { @@ -219,7 +219,7 @@ class ChatSessionItemCollectionImpl implements vscode.ChatSessionItemCollection } this.#items.set(item.resource, item); - this.#callbacks.onItemChanged(item); + this.#callbacks.onItemAddedOrUpdated(item); } delete(resource: vscode.Uri): void { @@ -339,7 +339,7 @@ export class ExtHostChatSessions extends Disposable implements ExtHostChatSessio const collection = new ChatSessionItemCollectionImpl({ // Noop for providers onItemsChanged: () => { }, - onItemChanged: () => { } + onItemAddedOrUpdated: () => { } }); // Helper to push items to main thread @@ -414,11 +414,12 @@ export class ExtHostChatSessions extends Disposable implements ExtHostChatSessio void this._proxy.$setChatSessionItems(controllerHandle, items); }; - const onItemChanged = (item: vscode.ChatSessionItem) => { - void this._proxy.$updateChatSessionItem(controllerHandle, typeConvert.ChatSessionItem.from(item)); - }; - - const collection = new ChatSessionItemCollectionImpl({ onItemsChanged, onItemChanged }); + const collection = new ChatSessionItemCollectionImpl({ + onItemsChanged, + onItemAddedOrUpdated: (item: vscode.ChatSessionItem) => { + void this._proxy.$addOrUpdateChatSessionItem(controllerHandle, typeConvert.ChatSessionItem.from(item)); + } + }); const controller = Object.freeze({ id, @@ -438,8 +439,9 @@ export class ExtHostChatSessions extends Disposable implements ExtHostChatSessio } const item = new ChatSessionItemImpl(resource, label, () => { + // Make sure the item really is in the collection. If not we don't need to transmit it to the main thread yet if (collection.get(resource) === item) { - onItemChanged(item); + void this._proxy.$addOrUpdateChatSessionItem(controllerHandle, typeConvert.ChatSessionItem.from(item)); } }); return item;