Path: blob/main/src/vs/workbench/contrib/chat/browser/modelPicker/modePickerActionItem.ts
3296 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 * as dom from '../../../../../base/browser/dom.js';6import { renderLabelWithIcons } from '../../../../../base/browser/ui/iconLabel/iconLabels.js';7import { IAction } from '../../../../../base/common/actions.js';8import { IDisposable } from '../../../../../base/common/lifecycle.js';9import { autorun, IObservable } from '../../../../../base/common/observable.js';10import { localize } from '../../../../../nls.js';11import { ActionWidgetDropdownActionViewItem } from '../../../../../platform/actions/browser/actionWidgetDropdownActionViewItem.js';12import { getFlatActionBarActions } from '../../../../../platform/actions/browser/menuEntryActionViewItem.js';13import { IMenuService, MenuId, MenuItemAction } from '../../../../../platform/actions/common/actions.js';14import { IActionWidgetService } from '../../../../../platform/actionWidget/browser/actionWidget.js';15import { IActionWidgetDropdownAction, IActionWidgetDropdownActionProvider, IActionWidgetDropdownOptions } from '../../../../../platform/actionWidget/browser/actionWidgetDropdown.js';16import { ICommandService } from '../../../../../platform/commands/common/commands.js';17import { IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js';18import { IKeybindingService } from '../../../../../platform/keybinding/common/keybinding.js';19import { IChatAgentService } from '../../common/chatAgents.js';20import { IChatMode, IChatModeService } from '../../common/chatModes.js';21import { ChatAgentLocation } from '../../common/constants.js';22import { getOpenChatActionIdForMode } from '../actions/chatActions.js';23import { IToggleChatModeArgs, ToggleAgentModeActionId } from '../actions/chatExecuteActions.js';2425export interface IModePickerDelegate {26readonly currentMode: IObservable<IChatMode>;27}2829export class ModePickerActionItem extends ActionWidgetDropdownActionViewItem {30constructor(31action: MenuItemAction,32private readonly delegate: IModePickerDelegate,33@IActionWidgetService actionWidgetService: IActionWidgetService,34@IChatAgentService chatAgentService: IChatAgentService,35@IKeybindingService keybindingService: IKeybindingService,36@IContextKeyService private readonly contextKeyService: IContextKeyService,37@IChatModeService chatModeService: IChatModeService,38@IMenuService private readonly menuService: IMenuService,39@ICommandService commandService: ICommandService40) {41const makeAction = (mode: IChatMode, currentMode: IChatMode): IActionWidgetDropdownAction => ({42...action,43id: getOpenChatActionIdForMode(mode),44label: mode.label,45class: undefined,46enabled: true,47checked: currentMode.id === mode.id,48tooltip: chatAgentService.getDefaultAgent(ChatAgentLocation.Panel, mode.kind)?.description ?? action.tooltip,49run: async () => {50const result = await commandService.executeCommand(ToggleAgentModeActionId, { modeId: mode.id } satisfies IToggleChatModeArgs);51this.renderLabel(this.element!);52return result;53},54category: { label: localize('built-in', "Built-In"), order: 0 }55});5657const makeActionFromCustomMode = (mode: IChatMode, currentMode: IChatMode): IActionWidgetDropdownAction => ({58...action,59id: getOpenChatActionIdForMode(mode),60label: mode.label,61class: undefined,62enabled: true,63checked: currentMode.id === mode.id,64tooltip: mode.description.get() ?? chatAgentService.getDefaultAgent(ChatAgentLocation.Panel, mode.kind)?.description ?? action.tooltip,65run: async () => {66const result = await commandService.executeCommand(ToggleAgentModeActionId, { modeId: mode.id } satisfies IToggleChatModeArgs);67this.renderLabel(this.element!);68return result;69},70category: { label: localize('custom', "Custom"), order: 1 }71});7273const actionProvider: IActionWidgetDropdownActionProvider = {74getActions: () => {75const modes = chatModeService.getModes();76const currentMode = delegate.currentMode.get();77const agentStateActions: IActionWidgetDropdownAction[] = modes.builtin.map(mode => makeAction(mode, currentMode));78if (modes.custom) {79agentStateActions.push(...modes.custom.map(mode => makeActionFromCustomMode(mode, currentMode)));80}8182return agentStateActions;83}84};8586const modePickerActionWidgetOptions: Omit<IActionWidgetDropdownOptions, 'label' | 'labelRenderer'> = {87actionProvider,88actionBarActionProvider: {89getActions: () => this.getModePickerActionBarActions()90},91showItemKeybindings: true92};9394super(action, modePickerActionWidgetOptions, actionWidgetService, keybindingService, contextKeyService);9596// Listen to changes in the current mode and its properties97this._register(autorun(reader => {98this.renderLabel(this.element!, this.delegate.currentMode.read(reader));99}));100}101102private getModePickerActionBarActions(): IAction[] {103const menuActions = this.menuService.createMenu(MenuId.ChatModePicker, this.contextKeyService);104const menuContributions = getFlatActionBarActions(menuActions.getActions({ renderShortTitle: true }));105menuActions.dispose();106107return menuContributions;108}109110protected override renderLabel(element: HTMLElement, mode: IChatMode = this.delegate.currentMode.get()): IDisposable | null {111if (!this.element) {112return null;113}114this.setAriaLabelAttributes(element);115const state = this.delegate.currentMode.get().label;116dom.reset(element, dom.$('span.chat-model-label', undefined, state), ...renderLabelWithIcons(`$(chevron-down)`));117return null;118}119120override render(container: HTMLElement): void {121super.render(container);122container.classList.add('chat-modelPicker-item');123}124}125126127