mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-02 16:25:00 +01:00
Show manage models action in the search input (#300165)
* Add filter actions to ActionList and manage models option in chat model picker * Refactor model picker to support additional entries and improve manage models action handling * Refactor model picker to conditionally add separator for additional entries and streamline manage models action handling * Improve manage models action visibility logic in ModelPickerWidget * Refactor model picker to streamline additional entry handling and improve action management * Refactor model picker to integrate manage models action and streamline additional entry handling
This commit is contained in:
committed by
GitHub
parent
812058f3c3
commit
4a4e6624c3
@@ -359,6 +359,11 @@ export interface IActionListOptions {
|
||||
*/
|
||||
readonly filterPlaceholder?: string;
|
||||
|
||||
/**
|
||||
* Optional actions shown in the filter row, to the right of the input.
|
||||
*/
|
||||
readonly filterActions?: readonly IAction[];
|
||||
|
||||
/**
|
||||
* Section IDs that should be collapsed by default.
|
||||
*/
|
||||
@@ -516,13 +521,21 @@ export class ActionList<T> extends Disposable {
|
||||
if (this._options?.showFilter) {
|
||||
this._filterContainer = document.createElement('div');
|
||||
this._filterContainer.className = 'action-list-filter';
|
||||
const filterRow = dom.append(this._filterContainer, dom.$('.action-list-filter-row'));
|
||||
|
||||
this._filterInput = document.createElement('input');
|
||||
this._filterInput.type = 'text';
|
||||
this._filterInput.className = 'action-list-filter-input';
|
||||
this._filterInput.placeholder = this._options?.filterPlaceholder ?? localize('actionList.filter.placeholder', "Search...");
|
||||
this._filterInput.setAttribute('aria-label', localize('actionList.filter.ariaLabel', "Filter items"));
|
||||
this._filterContainer.appendChild(this._filterInput);
|
||||
filterRow.appendChild(this._filterInput);
|
||||
|
||||
const filterActions = this._options?.filterActions ?? [];
|
||||
if (filterActions.length > 0) {
|
||||
const filterActionsContainer = dom.append(filterRow, dom.$('.action-list-filter-actions'));
|
||||
const filterActionBar = this._register(new ActionBar(filterActionsContainer));
|
||||
filterActionBar.push(filterActions, { icon: true, label: false });
|
||||
}
|
||||
|
||||
this._register(dom.addDisposableListener(this._filterInput, 'input', () => {
|
||||
this._filterText = this._filterInput!.value;
|
||||
|
||||
@@ -265,7 +265,13 @@
|
||||
|
||||
/* Filter input */
|
||||
.action-widget .action-list-filter {
|
||||
padding: 2px 2px 4px 2px
|
||||
padding: 2px 2px 4px 2px;
|
||||
}
|
||||
|
||||
.action-widget .action-list-filter-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.action-widget .action-list-filter:first-child {
|
||||
@@ -278,6 +284,7 @@
|
||||
|
||||
.action-widget .action-list-filter-input {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
box-sizing: border-box;
|
||||
padding: 4px 8px;
|
||||
border: 1px solid var(--vscode-input-border, transparent);
|
||||
@@ -294,3 +301,12 @@
|
||||
.action-widget .action-list-filter-input::placeholder {
|
||||
color: var(--vscode-input-placeholderForeground);
|
||||
}
|
||||
|
||||
.action-widget .action-list-filter-actions .action-label {
|
||||
padding: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.action-widget .action-list-filter-actions .action-label:hover {
|
||||
background-color: var(--vscode-toolbar-hoverBackground);
|
||||
}
|
||||
|
||||
@@ -109,6 +109,27 @@ function createModelAction(
|
||||
};
|
||||
}
|
||||
|
||||
function shouldShowManageModelsAction(chatEntitlementService: IChatEntitlementService): boolean {
|
||||
return chatEntitlementService.entitlement === ChatEntitlement.Free ||
|
||||
chatEntitlementService.entitlement === ChatEntitlement.Pro ||
|
||||
chatEntitlementService.entitlement === ChatEntitlement.ProPlus ||
|
||||
chatEntitlementService.entitlement === ChatEntitlement.Business ||
|
||||
chatEntitlementService.entitlement === ChatEntitlement.Enterprise ||
|
||||
chatEntitlementService.isInternal;
|
||||
}
|
||||
|
||||
function createManageModelsAction(commandService: ICommandService): IActionWidgetDropdownAction {
|
||||
return {
|
||||
id: 'manageModels',
|
||||
enabled: true,
|
||||
checked: false,
|
||||
class: ThemeIcon.asClassName(Codicon.gear),
|
||||
tooltip: localize('chat.manageModels.tooltip', "Manage Language Models"),
|
||||
label: localize('chat.manageModels', "Manage Models..."),
|
||||
run: () => { commandService.executeCommand(MANAGE_CHAT_COMMAND_ID); }
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the grouped items for the model picker dropdown.
|
||||
*
|
||||
@@ -118,7 +139,7 @@ function createModelAction(
|
||||
* - Available models sorted alphabetically, followed by unavailable models
|
||||
* - Unavailable models show upgrade/update/admin status
|
||||
* 3. Other Models (collapsible toggle, available first, then sorted by vendor then name)
|
||||
* - Last item is "Manage Models..." (always visible during filtering)
|
||||
* 4. Optional "Manage Models..." action shown in Other Models after a separator
|
||||
*/
|
||||
export function buildModelPickerItems(
|
||||
models: ILanguageModelChatMetadataAndIdentifier[],
|
||||
@@ -130,7 +151,7 @@ export function buildModelPickerItems(
|
||||
onSelect: (model: ILanguageModelChatMetadataAndIdentifier) => void,
|
||||
manageSettingsUrl: string | undefined,
|
||||
canManageModels: boolean,
|
||||
commandService: ICommandService,
|
||||
manageModelsAction: IActionWidgetDropdownAction | undefined,
|
||||
chatEntitlementService: IChatEntitlementService,
|
||||
): IActionListItem<IActionWidgetDropdownAction>[] {
|
||||
const items: IActionListItem<IActionWidgetDropdownAction>[] = [];
|
||||
@@ -340,27 +361,12 @@ export function buildModelPickerItems(
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
chatEntitlementService.entitlement === ChatEntitlement.Free ||
|
||||
chatEntitlementService.entitlement === ChatEntitlement.Pro ||
|
||||
chatEntitlementService.entitlement === ChatEntitlement.ProPlus ||
|
||||
chatEntitlementService.entitlement === ChatEntitlement.Business ||
|
||||
chatEntitlementService.entitlement === ChatEntitlement.Enterprise ||
|
||||
chatEntitlementService.isInternal
|
||||
) {
|
||||
if (manageModelsAction) {
|
||||
items.push({ kind: ActionListItemKind.Separator, section: otherModels.length ? ModelPickerSection.Other : undefined });
|
||||
items.push({
|
||||
item: {
|
||||
id: 'manageModels',
|
||||
enabled: true,
|
||||
checked: false,
|
||||
class: undefined,
|
||||
tooltip: localize('chat.manageModels.tooltip', "Manage Language Models"),
|
||||
label: localize('chat.manageModels', "Manage Models..."),
|
||||
run: () => { commandService.executeCommand(MANAGE_CHAT_COMMAND_ID); }
|
||||
},
|
||||
item: manageModelsAction,
|
||||
kind: ActionListItemKind.Action,
|
||||
label: localize('chat.manageModels', "Manage Models..."),
|
||||
label: manageModelsAction.label,
|
||||
group: { title: '', icon: Codicon.blank },
|
||||
hideIcon: false,
|
||||
section: otherModels.length ? ModelPickerSection.Other : undefined,
|
||||
@@ -562,9 +568,12 @@ export class ModelPickerWidget extends Disposable {
|
||||
};
|
||||
|
||||
const models = this._delegate.getModels();
|
||||
const showFilter = models.length >= 10;
|
||||
const isPro = isProUser(this._entitlementService.entitlement);
|
||||
const manifest = this._languageModelsService.getModelsControlManifest();
|
||||
const controlModelsForTier = isPro ? manifest.paid : manifest.free;
|
||||
const canShowManageModelsAction = this._delegate.canManageModels() && shouldShowManageModelsAction(this._entitlementService);
|
||||
const manageModelsAction = canShowManageModelsAction ? createManageModelsAction(this._commandService) : undefined;
|
||||
const items = buildModelPickerItems(
|
||||
models,
|
||||
this._selectedModel?.identifier,
|
||||
@@ -575,13 +584,14 @@ export class ModelPickerWidget extends Disposable {
|
||||
onSelect,
|
||||
this._productService.defaultChatAgent?.manageSettingsUrl,
|
||||
this._delegate.canManageModels(),
|
||||
this._commandService,
|
||||
!showFilter ? manageModelsAction : undefined,
|
||||
this._entitlementService,
|
||||
);
|
||||
|
||||
const listOptions = {
|
||||
showFilter: models.length >= 10,
|
||||
showFilter,
|
||||
filterPlaceholder: localize('chat.modelPicker.search', "Search models"),
|
||||
filterActions: showFilter && manageModelsAction ? [manageModelsAction] : undefined,
|
||||
focusFilterOnOpen: true,
|
||||
collapsedByDefault: new Set([ModelPickerSection.Other]),
|
||||
minWidth: 200,
|
||||
|
||||
@@ -10,7 +10,6 @@ import { IStringDictionary } from '../../../../../../../base/common/collections.
|
||||
import { MarkdownString } from '../../../../../../../base/common/htmlContent.js';
|
||||
import { ActionListItemKind, IActionListItem } from '../../../../../../../platform/actionWidget/browser/actionList.js';
|
||||
import { IActionWidgetDropdownAction } from '../../../../../../../platform/actionWidget/browser/actionWidgetDropdown.js';
|
||||
import { ICommandService } from '../../../../../../../platform/commands/common/commands.js';
|
||||
import { StateType } from '../../../../../../../platform/update/common/update.js';
|
||||
import { buildModelPickerItems, getModelPickerAccessibilityProvider } from '../../../../browser/widget/input/chatModelPicker.js';
|
||||
import { ILanguageModelChatMetadata, ILanguageModelChatMetadataAndIdentifier, IModelControlEntry } from '../../../../common/languageModels.js';
|
||||
@@ -48,13 +47,6 @@ function createAutoModel(): ILanguageModelChatMetadataAndIdentifier {
|
||||
return createModel('auto', 'Auto', 'copilot');
|
||||
}
|
||||
|
||||
const stubCommandService: ICommandService = {
|
||||
_serviceBrand: undefined,
|
||||
onWillExecuteCommand: () => ({ dispose() { } }),
|
||||
onDidExecuteCommand: () => ({ dispose() { } }),
|
||||
executeCommand: () => Promise.resolve(undefined),
|
||||
};
|
||||
|
||||
function getActionItems(items: IActionListItem<IActionWidgetDropdownAction>[]): IActionListItem<IActionWidgetDropdownAction>[] {
|
||||
return items.filter(i => i.kind === ActionListItemKind.Action);
|
||||
}
|
||||
@@ -67,6 +59,16 @@ function getSeparatorCount(items: IActionListItem<IActionWidgetDropdownAction>[]
|
||||
return items.filter(i => i.kind === ActionListItemKind.Separator).length;
|
||||
}
|
||||
|
||||
const stubManageModelsAction: IActionWidgetDropdownAction = {
|
||||
id: 'manageModels',
|
||||
enabled: true,
|
||||
checked: false,
|
||||
class: undefined,
|
||||
tooltip: 'Manage Language Models',
|
||||
label: 'Manage Models...',
|
||||
run: () => { }
|
||||
};
|
||||
|
||||
function callBuild(
|
||||
models: ILanguageModelChatMetadataAndIdentifier[],
|
||||
opts: {
|
||||
@@ -95,7 +97,7 @@ function callBuild(
|
||||
onSelect,
|
||||
opts.manageSettingsUrl,
|
||||
true,
|
||||
stubCommandService,
|
||||
stubManageModelsAction,
|
||||
entitlementService,
|
||||
);
|
||||
}
|
||||
@@ -470,7 +472,7 @@ suite('buildModelPickerItems', () => {
|
||||
onSelect,
|
||||
undefined,
|
||||
true,
|
||||
stubCommandService,
|
||||
undefined,
|
||||
stubChatEntitlementService,
|
||||
);
|
||||
const gptItem = getActionItems(items).find(a => a.label === 'GPT-4o');
|
||||
@@ -552,7 +554,7 @@ suite('buildModelPickerItems', () => {
|
||||
() => { },
|
||||
'https://aka.ms/github-copilot-settings',
|
||||
true,
|
||||
stubCommandService,
|
||||
undefined,
|
||||
stubChatEntitlementService,
|
||||
);
|
||||
|
||||
@@ -635,7 +637,7 @@ suite('buildModelPickerItems', () => {
|
||||
onSelect,
|
||||
undefined,
|
||||
true,
|
||||
stubCommandService,
|
||||
undefined,
|
||||
anonymousEntitlementService,
|
||||
);
|
||||
const gptItem = getActionItems(items).find(a => a.label === 'GPT-4o');
|
||||
|
||||
Reference in New Issue
Block a user