diff --git a/public/scripts/authors-note.js b/public/scripts/authors-note.js
index fbc249aa2..a0307afee 100644
--- a/public/scripts/authors-note.js
+++ b/public/scripts/authors-note.js
@@ -12,6 +12,9 @@ import { extension_settings, getContext, saveMetadataDebounced } from './extensi
import { registerSlashCommand } from './slash-commands.js';
import { getCharaFilename, debounce, delay } from './utils.js';
import { getTokenCountAsync } from './tokenizers.js';
+import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
+import { SlashCommand } from './slash-commands/SlashCommand.js';
+import { ARGUMENT_TYPE, SlashCommandArgument } from './slash-commands/SlashCommandArgument.js';
export { MODULE_NAME as NOTE_MODULE_NAME };
const MODULE_NAME = '2_floating_prompt'; // <= Deliberate, for sorting lower than memory
@@ -454,9 +457,59 @@ export function initAuthorsNote() {
});
$('#option_toggle_AN').on('click', onANMenuItemClick);
- registerSlashCommand('note', setNoteTextCommand, [], '(text) – sets an author\'s note for the currently selected chat', true, true);
- registerSlashCommand('depth', setNoteDepthCommand, [], '(number) – sets an author\'s note depth for in-chat positioning', true, true);
- registerSlashCommand('freq', setNoteIntervalCommand, ['interval'], '(number) – sets an author\'s note insertion frequency', true, true);
- registerSlashCommand('pos', setNotePositionCommand, ['position'], '(chat or scenario) – sets an author\'s note position', true, true);
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'note',
+ callback: setNoteTextCommand,
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'text', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ helpString: `
+
+ Sets an author's note for the currently selected chat.
+
+ `,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'depth',
+ callback: setNoteDepthCommand,
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'number', [ARGUMENT_TYPE.NUMBER], true,
+ ),
+ ],
+ helpString: `
+
+ Sets an author's note depth for in-chat positioning.
+
+ `,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'freq',
+ callback: setNoteIntervalCommand,
+ namedArgumentList: [],
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'number', [ARGUMENT_TYPE.NUMBER], true,
+ ),
+ ],
+ helpString: `
+
+ Sets an author's note insertion frequency.
+
+ `,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'pos',
+ callback: setNotePositionCommand,
+ namedArgumentList: [],
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'position', [ARGUMENT_TYPE.STRING], true, false, null, ['chat', 'scenario'],
+ ),
+ ],
+ helpString: `
+
+ Sets an author's note position.
+
+ `,
+ }));
eventSource.on(event_types.CHAT_CHANGED, onChatChanged);
}
diff --git a/public/scripts/backgrounds.js b/public/scripts/backgrounds.js
index e462cb8f7..b3c1356c0 100644
--- a/public/scripts/backgrounds.js
+++ b/public/scripts/backgrounds.js
@@ -1,6 +1,8 @@
import { callPopup, chat_metadata, eventSource, event_types, generateQuietPrompt, getCurrentChatId, getRequestHeaders, getThumbnailUrl, saveSettingsDebounced } from '../script.js';
import { saveMetadataDebounced } from './extensions.js';
import { registerSlashCommand } from './slash-commands.js';
+import { SlashCommand } from './slash-commands/SlashCommand.js';
+import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
import { stringFormat } from './utils.js';
const BG_METADATA_KEY = 'custom_background';
@@ -481,7 +483,26 @@ export function initBackgrounds() {
$('#auto_background').on('click', autoBackgroundCommand);
$('#add_bg_button').on('change', onBackgroundUploadSelected);
$('#bg-filter').on('input', onBackgroundFilterInput);
- registerSlashCommand('lockbg', onLockBackgroundClick, ['bglock'], '– locks a background for the currently selected chat', true, true);
- registerSlashCommand('unlockbg', onUnlockBackgroundClick, ['bgunlock'], '– unlocks a background for the currently selected chat', true, true);
- registerSlashCommand('autobg', autoBackgroundCommand, ['bgauto'], '– automatically changes the background based on the chat context using the AI request prompt', true, true);
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'lockbg',
+ callback: onLockBackgroundClick,
+ aliases: ['bglock'],
+ helpString: 'Locks a background for the currently selected chat',
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'unlockbg',
+ callback: onUnlockBackgroundClick,
+ aliases: ['bgunlock'],
+ helpString: 'Unlocks a background for the currently selected chat',
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'autobg',
+ callback: autoBackgroundCommand,
+ aliases: ['bgauto'],
+ helpString: 'Automatically changes the background based on the chat context using the AI request prompt',
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ }));
+
}
diff --git a/public/scripts/extensions/attachments/index.js b/public/scripts/extensions/attachments/index.js
index ab3db9419..26e16cbaa 100644
--- a/public/scripts/extensions/attachments/index.js
+++ b/public/scripts/extensions/attachments/index.js
@@ -1,9 +1,19 @@
import { renderExtensionTemplateAsync } from '../../extensions.js';
import { registerSlashCommand } from '../../slash-commands.js';
+import { SlashCommand } from '../../slash-commands/SlashCommand.js';
+import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
jQuery(async () => {
const buttons = await renderExtensionTemplateAsync('attachments', 'buttons', {});
$('#extensionsMenu').prepend(buttons);
- registerSlashCommand('db', () => document.getElementById('manageAttachments')?.click(), ['databank', 'data-bank'], '– open the data bank', true, true);
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'db',
+ callback: () => document.getElementById('manageAttachments')?.click(),
+ aliases: ['databank', 'data-bank'],
+ helpString: 'Open the data bank',
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ }));
+
});
diff --git a/public/scripts/extensions/caption/index.js b/public/scripts/extensions/caption/index.js
index 572d02217..f197ba154 100644
--- a/public/scripts/extensions/caption/index.js
+++ b/public/scripts/extensions/caption/index.js
@@ -6,6 +6,9 @@ import { SECRET_KEYS, secret_state } from '../../secrets.js';
import { getMultimodalCaption } from '../shared.js';
import { textgen_types, textgenerationwebui_settings } from '../../textgen-settings.js';
import { registerSlashCommand } from '../../slash-commands.js';
+import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
+import { SlashCommand } from '../../slash-commands/SlashCommand.js';
+import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
export { MODULE_NAME };
const MODULE_NAME = 'caption';
@@ -492,5 +495,28 @@ jQuery(function () {
saveSettingsDebounced();
});
- registerSlashCommand('caption', captionCommandCallback, [], 'quiet=true/false [prompt] - caption an image with an optional prompt and passes the caption down the pipe. Only multimodal sources support custom prompts. Set the "quiet" argument to true to suppress sending a captioned message, default: false.', true, true);
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'caption',
+ callback: captionCommandCallback,
+ namedArgumentList: [
+ new SlashCommandNamedArgument(
+ 'quiet', 'suppress sending a captioned message', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false', ['true', 'false'],
+ ),
+ ],
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'prompt', [ARGUMENT_TYPE.STRING], false,
+ ),
+ ],
+ helpString: `
+
+ Caption an image with an optional prompt and passes the caption down the pipe.
+
+
+ Only multimodal sources support custom prompts.
+
+
+ Set the "quiet" argument to true to suppress sending a captioned message, default: false.
+
+ `,
+ }));
});
diff --git a/public/scripts/extensions/expressions/index.js b/public/scripts/extensions/expressions/index.js
index 8ff0ac935..abe3bf249 100644
--- a/public/scripts/extensions/expressions/index.js
+++ b/public/scripts/extensions/expressions/index.js
@@ -6,6 +6,9 @@ import { registerSlashCommand } from '../../slash-commands.js';
import { onlyUnique, debounce, getCharaFilename, trimToEndSentence, trimToStartSentence } from '../../utils.js';
import { hideMutedSprites } from '../../group-chats.js';
import { isJsonSchemaSupported } from '../../textgen-settings.js';
+import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
+import { SlashCommand } from '../../slash-commands/SlashCommand.js';
+import { ARGUMENT_TYPE, SlashCommandArgument } from '../../slash-commands/SlashCommandArgument.js';
export { MODULE_NAME };
const MODULE_NAME = 'expressions';
@@ -1965,9 +1968,68 @@ function migrateSettings() {
});
eventSource.on(event_types.MOVABLE_PANELS_RESET, updateVisualNovelModeDebounced);
eventSource.on(event_types.GROUP_UPDATED, updateVisualNovelModeDebounced);
- registerSlashCommand('sprite', setSpriteSlashCommand, ['emote'], '(spriteId) – force sets the sprite for the current character', true, true);
- registerSlashCommand('spriteoverride', setSpriteSetCommand, ['costume'], '(optional folder) – sets an override sprite folder for the current character. If the name starts with a slash or a backslash, selects a sub-folder in the character-named folder. Empty value to reset to default.', true, true);
- registerSlashCommand('lastsprite', (_, value) => lastExpression[value.trim()] ?? '', [], '(charName) – Returns the last set sprite / expression for the named character.', true, true);
- registerSlashCommand('th', toggleTalkingHeadCommand, ['talkinghead'], '– Character Expressions: toggles Image Type - talkinghead (extras) on/off.', true, true);
- registerSlashCommand('classify', classifyCommand, [], '(text) – performs an emotion classification of the given text and returns a label.', true, true);
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'sprite',
+ aliases: ['emote'],
+ callback: setSpriteSlashCommand,
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'spriteId', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ helpString: 'Force sets the sprite for the current character.',
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'spriteoverride',
+ aliases: ['costume'],
+ callback: setSpriteSetCommand,
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'optional folder', [ARGUMENT_TYPE.STRING], false,
+ ),
+ ],
+ helpString: 'Sets an override sprite folder for the current character. If the name starts with a slash or a backslash, selects a sub-folder in the character-named folder. Empty value to reset to default.',
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'lastsprite',
+ callback: (_, value) => lastExpression[value.trim()] ?? '',
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'charName', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ helpString: 'Returns the last set sprite / expression for the named character.',
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'th',
+ callback: toggleTalkingHeadCommand,
+ aliases: ['talkinghead'],
+ helpString: 'Character Expressions: toggles Image Type - talkinghead (extras) on/off.',
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'classify',
+ callback: classifyCommand,
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'text', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ returns: 'emotion classification label for the given text',
+ helpString: `
+
+ Performs an emotion classification of the given text and returns a label.
+
+
+ `,
+ }));
})();
diff --git a/public/scripts/extensions/gallery/index.js b/public/scripts/extensions/gallery/index.js
index 06d62d0a4..c1a7089f5 100644
--- a/public/scripts/extensions/gallery/index.js
+++ b/public/scripts/extensions/gallery/index.js
@@ -9,6 +9,9 @@ import { loadFileToDocument, delay } from '../../utils.js';
import { loadMovingUIState } from '../../power-user.js';
import { dragElement } from '../../RossAscends-mods.js';
import { registerSlashCommand } from '../../slash-commands.js';
+import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
+import { SlashCommand } from '../../slash-commands/SlashCommand.js';
+import { ARGUMENT_TYPE, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
const extensionName = 'gallery';
const extensionFolderPath = `scripts/extensions/${extensionName}/`;
@@ -415,8 +418,29 @@ function viewWithDragbox(items) {
// Registers a simple command for opening the char gallery.
-registerSlashCommand('show-gallery', showGalleryCommand, ['sg'], '– shows the gallery', true, true);
-registerSlashCommand('list-gallery', listGalleryCommand, ['lg'], '[optional char=charName] [optional group=groupName] – list images in the gallery of the current char / group or a specified char / group', true, true);
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'show-gallery',
+ aliases: ['sg'],
+ callback: showGalleryCommand,
+ helpString: 'Shows the gallery.',
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+}));
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'list-gallery',
+ aliases: ['lg'],
+ callback: listGalleryCommand,
+ namedArgumentList: [
+ new SlashCommandNamedArgument(
+ 'char', 'character name', [ARGUMENT_TYPE.STRING], false,
+ ),
+ new SlashCommandNamedArgument(
+ 'group', 'group name', [ARGUMENT_TYPE.STRING], false,
+ ),
+ ],
+ helpString: 'List images in the gallery of the current char / group or a specified char / group.',
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+}));
+
function showGalleryCommand(args) {
showCharGallery();
diff --git a/public/scripts/extensions/memory/index.js b/public/scripts/extensions/memory/index.js
index cb6bf95d5..b98311f07 100644
--- a/public/scripts/extensions/memory/index.js
+++ b/public/scripts/extensions/memory/index.js
@@ -20,6 +20,8 @@ import { registerSlashCommand } from '../../slash-commands.js';
import { loadMovingUIState } from '../../power-user.js';
import { dragElement } from '../../RossAscends-mods.js';
import { getTextTokens, getTokenCountAsync, tokenizers } from '../../tokenizers.js';
+import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
+import { SlashCommand } from '../../slash-commands/SlashCommand.js';
export { MODULE_NAME };
const MODULE_NAME = '1_memory';
@@ -864,5 +866,10 @@ jQuery(async function () {
eventSource.on(event_types.MESSAGE_EDITED, onChatEvent);
eventSource.on(event_types.MESSAGE_SWIPED, onChatEvent);
eventSource.on(event_types.CHAT_CHANGED, onChatEvent);
- registerSlashCommand('summarize', forceSummarizeChat, [], '– forces the summarization of the current chat using the Main API', true, true);
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'summarize',
+ callback: forceSummarizeChat,
+ helpString: 'Forces the summarization of the current chat using the Main API.',
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ }));
});
diff --git a/public/scripts/extensions/quick-reply/src/SlashCommandHandler.js b/public/scripts/extensions/quick-reply/src/SlashCommandHandler.js
index 45c120dcf..c22782103 100644
--- a/public/scripts/extensions/quick-reply/src/SlashCommandHandler.js
+++ b/public/scripts/extensions/quick-reply/src/SlashCommandHandler.js
@@ -1,4 +1,7 @@
import { registerSlashCommand } from '../../../slash-commands.js';
+import { SlashCommand } from '../../../slash-commands/SlashCommand.js';
+import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../../slash-commands/SlashCommandArgument.js';
+import { SlashCommandParser } from '../../../slash-commands/SlashCommandParser.js';
import { isTrueBoolean } from '../../../utils.js';
// eslint-disable-next-line no-unused-vars
import { QuickReplyApi } from '../api/QuickReplyApi.js';
@@ -17,46 +20,347 @@ export class SlashCommandHandler {
init() {
- registerSlashCommand('qr', (_, value) => this.executeQuickReplyByIndex(Number(value)), [], '(number) – activates the specified Quick Reply', true, true);
- registerSlashCommand('qrset', ()=>toastr.warning('The command /qrset has been deprecated. Use /qr-set, /qr-set-on, and /qr-set-off instead.'), [], 'DEPRECATED – The command /qrset has been deprecated. Use /qr-set, /qr-set-on, and /qr-set-off instead.', true, true);
- registerSlashCommand('qr-set', (args, value)=>this.toggleGlobalSet(value, args), [], '[visible=true] (number) – toggle global QR set', true, true);
- registerSlashCommand('qr-set-on', (args, value)=>this.addGlobalSet(value, args), [], '[visible=true] (number) – activate global QR set', true, true);
- registerSlashCommand('qr-set-off', (_, value)=>this.removeGlobalSet(value), [], '(number) – deactivate global QR set', true, true);
- registerSlashCommand('qr-chat-set', (args, value)=>this.toggleChatSet(value, args), [], '[visible=true] (number) – toggle chat QR set', true, true);
- registerSlashCommand('qr-chat-set-on', (args, value)=>this.addChatSet(value, args), [], '[visible=true] (number) – activate chat QR set', true, true);
- registerSlashCommand('qr-chat-set-off', (_, value)=>this.removeChatSet(value), [], '(number) – deactivate chat QR set', true, true);
- registerSlashCommand('qr-set-list', (_, value)=>this.listSets(value ?? 'all'), [], '(all|global|chat) – gets a list of the names of all quick reply sets', true, true);
- registerSlashCommand('qr-list', (_, value)=>this.listQuickReplies(value), [], '(set name) – gets a list of the names of all quick replies in this quick reply set', true, true);
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr',
+ callback: (_, value) => this.executeQuickReplyByIndex(Number(value)),
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'number', [ARGUMENT_TYPE.NUMBER], true,
+ ),
+ ],
+ helpString: 'Activates the specified Quick Reply',
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qrset',
+ callback: () => toastr.warning('The command /qrset has been deprecated. Use /qr-set, /qr-set-on, and /qr-set-off instead.'),
+ helpString: 'DEPRECATED – The command /qrset has been deprecated. Use /qr-set, /qr-set-on, and /qr-set-off instead.',
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-set',
+ callback: (args, value) => this.toggleGlobalSet(value, args),
+ namedArgumentList: [
+ new SlashCommandNamedArgument(
+ 'visible', 'set visibility', [ARGUMENT_TYPE.BOOLEAN], false, false, 'true',
+ ),
+ ],
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'QR set name', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ helpString: 'Toggle global QR set',
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-set-on',
+ callback: (args, value) => this.addGlobalSet(value, args),
+ namedArgumentList: [
+ new SlashCommandNamedArgument(
+ 'visible', 'set visibility', [ARGUMENT_TYPE.BOOLEAN], false, false, 'true',
+ ),
+ ],
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'QR set name', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ helpString: 'Activate global QR set',
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-set-off',
+ callback: (_, value) => this.removeGlobalSet(value),
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'QR set name', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ helpString: 'Deactivate global QR set',
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-chat-set',
+ callback: (args, value) => this.toggleChatSet(value, args),
+ namedArgumentList: [
+ new SlashCommandNamedArgument(
+ 'visible', 'set visibility', [ARGUMENT_TYPE.BOOLEAN], false, false, 'true',
+ ),
+ ],
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'QR set name', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ helpString: 'Toggle chat QR set',
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ }));
- const qrArgs = `
- label - string - text on the button, e.g., label=MyButton
- set - string - name of the QR set, e.g., set=PresetName1
- hidden - bool - whether the button should be hidden, e.g., hidden=true
- startup - bool - auto execute on app startup, e.g., startup=true
- user - bool - auto execute on user message, e.g., user=true
- bot - bool - auto execute on AI message, e.g., bot=true
- load - bool - auto execute on chat load, e.g., load=true
- group - bool - auto execute on group member selection, e.g., group=true
- title - string - title / tooltip to be shown on button, e.g., title="My Fancy Button"
- `.trim();
- const qrUpdateArgs = `
- newlabel - string - new text for the button, e.g. newlabel=MyRenamedButton
- ${qrArgs}
- `.trim();
- registerSlashCommand('qr-create', (args, message)=>this.createQuickReply(args, message), [], `[arguments] (message)\n arguments:\n ${qrArgs} – creates a new Quick Reply, example: /qr-create set=MyPreset label=MyButton /echo 123`, true, true);
- registerSlashCommand('qr-update', (args, message)=>this.updateQuickReply(args, message), [], `[arguments] (message)\n arguments:\n ${qrUpdateArgs} – updates Quick Reply, example: /qr-update set=MyPreset label=MyButton newlabel=MyRenamedButton /echo 123`, true, true);
- registerSlashCommand('qr-delete', (args, name)=>this.deleteQuickReply(args, name), [], 'set=string [label] – deletes Quick Reply', true, true);
- registerSlashCommand('qr-contextadd', (args, name)=>this.createContextItem(args, name), [], 'set=string label=string [chain=false] (preset name) – add context menu preset to a QR, example: /qr-contextadd set=MyPreset label=MyButton chain=true MyOtherPreset', true, true);
- registerSlashCommand('qr-contextdel', (args, name)=>this.deleteContextItem(args, name), [], 'set=string label=string (preset name) – remove context menu preset from a QR, example: /qr-contextdel set=MyPreset label=MyButton MyOtherPreset', true, true);
- registerSlashCommand('qr-contextclear', (args, label)=>this.clearContextMenu(args, label), [], 'set=string (label) – remove all context menu presets from a QR, example: /qr-contextclear set=MyPreset MyButton', true, true);
- const presetArgs = `
- nosend - bool - disable send / insert in user input (invalid for slash commands)
- before - bool - place QR before user input
- inject - bool - inject user input automatically (if disabled use {{input}})
- `.trim();
- registerSlashCommand('qr-set-create', (args, name)=>this.createSet(name, args), ['qr-presetadd'], `[arguments] (name)\n arguments:\n ${presetArgs} – create a new preset (overrides existing ones), example: /qr-set-add MyNewPreset`, true, true);
- registerSlashCommand('qr-set-update', (args, name)=>this.updateSet(name, args), ['qr-presetupdate'], `[arguments] (name)\n arguments:\n ${presetArgs} – update an existing preset, example: /qr-set-update enabled=false MyPreset`, true, true);
- registerSlashCommand('qr-set-delete', (args, name)=>this.deleteSet(name), ['qr-presetdelete'], `(name)\n arguments:\n ${presetArgs} – delete an existing preset, example: /qr-set-delete MyPreset`, true, true);
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-chat-set-on',
+ callback: (args, value) => this.addChatSet(value, args),
+ namedArgumentList: [
+ new SlashCommandNamedArgument(
+ 'visible', 'whether the QR set should be visible', [ARGUMENT_TYPE.BOOLEAN], false, false, 'true', ['true', 'false'],
+ ),
+ ],
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'QR set name', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ helpString: 'Activate chat QR set',
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-chat-set-off',
+ callback: (_, value) => this.removeChatSet(value),
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'QR set name', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ helpString: 'Deactivate chat QR set',
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-set-list',
+ callback: (_, value) => this.listSets(value ?? 'all'),
+ namedArgumentList: [],
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'set type', [ARGUMENT_TYPE.STRING], false, false, null, ['all', 'global', 'chat'],
+ ),
+ ],
+ helpString: 'Gets a list of the names of all quick reply sets.',
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-list',
+ callback: (_, value) => this.listQuickReplies(value),
+ namedArgumentList: [],
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'set name', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ helpString: 'Gets a list of the names of all quick replies in this quick reply set.',
+ }));
+
+ const qrArgs = [
+ new SlashCommandNamedArgument('label', 'text on the button, e.g., label=MyButton', [ARGUMENT_TYPE.STRING]),
+ new SlashCommandNamedArgument('set', 'name of the QR set, e.g., set=PresetName1', [ARGUMENT_TYPE.STRING]),
+ new SlashCommandNamedArgument('hidden', 'whether the button should be hidden, e.g., hidden=true', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false'),
+ new SlashCommandNamedArgument('startup', 'auto execute on app startup, e.g., startup=true', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false'),
+ new SlashCommandNamedArgument('user', 'auto execute on user message, e.g., user=true', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false'),
+ new SlashCommandNamedArgument('bot', 'auto execute on AI message, e.g., bot=true', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false'),
+ new SlashCommandNamedArgument('load', 'auto execute on chat load, e.g., load=true', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false'),
+ new SlashCommandNamedArgument('group', 'auto execute on group member selection, e.g., group=true', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false'),
+ new SlashCommandNamedArgument('title', 'title / tooltip to be shown on button, e.g., title="My Fancy Button"', [ARGUMENT_TYPE.STRING], false),
+ ];
+ const qrUpdateArgs = [
+ new SlashCommandNamedArgument('newlabel', 'new text for the button', [ARGUMENT_TYPE.STRING], false),
+ ];
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-create',
+ callback: (args, message) => this.createQuickReply(args, message),
+ namedArgumentList: qrArgs,
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'command', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ helpString: `
+ Creates a new Quick Reply.
+
+
+
Arguments:
+
${qrArgs}
+
+ `,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-update',
+ callback: (args, message) => this.updateQuickReply(args, message),
+ returns: 'updated quick reply',
+ namedArgumentList: [...qrUpdateArgs, ...qrArgs],
+ helpString: `
+
+ Updates Quick Reply.
+
+
+ `,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-delete',
+ callback: (args, name) => this.deleteQuickReply(args, name),
+ namedArgumentList: [
+ new SlashCommandNamedArgument(
+ 'set', 'Quick Reply set', [ARGUMENT_TYPE.STRING], true,
+ ),
+ new SlashCommandNamedArgument(
+ 'label', 'Quick Reply label', [ARGUMENT_TYPE.STRING], false,
+ ),
+ ],
+ helpString: 'Deletes a Quick Reply from the specified set. If no label is provided, the entire set is deleted.',
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-contextadd',
+ callback: (args, name) => this.createContextItem(args, name),
+ namedArgumentList: [
+ new SlashCommandNamedArgument(
+ 'set', 'string', [ARGUMENT_TYPE.STRING], true,
+ ),
+ new SlashCommandNamedArgument(
+ 'label', 'string', [ARGUMENT_TYPE.STRING], true,
+ ),
+ new SlashCommandNamedArgument(
+ 'chain', 'boolean', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false',
+ ),
+ ],
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'preset name', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ helpString: `
+
+ Add context menu preset to a QR.
+
+
+ `,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-contextdel',
+ callback: (args, name) => this.deleteContextItem(args, name),
+ namedArgumentList: [
+ new SlashCommandNamedArgument(
+ 'set', 'string', [ARGUMENT_TYPE.STRING], true,
+ ),
+ new SlashCommandNamedArgument(
+ 'label', 'string', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'preset name', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ helpString: `
+
+ Remove context menu preset from a QR.
+
+
+ `,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-contextclear',
+ callback: (args, label) => this.clearContextMenu(args, label),
+ namedArgumentList: [
+ new SlashCommandNamedArgument(
+ 'set', 'context menu preset name', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'label', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ helpString: `
+
+ Remove all context menu presets from a QR.
+
+
+ `,
+ purgeFromMessage: true,
+ interruptsGeneration: true,
+ }));
+
+ const presetArgs = [
+ new SlashCommandNamedArgument('nosend', 'disable send / insert in user input (invalid for slash commands)', [ARGUMENT_TYPE.BOOLEAN], false),
+ new SlashCommandNamedArgument('before', 'place QR before user input', [ARGUMENT_TYPE.BOOLEAN], false),
+ new SlashCommandNamedArgument('inject', 'inject user input automatically (if disabled use {{input}})', [ARGUMENT_TYPE.BOOLEAN], false),
+ ];
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-set-create',
+ callback: (args, name) => this.createSet(name, args),
+ aliases: ['qr-presetadd'],
+ namedArgumentList: presetArgs,
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'name', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ helpString: `
+
+ Create a new preset (overrides existing ones).
+
+
+
Example:
+
+ -
+
/qr-set-add MyNewPreset
+
+
+
+ `,
+ }));
+
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-set-update',
+ callback: (args, name) => this.updateSet(name, args),
+ aliases: ['qr-presetupdate'],
+ namedArgumentList: presetArgs,
+ unnamedArgumentList: [
+ new SlashCommandArgument('name', [ARGUMENT_TYPE.STRING], true),
+ ],
+ helpString: `
+
+ Update an existing preset.
+
+
+
Example:
+
/qr-set-update enabled=false MyPreset
+
+ `,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-set-delete',
+ callback: (args, name) => this.deleteSet(name),
+ aliases: ['qr-presetdelete'],
+ unnamedArgumentList: [
+ new SlashCommandArgument('name', [ARGUMENT_TYPE.STRING], true),
+ ],
+ helpString: `
+
+ Delete an existing preset.
+
+
+
Example:
+
/qr-set-delete MyPreset
+
+ `,
+ }));
}
diff --git a/public/scripts/extensions/regex/index.js b/public/scripts/extensions/regex/index.js
index 5115af276..fd4714154 100644
--- a/public/scripts/extensions/regex/index.js
+++ b/public/scripts/extensions/regex/index.js
@@ -1,6 +1,9 @@
import { callPopup, getCurrentChatId, reloadCurrentChat, saveSettingsDebounced } from '../../../script.js';
import { extension_settings, renderExtensionTemplateAsync } from '../../extensions.js';
import { registerSlashCommand } from '../../slash-commands.js';
+import { SlashCommand } from '../../slash-commands/SlashCommand.js';
+import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
+import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
import { download, getFileText, getSortableDelay, uuidv4 } from '../../utils.js';
import { resolveVariable } from '../../variables.js';
import { regex_placement, runRegexScript } from './engine.js';
@@ -353,5 +356,19 @@ jQuery(async () => {
await loadRegexScripts();
$('#saved_regex_scripts').sortable('enable');
- registerSlashCommand('regex', runRegexCallback, [], '(name=scriptName [input]) – runs a Regex extension script by name on the provided string. The script must be enabled.', true, true);
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'regex',
+ callback: runRegexCallback,
+ namedArgumentList: [
+ new SlashCommandNamedArgument(
+ 'name', 'script name', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'input', [ARGUMENT_TYPE.STRING], false,
+ ),
+ ],
+ helpString: 'Runs a Regex extension script by name on the provided string. The script must be enabled.',
+ }));
+
});
diff --git a/public/scripts/extensions/stable-diffusion/index.js b/public/scripts/extensions/stable-diffusion/index.js
index 88fdbad40..bd49e52bf 100644
--- a/public/scripts/extensions/stable-diffusion/index.js
+++ b/public/scripts/extensions/stable-diffusion/index.js
@@ -26,6 +26,9 @@ import { SECRET_KEYS, secret_state } from '../../secrets.js';
import { getNovelUnlimitedImageGeneration, getNovelAnlas, loadNovelSubscriptionData } from '../../nai-settings.js';
import { getMultimodalCaption } from '../shared.js';
import { registerSlashCommand } from '../../slash-commands.js';
+import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
+import { SlashCommand } from '../../slash-commands/SlashCommand.js';
+import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
export { MODULE_NAME };
// Wraps a string into monospace font-face span
@@ -3025,8 +3028,42 @@ $('#sd_dropdown [id]').on('click', function () {
});
jQuery(async () => {
- registerSlashCommand('imagine', generatePicture, ['sd', 'img', 'image'], helpString, true, true);
- registerSlashCommand('imagine-comfy-workflow', changeComfyWorkflow, ['icw'], '(workflowName) - change the workflow to be used for image generation with ComfyUI, e.g. /imagine-comfy-workflow MyWorkflow');
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'imagine',
+ callback: generatePicture,
+ aliases: ['sd', 'img', 'image'],
+ namedArgumentList: [
+ new SlashCommandNamedArgument(
+ 'quiet', 'whether to post the generated image to chat', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false', ['false', 'true'],
+ ),
+ ],
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'argument', [ARGUMENT_TYPE.STRING], false, false, null, Object.values(triggerWords).flat(),
+ ),
+ ],
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ helpString: `
+
+ Requests to generate an image and posts it to chat (unless quiet=true argument is specified). Supported arguments: ${Object.values(triggerWords).flat().join(', ')}
.
+
+
+ Anything else would trigger a "free mode" to make generate whatever you prompted. Example: /imagine apple tree
would generate a picture of an apple tree. Returns a link to the generated image.
+
+ `,
+ }));
+
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'imagine-comfy-workflow',
+ callback: changeComfyWorkflow,
+ aliases: ['icw'],
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'workflowName', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ helpString: '(workflowName) - change the workflow to be used for image generation with ComfyUI, e.g. /imagine-comfy-workflow MyWorkflow
',
+ }));
+
const template = await renderExtensionTemplateAsync('stable-diffusion', 'settings', defaultSettings);
$('#extensions_settings').append(template);
diff --git a/public/scripts/extensions/token-counter/index.js b/public/scripts/extensions/token-counter/index.js
index d9231dac1..91c6f32ef 100644
--- a/public/scripts/extensions/token-counter/index.js
+++ b/public/scripts/extensions/token-counter/index.js
@@ -1,6 +1,8 @@
import { callPopup, main_api } from '../../../script.js';
import { getContext } from '../../extensions.js';
import { registerSlashCommand } from '../../slash-commands.js';
+import { SlashCommand } from '../../slash-commands/SlashCommand.js';
+import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
import { getFriendlyTokenizerName, getTextTokens, getTokenCountAsync, tokenizers } from '../../tokenizers.js';
import { resetScrollHeight, debounce } from '../../utils.js';
@@ -131,5 +133,11 @@ jQuery(() => {
`;
$('#extensionsMenu').prepend(buttonHtml);
$('#token_counter').on('click', doTokenCounter);
- registerSlashCommand('count', doCount, [], '– counts the number of tokens in the current chat', true, false);
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'count',
+ callback: doCount,
+ helpString: 'Counts the number of tokens in the current chat.',
+ interruptsGeneration: true,
+ purgeFromMessage: false,
+ }));
+
});
diff --git a/public/scripts/extensions/tts/index.js b/public/scripts/extensions/tts/index.js
index 6203bd213..b64eaf20a 100644
--- a/public/scripts/extensions/tts/index.js
+++ b/public/scripts/extensions/tts/index.js
@@ -13,6 +13,9 @@ import { OpenAITtsProvider } from './openai.js';
import { XTTSTtsProvider } from './xtts.js';
import { AllTalkTtsProvider } from './alltalk.js';
import { SpeechT5TtsProvider } from './speecht5.js';
+import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
+import { SlashCommand } from '../../slash-commands/SlashCommand.js';
+import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
export { talkingAnimation };
const UPDATE_INTERVAL = 1000;
@@ -1063,6 +1066,37 @@ $(document).ready(function () {
eventSource.on(event_types.GROUP_UPDATED, onChatChanged);
eventSource.on(event_types.MESSAGE_SENT, onMessageEvent);
eventSource.on(event_types.MESSAGE_RECEIVED, onMessageEvent);
- registerSlashCommand('speak', onNarrateText, ['narrate', 'tts'], '(text) – narrate any text using currently selected character\'s voice. Use voice="Character Name" argument to set other voice from the voice map, example: /speak voice="Donald Duck" Quack!', true, true);
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'speak',
+ callback: onNarrateText,
+ aliases: ['narrate', 'tts'],
+ namedArgumentList: [
+ new SlashCommandNamedArgument(
+ 'voice', 'character voice name', [ARGUMENT_TYPE.STRING], false,
+ ),
+ ],
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'text', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ helpString: `
+
+ Narrate any text using currently selected character's voice.
+
+
+ Use voice="Character Name"
argument to set other voice from the voice map.
+
+
+ `,
+ }));
+
document.body.appendChild(audioElement);
});
diff --git a/public/scripts/openai.js b/public/scripts/openai.js
index 10b15326d..6682568d9 100644
--- a/public/scripts/openai.js
+++ b/public/scripts/openai.js
@@ -66,6 +66,9 @@ import {
} from './instruct-mode.js';
import { isMobile } from './RossAscends-mods.js';
import { saveLogprobsForActiveMessage } from './logprobs.js';
+import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
+import { SlashCommand } from './slash-commands/SlashCommand.js';
+import { ARGUMENT_TYPE, SlashCommandArgument } from './slash-commands/SlashCommandArgument.js';
export {
openai_messages_count,
@@ -4292,7 +4295,17 @@ function runProxyCallback(_, value) {
return foundName;
}
-registerSlashCommand('proxy', runProxyCallback, [], '(name) – sets a proxy preset by name');
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'proxy',
+ callback: runProxyCallback,
+ namedArgumentList: [],
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'name', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ helpString: 'Sets a proxy preset by name.',
+}));
+
$(document).ready(async function () {
$('#test_api_button').on('click', testApiConnection);
diff --git a/public/scripts/power-user.js b/public/scripts/power-user.js
index d74b0c064..1cab70e15 100644
--- a/public/scripts/power-user.js
+++ b/public/scripts/power-user.js
@@ -41,7 +41,9 @@ import { BIAS_CACHE } from './logit-bias.js';
import { renderTemplateAsync } from './templates.js';
import { countOccurrences, debounce, delay, download, getFileText, isOdd, resetScrollHeight, shuffle, sortMoments, stringToRange, timestampToMoment } from './utils.js';
-import { PARSER_FLAG } from './slash-commands/SlashCommandParser.js';
+import { PARSER_FLAG, SlashCommandParser } from './slash-commands/SlashCommandParser.js';
+import { SlashCommand } from './slash-commands/SlashCommand.js';
+import { ARGUMENT_TYPE, SlashCommandArgument } from './slash-commands/SlashCommandArgument.js';
export {
loadPowerUserSettings,
@@ -3622,13 +3624,96 @@ $(document).ready(() => {
browser_has_focus = false;
});
- registerSlashCommand('vn', toggleWaifu, [], '– swaps Visual Novel Mode On/Off', false, true);
- registerSlashCommand('newchat', doNewChat, [], '– start a new chat with current character', true, true);
- registerSlashCommand('random', doRandomChat, [], '(optional tag name) – start a new chat with a random character. If an argument is provided, only considers characters that have the specified tag.', true, true);
- registerSlashCommand('delmode', doDelMode, ['del'], '(optional number) – enter message deletion mode, and auto-deletes last N messages if numeric argument is provided', true, true);
- registerSlashCommand('cut', doMesCut, [], '(number or range) – cuts the specified message or continuous chunk from the chat, e.g. /cut 0-10. Ranges are inclusive! Returns the text of cut messages separated by a newline.', true, true);
- registerSlashCommand('resetpanels', doResetPanels, ['resetui'], '– resets UI panels to original state.', true, true);
- registerSlashCommand('bgcol', setAvgBG, [], '– WIP test of auto-bg avg coloring', true, true);
- registerSlashCommand('theme', setThemeCallback, [], '(name) – sets a UI theme by name', true, true);
- registerSlashCommand('movingui', setmovingUIPreset, [], '(name) – activates a movingUI preset by name', true, true);
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'vn',
+ callback: toggleWaifu,
+ helpString: 'Swaps Visual Novel Mode On/Off',
+ interruptsGeneration: false,
+ purgeFromMessage: true,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'newchat',
+ callback: doNewChat,
+ helpString: 'Start a new chat with the current character',
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'random',
+ callback: doRandomChat,
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'optional tag name', [ARGUMENT_TYPE.STRING], false,
+ ),
+ ],
+ helpString: 'Start a new chat with a random character. If an argument is provided, only considers characters that have the specified tag.',
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'delmode',
+ callback: doDelMode,
+ aliases: ['del'],
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'optional number', [ARGUMENT_TYPE.NUMBER], false,
+ ),
+ ],
+ helpString: 'Enter message deletion mode, and auto-deletes last N messages if numeric argument is provided.',
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'cut',
+ callback: doMesCut,
+ returns: 'the text of cut messages separated by a newline',
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'number or range', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE], true,
+ ),
+ ],
+ helpString: `
+
+ Cuts the specified message or continuous chunk from the chat.
+
+
+ Ranges are inclusive!
+
+
+ `,
+ aliases: [],
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'resetpanels',
+ callback: doResetPanels,
+ helpString: 'resets UI panels to original state',
+ aliases: ['resetui'],
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'bgcol',
+ callback: setAvgBG,
+ helpString: '– WIP test of auto-bg avg coloring',
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'theme',
+ callback: setThemeCallback,
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'name', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ helpString: 'sets a UI theme by name',
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'movingui',
+ callback: setmovingUIPreset,
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'name', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ helpString: 'activates a movingUI preset by name',
+ }));
});
diff --git a/public/scripts/preset-manager.js b/public/scripts/preset-manager.js
index 1a28f075c..d9bdf7e47 100644
--- a/public/scripts/preset-manager.js
+++ b/public/scripts/preset-manager.js
@@ -21,6 +21,9 @@ import { instruct_presets } from './instruct-mode.js';
import { kai_settings } from './kai-settings.js';
import { context_presets, getContextSettings, power_user } from './power-user.js';
import { registerSlashCommand } from './slash-commands.js';
+import { SlashCommand } from './slash-commands/SlashCommand.js';
+import { ARGUMENT_TYPE, SlashCommandArgument } from './slash-commands/SlashCommandArgument.js';
+import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
import {
textgenerationwebui_preset_names,
textgenerationwebui_presets,
@@ -470,7 +473,33 @@ async function waitForConnection() {
export async function initPresetManager() {
eventSource.on(event_types.CHAT_CHANGED, autoSelectPreset);
registerPresetManagers();
- registerSlashCommand('preset', presetCommandCallback, [], '(name) – sets a preset by name for the current API. Gets the current preset if no name is provided', true, true);
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'preset',
+ callback: presetCommandCallback,
+ namedArgumentList: [],
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'name', [ARGUMENT_TYPE.STRING], false,
+ ),
+ ],
+ helpString: `
+
+ Sets a preset by name for the current API. Gets the current preset if no name is provided.
+
+
+
Example:
+
+ -
+
/preset myPreset
+
+ -
+
/preset
+
+
+
+ `,
+ }));
+
$(document).on('click', '[data-preset-manager-update]', async function () {
const apiId = $(this).data('preset-manager-update');
diff --git a/public/scripts/world-info.js b/public/scripts/world-info.js
index 767f923d0..7199d29e2 100644
--- a/public/scripts/world-info.js
+++ b/public/scripts/world-info.js
@@ -9,6 +9,9 @@ import { getTokenCountAsync } from './tokenizers.js';
import { power_user } from './power-user.js';
import { getTagKeyForEntity } from './tags.js';
import { resolveVariable } from './variables.js';
+import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
+import { SlashCommand } from './slash-commands/SlashCommand.js';
+import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js';
export {
world_info,
@@ -590,12 +593,166 @@ function registerWorldInfoSlashCommands() {
return '';
}
- registerSlashCommand('world', onWorldInfoChange, [], '[optional state=off|toggle] [optional silent=true] (optional name) – sets active World, or unsets if no args provided, use state=off
and state=toggle
to deactivate or toggle a World, use silent=true
to suppress toast messages', true, true);
- registerSlashCommand('getchatbook', getChatBookCallback, ['getchatlore', 'getchatwi'], '– get a name of the chat-bound lorebook or create a new one if was unbound, and pass it down the pipe', true, true);
- registerSlashCommand('findentry', findBookEntryCallback, ['findlore', 'findwi'], '(file=bookName field=field [texts]) – find a UID of the record from the specified book using the fuzzy match of a field value (default: key) and pass it down the pipe, e.g. /findentry file=chatLore field=key Shadowfang', true, true);
- registerSlashCommand('getentryfield', getEntryFieldCallback, ['getlorefield', 'getwifield'], '(file=bookName field=field [UID]) – get a field value (default: content) of the record with the UID from the specified book and pass it down the pipe, e.g. /getentryfield file=chatLore field=content 123', true, true);
- registerSlashCommand('createentry', createEntryCallback, ['createlore', 'createwi'], '(file=bookName key=key [content]) – create a new record in the specified book with the key and content (both are optional) and pass the UID down the pipe, e.g. /createentry file=chatLore key=Shadowfang The sword of the king', true, true);
- registerSlashCommand('setentryfield', setEntryFieldCallback, ['setlorefield', 'setwifield'], '(file=bookName uid=UID field=field [value]) – set a field value (default: content) of the record with the UID from the specified book. To set multiple values for key fields, use comma-delimited list as a value, e.g. /setentryfield file=chatLore uid=123 field=key Shadowfang,sword,weapon', true, true);
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'world',
+ callback: onWorldInfoChange,
+ namedArgumentList: [
+ new SlashCommandNamedArgument(
+ 'state', 'set world state', [ARGUMENT_TYPE.STRING], false, false, null, ['off', 'toggle'],
+ ),
+ new SlashCommandNamedArgument(
+ 'silent', 'suppress toast messages', [ARGUMENT_TYPE.BOOLEAN], false,
+ ),
+ ],
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'name', [ARGUMENT_TYPE.STRING], false,
+ ),
+ ],
+ helpString: `
+
+ Sets active World, or unsets if no args provided, use state=off
and state=toggle
to deactivate or toggle a World, use silent=true
to suppress toast messages.
+
+ `,
+ aliases: [],
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'getchatbook',
+ callback: getChatBookCallback,
+ helpString: 'Get a name of the chat-bound lorebook or create a new one if was unbound, and pass it down the pipe.',
+ aliases: ['getchatlore', 'getchatwi'],
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'findentry',
+ aliases: ['findlore', 'findwi'],
+ callback: findBookEntryCallback,
+ namedArgumentList: [
+ new SlashCommandNamedArgument(
+ 'file', 'bookName', ARGUMENT_TYPE.STRING, true,
+ ),
+ new SlashCommandNamedArgument(
+ 'field', 'field value for fuzzy match (default: key)', ARGUMENT_TYPE.STRING, false, false, 'key',
+ ),
+ ],
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'texts', ARGUMENT_TYPE.STRING, true, true,
+ ),
+ ],
+ helpString: `
+
+ Find a UID of the record from the specified book using the fuzzy match of a field value (default: key) and pass it down the pipe.
+
+
+ `,
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'getentryfield',
+ aliases: ['getlorefield', 'getwifield'],
+ callback: getEntryFieldCallback,
+ namedArgumentList: [
+ new SlashCommandNamedArgument(
+ 'file', 'bookName', ARGUMENT_TYPE.STRING, true,
+ ),
+ new SlashCommandNamedArgument(
+ 'field', 'field to retrieve (default: content)', ARGUMENT_TYPE.STRING, false, false, 'content',
+ ),
+ ],
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'UID', ARGUMENT_TYPE.STRING, true,
+ ),
+ ],
+ helpString: `
+
+ Get a field value (default: content) of the record with the UID from the specified book and pass it down the pipe.
+
+
+ `,
+ interruptsGeneration: true,
+ purgeFromMessage: true,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'createentry',
+ callback: createEntryCallback,
+ aliases: ['createlore', 'createwi'],
+ returns: 'UID of the new record',
+ namedArgumentList: [
+ new SlashCommandNamedArgument(
+ 'file', 'book name', [ARGUMENT_TYPE.STRING], true,
+ ),
+ new SlashCommandNamedArgument(
+ 'key', 'record key', [ARGUMENT_TYPE.STRING], false,
+ ),
+ ],
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'content', [ARGUMENT_TYPE.STRING], false,
+ ),
+ ],
+ helpString: `
+
+ Create a new record in the specified book with the key and content (both are optional) and pass the UID down the pipe.
+
+
+ `,
+ }));
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'setentryfield',
+ callback: setEntryFieldCallback,
+ aliases: ['setlorefield', 'setwifield'],
+ namedArgumentList: [
+ new SlashCommandNamedArgument(
+ 'file', 'book name', [ARGUMENT_TYPE.STRING], true,
+ ),
+ new SlashCommandNamedArgument(
+ 'uid', 'record UID', [ARGUMENT_TYPE.STRING], true,
+ ),
+ new SlashCommandNamedArgument(
+ 'field', 'field name', [ARGUMENT_TYPE.STRING], true, false, 'content',
+ ),
+ ],
+ unnamedArgumentList: [
+ new SlashCommandArgument(
+ 'value', [ARGUMENT_TYPE.STRING], true,
+ ),
+ ],
+ helpString: `
+
+ Set a field value (default: content) of the record with the UID from the specified book. To set multiple values for key fields, use comma-delimited list as a value.
+
+
+ `,
+ }));
+
}
// World Info Editor