Skip to content

Commit 0a10c7c

Browse files
authored
Merge pull request #323201 from microsoft/model-picker-restricted-copy
Model picker: clearer Restricted Mode copy and suppress search
2 parents cd6804d + 6d9a8ec commit 0a10c7c

6 files changed

Lines changed: 36 additions & 25 deletions

File tree

src/vs/sessions/contrib/chat/browser/modelPicker.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,8 @@ export class ModelPicker extends Disposable {
160160
// Re-evaluate when workspace trust changes (or finishes initializing): an
161161
// untrusted workspace disables the model providers, and the shared widget
162162
// then renders its Restricted Mode state. Visibility is recomputed so the
163-
// picker stays visible to surface "Pick Model" + the Trust action instead
164-
// of hiding as an empty picker.
163+
// picker stays visible to surface the "Models" placeholder + the Trust
164+
// action instead of hiding as an empty picker.
165165
this._register(this._workspaceTrustManagementService.onDidChangeTrust(() => this._initModel()));
166166
this._workspaceTrustManagementService.workspaceTrustInitialized.then(() => {
167167
if (!this._store.isDisposed) {

src/vs/sessions/contrib/providers/agentHost/browser/agentHostSessionConfigPicker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -975,7 +975,7 @@ registerAction2(class extends Action2 {
975975
group: 'navigation',
976976
// `OpenModelPickerAction` (the "Auto" model picker) is at order 3
977977
// in the same menu — sit just before it so the mode pill renders
978-
// to the left of "Pick Model".
978+
// to the left of the model picker.
979979
order: 2,
980980
// Hide the agent mode picker while a delegation (continue in) target is pending.
981981
when: ContextKeyExpr.and(ChatContextKeyExprs.isAgentHostSession, ChatContextKeys.hasPendingDelegationTarget.negate()),

src/vs/workbench/contrib/chat/browser/widget/input/chatModelPicker.ts

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ const ModelPickerSection = {
8080
} as const;
8181

8282
/**
83-
* Id of the synthetic "Trust Workspace..." entry shown in Restricted Mode. It is
83+
* Id of the synthetic "Trust Workspace to enable models..." entry shown in Restricted Mode. It is
8484
* a command (not a selectable model), so the accessibility provider gives it a
8585
* plain `menuitem` role instead of `menuitemradio`.
8686
*/
@@ -473,8 +473,9 @@ function createManageModelsAction(commandService: ICommandService): IActionWidge
473473
* 4. Optional "Manage Models..." action shown in Other Models after a separator
474474
*
475475
* When `restrictedMode` is set (untrusted workspace), an explanatory "Models
476-
* Unavailable in Restricted Mode" header and a "Trust Workspace..." action
477-
* (invoking `onRequestTrust`) replace all of the above. Likewise, when
476+
* unavailable while in Restricted mode" header and a "Trust Workspace to enable
477+
* models..." action (invoking `onRequestTrust`) replace all of the above.
478+
* Likewise, when
478479
* `setupRequired` is set (trusted, but Chat still needs sign-in / setup), a
479480
* "Sign in to use Copilot" header and a Sign In action (invoking
480481
* `onRequestSetup`) replace all of the above. `restrictedMode` takes precedence.
@@ -515,20 +516,20 @@ export function buildModelPickerItems(
515516
// non-empty.
516517
items.push({
517518
kind: ActionListItemKind.Header,
518-
label: localize('chat.modelPicker.restrictedMode', "Models Unavailable in Restricted Mode"),
519+
label: localize('chat.modelPicker.restrictedMode', "Models unavailable while in Restricted mode"),
519520
});
520521
items.push({
521522
item: {
522523
id: RESTRICTED_MODE_TRUST_ACTION_ID,
523524
enabled: !!onRequestTrust,
524525
checked: false,
525526
class: undefined,
526-
tooltip: localize('chat.modelPicker.restrictedMode.trustTooltip', "Trust the workspace to enable AI models."),
527-
label: localize('chat.modelPicker.restrictedMode.trust', "Trust Workspace..."),
527+
tooltip: localize('chat.modelPicker.restrictedMode.trustTooltip', "Trust the workspace to enable models."),
528+
label: localize('chat.modelPicker.restrictedMode.trust', "Trust Workspace to enable models..."),
528529
run: () => onRequestTrust?.()
529530
},
530531
kind: ActionListItemKind.Action,
531-
label: localize('chat.modelPicker.restrictedMode.trust', "Trust Workspace..."),
532+
label: localize('chat.modelPicker.restrictedMode.trust', "Trust Workspace to enable models..."),
532533
group: { title: '', icon: ThemeIcon.fromId(Codicon.workspaceTrusted.id) },
533534
disabled: !onRequestTrust,
534535
hideIcon: false,
@@ -1387,9 +1388,14 @@ export class ModelPickerWidget extends Disposable {
13871388
}
13881389
}
13891390

1391+
// Hide the filter in the unavailable states (Restricted Mode / setup
1392+
// required): the only entries are the explanatory header and the Trust /
1393+
// Sign In action, so a search field would just let users filter through
1394+
// stale, unusable models. Shown otherwise (it also hosts the secondary
1395+
// heading).
1396+
const unavailable = this.isRestrictedMode() || this.isSetupRequired();
13901397
const listOptions = {
1391-
// Always show the filter to allow for the secondary heading to show
1392-
showFilter: true,
1398+
showFilter: !unavailable,
13931399
filterPlaceholder: localize('chat.modelPicker.search', "Search models"),
13941400
filterActions: !isUBB && manageModelsAction ? [manageModelsAction] : undefined,
13951401
focusFilterOnOpen: true,
@@ -1466,13 +1472,13 @@ export class ModelPickerWidget extends Disposable {
14661472

14671473
const { name, statusIcon } = this._selectedModel?.metadata || {};
14681474

1469-
// Untrusted workspace: present a normal "Pick Model" placeholder (no badge)
1475+
// Untrusted workspace: present a normal "Models" placeholder (no badge)
14701476
// rather than a dead-end label; the hover and dropdown carry the Restricted
14711477
// Mode explanation and the Trust Workspace action.
14721478
const restrictedMode = this.isRestrictedMode();
14731479

14741480
// Trusted, but Chat still needs sign-in / setup before any model is
1475-
// usable: present the same "Pick Model" placeholder, with the dropdown
1481+
// usable: present the same "Models" placeholder, with the dropdown
14761482
// carrying a Sign In action instead of a misleading "Auto".
14771483
const setupRequired = this.isSetupRequired();
14781484
const unavailable = restrictedMode || setupRequired;
@@ -1495,7 +1501,7 @@ export class ModelPickerWidget extends Disposable {
14951501
nameChildren.push(renderIcon(statusIcon));
14961502
}
14971503
const modelLabel = unavailable
1498-
? localize('chat.modelPicker.label', "Pick Model")
1504+
? localize('chat.modelPicker.modelsLabel', "Models")
14991505
: activating
15001506
? localize('chat.modelPicker.activating', "Activating...")
15011507
: genericNoModels
@@ -1549,12 +1555,13 @@ export class ModelPickerWidget extends Disposable {
15491555
}
15501556
}
15511557

1552-
// Aria
1558+
// Aria — name the control "Models" to match the visible label; the comma
1559+
// separates the control name from its current value / state.
15531560
this._domNode.ariaLabel = restrictedMode
1554-
? localize('chat.modelPicker.ariaLabelRestricted', "Pick Model, models are unavailable in Restricted Mode")
1561+
? localize('chat.modelPicker.ariaLabelRestricted', "Models, unavailable while in Restricted mode")
15551562
: setupRequired
1556-
? localize('chat.modelPicker.ariaLabelSetupRequired', "Pick Model, sign in to use Copilot")
1557-
: localize('chat.modelPicker.ariaLabel', "Pick Model, {0}", fullLabel);
1563+
? localize('chat.modelPicker.ariaLabelSetupRequired', "Models, sign in to use Copilot")
1564+
: localize('chat.modelPicker.ariaLabel', "Models, {0}", fullLabel);
15581565
}
15591566

15601567
/**

src/vs/workbench/contrib/chat/browser/widget/input/chatModelSelectionLogic.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ export function resolveConfiguredModel(
397397

398398
/**
399399
* Why a model picker has no model to offer, when that is the case. Drives a
400-
* "Pick Model" placeholder plus a contextual action instead of a misleading
400+
* "Models" placeholder plus a contextual action instead of a misleading
401401
* lone "Auto".
402402
*/
403403
export const enum ModelPickerUnavailableReason {

src/vs/workbench/contrib/chat/browser/widget/input/modelPickerActionItem.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ export class ModelPickerActionItem extends BaseActionViewItem {
126126
/**
127127
* Whether the picker has no usable model because the workspace is untrusted
128128
* (Restricted Mode). Lets a host (e.g. the sessions picker) keep the picker
129-
* visible to surface the "Pick Model" placeholder and Trust Workspace action
129+
* visible to surface the "Models" placeholder and Trust Workspace action
130130
* instead of hiding it as an empty/no-model picker.
131131
*/
132132
public isRestrictedMode(): boolean {
@@ -136,7 +136,7 @@ export class ModelPickerActionItem extends BaseActionViewItem {
136136
/**
137137
* Whether the picker has no usable model because Chat still needs sign-in /
138138
* setup. Like {@link isRestrictedMode}, lets a host keep the picker visible to
139-
* surface the "Pick Model" placeholder and Sign In action.
139+
* surface the "Models" placeholder and Sign In action.
140140
*/
141141
public isSetupRequired(): boolean {
142142
return this._pickerWidget.isSetupRequired();
@@ -163,13 +163,17 @@ export class ModelPickerActionItem extends BaseActionViewItem {
163163
}
164164

165165
private _getHoverContents(): IManagedHoverContent {
166-
let label = localize('chat.modelPicker.label', "Pick Model");
166+
// Keep the hover prefix in sync with the picker's visible "Models" label
167+
// (the same localization key) so the hover doesn't read "Pick Model • …".
168+
let label = localize('chat.modelPicker.modelsLabel', "Models");
167169
const keybindingLabel = this.keybindingService.lookupKeybinding(this._action.id, this._contextKeyService)?.getLabel();
168170
if (keybindingLabel) {
169171
label += ` (${keybindingLabel})`;
170172
}
171173
if (this._pickerWidget.isRestrictedMode()) {
172-
return localize('chat.modelPicker.restrictedHover', "{0} • Models are unavailable in Restricted Mode. Trust the workspace to choose a model.", label);
174+
// Suffix avoids a leading "Models" so the hover doesn't stutter as
175+
// "Models • Models unavailable…" once the prefix is "Models".
176+
return localize('chat.modelPicker.restrictedHover', "{0} • Unavailable while in Restricted mode. Trust Workspace to enable models.", label);
173177
}
174178
if (this._pickerWidget.isSetupRequired()) {
175179
return localize('chat.modelPicker.setupRequiredHover', "{0} • Sign in to GitHub Copilot to choose a model.", label);

src/vs/workbench/contrib/chat/test/browser/widget/input/chatModelPicker.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ suite('buildModelPickerItems', () => {
266266
const items = callBuild([], { restrictedMode: true, onRequestTrust: () => { } });
267267
const actions = getActionItems(items);
268268
// The explanation is a non-interactive header; only Trust is selectable.
269-
assert.ok(items.some(i => i.kind === ActionListItemKind.Header && i.label === 'Models Unavailable in Restricted Mode'));
269+
assert.ok(items.some(i => i.kind === ActionListItemKind.Header && i.label === 'Models unavailable while in Restricted mode'));
270270
assert.strictEqual(actions.length, 1);
271271
assert.strictEqual(actions[0].item?.id, 'restrictedModeTrust');
272272
assert.strictEqual(actions[0].item?.enabled, true);

0 commit comments

Comments
 (0)