Make chat sessions give a delta of what has changed

For #300770
This commit is contained in:
Matt Bierner
2026-03-11 16:39:13 -07:00
parent fe7157a1f3
commit ee699b749f
14 changed files with 223 additions and 133 deletions
+10 -5
View File
@@ -22,7 +22,7 @@ import { URI } from '../../base/common/uri.js';
import { Disposable } from '../../base/common/lifecycle.js';
import { IWorkbenchContribution, registerWorkbenchContribution2, WorkbenchPhase } from '../../workbench/common/contributions.js';
import { IChatProgress } from '../../workbench/contrib/chat/common/chatService/chatService.js';
import { IChatSessionsService, IChatSessionItem, IChatSessionFileChange, ChatSessionStatus, IChatSessionHistoryItem } from '../../workbench/contrib/chat/common/chatSessionsService.js';
import { IChatSessionsService, IChatSessionItem, IChatSessionFileChange, ChatSessionStatus, IChatSessionHistoryItem, IChatSessionItemsDelta } from '../../workbench/contrib/chat/common/chatSessionsService.js';
import { IGitService, IGitExtensionDelegate, IGitRepository } from '../../workbench/contrib/git/common/gitService.js';
import { IFileService } from '../../platform/files/common/files.js';
import { InMemoryFileSystemProvider } from '../../platform/files/common/inMemoryFilesystemProvider.js';
@@ -228,7 +228,7 @@ class MockChatAgentContribution extends Disposable implements IWorkbenchContribu
static readonly ID = 'sessions.test.mockChatAgent';
private readonly _sessionItems: IChatSessionItem[] = [];
private readonly _itemsChangedEmitter = new Emitter<void>();
private readonly _itemsChangedEmitter = new Emitter<IChatSessionItemsDelta>();
private readonly _sessionHistory = new Map<string, IChatSessionHistoryItem[]>();
constructor(
@@ -273,6 +273,7 @@ class MockChatAgentContribution extends Disposable implements IWorkbenchContribu
// Add or update session in list
const existing = this._sessionItems.find(s => s.resource.toString() === key);
let addedOrUpdated: IChatSessionItem | undefined = existing;
if (existing) {
existing.timing.lastRequestStarted = now;
existing.timing.lastRequestEnded = now;
@@ -280,15 +281,19 @@ class MockChatAgentContribution extends Disposable implements IWorkbenchContribu
existing.changes = changes;
}
} else {
this._sessionItems.push({
addedOrUpdated = {
resource,
label: message.slice(0, 50) || 'Mock Session',
status: ChatSessionStatus.Completed,
timing: { created: now, lastRequestStarted: now, lastRequestEnded: now },
...(changes ? { changes } : {}),
});
};
this._sessionItems.push(addedOrUpdated);
}
if (addedOrUpdated) {
this._itemsChangedEmitter.fire({ addedOrUpdated: [addedOrUpdated] });
}
this._itemsChangedEmitter.fire();
}
private registerMockAgents(): void {
@@ -15,6 +15,7 @@ import { isEqual } from '../../../base/common/resources.js';
import { URI, UriComponents } from '../../../base/common/uri.js';
import { localize } from '../../../nls.js';
import { IDialogService } from '../../../platform/dialogs/common/dialogs.js';
import { IInstantiationService } from '../../../platform/instantiation/common/instantiation.js';
import { ILogService } from '../../../platform/log/common/log.js';
import { hasValidDiff, IAgentSession } from '../../contrib/chat/browser/agentSessions/agentSessionsModel.js';
import { IAgentSessionsService } from '../../contrib/chat/browser/agentSessions/agentSessionsService.js';
@@ -24,7 +25,7 @@ import { ChatEditorInput } from '../../contrib/chat/browser/widgetHosts/editor/c
import { IChatRequestVariableEntry } from '../../contrib/chat/common/attachments/chatVariableEntries.js';
import { awaitStatsForSession } from '../../contrib/chat/common/chat.js';
import { IChatContentInlineReference, IChatProgress, IChatService, ResponseModelState } from '../../contrib/chat/common/chatService/chatService.js';
import { ChatSessionStatus, IChatNewSessionRequest, IChatSession, IChatSessionContentProvider, IChatSessionHistoryItem, IChatSessionItem, IChatSessionItemController, IChatSessionProviderOptionItem, IChatSessionsService } from '../../contrib/chat/common/chatSessionsService.js';
import { ChatSessionStatus, IChatNewSessionRequest, IChatSession, IChatSessionContentProvider, IChatSessionHistoryItem, IChatSessionItem, IChatSessionItemController, IChatSessionItemsDelta, IChatSessionProviderOptionItem, IChatSessionsService } from '../../contrib/chat/common/chatSessionsService.js';
import { ChatAgentLocation } from '../../contrib/chat/common/constants.js';
import { IChatModel } from '../../contrib/chat/common/model/chatModel.js';
import { isUntitledChatSession } from '../../contrib/chat/common/model/chatUri.js';
@@ -329,16 +330,25 @@ class MainThreadChatSessionItemController extends Disposable implements IChatSes
private readonly _proxy: ExtHostChatSessionsShape;
private readonly _handle: number;
private readonly _onDidChangeChatSessionItems = this._register(new Emitter<void>());
private readonly _onDidChangeChatSessionItems = this._register(new Emitter<IChatSessionItemsDelta>());
public readonly onDidChangeChatSessionItems = this._onDidChangeChatSessionItems.event;
constructor(
proxy: ExtHostChatSessionsShape,
handle: number
chatSessionType: string,
handle: number,
@IChatService chatService: IChatService,
) {
super();
this._proxy = proxy;
this._handle = handle;
this._register(chatService.registerChatModelChangeListeners(chatSessionType, (sessionResource) => {
const item = this._items.get(sessionResource);
if (item) {
this._onDidChangeChatSessionItems.fire({ addedOrUpdated: [item] });
}
}));
}
private readonly _items = new ResourceMap<IChatSessionItem>();
@@ -361,7 +371,9 @@ class MainThreadChatSessionItemController extends Disposable implements IChatSes
changes: revive(dto.changes),
};
this._items.set(item.resource, item);
this._onDidChangeChatSessionItems.fire();
this._onDidChangeChatSessionItems.fire({
addedOrUpdated: [item],
});
return item;
}
@@ -373,17 +385,18 @@ class MainThreadChatSessionItemController extends Disposable implements IChatSes
for (const uri of change.removed) {
this._items.delete(uri);
}
this._onDidChangeChatSessionItems.fire();
this._onDidChangeChatSessionItems.fire({
addedOrUpdated: change.addedOrUpdated,
removed: change.removed,
});
}
addOrUpdateItem(item: IChatSessionItem): void {
warnOnUntitledSessionResource(item.resource);
this._items.set(item.resource, item);
this._onDidChangeChatSessionItems.fire();
}
fireOnDidChangeChatSessionItems(): void {
this._onDidChangeChatSessionItems.fire();
this._onDidChangeChatSessionItems.fire({
addedOrUpdated: [item],
});
}
}
@@ -413,6 +426,7 @@ export class MainThreadChatSessions extends Disposable implements MainThreadChat
@IEditorService private readonly _editorService: IEditorService,
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService,
@ILogService private readonly _logService: ILogService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
) {
super();
@@ -446,7 +460,7 @@ export class MainThreadChatSessions extends Disposable implements MainThreadChat
$registerChatSessionItemController(handle: number, chatSessionType: string): void {
const disposables = new DisposableStore();
const controller = disposables.add(new MainThreadChatSessionItemController(this._proxy, handle));
const controller = disposables.add(this._instantiationService.createInstance(MainThreadChatSessionItemController, this._proxy, chatSessionType, handle));
disposables.add(this._chatSessionsService.registerChatSessionItemController(chatSessionType, controller));
this._itemControllerRegistrations.set(handle, {
@@ -454,11 +468,6 @@ export class MainThreadChatSessions extends Disposable implements MainThreadChat
controller,
dispose: () => disposables.dispose(),
});
disposables.add(this._chatService.registerChatModelChangeListeners(
chatSessionType,
() => controller.fireOnDidChangeChatSessionItems()
));
}
private getController(handle: number): MainThreadChatSessionItemController {
@@ -469,11 +478,6 @@ export class MainThreadChatSessions extends Disposable implements MainThreadChat
return registration.controller;
}
$onDidChangeChatSessionItems(handle: number): void {
const controller = this.getController(handle);
controller.fireOnDidChangeChatSessionItems();
}
private async _resolveSessionItem(item: Dto<IChatSessionItem>): Promise<IChatSessionItem> {
const uri = URI.revive(item.resource);
const model = this._chatService.getSession(uri);
@@ -3587,7 +3587,6 @@ export interface MainThreadChatSessionsShape extends IDisposable {
$unregisterChatSessionItemController(controllerHandle: number): void;
$updateChatSessionItems(controllerHandle: number, change: IChatSessionItemsChange): Promise<void>;
$addOrUpdateChatSessionItem(controllerHandle: number, item: Dto<IChatSessionItem>): Promise<void>;
$onDidChangeChatSessionItems(controllerHandle: number): void;
$onDidCommitChatSessionItem(controllerHandle: number, original: UriComponents, modified: UriComponents): void;
$registerChatSessionContentProvider(handle: number, chatSessionScheme: string): void;
$unregisterChatSessionContentProvider(handle: number): void;
@@ -27,6 +27,7 @@ import { IChatEntitlementService } from '../../../../services/chat/common/chatEn
import { ILifecycleService } from '../../../../services/lifecycle/common/lifecycle.js';
import { Extensions, IOutputChannelRegistry, IOutputService } from '../../../../services/output/common/output.js';
import { ChatSessionStatus as AgentSessionStatus, IChatSessionFileChange, IChatSessionFileChange2, IChatSessionItem, IChatSessionsService, ResolvedChatSessionsExtensionPoint } from '../../common/chatSessionsService.js';
import { getChatSessionType } from '../../common/model/chatUri.js';
import { IChatWidgetService } from '../chat.js';
import { AgentSessionProviders, getAgentSessionProvider, getAgentSessionProviderIcon, getAgentSessionProviderName, isBuiltInAgentSessionProvider } from './agentSessions.js';
@@ -434,7 +435,19 @@ export class AgentSessionsModel extends Disposable implements IAgentSessionsMode
// Sessions updates
this._register(this.chatSessionsService.onDidChangeItemsProviders(({ chatSessionType }) => this.resolve(chatSessionType)));
this._register(this.chatSessionsService.onDidChangeAvailability(() => this.resolve(undefined)));
this._register(this.chatSessionsService.onDidChangeSessionItems(({ chatSessionType }) => this.updateItems([chatSessionType], CancellationToken.None)));
this._register(this.chatSessionsService.onDidChangeSessionItems((delta) => {
const changedChatSessionTypes = new Set<string>();
for (const resource of delta.addedOrUpdated ?? []) {
changedChatSessionTypes.add(getChatSessionType(resource.resource));
}
for (const resource of delta.removed ?? []) {
changedChatSessionTypes.add(getChatSessionType(resource));
}
this.updateItems(Array.from(changedChatSessionTypes), CancellationToken.None);
}));
this._register(this.workspaceContextService.onDidChangeWorkspaceFolders(() => this.resolve(undefined)));
this._register(this.workspaceTrustManagementService.onDidChangeTrust(() => this.resolve(undefined)));
@@ -10,12 +10,14 @@ import { Emitter } from '../../../../../base/common/event.js';
import { Disposable } from '../../../../../base/common/lifecycle.js';
import { ResourceSet } from '../../../../../base/common/map.js';
import { Schemas } from '../../../../../base/common/network.js';
import { IWorkbenchContribution } from '../../../../common/contributions.js';
import { IChatModel } from '../../common/model/chatModel.js';
import { convertLegacyChatSessionTiming, IChatDetail, IChatService, ResponseModelState } from '../../common/chatService/chatService.js';
import { ChatSessionStatus, IChatSessionItem, IChatSessionItemController, IChatSessionsService, localChatSessionType } from '../../common/chatSessionsService.js';
import { getChatSessionType } from '../../common/model/chatUri.js';
import { isEqual } from '../../../../../base/common/resources.js';
import { URI } from '../../../../../base/common/uri.js';
import { ILogService } from '../../../../../platform/log/common/log.js';
import { IWorkbenchContribution } from '../../../../common/contributions.js';
import { convertLegacyChatSessionTiming, IChatDetail, IChatService, ResponseModelState } from '../../common/chatService/chatService.js';
import { ChatSessionStatus, IChatSessionItem, IChatSessionItemController, IChatSessionItemsDelta, IChatSessionsService, localChatSessionType } from '../../common/chatSessionsService.js';
import { IChatModel } from '../../common/model/chatModel.js';
import { getChatSessionType } from '../../common/model/chatUri.js';
export class LocalAgentsSessionsController extends Disposable implements IChatSessionItemController, IWorkbenchContribution {
@@ -26,7 +28,7 @@ export class LocalAgentsSessionsController extends Disposable implements IChatSe
private readonly _onDidChange = this._register(new Emitter<void>());
readonly onDidChange = this._onDidChange.event;
readonly _onDidChangeChatSessionItems = this._register(new Emitter<void>());
readonly _onDidChangeChatSessionItems = this._register(new Emitter<IChatSessionItemsDelta>());
readonly onDidChangeChatSessionItems = this._onDidChangeChatSessionItems.event;
constructor(
@@ -51,20 +53,32 @@ export class LocalAgentsSessionsController extends Disposable implements IChatSe
}
private registerListeners(): void {
const refreshItems = async () => {
this._onDidChangeChatSessionItems.fire();
await this.refresh(CancellationToken.None);
this._onDidChangeChatSessionItems.fire();
};
this._register(this.chatService.registerChatModelChangeListeners(Schemas.vscodeLocalChatSession, async sessionResource => {
if (getChatSessionType(sessionResource) !== this.chatSessionType) {
return;
}
this._register(this.chatService.registerChatModelChangeListeners(Schemas.vscodeLocalChatSession, refreshItems));
let item = this.getItem(sessionResource);
if (!item) {
await this.refresh(CancellationToken.None);
item = this.getItem(sessionResource);
}
this._register(this.chatService.onDidDisposeSession(e => {
const session = e.sessionResource.filter(resource => getChatSessionType(resource) === this.chatSessionType);
if (session.length > 0) {
refreshItems();
if (item) {
this._onDidChangeChatSessionItems.fire({ addedOrUpdated: [item] });
}
}));
this._register(this.chatService.onDidDisposeSession(e => {
const removedSessionResources = e.sessionResource.filter(resource => getChatSessionType(resource) === this.chatSessionType);
if (removedSessionResources.length) {
this._onDidChangeChatSessionItems.fire({ removed: removedSessionResources });
}
}));
}
private getItem(sessionResource: URI): IChatSessionItem | undefined {
return this._items.find(item => isEqual(item.resource, sessionResource));
}
private async provideChatSessionItems(token: CancellationToken): Promise<IChatSessionItem[]> {
@@ -9,7 +9,7 @@ import { CancellationToken, CancellationTokenSource } from '../../../../../base/
import { Codicon } from '../../../../../base/common/codicons.js';
import { AsyncEmitter, Emitter, Event } from '../../../../../base/common/event.js';
import { combinedDisposable, Disposable, DisposableMap, DisposableStore, IDisposable } from '../../../../../base/common/lifecycle.js';
import { ResourceMap } from '../../../../../base/common/map.js';
import { ResourceMap, ResourceSet } from '../../../../../base/common/map.js';
import { Schemas } from '../../../../../base/common/network.js';
import * as resources from '../../../../../base/common/resources.js';
import { ThemeIcon } from '../../../../../base/common/themables.js';
@@ -31,7 +31,7 @@ import { ExtensionsRegistry } from '../../../../services/extensions/common/exten
import { ChatEditorInput } from '../widgetHosts/editor/chatEditorInput.js';
import { IChatAgentAttachmentCapabilities, IChatAgentData, IChatAgentService } from '../../common/participants/chatAgents.js';
import { ChatContextKeys } from '../../common/actions/chatContextKeys.js';
import { IChatNewSessionRequest, IChatSession, IChatSessionContentProvider, IChatSessionItem, IChatSessionItemController, IChatSessionOptionsWillNotifyExtensionEvent, IChatSessionProviderOptionGroup, IChatSessionProviderOptionItem, IChatSessionsExtensionPoint, IChatSessionsService, isSessionInProgressStatus, ResolvedChatSessionsExtensionPoint } from '../../common/chatSessionsService.js';
import { IChatNewSessionRequest, IChatSession, IChatSessionContentProvider, IChatSessionItem, IChatSessionItemController, IChatSessionItemsDelta, IChatSessionOptionsWillNotifyExtensionEvent, IChatSessionProviderOptionGroup, IChatSessionProviderOptionItem, IChatSessionsExtensionPoint, IChatSessionsService, isSessionInProgressStatus, ResolvedChatSessionsExtensionPoint } from '../../common/chatSessionsService.js';
import { ChatAgentLocation, ChatModeKind } from '../../common/constants.js';
import { CHAT_CATEGORY } from '../actions/chatActions.js';
import { IChatEditorOptions } from '../widgetHosts/editor/chatEditor.js';
@@ -47,7 +47,10 @@ import { ChatViewPane } from '../widgetHosts/viewPane/chatViewPane.js';
import { AgentSessionProviders, getAgentSessionProviderName } from '../agentSessions/agentSessions.js';
import { BugIndicatingError, isCancellationError } from '../../../../../base/common/errors.js';
import { IEditorGroupsService } from '../../../../services/editor/common/editorGroupsService.js';
import { isUntitledChatSession, LocalChatSessionUri } from '../../common/model/chatUri.js';
import {
getChatSessionType,
isUntitledChatSession, LocalChatSessionUri
} from '../../common/model/chatUri.js';
import { assertNever } from '../../../../../base/common/assert.js';
import { ICommandService } from '../../../../../platform/commands/common/commands.js';
import { Target } from '../../common/promptSyntax/promptTypes.js';
@@ -276,7 +279,7 @@ export class ChatSessionsService extends Disposable implements IChatSessionsServ
private readonly _onDidChangeItemsProviders = this._register(new Emitter<{ readonly chatSessionType: string }>());
readonly onDidChangeItemsProviders = this._onDidChangeItemsProviders.event;
private readonly _onDidChangeSessionItems = this._register(new Emitter<{ readonly chatSessionType: string }>());
private readonly _onDidChangeSessionItems = this._register(new Emitter<IChatSessionItemsDelta>());
readonly onDidChangeSessionItems = this._onDidChangeSessionItems.event;
private readonly _onDidChangeAvailability = this._register(new Emitter<void>());
@@ -350,10 +353,17 @@ export class ChatSessionsService extends Disposable implements IChatSessionsServ
}
}));
this._register(this.onDidChangeSessionItems(({ chatSessionType }) => {
this.updateInProgressStatus(chatSessionType).catch(error => {
this._logService.warn(`Failed to update progress status for '${chatSessionType}':`, error);
});
this._register(this.onDidChangeSessionItems((delta) => {
const changedChatSessionTypes = new Set<string>();
for (const resource of delta.addedOrUpdated ?? []) {
changedChatSessionTypes.add(getChatSessionType(resource.resource));
}
for (const chatSessionType of changedChatSessionTypes) {
this.updateInProgressStatus(chatSessionType).catch(error => {
this._logService.warn(`Failed to update progress status for '${chatSessionType}':`, error);
});
}
}));
this._register(this._labelService.registerFormatter({
@@ -597,7 +607,11 @@ export class ChatSessionsService extends Disposable implements IChatSessionsServ
}
private _evaluateAvailability(): void {
let hasChanges = false;
const newlyEnabledChatSessionTypes = new Set<string>();
const newlyDisabledChatSessionTypes = new Set<string>();
const disposedChatSessions = new ResourceSet();
for (const { contribution, extension } of this._contributions.values()) {
const isCurrentlyRegistered = this._contributionDisposables.has(contribution.type);
const shouldBeRegistered = this._isContributionAvailable(contribution);
@@ -607,21 +621,25 @@ export class ChatSessionsService extends Disposable implements IChatSessionsServ
this._contributionDisposables.deleteAndDispose(contribution.type);
// Also dispose any cached sessions for this contribution
this._disposeSessionsForContribution(contribution.type);
hasChanges = true;
for (const sessionResource of this._disposeSessionsForContribution(contribution.type)) {
disposedChatSessions.add(sessionResource);
}
newlyDisabledChatSessionTypes.add(contribution.type);
} else if (!isCurrentlyRegistered && shouldBeRegistered) {
// Enable the contribution by registering it
this._enableContribution(contribution, extension);
hasChanges = true;
newlyEnabledChatSessionTypes.add(contribution.type);
}
}
if (hasChanges) {
if (newlyEnabledChatSessionTypes.size > 0 || newlyDisabledChatSessionTypes.size > 0) {
this._onDidChangeAvailability.fire();
for (const chatSessionType of this._itemControllers.keys()) {
for (const chatSessionType of [...newlyEnabledChatSessionTypes, ...newlyDisabledChatSessionTypes]) {
this._onDidChangeItemsProviders.fire({ chatSessionType });
}
for (const { contribution } of this._contributions.values()) {
this._onDidChangeSessionItems.fire({ chatSessionType: contribution.type });
if (disposedChatSessions.size > 0) {
this._onDidChangeSessionItems.fire({ removed: Array.from(disposedChatSessions) });
}
}
this._updateHasCanDelegateProvidersContextKey();
@@ -638,7 +656,12 @@ export class ChatSessionsService extends Disposable implements IChatSessionsServ
disposableStore.add(this._registerMenuItems(contribution, ext));
}
private _disposeSessionsForContribution(contributionId: string): void {
/**
* Disposes of all sessions that belong to a contribution
*
* @returns List of session resources that were disposed.
*/
private _disposeSessionsForContribution(contributionId: string): URI[] {
// Find and dispose all sessions that belong to this contribution
const sessionsToDispose: URI[] = [];
for (const [sessionResource, sessionData] of this._sessions) {
@@ -657,6 +680,7 @@ export class ChatSessionsService extends Disposable implements IChatSessionsServ
sessionData.dispose(); // This will call _onWillDisposeSession and clean up
}
}
return sessionsToDispose;
}
private _registerAgent(contribution: IChatSessionsExtensionPoint, ext: IRelaxedExtensionDescription): IDisposable {
@@ -866,8 +890,8 @@ export class ChatSessionsService extends Disposable implements IChatSessionsServ
this._itemControllers.set(chatSessionType, { controller, initialRefresh: controller.refresh(initialRefreshCts.token) });
this._onDidChangeItemsProviders.fire({ chatSessionType });
disposables.add(controller.onDidChangeChatSessionItems(() => {
this._onDidChangeSessionItems.fire({ chatSessionType });
disposables.add(controller.onDidChangeChatSessionItems(e => {
this._onDidChangeSessionItems.fire(e);
}));
this.updateInProgressStatus(chatSessionType).catch(error => {
@@ -14,7 +14,7 @@ import { ICommandService } from '../../../../../platform/commands/common/command
import { ILogService } from '../../../../../platform/log/common/log.js';
import { IStorageService, StorageScope, StorageTarget } from '../../../../../platform/storage/common/storage.js';
import { ILifecycleService, LifecyclePhase } from '../../../../services/lifecycle/common/lifecycle.js';
import { ChatSessionStatus, IChatSessionItem, IChatSessionItemController, IChatSessionsService } from '../../common/chatSessionsService.js';
import { ChatSessionStatus, IChatSessionItem, IChatSessionItemController, IChatSessionItemsDelta, IChatSessionsService } from '../../common/chatSessionsService.js';
import { AgentSessionProviders } from '../agentSessions/agentSessions.js';
import { IAgentSession } from '../agentSessions/agentSessionsModel.js';
import { ISessionOpenerParticipant, ISessionOpenOptions, sessionOpenerRegistry } from '../agentSessions/agentSessionsOpener.js';
@@ -36,8 +36,8 @@ export class GrowthSessionController extends Disposable implements IChatSessionI
private static readonly SESSION_URI = URI.from({ scheme: AgentSessionProviders.Growth, path: '/growth-welcome' });
private readonly _onDidChangeChatSessionItems = this._register(new Emitter<void>());
readonly onDidChangeChatSessionItems: Event<void> = this._onDidChangeChatSessionItems.event;
private readonly _onDidChangeChatSessionItems = this._register(new Emitter<IChatSessionItemsDelta>());
readonly onDidChangeChatSessionItems = this._onDidChangeChatSessionItems.event;
private readonly _onDidDismiss = this._register(new Emitter<void>());
readonly onDidDismiss: Event<void> = this._onDidDismiss.event;
@@ -103,7 +103,9 @@ export class GrowthSessionController extends Disposable implements IChatSessionI
this.storageService.store(GrowthSessionController.STORAGE_KEY, true, StorageScope.APPLICATION, StorageTarget.USER);
// Fire change event first so that listeners (like the model) see empty items
this._onDidChangeChatSessionItems.fire();
this._onDidChangeChatSessionItems.fire({
removed: [GrowthSessionController.SESSION_URI],
});
// Then fire dismiss event which triggers unregistration of the controller.
this._onDidDismiss.fire();
}
@@ -1499,7 +1499,7 @@ export interface IChatService {
readonly onDidReceiveQuestionCarouselAnswer: Event<{ requestId: string; resolveId: string; answers: IChatQuestionAnswers | undefined }>;
notifyQuestionCarouselAnswer(requestId: string, resolveId: string, answers: IChatQuestionAnswers | undefined): void;
readonly onDidDisposeSession: Event<{ readonly sessionResource: URI[]; readonly reason: 'cleared' }>;
readonly onDidDisposeSession: Event<{ readonly sessionResource: readonly URI[]; readonly reason: 'cleared' }>;
transferChatSession(transferredSessionResource: URI, toWorkspace: URI): Promise<void>;
@@ -1510,7 +1510,7 @@ export interface IChatService {
/**
* @deprecated
*/
registerChatModelChangeListeners(chatSessionType: string, onChange: () => void): IDisposable;
registerChatModelChangeListeners(chatSessionType: string, onChange: (chatSessionResource: URI) => void): IDisposable;
/**
* For tests only!
@@ -1615,7 +1615,7 @@ export class ChatService extends Disposable implements IChatService {
return localSessionId;
}
public registerChatModelChangeListeners(chatSessionType: string, onChange: () => void): IDisposable {
public registerChatModelChangeListeners(chatSessionType: string, onChange: (chatSessionResource: URI) => void): IDisposable {
const disposableStore = new DisposableStore();
const chatModelsICareAbout = this.chatModels.map(models =>
Array.from(models).filter((model: IChatModel) => model.sessionResource.scheme === chatSessionType)
@@ -1638,7 +1638,7 @@ export class ChatService extends Disposable implements IChatService {
listeners.set(added.sessionResource, autorun(reader => {
requestChangeListener.read(reader)?.read(reader);
modelChangeListener.read(reader);
onChange();
onChange(added.sessionResource);
}));
});
}
@@ -198,9 +198,14 @@ export interface IChatNewSessionRequest {
readonly command?: string;
}
export interface IChatSessionItemsDelta {
readonly addedOrUpdated?: readonly IChatSessionItem[];
readonly removed?: readonly URI[];
}
export interface IChatSessionItemController {
readonly onDidChangeChatSessionItems: Event<void>;
readonly onDidChangeChatSessionItems: Event<IChatSessionItemsDelta>;
get items(): readonly IChatSessionItem[];
@@ -229,7 +234,7 @@ export interface IChatSessionsService {
// #region Chat session item provider support
readonly onDidChangeItemsProviders: Event<{ readonly chatSessionType: string }>;
readonly onDidChangeSessionItems: Event<{ readonly chatSessionType: string }>;
readonly onDidChangeSessionItems: Event<IChatSessionItemsDelta>;
readonly onDidChangeAvailability: Event<void>;
readonly onDidChangeInProgress: Event<void>;
@@ -77,7 +77,7 @@ suite('AgentSessions', () => {
test('should resolve sessions from controllers', async () => {
return runWithFakedTimers({}, async () => {
const chatSessionType = 'test-type';
const chatSessionType = chatSessionTestType;
const controller = new StaticChatSessionItemController([
makeSimpleSessionItem('session-1', {
label: 'Test Session 1'
@@ -93,9 +93,9 @@ suite('AgentSessions', () => {
await viewModel.resolve(undefined);
assert.strictEqual(viewModel.sessions.length, 2);
assert.strictEqual(viewModel.sessions[0].resource.toString(), 'test://session-1');
assert.strictEqual(viewModel.sessions[0].resource.toString(), `${chatSessionTestType}://session-1`);
assert.strictEqual(viewModel.sessions[0].label, 'Test Session 1');
assert.strictEqual(viewModel.sessions[1].resource.toString(), 'test://session-2');
assert.strictEqual(viewModel.sessions[1].resource.toString(), `${chatSessionTestType}://session-2`);
assert.strictEqual(viewModel.sessions[1].label, 'Test Session 2');
});
});
@@ -114,8 +114,8 @@ suite('AgentSessions', () => {
await viewModel.resolve(undefined);
assert.strictEqual(viewModel.sessions.length, 2);
assert.strictEqual(viewModel.sessions[0].resource.toString(), 'test://session-1');
assert.strictEqual(viewModel.sessions[1].resource.toString(), 'test://session-2');
assert.strictEqual(viewModel.sessions[0].resource.toString(), `${chatSessionTestType}://session-1`);
assert.strictEqual(viewModel.sessions[1].resource.toString(), `${chatSessionTestType}://session-2`);
});
});
@@ -123,7 +123,7 @@ suite('AgentSessions', () => {
return runWithFakedTimers({}, async () => {
const controller = new StaticChatSessionItemController([]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = createViewModel();
let willResolveFired = false;
@@ -150,7 +150,7 @@ suite('AgentSessions', () => {
return runWithFakedTimers({}, async () => {
const controller = new StaticChatSessionItemController([makeSimpleSessionItem('session-1')]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = createViewModel();
let sessionsChangedFired = false;
@@ -180,7 +180,7 @@ suite('AgentSessions', () => {
changes: { files: 1, insertions: 10, deletions: 5 }
}]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = createViewModel();
await viewModel.resolve(undefined);
@@ -241,7 +241,7 @@ suite('AgentSessions', () => {
test('should respond to onDidChangeItemsProviders event', async () => {
return runWithFakedTimers({}, async () => {
const chatSessionType = 'test-type';
const chatSessionType = chatSessionTestType;
const controller = new StaticChatSessionItemController([makeSimpleSessionItem('session-1')]);
mockChatSessionsService.registerChatSessionItemController(chatSessionType, controller);
@@ -263,7 +263,7 @@ suite('AgentSessions', () => {
return runWithFakedTimers({}, async () => {
const controller = new StaticChatSessionItemController([makeSimpleSessionItem('session-1')]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = createViewModel();
const sessionsChangedPromise = Event.toPromise(viewModel.onDidChangeSessions);
@@ -280,15 +280,16 @@ suite('AgentSessions', () => {
test('should respond to onDidChangeSessionItems event', async () => {
return runWithFakedTimers({}, async () => {
const controller = new StaticChatSessionItemController([makeSimpleSessionItem('session-1')]);
const testSession = makeSimpleSessionItem('session-1');
const controller = new StaticChatSessionItemController([testSession]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = createViewModel();
const sessionsChangedPromise = Event.toPromise(viewModel.onDidChangeSessions);
// Trigger event - this should automatically call resolve
mockChatSessionsService.fireDidChangeSessionItems('test-type');
mockChatSessionsService.fireDidChangeSessionItems({ addedOrUpdated: [testSession] });
// Wait for the sessions to be resolved
await sessionsChangedPromise;
@@ -301,13 +302,13 @@ suite('AgentSessions', () => {
return runWithFakedTimers({}, async () => {
const controller = new StaticChatSessionItemController([makeSimpleSessionItem('session-1')]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = createViewModel();
await viewModel.resolve(undefined);
assert.strictEqual(viewModel.sessions.length, 1);
assert.strictEqual(viewModel.sessions[0].providerType, 'test-type');
assert.strictEqual(viewModel.sessions[0].providerType, chatSessionTestType);
});
});
@@ -315,7 +316,7 @@ suite('AgentSessions', () => {
return runWithFakedTimers({}, async () => {
const controller = new StaticChatSessionItemController([]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = createViewModel();
await viewModel.resolve(undefined);
@@ -347,7 +348,7 @@ suite('AgentSessions', () => {
}
]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = createViewModel();
await viewModel.resolve(undefined);
@@ -375,7 +376,7 @@ suite('AgentSessions', () => {
get items() { return _items; }
};
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = createViewModel();
await viewModel.resolve(undefined);
@@ -415,7 +416,7 @@ suite('AgentSessions', () => {
timing: makeNewSessionTiming()
}]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = createViewModel();
await viewModel.resolve(undefined);
@@ -437,7 +438,7 @@ suite('AgentSessions', () => {
}
};
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
// Registering calls a refresh initially
assert.strictEqual(controllerCallCount, 1);
@@ -669,7 +670,7 @@ suite('AgentSessions', () => {
function createSession(overrides: Partial<IAgentSession> = {}): IAgentSession {
return {
providerType: 'test-type',
providerType: chatSessionTestType,
providerLabel: 'Test Provider',
icon: Codicon.chatSparkle,
resource: URI.parse('test://session'),
@@ -1214,7 +1215,7 @@ suite('AgentSessions', () => {
return runWithFakedTimers({}, async () => {
const controller = new StaticChatSessionItemController([makeSimpleSessionItem('session-1')]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = disposables.add(instantiationService.createInstance(AgentSessionsModel));
await viewModel.resolve(undefined);
@@ -1236,7 +1237,7 @@ suite('AgentSessions', () => {
return runWithFakedTimers({}, async () => {
const controller = new StaticChatSessionItemController([makeSimpleSessionItem('session-1')]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = disposables.add(instantiationService.createInstance(AgentSessionsModel));
await viewModel.resolve(undefined);
@@ -1256,7 +1257,7 @@ suite('AgentSessions', () => {
return runWithFakedTimers({}, async () => {
const controller = new StaticChatSessionItemController([makeSimpleSessionItem('session-1')]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = disposables.add(instantiationService.createInstance(AgentSessionsModel));
await viewModel.resolve(undefined);
@@ -1284,7 +1285,7 @@ suite('AgentSessions', () => {
timing: makeNewSessionTiming()
}]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = disposables.add(instantiationService.createInstance(AgentSessionsModel));
await viewModel.resolve(undefined);
@@ -1303,7 +1304,7 @@ suite('AgentSessions', () => {
timing: makeNewSessionTiming()
}]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = disposables.add(instantiationService.createInstance(AgentSessionsModel));
await viewModel.resolve(undefined);
@@ -1358,7 +1359,7 @@ suite('AgentSessions', () => {
timing: futureSessionTiming,
}]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = disposables.add(instantiationService.createInstance(AgentSessionsModel));
await viewModel.resolve(undefined);
@@ -1379,7 +1380,7 @@ suite('AgentSessions', () => {
return runWithFakedTimers({}, async () => {
const controller = new StaticChatSessionItemController([makeSimpleSessionItem('session-1')]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = disposables.add(instantiationService.createInstance(AgentSessionsModel));
await viewModel.resolve(undefined);
@@ -1401,7 +1402,7 @@ suite('AgentSessions', () => {
return runWithFakedTimers({}, async () => {
const controller = new StaticChatSessionItemController([makeSimpleSessionItem('session-1')]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = disposables.add(instantiationService.createInstance(AgentSessionsModel));
await viewModel.resolve(undefined);
@@ -1424,7 +1425,7 @@ suite('AgentSessions', () => {
return runWithFakedTimers({}, async () => {
const controller = new StaticChatSessionItemController([makeSimpleSessionItem('session-1')]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = disposables.add(instantiationService.createInstance(AgentSessionsModel));
await viewModel.resolve(undefined);
@@ -1455,7 +1456,7 @@ suite('AgentSessions', () => {
timing: oldSessionTiming,
}]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = disposables.add(instantiationService.createInstance(AgentSessionsModel));
await viewModel.resolve(undefined);
@@ -1480,7 +1481,7 @@ suite('AgentSessions', () => {
timing: newSessionTiming,
}]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = disposables.add(instantiationService.createInstance(AgentSessionsModel));
await viewModel.resolve(undefined);
@@ -1506,7 +1507,7 @@ suite('AgentSessions', () => {
timing: sessionTiming,
}]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = disposables.add(instantiationService.createInstance(AgentSessionsModel));
await viewModel.resolve(undefined);
@@ -1532,7 +1533,7 @@ suite('AgentSessions', () => {
timing: sessionTiming,
}]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = disposables.add(instantiationService.createInstance(AgentSessionsModel));
await viewModel.resolve(undefined);
@@ -1557,7 +1558,7 @@ suite('AgentSessions', () => {
timing: newSessionTiming,
}]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = disposables.add(instantiationService.createInstance(AgentSessionsModel));
await viewModel.resolve(undefined);
@@ -1590,7 +1591,7 @@ suite('AgentSessions', () => {
timing: newSessionTiming,
}]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = disposables.add(instantiationService.createInstance(AgentSessionsModel));
await viewModel.resolve(undefined);
@@ -1629,7 +1630,7 @@ suite('AgentSessions', () => {
timing: newSessionTiming,
}]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = disposables.add(instantiationService.createInstance(AgentSessionsModel));
await viewModel.resolve(undefined);
@@ -1659,7 +1660,7 @@ suite('AgentSessions', () => {
lastRequestEnded: Date.UTC(2025, 10 /* November */, 2),
};
const chatSessionType = 'test-type';
const chatSessionType = chatSessionTestType;
const controller = new StaticChatSessionItemController([{
resource: URI.parse('test://old-session'),
label: 'Old Session',
@@ -1727,7 +1728,7 @@ suite('AgentSessions', () => {
get items() { return _items; }
};
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = disposables.add(instantiationService.createInstance(AgentSessionsModel));
await viewModel.resolve(undefined);
@@ -1757,7 +1758,7 @@ suite('AgentSessions', () => {
get items() { return _items; }
};
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = disposables.add(instantiationService.createInstance(AgentSessionsModel));
await viewModel.resolve(undefined);
@@ -1967,7 +1968,7 @@ suite('AgentSessions', () => {
return runWithFakedTimers({}, async () => {
const controller = new StaticChatSessionItemController([makeSimpleSessionItem('session-1')]);
mockChatSessionsService.registerChatSessionItemController('test-type', controller);
mockChatSessionsService.registerChatSessionItemController(chatSessionTestType, controller);
viewModel = disposables.add(instantiationService.createInstance(AgentSessionsModel));
// Set willShutdown to true
@@ -2018,9 +2019,11 @@ suite('AgentSessions', () => {
}); // End of Agent Sessions suite
const chatSessionTestType = 'test-type';
function makeSimpleSessionItem(id: string, overrides?: Partial<IChatSessionItem>): IChatSessionItem {
return {
resource: URI.parse(`test://${id}`),
resource: URI.parse(`${chatSessionTestType}://${id}`),
label: `Session ${id}`,
timing: makeNewSessionTiming(),
...overrides
@@ -6,7 +6,7 @@
import assert from 'assert';
import { CancellationToken } from '../../../../../../base/common/cancellation.js';
import { Codicon } from '../../../../../../base/common/codicons.js';
import { Emitter } from '../../../../../../base/common/event.js';
import { Emitter, Event } from '../../../../../../base/common/event.js';
import { DisposableStore } from '../../../../../../base/common/lifecycle.js';
import { observableValue } from '../../../../../../base/common/observable.js';
import { URI } from '../../../../../../base/common/uri.js';
@@ -585,14 +585,25 @@ suite('LocalAgentsSessionsController', () => {
// Add the session first
mockChatService.addSession(mockModel);
mockChatService.setLiveSessionItems([{
sessionResource,
title: 'Test Session',
lastMessageDate: Date.now(),
isActive: true,
timing: createTestTiming(),
lastResponseState: ResponseModelState.Complete
}]);
let changeEventCount = 0;
disposables.add(controller.onDidChangeChatSessionItems(() => {
changeEventCount++;
}));
const onDidChangeChatSessionItems = Event.toPromise(controller.onDidChangeChatSessionItems);
// Simulate progress change by triggering the progress listener
mockChatService.triggerProgressEvent();
mockChatService.triggerProgressEvent(sessionResource);
await onDidChangeChatSessionItems;
assert.strictEqual(changeEventCount, 1);
});
@@ -611,15 +622,26 @@ suite('LocalAgentsSessionsController', () => {
// Add the session first
mockChatService.addSession(mockModel);
mockChatService.setLiveSessionItems([{
sessionResource,
title: 'Test Session',
lastMessageDate: Date.now(),
isActive: true,
timing: createTestTiming(),
lastResponseState: ResponseModelState.Complete
}]);
let changeEventCount = 0;
disposables.add(controller.onDidChangeChatSessionItems(() => {
changeEventCount++;
}));
// Simulate progress change by triggering the progress listener
mockChatService.triggerProgressEvent();
const onDidChangeChatSessionItems = Event.toPromise(controller.onDidChangeChatSessionItems);
// Simulate progress change by triggering the progress listener
mockChatService.triggerProgressEvent(sessionResource);
await onDidChangeChatSessionItems;
assert.strictEqual(changeEventCount, 1);
});
});
@@ -6,6 +6,7 @@
import { CancellationToken } from '../../../../../../base/common/cancellation.js';
import { Emitter, Event } from '../../../../../../base/common/event.js';
import { IDisposable } from '../../../../../../base/common/lifecycle.js';
import { ResourceMap } from '../../../../../../base/common/map.js';
import { ISettableObservable, observableValue } from '../../../../../../base/common/observable.js';
import { URI } from '../../../../../../base/common/uri.js';
import { ChatRequestQueueKind, ChatSendResult, IChatDetail, IChatModelReference, IChatProgress, IChatSendRequestOptions, IChatService, IChatSessionContext, IChatSessionStartOptions, IChatUserActionEvent } from '../../../common/chatService/chatService.js';
@@ -22,7 +23,7 @@ export class MockChatService implements IChatService {
readonly onDidSubmitRequest = Event.None;
readonly onDidCreateModel = Event.None;
private sessions = new Map<string, IChatModel>();
private readonly sessions = new ResourceMap<IChatModel>();
private liveSessionItems: IChatDetail[] = [];
private historySessionItems: IChatDetail[] = [];
@@ -50,13 +51,13 @@ export class MockChatService implements IChatService {
}
addSession(session: IChatModel): void {
this.sessions.set(session.sessionResource.toString(), session);
this.sessions.set(session.sessionResource, session);
// Update the chatModels observable
this._chatModels.set([...this.sessions.values()], undefined);
}
removeSession(sessionResource: URI): void {
this.sessions.delete(sessionResource.toString());
this.sessions.delete(sessionResource);
// Update the chatModels observable
this._chatModels.set([...this.sessions.values()], undefined);
}
@@ -78,7 +79,7 @@ export class MockChatService implements IChatService {
}
getSession(sessionResource: URI): IChatModel | undefined {
return this.sessions.get(sessionResource.toString());
return this.sessions.get(sessionResource);
}
getLatestRequest(): IChatRequestModel | undefined {
@@ -190,9 +191,9 @@ export class MockChatService implements IChatService {
}
private onChange?: () => void;
private onChange?: (sessionResource: URI) => void;
registerChatModelChangeListeners(chatSessionType: string, onChange: () => void): IDisposable {
registerChatModelChangeListeners(chatSessionType: string, onChange: (sessionResource: URI) => void): IDisposable {
// Store the emitter so tests can trigger it
this.onChange = onChange;
return {
@@ -203,9 +204,7 @@ export class MockChatService implements IChatService {
}
// Helper method for tests to trigger progress events
triggerProgressEvent(): void {
if (this.onChange) {
this.onChange();
}
triggerProgressEvent(sessionResource: URI): void {
this.onChange?.(sessionResource);
}
}
@@ -11,7 +11,7 @@ import { ThemeIcon } from '../../../../../base/common/themables.js';
import { URI } from '../../../../../base/common/uri.js';
import { IChatAgentAttachmentCapabilities } from '../../common/participants/chatAgents.js';
import { IChatModel } from '../../common/model/chatModel.js';
import { IChatNewSessionRequest, IChatSession, IChatSessionContentProvider, IChatSessionItemController, IChatSessionItem, IChatSessionOptionsWillNotifyExtensionEvent, IChatSessionProviderOptionGroup, IChatSessionProviderOptionItem, IChatSessionsExtensionPoint, IChatSessionsService, ResolvedChatSessionsExtensionPoint } from '../../common/chatSessionsService.js';
import { IChatNewSessionRequest, IChatSession, IChatSessionContentProvider, IChatSessionItemController, IChatSessionItem, IChatSessionOptionsWillNotifyExtensionEvent, IChatSessionProviderOptionGroup, IChatSessionProviderOptionItem, IChatSessionsExtensionPoint, IChatSessionsService, ResolvedChatSessionsExtensionPoint, IChatSessionItemsDelta } from '../../common/chatSessionsService.js';
import { Target } from '../../common/promptSyntax/promptTypes.js';
export class MockChatSessionsService implements IChatSessionsService {
@@ -22,7 +22,7 @@ export class MockChatSessionsService implements IChatSessionsService {
private readonly _onDidChangeItemsProviders = new Emitter<{ readonly chatSessionType: string }>();
readonly onDidChangeItemsProviders = this._onDidChangeItemsProviders.event;
private readonly _onDidChangeSessionItems = new Emitter<{ readonly chatSessionType: string }>();
private readonly _onDidChangeSessionItems = new Emitter<IChatSessionItemsDelta>();
readonly onDidChangeSessionItems = this._onDidChangeSessionItems.event;
private readonly _onDidChangeAvailability = new Emitter<void>();
@@ -52,8 +52,8 @@ export class MockChatSessionsService implements IChatSessionsService {
this._onDidChangeItemsProviders.fire(event);
}
fireDidChangeSessionItems(chatSessionType: string): void {
this._onDidChangeSessionItems.fire({ chatSessionType });
fireDidChangeSessionItems(event: IChatSessionItemsDelta): void {
this._onDidChangeSessionItems.fire(event);
}
fireDidChangeAvailability(): void {