Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/chat/browser/modelPicker/modelPickerActionItem.ts
3296 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 { IAction } from '../../../../../base/common/actions.js';
7
import { Event } from '../../../../../base/common/event.js';
8
import { ILanguageModelChatMetadataAndIdentifier } from '../../common/languageModels.js';
9
import { localize } from '../../../../../nls.js';
10
import * as dom from '../../../../../base/browser/dom.js';
11
import { renderLabelWithIcons } from '../../../../../base/browser/ui/iconLabel/iconLabels.js';
12
import { IDisposable } from '../../../../../base/common/lifecycle.js';
13
import { ActionWidgetDropdownActionViewItem } from '../../../../../platform/actions/browser/actionWidgetDropdownActionViewItem.js';
14
import { IActionWidgetService } from '../../../../../platform/actionWidget/browser/actionWidget.js';
15
import { IActionWidgetDropdownAction, IActionWidgetDropdownActionProvider, IActionWidgetDropdownOptions } from '../../../../../platform/actionWidget/browser/actionWidgetDropdown.js';
16
import { IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js';
17
import { ICommandService } from '../../../../../platform/commands/common/commands.js';
18
import { ChatEntitlement, IChatEntitlementService } from '../../common/chatEntitlementService.js';
19
import { IKeybindingService } from '../../../../../platform/keybinding/common/keybinding.js';
20
import { DEFAULT_MODEL_PICKER_CATEGORY } from '../../common/modelPicker/modelPickerWidget.js';
21
import { ManageModelsAction } from '../actions/manageModelsActions.js';
22
import { IActionProvider } from '../../../../../base/browser/ui/dropdown/dropdown.js';
23
24
export interface IModelPickerDelegate {
25
readonly onDidChangeModel: Event<ILanguageModelChatMetadataAndIdentifier>;
26
getCurrentModel(): ILanguageModelChatMetadataAndIdentifier | undefined;
27
setModel(model: ILanguageModelChatMetadataAndIdentifier): void;
28
getModels(): ILanguageModelChatMetadataAndIdentifier[];
29
}
30
31
function modelDelegateToWidgetActionsProvider(delegate: IModelPickerDelegate): IActionWidgetDropdownActionProvider {
32
return {
33
getActions: () => {
34
return delegate.getModels().map(model => {
35
return {
36
id: model.metadata.id,
37
enabled: true,
38
icon: model.metadata.statusIcon,
39
checked: model.identifier === delegate.getCurrentModel()?.identifier,
40
category: model.metadata.modelPickerCategory || DEFAULT_MODEL_PICKER_CATEGORY,
41
class: undefined,
42
description: model.metadata.detail,
43
tooltip: model.metadata.tooltip ?? model.metadata.name,
44
label: model.metadata.name,
45
run: () => {
46
delegate.setModel(model);
47
}
48
} satisfies IActionWidgetDropdownAction;
49
});
50
}
51
};
52
}
53
54
function getModelPickerActionBarActionProvider(commandService: ICommandService, chatEntitlementService: IChatEntitlementService): IActionProvider {
55
56
const actionProvider: IActionProvider = {
57
getActions: () => {
58
const additionalActions: IAction[] = [];
59
if (
60
chatEntitlementService.entitlement === ChatEntitlement.Free ||
61
chatEntitlementService.entitlement === ChatEntitlement.Pro ||
62
chatEntitlementService.entitlement === ChatEntitlement.ProPlus ||
63
chatEntitlementService.isInternal
64
) {
65
additionalActions.push({
66
id: 'manageModels',
67
label: localize('chat.manageModels', "Manage Models..."),
68
enabled: true,
69
tooltip: localize('chat.manageModels.tooltip', "Manage language models"),
70
class: undefined,
71
run: () => {
72
const commandId = ManageModelsAction.ID;
73
commandService.executeCommand(commandId);
74
}
75
});
76
}
77
78
// Add upgrade option if entitlement is free
79
if (chatEntitlementService.entitlement === ChatEntitlement.Free) {
80
additionalActions.push({
81
id: 'moreModels',
82
label: localize('chat.moreModels', "Add Premium Models"),
83
enabled: true,
84
tooltip: localize('chat.moreModels.tooltip', "Add premium models"),
85
class: undefined,
86
run: () => {
87
const commandId = 'workbench.action.chat.upgradePlan';
88
commandService.executeCommand(commandId);
89
}
90
});
91
}
92
93
return additionalActions;
94
}
95
};
96
return actionProvider;
97
}
98
99
/**
100
* Action view item for selecting a language model in the chat interface.
101
*/
102
export class ModelPickerActionItem extends ActionWidgetDropdownActionViewItem {
103
constructor(
104
action: IAction,
105
private currentModel: ILanguageModelChatMetadataAndIdentifier | undefined,
106
delegate: IModelPickerDelegate,
107
@IActionWidgetService actionWidgetService: IActionWidgetService,
108
@IContextKeyService contextKeyService: IContextKeyService,
109
@ICommandService commandService: ICommandService,
110
@IChatEntitlementService chatEntitlementService: IChatEntitlementService,
111
@IKeybindingService keybindingService: IKeybindingService,
112
) {
113
// Modify the original action with a different label and make it show the current model
114
const actionWithLabel: IAction = {
115
...action,
116
label: currentModel?.metadata.name ?? localize('chat.modelPicker.label', "Pick Model"),
117
tooltip: localize('chat.modelPicker.label', "Pick Model"),
118
run: () => { }
119
};
120
121
const modelPickerActionWidgetOptions: Omit<IActionWidgetDropdownOptions, 'label' | 'labelRenderer'> = {
122
actionProvider: modelDelegateToWidgetActionsProvider(delegate),
123
actionBarActionProvider: getModelPickerActionBarActionProvider(commandService, chatEntitlementService)
124
};
125
126
super(actionWithLabel, modelPickerActionWidgetOptions, actionWidgetService, keybindingService, contextKeyService);
127
128
// Listen for model changes from the delegate
129
this._register(delegate.onDidChangeModel(model => {
130
this.currentModel = model;
131
if (this.element) {
132
this.renderLabel(this.element);
133
}
134
}));
135
}
136
137
protected override renderLabel(element: HTMLElement): IDisposable | null {
138
const domChildren = [];
139
if (this.currentModel?.metadata.statusIcon) {
140
domChildren.push(...renderLabelWithIcons(`\$(${this.currentModel.metadata.statusIcon.id})`));
141
}
142
domChildren.push(dom.$('span.chat-model-label', undefined, this.currentModel?.metadata.name ?? localize('chat.modelPicker.label', "Pick Model")));
143
domChildren.push(...renderLabelWithIcons(`$(chevron-down)`));
144
145
dom.reset(element, ...domChildren);
146
this.setAriaLabelAttributes(element);
147
return null;
148
}
149
150
override render(container: HTMLElement): void {
151
super.render(container);
152
container.classList.add('chat-modelPicker-item');
153
}
154
}
155
156