diff --git a/src/vs/workbench/contrib/chat/browser/actions/reusablePromptActions/chatAttachPromptAction.ts b/src/vs/workbench/contrib/chat/browser/actions/reusablePromptActions/chatAttachPromptAction.ts index 70160fb882d..cf49066429a 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/reusablePromptActions/chatAttachPromptAction.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/reusablePromptActions/chatAttachPromptAction.ts @@ -25,10 +25,10 @@ import { ISelectPromptOptions, askToSelectPrompt } from './dialogs/askToSelectPr /** * Action ID for the `Attach Prompt` action. */ -const ATTACH_PROMPT_ACTION_ID = 'workbench.action.chat.attach.prompt'; +const ATTACH_INSTRUCTIONS_ACTION_ID = 'workbench.action.chat.attach.instructions'; /** - * Options for the {@link AttachPromptAction} action. + * Options for the {@link AttachInstructionsAction} action. */ export interface IChatAttachPromptActionOptions extends Pick< ISelectPromptOptions, 'resource' | 'widget' @@ -51,11 +51,11 @@ export interface IChatAttachPromptActionOptions extends Pick< /** * Action to attach a prompt to a chat widget input. */ -class AttachPromptAction extends Action2 { +class AttachInstructionsAction extends Action2 { constructor() { super({ - id: ATTACH_PROMPT_ACTION_ID, - title: localize2('workbench.action.chat.attach.prompt.label', "Use Prompt"), + id: ATTACH_INSTRUCTIONS_ACTION_ID, + title: localize2('workbench.action.chat.attach.instructions.label', "Attach Instructions"), f1: false, precondition: ContextKeyExpr.and(PromptsConfig.enabledCtx, ChatContextKeys.enabled), category: CHAT_CATEGORY, @@ -100,10 +100,11 @@ class AttachPromptAction extends Action2 { } // find all prompt files in the user workspace - const promptFiles = await promptsService.listPromptFiles(); + const promptFiles = await promptsService.listPromptFiles('instructions'); await askToSelectPrompt({ ...options, + type: 'instructions', promptFiles, fileService, viewsService, @@ -118,7 +119,7 @@ class AttachPromptAction extends Action2 { /** * Runs the `Attach Prompt` action with provided options. We export this - * function instead of {@link ATTACH_PROMPT_ACTION_ID} directly to + * function instead of {@link ATTACH_INSTRUCTIONS_ACTION_ID} directly to * encapsulate/enforce the correct options to be passed to the action. */ export const runAttachPromptAction = async ( @@ -126,7 +127,7 @@ export const runAttachPromptAction = async ( commandService: ICommandService, ): Promise => { return await commandService.executeCommand( - ATTACH_PROMPT_ACTION_ID, + ATTACH_INSTRUCTIONS_ACTION_ID, options, ); }; @@ -135,5 +136,5 @@ export const runAttachPromptAction = async ( * Helper to register the `Attach Prompt` action. */ export const registerAttachPromptActions = () => { - registerAction2(AttachPromptAction); + registerAction2(AttachInstructionsAction); }; diff --git a/src/vs/workbench/contrib/chat/browser/actions/reusablePromptActions/dialogs/askToSelectPrompt/askToSelectPrompt.ts b/src/vs/workbench/contrib/chat/browser/actions/reusablePromptActions/dialogs/askToSelectPrompt/askToSelectPrompt.ts index 3a8868e1e5b..c4b96779717 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/reusablePromptActions/dialogs/askToSelectPrompt/askToSelectPrompt.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/reusablePromptActions/dialogs/askToSelectPrompt/askToSelectPrompt.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { DOCS_OPTION } from './constants.js'; +import { PROMPT_DOCS_OPTION } from './constants.js'; import { IChatWidget } from '../../../../chat.js'; import { attachPrompt } from './utils/attachPrompt.js'; import { handleButtonClick } from './utils/handleButtonClick.js'; @@ -13,7 +13,7 @@ import { createPromptPickItem } from './utils/createPromptPickItem.js'; import { createPlaceholderText } from './utils/createPlaceholderText.js'; import { extUri } from '../../../../../../../../base/common/resources.js'; import { WithUriValue } from '../../../../../../../../base/common/types.js'; -import { IPromptPath } from '../../../../../common/promptSyntax/service/types.js'; +import { IPromptPath, TPromptsType } from '../../../../../common/promptSyntax/service/types.js'; import { DisposableStore } from '../../../../../../../../base/common/lifecycle.js'; import { IFileService } from '../../../../../../../../platform/files/common/files.js'; import { ILabelService } from '../../../../../../../../platform/label/common/label.js'; @@ -48,6 +48,11 @@ export interface ISelectPromptOptions { */ readonly promptFiles: readonly IPromptPath[]; + /** + * Type of the prompt files to select. + */ + readonly type: TPromptsType; + readonly fileService: IFileService; readonly labelService: ILabelService; readonly viewsService: IViewsService; @@ -66,7 +71,7 @@ export interface ISelectPromptOptions { export const askToSelectPrompt = async ( options: ISelectPromptOptions, ): Promise => { - const { promptFiles, resource, quickInputService, labelService } = options; + const { promptFiles, resource, quickInputService, labelService, type } = options; const fileOptions = promptFiles.map((promptFile) => { return createPromptPickItem(promptFile, labelService); @@ -75,7 +80,7 @@ export const askToSelectPrompt = async ( /** * Add a link to the documentation to the end of prompts list. */ - fileOptions.push(DOCS_OPTION); + fileOptions.push(PROMPT_DOCS_OPTION); // if a resource is provided, create an `activeItem` for it to pre-select // it in the UI, and sort the list so the active item appears at the top @@ -94,7 +99,8 @@ export const askToSelectPrompt = async ( uri: resource, // "user" prompts are always registered in the prompts list, hence it // should be safe to assume that `resource` is not "user" prompt here - type: 'local', + storage: 'local', + type, }, labelService); fileOptions.push(activeItem); } @@ -164,7 +170,7 @@ export const askToSelectPrompt = async ( const selectedOption = selectedItems[0]; // whether user selected the docs link option - const docsSelected = (selectedOption === DOCS_OPTION); + const docsSelected = (selectedOption === PROMPT_DOCS_OPTION); // if documentation item was selected, open its link in a browser if (docsSelected) { diff --git a/src/vs/workbench/contrib/chat/browser/actions/reusablePromptActions/dialogs/askToSelectPrompt/constants.ts b/src/vs/workbench/contrib/chat/browser/actions/reusablePromptActions/dialogs/askToSelectPrompt/constants.ts index a7b1de1c72d..70ab1ce6266 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/reusablePromptActions/dialogs/askToSelectPrompt/constants.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/reusablePromptActions/dialogs/askToSelectPrompt/constants.ts @@ -8,7 +8,7 @@ import { URI } from '../../../../../../../../base/common/uri.js'; import { Codicon } from '../../../../../../../../base/common/codicons.js'; import { WithUriValue } from '../../../../../../../../base/common/types.js'; import { ThemeIcon } from '../../../../../../../../base/common/themables.js'; -import { DOCUMENTATION_URL } from '../../../../../common/promptSyntax/constants.js'; +import { INSTRUCTIONS_DOCUMENTATION_URL, PROMPT_DOCUMENTATION_URL } from '../../../../../common/promptSyntax/constants.js'; import { isLinux, isWindows } from '../../../../../../../../base/common/platform.js'; import { IQuickInputButton, IQuickPickItem } from '../../../../../../../../platform/quickinput/common/quickInput.js'; @@ -25,15 +25,29 @@ export const ALT_KEY_NAME = (isWindows || isLinux) ? 'Alt' : '⌥'; /** * A special quick pick item that links to the documentation. */ -export const DOCS_OPTION: WithUriValue = Object.freeze({ +export const PROMPT_DOCS_OPTION: WithUriValue = Object.freeze({ type: 'item', label: localize( 'commands.prompts.use.select-dialog.docs-label', 'Learn how to create reusable prompts', ), - description: DOCUMENTATION_URL, - tooltip: DOCUMENTATION_URL, - value: URI.parse(DOCUMENTATION_URL), + description: PROMPT_DOCUMENTATION_URL, + tooltip: PROMPT_DOCUMENTATION_URL, + value: URI.parse(PROMPT_DOCUMENTATION_URL), +}); + +/** + * A special quick pick item that links to the documentation. + */ +export const INSTRUCTIONS_DOCS_OPTION: WithUriValue = Object.freeze({ + type: 'item', + label: localize( + 'commands.instructions.use.select-dialog.docs-label', + 'Learn how to create custom instructions', + ), + description: INSTRUCTIONS_DOCUMENTATION_URL, + tooltip: INSTRUCTIONS_DOCUMENTATION_URL, + value: URI.parse(INSTRUCTIONS_DOCUMENTATION_URL), }); /** diff --git a/src/vs/workbench/contrib/chat/browser/actions/reusablePromptActions/dialogs/askToSelectPrompt/utils/createPromptPickItem.ts b/src/vs/workbench/contrib/chat/browser/actions/reusablePromptActions/dialogs/askToSelectPrompt/utils/createPromptPickItem.ts index 5203dddcd34..1f12bbf5cea 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/reusablePromptActions/dialogs/askToSelectPrompt/utils/createPromptPickItem.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/reusablePromptActions/dialogs/askToSelectPrompt/utils/createPromptPickItem.ts @@ -19,19 +19,19 @@ export const createPromptPickItem = ( promptFile: IPromptPath, labelService: ILabelService, ): WithUriValue => { - const { uri, type } = promptFile; + const { uri, storage } = promptFile; const fileWithoutExtension = getCleanPromptName(uri); // if a "user" prompt, don't show its filesystem path in // the user interface, but do that for all the "local" ones - const description = (type === 'user') + const description = (storage === 'user') ? localize( 'user-prompt.capitalized', 'User prompt', ) : labelService.getUriLabel(dirname(uri), { relative: true }); - const tooltip = (type === 'user') + const tooltip = (storage === 'user') ? description : uri.fsPath; diff --git a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts index 56220de100a..4084fff59f4 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts @@ -48,7 +48,7 @@ import { ILanguageModelIgnoredFilesService, LanguageModelIgnoredFilesService } f import { ILanguageModelsService, LanguageModelsService } from '../common/languageModels.js'; import { ILanguageModelStatsService, LanguageModelStatsService } from '../common/languageModelStats.js'; import { ILanguageModelToolsService } from '../common/languageModelToolsService.js'; -import { DOCUMENTATION_URL } from '../common/promptSyntax/constants.js'; +import { PROMPT_DOCUMENTATION_URL } from '../common/promptSyntax/constants.js'; import { registerReusablePromptLanguageFeatures } from '../common/promptSyntax/languageFeatures/providers/index.js'; import { PromptsService } from '../common/promptSyntax/service/promptsService.js'; import { IPromptsService } from '../common/promptSyntax/service/types.js'; @@ -282,7 +282,7 @@ configurationRegistry.registerConfiguration({ 'chat.reusablePrompts.config.enabled.description', "Enable reusable prompt files (`*{0}`) in Chat, Edits, and Inline Chat sessions. [Learn More]({1}).", PROMPT_FILE_EXTENSION, - DOCUMENTATION_URL, + PROMPT_DOCUMENTATION_URL, ), default: true, restricted: true, @@ -306,7 +306,7 @@ configurationRegistry.registerConfiguration({ 'chat.reusablePrompts.config.locations.description', "Specify location(s) of reusable prompt files (`*{0}`) that can be attached in Chat, Edits, and Inline Chat sessions. [Learn More]({1}).\n\nRelative paths are resolved from the root folder(s) of your workspace.", PROMPT_FILE_EXTENSION, - DOCUMENTATION_URL, + PROMPT_DOCUMENTATION_URL, ), default: { [PROMPT_FILES_DEFAULT_SOURCE_FOLDER]: true, diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/createPromptCommand.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/createPromptCommand.ts index 2cde08cb946..ce9cd956fd3 100644 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/createPromptCommand.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/createPromptCommand.ts @@ -17,7 +17,7 @@ import { PromptsConfig } from '../../../../../../../platform/prompts/common/conf import { ICommandService } from '../../../../../../../platform/commands/common/commands.js'; import { ContextKeyExpr } from '../../../../../../../platform/contextkey/common/contextkey.js'; import { MenuId, MenuRegistry } from '../../../../../../../platform/actions/common/actions.js'; -import { IPromptPath, IPromptsService } from '../../../../common/promptSyntax/service/types.js'; +import { IPromptsService, TPromptsStorage, TPromptsType } from '../../../../common/promptSyntax/service/types.js'; import { IQuickInputService } from '../../../../../../../platform/quickinput/common/quickInput.js'; import { ServicesAccessor } from '../../../../../../../platform/instantiation/common/instantiation.js'; import { IWorkspaceContextService } from '../../../../../../../platform/workspace/common/workspace.js'; @@ -26,37 +26,13 @@ import { IUserDataSyncEnablementService, SyncResource } from '../../../../../../ import { KeybindingsRegistry, KeybindingWeight } from '../../../../../../../platform/keybinding/common/keybindingsRegistry.js'; import { INotificationService, NeverShowAgainScope, Severity } from '../../../../../../../platform/notification/common/notification.js'; -/** - * Base command ID prefix. - */ -const BASE_COMMAND_ID = 'workbench.command.prompts.create'; - -/** - * Command ID for creating a 'local' prompt. - */ -const LOCAL_COMMAND_ID = `${BASE_COMMAND_ID}.local`; - -/** - * Command ID for creating a 'user' prompt. - */ -const USER_COMMAND_ID = `${BASE_COMMAND_ID}.user`; - -/** - * Title of the 'create local prompt' command. - */ -const LOCAL_COMMAND_TITLE = localize('commands.prompts.create.title.local', "Create Prompt"); - -/** - * Title of the 'create user prompt' command. - */ -const USER_COMMAND_TITLE = localize('commands.prompts.create.title.user', "Create User Prompt"); - /** * The command implementation. */ const command = async ( accessor: ServicesAccessor, - type: IPromptPath['type'], + type: TPromptsType, + storage: TPromptsStorage ): Promise => { const logService = accessor.get(ILogService); const fileService = accessor.get(IFileService); @@ -69,13 +45,14 @@ const command = async ( const workspaceService = accessor.get(IWorkspaceContextService); const userDataSyncEnablementService = accessor.get(IUserDataSyncEnablementService); - const fileName = await askForPromptName(type, quickInputService); + const fileName = await askForPromptName(storage, quickInputService); if (!fileName) { return; } const selectedFolder = await askForPromptSourceFolder({ type: type, + storage: storage, labelService, openerService, promptsService, @@ -101,7 +78,7 @@ const command = async ( await openerService.open(promptUri); - if (type !== 'user') { + if (storage !== 'user') { return; } @@ -148,55 +125,33 @@ const command = async ( ); }; -/** - * Factory for creating the command handler with specific prompt `type`. - */ -const commandFactory = (type: 'local' | 'user') => { - return async (accessor: ServicesAccessor): Promise => { - return command(accessor, type); - }; -}; +function register(type: TPromptsType, storage: TPromptsStorage, id: string, title: string) { + /** + * Register the command. + */ + KeybindingsRegistry.registerCommandAndKeybindingRule({ + id, + weight: KeybindingWeight.WorkbenchContrib, + handler: async (accessor: ServicesAccessor): Promise => { + return command(accessor, type, storage); + }, + when: ContextKeyExpr.and(PromptsConfig.enabledCtx, ChatContextKeys.enabled), + }); -/** - * Register the "Create Prompt" command. - */ -KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: LOCAL_COMMAND_ID, - weight: KeybindingWeight.WorkbenchContrib, - handler: commandFactory('local'), - when: ContextKeyExpr.and(PromptsConfig.enabledCtx, ChatContextKeys.enabled), -}); + /** + * Register the command in the command palette. + */ + MenuRegistry.appendMenuItem(MenuId.CommandPalette, { + command: { + id, + title, + category: CHAT_CATEGORY + }, + when: ContextKeyExpr.and(PromptsConfig.enabledCtx, ChatContextKeys.enabled) + }); +} -/** - * Register the "Create User Prompt" command. - */ -KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: USER_COMMAND_ID, - weight: KeybindingWeight.WorkbenchContrib, - handler: commandFactory('user'), - when: ContextKeyExpr.and(PromptsConfig.enabledCtx, ChatContextKeys.enabled), -}); - -/** - * Register the "Create Prompt" command in the command palette. - */ -MenuRegistry.appendMenuItem(MenuId.CommandPalette, { - command: { - id: LOCAL_COMMAND_ID, - title: LOCAL_COMMAND_TITLE, - category: CHAT_CATEGORY - }, - when: ContextKeyExpr.and(PromptsConfig.enabledCtx, ChatContextKeys.enabled) -}); - -/** - * Register the "Create User Prompt" command in the command palette. - */ -MenuRegistry.appendMenuItem(MenuId.CommandPalette, { - command: { - id: USER_COMMAND_ID, - title: USER_COMMAND_TITLE, - category: CHAT_CATEGORY, - }, - when: ContextKeyExpr.and(PromptsConfig.enabledCtx, ChatContextKeys.enabled) -}); +register('instructions', 'local', 'workbench.command.instructions.create.local', localize('commands.instructions.create.title.local', "Create Instructions File")); +register('instructions', 'user', 'workbench.command.instructions.create.user', localize('commands.instructions.create.title.user', "Create User Instructions File")); +register('prompt', 'local', 'workbench.command.prompts.create.local', localize('commands.prompts.create.title.local', "Create Prompt File")); +register('prompt', 'user', 'workbench.command.prompts.create.user', localize('commands.prompts.create.title.user', "Create User Prompt File")); diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/dialogs/askForPromptSourceFolder.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/dialogs/askForPromptSourceFolder.ts index 2f446a81472..9a11c1c99d7 100644 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/dialogs/askForPromptSourceFolder.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/dialogs/askForPromptSourceFolder.ts @@ -6,9 +6,9 @@ import { localize } from '../../../../../../../../nls.js'; import { URI } from '../../../../../../../../base/common/uri.js'; import { WithUriValue } from '../../../../../../../../base/common/types.js'; -import { DOCUMENTATION_URL } from '../../../../../common/promptSyntax/constants.js'; +import { PROMPT_DOCUMENTATION_URL } from '../../../../../common/promptSyntax/constants.js'; import { basename, extUri } from '../../../../../../../../base/common/resources.js'; -import { IPromptsService } from '../../../../../common/promptSyntax/service/types.js'; +import { IPromptsService, TPromptsStorage, TPromptsType } from '../../../../../common/promptSyntax/service/types.js'; import { ILabelService } from '../../../../../../../../platform/label/common/label.js'; import { IOpenerService } from '../../../../../../../../platform/opener/common/opener.js'; import { IWorkspaceContextService } from '../../../../../../../../platform/workspace/common/workspace.js'; @@ -18,10 +18,9 @@ import { IPickOptions, IQuickInputService, IQuickPickItem } from '../../../../.. * Options for {@link askForPromptSourceFolder} dialog. */ interface IAskForFolderOptions { - /** - * Prompt type. - */ - readonly type: 'local' | 'user'; + + readonly type: TPromptsType; + readonly storage: TPromptsStorage; readonly labelService: ILabelService; readonly openerService: IOpenerService; @@ -37,10 +36,10 @@ interface IAskForFolderOptions { export const askForPromptSourceFolder = async ( options: IAskForFolderOptions, ): Promise => { - const { type, promptsService, quickInputService, labelService, openerService, workspaceService } = options; + const { storage, type, promptsService, quickInputService, labelService, openerService, workspaceService } = options; // get prompts source folders based on the prompt type - const folders = promptsService.getSourceFolders(type); + const folders = promptsService.getSourceFolders(type, storage); // if no source folders found, show 'learn more' dialog // note! this is a temporary solution and must be replaced with a dialog to select @@ -122,9 +121,9 @@ const showNoFoldersDialog = async ( 'commands.prompts.create.ask-folder.empty.docs-label', 'Learn how to configure reusable prompts', ), - description: DOCUMENTATION_URL, - tooltip: DOCUMENTATION_URL, - value: URI.parse(DOCUMENTATION_URL), + description: PROMPT_DOCUMENTATION_URL, + tooltip: PROMPT_DOCUMENTATION_URL, + value: URI.parse(PROMPT_DOCUMENTATION_URL), }; const result = await quickInputService.pick( diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/usePromptCommand.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/usePromptCommand.ts index 88721eb9795..a1674948e4e 100644 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/usePromptCommand.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/usePromptCommand.ts @@ -22,19 +22,19 @@ import { IActiveCodeEditor, isCodeEditor, isDiffEditor } from '../../../../../.. import { KeybindingsRegistry, KeybindingWeight } from '../../../../../../platform/keybinding/common/keybindingsRegistry.js'; /** - * Command ID of the "Use Prompt" command. + * Command ID of the "Use Instructions" command. */ -export const COMMAND_ID = 'workbench.command.prompts.use'; +export const COMMAND_ID = 'workbench.command.instructions.use'; /** - * Keybinding of the "Use Prompt" command. + * Keybinding of the "Use Instructions" command. * The `cmd + /` is the current keybinding for 'attachment', so we use - * the `alt` key modifier to convey the "prompt attachment" action. + * the `alt` key modifier to convey the "instructions attachment" action. */ const COMMAND_KEY_BINDING = KeyMod.CtrlCmd | KeyCode.Slash | KeyMod.Alt; /** - * Implementation of the "Use Prompt" command. The command works in the following way. + * Implementation of the "Use Instructions" command. The command works in the following way. * * When executed, it tries to see if a `prompt file` was open in the active code editor * (see {@link IChatAttachPromptActionOptions.resource resource}), and if a chat input @@ -139,12 +139,12 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ }); /** - * Register the "Use Prompt" command in the `command palette`. + * Register the "Use Instructions" command in the `command palette`. */ MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: COMMAND_ID, - title: localize('commands.prompts.use.title', "Use Prompt"), + title: localize('commands.prompts.use.title', "Use Instructions"), category: CHAT_CATEGORY }, when: ContextKeyExpr.and(PromptsConfig.enabledCtx, ChatContextKeys.enabled) diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/constants.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/constants.ts index 0f25d3da6e6..f3a390da4ae 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/constants.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/constants.ts @@ -8,7 +8,8 @@ import { LanguageFilter } from '../../../../../editor/common/languageSelector.js /** * Documentation link for the reusable prompts feature. */ -export const DOCUMENTATION_URL = 'https://aka.ms/vscode-ghcp-prompt-snippets'; +export const PROMPT_DOCUMENTATION_URL = 'https://aka.ms/vscode-ghcp-prompt-snippets'; +export const INSTRUCTIONS_DOCUMENTATION_URL = PROMPT_DOCUMENTATION_URL; // TODO: instructions specific link /** * Language ID for the reusable prompt syntax. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts index 000bc70a9c9..1907980c2ed 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IPromptPath, IPromptsService } from './types.js'; +import { IPromptPath, IPromptsService, TPromptsStorage, TPromptsType } from './types.js'; import { URI } from '../../../../../../base/common/uri.js'; import { assert } from '../../../../../../base/common/assert.js'; import { PromptFilesLocator } from '../utils/promptFilesLocator.js'; @@ -83,34 +83,35 @@ export class PromptsService extends Disposable implements IPromptsService { return this.cache.get(model); } - public async listPromptFiles(): Promise { + public async listPromptFiles(type: TPromptsType): Promise { const userLocations = [this.userDataService.currentProfile.promptsHome]; const prompts = await Promise.all([ this.fileLocator.listFilesIn(userLocations) - .then(withType('user')), + .then(withType('user', type)), this.fileLocator.listFiles() - .then(withType('local')), + .then(withType('local', type)), ]); return prompts.flat(); } public getSourceFolders( - type: IPromptPath['type'], + type: TPromptsType, + storage: TPromptsStorage, ): readonly IPromptPath[] { // sanity check to make sure we don't miss a new // prompt type that could be added in the future assert( - type === 'local' || type === 'user', - `Unknown prompt type '${type}'.`, + storage === 'local' || storage === 'user', + `Unknown prompt storage '${storage}'.`, ); - const prompts = (type === 'user') + const prompts = (storage === 'user') ? [this.userDataService.currentProfile.promptsHome] : this.fileLocator.getConfigBasedSourceFolders(); - return prompts.map(addType(type)); + return prompts.map(addType(storage, type)); } } @@ -118,10 +119,11 @@ export class PromptsService extends Disposable implements IPromptsService { * Utility to add a provided prompt `type` to a prompt URI. */ const addType = ( - type: 'local' | 'user', + storage: TPromptsStorage, + type: TPromptsType, ): (uri: URI) => IPromptPath => { return (uri) => { - return { uri, type: type }; + return { uri, storage, type }; }; }; @@ -129,10 +131,11 @@ const addType = ( * Utility to add a provided prompt `type` to a list of prompt URIs. */ const withType = ( - type: 'local' | 'user', + storage: TPromptsStorage, + type: TPromptsType, ): (uris: readonly URI[]) => (readonly IPromptPath[]) => { return (uris) => { return uris - .map(addType(type)); + .map(addType(storage, type)); }; }; diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/service/types.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/service/types.ts index ca6bec78b6d..50d89b00249 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/service/types.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/service/types.ts @@ -15,11 +15,14 @@ import { createDecorator } from '../../../../../../platform/instantiation/common export const IPromptsService = createDecorator('IPromptsService'); /** -* Supported prompt types. -* - `local` means the prompt is a local file. -* - `user` means a "roam-able" prompt file (similar to snippets). -*/ -type TPromptsType = 'local' | 'user'; + * Where the prompt is stored. + */ +export type TPromptsStorage = 'local' | 'user'; + +/** + * What the prompt is used for. + */ +export type TPromptsType = 'instructions' | 'prompt'; /** * Represents a prompt path with its type. @@ -32,11 +35,17 @@ export interface IPromptPath { readonly uri: URI; /** - * Type of the prompt. + * Storage of the prompt. + */ + readonly storage: TPromptsStorage; + + /** + * Type */ readonly type: TPromptsType; } + /** * Provides prompt services. */ @@ -54,12 +63,12 @@ export interface IPromptsService extends IDisposable { /** * List all available prompt files. */ - listPromptFiles(): Promise; + listPromptFiles(type: TPromptsType): Promise; /** - * Get a list of prompt source folders based on the provided prompt type. + * Get a list of prompt source folders based on the provided prompt type and storage. */ - getSourceFolders(type: TPromptsType): readonly IPromptPath[]; + getSourceFolders(type: TPromptsType, storage: TPromptsStorage): readonly IPromptPath[]; } /**