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
4780 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 { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
16
import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
17
import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js';
18
import { ILogService } from '../../../../platform/log/common/log.js';
19
import { INativeHostService } from '../../../../platform/native/common/native.js';
20
import { IWorkspaceTrustRequestService } from '../../../../platform/workspace/common/workspaceTrust.js';
21
import { WorkbenchPhase, registerWorkbenchContribution2 } from '../../../common/contributions.js';
22
import { ViewContainerLocation } from '../../../common/views.js';
23
import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-browser/environmentService.js';
24
import { IExtensionService } from '../../../services/extensions/common/extensions.js';
25
import { IWorkbenchLayoutService } from '../../../services/layout/browser/layoutService.js';
26
import { ILifecycleService, ShutdownReason } from '../../../services/lifecycle/common/lifecycle.js';
27
import { ACTION_ID_NEW_CHAT, CHAT_OPEN_ACTION_ID, IChatViewOpenOptions } from '../browser/actions/chatActions.js';
28
import { IChatWidgetService } from '../browser/chat.js';
29
import { ChatContextKeys } from '../common/actions/chatContextKeys.js';
30
import { ChatConfiguration, ChatModeKind } from '../common/constants.js';
31
import { IChatService } from '../common/chatService/chatService.js';
32
import { registerChatDeveloperActions } from './actions/chatDeveloperActions.js';
33
import { HoldToVoiceChatInChatViewAction, InlineVoiceChatAction, KeywordActivationContribution, QuickVoiceChatAction, ReadChatResponseAloud, StartVoiceChatAction, StopListeningAction, StopListeningAndSubmitAction, StopReadAloud, StopReadChatItemAloud, VoiceChatInChatViewAction } from './actions/voiceChatActions.js';
34
import { NativeBuiltinToolsContribution } from './builtInTools/tools.js';
35
36
class ChatCommandLineHandler extends Disposable {
37
38
static readonly ID = 'workbench.contrib.chatCommandLineHandler';
39
40
constructor(
41
@INativeWorkbenchEnvironmentService private readonly environmentService: INativeWorkbenchEnvironmentService,
42
@ICommandService private readonly commandService: ICommandService,
43
@IWorkspaceTrustRequestService private readonly workspaceTrustRequestService: IWorkspaceTrustRequestService,
44
@ILogService private readonly logService: ILogService,
45
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
46
@IContextKeyService private readonly contextKeyService: IContextKeyService
47
) {
48
super();
49
50
this.registerListeners();
51
}
52
53
private registerListeners() {
54
ipcRenderer.on('vscode:handleChatRequest', (_, ...args: unknown[]) => {
55
const chatArgs = args[0] as typeof this.environmentService.args.chat;
56
this.logService.trace('vscode:handleChatRequest', chatArgs);
57
58
this.prompt(chatArgs);
59
});
60
}
61
62
private async prompt(args: typeof this.environmentService.args.chat): Promise<void> {
63
if (!Array.isArray(args?._)) {
64
return;
65
}
66
67
const trusted = await this.workspaceTrustRequestService.requestWorkspaceTrust({
68
message: localize('copilotWorkspaceTrust', "AI features are currently only supported in trusted workspaces.")
69
});
70
71
if (!trusted) {
72
return;
73
}
74
75
const opts: IChatViewOpenOptions = {
76
query: args._.length > 0 ? args._.join(' ') : '',
77
mode: args.mode ?? ChatModeKind.Agent,
78
attachFiles: args['add-file']?.map(file => URI.file(resolve(file))), // use `resolve` to deal with relative paths properly
79
};
80
81
if (args.maximize) {
82
const location = this.contextKeyService.getContextKeyValue<ViewContainerLocation>(ChatContextKeys.panelLocation.key);
83
if (location === ViewContainerLocation.AuxiliaryBar) {
84
this.layoutService.setAuxiliaryBarMaximized(true);
85
} else if (location === ViewContainerLocation.Panel && !this.layoutService.isPanelMaximized()) {
86
this.layoutService.toggleMaximizedPanel();
87
}
88
}
89
90
await this.commandService.executeCommand(ACTION_ID_NEW_CHAT);
91
await this.commandService.executeCommand(CHAT_OPEN_ACTION_ID, opts);
92
}
93
}
94
95
class ChatSuspendThrottlingHandler extends Disposable {
96
97
static readonly ID = 'workbench.contrib.chatSuspendThrottlingHandler';
98
99
constructor(
100
@INativeHostService nativeHostService: INativeHostService,
101
@IChatService chatService: IChatService,
102
@IConfigurationService configurationService: IConfigurationService
103
) {
104
super();
105
106
if (!configurationService.getValue<boolean>(ChatConfiguration.SuspendThrottling)) {
107
return;
108
}
109
110
this._register(autorun(reader => {
111
const running = chatService.requestInProgressObs.read(reader);
112
113
// When a chat request is in progress, we must ensure that background
114
// throttling is not applied so that the chat session can continue
115
// even when the window is not in focus.
116
nativeHostService.setBackgroundThrottling(!running);
117
}));
118
}
119
}
120
121
class ChatLifecycleHandler extends Disposable {
122
123
static readonly ID = 'workbench.contrib.chatLifecycleHandler';
124
125
constructor(
126
@ILifecycleService lifecycleService: ILifecycleService,
127
@IChatService private readonly chatService: IChatService,
128
@IDialogService private readonly dialogService: IDialogService,
129
@IChatWidgetService private readonly widgetService: IChatWidgetService,
130
@IContextKeyService private readonly contextKeyService: IContextKeyService,
131
@IExtensionService extensionService: IExtensionService,
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.chatService.requestInProgressObs.get(), localize('chatRequestInProgress', "A chat request is in progress."));
141
}));
142
}
143
144
private shouldVetoShutdown(reason: ShutdownReason): boolean | Promise<boolean> {
145
const running = this.chatService.requestInProgressObs.read(undefined);
146
if (!running) {
147
return false;
148
}
149
150
if (ChatContextKeys.skipChatRequestInProgressMessage.getValue(this.contextKeyService) === true) {
151
return false;
152
}
153
154
return this.doShouldVetoShutdown(reason);
155
}
156
157
private async doShouldVetoShutdown(reason: ShutdownReason): Promise<boolean> {
158
159
this.widgetService.revealWidget();
160
161
let message: string;
162
let detail: string;
163
switch (reason) {
164
case ShutdownReason.CLOSE:
165
message = localize('closeTheWindow.message', "A chat request is in progress. Are you sure you want to close the window?");
166
detail = localize('closeTheWindow.detail', "The chat request will stop if you close the window.");
167
break;
168
case ShutdownReason.LOAD:
169
message = localize('changeWorkspace.message', "A chat request is in progress. Are you sure you want to change the workspace?");
170
detail = localize('changeWorkspace.detail', "The chat request will stop if you change the workspace.");
171
break;
172
case ShutdownReason.RELOAD:
173
message = localize('reloadTheWindow.message', "A chat request is in progress. Are you sure you want to reload the window?");
174
detail = localize('reloadTheWindow.detail', "The chat request will stop if you reload the window.");
175
break;
176
default:
177
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?");
178
detail = isMacintosh ? localize('quit.detail', "The chat request will stop if you quit.") : localize('exit.detail', "The chat request will stop if you exit.");
179
break;
180
}
181
182
const result = await this.dialogService.confirm({ message, detail });
183
184
return !result.confirmed;
185
}
186
}
187
188
registerAction2(StartVoiceChatAction);
189
190
registerAction2(VoiceChatInChatViewAction);
191
registerAction2(HoldToVoiceChatInChatViewAction);
192
registerAction2(QuickVoiceChatAction);
193
registerAction2(InlineVoiceChatAction);
194
195
registerAction2(StopListeningAction);
196
registerAction2(StopListeningAndSubmitAction);
197
198
registerAction2(ReadChatResponseAloud);
199
registerAction2(StopReadChatItemAloud);
200
registerAction2(StopReadAloud);
201
202
registerChatDeveloperActions();
203
204
registerWorkbenchContribution2(KeywordActivationContribution.ID, KeywordActivationContribution, WorkbenchPhase.AfterRestored);
205
registerWorkbenchContribution2(NativeBuiltinToolsContribution.ID, NativeBuiltinToolsContribution, WorkbenchPhase.AfterRestored);
206
registerWorkbenchContribution2(ChatCommandLineHandler.ID, ChatCommandLineHandler, WorkbenchPhase.BlockRestore);
207
registerWorkbenchContribution2(ChatSuspendThrottlingHandler.ID, ChatSuspendThrottlingHandler, WorkbenchPhase.AfterRestored);
208
registerWorkbenchContribution2(ChatLifecycleHandler.ID, ChatLifecycleHandler, WorkbenchPhase.AfterRestored);
209
210