Skip to content

Commit ad582f1

Browse files
authored
Enable workbench.action.chat.open to switch to custom modes (microsoft#253120)
* Enable workbench.action.chat.open to switch to custom modes * Fix build
1 parent 060f72a commit ad582f1

File tree

4 files changed

+39
-39
lines changed

4 files changed

+39
-39
lines changed

src/vs/workbench/contrib/chat/browser/actions/chatActions.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,12 @@ import { IChatAgentService } from '../../common/chatAgents.js';
5050
import { ChatContextKeys } from '../../common/chatContextKeys.js';
5151
import { IChatEditingSession, ModifiedFileEntryState } from '../../common/chatEditingService.js';
5252
import { ChatEntitlement, IChatEntitlementService } from '../../common/chatEntitlementService.js';
53-
import { ChatMode, IChatMode } from '../../common/chatModes.js';
53+
import { ChatMode, IChatMode, IChatModeService } from '../../common/chatModes.js';
5454
import { extractAgentAndCommand } from '../../common/chatParserTypes.js';
5555
import { IChatDetail, IChatService } from '../../common/chatService.js';
5656
import { IChatRequestViewModel, IChatResponseViewModel, isRequestVM } from '../../common/chatViewModel.js';
5757
import { IChatWidgetHistoryService } from '../../common/chatWidgetHistoryService.js';
58-
import { ChatAgentLocation, ChatConfiguration, ChatModeKind, validateChatMode } from '../../common/constants.js';
58+
import { ChatAgentLocation, ChatConfiguration, ChatModeKind } from '../../common/constants.js';
5959
import { CopilotUsageExtensionFeatureId } from '../../common/languageModelStats.js';
6060
import { ILanguageModelToolsService } from '../../common/languageModelToolsService.js';
6161
import { ChatViewId, IChatWidget, IChatWidgetService, showChatView, showCopilotView } from '../chat.js';
@@ -100,9 +100,9 @@ export interface IChatViewOpenOptions {
100100
*/
101101
attachFiles?: URI[];
102102
/**
103-
* The mode to open the chat in.
103+
* The mode ID or name to open the chat in.
104104
*/
105-
mode?: ChatModeKind;
105+
mode?: ChatModeKind | string;
106106
}
107107

108108
export interface IChatViewOpenRequestEntry {
@@ -139,6 +139,7 @@ abstract class OpenChatGlobalAction extends Action2 {
139139
const chatAgentService = accessor.get(IChatAgentService);
140140
const instaService = accessor.get(IInstantiationService);
141141
const commandService = accessor.get(ICommandService);
142+
const chatModeService = accessor.get(IChatModeService);
142143

143144
let chatWidget = widgetService.lastFocusedWidget;
144145
// When this was invoked to switch to a mode via keybinding, and some chat widget is focused, use that one.
@@ -151,11 +152,12 @@ abstract class OpenChatGlobalAction extends Action2 {
151152
return;
152153
}
153154

154-
let switchToMode = opts?.mode ?? this.mode;
155+
const switchToModeInput = opts?.mode ?? this.mode;
156+
let switchToMode = switchToModeInput && (chatModeService.findModeById(switchToModeInput) ?? chatModeService.findModeByName(switchToModeInput));
155157
if (!switchToMode) {
156-
switchToMode = opts?.query?.startsWith('@') ? ChatModeKind.Ask : undefined;
158+
switchToMode = opts?.query?.startsWith('@') ? ChatMode.Ask : undefined;
157159
}
158-
if (switchToMode && validateChatMode(switchToMode)) {
160+
if (switchToMode) {
159161
await this.handleSwitchToMode(switchToMode, chatWidget, instaService, commandService);
160162
}
161163

@@ -203,17 +205,17 @@ abstract class OpenChatGlobalAction extends Action2 {
203205
chatWidget.focusInput();
204206
}
205207

206-
private async handleSwitchToMode(switchToMode: ChatModeKind, chatWidget: IChatWidget, instaService: IInstantiationService, commandService: ICommandService): Promise<void> {
208+
private async handleSwitchToMode(switchToMode: IChatMode, chatWidget: IChatWidget, instaService: IInstantiationService, commandService: ICommandService): Promise<void> {
207209
const currentMode = chatWidget.input.currentModeKind;
208210

209211
if (switchToMode) {
210212
const editingSession = chatWidget.viewModel?.model.editingSession;
211213
const requestCount = chatWidget.viewModel?.model.getRequests().length ?? 0;
212-
const chatModeCheck = await instaService.invokeFunction(handleModeSwitch, currentMode, switchToMode, requestCount, editingSession);
214+
const chatModeCheck = await instaService.invokeFunction(handleModeSwitch, currentMode, switchToMode.kind, requestCount, editingSession);
213215
if (!chatModeCheck) {
214216
return;
215217
}
216-
chatWidget.input.setChatMode(switchToMode);
218+
chatWidget.input.setChatMode(switchToMode.id);
217219

218220
if (chatModeCheck.needToClearSession) {
219221
await commandService.executeCommand(ACTION_ID_NEW_CHAT);

src/vs/workbench/contrib/chat/common/chatModes.ts

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { ILogService } from '../../../../platform/log/common/log.js';
1515
import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
1616
import { IChatAgentService } from './chatAgents.js';
1717
import { ChatContextKeys } from './chatContextKeys.js';
18-
import { ChatModeKind, modeToString } from './constants.js';
18+
import { ChatModeKind } from './constants.js';
1919
import { ICustomChatMode, IPromptsService } from './promptSyntax/service/promptsService.js';
2020

2121
export const IChatModeService = createDecorator<IChatModeService>('chatModeService');
@@ -26,6 +26,7 @@ export interface IChatModeService {
2626
onDidChangeChatModes: Event<void>;
2727
getModes(): { builtin: readonly IChatMode[]; custom: readonly IChatMode[] };
2828
findModeById(id: string): IChatMode | undefined;
29+
findModeByName(name: string): IChatMode | undefined;
2930
}
3031

3132
export class ChatModeService extends Disposable implements IChatModeService {
@@ -163,13 +164,19 @@ export class ChatModeService extends Disposable implements IChatModeService {
163164
return { builtin: this.getBuiltinModes(), custom: Array.from(this._customModeInstances.values()) };
164165
}
165166

166-
findModeById(id: string | ChatModeKind): IChatMode | undefined {
167+
private getFlatModes(): IChatMode[] {
167168
const allModes = this.getModes();
168-
const builtinMode = allModes.builtin.find(mode => mode.id === id);
169-
if (builtinMode) {
170-
return builtinMode;
171-
}
172-
return allModes.custom.find(mode => mode.id === id);
169+
return [...allModes.builtin, ...allModes.custom];
170+
}
171+
172+
findModeById(id: string | ChatModeKind): IChatMode | undefined {
173+
const allModes = this.getFlatModes();
174+
return allModes.find(mode => mode.id === id);
175+
}
176+
177+
findModeByName(name: string): IChatMode | undefined {
178+
const allModes = this.getFlatModes();
179+
return allModes.find(mode => mode.name === name);
173180
}
174181

175182
private getBuiltinModes(): IChatMode[] {
@@ -298,13 +305,12 @@ export class CustomChatMode implements IChatMode {
298305

299306
export class BuiltinChatMode implements IChatMode {
300307
public readonly description: IObservable<string>;
301-
public readonly name: string;
302308

303309
constructor(
304310
public readonly kind: ChatModeKind,
311+
public readonly name: string,
305312
description: string
306313
) {
307-
this.name = modeToString(this.kind);
308314
this.description = observableValue('description', description);
309315
}
310316

@@ -327,9 +333,9 @@ export class BuiltinChatMode implements IChatMode {
327333
}
328334

329335
export namespace ChatMode {
330-
export const Ask = new BuiltinChatMode(ChatModeKind.Ask, localize('chatDescription', "Ask Copilot"));
331-
export const Edit = new BuiltinChatMode(ChatModeKind.Edit, localize('editsDescription', "Edit files in your workspace"));
332-
export const Agent = new BuiltinChatMode(ChatModeKind.Agent, localize('agentDescription', "Edit files in your workspace in agent mode"));
336+
export const Ask = new BuiltinChatMode(ChatModeKind.Ask, 'Ask', localize('chatDescription', "Ask Copilot"));
337+
export const Edit = new BuiltinChatMode(ChatModeKind.Edit, 'Edit', localize('editsDescription', "Edit files in your workspace"));
338+
export const Agent = new BuiltinChatMode(ChatModeKind.Agent, 'Agent', localize('agentDescription', "Edit files in your workspace in agent mode"));
333339
}
334340

335341
export function isBuiltinChatMode(mode: IChatMode): boolean {

src/vs/workbench/contrib/chat/common/constants.ts

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,6 @@ export enum ChatModeKind {
2020
Agent = 'agent'
2121
}
2222

23-
export function modeToString(mode: ChatModeKind) {
24-
switch (mode) {
25-
case ChatModeKind.Agent:
26-
return 'Agent';
27-
case ChatModeKind.Edit:
28-
return 'Edit';
29-
case ChatModeKind.Ask:
30-
default:
31-
return 'Ask';
32-
}
33-
}
34-
3523
export function validateChatMode(mode: unknown): ChatModeKind | undefined {
3624
switch (mode) {
3725
case ChatModeKind.Ask:

src/vs/workbench/contrib/chat/test/common/mockChatModeService.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,15 @@ export class MockChatModeService implements IChatModeService {
1919
}
2020

2121
findModeById(id: string): IChatMode | undefined {
22+
return this.getFlatModes().find(mode => mode.id === id);
23+
}
24+
25+
findModeByName(name: string): IChatMode | undefined {
26+
return this.getFlatModes().find(mode => mode.name === name);
27+
}
28+
29+
private getFlatModes(): IChatMode[] {
2230
const allModes = this.getModes();
23-
const builtinMode = allModes.builtin.find(mode => mode.id === id);
24-
if (builtinMode) {
25-
return builtinMode;
26-
}
27-
return allModes.custom.find(mode => mode.id === id);
31+
return [...allModes.builtin, ...allModes.custom];
2832
}
2933
}

0 commit comments

Comments
 (0)