Path: blob/main/src/vs/workbench/contrib/chat/test/common/mockChatSessionsService.ts
5281 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { CancellationToken } from '../../../../../base/common/cancellation.js';6import { AsyncEmitter, Emitter } from '../../../../../base/common/event.js';7import { IDisposable } from '../../../../../base/common/lifecycle.js';8import { ResourceMap } from '../../../../../base/common/map.js';9import { ThemeIcon } from '../../../../../base/common/themables.js';10import { URI } from '../../../../../base/common/uri.js';11import { IChatAgentAttachmentCapabilities } from '../../common/participants/chatAgents.js';12import { IChatModel } from '../../common/model/chatModel.js';13import { IChatService } from '../../common/chatService/chatService.js';14import { IChatSession, IChatSessionContentProvider, IChatSessionItemController, IChatSessionItem, IChatSessionOptionsWillNotifyExtensionEvent, IChatSessionProviderOptionGroup, IChatSessionProviderOptionItem, IChatSessionsExtensionPoint, IChatSessionsService } from '../../common/chatSessionsService.js';15import { Target } from '../../common/promptSyntax/service/promptsService.js';1617export class MockChatSessionsService implements IChatSessionsService {18_serviceBrand: undefined;1920private readonly _onDidChangeSessionOptions = new Emitter<URI>();21readonly onDidChangeSessionOptions = this._onDidChangeSessionOptions.event;22private readonly _onDidChangeItemsProviders = new Emitter<{ readonly chatSessionType: string }>();23readonly onDidChangeItemsProviders = this._onDidChangeItemsProviders.event;2425private readonly _onDidChangeSessionItems = new Emitter<{ readonly chatSessionType: string }>();26readonly onDidChangeSessionItems = this._onDidChangeSessionItems.event;2728private readonly _onDidChangeAvailability = new Emitter<void>();29readonly onDidChangeAvailability = this._onDidChangeAvailability.event;3031private readonly _onDidChangeInProgress = new Emitter<void>();32readonly onDidChangeInProgress = this._onDidChangeInProgress.event;3334private readonly _onDidChangeContentProviderSchemes = new Emitter<{ readonly added: string[]; readonly removed: string[] }>();35readonly onDidChangeContentProviderSchemes = this._onDidChangeContentProviderSchemes.event;3637private readonly _onDidChangeOptionGroups = new Emitter<string>();38readonly onDidChangeOptionGroups = this._onDidChangeOptionGroups.event;3940private readonly _onRequestNotifyExtension = new AsyncEmitter<IChatSessionOptionsWillNotifyExtensionEvent>();41readonly onRequestNotifyExtension = this._onRequestNotifyExtension.event;4243private sessionItemControllers = new Map<string, { readonly controller: IChatSessionItemController; readonly initialRefresh: Promise<void> }>();44private contentProviders = new Map<string, IChatSessionContentProvider>();45private contributions: IChatSessionsExtensionPoint[] = [];46private optionGroups = new Map<string, IChatSessionProviderOptionGroup[]>();47private sessionOptions = new ResourceMap<Map<string, string>>();48private inProgress = new Map<string, number>();49private onChange = () => { };5051// For testing: allow triggering events52fireDidChangeItemsProviders(event: { chatSessionType: string }): void {53this._onDidChangeItemsProviders.fire(event);54}5556fireDidChangeSessionItems(chatSessionType: string): void {57this._onDidChangeSessionItems.fire({ chatSessionType });58}5960fireDidChangeAvailability(): void {61this._onDidChangeAvailability.fire();62}6364fireDidChangeInProgress(): void {65this._onDidChangeInProgress.fire();66}6768registerChatSessionItemController(chatSessionType: string, controller: IChatSessionItemController): IDisposable {69this.sessionItemControllers.set(chatSessionType, { controller, initialRefresh: controller.refresh(CancellationToken.None) });70return {71dispose: () => {72this.sessionItemControllers.delete(chatSessionType);73}74};75}7677getAllChatSessionContributions(): IChatSessionsExtensionPoint[] {78return this.contributions;79}8081getChatSessionContribution(chatSessionType: string): IChatSessionsExtensionPoint | undefined {82return this.contributions.find(contrib => contrib.type === chatSessionType);83}8485setContributions(contributions: IChatSessionsExtensionPoint[]): void {86this.contributions = contributions;87}8889async activateChatSessionItemProvider(chatSessionType: string): Promise<void> {90// Noop, nothing to activate91}9293getIconForSessionType(chatSessionType: string): ThemeIcon | URI | undefined {94const contribution = this.contributions.find(c => c.type === chatSessionType);95return contribution?.icon && typeof contribution.icon === 'string' ? ThemeIcon.fromId(contribution.icon) : undefined;96}9798getWelcomeTitleForSessionType(chatSessionType: string): string | undefined {99return this.contributions.find(c => c.type === chatSessionType)?.welcomeTitle;100}101102getWelcomeMessageForSessionType(chatSessionType: string): string | undefined {103return this.contributions.find(c => c.type === chatSessionType)?.welcomeMessage;104}105106getInputPlaceholderForSessionType(chatSessionType: string): string | undefined {107return this.contributions.find(c => c.type === chatSessionType)?.inputPlaceholder;108}109110getChatSessionItems(providerTypeFilter: readonly string[] | undefined, token: CancellationToken): Promise<Array<{ readonly chatSessionType: string; readonly items: readonly IChatSessionItem[] }>> {111return Promise.all(112Array.from(this.sessionItemControllers.entries())113.filter(([chatSessionType]) => !providerTypeFilter || providerTypeFilter.includes(chatSessionType))114.map(async ([chatSessionType, controllerEntry]) => {115await controllerEntry.initialRefresh; // ensure initial refresh is done116return ({117chatSessionType: chatSessionType,118items: controllerEntry.controller.items119});120}));121}122123async refreshChatSessionItems(providerTypeFilter: readonly string[] | undefined, token: CancellationToken): Promise<void> {124await Promise.all(125Array.from(this.sessionItemControllers.entries())126.filter(([chatSessionType]) => !providerTypeFilter || providerTypeFilter.includes(chatSessionType))127.map(async ([_chatSessionType, controllerEntry]) => {128await controllerEntry.controller.refresh(token);129}));130}131132reportInProgress(chatSessionType: string, count: number): void {133this.inProgress.set(chatSessionType, count);134this._onDidChangeInProgress.fire();135}136137getInProgress(): { displayName: string; count: number }[] {138return Array.from(this.inProgress.entries()).map(([displayName, count]) => ({ displayName, count }));139}140141registerChatSessionContentProvider(chatSessionType: string, provider: IChatSessionContentProvider): IDisposable {142this.contentProviders.set(chatSessionType, provider);143this._onDidChangeContentProviderSchemes.fire({ added: [chatSessionType], removed: [] });144return {145dispose: () => {146this.contentProviders.delete(chatSessionType);147}148};149}150151async canResolveContentProvider(chatSessionType: string): Promise<boolean> {152return this.contentProviders.has(chatSessionType);153}154155async getOrCreateChatSession(sessionResource: URI, token: CancellationToken): Promise<IChatSession> {156const provider = this.contentProviders.get(sessionResource.scheme);157if (!provider) {158throw new Error(`No content provider for ${sessionResource.scheme}`);159}160return provider.provideChatSessionContent(sessionResource, token);161}162163async canResolveChatSession(chatSessionResource: URI): Promise<boolean> {164return this.contentProviders.has(chatSessionResource.scheme);165}166167getOptionGroupsForSessionType(chatSessionType: string): IChatSessionProviderOptionGroup[] | undefined {168return this.optionGroups.get(chatSessionType);169}170171setOptionGroupsForSessionType(chatSessionType: string, handle: number, optionGroups?: IChatSessionProviderOptionGroup[]): void {172if (optionGroups) {173this.optionGroups.set(chatSessionType, optionGroups);174} else {175this.optionGroups.delete(chatSessionType);176}177}178179async notifySessionOptionsChange(sessionResource: URI, updates: ReadonlyArray<{ optionId: string; value: string | IChatSessionProviderOptionItem }>): Promise<void> {180await this._onRequestNotifyExtension.fireAsync({ sessionResource, updates }, CancellationToken.None);181}182183getSessionOption(sessionResource: URI, optionId: string): string | undefined {184return this.sessionOptions.get(sessionResource)?.get(optionId);185}186187setSessionOption(sessionResource: URI, optionId: string, value: string): boolean {188if (!this.sessionOptions.has(sessionResource)) {189this.sessionOptions.set(sessionResource, new Map());190}191this.sessionOptions.get(sessionResource)!.set(optionId, value);192return true;193}194195hasAnySessionOptions(resource: URI): boolean {196return this.sessionOptions.has(resource) && this.sessionOptions.get(resource)!.size > 0;197}198199getCapabilitiesForSessionType(chatSessionType: string): IChatAgentAttachmentCapabilities | undefined {200return this.contributions.find(c => c.type === chatSessionType)?.capabilities;201}202203getCustomAgentTargetForSessionType(chatSessionType: string): Target {204return this.contributions.find(c => c.type === chatSessionType)?.customAgentTarget ?? Target.Undefined;205}206207getContentProviderSchemes(): string[] {208return Array.from(this.contentProviders.keys());209}210211getInProgressSessionDescription(chatModel: IChatModel): string | undefined {212return undefined;213}214215registerChatModelChangeListeners(chatService: IChatService, chatSessionType: string, onChange: () => void): IDisposable {216// Store the emitter so tests can trigger it217this.onChange = onChange;218return {219dispose: () => {220}221};222}223224// Helper method for tests to trigger progress events225triggerProgressEvent(): void {226if (this.onChange) {227this.onChange();228}229}230}231232233