Skip to content

Commit 2adee83

Browse files
Customizations modal redesign (#322043)
* Add prototype design for plugin page in customizations modal * More updates/tweaks * More updates/tweaks * More updates * Refactor AI customization components and tests for improved functionality - Enhance aiCustomizationListWidget and related management editors. - Introduce aiCustomizationPresentation for better UI handling. - Update styles in aiCustomizationManagement.css for consistency. - Improve tests for aiCustomization components to ensure reliability. * Refactor AI customization management and update related tests - Improve aiCustomizationManagementEditor and associated components - Enhance styling in aiCustomizationManagement and welcome prompt - Update tests for aiCustomizationManagementEditor and welcome page * Refactor AI customization components and update related tests * Refactor AI customization components and improve session handling - Update agent host sessions provider for better integration. - Enhance AI customization management editor and presentation. - Optimize embedded agent plugin and MCP server details. - Clean up CSS for AI customization management. - Adjust tests to reflect changes in AI customization components. * Refactor AI customization components and add new tests for coverage * Fix AgentService provider refactor compilation Route failed-turn resume through the provider service and use the existing provider registration helper in its tests.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address customization editor review feedback Preserve live MCP and plugin detail controls, map remote MCP resources correctly, defer marketplace and editor work until visible, scope hook discovery by storage, and make card-list metadata linear.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix customization CI regressions Keep Agent Host provider mapping compatible with lightweight providers and accept the reviewed component screenshot baselines generated by CI.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Update customization screenshot baselines Accept the reviewed Agent Host migration and welcome-page hashes generated by the blocks-CI Ubuntu run.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 8a90852 commit 2adee83

50 files changed

Lines changed: 6827 additions & 1592 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/vs/sessions/common/agentHostSessionsProvider.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { URI } from '../../base/common/uri.js';
1010
import { AuthenticateParams, AuthenticateResult, IAgentConnection } from '../../platform/agentHost/common/agentService.js';
1111
import { RemoteAgentHostConnectionStatus } from '../../platform/agentHost/common/remoteAgentHostService.js';
1212
import { ResolveSessionConfigResult, SessionConfigValueItem } from '../../platform/agentHost/common/state/protocol/commands.js';
13-
import { AgentCustomization, Customization, McpServerStatus, RootConfigState, type CustomizationEnablement, type McpServerState, type RootState } from '../../platform/agentHost/common/state/protocol/state.js';
13+
import { AgentCustomization, Customization, McpServerStatus, RootConfigState, type CustomizationEnablement, type McpServerState, type RootState, type TextRange } from '../../platform/agentHost/common/state/protocol/state.js';
1414
import { type CustomizationDisabledReason } from '../../platform/agentHost/common/customizationEnablement.js';
1515
import { ISessionsProvider } from '../services/sessions/common/sessionsProvider.js';
1616
import { ISessionAgentRef } from '../services/sessions/common/session.js';
@@ -40,6 +40,8 @@ export interface IAgentHostMcpServer {
4040
readonly disabledReason?: CustomizationDisabledReason;
4141
readonly status: McpServerStatus;
4242
readonly state: McpServerState;
43+
readonly sourceUri?: URI;
44+
readonly sourceRange?: TextRange;
4345
readonly logOutputChannelId?: string;
4446
/** Starts or restarts the server. Providers that cannot control lifecycle may no-op. */
4547
start(): Promise<void>;

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,14 @@ export class SessionsAICustomizationWorkspaceService implements IAICustomization
9595
}
9696

9797
readonly managementSections: readonly AICustomizationManagementSection[] = [
98-
AICustomizationManagementSection.Agents,
98+
AICustomizationManagementSection.Plugins,
99+
AICustomizationManagementSection.McpServers,
99100
AICustomizationManagementSection.Skills,
100101
AICustomizationManagementSection.Instructions,
102+
AICustomizationManagementSection.Agents,
101103
AICustomizationManagementSection.Hooks,
102-
AICustomizationManagementSection.Automations,
103-
AICustomizationManagementSection.McpServers,
104-
AICustomizationManagementSection.Plugins,
105104
AICustomizationManagementSection.Tools,
105+
AICustomizationManagementSection.Automations,
106106
AICustomizationManagementSection.HarnessSettings,
107107
];
108108

src/vs/sessions/contrib/sessions/browser/customizationsToolbar.contribution.ts

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,18 @@ const CUSTOMIZATION_OVERVIEW_ITEM: ICustomizationItemConfig = {
6868

6969
export const CUSTOMIZATION_ITEMS: ICustomizationItemConfig[] = [
7070
{
71-
id: 'sessions.customization.agents',
72-
label: localize('agents', "Agents"),
73-
icon: agentIcon,
74-
section: AICustomizationManagementSection.Agents,
75-
modelSection: AICustomizationManagementSection.Agents,
71+
id: 'sessions.customization.plugins',
72+
label: localize('plugins', "Plugins"),
73+
icon: pluginIcon,
74+
section: AICustomizationManagementSection.Plugins,
75+
isPlugins: true,
76+
},
77+
{
78+
id: 'sessions.customization.mcpServers',
79+
label: localize('mcpServers', "MCP Servers"),
80+
icon: mcpServerIcon,
81+
section: AICustomizationManagementSection.McpServers,
82+
isMcp: true,
7683
},
7784
{
7885
id: 'sessions.customization.skills',
@@ -88,27 +95,20 @@ export const CUSTOMIZATION_ITEMS: ICustomizationItemConfig[] = [
8895
section: AICustomizationManagementSection.Instructions,
8996
modelSection: AICustomizationManagementSection.Instructions,
9097
},
98+
{
99+
id: 'sessions.customization.agents',
100+
label: localize('agents', "Agents"),
101+
icon: agentIcon,
102+
section: AICustomizationManagementSection.Agents,
103+
modelSection: AICustomizationManagementSection.Agents,
104+
},
91105
{
92106
id: 'sessions.customization.hooks',
93107
label: localize('hooks', "Hooks"),
94108
icon: hookIcon,
95109
section: AICustomizationManagementSection.Hooks,
96110
modelSection: AICustomizationManagementSection.Hooks,
97111
},
98-
{
99-
id: 'sessions.customization.mcpServers',
100-
label: localize('mcpServers', "MCP Servers"),
101-
icon: mcpServerIcon,
102-
section: AICustomizationManagementSection.McpServers,
103-
isMcp: true,
104-
},
105-
{
106-
id: 'sessions.customization.plugins',
107-
label: localize('plugins', "Plugins"),
108-
icon: pluginIcon,
109-
section: AICustomizationManagementSection.Plugins,
110-
isPlugins: true,
111-
},
112112
{
113113
id: 'sessions.customization.tools',
114114
label: localize('tools', "Tools"),
@@ -131,6 +131,7 @@ export async function openCustomizationOverviewPage(editorService: IEditorServic
131131
}
132132

133133
const input = AICustomizationManagementEditorInput.getOrCreate();
134+
input.setTargetLabel(harnessService.getActiveDescriptor().label);
134135
const pane = await editorService.openEditor(input, { pinned: true });
135136
if (pane instanceof AICustomizationManagementEditor) {
136137
pane.showWelcomePage();
@@ -144,6 +145,7 @@ async function openCustomizationSectionPage(editorService: IEditorService, harne
144145
}
145146

146147
const input = AICustomizationManagementEditorInput.getOrCreate();
148+
input.setTargetLabel(harnessService.getActiveDescriptor().label);
147149
const pane = await editorService.openEditor(input, { pinned: true });
148150
if (pane instanceof AICustomizationManagementEditor) {
149151
pane.selectSectionById(section);

src/vs/sessions/services/agentHost/browser/agentHostCustomizationService.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { URI } from '../../../../base/common/uri.js';
7+
import { identityAgentHostResourceUriMapper } from '../../../../platform/agentHost/common/agentHostUri.js';
78
import { combinedDisposable, DisposableMap } from '../../../../base/common/lifecycle.js';
89
import { basename, isEqual } from '../../../../base/common/resources.js';
910
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
@@ -69,6 +70,7 @@ export class AgentHostCustomizationService extends AbstractAgentHostCustomizatio
6970
}
7071
return {
7172
customizations: provider.getCustomizations(session.sessionId),
73+
resourceUris: provider.getFeedbackAnnotationsChannel?.(session.sessionId)?.connection.resourceUris ?? identityAgentHostResourceUriMapper,
7274
workingDirectory: provider.getWorkingDirectory(session.sessionId),
7375
workingDirectories: provider.getWorkingDirectories(session.sessionId),
7476
rootConfig: provider.getRootConfig(),

src/vs/workbench/contrib/chat/browser/agentPluginActions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export class InstallPluginAction extends Action {
3838
() => pluginInstallService.installPlugin({
3939
name: item.name,
4040
description: item.description,
41-
version: '',
41+
version: item.version ?? '',
4242
source: item.source,
4343
sourceDescriptor: item.sourceDescriptor,
4444
marketplace: item.marketplace,

src/vs/workbench/contrib/chat/browser/agentPluginEditor/agentPluginEditor.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ export class AgentPluginEditor extends EditorPane {
224224
const expectedUri = this.pluginInstallService.getPluginInstallUri({
225225
name: item.name,
226226
description: item.description,
227-
version: '',
227+
version: item.version ?? '',
228228
source: item.source,
229229
sourceDescriptor: item.sourceDescriptor,
230230
marketplace: item.marketplace,
@@ -246,6 +246,7 @@ export class AgentPluginEditor extends EditorPane {
246246
kind: AgentPluginItemKind.Marketplace,
247247
name: item.name,
248248
description: mp.description,
249+
version: mp.version,
249250
source: mp.source,
250251
sourceDescriptor: mp.sourceDescriptor,
251252
marketplace: mp.marketplace,

src/vs/workbench/contrib/chat/browser/agentPluginEditor/agentPluginItems.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export interface IMarketplacePluginItem {
2626
readonly kind: AgentPluginItemKind.Marketplace;
2727
readonly name: string;
2828
readonly description: string;
29+
readonly version?: string;
2930
readonly source: string;
3031
readonly sourceDescriptor: IPluginSourceDescriptor;
3132
readonly marketplace: string;

src/vs/workbench/contrib/chat/browser/agentPluginsView.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ function marketplacePluginToItem(plugin: IMarketplacePlugin): IMarketplacePlugin
6969
kind: AgentPluginItemKind.Marketplace,
7070
name: plugin.name,
7171
description: plugin.description,
72+
version: plugin.version,
7273
source: plugin.source,
7374
sourceDescriptor: plugin.sourceDescriptor,
7475
marketplace: plugin.marketplace,
@@ -466,7 +467,7 @@ export class AgentPluginsListView extends AbstractExtensionsListView<IAgentPlugi
466467
const expectedUri = this.pluginInstallService.getPluginInstallUri({
467468
name: m.name,
468469
description: m.description,
469-
version: '',
470+
version: m.version ?? '',
470471
source: m.source,
471472
sourceDescriptor: m.sourceDescriptor,
472473
marketplace: m.marketplace,

src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostChatContribution.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,10 +320,9 @@ export class AgentHostContribution extends Disposable implements IWorkbenchContr
320320
syncedUri => this._activeClientService.getOrigin(syncedUri)));
321321
itemProvider.setDraftCustomAgents(ambientScope.customAgents);
322322
itemProvider.setDraftCustomizations(ambientScope.customizations);
323-
// `[Agent Host]` suffix disambiguates from the extension-host Copilot CLI harness, which uses the same displayName.
324323
store.add(this._customizationHarnessService.registerExternalHarness({
325324
id: sessionType,
326-
label: localize('agentHostHarnessLabel.local', "{0} [Agent Host]", agent.displayName),
325+
label: agent.displayName,
327326
icon: ThemeIcon.fromId(Codicon.server.id),
328327
// The Tools section is surfaced for the Copilot CLI agent host only.
329328
hiddenSections: agent.provider === 'copilotcli' ? [AICustomizationManagementSection.Prompts] : [AICustomizationManagementSection.Tools, AICustomizationManagementSection.Prompts],

src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostCustomizationService.ts

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { Disposable, DisposableResourceMap, IDisposable, toDisposable } from '..
1010
import { ResourceSet } from '../../../../../../base/common/map.js';
1111
import { AgentHostMcpServers, AgentHostMcpServersConfigKey } from '../../../../../../platform/agentHost/common/agentHostSchema.js';
1212
import { IAgentConnection } from '../../../../../../platform/agentHost/common/agentService.js';
13+
import { IAgentHostResourceUriMapper } from '../../../../../../platform/agentHost/common/agentHostUri.js';
1314
import { IAgentHostConnectionsService, IAgentHostSessionResolution } from '../../../../../../platform/agentHost/common/agentHostConnectionsService.js';
1415
import { getEffectiveAgents } from '../../../../../../platform/agentHost/common/customAgents.js';
1516
import { getCustomizationDisabledReason, isCustomizationEnabled, withCustomizationEnablement } from '../../../../../../platform/agentHost/common/customizationEnablement.js';
@@ -135,6 +136,7 @@ export class NullAgentHostCustomizationService implements IAgentHostCustomizatio
135136

136137
export interface IAgentHostCustomizationTarget {
137138
readonly customizations: readonly Customization[];
139+
readonly resourceUris: IAgentHostResourceUriMapper;
138140
readonly folderPickerDecision?: ISessionFolderPickerDecision;
139141
readonly workingDirectory?: string;
140142
readonly workingDirectories?: readonly string[];
@@ -201,22 +203,27 @@ export abstract class AbstractAgentHostCustomizationService extends Disposable i
201203
return [];
202204
}
203205
return getPresentableMcpServerCustomizations(target.customizations)
204-
.map(({ server, plugin }): IAgentHostMcpServer => ({
205-
id: this._scopedMcpServerId(sessionResource, server.id),
206-
name: server.name,
207-
enabled: isCustomizationEnabled(server) && (!plugin || isCustomizationEnabled(plugin)),
208-
enablement: server.enablement,
209-
isPluginProvided: plugin !== undefined,
210-
isClientBundled: plugin !== undefined && target.isBundledMcpServer(plugin.uri, server.name),
211-
owningPluginClientId: plugin?.clientId,
212-
disabledReason: getCustomizationDisabledReason(server, plugin),
213-
status: server.state.kind,
214-
state: server.state,
215-
logOutputChannelId: channelIdForMcpServer(sessionResource.toString(), server.id),
216-
setEnabled: (enabled: boolean) => target.setCustomizationEnablement(server.id, withCustomizationEnablement(server.enablement, CustomizationEnablementKind.Session, { kind: CustomizationEnablementKind.Session, enabled })),
217-
start: () => target.startMcpServer(server.id),
218-
stop: () => target.stopMcpServer(server.id),
219-
}));
206+
.map(({ server, plugin }): IAgentHostMcpServer => {
207+
const source = URI.parse(server.uri);
208+
return {
209+
id: this._scopedMcpServerId(sessionResource, server.id),
210+
name: server.name,
211+
enabled: isCustomizationEnabled(server) && (!plugin || isCustomizationEnabled(plugin)),
212+
enablement: server.enablement,
213+
isPluginProvided: plugin !== undefined,
214+
isClientBundled: plugin !== undefined && target.isBundledMcpServer(plugin.uri, server.name),
215+
owningPluginClientId: plugin?.clientId,
216+
disabledReason: getCustomizationDisabledReason(server, plugin),
217+
status: server.state.kind,
218+
state: server.state,
219+
sourceUri: source.scheme === 'mcp-top-level' ? undefined : target.resourceUris.fromAgentHost(source),
220+
sourceRange: server.range,
221+
logOutputChannelId: channelIdForMcpServer(sessionResource.toString(), server.id),
222+
setEnabled: (enabled: boolean) => target.setCustomizationEnablement(server.id, withCustomizationEnablement(server.enablement, CustomizationEnablementKind.Session, { kind: CustomizationEnablementKind.Session, enabled })),
223+
start: () => target.startMcpServer(server.id),
224+
stop: () => target.stopMcpServer(server.id),
225+
};
226+
});
220227
}
221228

222229
showMcpServerLog(sessionResource: URI, serverId: string, beforeShow?: () => Promise<void>): Promise<void> {
@@ -481,6 +488,7 @@ class WorkbenchAgentHostCustomizationService extends AbstractAgentHostCustomizat
481488
const channel = target.backendSession.toString();
482489
return {
483490
customizations: sessionState?.customizations ?? [],
491+
resourceUris: target.connection.resourceUris,
484492
folderPickerDecision: readSessionFolderPickerDecision(sessionState?._meta),
485493
workingDirectory: sessionState?.workingDirectories?.[0],
486494
workingDirectories: sessionState?.workingDirectories,

0 commit comments

Comments
 (0)