Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/vs/sessions/common/agentHostSessionsProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { URI } from '../../base/common/uri.js';
import { AuthenticateParams, AuthenticateResult, IAgentConnection } from '../../platform/agentHost/common/agentService.js';
import { RemoteAgentHostConnectionStatus } from '../../platform/agentHost/common/remoteAgentHostService.js';
import { ResolveSessionConfigResult, SessionConfigValueItem } from '../../platform/agentHost/common/state/protocol/commands.js';
import { AgentCustomization, Customization, McpServerStatus, RootConfigState, type CustomizationEnablement, type McpServerState, type RootState } from '../../platform/agentHost/common/state/protocol/state.js';
import { AgentCustomization, Customization, McpServerStatus, RootConfigState, type CustomizationEnablement, type McpServerState, type RootState, type TextRange } from '../../platform/agentHost/common/state/protocol/state.js';
import { type CustomizationDisabledReason } from '../../platform/agentHost/common/customizationEnablement.js';
import { ISessionsProvider } from '../services/sessions/common/sessionsProvider.js';
import { ISessionAgentRef } from '../services/sessions/common/session.js';
Expand Down Expand Up @@ -40,6 +40,8 @@ export interface IAgentHostMcpServer {
readonly disabledReason?: CustomizationDisabledReason;
readonly status: McpServerStatus;
readonly state: McpServerState;
readonly sourceUri?: URI;
readonly sourceRange?: TextRange;
readonly logOutputChannelId?: string;
/** Starts or restarts the server. Providers that cannot control lifecycle may no-op. */
start(): Promise<void>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,14 @@ export class SessionsAICustomizationWorkspaceService implements IAICustomization
}

