From 5952c3540232a8b3235d9dfbc49a7b27616c689c Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Mon, 30 Sep 2024 18:13:13 +0200 Subject: [PATCH 01/14] Refactor if checks on /sendas --- public/scripts/slash-commands.js | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/public/scripts/slash-commands.js b/public/scripts/slash-commands.js index eb81a0218..506bf4bc5 100644 --- a/public/scripts/slash-commands.js +++ b/public/scripts/slash-commands.js @@ -3107,30 +3107,20 @@ async function setNarratorName(_, text) { export async function sendMessageAs(args, text) { if (!text) { + toastr.warning('You must specify text to send as'); return ''; } - let name; + let name = args.name?.trim(); let mesText; - if (args.name) { - name = args.name.trim(); - - if (!name && !text) { - toastr.warning('You must specify a name and text to send as'); - return ''; - } - } else { + if (!name) { const namelessWarningKey = 'sendAsNamelessWarningShown'; if (localStorage.getItem(namelessWarningKey) !== 'true') { toastr.warning('To avoid confusion, please use /sendas name="Character Name"', 'Name defaulted to {{char}}', { timeOut: 10000 }); localStorage.setItem(namelessWarningKey, 'true'); } name = name2; - if (!text) { - toastr.warning('You must specify text to send as'); - return ''; - } } mesText = text.trim(); From 0ab74f0819a8f3705b4a630c77b97b821c7d6b29 Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Mon, 30 Sep 2024 18:30:09 +0200 Subject: [PATCH 02/14] Update return values of send commands - /sendas - /sys - /comment --- public/scripts/slash-commands.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/public/scripts/slash-commands.js b/public/scripts/slash-commands.js index 506bf4bc5..e9d0763c5 100644 --- a/public/scripts/slash-commands.js +++ b/public/scripts/slash-commands.js @@ -176,6 +176,7 @@ export function initDefaultSlashCommands() { SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'sendas', callback: sendMessageAs, + returns: 'The text of the sent message', namedArgumentList: [ SlashCommandNamedArgument.fromProps({ name: 'name', @@ -222,6 +223,7 @@ export function initDefaultSlashCommands() { name: 'sys', callback: sendNarratorMessage, aliases: ['nar'], + returns: 'The text of the sent message', namedArgumentList: [ new SlashCommandNamedArgument( 'compact', @@ -276,6 +278,7 @@ export function initDefaultSlashCommands() { SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'comment', callback: sendCommentMessage, + returns: 'The text of the sent message', namedArgumentList: [ new SlashCommandNamedArgument( 'compact', @@ -2843,7 +2846,7 @@ function findPersonaByName(name) { async function sendUserMessageCallback(args, text) { if (!text) { - console.warn('WARN: No text provided for /send command'); + toastr.warning('You must specify text to send'); return; } @@ -3205,11 +3208,12 @@ export async function sendMessageAs(args, text) { await saveChatConditional(); } - return ''; + return message.mes; } export async function sendNarratorMessage(args, text) { if (!text) { + toastr.warning('You must specify text to send'); return ''; } @@ -3258,7 +3262,7 @@ export async function sendNarratorMessage(args, text) { await saveChatConditional(); } - return ''; + return message.mes; } export async function promptQuietForLoudResponse(who, text) { @@ -3304,6 +3308,7 @@ export async function promptQuietForLoudResponse(who, text) { async function sendCommentMessage(args, text) { if (!text) { + toastr.warning('You must specify text to send'); return ''; } @@ -3346,7 +3351,7 @@ async function sendCommentMessage(args, text) { await saveChatConditional(); } - return ''; + return message.mes; } /** From 1128de91f4c9cfbc2abec1d83c363059c993a1ca Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Mon, 30 Sep 2024 18:32:21 +0200 Subject: [PATCH 03/14] /send with return value too - /send - return message on `sendMessageAsUser` now --- public/script.js | 4 +++- public/scripts/slash-commands.js | 8 +++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/public/script.js b/public/script.js index cda7adea3..b1e0cffbb 100644 --- a/public/script.js +++ b/public/script.js @@ -4784,7 +4784,7 @@ export function removeMacros(str) { * @param {boolean} [compact] Send as a compact display message. * @param {string} [name] Name of the user sending the message. Defaults to name1. * @param {string} [avatar] Avatar of the user sending the message. Defaults to user_avatar. - * @returns {Promise} A promise that resolves when the message is inserted. + * @returns {Promise} A promise that resolves to the message when it is inserted. */ export async function sendMessageAsUser(messageText, messageBias, insertAt = null, compact = false, name = name1, avatar = user_avatar) { messageText = getRegexedString(messageText, regex_placement.USER_INPUT); @@ -4831,6 +4831,8 @@ export async function sendMessageAsUser(messageText, messageBias, insertAt = nul await eventSource.emit(event_types.USER_MESSAGE_RENDERED, chat_id); await saveChatConditional(); } + + return message; } /** diff --git a/public/scripts/slash-commands.js b/public/scripts/slash-commands.js index e9d0763c5..9fe306279 100644 --- a/public/scripts/slash-commands.js +++ b/public/scripts/slash-commands.js @@ -478,6 +478,7 @@ export function initDefaultSlashCommands() { SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'send', callback: sendUserMessageCallback, + returns: 'The text of the sent message', namedArgumentList: [ new SlashCommandNamedArgument( 'compact', @@ -2862,16 +2863,17 @@ async function sendUserMessageCallback(args, text) { insertAt = chat.length + insertAt; } + let message; if ('name' in args) { const name = args.name || ''; const avatar = findPersonaByName(name) || user_avatar; - await sendMessageAsUser(text, bias, insertAt, compact, name, avatar); + message = await sendMessageAsUser(text, bias, insertAt, compact, name, avatar); } else { - await sendMessageAsUser(text, bias, insertAt, compact); + message = await sendMessageAsUser(text, bias, insertAt, compact); } - return ''; + return message.mes; } async function deleteMessagesByNameCallback(_, name) { From 1c65a5badd6d9f5546fdbb620028676d21e01638 Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Mon, 30 Sep 2024 18:38:17 +0200 Subject: [PATCH 04/14] Update /ask toasts to warnings for consistency --- public/scripts/slash-commands.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/scripts/slash-commands.js b/public/scripts/slash-commands.js index 9fe306279..6335e93b1 100644 --- a/public/scripts/slash-commands.js +++ b/public/scripts/slash-commands.js @@ -2481,7 +2481,7 @@ async function askCharacter(args, text) { // Not supported in group chats // TODO: Maybe support group chats? if (selected_group) { - toastr.error('Cannot run /ask command in a group chat!'); + toastr.warning('Cannot run /ask command in a group chat!'); return ''; } @@ -2501,7 +2501,7 @@ async function askCharacter(args, text) { // Find the character const chId = characters.findIndex((e) => e.name === name || e.avatar === name); if (!characters[chId] || chId === -1) { - toastr.error('Character not found.'); + toastr.warning('Character not found.'); return ''; } From d8379edee7d8fb0a99e742aa929dc02602490860 Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Mon, 30 Sep 2024 23:32:24 +0200 Subject: [PATCH 05/14] Update return types as optional via named arg - Update the modified slash commands for chat sending to use the named arg - Add `slashCommandReturnHelper` for shared funcitonality on return type usage --- public/scripts/slash-commands.js | 37 ++++++++-- .../SlashCommandCommonEnumsProvider.js | 1 + .../SlashCommandReturnHelper.js | 74 +++++++++++++++++++ 3 files changed, 106 insertions(+), 6 deletions(-) create mode 100644 public/scripts/slash-commands/SlashCommandReturnHelper.js diff --git a/public/scripts/slash-commands.js b/public/scripts/slash-commands.js index 6335e93b1..599d6b850 100644 --- a/public/scripts/slash-commands.js +++ b/public/scripts/slash-commands.js @@ -71,6 +71,7 @@ import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCom import { SlashCommandDebugController } from './slash-commands/SlashCommandDebugController.js'; import { SlashCommandBreakController } from './slash-commands/SlashCommandBreakController.js'; import { SlashCommandExecutionError } from './slash-commands/SlashCommandExecutionError.js'; +import { slashCommandReturnHelper } from './slash-commands/SlashCommandReturnHelper.js'; export { executeSlashCommands, executeSlashCommandsWithOptions, getSlashCommandsHelp, registerSlashCommand, }; @@ -176,7 +177,7 @@ export function initDefaultSlashCommands() { SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'sendas', callback: sendMessageAs, - returns: 'The text of the sent message', + returns: 'Optionally the text of the sent message, if specified in the "return" argument', namedArgumentList: [ SlashCommandNamedArgument.fromProps({ name: 'name', @@ -195,6 +196,14 @@ export function initDefaultSlashCommands() { typeList: [ARGUMENT_TYPE.NUMBER], enumProvider: commonEnumProviders.messages({ allowIdAfter: true }), }), + SlashCommandNamedArgument.fromProps({ + name: 'return', + description: 'The way how you want the return value to be provided', + typeList: [ARGUMENT_TYPE.STRING], + defaultValue: 'none', + enumList: slashCommandReturnHelper.enumList({ allowObject: true }), + forceEnum: true, + }), ], unnamedArgumentList: [ new SlashCommandArgument( @@ -223,7 +232,7 @@ export function initDefaultSlashCommands() { name: 'sys', callback: sendNarratorMessage, aliases: ['nar'], - returns: 'The text of the sent message', + returns: 'Optionally the text of the sent message, if specified in the "return" argument', namedArgumentList: [ new SlashCommandNamedArgument( 'compact', @@ -239,6 +248,14 @@ export function initDefaultSlashCommands() { typeList: [ARGUMENT_TYPE.NUMBER], enumProvider: commonEnumProviders.messages({ allowIdAfter: true }), }), + SlashCommandNamedArgument.fromProps({ + name: 'return', + description: 'The way how you want the return value to be provided', + typeList: [ARGUMENT_TYPE.STRING], + defaultValue: 'none', + enumList: slashCommandReturnHelper.enumList({ allowObject: true }), + forceEnum: true, + }), ], unnamedArgumentList: [ new SlashCommandArgument( @@ -278,7 +295,7 @@ export function initDefaultSlashCommands() { SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'comment', callback: sendCommentMessage, - returns: 'The text of the sent message', + returns: 'Optionally the text of the sent message, if specified in the "return" argument', namedArgumentList: [ new SlashCommandNamedArgument( 'compact', @@ -294,6 +311,14 @@ export function initDefaultSlashCommands() { typeList: [ARGUMENT_TYPE.NUMBER], enumProvider: commonEnumProviders.messages({ allowIdAfter: true }), }), + SlashCommandNamedArgument.fromProps({ + name: 'return', + description: 'The way how you want the return value to be provided', + typeList: [ARGUMENT_TYPE.STRING], + defaultValue: 'none', + enumList: slashCommandReturnHelper.enumList({ allowObject: true }), + forceEnum: true, + }), ], unnamedArgumentList: [ new SlashCommandArgument( @@ -3210,7 +3235,7 @@ export async function sendMessageAs(args, text) { await saveChatConditional(); } - return message.mes; + return await slashCommandReturnHelper.doReturn(args.return ?? 'none', message, { objectToStringFunc: x => x.mes }); } export async function sendNarratorMessage(args, text) { @@ -3264,7 +3289,7 @@ export async function sendNarratorMessage(args, text) { await saveChatConditional(); } - return message.mes; + return await slashCommandReturnHelper.doReturn(args.return ?? 'none', message, { objectToStringFunc: x => x.mes }); } export async function promptQuietForLoudResponse(who, text) { @@ -3353,7 +3378,7 @@ async function sendCommentMessage(args, text) { await saveChatConditional(); } - return message.mes; + return await slashCommandReturnHelper.doReturn(args.return ?? 'none', message, { objectToStringFunc: x => x.mes }); } /** diff --git a/public/scripts/slash-commands/SlashCommandCommonEnumsProvider.js b/public/scripts/slash-commands/SlashCommandCommonEnumsProvider.js index 5612f47b5..bd5a7e8a3 100644 --- a/public/scripts/slash-commands/SlashCommandCommonEnumsProvider.js +++ b/public/scripts/slash-commands/SlashCommandCommonEnumsProvider.js @@ -36,6 +36,7 @@ export const enumIcons = { message: '💬', voice: '🎤', server: '🖥️', + popup: '🗔', true: '✔️', false: '❌', diff --git a/public/scripts/slash-commands/SlashCommandReturnHelper.js b/public/scripts/slash-commands/SlashCommandReturnHelper.js new file mode 100644 index 000000000..90ec0d783 --- /dev/null +++ b/public/scripts/slash-commands/SlashCommandReturnHelper.js @@ -0,0 +1,74 @@ +import { sendSystemMessage, system_message_types } from '../../script.js'; +import { callGenericPopup, POPUP_TYPE } from '../popup.js'; +import { escapeHtml } from '../utils.js'; +import { enumIcons } from './SlashCommandCommonEnumsProvider.js'; +import { enumTypes, SlashCommandEnumValue } from './SlashCommandEnumValue.js'; + +/** @typedef {'pipe'|'object'|'chat-html'|'chat-text'|'popup-html'|'popup-text'|'toast-html'|'toast-text'|'console'|'none'} SlashCommandReturnType */ + +export const slashCommandReturnHelper = { + /** + * Gets/creates the enum list of types of return relevant for a slash command + * + * @param {object} [options={}] Options + * @param {boolean} [options.allowPipe=true] Allow option to pipe the return value + * @param {boolean} [options.allowObject=false] Allow option to return the value as an object + * @param {boolean} [options.allowChat=false] Allow option to return the value as a chat message + * @param {boolean} [options.allowPopup=false] Allow option to return the value as a popup + * @returns {SlashCommandEnumValue[]} The enum list + */ + enumList: ({ allowPipe = true, allowObject = false, allowChat = false, allowPopup = false } = {}) => [ + allowPipe && new SlashCommandEnumValue('pipe', 'Return to the pipe for the next command', enumTypes.name, '|'), + allowObject && new SlashCommandEnumValue('object', 'Return as an object to the pipe for the next command', enumTypes.variable, enumIcons.dictionary), + allowChat && new SlashCommandEnumValue('chat-html', 'Sending a chat message with the return value - Can display HTML', enumTypes.command, enumIcons.message), + allowChat && new SlashCommandEnumValue('chat-text', 'Sending a chat message with the return value - Will only display as text', enumTypes.qr, enumIcons.message), + new SlashCommandEnumValue('popup-html', 'Showing as a popup with the return value - Can display HTML', enumTypes.command, enumIcons.popup), + new SlashCommandEnumValue('popup-text', 'Showing as a popup with the return value - Will only display as text', enumTypes.qr, enumIcons.popup), + new SlashCommandEnumValue('toast-html', 'Show the return value as a toast notification - Can display HTML', enumTypes.command, 'ℹ️'), + new SlashCommandEnumValue('toast-text', 'Show the return value as a toast notification - Will only display as text', enumTypes.qr, 'ℹ️'), + new SlashCommandEnumValue('console', 'Log the return value to the console', enumTypes.enum, '>'), + new SlashCommandEnumValue('none', 'No return value'), + ].filter(x => !!x), + + /** + * Handles the return value based on the specified type + * + * @param {SlashCommandReturnType} type The type of return + * @param {object|number|string} value The value to return + * @param {object} [options={}] Options + * @param {(o: object) => string} [options.objectToStringFunc=null] Function to convert the object to a string, if object was provided and 'object' was not the chosen return type + * @returns {Promise<*>} The processed return value + */ + async doReturn(type, value, { objectToStringFunc = o => o?.toString() } = {}) { + const stringValue = typeof value !== 'string' ? objectToStringFunc(value) : value; + + switch (type) { + case 'popup-html': + case 'popup-text': + case 'chat-text': + case 'chat-html': + case 'toast-text': + case 'toast-html': { + const shouldHtml = type.endsWith('html'); + const makeHtml = (str) => (new showdown.Converter()).makeHtml(str); + + if (type.startsWith('popup')) await callGenericPopup(shouldHtml ? makeHtml(stringValue) : escapeHtml(stringValue), POPUP_TYPE.TEXT); + if (type.startsWith('chat')) sendSystemMessage(system_message_types.GENERIC, shouldHtml ? makeHtml(stringValue) : escapeHtml(stringValue)); + if (type.startsWith('toast')) toastr.info(stringValue, null, { escapeHtml: !shouldHtml }); // Toastr handles HTML conversion internally already + + return ''; + } + case 'pipe': + return stringValue ?? ''; + case 'object': + return JSON.stringify(value); + case 'console': + console.info(value); + return ''; + case 'none': + return ''; + default: + throw new Error(`Unknown return type: ${type}`); + } + }, +}; From e3c0c5442c1646970802cb1243bb9e39279d28be Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Mon, 30 Sep 2024 23:37:21 +0200 Subject: [PATCH 06/14] Update /ask with return types, defaulting 'pipe' --- public/scripts/slash-commands.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/public/scripts/slash-commands.js b/public/scripts/slash-commands.js index 599d6b850..792e54bf1 100644 --- a/public/scripts/slash-commands.js +++ b/public/scripts/slash-commands.js @@ -456,7 +456,7 @@ export function initDefaultSlashCommands() { SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'ask', callback: askCharacter, - returns: 'the generated text', + returns: 'Optionally the text of the sent message, if specified in the "return" argument', namedArgumentList: [ SlashCommandNamedArgument.fromProps({ name: 'name', @@ -465,6 +465,14 @@ export function initDefaultSlashCommands() { isRequired: true, enumProvider: commonEnumProviders.characters('character'), }), + SlashCommandNamedArgument.fromProps({ + name: 'return', + description: 'The way how you want the return value to be provided', + typeList: [ARGUMENT_TYPE.STRING], + defaultValue: 'pipe', + enumList: slashCommandReturnHelper.enumList({ allowObject: true }), + forceEnum: true, + }), ], unnamedArgumentList: [ new SlashCommandArgument( @@ -2594,7 +2602,9 @@ async function askCharacter(args, text) { } } - return askResult; + const message = askResult ? chat[chat.length - 1] : null; + + return await slashCommandReturnHelper.doReturn(args.return ?? 'pipe', message, { objectToStringFunc: x => x.mes }); } async function hideMessageCallback(_, arg) { From 62fd450c592653fd256eaf631372cd05c72745ae Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Tue, 1 Oct 2024 00:06:18 +0200 Subject: [PATCH 07/14] Refactor /listinjects, deprecate its "format" arg --- public/scripts/slash-commands.js | 74 +++++++++++-------- .../SlashCommandReturnHelper.js | 16 ++-- 2 files changed, 55 insertions(+), 35 deletions(-) diff --git a/public/scripts/slash-commands.js b/public/scripts/slash-commands.js index 792e54bf1..17352b233 100644 --- a/public/scripts/slash-commands.js +++ b/public/scripts/slash-commands.js @@ -1525,11 +1525,20 @@ export function initDefaultSlashCommands() { name: 'listinjects', callback: listInjectsCallback, helpString: 'Lists all script injections for the current chat. Displays injects in a popup by default. Use the format argument to change the output format.', - returns: 'JSON object of script injections', + returns: 'Optionalls the JSON object of script injections', namedArgumentList: [ + SlashCommandNamedArgument.fromProps({ + name: 'return', + description: 'The way how you want the return value to be provided', + typeList: [ARGUMENT_TYPE.STRING], + defaultValue: 'object', + enumList: slashCommandReturnHelper.enumList({ allowPipe: false, allowObject: true, allowChat: true, allowPopup: true, allowTextVersion: false }), + forceEnum: true, + }), + // TODO remove some day SlashCommandNamedArgument.fromProps({ name: 'format', - description: 'output format', + description: 'DEPRECATED - use "return" instead - output format', typeList: [ARGUMENT_TYPE.STRING], isRequired: true, forceEnum: true, @@ -1798,37 +1807,44 @@ function injectCallback(args, value) { } async function listInjectsCallback(args) { - const type = String(args?.format).toLowerCase().trim(); - if (!chat_metadata.script_injects || !Object.keys(chat_metadata.script_injects).length) { - type !== 'none' && toastr.info('No script injections for the current chat'); - return JSON.stringify({}); + /** @type {import('./slash-commands/SlashCommandReturnHelper.js').SlashCommandReturnType} */ + let returnType = args.return; + + // Old legacy return type handling + if (args.format) { + toastr.warning(`Legacy argument 'format' with value '${args.format}' is deprecated. Please use 'return' instead. Routing to the correct return type...`, 'Deprecation warning'); + const type = String(args?.format).toLowerCase().trim(); + if (!chat_metadata.script_injects || !Object.keys(chat_metadata.script_injects).length) { + type !== 'none' && toastr.info('No script injections for the current chat'); + } + switch (type) { + case 'none': + returnType = 'none'; + break; + case 'chat': + returnType = 'chat-html'; + break; + case 'popup': + default: + returnType = 'popup-html'; + break; + } } - const injects = Object.entries(chat_metadata.script_injects) - .map(([id, inject]) => { - const position = Object.entries(extension_prompt_types); - const positionName = position.find(([_, value]) => value === inject.position)?.[0] ?? 'unknown'; - return `* **${id}**: ${inject.value} (${positionName}, depth: ${inject.depth}, scan: ${inject.scan ?? false}, role: ${inject.role ?? extension_prompt_roles.SYSTEM})`; - }) - .join('\n'); + // Now the actual new return type handling - const converter = new showdown.Converter(); - const messageText = `### Script injections:\n${injects}`; - const htmlMessage = DOMPurify.sanitize(converter.makeHtml(messageText)); + const buildTextValue = (injects) => { + const injectsStr = Object.entries(injects) + .map(([id, inject]) => { + const position = Object.entries(extension_prompt_types); + const positionName = position.find(([_, value]) => value === inject.position)?.[0] ?? 'unknown'; + return `* **${id}**: ${inject.value} (${positionName}, depth: ${inject.depth}, scan: ${inject.scan ?? false}, role: ${inject.role ?? extension_prompt_roles.SYSTEM})`; + }) + .join('\n'); + return `### Script injections:\n${injectsStr}`; + }; - switch (type) { - case 'none': - break; - case 'chat': - sendSystemMessage(system_message_types.GENERIC, htmlMessage); - break; - case 'popup': - default: - await callGenericPopup(htmlMessage, POPUP_TYPE.TEXT); - break; - } - - return JSON.stringify(chat_metadata.script_injects); + return await slashCommandReturnHelper.doReturn(returnType ?? 'object', chat_metadata.script_injects, { objectToStringFunc: buildTextValue }); } /** diff --git a/public/scripts/slash-commands/SlashCommandReturnHelper.js b/public/scripts/slash-commands/SlashCommandReturnHelper.js index 90ec0d783..cdcc914cd 100644 --- a/public/scripts/slash-commands/SlashCommandReturnHelper.js +++ b/public/scripts/slash-commands/SlashCommandReturnHelper.js @@ -7,6 +7,9 @@ import { enumTypes, SlashCommandEnumValue } from './SlashCommandEnumValue.js'; /** @typedef {'pipe'|'object'|'chat-html'|'chat-text'|'popup-html'|'popup-text'|'toast-html'|'toast-text'|'console'|'none'} SlashCommandReturnType */ export const slashCommandReturnHelper = { + // Without this, VSCode formatter fucks up JS docs. Don't ask me why. + _: false, + /** * Gets/creates the enum list of types of return relevant for a slash command * @@ -15,18 +18,19 @@ export const slashCommandReturnHelper = { * @param {boolean} [options.allowObject=false] Allow option to return the value as an object * @param {boolean} [options.allowChat=false] Allow option to return the value as a chat message * @param {boolean} [options.allowPopup=false] Allow option to return the value as a popup + * @param {boolean}[options.allowTextVersion=true] Used in combination with chat/popup/toast, some of them do not make sense for text versions, e.g.if you are building a HTML string anyway * @returns {SlashCommandEnumValue[]} The enum list */ - enumList: ({ allowPipe = true, allowObject = false, allowChat = false, allowPopup = false } = {}) => [ + enumList: ({ allowPipe = true, allowObject = false, allowChat = false, allowPopup = false, allowTextVersion = true } = {}) => [ allowPipe && new SlashCommandEnumValue('pipe', 'Return to the pipe for the next command', enumTypes.name, '|'), allowObject && new SlashCommandEnumValue('object', 'Return as an object to the pipe for the next command', enumTypes.variable, enumIcons.dictionary), allowChat && new SlashCommandEnumValue('chat-html', 'Sending a chat message with the return value - Can display HTML', enumTypes.command, enumIcons.message), - allowChat && new SlashCommandEnumValue('chat-text', 'Sending a chat message with the return value - Will only display as text', enumTypes.qr, enumIcons.message), - new SlashCommandEnumValue('popup-html', 'Showing as a popup with the return value - Can display HTML', enumTypes.command, enumIcons.popup), - new SlashCommandEnumValue('popup-text', 'Showing as a popup with the return value - Will only display as text', enumTypes.qr, enumIcons.popup), + allowChat && allowTextVersion && new SlashCommandEnumValue('chat-text', 'Sending a chat message with the return value - Will only display as text', enumTypes.qr, enumIcons.message), + allowPopup && new SlashCommandEnumValue('popup-html', 'Showing as a popup with the return value - Can display HTML', enumTypes.command, enumIcons.popup), + allowPopup && allowTextVersion && new SlashCommandEnumValue('popup-text', 'Showing as a popup with the return value - Will only display as text', enumTypes.qr, enumIcons.popup), new SlashCommandEnumValue('toast-html', 'Show the return value as a toast notification - Can display HTML', enumTypes.command, 'ℹ️'), - new SlashCommandEnumValue('toast-text', 'Show the return value as a toast notification - Will only display as text', enumTypes.qr, 'ℹ️'), - new SlashCommandEnumValue('console', 'Log the return value to the console', enumTypes.enum, '>'), + allowTextVersion && new SlashCommandEnumValue('toast-text', 'Show the return value as a toast notification - Will only display as text', enumTypes.qr, 'ℹ️'), + new SlashCommandEnumValue('console', 'Log the return value (object, if it can be one) to the console', enumTypes.enum, '>'), new SlashCommandEnumValue('none', 'No return value'), ].filter(x => !!x), From 697b3b2034c20ea15e48002929b696f85bfb3a64 Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Tue, 1 Oct 2024 00:23:00 +0200 Subject: [PATCH 08/14] Refactor /listvar, deprecate its "format" arg - Update /listvar - Fix toasts not doing correct HMTL here --- public/scripts/slash-commands.js | 9 +-- .../SlashCommandReturnHelper.js | 2 +- public/scripts/variables.js | 77 ++++++++++++------- 3 files changed, 55 insertions(+), 33 deletions(-) diff --git a/public/scripts/slash-commands.js b/public/scripts/slash-commands.js index 17352b233..d74eedbb9 100644 --- a/public/scripts/slash-commands.js +++ b/public/scripts/slash-commands.js @@ -1524,21 +1524,21 @@ export function initDefaultSlashCommands() { SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'listinjects', callback: listInjectsCallback, - helpString: 'Lists all script injections for the current chat. Displays injects in a popup by default. Use the format argument to change the output format.', + helpString: 'Lists all script injections for the current chat. Displays injects in a popup by default. Use the return argument to change the return type.', returns: 'Optionalls the JSON object of script injections', namedArgumentList: [ SlashCommandNamedArgument.fromProps({ name: 'return', description: 'The way how you want the return value to be provided', typeList: [ARGUMENT_TYPE.STRING], - defaultValue: 'object', + defaultValue: 'popup-html', enumList: slashCommandReturnHelper.enumList({ allowPipe: false, allowObject: true, allowChat: true, allowPopup: true, allowTextVersion: false }), forceEnum: true, }), // TODO remove some day SlashCommandNamedArgument.fromProps({ name: 'format', - description: 'DEPRECATED - use "return" instead - output format', + description: '!!! DEPRECATED - use "return" instead !!! output format)', typeList: [ARGUMENT_TYPE.STRING], isRequired: true, forceEnum: true, @@ -1832,7 +1832,6 @@ async function listInjectsCallback(args) { } // Now the actual new return type handling - const buildTextValue = (injects) => { const injectsStr = Object.entries(injects) .map(([id, inject]) => { @@ -1844,7 +1843,7 @@ async function listInjectsCallback(args) { return `### Script injections:\n${injectsStr}`; }; - return await slashCommandReturnHelper.doReturn(returnType ?? 'object', chat_metadata.script_injects, { objectToStringFunc: buildTextValue }); + return await slashCommandReturnHelper.doReturn(returnType ?? 'popup-html', chat_metadata.script_injects, { objectToStringFunc: buildTextValue }); } /** diff --git a/public/scripts/slash-commands/SlashCommandReturnHelper.js b/public/scripts/slash-commands/SlashCommandReturnHelper.js index cdcc914cd..941e1f302 100644 --- a/public/scripts/slash-commands/SlashCommandReturnHelper.js +++ b/public/scripts/slash-commands/SlashCommandReturnHelper.js @@ -58,7 +58,7 @@ export const slashCommandReturnHelper = { if (type.startsWith('popup')) await callGenericPopup(shouldHtml ? makeHtml(stringValue) : escapeHtml(stringValue), POPUP_TYPE.TEXT); if (type.startsWith('chat')) sendSystemMessage(system_message_types.GENERIC, shouldHtml ? makeHtml(stringValue) : escapeHtml(stringValue)); - if (type.startsWith('toast')) toastr.info(stringValue, null, { escapeHtml: !shouldHtml }); // Toastr handles HTML conversion internally already + if (type.startsWith('toast')) toastr.info(shouldHtml ? makeHtml(stringValue) : escapeHtml(stringValue), null, { escapeHtml: !shouldHtml }); return ''; } diff --git a/public/scripts/variables.js b/public/scripts/variables.js index e9cd8c653..55e9fe9ab 100644 --- a/public/scripts/variables.js +++ b/public/scripts/variables.js @@ -11,6 +11,7 @@ import { SlashCommandClosureResult } from './slash-commands/SlashCommandClosureR import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js'; import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js'; import { PARSER_FLAG, SlashCommandParser } from './slash-commands/SlashCommandParser.js'; +import { slashCommandReturnHelper } from './slash-commands/SlashCommandReturnHelper.js'; import { SlashCommandScope } from './slash-commands/SlashCommandScope.js'; import { isFalseBoolean, convertValueType, isTrueBoolean } from './utils.js'; @@ -305,7 +306,31 @@ export function replaceVariableMacros(input) { } async function listVariablesCallback(args) { - const type = String(args?.format || '').toLowerCase().trim() || 'popup'; + /** @type {import('./slash-commands/SlashCommandReturnHelper.js').SlashCommandReturnType} */ + let returnType = args.return; + + // Old legacy return type handling + if (args.format) { + toastr.warning(`Legacy argument 'format' with value '${args.format}' is deprecated. Please use 'return' instead. Routing to the correct return type...`, 'Deprecation warning'); + const type = String(args?.format).toLowerCase().trim(); + if (!chat_metadata.script_injects || !Object.keys(chat_metadata.script_injects).length) { + type !== 'none' && toastr.info('No script injections for the current chat'); + } + switch (type) { + case 'none': + returnType = 'none'; + break; + case 'chat': + returnType = 'chat-html'; + break; + case 'popup': + default: + returnType = 'popup-html'; + break; + } + } + + // Now the actual new return type handling const scope = String(args?.scope || '').toLowerCase().trim() || 'all'; if (!chat_metadata.variables) { chat_metadata.variables = {}; @@ -317,35 +342,24 @@ async function listVariablesCallback(args) { const localVariables = includeLocalVariables ? Object.entries(chat_metadata.variables).map(([name, value]) => `${name}: ${value}`) : []; const globalVariables = includeGlobalVariables ? Object.entries(extension_settings.variables.global).map(([name, value]) => `${name}: ${value}`) : []; + const buildTextValue = (_) => { + const localVariablesString = localVariables.length > 0 ? localVariables.join('\n\n') : 'No local variables'; + const globalVariablesString = globalVariables.length > 0 ? globalVariables.join('\n\n') : 'No global variables'; + const chatName = getCurrentChatId(); + + const message = [ + includeLocalVariables ? `### Local variables (${chatName}):\n${localVariablesString}` : '', + includeGlobalVariables ? `### Global variables:\n${globalVariablesString}` : '', + ].filter(x => x).join('\n\n'); + return message; + }; + const jsonVariables = [ ...Object.entries(chat_metadata.variables).map(x => ({ key: x[0], value: x[1], scope: 'local' })), ...Object.entries(extension_settings.variables.global).map(x => ({ key: x[0], value: x[1], scope: 'global' })), ]; - const localVariablesString = localVariables.length > 0 ? localVariables.join('\n\n') : 'No local variables'; - const globalVariablesString = globalVariables.length > 0 ? globalVariables.join('\n\n') : 'No global variables'; - const chatName = getCurrentChatId(); - - const converter = new showdown.Converter(); - const message = [ - includeLocalVariables ? `### Local variables (${chatName}):\n${localVariablesString}` : '', - includeGlobalVariables ? `### Global variables:\n${globalVariablesString}` : '', - ].filter(x => x).join('\n\n'); - const htmlMessage = DOMPurify.sanitize(converter.makeHtml(message)); - - switch (type) { - case 'none': - break; - case 'chat': - sendSystemMessage(system_message_types.GENERIC, htmlMessage); - break; - case 'popup': - default: - await callGenericPopup(htmlMessage, POPUP_TYPE.TEXT); - break; - } - - return JSON.stringify(jsonVariables); + return await slashCommandReturnHelper.doReturn(returnType ?? 'popup-html', jsonVariables, { objectToStringFunc: buildTextValue }); } /** @@ -910,7 +924,7 @@ export function registerVariableCommands() { name: 'listvar', callback: listVariablesCallback, aliases: ['listchatvar'], - helpString: 'List registered chat variables. Displays variables in a popup by default. Use the format argument to change the output format.', + helpString: 'List registered chat variables. Displays variables in a popup by default. Use the return argument to change the return type.', returns: 'JSON list of local variables', namedArgumentList: [ SlashCommandNamedArgument.fromProps({ @@ -926,9 +940,18 @@ export function registerVariableCommands() { new SlashCommandEnumValue('global', 'Global variables', enumTypes.enum, enumIcons.globalVariable), ], }), + SlashCommandNamedArgument.fromProps({ + name: 'return', + description: 'The way how you want the return value to be provided', + typeList: [ARGUMENT_TYPE.STRING], + defaultValue: 'popup-html', + enumList: slashCommandReturnHelper.enumList({ allowPipe: false, allowObject: true, allowChat: true, allowPopup: true, allowTextVersion: false }), + forceEnum: true, + }), + // TODO remove some day SlashCommandNamedArgument.fromProps({ name: 'format', - description: 'output format', + description: '!!! DEPRECATED - use "return" instead !!! output format)', typeList: [ARGUMENT_TYPE.STRING], isRequired: true, forceEnum: true, From 7a1b43eb8943b48747bd3efa139e81186346f964 Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Tue, 1 Oct 2024 00:37:21 +0200 Subject: [PATCH 09/14] Refactor /classify-expressions, deprecating... - Update /classify-expressions, deprecating the old "format" - Fix some oversights --- .../scripts/extensions/expressions/index.js | 40 +++++++++++++++---- public/scripts/slash-commands.js | 2 +- .../SlashCommandReturnHelper.js | 2 +- public/scripts/variables.js | 2 +- 4 files changed, 36 insertions(+), 10 deletions(-) diff --git a/public/scripts/extensions/expressions/index.js b/public/scripts/extensions/expressions/index.js index 71be1e422..a37d011c5 100644 --- a/public/scripts/extensions/expressions/index.js +++ b/public/scripts/extensions/expressions/index.js @@ -12,6 +12,8 @@ import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from ' import { isFunctionCallingSupported } from '../../openai.js'; import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashCommandEnumValue.js'; import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js'; +import { slashCommandReturnHelper } from '../../slash-commands/SlashCommandReturnHelper.js'; +import { SlashCommandClosure } from '../../slash-commands/SlashCommandClosure.js'; export { MODULE_NAME }; const MODULE_NAME = 'expressions'; @@ -2128,18 +2130,42 @@ function migrateSettings() { name: 'classify-expressions', aliases: ['expressions'], callback: async (args) => { - const list = await getExpressionsList(); - switch (String(args.format).toLowerCase()) { - case 'json': - return JSON.stringify(list); - default: - return list.join(', '); + /** @type {import('../../slash-commands/SlashCommandReturnHelper.js').SlashCommandReturnType} */ + // @ts-ignore + let returnType = args.return; + + // Old legacy return type handling + if (args.format) { + toastr.warning(`Legacy argument 'format' with value '${args.format}' is deprecated. Please use 'return' instead. Routing to the correct return type...`, 'Deprecation warning'); + const type = String(args?.format).toLowerCase().trim(); + switch (type) { + case 'json': + returnType = 'object'; + break; + default: + returnType = 'pipe'; + break; + } } + + // Now the actual new return type handling + const list = await getExpressionsList(); + + return await slashCommandReturnHelper.doReturn(returnType ?? 'pipe', list, { objectToStringFunc: list => list.join(', ') }); }, namedArgumentList: [ + SlashCommandNamedArgument.fromProps({ + name: 'return', + description: 'The way how you want the return value to be provided', + typeList: [ARGUMENT_TYPE.STRING], + defaultValue: 'pipe', + enumList: slashCommandReturnHelper.enumList({ allowObject: true }), + forceEnum: true, + }), + // TODO remove some day SlashCommandNamedArgument.fromProps({ name: 'format', - description: 'The format to return the list in: comma-separated plain text or JSON array. Default is plain text.', + description: '!!! DEPRECATED - use "return" instead !!! The format to return the list in: comma-separated plain text or JSON array. Default is plain text.', typeList: [ARGUMENT_TYPE.STRING], enumList: [ new SlashCommandEnumValue('plain', null, enumTypes.enum, ', '), diff --git a/public/scripts/slash-commands.js b/public/scripts/slash-commands.js index d74eedbb9..85744fdd8 100644 --- a/public/scripts/slash-commands.js +++ b/public/scripts/slash-commands.js @@ -1538,7 +1538,7 @@ export function initDefaultSlashCommands() { // TODO remove some day SlashCommandNamedArgument.fromProps({ name: 'format', - description: '!!! DEPRECATED - use "return" instead !!! output format)', + description: '!!! DEPRECATED - use "return" instead !!! output format', typeList: [ARGUMENT_TYPE.STRING], isRequired: true, forceEnum: true, diff --git a/public/scripts/slash-commands/SlashCommandReturnHelper.js b/public/scripts/slash-commands/SlashCommandReturnHelper.js index 941e1f302..9d34846bb 100644 --- a/public/scripts/slash-commands/SlashCommandReturnHelper.js +++ b/public/scripts/slash-commands/SlashCommandReturnHelper.js @@ -23,7 +23,7 @@ export const slashCommandReturnHelper = { */ enumList: ({ allowPipe = true, allowObject = false, allowChat = false, allowPopup = false, allowTextVersion = true } = {}) => [ allowPipe && new SlashCommandEnumValue('pipe', 'Return to the pipe for the next command', enumTypes.name, '|'), - allowObject && new SlashCommandEnumValue('object', 'Return as an object to the pipe for the next command', enumTypes.variable, enumIcons.dictionary), + allowObject && new SlashCommandEnumValue('object', 'Return as an object (or array) to the pipe for the next command', enumTypes.variable, enumIcons.dictionary), allowChat && new SlashCommandEnumValue('chat-html', 'Sending a chat message with the return value - Can display HTML', enumTypes.command, enumIcons.message), allowChat && allowTextVersion && new SlashCommandEnumValue('chat-text', 'Sending a chat message with the return value - Will only display as text', enumTypes.qr, enumIcons.message), allowPopup && new SlashCommandEnumValue('popup-html', 'Showing as a popup with the return value - Can display HTML', enumTypes.command, enumIcons.popup), diff --git a/public/scripts/variables.js b/public/scripts/variables.js index 55e9fe9ab..67844e375 100644 --- a/public/scripts/variables.js +++ b/public/scripts/variables.js @@ -951,7 +951,7 @@ export function registerVariableCommands() { // TODO remove some day SlashCommandNamedArgument.fromProps({ name: 'format', - description: '!!! DEPRECATED - use "return" instead !!! output format)', + description: '!!! DEPRECATED - use "return" instead !!! output format', typeList: [ARGUMENT_TYPE.STRING], isRequired: true, forceEnum: true, From f317b1b764eb5013fd3d88defd91f5165890a58a Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Tue, 1 Oct 2024 00:41:14 +0200 Subject: [PATCH 10/14] Oversight, missed /send in refactoring... --- public/scripts/slash-commands.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/public/scripts/slash-commands.js b/public/scripts/slash-commands.js index 85744fdd8..d1ab9523e 100644 --- a/public/scripts/slash-commands.js +++ b/public/scripts/slash-commands.js @@ -511,7 +511,7 @@ export function initDefaultSlashCommands() { SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'send', callback: sendUserMessageCallback, - returns: 'The text of the sent message', + returns: 'Optionally the text of the sent message, if specified in the "return" argument', namedArgumentList: [ new SlashCommandNamedArgument( 'compact', @@ -534,6 +534,14 @@ export function initDefaultSlashCommands() { defaultValue: '{{user}}', enumProvider: commonEnumProviders.personas, }), + SlashCommandNamedArgument.fromProps({ + name: 'return', + description: 'The way how you want the return value to be provided', + typeList: [ARGUMENT_TYPE.STRING], + defaultValue: 'none', + enumList: slashCommandReturnHelper.enumList({ allowObject: true }), + forceEnum: true, + }), ], unnamedArgumentList: [ new SlashCommandArgument( @@ -2923,7 +2931,7 @@ async function sendUserMessageCallback(args, text) { message = await sendMessageAsUser(text, bias, insertAt, compact); } - return message.mes; + return await slashCommandReturnHelper.doReturn(args.return ?? 'none', message, { objectToStringFunc: x => x.mes }); } async function deleteMessagesByNameCallback(_, name) { From 398ae6ba2e0c23fb12741ee2bfea52454e6a82cd Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Tue, 1 Oct 2024 00:53:19 +0200 Subject: [PATCH 11/14] Update doReturn() API with objectToHtmlFunc - Allow future commands to provide a different "object to HTML" converter func than "object to text", if need be --- .../slash-commands/SlashCommandReturnHelper.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/public/scripts/slash-commands/SlashCommandReturnHelper.js b/public/scripts/slash-commands/SlashCommandReturnHelper.js index 9d34846bb..be1a2da5a 100644 --- a/public/scripts/slash-commands/SlashCommandReturnHelper.js +++ b/public/scripts/slash-commands/SlashCommandReturnHelper.js @@ -41,10 +41,13 @@ export const slashCommandReturnHelper = { * @param {object|number|string} value The value to return * @param {object} [options={}] Options * @param {(o: object) => string} [options.objectToStringFunc=null] Function to convert the object to a string, if object was provided and 'object' was not the chosen return type + * @param {(o: object) => string} [options.objectToHtmlFunc=null] Analog to 'objectToStringFunc', which will be used here if not provided - but can do a different string layout if HTML is requested * @returns {Promise<*>} The processed return value */ - async doReturn(type, value, { objectToStringFunc = o => o?.toString() } = {}) { - const stringValue = typeof value !== 'string' ? objectToStringFunc(value) : value; + async doReturn(type, value, { objectToStringFunc = o => o?.toString(), objectToHtmlFunc = null } = {}) { + const shouldHtml = type.endsWith('html'); + const actualConverterFunc = shouldHtml && objectToHtmlFunc ? objectToHtmlFunc : objectToStringFunc; + const stringValue = typeof value !== 'string' ? actualConverterFunc(value) : value; switch (type) { case 'popup-html': @@ -53,12 +56,11 @@ export const slashCommandReturnHelper = { case 'chat-html': case 'toast-text': case 'toast-html': { - const shouldHtml = type.endsWith('html'); - const makeHtml = (str) => (new showdown.Converter()).makeHtml(str); + const htmlOrNotHtml = shouldHtml ? (new showdown.Converter()).makeHtml(stringValue) : escapeHtml(stringValue); - if (type.startsWith('popup')) await callGenericPopup(shouldHtml ? makeHtml(stringValue) : escapeHtml(stringValue), POPUP_TYPE.TEXT); - if (type.startsWith('chat')) sendSystemMessage(system_message_types.GENERIC, shouldHtml ? makeHtml(stringValue) : escapeHtml(stringValue)); - if (type.startsWith('toast')) toastr.info(shouldHtml ? makeHtml(stringValue) : escapeHtml(stringValue), null, { escapeHtml: !shouldHtml }); + if (type.startsWith('popup')) await callGenericPopup(htmlOrNotHtml, POPUP_TYPE.TEXT); + if (type.startsWith('chat')) sendSystemMessage(system_message_types.GENERIC, htmlOrNotHtml); + if (type.startsWith('toast')) toastr.info(htmlOrNotHtml, null, { escapeHtml: !shouldHtml }); return ''; } From 56265540dbeafc9afa0b6d8f5f26efa002d1b02f Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Tue, 1 Oct 2024 01:23:34 +0200 Subject: [PATCH 12/14] sanitize HTML on html returns - I had it in there for some time, I even tested it... likely gone during some commits --- public/scripts/slash-commands/SlashCommandReturnHelper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/scripts/slash-commands/SlashCommandReturnHelper.js b/public/scripts/slash-commands/SlashCommandReturnHelper.js index be1a2da5a..3601c30cd 100644 --- a/public/scripts/slash-commands/SlashCommandReturnHelper.js +++ b/public/scripts/slash-commands/SlashCommandReturnHelper.js @@ -56,7 +56,7 @@ export const slashCommandReturnHelper = { case 'chat-html': case 'toast-text': case 'toast-html': { - const htmlOrNotHtml = shouldHtml ? (new showdown.Converter()).makeHtml(stringValue) : escapeHtml(stringValue); + const htmlOrNotHtml = shouldHtml ? DOMPurify.sanitize((new showdown.Converter()).makeHtml(stringValue)) : escapeHtml(stringValue); if (type.startsWith('popup')) await callGenericPopup(htmlOrNotHtml, POPUP_TYPE.TEXT); if (type.startsWith('chat')) sendSystemMessage(system_message_types.GENERIC, htmlOrNotHtml); From f6726db9fb87efe785c57e2d8a32b6a97faee117 Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Tue, 1 Oct 2024 01:30:20 +0200 Subject: [PATCH 13/14] Fix empty script injections on /listinjects --- public/scripts/slash-commands.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/scripts/slash-commands.js b/public/scripts/slash-commands.js index 9347bf016..98738e5c3 100644 --- a/public/scripts/slash-commands.js +++ b/public/scripts/slash-commands.js @@ -1929,10 +1929,10 @@ async function listInjectsCallback(args) { return `* **${id}**: ${inject.value} (${positionName}, depth: ${inject.depth}, scan: ${inject.scan ?? false}, role: ${inject.role ?? extension_prompt_roles.SYSTEM})`; }) .join('\n'); - return `### Script injections:\n${injectsStr}`; + return `### Script injections:\n${injectsStr || 'No script injections for the current chat'}`; }; - return await slashCommandReturnHelper.doReturn(returnType ?? 'popup-html', chat_metadata.script_injects, { objectToStringFunc: buildTextValue }); + return await slashCommandReturnHelper.doReturn(returnType ?? 'popup-html', chat_metadata.script_injects ?? {}, { objectToStringFunc: buildTextValue }); } /** From 33222191be5782c8503addd3d10a7fc9afecae08 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Tue, 1 Oct 2024 19:15:53 +0300 Subject: [PATCH 14/14] Remove confusing toast from listvar --- public/scripts/variables.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/public/scripts/variables.js b/public/scripts/variables.js index 93c2238fd..c768c4f5e 100644 --- a/public/scripts/variables.js +++ b/public/scripts/variables.js @@ -313,9 +313,6 @@ async function listVariablesCallback(args) { if (args.format) { toastr.warning(`Legacy argument 'format' with value '${args.format}' is deprecated. Please use 'return' instead. Routing to the correct return type...`, 'Deprecation warning'); const type = String(args?.format).toLowerCase().trim(); - if (!chat_metadata.script_injects || !Object.keys(chat_metadata.script_injects).length) { - type !== 'none' && toastr.info('No script injections for the current chat'); - } switch (type) { case 'none': returnType = 'none';