From 65d430b7cf19ed1e84c189d0086fe1d542af4ffb Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Wed, 13 Nov 2024 10:24:24 +0100 Subject: [PATCH] Add GitHub Copilot prompt functionality #888 --- CHANGELOG.md | 8 ++++++++ src/helpers/CustomScript.ts | 41 +++++++++++++++++++++++++++++-------- src/models/ScriptAction.ts | 7 +++++++ src/models/index.ts | 1 + src/services/Copilot.ts | 28 +++++++++++++++++++++++++ 5 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 src/models/ScriptAction.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 075f4669..575b664a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Change Log +## [10.7.0] - 2024-xx-xx + +### 🎨 Enhancements + +- [#888](https://github.com/estruyf/vscode-front-matter/issues/888): Added the ability to prompt GitHub Copilot from a custom script/action + +### 🐞 Fixes + ## [10.6.0] - 2024-11-06 - [Release notes](https://beta.frontmatter.codes/updates/v10.6.0) ### 🎨 Enhancements diff --git a/src/helpers/CustomScript.ts b/src/helpers/CustomScript.ts index 79d9aa70..98de5abc 100644 --- a/src/helpers/CustomScript.ts +++ b/src/helpers/CustomScript.ts @@ -15,6 +15,8 @@ import { ParsedFrontMatter } from '../parsers'; import { SETTING_CUSTOM_SCRIPTS } from '../constants'; import { evaluateCommand, existsAsync, getPlatform } from '../utils'; import { LocalizationKey, localize } from '../localization'; +import { ScriptAction } from '../models'; +import { Copilot } from '../services/Copilot'; export class CustomScript { /** @@ -267,12 +269,7 @@ export class CustomScript { try { const data: { frontmatter?: { [key: string]: any }; - fmAction?: - | 'open' - | 'copyMediaMetadata' - | 'copyMediaMetadataAndDelete' - | 'deleteMedia' - | 'fieldAction'; + fmAction?: ScriptAction; fmPath?: string; fmSourcePath?: string; fmDestinationPath?: string; @@ -425,14 +422,31 @@ export class CustomScript { const fullScript = `${command} "${scriptPath}" ${args}`; Logger.info(localize(LocalizationKey.helpersCustomScriptExecuting, fullScript)); + const output = await CustomScript.processExecution(fullScript, wsPath); + return output; + } + + // Recursive function to process the execution of the script + private static async processExecution(fullScript: string, wsPath: string): Promise { const output: string = await CustomScript.executeScriptAsync(fullScript, wsPath); try { const data = JSON.parse(output); - if (data.questions) { + const { questions, fmAction, fmPrompt } = data as { + questions?: { + name: string; + message: string; + default?: string; + options?: string[]; + }[]; + fmAction?: ScriptAction; + fmPrompt?: any; // When the 'promptCopilot' action is used + }; + + if (questions) { const answers: string[] = []; - for (const question of data.questions) { + for (const question of questions) { if (question.name && question.message) { let answer; if (question.options) { @@ -460,7 +474,16 @@ export class CustomScript { if (answers.length > 0) { const newScript = `${fullScript} ${answers.join(' ')}`; - return await CustomScript.executeScriptAsync(newScript, wsPath); + return await CustomScript.processExecution(newScript, wsPath); + } + } else if (fmAction) { + if (fmAction === 'promptCopilot' && fmPrompt) { + const response = await Copilot.promptCopilot(fmPrompt); + if (response) { + const promptResponse = `promptResponse="${response}"`; + const newScript = `${fullScript} ${promptResponse}`; + return await CustomScript.processExecution(newScript, wsPath); + } } } } catch (error) { diff --git a/src/models/ScriptAction.ts b/src/models/ScriptAction.ts new file mode 100644 index 00000000..a50f0132 --- /dev/null +++ b/src/models/ScriptAction.ts @@ -0,0 +1,7 @@ +export type ScriptAction = + | 'open' + | 'copyMediaMetadata' + | 'copyMediaMetadataAndDelete' + | 'deleteMedia' + | 'fieldAction' + | 'promptCopilot'; diff --git a/src/models/index.ts b/src/models/index.ts index 81684673..651a3887 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -22,6 +22,7 @@ export * from './Mode'; export * from './PanelSettings'; export * from './PostMessageData'; export * from './Project'; +export * from './ScriptAction'; export * from './ShellSetting'; export * from './Snippets'; export * from './SortOrder'; diff --git a/src/services/Copilot.ts b/src/services/Copilot.ts index 1a07b212..dbfa14f0 100644 --- a/src/services/Copilot.ts +++ b/src/services/Copilot.ts @@ -203,6 +203,34 @@ Example: SEO, website optimization, digital marketing.` } } + /** + * Prompts the Copilot service with a given message and returns the response. + * + * @param {string} prompt - The message to send to the Copilot service. + * @returns {Promise} - The response from the Copilot service, or undefined if no prompt is provided or an error occurs. + * + * @throws {Error} - Logs an error message if an exception occurs during the process. + */ + public static async promptCopilot(prompt: string): Promise { + if (!prompt) { + return; + } + + try { + const messages = [LanguageModelChatMessage.User(prompt)]; + + const chatResponse = await Copilot.getChatResponse(messages); + if (!chatResponse) { + return; + } + + return chatResponse; + } catch (err) { + Logger.error(`Copilot:promptCopilot:: ${(err as Error).message}`); + return ''; + } + } + /** * Retrieves the chat response from the language model. * @param messages - The chat messages to send to the language model.