readonly managementSections: readonly AICustomizationManagementSection[] = [
AICustomizationManagementSection.Agents,
AICustomizationManagementSection.Plugins,
AICustomizationManagementSection.McpServers,
AICustomizationManagementSection.Skills,
AICustomizationManagementSection.Instructions,
AICustomizationManagementSection.Agents,
AICustomizationManagementSection.Hooks,
AICustomizationManagementSection.Automations,
AICustomizationManagementSection.McpServers,
AICustomizationManagementSection.Plugins,
AICustomizationManagementSection.Tools,
AICustomizationManagementSection.Automations,
AICustomizationManagementSection.HarnessSettings,
];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,18 @@ const CUSTOMIZATION_OVERVIEW_ITEM: ICustomizationItemConfig = {

export const CUSTOMIZATION_ITEMS: ICustomizationItemConfig[] = [
{
id: 'sessions.customization.agents',
label: localize('agents', "Agents"),
icon: agentIcon,
section: AICustomizationManagementSection.Agents,
modelSection: AICustomizationManagementSection.Agents,
id: 'sessions.customization.plugins',
label: localize('plugins', "Plugins"),
icon: pluginIcon,
section: AICustomizationManagementSection.Plugins,
isPlugins: true,
},
{
id: 'sessions.customization.mcpServers',
label: localize('mcpServers', "MCP Servers"),
icon: mcpServerIcon,
section: AICustomizationManagementSection.McpServers,
isMcp: true,
},
{
id: 'sessions.customization.skills',
Expand All @@ -88,27 +95,20 @@ export const CUSTOMIZATION_ITEMS: ICustomizationItemConfig[] = [
section: AICustomizationManagementSection.Instructions,
modelSection: AICustomizationManagementSection.Instructions,
},
{
id: 'sessions.customization.agents',
label: localize('agents', "Agents"),
icon: agentIcon,
section: AICustomizationManagementSection.Agents,
modelSection: AICustomizationManagementSection.Agents,
},
{
id: 'sessions.customization.hooks',
label: localize('hooks', "Hooks"),
icon: hookIcon,
section: AICustomizationManagementSection.Hooks,
modelSection: AICustomizationManagementSection.Hooks,
},
{
id: 'sessions.customization.mcpServers',
label: localize('mcpServers', "MCP Servers"),
icon: mcpServerIcon,
section: AICustomizationManagementSection.McpServers,
isMcp: true,
},
{
id: 'sessions.customization.plugins',
label: localize('plugins', "Plugins"),
icon: pluginIcon,
section: AICustomizationManagementSection.Plugins,
isPlugins: true,
},
{
id: 'sessions.customization.tools',
label: localize('tools', "Tools"),
Expand All @@ -131,6 +131,7 @@ export async function openCustomizationOverviewPage(editorService: IEditorServic
}

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

const input = AICustomizationManagementEditorInput.getOrCreate();
input.setTargetLabel(harnessService.getActiveDescriptor().label);
const pane = await editorService.openEditor(input, { pinned: true });
if (pane instanceof AICustomizationManagementEditor) {
pane.selectSectionById(section);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/

import { URI } from '../../../../base/common/uri.js';
import { identityAgentHostResourceUriMapper } from '../../../../platform/agentHost/common/agentHostUri.js';
import { combinedDisposable, DisposableMap } from '../../../../base/common/lifecycle.js';
import { basename, isEqual } from '../../../../base/common/resources.js';
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
Expand Down Expand Up @@ -69,6 +70,7 @@ export class AgentHostCustomizationService extends AbstractAgentHostCustomizatio
}
return {
customizations: provider.getCustomizations(session.sessionId),
resourceUris: provider.getFeedbackAnnotationsChannel?.(session.sessionId)?.connection.resourceUris ?? identityAgentHostResourceUriMapper,
workingDirectory: provider.getWorkingDirectory(session.sessionId),
workingDirectories: provider.getWorkingDirectories(session.sessionId),
rootConfig: provider.getRootConfig(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class InstallPluginAction extends Action {
() => pluginInstallService.installPlugin({
name: item.name,
description: item.description,
version: '',
version: item.version ?? '',
source: item.source,
sourceDescriptor: item.sourceDescriptor,
marketplace: item.marketplace,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ export class AgentPluginEditor extends EditorPane {
const expectedUri = this.pluginInstallService.getPluginInstallUri({
name: item.name,
description: item.description,
version: '',
version: item.version ?? '',
source: item.source,
sourceDescriptor: item.sourceDescriptor,
marketplace: item.marketplace,
Expand All @@ -246,6 +246,7 @@ export class AgentPluginEditor extends EditorPane {
kind: AgentPluginItemKind.Marketplace,
name: item.name,
description: mp.description,
version: mp.version,
source: mp.source,
sourceDescriptor: mp.sourceDescriptor,
marketplace: mp.marketplace,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export interface IMarketplacePluginItem {
readonly kind: AgentPluginItemKind.Marketplace;
readonly name: string;
readonly description: string;
readonly version?: string;
readonly source: string;
readonly sourceDescriptor: IPluginSourceDescriptor;
readonly marketplace: string;
Expand Down
3 changes: 2 additions & 1 deletion src/vs/workbench/contrib/chat/browser/agentPluginsView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ function marketplacePluginToItem(plugin: IMarketplacePlugin): IMarketplacePlugin
kind: AgentPluginItemKind.Marketplace,
name: plugin.name,
description: plugin.description,
version: plugin.version,
source: plugin.source,
sourceDescriptor: plugin.sourceDescriptor,
marketplace: plugin.marketplace,
Expand Down Expand Up @@ -466,7 +467,7 @@ export class AgentPluginsListView extends AbstractExtensionsListView<IAgentPlugi
const expectedUri = this.pluginInstallService.getPluginInstallUri({
name: m.name,
description: m.description,
version: '',
version: m.version ?? '',
source: m.source,
sourceDescriptor: m.sourceDescriptor,
marketplace: m.marketplace,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,10 +320,9 @@ export class AgentHostContribution extends Disposable implements IWorkbenchContr
syncedUri => this._activeClientService.getOrigin(syncedUri)));
itemProvider.setDraftCustomAgents(ambientScope.customAgents);
itemProvider.setDraftCustomizations(ambientScope.customizations);
// `[Agent Host]` suffix disambiguates from the extension-host Copilot CLI harness, which uses the same displayName.
store.add(this._customizationHarnessService.registerExternalHarness({
id: sessionType,
label: localize('agentHostHarnessLabel.local', "{0} [Agent Host]", agent.displayName),
label: agent.displayName,
icon: ThemeIcon.fromId(Codicon.server.id),
// The Tools section is surfaced for the Copilot CLI agent host only.
hiddenSections: agent.provider === 'copilotcli' ? [AICustomizationManagementSection.Prompts] : [AICustomizationManagementSection.Tools, AICustomizationManagementSection.Prompts],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Disposable, DisposableResourceMap, IDisposable, toDisposable } from '..
import { ResourceSet } from '../../../../../../base/common/map.js';
import { AgentHostMcpServers, AgentHostMcpServersConfigKey } from '../../../../../../platform/agentHost/common/agentHostSchema.js';
import { IAgentConnection } from '../../../../../../platform/agentHost/common/agentService.js';
import { IAgentHostResourceUriMapper } from '../../../../../../platform/agentHost/common/agentHostUri.js';
import { IAgentHostConnectionsService, IAgentHostSessionResolution } from '../../../../../../platform/agentHost/common/agentHostConnectionsService.js';
import { getEffectiveAgents } from '../../../../../../platform/agentHost/common/customAgents.js';
import { getCustomizationDisabledReason, isCustomizationEnabled, withCustomizationEnablement } from '../../../../../../platform/agentHost/common/customizationEnablement.js';
Expand Down Expand Up @@ -135,6 +136,7 @@ export class NullAgentHostCustomizationService implements IAgentHostCustomizatio

export interface IAgentHostCustomizationTarget {
readonly customizations: readonly Customization[];
readonly resourceUris: IAgentHostResourceUriMapper;
readonly folderPickerDecision?: ISessionFolderPickerDecision;
readonly workingDirectory?: string;
readonly workingDirectories?: readonly string[];
Expand Down Expand Up @@ -201,22 +203,27 @@ export abstract class AbstractAgentHostCustomizationService extends Disposable i
return [];
}
return getPresentableMcpServerCustomizations(target.customizations)
.map(({ server, plugin }): IAgentHostMcpServer => ({
id: this._scopedMcpServerId(sessionResource, server.id),
name: server.name,
enabled: isCustomizationEnabled(server) && (!plugin || isCustomizationEnabled(plugin)),
enablement: server.enablement,
isPluginProvided: plugin !== undefined,
isClientBundled: plugin !== undefined && target.isBundledMcpServer(plugin.uri, server.name),
owningPluginClientId: plugin?.clientId,
disabledReason: getCustomizationDisabledReason(server, plugin),
status: server.state.kind,
state: server.state,
logOutputChannelId: channelIdForMcpServer(sessionResource.toString(), server.id),
setEnabled: (enabled: boolean) => target.setCustomizationEnablement(server.id, withCustomizationEnablement(server.enablement, CustomizationEnablementKind.Session, { kind: CustomizationEnablementKind.Session, enabled })),
start: () => target.startMcpServer(server.id),
stop: () => target.stopMcpServer(server.id),
}));
.map(({ server, plugin }): IAgentHostMcpServer => {
const source = URI.parse(server.uri);
return {
id: this._scopedMcpServerId(sessionResource, server.id),
name: server.name,
enabled: isCustomizationEnabled(server) && (!plugin || isCustomizationEnabled(plugin)),
enablement: server.enablement,
isPluginProvided: plugin !== undefined,
isClientBundled: plugin !== undefined && target.isBundledMcpServer(plugin.uri, server.name),
owningPluginClientId: plugin?.clientId,
disabledReason: getCustomizationDisabledReason(server, plugin),
status: server.state.kind,
state: server.state,
sourceUri: source.scheme === 'mcp-top-level' ? undefined : target.resourceUris.fromAgentHost(source),
sourceRange: server.range,
logOutputChannelId: channelIdForMcpServer(sessionResource.toString(), server.id),
setEnabled: (enabled: boolean) => target.setCustomizationEnablement(server.id, withCustomizationEnablement(server.enablement, CustomizationEnablementKind.Session, { kind: CustomizationEnablementKind.Session, enabled })),
start: () => target.startMcpServer(server.id),
stop: () => target.stopMcpServer(server.id),
};
});
}

showMcpServerLog(sessionResource: URI, serverId: string, beforeShow?: () => Promise<void>): Promise<void> {
Expand Down Expand Up @@ -481,6 +488,7 @@ class WorkbenchAgentHostCustomizationService extends AbstractAgentHostCustomizat
const channel = target.backendSession.toString();
return {
customizations: sessionState?.customizations ?? [],
resourceUris: target.connection.resourceUris,
folderPickerDecision: readSessionFolderPickerDecision(sessionState?._meta),
workingDirectory: sessionState?.workingDirectories?.[0],
workingDirectories: sessionState?.workingDirectories,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { parse as parseJSONC } from '../../../../../base/common/json.js';
import { ResourceMap } from '../../../../../base/common/map.js';
import { Schemas } from '../../../../../base/common/network.js';
import { OS } from '../../../../../base/common/platform.js';
import { basename, dirname } from '../../../../../base/common/resources.js';
import { basename } from '../../../../../base/common/resources.js';
import { ThemeIcon } from '../../../../../base/common/themables.js';
import { URI } from '../../../../../base/common/uri.js';
import { localize } from '../../../../../nls.js';
Expand Down Expand Up @@ -277,7 +277,7 @@ export async function mergeBuiltinSkills(
items: readonly IAICustomizationListItem[],
promptType: PromptsType,
promptsService: IPromptsService,
workspaceService: IAICustomizationWorkspaceService,
_workspaceService: IAICustomizationWorkspaceService,
itemNormalizer: AICustomizationItemNormalizer,
): Promise<IAICustomizationListItem[]> {
const builtinPaths: readonly { uri: URI; name?: string; description?: string }[] = await promptsService.listPromptFilesForStorage(PromptsType.skill, PromptsStorage.builtIn, CancellationToken.None);
Expand All @@ -294,9 +294,6 @@ export async function mergeBuiltinSkills(
// re-discovered the bundled copy by scanning disk).
const deduped = items.filter(item => !builtinUris.has(item.uri));

const uiIntegrations = workspaceService.getSkillUIIntegrations();
const uiIntegrationBadge = localize('uiIntegrationBadge', "UI Integration");

// Collect names of user/workspace skills so we can hide the built-in
// copy once the user has added an override at either level.
const overriddenNames = new Set<string>();
Expand All @@ -321,8 +318,6 @@ export async function mergeBuiltinSkills(
if (overriddenNames.has(name)) {
continue;
}
const folderName = basename(dirname(p.uri));
const uiTooltip = uiIntegrations.get(folderName);
const builtinItem: ICustomizationItem = {
uri: p.uri,
type: PromptsType.skill,
Expand All @@ -331,8 +326,6 @@ export async function mergeBuiltinSkills(
source: AICustomizationSources.builtin,
groupKey: BUILTIN_STORAGE,
enabled: !disabledPromptFiles.has(p.uri),
badge: uiTooltip ? uiIntegrationBadge : undefined,
badgeTooltip: uiTooltip,
extensionId: undefined,
pluginUri: undefined,
userInvocable: true,
Expand Down
Loading
Loading