Path: blob/main/src/vs/workbench/contrib/chat/browser/promptSyntax/saveToPromptAction.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { localize2 } from '../../../../../nls.js';6import { Action2, registerAction2 } from '../../../../../platform/actions/common/actions.js';78import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contextkey.js';9import { IInstantiationService, ServicesAccessor } from '../../../../../platform/instantiation/common/instantiation.js';10import { ILogService } from '../../../../../platform/log/common/log.js';11import { PromptsConfig } from '../../common/promptSyntax/config/config.js';12import { IEditorService } from '../../../../services/editor/common/editorService.js';13import { ChatContextKeys } from '../../common/chatContextKeys.js';14import { chatSubcommandLeader, IParsedChatRequest } from '../../common/chatParserTypes.js';15import { PROMPT_LANGUAGE_ID } from '../../common/promptSyntax/promptTypes.js';16import { CHAT_CATEGORY } from '../actions/chatActions.js';17import { IChatWidget } from '../chat.js';18import { ChatModeKind } from '../../common/constants.js';19import { PromptFileRewriter } from './promptFileRewriter.js';20import { ILanguageModelChatMetadata } from '../../common/languageModels.js';21import { URI } from '../../../../../base/common/uri.js';22import { Schemas } from '../../../../../base/common/network.js';2324/**25* Action ID for the `Save Prompt` action.26*/27export const SAVE_TO_PROMPT_ACTION_ID = 'workbench.action.chat.save-to-prompt';2829/**30* Name of the in-chat slash command associated with this action.31*/32export const SAVE_TO_PROMPT_SLASH_COMMAND_NAME = 'save';3334/**35* Options for the {@link SaveToPromptAction} action.36*/37interface ISaveToPromptActionOptions {38/**39* Chat widget reference to save session of.40*/41readonly chat: IChatWidget;42}4344/**45* Class that defines the `Save Prompt` action.46*/47class SaveToPromptAction extends Action2 {48constructor() {49super({50id: SAVE_TO_PROMPT_ACTION_ID,51title: localize2(52'workbench.actions.save-to-prompt.label',53"Save chat session to a prompt file",54),55f1: false,56precondition: ContextKeyExpr.and(PromptsConfig.enabledCtx, ChatContextKeys.enabled),57category: CHAT_CATEGORY,58});59}6061public async run(62accessor: ServicesAccessor,63options: ISaveToPromptActionOptions,64): Promise<void> {65const logService = accessor.get(ILogService);66const editorService = accessor.get(IEditorService);67const rewriter = accessor.get(IInstantiationService).createInstance(PromptFileRewriter);6869const logPrefix = 'save to prompt';70const chatWidget = options.chat;71const mode = chatWidget.input.currentModeObs.get();72const model = chatWidget.input.selectedLanguageModel;7374const output = [];75output.push('---');76output.push(`description: New prompt created from chat session`);77output.push(`mode: ${mode.kind}`);78if (mode.kind === ChatModeKind.Agent) {79const toolAndToolsetMap = chatWidget.input.selectedToolsModel.entriesMap.get();80output.push(`tools: ${rewriter.getNewValueString(toolAndToolsetMap)}`);81}82if (model) {83output.push(`model: ${ILanguageModelChatMetadata.asQualifiedName(model.metadata)}`);84}85output.push('---');8687const viewModel = chatWidget.viewModel;88if (viewModel) {8990for (const request of viewModel.model.getRequests()) {91const { message, response: responseModel } = request;9293if (isSaveToPromptSlashCommand(message)) {94continue;95}9697if (responseModel === undefined) {98logService.warn(`[${logPrefix}]: skipping request '${request.id}' with no response`);99continue;100}101102const { response } = responseModel;103104output.push(`<user>`);105output.push(request.message.text);106output.push(`</user>`);107output.push();108output.push(`<assistant>`);109output.push(response.getMarkdown());110output.push(`</assistant>`);111output.push();112}113const promptText = output.join('\n');114115const untitledPath = 'new.prompt.md';116const untitledResource = URI.from({ scheme: Schemas.untitled, path: untitledPath });117118const editor = await editorService.openEditor({119resource: untitledResource,120contents: promptText,121languageId: PROMPT_LANGUAGE_ID,122});123124editor?.focus();125}126}127}128129/**130* Check if provided message belongs to the `save to prompt` slash131* command itself that was run in the chat to invoke this action.132*/133function isSaveToPromptSlashCommand(message: IParsedChatRequest): boolean {134const { parts } = message;135if (parts.length < 1) {136return false;137}138139const firstPart = parts[0];140if (firstPart.kind !== 'slash') {141return false;142}143144if (firstPart.text !== `${chatSubcommandLeader}${SAVE_TO_PROMPT_SLASH_COMMAND_NAME}`) {145return false;146}147148return true;149}150151/**152* Helper to register all the `Save Prompt` actions.153*/154export function registerSaveToPromptActions(): void {155registerAction2(SaveToPromptAction);156}157158159