From d944566c4db6f2159e2b4309a0282a948e99fe83 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 29 Jan 2026 17:34:57 +0100 Subject: [PATCH] Show chat agents/prompts in extension features list (#291643) --- .../platform/extensions/common/extensions.ts | 1 + .../chatPromptFilesContribution.ts | 84 ++++++++++++++++++- 2 files changed, 83 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/extensions/common/extensions.ts b/src/vs/platform/extensions/common/extensions.ts index e8470285f7f..021ad016e02 100644 --- a/src/vs/platform/extensions/common/extensions.ts +++ b/src/vs/platform/extensions/common/extensions.ts @@ -235,6 +235,7 @@ export interface IExtensionContributions { readonly chatPromptFiles?: ReadonlyArray; readonly chatInstructions?: ReadonlyArray; readonly chatAgents?: ReadonlyArray; + readonly chatSkills?: ReadonlyArray; readonly languageModelTools?: ReadonlyArray; readonly languageModelToolSets?: ReadonlyArray; readonly mcpServerDefinitionProviders?: ReadonlyArray; diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/chatPromptFilesContribution.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/chatPromptFilesContribution.ts index 8e9d41c3db7..6468c60cdfa 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/chatPromptFilesContribution.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/chatPromptFilesContribution.ts @@ -4,10 +4,10 @@ *--------------------------------------------------------------------------------------------*/ -import { DisposableMap } from '../../../../../base/common/lifecycle.js'; +import { Disposable, DisposableMap } from '../../../../../base/common/lifecycle.js'; import { joinPath, isEqualOrParent } from '../../../../../base/common/resources.js'; import { localize } from '../../../../../nls.js'; -import { ExtensionIdentifier } from '../../../../../platform/extensions/common/extensions.js'; +import { ExtensionIdentifier, IExtensionManifest } from '../../../../../platform/extensions/common/extensions.js'; import { IWorkbenchContribution } from '../../../../common/contributions.js'; import * as extensionsRegistry from '../../../../services/extensions/common/extensionsRegistry.js'; import { IPromptsService, PromptsStorage } from './service/promptsService.js'; @@ -15,6 +15,9 @@ import { PromptsType } from './promptTypes.js'; import { UriComponents } from '../../../../../base/common/uri.js'; import { CommandsRegistry } from '../../../../../platform/commands/common/commands.js'; import { CancellationToken } from '../../../../../base/common/cancellation.js'; +import { SyncDescriptor } from '../../../../../platform/instantiation/common/descriptors.js'; +import { Registry } from '../../../../../platform/registry/common/platform.js'; +import { Extensions, IExtensionFeaturesRegistry, IExtensionFeatureTableRenderer, IRenderedData, IRowData, ITableData } from '../../../../services/extensionManagement/common/extensionFeatures.js'; interface IRawChatFileContribution { readonly path: string; @@ -162,3 +165,80 @@ CommandsRegistry.registerCommand('_listExtensionPromptFiles', async (accessor): return result; }); + +class ChatPromptFilesDataRenderer extends Disposable implements IExtensionFeatureTableRenderer { + readonly type = 'table'; + + constructor(private readonly contributionPoint: ChatContributionPoint) { + super(); + } + + shouldRender(manifest: IExtensionManifest): boolean { + return !!manifest.contributes?.[this.contributionPoint]; + } + + render(manifest: IExtensionManifest): IRenderedData { + const contributions = manifest.contributes?.[this.contributionPoint] ?? []; + if (!contributions.length) { + return { data: { headers: [], rows: [] }, dispose: () => { } }; + } + + const headers = [ + localize('chatFilesName', "Name"), + localize('chatFilesDescription', "Description"), + localize('chatFilesPath', "Path"), + ]; + + const rows: IRowData[][] = contributions.map(d => { + return [ + d.name ?? '-', + d.description ?? '-', + d.path, + ]; + }); + + return { + data: { + headers, + rows + }, + dispose: () => { } + }; + } +} + +Registry.as(Extensions.ExtensionFeaturesRegistry).registerExtensionFeature({ + id: ChatContributionPoint.chatPromptFiles, + label: localize('chatPromptFiles', "Chat Prompt Files"), + access: { + canToggle: false + }, + renderer: new SyncDescriptor(ChatPromptFilesDataRenderer, [ChatContributionPoint.chatPromptFiles]), +}); + +Registry.as(Extensions.ExtensionFeaturesRegistry).registerExtensionFeature({ + id: ChatContributionPoint.chatInstructions, + label: localize('chatInstructions', "Chat Instructions"), + access: { + canToggle: false + }, + renderer: new SyncDescriptor(ChatPromptFilesDataRenderer, [ChatContributionPoint.chatInstructions]), +}); + +Registry.as(Extensions.ExtensionFeaturesRegistry).registerExtensionFeature({ + id: ChatContributionPoint.chatAgents, + label: localize('chatAgents', "Chat Agents"), + access: { + canToggle: false + }, + renderer: new SyncDescriptor(ChatPromptFilesDataRenderer, [ChatContributionPoint.chatAgents]), +}); + +Registry.as(Extensions.ExtensionFeaturesRegistry).registerExtensionFeature({ + id: ChatContributionPoint.chatSkills, + label: localize('chatSkills', "Chat Skills"), + access: { + canToggle: false + }, + renderer: new SyncDescriptor(ChatPromptFilesDataRenderer, [ChatContributionPoint.chatSkills]), +});