Path: blob/main/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsOpener.ts
5343 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 { IDisposable } from '../../../../../base/common/lifecycle.js';6import { IAgentSession, isLocalAgentSessionItem } from './agentSessionsModel.js';7import { ServicesAccessor } from '../../../../../editor/browser/editorExtensions.js';8import { IChatEditorOptions } from '../widgetHosts/editor/chatEditor.js';9import { ChatViewPaneTarget, IChatWidget, IChatWidgetService } from '../chat.js';10import { ACTIVE_GROUP, SIDE_GROUP } from '../../../../services/editor/common/editorService.js';11import { IEditorOptions } from '../../../../../platform/editor/common/editor.js';12import { IChatSessionsService } from '../../common/chatSessionsService.js';13import { Schemas } from '../../../../../base/common/network.js';14import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js';15import { INotificationService } from '../../../../../platform/notification/common/notification.js';16import { localize } from '../../../../../nls.js';17import { toErrorMessage } from '../../../../../base/common/errorMessage.js';18import { ILogService } from '../../../../../platform/log/common/log.js';1920//#region Session Opener Registry2122export interface ISessionOpenerParticipant {23handleOpenSession(accessor: ServicesAccessor, session: IAgentSession, openOptions?: ISessionOpenOptions): Promise<boolean>;24}2526export interface ISessionOpenOptions {27readonly sideBySide?: boolean;28readonly editorOptions?: IEditorOptions;29}3031class SessionOpenerRegistry {3233private readonly participants = new Set<ISessionOpenerParticipant>();3435registerParticipant(participant: ISessionOpenerParticipant): IDisposable {36this.participants.add(participant);3738return {39dispose: () => {40this.participants.delete(participant);41}42};43}4445getParticipants(): readonly ISessionOpenerParticipant[] {46return Array.from(this.participants);47}48}4950export const sessionOpenerRegistry = new SessionOpenerRegistry();5152//#endregion5354export async function openSession(accessor: ServicesAccessor, session: IAgentSession, openOptions?: ISessionOpenOptions): Promise<IChatWidget | undefined> {55const instantiationService = accessor.get(IInstantiationService);56const logService = accessor.get(ILogService);5758// First, give registered participants a chance to handle the session59for (const participant of sessionOpenerRegistry.getParticipants()) {60try {61const handled = await instantiationService.invokeFunction(accessor => participant.handleOpenSession(accessor, session, openOptions));62if (handled) {63return undefined; // Participant handled the session, skip default opening64}65} catch (error) {66logService.error(error); // log error but continue to support opening from default logic67}68}6970// Default session opening logic71return instantiationService.invokeFunction(accessor => openSessionDefault(accessor, session, openOptions));72}7374async function openSessionDefault(accessor: ServicesAccessor, session: IAgentSession, openOptions?: ISessionOpenOptions): Promise<IChatWidget | undefined> {75const chatSessionsService = accessor.get(IChatSessionsService);76const chatWidgetService = accessor.get(IChatWidgetService);77const notificationService = accessor.get(INotificationService);7879try {80session.setRead(true); // mark as read when opened8182let sessionOptions: IChatEditorOptions;83if (isLocalAgentSessionItem(session)) {84sessionOptions = {};85} else {86sessionOptions = { title: { preferred: session.label } };87}8889let options: IChatEditorOptions = {90...sessionOptions,91...openOptions?.editorOptions,92revealIfOpened: true, // always try to reveal if already opened93};9495await chatSessionsService.activateChatSessionItemProvider(session.providerType); // ensure provider is activated before trying to open9697let target: typeof SIDE_GROUP | typeof ACTIVE_GROUP | typeof ChatViewPaneTarget | undefined;98if (openOptions?.sideBySide) {99target = ACTIVE_GROUP;100} else {101target = ChatViewPaneTarget;102}103104const isLocalChatSession = session.resource.scheme === Schemas.vscodeChatEditor || session.resource.scheme === Schemas.vscodeLocalChatSession;105if (!isLocalChatSession && !(await chatSessionsService.canResolveChatSession(session.resource))) {106target = openOptions?.sideBySide ? SIDE_GROUP : ACTIVE_GROUP; // force to open in editor if session cannot be resolved in panel107options = { ...options, revealIfOpened: true };108}109110return await chatWidgetService.openSession(session.resource, target, options);111} catch (error) {112notificationService.error(localize('chat.openSessionFailed', "Failed to open chat session: {0}", toErrorMessage(error)));113return undefined;114}115}116117118