Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/chat/electron-browser/chat.contribution.ts
5272 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { Disposable } from '../../../../base/common/lifecycle.js';
7
import { autorun } from '../../../../base/common/observable.js';
8
import { resolve } from '../../../../base/common/path.js';
9
import { isMacintosh } from '../../../../base/common/platform.js';
10
import { URI } from '../../../../base/common/uri.js';
11
import { ipcRenderer } from '../../../../base/parts/sandbox/electron-browser/globals.js';
12
import { localize } from '../../../../nls.js';
13
import { registerAction2 } from '../../../../platform/actions/common/actions.js';
14
import { ICommandService } from '../../../../platform/commands/common/commands.js';
15
import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
16
import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js';
17
import { ILogService } from '../../../../platform/log/common/log.js';
18
import { INativeHostService } from '../../../../platform/native/common/native.js';
19
import { IWorkspaceTrustRequestService } from '../../../../platform/workspace/common/workspaceTrust.js';
20
import { WorkbenchPhase, registerWorkbenchContribution2 } from '../../../common/contributions.js';
21
import { ViewContainerLocation } from '../../../common/views.js';
22
import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-browser/environmentService.js';
23
import { IExtensionService } from '../../../services/extensions/common/extensions.js';
24
import { IWorkbenchLayoutService } from '../../../services/layout/browser/layoutService.js';
25
import { ILifecycleService, ShutdownReason } from '../../../services/lifecycle/common/lifecycle.js';
26
import { ACTION_ID_NEW_CHAT, CHAT_OPEN_ACTION_ID, IChatViewOpenOptions } from '../browser/actions/chatActions.js';
27
import { IChatWidgetService } from '../browser/chat.js';
28
import { AgentSessionProviders } from '../browser/agentSessions/agentSessions.js';
29
import { isSessionInProgressStatus } from '../browser/agentSessions/agentSessionsModel.js';
30
import { IAgentSessionsService } from '../browser/agentSessions/agentSessionsService.js';
31
import { ChatContextKeys } from '../common/actions/chatContextKeys.js';
32
import { ChatModeKind } from '../common/constants.js';
33
import { IChatService } from '../common/chatService/chatService.js';
34
import { registerChatDeveloperActions } from './actions/chatDeveloperActions.js';
35
import { registerChatExportZipAction } from './actions/chatExportZip.js';
36
import { HoldToVoiceChatInChatViewAction, InlineVoiceChatAction, KeywordActivationContribution, QuickVoiceChatAction, ReadChatResponseAloud, StartVoiceChatAction, StopListeningAction, StopListeningAndSubmitAction, StopReadAloud, StopReadChatItemAloud, VoiceChatInChatViewAction } from './actions/voiceChatActions.js';
37
import { NativeBuiltinToolsContribution } from './builtInTools/tools.js';
38
import { OpenAgentSessionsWindowAction, SwitchToAgentSessionsModeAction, SwitchToNormalModeAction } from './agentSessions/agentSessionsActions.js';
39
40
class ChatCommandLineHandler extends Disposable {
41
42
static readonly ID = 'workbench.contrib.chatCommandLineHandler';
43
44
constructor(
45
@INativeWorkbenchEnvironmentService private readonly environmentService: INativeWorkbenchEnvironmentService,
46
@ICommandService private readonly commandService: ICommandService,
47
@IWorkspaceTrustRequestService private readonly workspaceTrustRequestService: IWorkspaceTrustRequestService,
48
@ILogService private readonly logService: ILogService,
49
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
50
@IContextKeyService private readonly contextKeyService: IContextKeyService
51
) {
52
super();
53
54
this.registerListeners();
55
}
56
57
private registerListeners() {
58
ipcRenderer.on('vscode:handleChatRequest', (_, ...args: unknown[]) => {
59
const chatArgs = args[0] as typeof this.environmentService.args.chat;
60
this.logService.trace('vscode:handleChatRequest', chatArgs);
61
62
this.prompt(chatArgs);
63
});
64
}
65
66
private async prompt(args: typeof this.environmentService.args.chat): Promise<void> {
67
if (!Array.isArray(args?._)) {
68
return;
69
}
70
71
const trusted = await this.workspaceTrustRequestService.requestWorkspaceTrust({
72
message: localize('copilotWorkspaceTrust', "AI features are currently only supported in trusted workspaces.")
73
});
74
75
if (!trusted) {
76
return;
77
}
78
79
const opts: IChatViewOpenOptions = {
80
query: args._.length > 0 ? args._.join(' ') : '',
81
mode: args.mode ?? ChatModeKind.Agent,
82
attachFiles: args['add-file']?.map(file => URI.file(resolve(file))), // use `resolve` to deal with relative paths properly
83
};
84
85
if (args.maximize) {
86
const location = this.contextKeyService.getContextKeyValue<ViewContainerLocation>(ChatContextKeys.panelLocation.key);
87
if (location === ViewContainerLocation.AuxiliaryBar) {
88
this.layoutService.setAuxiliaryBarMaximized(true);
89
} else if (location === ViewContainerLocation.Panel && !this.layoutService.isPanelMaximized()) {
90
this.layoutService.toggleMaximizedPanel();
91
}
92
}
93
94
await this.commandService.executeCommand(ACTION_ID_NEW_CHAT);
95
await this.commandService.executeCommand(CHAT_OPEN_ACTION_ID, opts);
96
}
97
}
98
99
class ChatSuspendThrottlingHandler extends Disposable {
100
101
static readonly ID = 'workbench.contrib.chatSuspendThrottlingHandler';
102
103
constructor(
104
@INativeHostService nativeHostService: INativeHostService,
105
@IChatService chatService: IChatService
106
) {
107
super();
108
109
this._register(autorun(reader => {
110
const running = chatService.requestInProgressObs.read(reader);
111
112
// When a chat request is in progress, we must ensure that background
113
// throttling is not applied so that the chat session can continue
114
// even when the window is not in focus.
115
nativeHostService.setBackgroundThrottling(!running);
116
}));
117
}
118
}
119
120
class ChatLifecycleHandler extends Disposable {
121
122
static readonly ID = 'workbench.contrib.chatLifecycleHandler';
123
124
constructor(
125
@ILifecycleService lifecycleService: ILifecycleService,
126
@IAgentSessionsService private readonly agentSessionsService: IAgentSessionsService,
127
@IDialogService private readonly dialogService: IDialogService,
128
@IChatWidgetService private readonly widgetService: IChatWidgetService,
129
@IContextKeyService private readonly contextKeyService: IContextKeyService,
130
@IExtensionService extensionService: IExtensionService,
131
@INativeWorkbenchEnvironmentService private readonly environmentService: INativeWorkbenchEnvironmentService,
132
) {
133
super();
134
135
this._register(lifecycleService.onBeforeShutdown(e => {
136
e.veto(this.shouldVetoShutdown(e.reason), 'veto.chat');
137
}));
138
139
this._register(extensionService.onWillStop(e => {
140
e.veto(this.hasNonCloudSessionInProgress(), localize('chatRequestInProgress', "A chat request is in progress."));
141
}));
142
}
143
144
private hasNonCloudSessionInProgress(): boolean {
145
return this.agentSessionsService.model.sessions.some(session =>
146
isSessionInProgressStatus(session.status) && session.providerType !== AgentSessionProviders.Cloud
147
);
148
}
149
150
private shouldVetoShutdown(reason: ShutdownReason): boolean | Promise<boolean> {
151
if (this.environmentService.enableSmokeTestDriver) {
152
return false;
153
}
154
155
if (!this.hasNonCloudSessionInProgress()) {
156
return false;
157
}
158
159
if (ChatContextKeys.skipChatRequestInProgressMessage.getValue(this.contextKeyService) === true) {
160
return false;
161
}
162
163
return this.doShouldVetoShutdown(reason);
164
}
165
166
private async doShouldVetoShutdown(reason: ShutdownReason): Promise<boolean> {
167
168
this.widgetService.revealWidget();
169
170
let message: string;
171
let detail: string;
172
switch (reason) {
173
case ShutdownReason.CLOSE:
174
message = localize('closeTheWindow.message', "A chat request is in progress. Are you sure you want to close the window?");
175
detail = localize('closeTheWindow.detail', "The chat request will stop if you close the window.");
176
break;
177
case ShutdownReason.LOAD:
178
message = localize('changeWorkspace.message', "A chat request is in progress. Are you sure you want to change the workspace?");
179
detail = localize('changeWorkspace.detail', "The chat request will stop if you change the workspace.");
180
break;
181
case ShutdownReason.RELOAD:
182
message = localize('reloadTheWindow.message', "A chat request is in progress. Are you sure you want to reload the window?");
183
detail = localize('reloadTheWindow.detail', "The chat request will stop if you reload the window.");
184
break;
185
default:
186
message = 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?");
187
detail = isMacintosh ? localize('quit.detail', "The chat request will stop if you quit.") : localize('exit.detail', "The chat request will stop if you exit.");
188
break;
189
}
190
191
const result = await this.dialogService.confirm({ message, detail });
192
193
return !result.confirmed;
194
}
195
}
196
197
registerAction2(OpenAgentSessionsWindowAction);
198
registerAction2(SwitchToAgentSessionsModeAction);
199
registerAction2(SwitchToNormalModeAction);
200
registerAction2(StartVoiceChatAction);
201
202
registerAction2(VoiceChatInChatViewAction);
203
registerAction2(HoldToVoiceChatInChatViewAction);
204
registerAction2(QuickVoiceChatAction);
205
registerAction2(InlineVoiceChatAction);
206
207
registerAction2(StopListeningAction);
208
registerAction2(StopListeningAndSubmitAction);
209
210
registerAction2(ReadChatResponseAloud);
211
registerAction2(StopReadChatItemAloud);
212
registerAction2(StopReadAloud);
213
214
registerChatDeveloperActions();
215
registerChatExportZipAction();
216
217
registerWorkbenchContribution2(KeywordActivationContribution.ID, KeywordActivationContribution, WorkbenchPhase.AfterRestored);
218
registerWorkbenchContribution2(NativeBuiltinToolsContribution.ID, NativeBuiltinToolsContribution, WorkbenchPhase.AfterRestored);
219
registerWorkbenchContribution2(ChatCommandLineHandler.ID, ChatCommandLineHandler, WorkbenchPhase.BlockRestore);
220
registerWorkbenchContribution2(ChatSuspendThrottlingHandler.ID, ChatSuspendThrottlingHandler, WorkbenchPhase.AfterRestored);
221
registerWorkbenchContribution2(ChatLifecycleHandler.ID, ChatLifecycleHandler, WorkbenchPhase.AfterRestored);
222
223