From 21ef72b45b287c387d7e42bc059e611d2cdb7720 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 29 Apr 2026 17:35:37 +0200 Subject: [PATCH] add pluginUri and extensionId to ICustomizationItem: fix slash command qualification (#313217) * add pluginUri and extensionId to ICustomizationItem: fix slash command qualification * Update src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostLocalCustomizations.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * update * update * update --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../copilotCLICustomizationProvider.ts | 18 ++++- .../copilotCLICustomizationProvider.spec.ts | 2 +- .../claudeCustomizationProvider.ts | 13 ++++ .../api/browser/mainThreadChatAgents2.ts | 9 ++- .../workbench/api/common/extHost.protocol.ts | 6 +- .../api/common/extHostChatAgents2.ts | 12 +++- .../agentHost/agentHostLocalCustomizations.ts | 17 +++-- .../aiCustomizationDebugPanel.ts | 7 +- .../aiCustomizationItemSource.ts | 66 ++++++------------- .../aiCustomizationListWidget.ts | 4 +- .../common/customizationHarnessService.ts | 27 +++----- .../vscode.proposed.chatPromptFiles.d.ts | 17 +++++ ...osed.chatSessionCustomizationProvider.d.ts | 10 +++ 13 files changed, 126 insertions(+), 82 deletions(-) diff --git a/extensions/copilot/src/extension/chatSessions/copilotcli/vscode-node/copilotCLICustomizationProvider.ts b/extensions/copilot/src/extension/chatSessions/copilotcli/vscode-node/copilotCLICustomizationProvider.ts index 95ff49d8534..5063a8a6739 100644 --- a/extensions/copilot/src/extension/chatSessions/copilotcli/vscode-node/copilotCLICustomizationProvider.ts +++ b/extensions/copilot/src/extension/chatSessions/copilotcli/vscode-node/copilotCLICustomizationProvider.ts @@ -88,11 +88,13 @@ export class CopilotCLICustomizationProvider extends Disposable implements vscod */ private async getAgentItems(_token: vscode.CancellationToken): Promise { const agentInfos = await this.copilotCLIAgents.getAgents(); - return agentInfos.map(({ agent, sourceUri }) => ({ + return agentInfos.map(({ agent, sourceUri, pluginUri, extensionId }) => ({ uri: sourceUri, type: vscode.ChatSessionCustomizationType.Agent, name: agent.displayName || agent.name, description: agent.description, + extensionId, + pluginUri })); } @@ -133,7 +135,10 @@ export class CopilotCLICustomizationProvider extends Disposable implements vscod uri, type: vscode.ChatSessionCustomizationType.Instructions, name: basename(uri), + description: undefined, groupKey: 'agent-instructions', + extensionId: undefined, + pluginUri: undefined }); } @@ -166,6 +171,8 @@ export class CopilotCLICustomizationProvider extends Disposable implements vscod groupKey: 'context-instructions', badge, badgeTooltip, + extensionId: instruction.extensionId, + pluginUri: instruction.pluginUri }); } else { items.push({ @@ -174,6 +181,8 @@ export class CopilotCLICustomizationProvider extends Disposable implements vscod name, description, groupKey: 'on-demand-instructions', + extensionId: instruction.extensionId, + pluginUri: instruction.pluginUri }); } } @@ -189,6 +198,7 @@ export class CopilotCLICustomizationProvider extends Disposable implements vscod uri: s.uri, type: vscode.ChatSessionCustomizationType.Skill, name: s.name, + description: s.description, extensionId: s.extensionId, pluginUri: s.pluginUri, })); @@ -203,6 +213,9 @@ export class CopilotCLICustomizationProvider extends Disposable implements vscod uri: h.uri, type: vscode.ChatSessionCustomizationType.Hook, name: basename(h.uri).replace(/\.json$/i, ''), + description: undefined, + extensionId: h.extensionId, + pluginUri: h.pluginUri, })); } @@ -214,6 +227,9 @@ export class CopilotCLICustomizationProvider extends Disposable implements vscod uri: p.uri, type: vscode.ChatSessionCustomizationType.Plugins, name: basename(p.uri), + description: undefined, + extensionId: undefined, + pluginUri: undefined, })); } } diff --git a/extensions/copilot/src/extension/chatSessions/copilotcli/vscode-node/test/copilotCLICustomizationProvider.spec.ts b/extensions/copilot/src/extension/chatSessions/copilotcli/vscode-node/test/copilotCLICustomizationProvider.spec.ts index a9f947bdfde..e2407ec2518 100644 --- a/extensions/copilot/src/extension/chatSessions/copilotcli/vscode-node/test/copilotCLICustomizationProvider.spec.ts +++ b/extensions/copilot/src/extension/chatSessions/copilotcli/vscode-node/test/copilotCLICustomizationProvider.spec.ts @@ -65,7 +65,7 @@ function makeSkill(uri: URI, name: string): vscode.ChatSkill { /** Creates a ChatHook stub. */ function makeHook(uri: URI): vscode.ChatHook { - return { uri }; + return { uri, source: 'local' }; } /** Creates a ChatPlugin stub. */ diff --git a/extensions/copilot/src/extension/chatSessions/vscode-node/claudeCustomizationProvider.ts b/extensions/copilot/src/extension/chatSessions/vscode-node/claudeCustomizationProvider.ts index 89f766fd1a6..85dfb099b4d 100644 --- a/extensions/copilot/src/extension/chatSessions/vscode-node/claudeCustomizationProvider.ts +++ b/extensions/copilot/src/extension/chatSessions/vscode-node/claudeCustomizationProvider.ts @@ -108,6 +108,8 @@ export class ClaudeCustomizationProvider extends Disposable implements vscode.Ch type: vscode.ChatSessionCustomizationType.Agent, name: agent.name, description: agent.description, + extensionId: undefined, + pluginUri: undefined, // No groupKey — vscode infers Built-in from non-file: scheme }); } @@ -121,6 +123,9 @@ export class ClaudeCustomizationProvider extends Disposable implements vscode.Ch uri: agent.uri, type: vscode.ChatSessionCustomizationType.Agent, name, + description: agent.description, + extensionId: agent.extensionId, + pluginUri: agent.pluginUri, }); } } @@ -142,6 +147,9 @@ export class ClaudeCustomizationProvider extends Disposable implements vscode.Ch uri: skill.uri, type: vscode.ChatSessionCustomizationType.Skill, name: skill.name, + description: skill.description, + extensionId: skill.extensionId, + pluginUri: skill.pluginUri, }; skillItems.push(item); } @@ -183,6 +191,9 @@ export class ClaudeCustomizationProvider extends Disposable implements vscode.Ch uri, type: vscode.ChatSessionCustomizationType.Instructions, name, + description: undefined, + extensionId: undefined, + pluginUri: undefined, }); } } @@ -225,6 +236,8 @@ export class ClaudeCustomizationProvider extends Disposable implements vscode.Ch type: vscode.ChatSessionCustomizationType.Hook, name: `${eventId}${matcherLabel}`, description: hook.command, + extensionId: undefined, + pluginUri: undefined, }); } } diff --git a/src/vs/workbench/api/browser/mainThreadChatAgents2.ts b/src/vs/workbench/api/browser/mainThreadChatAgents2.ts index 10b6d60ecf4..4c0790ec515 100644 --- a/src/vs/workbench/api/browser/mainThreadChatAgents2.ts +++ b/src/vs/workbench/api/browser/mainThreadChatAgents2.ts @@ -271,12 +271,15 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA return { uri: hookFile.uri, sessionTypes: hookFile.sessionTypes, + source: this._toChatResourceSource(hookFile.storage), + extensionId: hookFile.extension?.identifier.value, + pluginUri: hookFile.pluginUri, }; } private _toPluginDto(plugin: IAgentPlugin): IPluginDto { return { - uri: plugin.uri + uri: plugin.uri, }; } @@ -753,8 +756,8 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA groupKey: item.groupKey, badge: item.badge, badgeTooltip: item.badgeTooltip, - extensionId: undefined, - pluginUri: undefined + extensionId: item.extensionId, + pluginUri: item.pluginUri ? URI.revive(item.pluginUri) : undefined })); }, }; diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 79ea40ff4d9..2d4a173c6d1 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1719,6 +1719,9 @@ export interface ISlashCommandDto extends IChatResourceDto { export interface IHookDto { readonly uri: UriComponents; readonly sessionTypes?: readonly string[]; + readonly source: IChatResourceSourceDto; + readonly extensionId?: string; + readonly pluginUri?: UriComponents; } export interface IPluginDto { @@ -1738,7 +1741,8 @@ export interface IChatSessionCustomizationItemDto { readonly description?: string; readonly groupKey?: string; readonly badge?: string; - + readonly extensionId?: string; + readonly pluginUri?: UriComponents; readonly badgeTooltip?: string; } export interface IChatParticipantMetadata { diff --git a/src/vs/workbench/api/common/extHostChatAgents2.ts b/src/vs/workbench/api/common/extHostChatAgents2.ts index 08e75067940..f669dc26a74 100644 --- a/src/vs/workbench/api/common/extHostChatAgents2.ts +++ b/src/vs/workbench/api/common/extHostChatAgents2.ts @@ -589,7 +589,13 @@ export class ExtHostChatAgents2 extends Disposable implements ExtHostChatAgentsS } private toHook(dto: IHookDto): vscode.ChatHook { - return Object.freeze({ uri: URI.revive(dto.uri), sessionTypes: dto.sessionTypes }); + return Object.freeze({ + uri: URI.revive(dto.uri), + sessionTypes: dto.sessionTypes, + source: dto.source, + extensionId: dto.extensionId, + pluginUri: dto.pluginUri ? URI.revive(dto.pluginUri) : undefined, + }); } private toPlugin(dto: IPluginDto): vscode.ChatPlugin { @@ -830,7 +836,9 @@ export class ExtHostChatAgents2 extends Disposable implements ExtHostChatAgentsS description: item.description, groupKey: item.groupKey, badge: item.badge, - badgeTooltip: item.badgeTooltip + badgeTooltip: item.badgeTooltip, + extensionId: item.extensionId, + pluginUri: item.pluginUri, } satisfies IChatSessionCustomizationItemDto)); } catch (err) { return undefined; diff --git a/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostLocalCustomizations.ts b/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostLocalCustomizations.ts index 143a2b41237..16ee656f859 100644 --- a/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostLocalCustomizations.ts +++ b/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostLocalCustomizations.ts @@ -7,16 +7,17 @@ import { CancellationToken } from '../../../../../../base/common/cancellation.js import { Emitter, Event } from '../../../../../../base/common/event.js'; import { Disposable } from '../../../../../../base/common/lifecycle.js'; import { ResourceMap } from '../../../../../../base/common/map.js'; -import { basename, dirname, isEqualOrParent } from '../../../../../../base/common/resources.js'; +import { basename, isEqualOrParent } from '../../../../../../base/common/resources.js'; import { URI } from '../../../../../../base/common/uri.js'; import { type URI as ProtocolURI } from '../../../../../../platform/agentHost/common/state/protocol/state.js'; import { type CustomizationRef } from '../../../../../../platform/agentHost/common/state/sessionState.js'; import { PromptsType } from '../../../common/promptSyntax/promptTypes.js'; -import { IPromptPath, IPromptsService, PromptsStorage } from '../../../common/promptSyntax/service/promptsService.js'; +import { IPromptsService, PromptsStorage } from '../../../common/promptSyntax/service/promptsService.js'; import { type ICustomizationSyncProvider, type ICustomizationItem, type ICustomizationItemProvider } from '../../../common/customizationHarnessService.js'; import { IAgentPluginService } from '../../../common/plugins/agentPluginService.js'; import { getFriendlyName } from '../../aiCustomization/aiCustomizationItemSource.js'; import type { SyncedCustomizationBundler } from './syncedCustomizationBundler.js'; +import { getSkillFolderName } from '../../../common/promptSyntax/config/promptFileLocations.js'; /** * Prompt types that participate in auto-sync to an agent host harness. @@ -48,6 +49,8 @@ export interface ILocalCustomizationFile { readonly type: PromptsType; readonly storage: PromptsStorage; readonly disabled: boolean; + readonly pluginUri?: URI; + readonly extensionId?: string; } /** @@ -70,11 +73,13 @@ export async function enumerateLocalCustomizationsForHarness( ); for (let i = 0; i < lists.length; i++) { const storage = SYNCABLE_STORAGE_SOURCES[i]; - for (const file of lists[i] as readonly IPromptPath[]) { + for (const file of lists[i]) { result.push({ uri: file.uri, type, storage, + pluginUri: file.pluginUri, + extensionId: file.extension?.identifier.value, disabled: syncProvider.isDisabled(file.uri), }); } @@ -131,7 +136,7 @@ export class LocalAgentHostCustomizationItemProvider extends Disposable implemen let description: string | undefined; if (file.type === PromptsType.skill) { const parsed = skillByUri.get(file.uri); - name = parsed?.name ?? basename(dirname(file.uri)); + name = parsed?.name ?? getSkillFolderName(file.uri); description = parsed?.description; } else { name = getFriendlyName(basename(file.uri)); @@ -143,8 +148,8 @@ export class LocalAgentHostCustomizationItemProvider extends Disposable implemen description, storage: file.storage, enabled: !file.disabled, - extensionId: undefined, - pluginUri: undefined, + extensionId: file.extensionId, + pluginUri: file.pluginUri, }; }); } diff --git a/src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationDebugPanel.ts b/src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationDebugPanel.ts index 1d10751a402..1250785f188 100644 --- a/src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationDebugPanel.ts +++ b/src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationDebugPanel.ts @@ -169,8 +169,11 @@ async function appendProviderData(lines: string[], provider: ICustomizationItemP if (item.itemKey) { lines.push(` itemKey: ${item.itemKey}`); } - if (item.extensionLabel) { - lines.push(` extensionLabel: ${item.extensionLabel}`); + if (item.extensionId) { + lines.push(` extensionId: ${item.extensionId}`); + } + if (item.pluginUri) { + lines.push(` pluginUri: ${item.pluginUri.toString()}`); } if (item.badge) { lines.push(` badge: ${item.badge}`); diff --git a/src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationItemSource.ts b/src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationItemSource.ts index 9815e2e39cc..ed58f453590 100644 --- a/src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationItemSource.ts +++ b/src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationItemSource.ts @@ -62,7 +62,7 @@ export interface IAICustomizationListItem { /** True when item comes from the default chat extension (grouped under Built-in). */ readonly isBuiltin?: boolean; /** Display name of the contributing extension (for non-built-in extension items). */ - readonly extensionLabel?: string; + readonly extensionId?: string; /** Server-reported loading/sync status for remote customizations. */ readonly status?: 'loading' | 'loaded' | 'degraded' | 'error'; /** Human-readable status detail (e.g. error message or warning). */ @@ -199,7 +199,7 @@ export class AICustomizationItemNormalizer { } normalizeItem(item: ICustomizationItem, promptType: PromptsType, uriUseCounts = new ResourceMap()): IAICustomizationListItem { - const { storage, groupKey, isBuiltin, extensionLabel } = this.resolveSource(item); + const { storage, groupKey, isBuiltin, extensionId, pluginUri } = this.inferStorageAndGroup(item); const seenCount = uriUseCounts.get(item.uri) ?? 0; uriUseCounts.set(item.uri, seenCount + 1); const duplicateSuffix = seenCount === 0 ? '' : `#${seenCount}`; @@ -217,64 +217,49 @@ export class AICustomizationItemNormalizer { promptType, disabled: item.enabled === false, groupKey, - pluginUri: storage === PromptsStorage.plugin ? this.findPluginUri(item.uri) : undefined, + pluginUri, displayName: item.name, badge: item.badge, badgeTooltip: item.badgeTooltip, typeIcon: promptType === PromptsType.instructions && storage ? storageToIcon(storage) : undefined, isBuiltin, - extensionLabel, + extensionId, status: item.status, statusMessage: item.statusMessage, }; } - private resolveSource(item: ICustomizationItem): { storage?: PromptsStorage; groupKey?: string; isBuiltin?: boolean; extensionLabel?: string } { - const inferred = this.inferStorageAndGroup(item.uri); + private inferStorageAndGroup(item: ICustomizationItem): { storage: PromptsStorage; groupKey?: string; isBuiltin?: boolean; extensionId?: string; pluginUri?: URI } { + const groupKey = item.groupKey; + const isBuiltin = groupKey === BUILTIN_STORAGE; - // Use provider-supplied values when available; otherwise fall back to URI inference. - const storage = item.storage ?? inferred.storage; - const extensionLabel = item.extensionLabel ?? inferred.extensionLabel; - - if (!item.groupKey) { - return { ...inferred, storage, extensionLabel }; - } - - switch (item.groupKey) { - case BUILTIN_STORAGE: { - // Preserve a provider-supplied BUILTIN_STORAGE so the management - // editor's "edit built-in and save as user/workspace copy" flow - // activates. Otherwise fall back to extension storage (the - // historical source of built-in items). - const builtinStorage = (item.storage as PromptsStorage | typeof BUILTIN_STORAGE | undefined) === BUILTIN_STORAGE - ? (BUILTIN_STORAGE as unknown as PromptsStorage) - : PromptsStorage.extension; - return { storage: builtinStorage, groupKey: BUILTIN_STORAGE, isBuiltin: true, extensionLabel }; + if (item.extensionId) { + const extensionIdentifier = new ExtensionIdentifier(item.extensionId); + if (isChatExtensionItem(extensionIdentifier, this.productService)) { + return { storage: PromptsStorage.extension, groupKey: BUILTIN_STORAGE, isBuiltin: true, extensionId: item.extensionId }; } - default: - return { storage, groupKey: item.groupKey, extensionLabel }; + return { storage: PromptsStorage.extension, extensionId: item.extensionId, groupKey, isBuiltin }; + } + if (item.pluginUri) { + return { storage: PromptsStorage.plugin, pluginUri: item.pluginUri, groupKey, isBuiltin }; } - } - private inferStorageAndGroup(uri: URI): { storage?: PromptsStorage; groupKey?: string; isBuiltin?: boolean; extensionLabel?: string } { - if (uri.scheme !== Schemas.file) { - return { storage: PromptsStorage.extension, groupKey: BUILTIN_STORAGE, isBuiltin: true }; - } + const uri = item.uri; const activeProjectRoot = this.workspaceService.getActiveProjectRoot(); if (activeProjectRoot && isEqualOrParent(uri, activeProjectRoot)) { - return { storage: PromptsStorage.local }; + return { storage: PromptsStorage.local, groupKey, isBuiltin }; } for (const folder of this.workspaceContextService.getWorkspace().folders) { if (isEqualOrParent(uri, folder.uri)) { - return { storage: PromptsStorage.local }; + return { storage: PromptsStorage.local, groupKey, isBuiltin }; } } for (const plugin of this.agentPluginService.plugins.get()) { if (isEqualOrParent(uri, plugin.uri)) { - return { storage: PromptsStorage.plugin }; + return { storage: PromptsStorage.plugin, pluginUri: plugin.uri, groupKey, isBuiltin }; } } @@ -282,22 +267,13 @@ export class AICustomizationItemNormalizer { if (extensionId) { const extensionIdentifier = new ExtensionIdentifier(extensionId); if (isChatExtensionItem(extensionIdentifier, this.productService)) { - return { storage: PromptsStorage.extension, groupKey: BUILTIN_STORAGE, isBuiltin: true }; + return { storage: PromptsStorage.extension, groupKey: BUILTIN_STORAGE, isBuiltin: true, extensionId }; } - return { storage: PromptsStorage.extension, extensionLabel: extensionIdentifier.value }; + return { storage: PromptsStorage.extension, extensionId, groupKey, isBuiltin }; } - return { storage: PromptsStorage.user }; } - private findPluginUri(itemUri: URI): URI | undefined { - for (const plugin of this.agentPluginService.plugins.get()) { - if (isEqualOrParent(itemUri, plugin.uri)) { - return plugin.uri; - } - } - return undefined; - } } // #endregion diff --git a/src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationListWidget.ts b/src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationListWidget.ts index 241a0072b99..e0885e9cfac 100644 --- a/src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationListWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationListWidget.ts @@ -285,8 +285,8 @@ class AICustomizationItemRenderer implements IListRenderer('customizationHarnessService'); @@ -164,8 +165,6 @@ export interface ICustomizationItem { readonly description?: string; /** Storage origin (local, user, extension, plugin). Set by providers that know the source. */ readonly storage?: PromptsStorage; - /** Display name of the contributing extension (e.g. "GitHub Copilot Chat"). */ - readonly extensionLabel?: string; /** The extension identifier that contributed this customization, if any. */ readonly extensionId: string | undefined; /** The URI of the plugin that contributed this customization, if any. */ @@ -644,7 +643,7 @@ export class CustomizationHarnessServiceBase implements ICustomizationHarnessSer result.push({ uri: item.uri, type: item.type as PromptsType.prompt | PromptsType.skill, - name: item.name, + name: item.pluginUri ? getCanonicalPluginCommandId({ uri: item.pluginUri }, item.name) : item.name, description: item.description, userInvocable: true, // todo we need a way for providers to specify this if some items aren't user-invocable` storage: item.storage ?? PromptsStorage.local, @@ -697,23 +696,13 @@ export class CustomizationHarnessServiceBase implements ICustomizationHarnessSer } public async resolvePromptSlashCommand(name: string, sessionType: string, token: CancellationToken): Promise { - const harness = this.findHarnessById(sessionType); - if (!harness || !harness.itemProvider) { - return this.promptsService.resolvePromptSlashCommand(name, sessionType, token); - } - - const items = await harness.itemProvider.provideChatSessionCustomizations(token); - const item = items?.find(cmd => cmd.name === name); - if (item) { - const parsedPromptFile = await this.promptsService.parseNew(item.uri, token); + const commands = await this.getSlashCommands(sessionType, token); + const command = commands.find(cmd => cmd.name === name); + if (command) { + const parsedPromptFile = await this.promptsService.parseNew(command.uri, token); return { - uri: item.uri, - type: item.type as PromptsType.prompt | PromptsType.skill, - name: item.name, - description: item.description, - userInvocable: parsedPromptFile.header?.userInvocable ?? true, - storage: item.storage ?? PromptsStorage.local, - sessionTypes: [sessionType], + ...command, + userInvocable: parsedPromptFile.header?.userInvocable ?? command.userInvocable, parsedPromptFile, }; } diff --git a/src/vscode-dts/vscode.proposed.chatPromptFiles.d.ts b/src/vscode-dts/vscode.proposed.chatPromptFiles.d.ts index 340d641d635..54345bcf55c 100644 --- a/src/vscode-dts/vscode.proposed.chatPromptFiles.d.ts +++ b/src/vscode-dts/vscode.proposed.chatPromptFiles.d.ts @@ -244,6 +244,22 @@ declare module 'vscode' { * Optional session types that describe when the hook should be offered. */ readonly sessionTypes?: readonly string[]; + + /** + * Where the chat resource was loaded from. + */ + readonly source: ChatResourceSource; + + /** + * The contributing extension identifier when {@link source} is `extension`. + */ + readonly extensionId?: string; + + /** + * The contributing plugin URI when {@link source} is `plugin`. + */ + readonly pluginUri?: Uri; + } export interface ChatPlugin { @@ -252,6 +268,7 @@ declare module 'vscode' { * Optional session types that describe when the plugin should be offered. */ readonly sessionTypes?: readonly string[]; + } // #endregion diff --git a/src/vscode-dts/vscode.proposed.chatSessionCustomizationProvider.d.ts b/src/vscode-dts/vscode.proposed.chatSessionCustomizationProvider.d.ts index 33027458d2c..dfaaab69cc2 100644 --- a/src/vscode-dts/vscode.proposed.chatSessionCustomizationProvider.d.ts +++ b/src/vscode-dts/vscode.proposed.chatSessionCustomizationProvider.d.ts @@ -89,6 +89,16 @@ declare module 'vscode' { */ readonly description?: string; + /** + * The extension identifier that contributed this customization, if any. + */ + readonly extensionId?: string; + + /** + * The URI of the plugin that contributed this customization, if any. + */ + readonly pluginUri?: Uri; + /** * Optional group key for display grouping. Items sharing the same * `groupKey` are placed under a shared collapsible header in the