Path: blob/main/src/vs/workbench/contrib/chat/electron-browser/chat.contribution.ts
5272 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 { Disposable } from '../../../../base/common/lifecycle.js';6import { autorun } from '../../../../base/common/observable.js';7import { resolve } from '../../../../base/common/path.js';8import { isMacintosh } from '../../../../base/common/platform.js';9import { URI } from '../../../../base/common/uri.js';10import { ipcRenderer } from '../../../../base/parts/sandbox/electron-browser/globals.js';11import { localize } from '../../../../nls.js';12import { registerAction2 } from '../../../../platform/actions/common/actions.js';13import { ICommandService } from '../../../../platform/commands/common/commands.js';14import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';15import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js';16import { ILogService } from '../../../../platform/log/common/log.js';17import { INativeHostService } from '../../../../platform/native/common/native.js';18import { IWorkspaceTrustRequestService } from '../../../../platform/workspace/common/workspaceTrust.js';19import { WorkbenchPhase, registerWorkbenchContribution2 } from '../../../common/contributions.js';20import { ViewContainerLocation } from '../../../common/views.js';21import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-browser/environmentService.js';22import { IExtensionService } from '../../../services/extensions/common/extensions.js';23import { IWorkbenchLayoutService } from '../../../services/layout/browser/layoutService.js';24import { ILifecycleService, ShutdownReason } from '../../../services/lifecycle/common/lifecycle.js';25import { ACTION_ID_NEW_CHAT, CHAT_OPEN_ACTION_ID, IChatViewOpenOptions } from '../browser/actions/chatActions.js';26import { IChatWidgetService } from '../browser/chat.js';27import { AgentSessionProviders } from '../browser/agentSessions/agentSessions.js';28import { isSessionInProgressStatus } from '../browser/agentSessions/agentSessionsModel.js';29import { IAgentSessionsService } from '../browser/agentSessions/agentSessionsService.js';30import { ChatContextKeys } from '../common/actions/chatContextKeys.js';31import { ChatModeKind } from '../common/constants.js';32import { IChatService } from '../common/chatService/chatService.js';33import { registerChatDeveloperActions } from './actions/chatDeveloperActions.js';34import { registerChatExportZipAction } from './actions/chatExportZip.js';35import { HoldToVoiceChatInChatViewAction, InlineVoiceChatAction, KeywordActivationContribution, QuickVoiceChatAction, ReadChatResponseAloud, StartVoiceChatAction, StopListeningAction, StopListeningAndSubmitAction, StopReadAloud, StopReadChatItemAloud, VoiceChatInChatViewAction } from './actions/voiceChatActions.js';36import { NativeBuiltinToolsContribution } from './builtInTools/tools.js';37import { OpenAgentSessionsWindowAction, SwitchToAgentSessionsModeAction, SwitchToNormalModeAction } from './agentSessions/agentSessionsActions.js';3839class ChatCommandLineHandler extends Disposable {4041static readonly ID = 'workbench.contrib.chatCommandLineHandler';4243constructor(44@INativeWorkbenchEnvironmentService private readonly environmentService: INativeWorkbenchEnvironmentService,45@ICommandService private readonly commandService: ICommandService,46@IWorkspaceTrustRequestService private readonly workspaceTrustRequestService: IWorkspaceTrustRequestService,47@ILogService private readonly logService: ILogService,48@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,49@IContextKeyService private readonly contextKeyService: IContextKeyService50) {51super();5253this.registerListeners();54}5556private registerListeners() {57ipcRenderer.on('vscode:handleChatRequest', (_, ...args: unknown[]) => {58const chatArgs = args[0] as typeof this.environmentService.args.chat;59this.logService.trace('vscode:handleChatRequest', chatArgs);6061this.prompt(chatArgs);62});63}6465private async prompt(args: typeof this.environmentService.args.chat): Promise<void> {66if (!Array.isArray(args?._)) {67return;68}6970const trusted = await this.workspaceTrustRequestService.requestWorkspaceTrust({71message: localize('copilotWorkspaceTrust', "AI features are currently only supported in trusted workspaces.")72});7374if (!trusted) {75return;76}7778const opts: IChatViewOpenOptions = {79query: args._.length > 0 ? args._.join(' ') : '',80mode: args.mode ?? ChatModeKind.Agent,81attachFiles: args['add-file']?.map(file => URI.file(resolve(file))), // use `resolve` to deal with relative paths properly82};8384if (args.maximize) {85const location = this.contextKeyService.getContextKeyValue<ViewContainerLocation>(ChatContextKeys.panelLocation.key);86if (location === ViewContainerLocation.AuxiliaryBar) {87this.layoutService.setAuxiliaryBarMaximized(true);88} else if (location === ViewContainerLocation.Panel && !this.layoutService.isPanelMaximized()) {89this.layoutService.toggleMaximizedPanel();90}91}9293await this.commandService.executeCommand(ACTION_ID_NEW_CHAT);94await this.commandService.executeCommand(CHAT_OPEN_ACTION_ID, opts);95}96}9798class ChatSuspendThrottlingHandler extends Disposable {99100static readonly ID = 'workbench.contrib.chatSuspendThrottlingHandler';101102constructor(103@INativeHostService nativeHostService: INativeHostService,104@IChatService chatService: IChatService105) {106super();107108this._register(autorun(reader => {109const running = chatService.requestInProgressObs.read(reader);110111// When a chat request is in progress, we must ensure that background112// throttling is not applied so that the chat session can continue113// even when the window is not in focus.114nativeHostService.setBackgroundThrottling(!running);115}));116}117}118119class ChatLifecycleHandler extends Disposable {120121static readonly ID = 'workbench.contrib.chatLifecycleHandler';122123constructor(124@ILifecycleService lifecycleService: ILifecycleService,125@IAgentSessionsService private readonly agentSessionsService: IAgentSessionsService,126@IDialogService private readonly dialogService: IDialogService,127@IChatWidgetService private readonly widgetService: IChatWidgetService,128@IContextKeyService private readonly contextKeyService: IContextKeyService,129@IExtensionService extensionService: IExtensionService,130@INativeWorkbenchEnvironmentService private readonly environmentService: INativeWorkbenchEnvironmentService,131) {132super();133134this._register(lifecycleService.onBeforeShutdown(e => {135e.veto(this.shouldVetoShutdown(e.reason), 'veto.chat');136}));137138this._register(extensionService.onWillStop(e => {139e.veto(this.hasNonCloudSessionInProgress(), localize('chatRequestInProgress', "A chat request is in progress."));140}));141}142143private hasNonCloudSessionInProgress(): boolean {144return this.agentSessionsService.model.sessions.some(session =>145isSessionInProgressStatus(session.status) && session.providerType !== AgentSessionProviders.Cloud146);147}148149private shouldVetoShutdown(reason: ShutdownReason): boolean | Promise<boolean> {150if (this.environmentService.enableSmokeTestDriver) {151return false;152}153154if (!this.hasNonCloudSessionInProgress()) {155return false;156}157158if (ChatContextKeys.skipChatRequestInProgressMessage.getValue(this.contextKeyService) === true) {159return false;160}161162return this.doShouldVetoShutdown(reason);163}164165private async doShouldVetoShutdown(reason: ShutdownReason): Promise<boolean> {166167this.widgetService.revealWidget();168169let message: string;170let detail: string;171switch (reason) {172case ShutdownReason.CLOSE:173message = localize('closeTheWindow.message', "A chat request is in progress. Are you sure you want to close the window?");174detail = localize('closeTheWindow.detail', "The chat request will stop if you close the window.");175break;176case ShutdownReason.LOAD:177message = localize('changeWorkspace.message', "A chat request is in progress. Are you sure you want to change the workspace?");178detail = localize('changeWorkspace.detail', "The chat request will stop if you change the workspace.");179break;180case ShutdownReason.RELOAD:181message = localize('reloadTheWindow.message', "A chat request is in progress. Are you sure you want to reload the window?");182detail = localize('reloadTheWindow.detail', "The chat request will stop if you reload the window.");183break;184default:185message = isMacintosh ? localize('quit.message', "A chat request is in progress. Are you sure you want to quit?") : localize('exit.message', "A chat request is in progress. Are you sure you want to exit?");186detail = isMacintosh ? localize('quit.detail', "The chat request will stop if you quit.") : localize('exit.detail', "The chat request will stop if you exit.");187break;188}189190const result = await this.dialogService.confirm({ message, detail });191192return !result.confirmed;193}194}195196registerAction2(OpenAgentSessionsWindowAction);197registerAction2(SwitchToAgentSessionsModeAction);198registerAction2(SwitchToNormalModeAction);199registerAction2(StartVoiceChatAction);200201registerAction2(VoiceChatInChatViewAction);202registerAction2(HoldToVoiceChatInChatViewAction);203registerAction2(QuickVoiceChatAction);204registerAction2(InlineVoiceChatAction);205206registerAction2(StopListeningAction);207registerAction2(StopListeningAndSubmitAction);208209registerAction2(ReadChatResponseAloud);210registerAction2(StopReadChatItemAloud);211registerAction2(StopReadAloud);212213registerChatDeveloperActions();214registerChatExportZipAction();215216registerWorkbenchContribution2(KeywordActivationContribution.ID, KeywordActivationContribution, WorkbenchPhase.AfterRestored);217registerWorkbenchContribution2(NativeBuiltinToolsContribution.ID, NativeBuiltinToolsContribution, WorkbenchPhase.AfterRestored);218registerWorkbenchContribution2(ChatCommandLineHandler.ID, ChatCommandLineHandler, WorkbenchPhase.BlockRestore);219registerWorkbenchContribution2(ChatSuspendThrottlingHandler.ID, ChatSuspendThrottlingHandler, WorkbenchPhase.AfterRestored);220registerWorkbenchContribution2(ChatLifecycleHandler.ID, ChatLifecycleHandler, WorkbenchPhase.AfterRestored);221222223