fix: Slash command descriptions and argument help text are not translated (#4434) * fix: Slash command descriptions and argument help text are not translated #4428 * fix * fix: Refine slash command translation scope per review * fix * Join split multiline strings * Revert error name --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>

f9d1279a69270109ebf0aa80ca84220a9688c34d

MAX-TAB <60381043+MAX-TAB@users.noreply.github.com>

Signed
2 files changed, +517 -527Ignore whitespace
public/scripts/slash-commands.js+503 -512
@@ -229,7 +229,7 @@ export function initDefaultSlashCommands() {
229229 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
230230 name: 'dupe',
231231 callback: duplicateCharacter,
232232 helpString: 't`Duplicates the currently selected character.'`,
233233 }));
234234 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
235235 name: 'api',
@@ -306,11 +306,11 @@ export function initDefaultSlashCommands() {
306306 toastr.clear(toast);
307307 return text?.toString()?.trim() ?? '';
308308 },
309309 returns: 't`the current API'`,
310310 namedArgumentList: [
311311 SlashCommandNamedArgument.fromProps({
312312 name: 'quiet',
313313 description: 't`Suppress the toast message on connection'`,
314314 typeList: [ARGUMENT_TYPE.BOOLEAN],
315315 defaultValue: 'false',
316316 enumList: commonEnumProviders.boolean('trueFalse')(),
@@ -318,7 +318,7 @@ export function initDefaultSlashCommands() {
318318 ],
319319 unnamedArgumentList: [
320320 SlashCommandArgument.fromProps({
321321 description: 't`API to connect to'`,
322322 typeList: [ARGUMENT_TYPE.STRING],
323323 enumList: Object.entries(CONNECT_API_MAP).sort(([a], [b]) => a.localeCompare(b)).map(([api, { selected }]) =>
324324 new SlashCommandEnumValue(api, selected, enumTypes.getBasedOnIndex(UNIQUE_APIS.findIndex(x => x === selected)),
@@ -327,10 +327,10 @@ export function initDefaultSlashCommands() {
327327 ],
328328 helpString: `
329329 <div>
330330 ${t`Connect to an API. If no argument is provided, it will return the currently connected API.`}
331331 </div>
332332 <div>
333333 <strong>${t`Available APIs:`}</strong>
334334 <pre><code>${Object.keys(CONNECT_API_MAP).sort((a, b) => a.localeCompare(b)).join(', ')}</code></pre>
335335 </div>
336336 `,
@@ -367,7 +367,7 @@ export function initDefaultSlashCommands() {
367367 namedArgumentList: [
368368 new SlashCommandNamedArgument(
369369 'await',
370370 't`Whether to await for the triggered generation before continuing'`,
371371 [ARGUMENT_TYPE.BOOLEAN],
372372 false,
373373 false,
@@ -381,13 +381,13 @@ export function initDefaultSlashCommands() {
381381 ],
382382 helpString: `
383383 <div>
384384 ${t`Calls an impersonation response, with an optional additional prompt.`}
385385 </div>
386386 <div>
387387 ${t`If <code>await=true</code> named argument is passed, the command will wait for the impersonation to end before continuing.`}
388388 </div>
389389 <div>
390390 <strong>${t`Example:`}</strong>
391391 <ul>
392392 <li>
393393 <pre><code class="language-stscript">/impersonate What is the meaning of life?</code></pre>
@@ -426,7 +426,7 @@ export function initDefaultSlashCommands() {
426426 $(currentChatDeleteButton).trigger('click', { fromSlashCommand: true });
427427 }));
428428 },
429429 helpString: 't`Deletes the current chat.'`,
430430 }));
431431 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
432432 name: 'renamechat',
@@ -449,18 +449,18 @@ export function initDefaultSlashCommands() {
449449 },
450450 unnamedArgumentList: [
451451 new SlashCommandArgument(
452452 't`new chat name'`, [ARGUMENT_TYPE.STRING], true,
453453 ),
454454 ],
455455 helpString: 't`Renames the current chat.'`,
456456 }));
457457 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
458458 name: 'getchatname',
459459 callback: async function doGetChatName() {
460460 return getCurrentChatDetails().sessionName;
461461 },
462462 returns: 't`chat file name'`,
463463 helpString: 't`Returns the name of the current chat file into the pipe.'`,
464464 }));
465465 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
466466 name: 'closechat',
@@ -468,7 +468,7 @@ export function initDefaultSlashCommands() {
468468 $('#option_close_chat').trigger('click');
469469 return '';
470470 },
471471 helpString: 't`Closes the current chat.'`,
472472 }));
473473 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
474474 name: 'tempchat',
@@ -476,7 +476,7 @@ export function initDefaultSlashCommands() {
476476 return new Promise((resolve, reject) => {
477477 const eventCallback = async (chatId) => {
478478 if (chatId) {
479479 return reject('t`Not in a temporary chat'`);
480480 }
481481 await newAssistantChat({ temporary: true });
482482 return resolve('');
@@ -484,12 +484,12 @@ export function initDefaultSlashCommands() {
484484 eventSource.once(event_types.CHAT_CHANGED, eventCallback);
485485 $('#option_close_chat').trigger('click');
486486 setTimeout(() => {
487487 reject('t`Failed to open temporary chat'`);
488488 eventSource.removeListener(event_types.CHAT_CHANGED, eventCallback);
489489 }, debounce_timeout.relaxed);
490490 });
491491 },
492492 helpString: 't`Opens a temporary chat with Assistant.'`,
493493 }));
494494 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
495495 name: 'panels',
@@ -498,17 +498,17 @@ export function initDefaultSlashCommands() {
498498 return '';
499499 },
500500 aliases: ['togglepanels'],
501501 helpString: 't`Toggle UI panels on/off'`,
502502 }));
503503 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
504504 name: 'forcesave',
505505 callback: async function () {
506506 await saveSettings();
507507 await saveChatConditional();
508508 toastr.success('t`Chat and settings saved.'`);
509509 return '';
510510 },
511511 helpString: 't`Forces a save of the current chat and settings'`,
512512 }));
513513 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
514514 name: 'instruct',
@@ -531,18 +531,18 @@ export function initDefaultSlashCommands() {
531531 selectInstructPreset(foundName, { quiet: quiet });
532532 return foundName;
533533 },
534534 returns: 't`current template'`,
535535 namedArgumentList: [
536536 SlashCommandNamedArgument.fromProps({
537537 name: 'quiet',
538538 description: 't`Suppress the toast message on template change'`,
539539 typeList: [ARGUMENT_TYPE.BOOLEAN],
540540 defaultValue: 'false',
541541 enumList: commonEnumProviders.boolean('trueFalse')(),
542542 }),
543543 SlashCommandNamedArgument.fromProps({
544544 name: 'forceGet',
545545 description: 't`Force getting a name even if instruct mode is disabled'`,
546546 typeList: [ARGUMENT_TYPE.BOOLEAN],
547547 defaultValue: 'false',
548548 enumList: commonEnumProviders.boolean('trueFalse')(),
@@ -550,18 +550,18 @@ export function initDefaultSlashCommands() {
550550 ],
551551 unnamedArgumentList: [
552552 SlashCommandArgument.fromProps({
553553 description: 't`instruct template name'`,
554554 typeList: [ARGUMENT_TYPE.STRING],
555555 enumProvider: () => instruct_presets.map(preset => new SlashCommandEnumValue(preset.name, null, enumTypes.enum, enumIcons.preset)),
556556 }),
557557 ],
558558 helpString: `
559559 <div>
560560 ${t`Selects instruct mode template by name. Enables instruct mode if not already enabled.`}
561561 ${t`Gets the current instruct template if no name is provided and instruct mode is enabled or <code>forceGet=true</code> is passed.`}
562562 </div>
563563 <div>
564564 <strong>${t`Example:`}</strong>
565565 <ul>
566566 <li>
567567 <pre><code class="language-stscript">/instruct creative</code></pre>
@@ -573,20 +573,20 @@ export function initDefaultSlashCommands() {
573573 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
574574 name: 'instruct-on',
575575 callback: enableInstructCallback,
576576 helpString: 't`Enables instruct mode.'`,
577577 }));
578578 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
579579 name: 'instruct-off',
580580 callback: disableInstructCallback,
581581 helpString: 't`Disables instruct mode'`,
582582 }));
583583 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
584584 name: 'instruct-state',
585585 aliases: ['instruct-toggle'],
586586 helpString: 't`Gets the current instruct mode state. If an argument is provided, it will set the instruct mode state.'`,
587587 unnamedArgumentList: [
588588 SlashCommandArgument.fromProps({
589589 description: 't`instruct mode state'`,
590590 typeList: [ARGUMENT_TYPE.BOOLEAN],
591591 enumList: commonEnumProviders.boolean('trueFalse')(),
592592 }),
@@ -622,11 +622,11 @@ export function initDefaultSlashCommands() {
622622 selectContextPreset(foundName, { quiet: quiet });
623623 return foundName;
624624 },
625625 returns: 't`template name'`,
626626 namedArgumentList: [
627627 SlashCommandNamedArgument.fromProps({
628628 name: 'quiet',
629629 description: 't`Suppress the toast message on template change'`,
630630 typeList: [ARGUMENT_TYPE.BOOLEAN],
631631 defaultValue: 'false',
632632 enumList: commonEnumProviders.boolean('trueFalse')(),
@@ -634,12 +634,12 @@ export function initDefaultSlashCommands() {
634634 ],
635635 unnamedArgumentList: [
636636 SlashCommandArgument.fromProps({
637637 description: 't`context template name'`,
638638 typeList: [ARGUMENT_TYPE.STRING],
639639 enumProvider: () => context_presets.map(preset => new SlashCommandEnumValue(preset.name, null, enumTypes.enum, enumIcons.preset)),
640640 }),
641641 ],
642642 helpString: 't`Selects context template by name. Gets the current template if no name is provided'`,
643643 }));
644644 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
645645 name: 'chat-manager',
@@ -648,32 +648,32 @@ export function initDefaultSlashCommands() {
648648 return '';
649649 },
650650 aliases: ['chat-history', 'manage-chats'],
651651 helpString: 't`Opens the chat manager for the current character/group.'`,
652652 }));
653653 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
654654 name: '?',
655655 callback: helpCommandCallback,
656656 aliases: ['help'],
657657 unnamedArgumentList: [SlashCommandArgument.fromProps({
658658 description: 't`help topic'`,
659659 typeList: [ARGUMENT_TYPE.STRING],
660660 enumList: [
661661 new SlashCommandEnumValue('slash', 't`slash commands (STscript)'`, enumTypes.command, '/'),
662662 new SlashCommandEnumValue('macros', 't`{{macros}} (text replacement)'`, enumTypes.macro, enumIcons.macro),
663663 new SlashCommandEnumValue('format', 't`chat/text formatting'`, enumTypes.name, '★'),
664664 new SlashCommandEnumValue('hotkeys', 't`keyboard shortcuts'`, enumTypes.enum, '⏎'),
665665 ],
666666 })],
667667 helpString: 't`Get help on macros, chat formatting and commands.'`,
668668 }));
669669 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
670670 name: 'bg',
671671 callback: setBackgroundCallback,
672672 aliases: ['background'],
673673 returns: 't`the current background'`,
674674 unnamedArgumentList: [
675675 SlashCommandArgument.fromProps({
676676 description: 't`background filename'`,
677677 typeList: [ARGUMENT_TYPE.STRING],
678678 enumProvider: () => [...document.querySelectorAll('.bg_example')]
679679 .map(it => new SlashCommandEnumValue(it.getAttribute('bgfile')))
@@ -682,13 +682,13 @@ export function initDefaultSlashCommands() {
682682 ],
683683 helpString: `
684684 <div>
685685 ${t`Sets a background according to the provided filename. Partial names allowed.`}
686686 </div>
687687 <div>
688688 ${t`If no background is provided, this will return the currently selected background.`}
689689 </div>
690690 <div>
691691 <strong>${t`Example:`}</strong>
692692 <ul>
693693 <li>
694694 <pre><code>/bg beach.jpg</code></pre>
@@ -704,31 +704,31 @@ export function initDefaultSlashCommands() {
704704 name: 'char-find',
705705 aliases: ['findchar'],
706706 callback: (args, name) => {
707707 if (typeof name !== 'string') throw new Error('t`name must be a string'`);
708708 if (args.preferCurrent instanceof SlashCommandClosure || Array.isArray(args.preferCurrent)) throw new Error('t`preferCurrent cannot be a closure or array'`);
709709 if (args.quiet instanceof SlashCommandClosure || Array.isArray(args.quiet)) throw new Error('t`quiet cannot be a closure or array'`);
710710
711711 const char = findChar({ name: name, filteredByTags: validateArrayArgString(args.tag, 'tag'), preferCurrentChar: !isFalseBoolean(args.preferCurrent), quiet: isTrueBoolean(args.quiet) });
712712 return char?.avatar ?? '';
713713 },
714714 returns: 't`the avatar key (unique identifier) of the character'`,
715715 namedArgumentList: [
716716 SlashCommandNamedArgument.fromProps({
717717 name: 'tag',
718718 description: 't`Supply one or more tags to filter down to the correct character for the provided name, if multiple characters have the same name.'`,
719719 typeList: [ARGUMENT_TYPE.STRING],
720720 enumProvider: commonEnumProviders.tags('assigned'),
721721 acceptsMultiple: true,
722722 }),
723723 SlashCommandNamedArgument.fromProps({
724724 name: 'preferCurrent',
725725 description: 't`Prefer current character or characters in a group, if multiple characters match'`,
726726 typeList: [ARGUMENT_TYPE.BOOLEAN],
727727 defaultValue: 'true',
728728 }),
729729 SlashCommandNamedArgument.fromProps({
730730 name: 'quiet',
731731 description: 't`Do not show warning if multiple charactrers are found'`,
732732 typeList: [ARGUMENT_TYPE.BOOLEAN],
733733 defaultValue: 'false',
734734 enumProvider: commonEnumProviders.boolean('trueFalse'),
@@ -736,31 +736,29 @@ export function initDefaultSlashCommands() {
736736 ],
737737 unnamedArgumentList: [
738738 SlashCommandArgument.fromProps({
739739 description: 't`Character name - or unique character identifier (avatar key)'`,
740740 typeList: [ARGUMENT_TYPE.STRING],
741741 enumProvider: commonEnumProviders.characters('character'),
742742 }),
743743 ],
744744 helpString: `
745745 <div>
746746 ${t`Searches for a character and returns its avatar key.`}
747747 </div>
748748 <div>
749749 ${t`This can be used to choose the correct character for something like <code>/sendas</code> or other commands in need of a character name if you have multiple characters with the same name.`}
750- if you have multiple characters with the same name.
751750 </div>
752751 <div>
753752 <strong>${t`Example:`}</strong>
754753 <ul>
755754 <li>
756755 <pre><code>/char-find name="Chloe"</code></pre>
757756 ${t`Returns the avatar key for "Chloe".`}
758757 </li>
759758 <li>
760759 <pre><code>/search name="Chloe" tag="friend"</code></pre>
761760 ${t`Returns the avatar key for the character "Chloe" that is tagged with "friend".`}
762761 ${t`This is useful if you for example have multiple characters named "Chloe", and the others are "foe", "goddess", or anything else, so you can actually select the character you are looking for.`}
763- so you can actually select the character you are looking for.
764762 </li>
765763 </ul>
766764 </div>
@@ -770,36 +768,36 @@ export function initDefaultSlashCommands() {
770768 name: 'sendas',
771769 rawQuotes: true,
772770 callback: sendMessageAs,
773771 returns: 't`Optionally the text of the sent message, if specified in the "return" argument'`,
774772 namedArgumentList: [
775773 SlashCommandNamedArgument.fromProps({
776774 name: 'name',
777775 description: 't`Character name - or unique character identifier (avatar key)'`,
778776 typeList: [ARGUMENT_TYPE.STRING],
779777 isRequired: true,
780778 enumProvider: commonEnumProviders.characters('character'),
781779 }),
782780 SlashCommandNamedArgument.fromProps({
783781 name: 'avatar',
784782 description: 't`Character avatar override (Can be either avatar key or just the character name to pull the avatar from)'`,
785783 typeList: [ARGUMENT_TYPE.STRING],
786784 enumProvider: commonEnumProviders.characters('character'),
787785 }),
788786 SlashCommandNamedArgument.fromProps({
789787 name: 'compact',
790788 description: 't`Use compact layout'`,
791789 typeList: [ARGUMENT_TYPE.BOOLEAN],
792790 defaultValue: 'false',
793791 }),
794792 SlashCommandNamedArgument.fromProps({
795793 name: 'at',
796794 description: 't`position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values (including -0) are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.'`,
797795 typeList: [ARGUMENT_TYPE.NUMBER],
798796 enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
799797 }),
800798 SlashCommandNamedArgument.fromProps({
801799 name: 'return',
802800 description: 't`The way how you want the return value to be provided'`,
803801 typeList: [ARGUMENT_TYPE.STRING],
804802 defaultValue: 'none',
805803 enumList: slashCommandReturnHelper.enumList({ allowObject: true }),
@@ -807,7 +805,7 @@ export function initDefaultSlashCommands() {
807805 }),
808806 SlashCommandNamedArgument.fromProps({
809807 name: 'raw',
810808 description: 't`If true, does not alter quoted literal unnamed arguments'`,
811809 typeList: [ARGUMENT_TYPE.BOOLEAN],
812810 defaultValue: 'true',
813811 enumProvider: commonEnumProviders.boolean('trueFalse'),
@@ -821,23 +819,23 @@ export function initDefaultSlashCommands() {
821819 ],
822820 helpString: `
823821 <div>
824822 ${t`Sends a message as a specific character. Uses the character avatar if it exists in the characters list.`}
825823 </div>
826824 <div>
827825 <strong>${t`Example:`}</strong>
828826 <ul>
829827 <li>
830828 <pre><code>/sendas name="Chloe" Hello, guys!</code></pre>
831829 ${t`will send "Hello, guys!" from "Chloe".`}
832830 </li>
833831 <li>
834832 <pre><code>/sendas name="Chloe" avatar="BigBadBoss" Hehehe, I am the big bad evil, fear me.</code></pre>
835833 ${t`will send a message as the character "Chloe", but utilizing the avatar from a character named "BigBadBoss".`}
836834 </li>
837835 </ul>
838836 </div>
839837 <div>
840838 ${t`If "compact" is set to true, the message is sent using a compact layout.`}
841839 </div>
842840 `,
843841 }));
@@ -846,11 +844,11 @@ export function initDefaultSlashCommands() {
846844 rawQuotes: true,
847845 callback: sendNarratorMessage,
848846 aliases: ['nar'],
849847 returns: 't`Optionally the text of the sent message, if specified in the "return" argument'`,
850848 namedArgumentList: [
851849 new SlashCommandNamedArgument(
852850 'compact',
853851 't`compact layout'`,
854852 [ARGUMENT_TYPE.BOOLEAN],
855853 false,
856854 false,
@@ -858,18 +856,18 @@ export function initDefaultSlashCommands() {
858856 ),
859857 SlashCommandNamedArgument.fromProps({
860858 name: 'at',
861859 description: 't`position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values (including -0) are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.'`,
862860 typeList: [ARGUMENT_TYPE.NUMBER],
863861 enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
864862 }),
865863 SlashCommandNamedArgument.fromProps({
866864 name: 'name',
867865 description: 't`Optional custom display name to use for this system narrator message.'`,
868866 typeList: [ARGUMENT_TYPE.STRING],
869867 }),
870868 SlashCommandNamedArgument.fromProps({
871869 name: 'return',
872870 description: 't`The way how you want the return value to be provided'`,
873871 typeList: [ARGUMENT_TYPE.STRING],
874872 defaultValue: 'none',
875873 enumList: slashCommandReturnHelper.enumList({ allowObject: true }),
@@ -877,7 +875,7 @@ export function initDefaultSlashCommands() {
877875 }),
878876 SlashCommandNamedArgument.fromProps({
879877 name: 'raw',
880878 description: 't`If true, does not alter quoted literal unnamed arguments'`,
881879 typeList: [ARGUMENT_TYPE.BOOLEAN],
882880 defaultValue: 'true',
883881 enumProvider: commonEnumProviders.boolean('trueFalse'),
@@ -891,13 +889,13 @@ export function initDefaultSlashCommands() {
891889 ],
892890 helpString: `
893891 <div>
894892 ${t`Sends a message as a system narrator.`}
895893 </div>
896894 <div>
897895 ${t`If <code>compact</code> is set to <code>true</code>, the message is sent using a compact layout.`}
898896 </div>
899897 <div>
900898 <strong>${t`Example:`}</strong>
901899 <ul>
902900 <li>
903901 <pre><code>/sys The sun sets in the west.</code></pre>
@@ -914,20 +912,20 @@ export function initDefaultSlashCommands() {
914912 callback: setNarratorName,
915913 unnamedArgumentList: [
916914 new SlashCommandArgument(
917915 't`name'`, [ARGUMENT_TYPE.STRING], false,
918916 ),
919917 ],
920918 helpString: 't`Sets a name for future system narrator messages in this chat (display only). Default: System. Leave empty to reset.'`,
921919 }));
922920 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
923921 name: 'comment',
924922 rawQuotes: true,
925923 callback: sendCommentMessage,
926924 returns: 't`Optionally the text of the sent message, if specified in the "return" argument'`,
927925 namedArgumentList: [
928926 new SlashCommandNamedArgument(
929927 'compact',
930928 't`Whether to use a compact layout'`,
931929 [ARGUMENT_TYPE.BOOLEAN],
932930 false,
933931 false,
@@ -935,13 +933,13 @@ export function initDefaultSlashCommands() {
935933 ),
936934 SlashCommandNamedArgument.fromProps({
937935 name: 'at',
938936 description: 't`position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values (including -0) are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.'`,
939937 typeList: [ARGUMENT_TYPE.NUMBER],
940938 enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
941939 }),
942940 SlashCommandNamedArgument.fromProps({
943941 name: 'return',
944942 description: 't`The way how you want the return value to be provided'`,
945943 typeList: [ARGUMENT_TYPE.STRING],
946944 defaultValue: 'none',
947945 enumList: slashCommandReturnHelper.enumList({ allowObject: true }),
@@ -949,7 +947,7 @@ export function initDefaultSlashCommands() {
949947 }),
950948 SlashCommandNamedArgument.fromProps({
951949 name: 'raw',
952950 description: 't`If true, does not alter quoted literal unnamed arguments'`,
953951 typeList: [ARGUMENT_TYPE.BOOLEAN],
954952 defaultValue: 'true',
955953 enumProvider: commonEnumProviders.boolean('trueFalse'),
@@ -965,13 +963,13 @@ export function initDefaultSlashCommands() {
965963 ],
966964 helpString: `
967965 <div>
968966 ${t`Adds a note/comment message not part of the chat.`}
969967 </div>
970968 <div>
971969 ${t`If <code>compact</code> is set to <code>true</code>, the message is sent using a compact layout.`}
972970 </div>
973971 <div>
974972 <strong>${t`Example:`}</strong>
975973 <ul>
976974 <li>
977975 <pre><code>/comment This is a comment</code></pre>
@@ -987,19 +985,19 @@ export function initDefaultSlashCommands() {
987985 name: 'single',
988986 callback: setStoryModeCallback,
989987 aliases: ['story'],
990988 helpString: 't`Sets the message style to single document mode without names or avatars visible.'`,
991989 }));
992990 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
993991 name: 'bubble',
994992 callback: setBubbleModeCallback,
995993 aliases: ['bubbles'],
996994 helpString: 't`Sets the message style to bubble chat mode.'`,
997995 }));
998996 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
999997 name: 'flat',
1000998 callback: setFlatModeCallback,
1001999 aliases: ['default'],
10021000 helpString: 't`Sets the message style to flat chat mode.'`,
10031001 }));
10041002 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
10051003 name: 'continue',
@@ -1008,7 +1006,7 @@ export function initDefaultSlashCommands() {
10081006 namedArgumentList: [
10091007 new SlashCommandNamedArgument(
10101008 'await',
10111009 't`Whether to await for the continued generation before proceeding'`,
10121010 [ARGUMENT_TYPE.BOOLEAN],
10131011 false,
10141012 false,
@@ -1022,21 +1020,21 @@ export function initDefaultSlashCommands() {
10221020 ],
10231021 helpString: `
10241022 <div>
10251023 ${t`Continues the last message in the chat, with an optional additional prompt.`}
10261024 </div>
10271025 <div>
10281026 ${t`If <code>await=true</code> named argument is passed, the command will await for the continued generation before proceeding.`}
10291027 </div>
10301028 <div>
10311029 <strong>${t`Example:`}</strong>
10321030 <ul>
10331031 <li>
10341032 <pre><code>/continue</code></pre>
10351033 ${t`Continues the chat with no additional prompt and immediately proceeds to the next command.`}
10361034 </li>
10371035 <li>
10381036 <pre><code>/continue await=true Let's explore this further...</code></pre>
10391037 ${t`Continues the chat with the provided prompt and waits for the generation to finish.`}
10401038 </li>
10411039 </ul>
10421040 </div>
@@ -1045,16 +1043,16 @@ export function initDefaultSlashCommands() {
10451043 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
10461044 name: 'go',
10471045 callback: goToCharacterCallback,
10481046 returns: 't`The character/group name'`,
10491047 unnamedArgumentList: [
10501048 SlashCommandArgument.fromProps({
10511049 description: 't`Character name - or unique character identifier (avatar key)'`,
10521050 typeList: [ARGUMENT_TYPE.STRING],
10531051 isRequired: true,
10541052 enumProvider: commonEnumProviders.characters('all'),
10551053 }),
10561054 ],
10571055 helpString: 't`Opens up a chat with the character or group by its name'`,
10581056 aliases: ['char'],
10591057 }));
10601058 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
@@ -1064,21 +1062,21 @@ export function initDefaultSlashCommands() {
10641062 const renamed = await renameCharacter(name, { silent: isTrueBoolean(silent), renameChats: chats !== null ? isTrueBoolean(chats) : null });
10651063 return String(renamed);
10661064 },
10671065 returns: 't`true/false - Whether the rename was successful'`,
10681066 namedArgumentList: [
10691067 new SlashCommandNamedArgument(
10701068 'silent', 't`Hide any blocking popups. (if false, the name is optional. If not supplied, a popup asking for it will appear)'`, [ARGUMENT_TYPE.BOOLEAN], false, false, 'true',
10711069 ),
10721070 new SlashCommandNamedArgument(
10731071 'chats', 't`Rename char in all previous chats'`, [ARGUMENT_TYPE.BOOLEAN], false, false, '<null>',
10741072 ),
10751073 ],
10761074 unnamedArgumentList: [
10771075 new SlashCommandArgument(
10781076 't`new char name'`, [ARGUMENT_TYPE.STRING], true,
10791077 ),
10801078 ],
10811079 helpString: 't`Renames the current character.'`,
10821080 }));
10831081 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
10841082 name: 'sysgen',
@@ -1086,7 +1084,7 @@ export function initDefaultSlashCommands() {
10861084 namedArgumentList: [
10871085 SlashCommandNamedArgument.fromProps({
10881086 name: 'trim',
10891087 description: 't`Trim the output by the last sentence boundary'`,
10901088 typeList: [ARGUMENT_TYPE.BOOLEAN],
10911089 defaultValue: 'false',
10921090 isRequired: false,
@@ -1094,7 +1092,7 @@ export function initDefaultSlashCommands() {
10941092 }),
10951093 SlashCommandNamedArgument.fromProps({
10961094 name: 'compact',
10971095 description: 't`Use a compact layout for the message'`,
10981096 typeList: [ARGUMENT_TYPE.BOOLEAN],
10991097 defaultValue: 'false',
11001098 isRequired: false,
@@ -1103,18 +1101,18 @@ export function initDefaultSlashCommands() {
11031101 }),
11041102 SlashCommandNamedArgument.fromProps({
11051103 name: 'at',
11061104 description: 't`Position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values (including -0) are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.'`,
11071105 typeList: [ARGUMENT_TYPE.NUMBER],
11081106 enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
11091107 }),
11101108 SlashCommandNamedArgument.fromProps({
11111109 name: 'name',
11121110 description: 't`Optional custom display name to use for this system narrator message.'`,
11131111 typeList: [ARGUMENT_TYPE.STRING],
11141112 }),
11151113 SlashCommandNamedArgument.fromProps({
11161114 name: 'return',
11171115 description: 't`The way how you want the return value to be provided'`,
11181116 typeList: [ARGUMENT_TYPE.STRING],
11191117 defaultValue: 'none',
11201118 enumList: slashCommandReturnHelper.enumList({ allowObject: true }),
@@ -1126,23 +1124,23 @@ export function initDefaultSlashCommands() {
11261124 'prompt', [ARGUMENT_TYPE.STRING], true,
11271125 ),
11281126 ],
11291127 helpString: 't`Generates a system message using a specified prompt.'`,
11301128 }));
11311129 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
11321130 name: 'ask',
11331131 callback: askCharacter,
11341132 returns: 't`Optionally the text of the sent message, if specified in the "return" argument'`,
11351133 namedArgumentList: [
11361134 SlashCommandNamedArgument.fromProps({
11371135 name: 'name',
11381136 description: 't`Character name - or unique character identifier (avatar key)'`,
11391137 typeList: [ARGUMENT_TYPE.STRING],
11401138 isRequired: true,
11411139 enumProvider: commonEnumProviders.characters('character'),
11421140 }),
11431141 SlashCommandNamedArgument.fromProps({
11441142 name: 'return',
11451143 description: 't`The way how you want the return value to be provided'`,
11461144 typeList: [ARGUMENT_TYPE.STRING],
11471145 defaultValue: 'pipe',
11481146 enumList: slashCommandReturnHelper.enumList({ allowObject: true }),
@@ -1154,7 +1152,7 @@ export function initDefaultSlashCommands() {
11541152 'prompt', [ARGUMENT_TYPE.STRING], false, false,
11551153 ),
11561154 ],
11571155 helpString: 't`Asks a specified character card a prompt. Character name must be provided in a named argument.'`,
11581156 }));
11591157 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
11601158 name: 'delname',
@@ -1162,7 +1160,7 @@ export function initDefaultSlashCommands() {
11621160 namedArgumentList: [],
11631161 unnamedArgumentList: [
11641162 SlashCommandArgument.fromProps({
11651163 description: 't`Character name - or unique character identifier (avatar key)'`,
11661164 typeList: [ARGUMENT_TYPE.STRING],
11671165 isRequired: true,
11681166 enumProvider: commonEnumProviders.characters('character'),
@@ -1171,10 +1169,10 @@ export function initDefaultSlashCommands() {
11711169 aliases: ['cancel'],
11721170 helpString: `
11731171 <div>
11741172 ${t`Deletes all messages attributed to a specified name.`}
11751173 </div>
11761174 <div>
11771175 <strong>${t`Example:`}</strong>
11781176 <ul>
11791177 <li>
11801178 <pre><code>/delname John</code></pre>
@@ -1187,11 +1185,11 @@ export function initDefaultSlashCommands() {
11871185 name: 'send',
11881186 rawQuotes: true,
11891187 callback: sendUserMessageCallback,
11901188 returns: 't`Optionally the text of the sent message, if specified in the "return" argument'`,
11911189 namedArgumentList: [
11921190 new SlashCommandNamedArgument(
11931191 'compact',
11941192 't`whether to use a compact layout'`,
11951193 [ARGUMENT_TYPE.BOOLEAN],
11961194 false,
11971195 false,
@@ -1199,20 +1197,20 @@ export function initDefaultSlashCommands() {
11991197 ),
12001198 SlashCommandNamedArgument.fromProps({
12011199 name: 'at',
12021200 description: 't`position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values (including -0) are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.'`,
12031201 typeList: [ARGUMENT_TYPE.NUMBER],
12041202 enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
12051203 }),
12061204 SlashCommandNamedArgument.fromProps({
12071205 name: 'name',
12081206 description: 't`display name'`,
12091207 typeList: [ARGUMENT_TYPE.STRING],
12101208 defaultValue: '{{user}}',
12111209 enumProvider: commonEnumProviders.personas,
12121210 }),
12131211 SlashCommandNamedArgument.fromProps({
12141212 name: 'return',
12151213 description: 't`The way how you want the return value to be provided'`,
12161214 typeList: [ARGUMENT_TYPE.STRING],
12171215 defaultValue: 'none',
12181216 enumList: slashCommandReturnHelper.enumList({ allowObject: true }),
@@ -1220,7 +1218,7 @@ export function initDefaultSlashCommands() {
12201218 }),
12211219 SlashCommandNamedArgument.fromProps({
12221220 name: 'raw',
12231221 description: 't`If true, does not alter quoted literal unnamed arguments'`,
12241222 typeList: [ARGUMENT_TYPE.BOOLEAN],
12251223 defaultValue: 'true',
12261224 enumProvider: commonEnumProviders.boolean('trueFalse'),
@@ -1236,16 +1234,16 @@ export function initDefaultSlashCommands() {
12361234 ],
12371235 helpString: `
12381236 <div>
12391237 ${t`Adds a user message to the chat log without triggering a generation.`}
12401238 </div>
12411239 <div>
12421240 ${t`If <code>compact</code> is set to <code>true</code>, the message is sent using a compact layout.`}
12431241 </div>
12441242 <div>
12451243 ${t`If <code>name</code> is set, it will be displayed as the message sender. Can be an empty for no name.`}
12461244 </div>
12471245 <div>
12481246 <strong>${t`Example:`}</strong>
12491247 <ul>
12501248 <li>
12511249 <pre><code>/send Hello there!</code></pre>
@@ -1263,7 +1261,7 @@ export function initDefaultSlashCommands() {
12631261 namedArgumentList: [
12641262 new SlashCommandNamedArgument(
12651263 'await',
12661264 't`Whether to await for the triggered generation before continuing'`,
12671265 [ARGUMENT_TYPE.BOOLEAN],
12681266 false,
12691267 false,
@@ -1272,7 +1270,7 @@ export function initDefaultSlashCommands() {
12721270 ],
12731271 unnamedArgumentList: [
12741272 SlashCommandArgument.fromProps({
12751273 description: 't`group member index (starts with 0) or name'`,
12761274 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
12771275 isRequired: false,
12781276 enumProvider: commonEnumProviders.groupMembers(),
@@ -1280,10 +1278,10 @@ export function initDefaultSlashCommands() {
12801278 ],
12811279 helpString: `
12821280 <div>
12831281 ${t`Triggers a message generation. If in group, can trigger a message for the specified group member index or name.`}
12841282 </div>
12851283 <div>
12861284 ${t`If <code>await=true</code> named argument is passed, the command will await for the triggered generation before continuing.`}
12871285 </div>
12881286 `,
12891287 }));
@@ -1293,7 +1291,7 @@ export function initDefaultSlashCommands() {
12931291 namedArgumentList: [
12941292 SlashCommandNamedArgument.fromProps({
12951293 name: 'name',
12961294 description: 't`only hide messages from a certain character or persona'`,
12971295 typeList: [ARGUMENT_TYPE.STRING],
12981296 enumProvider: commonEnumProviders.messageNames,
12991297 isRequired: false,
@@ -1302,13 +1300,13 @@ export function initDefaultSlashCommands() {
13021300 ],
13031301 unnamedArgumentList: [
13041302 SlashCommandArgument.fromProps({
13051303 description: 't`message index (starts with 0) or range, defaults to the last message index if not provided'`,
13061304 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE],
13071305 isRequired: false,
13081306 enumProvider: commonEnumProviders.messages(),
13091307 }),
13101308 ],
13111309 helpString: 't`Hides a chat message from the prompt.'`,
13121310 }));
13131311 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
13141312 name: 'unhide',
@@ -1316,7 +1314,7 @@ export function initDefaultSlashCommands() {
13161314 namedArgumentList: [
13171315 SlashCommandNamedArgument.fromProps({
13181316 name: 'name',
13191317 description: 't`only unhide messages from a certain character or persona'`,
13201318 typeList: [ARGUMENT_TYPE.STRING],
13211319 enumProvider: commonEnumProviders.messageNames,
13221320 isRequired: false,
@@ -1325,36 +1323,36 @@ export function initDefaultSlashCommands() {
13251323 ],
13261324 unnamedArgumentList: [
13271325 SlashCommandArgument.fromProps({
13281326 description: 't`message index (starts with 0) or range, defaults to the last message index if not provided'`,
13291327 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE],
13301328 isRequired: false,
13311329 enumProvider: commonEnumProviders.messages(),
13321330 }),
13331331 ],
13341332 helpString: 't`Unhides a message from the prompt.'`,
13351333 }));
13361334 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
13371335 name: 'member-get',
13381336 aliases: ['getmember', 'memberget'],
13391337 callback: (async ({ field = 'name' }, arg) => {
13401338 if (!selected_group) {
13411339 toastr.warning('t`Cannot run /member-get command outside of a group chat.'`);
13421340 return '';
13431341 }
13441342 if (field === '') {
13451343 toastr.warning('\t`'/member-get field=\' argument required!'`);
13461344 return '';
13471345 }
13481346 field = field.toString();
13491347 arg = arg.toString();
13501348 if (!['name', 'index', 'id', 'avatar'].includes(field)) {
13511349 toastr.warning('\t`'/member-get field=\' argument required!'`);
13521350 return '';
13531351 }
13541352 const isId = !isNaN(parseInt(arg));
13551353 const groupMember = findGroupMemberId(arg, true);
13561354 if (!groupMember) {
13571355 toastr.warning(t`No group member found using ${isId ? 'id' : 'string'} ${arg}`);
13581356 return '';
13591357 }
13601358 return groupMember[field];
@@ -1362,27 +1360,27 @@ export function initDefaultSlashCommands() {
13621360 namedArgumentList: [
13631361 SlashCommandNamedArgument.fromProps({
13641362 name: 'field',
13651363 description: 't`Whether to retrieve the name, index, id, or avatar.'`,
13661364 typeList: [ARGUMENT_TYPE.STRING],
13671365 isRequired: true,
13681366 defaultValue: 'name',
13691367 enumList: [
13701368 new SlashCommandEnumValue('name', 't`Character name'`),
13711369 new SlashCommandEnumValue('index', 't`Group member index'`),
13721370 new SlashCommandEnumValue('avatar', 't`Character avatar'`),
13731371 new SlashCommandEnumValue('id', 't`Character index'`),
13741372 ],
13751373 }),
13761374 ],
13771375 unnamedArgumentList: [
13781376 SlashCommandArgument.fromProps({
13791377 description: 't`member index (starts with 0), name, or avatar'`,
13801378 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
13811379 isRequired: true,
13821380 enumProvider: commonEnumProviders.groupMembers(),
13831381 }),
13841382 ],
13851383 helpString: 't`Retrieves a group member\'s name, index, id, or avatar.'`,
13861384 }));
13871385 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
13881386 name: 'member-disable',
@@ -1390,13 +1388,13 @@ export function initDefaultSlashCommands() {
13901388 aliases: ['disable', 'disablemember', 'memberdisable'],
13911389 unnamedArgumentList: [
13921390 SlashCommandArgument.fromProps({
13931391 description: 't`member index (starts with 0) or name'`,
13941392 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
13951393 isRequired: true,
13961394 enumProvider: commonEnumProviders.groupMembers(),
13971395 }),
13981396 ],
13991397 helpString: 't`Disables a group member from being drafted for replies.'`,
14001398 }));
14011399 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
14021400 name: 'member-enable',
@@ -1404,13 +1402,13 @@ export function initDefaultSlashCommands() {
14041402 callback: enableGroupMemberCallback,
14051403 unnamedArgumentList: [
14061404 SlashCommandArgument.fromProps({
14071405 description: 't`member index (starts with 0) or name'`,
14081406 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
14091407 isRequired: true,
14101408 enumProvider: commonEnumProviders.groupMembers(),
14111409 }),
14121410 ],
14131411 helpString: 't`Enables a group member to be drafted for replies.'`,
14141412 }));
14151413 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
14161414 name: 'member-add',
@@ -1418,7 +1416,7 @@ export function initDefaultSlashCommands() {
14181416 aliases: ['addmember', 'memberadd'],
14191417 unnamedArgumentList: [
14201418 SlashCommandArgument.fromProps({
14211419 description: 't`Character name - or unique character identifier (avatar key)'`,
14221420 typeList: [ARGUMENT_TYPE.STRING],
14231421 isRequired: true,
14241422 enumProvider: () => selected_group ? commonEnumProviders.characters('character')() : [],
@@ -1426,10 +1424,10 @@ export function initDefaultSlashCommands() {
14261424 ],
14271425 helpString: `
14281426 <div>
14291427 ${t`Adds a new group member to the group chat.`}
14301428 </div>
14311429 <div>
14321430 <strong>${t`Example:`}</strong>
14331431 <ul>
14341432 <li>
14351433 <pre><code>/member-add John Doe</code></pre>
@@ -1444,7 +1442,7 @@ export function initDefaultSlashCommands() {
14441442 aliases: ['removemember', 'memberremove'],
14451443 unnamedArgumentList: [
14461444 SlashCommandArgument.fromProps({
14471445 description: 't`member index (starts with 0) or name'`,
14481446 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
14491447 isRequired: true,
14501448 enumProvider: commonEnumProviders.groupMembers(),
@@ -1452,10 +1450,10 @@ export function initDefaultSlashCommands() {
14521450 ],
14531451 helpString: `
14541452 <div>
14551453 ${t`Removes a group member from the group chat.`}
14561454 </div>
14571455 <div>
14581456 <strong>${t`Example:`}</strong>
14591457 <ul>
14601458 <li>
14611459 <pre><code>/member-remove 2</code></pre>
@@ -1471,13 +1469,13 @@ export function initDefaultSlashCommands() {
14711469 aliases: ['upmember', 'memberup'],
14721470 unnamedArgumentList: [
14731471 SlashCommandArgument.fromProps({
14741472 description: 't`member index (starts with 0) or name'`,
14751473 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
14761474 isRequired: true,
14771475 enumProvider: commonEnumProviders.groupMembers(),
14781476 }),
14791477 ],
14801478 helpString: 't`Moves a group member up in the group chat list.'`,
14811479 }));
14821480 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
14831481 name: 'member-down',
@@ -1485,13 +1483,13 @@ export function initDefaultSlashCommands() {
14851483 aliases: ['downmember', 'memberdown'],
14861484 unnamedArgumentList: [
14871485 SlashCommandArgument.fromProps({
14881486 description: 't`member index (starts with 0) or name'`,
14891487 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
14901488 isRequired: true,
14911489 enumProvider: commonEnumProviders.groupMembers(),
14921490 }),
14931491 ],
14941492 helpString: 't`Moves a group member down in the group chat list.'`,
14951493 }));
14961494 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
14971495 name: 'member-peek',
@@ -1499,7 +1497,7 @@ export function initDefaultSlashCommands() {
14991497 callback: peekCallback,
15001498 unnamedArgumentList: [
15011499 SlashCommandArgument.fromProps({
15021500 description: 't`member index (starts with 0) or name'`,
15031501 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
15041502 isRequired: true,
15051503 enumProvider: commonEnumProviders.groupMembers(),
@@ -1507,14 +1505,14 @@ export function initDefaultSlashCommands() {
15071505 ],
15081506 helpString: `
15091507 <div>
15101508 ${t`Shows a group member character card without switching chats.`}
15111509 </div>
15121510 <div>
15131511 <strong>${t`Examples:`}</strong>
15141512 <ul>
15151513 <li>
15161514 <pre><code>/peek Gloria</code></pre>
15171515 ${t`Shows the character card for the character named "Gloria".`}
15181516 </li>
15191517 </ul>
15201518 </div>
@@ -1524,16 +1522,16 @@ export function initDefaultSlashCommands() {
15241522 name: 'member-count',
15251523 callback: countGroupMemberCallback,
15261524 aliases: ['countmember', 'membercount'],
15271525 helpString: 't`Returns the total number of group members in the group chat list.'`,
15281526 }));
15291527 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
15301528 name: 'delswipe',
15311529 callback: deleteSwipeCallback,
15321530 returns: 't`the new, currently selected swipe id'`,
15331531 aliases: ['swipedel'],
15341532 unnamedArgumentList: [
15351533 SlashCommandArgument.fromProps({
15361534 description: 't`1-based swipe id'`,
15371535 typeList: [ARGUMENT_TYPE.NUMBER],
15381536 isRequired: true,
15391537 enumProvider: () => Array.isArray(chat[chat.length - 1]?.swipes) ?
@@ -1543,18 +1541,18 @@ export function initDefaultSlashCommands() {
15431541 ],
15441542 helpString: `
15451543 <div>
15461544 ${t`Deletes a swipe from the last chat message. If swipe id is not provided, it deletes the current swipe.`}
15471545 </div>
15481546 <div>
15491547 <strong>${t`Example:`}</strong>
15501548 <ul>
15511549 <li>
15521550 <pre><code>/delswipe</code></pre>
15531551 ${t`Deletes the current swipe.`}
15541552 </li>
15551553 <li>
15561554 <pre><code>/delswipe 2</code></pre>
15571555 ${t`Deletes the second swipe from the last chat message.`}
15581556 </li>
15591557 </ul>
15601558 </div>
@@ -1564,14 +1562,14 @@ export function initDefaultSlashCommands() {
15641562 name: 'echo',
15651563 rawQuotes: true,
15661564 callback: echoCallback,
15671565 returns: 't`the text'`,
15681566 namedArgumentList: [
15691567 new SlashCommandNamedArgument(
15701568 'title', 't`title of the toast message'`, [ARGUMENT_TYPE.STRING], false,
15711569 ),
15721570 SlashCommandNamedArgument.fromProps({
15731571 name: 'severity',
15741572 description: 't`severity level of the toast message'`,
15751573 typeList: [ARGUMENT_TYPE.STRING],
15761574 defaultValue: 'info',
15771575 enumProvider: () => [
@@ -1583,54 +1581,54 @@ export function initDefaultSlashCommands() {
15831581 }),
15841582 SlashCommandNamedArgument.fromProps({
15851583 name: 'timeout',
15861584 description: 't`time in milliseconds to display the toast message. Set this and \'extendedTimeout\' to 0 to show indefinitely until dismissed.'`,
15871585 typeList: [ARGUMENT_TYPE.NUMBER],
15881586 defaultValue: `${toastr.options.timeOut}`,
15891587 }),
15901588 SlashCommandNamedArgument.fromProps({
15911589 name: 'extendedTimeout',
15921590 description: 't`time in milliseconds to display the toast message. Set this and \'timeout\' to 0 to show indefinitely until dismissed.'`,
15931591 typeList: [ARGUMENT_TYPE.NUMBER],
15941592 defaultValue: `${toastr.options.extendedTimeOut}`,
15951593 }),
15961594 SlashCommandNamedArgument.fromProps({
15971595 name: 'preventDuplicates',
15981596 description: 't`prevent duplicate toasts with the same message from being displayed.'`,
15991597 typeList: [ARGUMENT_TYPE.BOOLEAN],
16001598 defaultValue: 'false',
16011599 enumList: commonEnumProviders.boolean('trueFalse')(),
16021600 }),
16031601 SlashCommandNamedArgument.fromProps({
16041602 name: 'awaitDismissal',
16051603 description: 't`wait for the toast to be dismissed before continuing.'`,
16061604 typeList: [ARGUMENT_TYPE.BOOLEAN],
16071605 defaultValue: 'false',
16081606 enumList: commonEnumProviders.boolean('trueFalse')(),
16091607 }),
16101608 SlashCommandNamedArgument.fromProps({
16111609 name: 'cssClass',
16121610 description: 't`additional CSS class to add to the toast message (e.g. for custom styling)'`,
16131611 typeList: [ARGUMENT_TYPE.STRING],
16141612 }),
16151613 SlashCommandNamedArgument.fromProps({
16161614 name: 'color',
16171615 description: 't`custom CSS color of the toast message. Accepts all valid CSS color values (e.g. \'red\', \'#FF0000\', \'rgb(255, 0, 0)\').<br />>Can be more customizable with the \'cssClass\' argument and custom classes.'`,
16181616 }),
16191617 SlashCommandNamedArgument.fromProps({
16201618 name: 'escapeHtml',
16211619 description: 't`whether to escape HTML in the toast message.'`,
16221620 typeList: [ARGUMENT_TYPE.BOOLEAN],
16231621 defaultValue: 'true',
16241622 enumList: commonEnumProviders.boolean('trueFalse')(),
16251623 }),
16261624 SlashCommandNamedArgument.fromProps({
16271625 name: 'onClick',
16281626 description: 't`a closure to call when the toast is clicked. This executed closure receives scope as provided in the script. Careful about possible side effects when manipulating variables and more.'`,
16291627 typeList: [ARGUMENT_TYPE.CLOSURE],
16301628 }),
16311629 SlashCommandNamedArgument.fromProps({
16321630 name: 'raw',
16331631 description: 't`If true, does not alter quoted literal unnamed arguments'`,
16341632 typeList: [ARGUMENT_TYPE.BOOLEAN],
16351633 defaultValue: 'true',
16361634 enumProvider: commonEnumProviders.boolean('trueFalse'),
@@ -1665,32 +1663,32 @@ export function initDefaultSlashCommands() {
16651663 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
16661664 name: 'gen',
16671665 callback: generateCallback,
16681666 returns: 't`generated text'`,
16691667 namedArgumentList: [
16701668 SlashCommandNamedArgument.fromProps({
16711669 name: 'trim',
16721670 description: 't`Trim the output by the last sentence boundary'`,
16731671 typeList: [ARGUMENT_TYPE.BOOLEAN],
16741672 defaultValue: 'false',
16751673 isRequired: false,
16761674 enumProvider: commonEnumProviders.boolean('trueFalse'),
16771675 }),
16781676 new SlashCommandNamedArgument(
16791677 'lock', 't`lock user input during generation'`, [ARGUMENT_TYPE.BOOLEAN], false, false, null, commonEnumProviders.boolean('onOff')(),
16801678 ),
16811679 SlashCommandNamedArgument.fromProps({
16821680 name: 'name',
16831681 description: 't`in-prompt character name for instruct mode (or unique character identifier (avatar key), which will be used as name)'`,
16841682 typeList: [ARGUMENT_TYPE.STRING],
16851683 defaultValue: 'System',
16861684 enumProvider: () => [...commonEnumProviders.characters('character')(), new SlashCommandEnumValue('System', null, enumTypes.enum, enumIcons.assistant)],
16871685 }),
16881686 new SlashCommandNamedArgument(
16891687 'length', 't`API response length in tokens'`, [ARGUMENT_TYPE.NUMBER], false,
16901688 ),
16911689 SlashCommandNamedArgument.fromProps({
16921690 name: 'as',
16931691 description: 't`role of the output prompt'`,
16941692 typeList: [ARGUMENT_TYPE.STRING],
16951693 enumList: [
16961694 new SlashCommandEnumValue('system', null, enumTypes.enum, enumIcons.assistant),
@@ -1705,30 +1703,30 @@ export function initDefaultSlashCommands() {
17051703 ],
17061704 helpString: `
17071705 <div>
17081706 ${t`Generates text using the provided prompt and passes it to the next command through the pipe, optionally locking user input while generating and allowing to configure the in-prompt name for instruct mode (default = "System").`}
17091707 </div>
17101708 <div>
17111709 ${t`"as" argument controls the role of the output prompt: system (default) or char. If "length" argument is provided as a number in tokens, allows to temporarily override an API response length.`}
17121710 </div>
17131711 `,
17141712 }));
17151713 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
17161714 name: 'genraw',
17171715 callback: generateRawCallback,
17181716 returns: 't`generated text'`,
17191717 namedArgumentList: [
17201718 new SlashCommandNamedArgument(
17211719 'lock', 't`lock user input during generation'`, [ARGUMENT_TYPE.BOOLEAN], false, false, 'off', commonEnumProviders.boolean('onOff')(),
17221720 ),
17231721 new SlashCommandNamedArgument(
17241722 'instruct', 't`use instruct mode'`, [ARGUMENT_TYPE.BOOLEAN], false, false, 'on', commonEnumProviders.boolean('onOff')(),
17251723 ),
17261724 new SlashCommandNamedArgument(
17271725 'stop', 't`one-time custom stop strings'`, [ARGUMENT_TYPE.LIST], false, false, '[]',
17281726 ),
17291727 SlashCommandNamedArgument.fromProps({
17301728 name: 'as',
17311729 description: 't`role of the output prompt'`,
17321730 defaultValue: 'system',
17331731 typeList: [ARGUMENT_TYPE.STRING],
17341732 enumList: [
@@ -1737,16 +1735,16 @@ export function initDefaultSlashCommands() {
17371735 ],
17381736 }),
17391737 new SlashCommandNamedArgument(
17401738 'system', 't`system prompt at the start'`, [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME], false,
17411739 ),
17421740 new SlashCommandNamedArgument(
17431741 'prefill', 't`prefill prompt at the end'`, [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME], false,
17441742 ),
17451743 new SlashCommandNamedArgument(
17461744 'length', 't`API response length in tokens'`, [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME], false,
17471745 ),
17481746 new SlashCommandNamedArgument(
17491747 'trim', 't`trim {{user}} and {{char}} prefixes from the output'`, [ARGUMENT_TYPE.BOOLEAN], false, false, 'on', commonEnumProviders.boolean('onOff')(),
17501748 ),
17511749 ],
17521750 unnamedArgumentList: [
@@ -1756,31 +1754,31 @@ export function initDefaultSlashCommands() {
17561754 ],
17571755 helpString: `
17581756 <div>
17591757 ${t`Generates text using the provided prompt and passes it to the next command through the pipe, optionally locking user input while generating. Does not include chat history or character card.`}
17601758 </div>
17611759 <div>
17621760 ${t`Use instruct=off to skip instruct formatting, e.g. <pre><code>/genraw instruct=off Why is the sky blue?</code></pre>`}
17631761 </div>
17641762 <div>
17651763 ${t`Use stop=... with a JSON-serialized array to add one-time custom stop strings, e.g. <pre><code>/genraw stop=["\\n"] Say hi</code></pre>`}
17661764 </div>
17671765 <div>
17681766 ${t`"as" argument controls the role of the output prompt: system (default) or char. "system" argument adds an (optional) system prompt at the start.`}
17691767 </div>
17701768 <div>
17711769 ${t`If "length" argument is provided as a number in tokens, allows to temporarily override an API response length.`}
17721770 </div>
17731771 `,
17741772 }));
17751773 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
17761774 name: 'addswipe',
17771775 callback: addSwipeCallback,
17781776 returns: 't`the new swipe id'`,
17791777 aliases: ['swipeadd'],
17801778 namedArgumentList: [
17811779 SlashCommandNamedArgument.fromProps({
17821780 name: 'switch',
17831781 description: 't`switch to the new swipe'`,
17841782 typeList: [ARGUMENT_TYPE.BOOLEAN],
17851783 enumList: commonEnumProviders.boolean()(),
17861784 }),
@@ -1792,10 +1790,10 @@ export function initDefaultSlashCommands() {
17921790 ],
17931791 helpString: `
17941792 <div>
17951793 ${t`Adds a swipe to the last chat message.`}
17961794 </div>
17971795 <div>
17981796 ${t`Use switch=true to switch to directly switch to the new swipe.`}
17991797 </div>`,
18001798 }));
18011799 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
@@ -1804,14 +1802,13 @@ export function initDefaultSlashCommands() {
18041802 const stopped = stopGeneration();
18051803 return String(stopped);
18061804 },
18071805 returns: 't`true/false, whether the generation was running and got stopped'`,
18081806 helpString: `
18091807 <div>
18101808 ${t`Stops the generation and any streaming if it is currently running.`}
18111809 </div>
18121810 <div>
18131811 ${t`Note: This command cannot be executed from the chat input, as sending any message or script from there is blocked during generation. But it can be executed via automations or QR scripts/buttons.`}
1814- But it can be executed via automations or QR scripts/buttons.
18151812 </div>
18161813 `,
18171814 aliases: ['generate-stop'],
@@ -1822,27 +1819,27 @@ export function initDefaultSlashCommands() {
18221819 namedArgumentList: [
18231820 SlashCommandNamedArgument.fromProps({
18241821 name: 'quiet',
18251822 description: 't`Whether to suppress the toast message notifying about the /abort call.'`,
18261823 typeList: [ARGUMENT_TYPE.BOOLEAN],
18271824 defaultValue: 'true',
18281825 }),
18291826 ],
18301827 unnamedArgumentList: [
18311828 SlashCommandArgument.fromProps({
18321829 description: 't`The reason for aborting command execution. Shown when quiet=false'`,
18331830 typeList: [ARGUMENT_TYPE.STRING],
18341831 }),
18351832 ],
18361833 helpString: 't`Aborts the slash command batch execution.'`,
18371834 }));
18381835 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
18391836 name: 'fuzzy',
18401837 callback: fuzzyCallback,
18411838 returns: 't`matching item'`,
18421839 namedArgumentList: [
18431840 SlashCommandNamedArgument.fromProps({
18441841 name: 'list',
18451842 description: 't`list of items to match against'`,
18461843 acceptsMultiple: false,
18471844 isRequired: true,
18481845 typeList: [ARGUMENT_TYPE.LIST, ARGUMENT_TYPE.VARIABLE_NAME],
@@ -1850,7 +1847,7 @@ export function initDefaultSlashCommands() {
18501847 }),
18511848 SlashCommandNamedArgument.fromProps({
18521849 name: 'threshold',
18531850 description: 't`fuzzy match threshold (0.0 to 1.0)'`,
18541851 typeList: [ARGUMENT_TYPE.NUMBER],
18551852 isRequired: false,
18561853 defaultValue: '0.4',
@@ -1858,44 +1855,43 @@ export function initDefaultSlashCommands() {
18581855 }),
18591856 SlashCommandNamedArgument.fromProps({
18601857 name: 'mode',
18611858 description: 't`fuzzy match mode'`,
18621859 typeList: [ARGUMENT_TYPE.STRING],
18631860 isRequired: false,
18641861 defaultValue: 'first',
18651862 acceptsMultiple: false,
18661863 enumList: [
18671864 new SlashCommandEnumValue('first', 't`first match below the threshold'`, enumTypes.enum, enumIcons.default),
18681865 new SlashCommandEnumValue('best', 't`best match below the threshold'`, enumTypes.enum, enumIcons.default),
18691866 ],
18701867 }),
18711868 ],
18721869 unnamedArgumentList: [
18731870 new SlashCommandArgument(
18741871 't`text to search'`, [ARGUMENT_TYPE.STRING], true,
18751872 ),
18761873 ],
18771874 helpString: `
18781875 <div>
18791876 ${t`Performs a fuzzy match of each item in the <code>list</code> against the <code>text to search</code>. If any item matches, then its name is returned. If no item matches the text, no value is returned.`}
1880- If any item matches, then its name is returned. If no item matches the text, no value is returned.
18811877 </div>
18821878 <div>
18831879 ${t`The optional <code>threshold</code> (default is 0.4) allows control over the match strictness.`}
18841880 ${t`A low value (min 0.0) means the match is very strict.`}
18851881 ${t`At 1.0 (max) the match is very loose and will match anything.`}
18861882 </div>
18871883 <div>
18881884 ${t`The optional <code>mode</code> argument allows to control the behavior when multiple items match the text.`}
18891885 <ul>
18901886 <li>${t`<code>first</code> (default) returns the first match below the threshold.`}</li>
18911887 <li>${t`<code>best</code> returns the best match below the threshold.`}</li>
18921888 </ul>
18931889 </div>
18941890 <div>
18951891 ${t`The returned value passes to the next command through the pipe.`}
18961892 </div>
18971893 <div>
18981894 <strong>${t`Example:`}</strong>
18991895 <ul>
19001896 <li>
19011897 <pre><code>/fuzzy list=["a","b","c"] threshold=0.4 abc</code></pre>
@@ -1908,23 +1904,23 @@ export function initDefaultSlashCommands() {
19081904 name: 'pass',
19091905 callback: (_, arg) => {
19101906 // We do not support arrays of closures. Arrays of strings will be send as JSON
19111907 if (Array.isArray(arg) && arg.some(x => x instanceof SlashCommandClosure)) throw new Error('t`Command /pass does not support multiple closures'`);
19121908 if (Array.isArray(arg)) return JSON.stringify(arg);
19131909 return arg;
19141910 },
19151911 returns: 't`the provided value'`,
19161912 unnamedArgumentList: [
19171913 new SlashCommandArgument(
19181914 't`text'`, [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.BOOLEAN, ARGUMENT_TYPE.LIST, ARGUMENT_TYPE.DICTIONARY, ARGUMENT_TYPE.CLOSURE], true,
19191915 ),
19201916 ],
19211917 aliases: ['return'],
19221918 helpString: `
19231919 <div>
19241920 <pre><span class="monospace">/pass (text)</span> – ${t`passes the text to the next command through the pipe.`}</pre>
19251921 </div>
19261922 <div>
19271923 <strong>${t`Example:`}</strong>
19281924 <ul>
19291925 <li><pre><code>/pass Hello world</code></pre></li>
19301926 </ul>
@@ -1937,15 +1933,15 @@ export function initDefaultSlashCommands() {
19371933 aliases: ['wait', 'sleep'],
19381934 unnamedArgumentList: [
19391935 new SlashCommandArgument(
19401936 't`milliseconds'`, [ARGUMENT_TYPE.NUMBER], true,
19411937 ),
19421938 ],
19431939 helpString: `
19441940 <div>
19451941 ${t`Delays the next command in the pipe by the specified number of milliseconds.`}
19461942 </div>
19471943 <div>
19481944 <strong>${t`Example:`}</strong>
19491945 <ul>
19501946 <li>
19511947 <pre><code>/delay 1000</code></pre>
@@ -1958,59 +1954,59 @@ export function initDefaultSlashCommands() {
19581954 name: 'input',
19591955 aliases: ['prompt'],
19601956 callback: inputCallback,
19611957 returns: 't`user input'`,
19621958 namedArgumentList: [
19631959 SlashCommandNamedArgument.fromProps({
19641960 name: 'default',
19651961 description: 't`default value of the input field'`,
19661962 typeList: [ARGUMENT_TYPE.STRING],
19671963 }),
19681964 SlashCommandNamedArgument.fromProps({
19691965 name: 'large',
19701966 description: 't`popup window will be shown larger in height, with more space for content (input field needs to be sized via \'rows\' argument)'`,
19711967 typeList: [ARGUMENT_TYPE.BOOLEAN],
19721968 defaultValue: 'off',
19731969 enumList: commonEnumProviders.boolean('onOff')(),
19741970 }),
19751971 SlashCommandNamedArgument.fromProps({
19761972 name: 'wide',
19771973 description: 't`popup window will be shown wider, with a wider input field'`,
19781974 typeList: [ARGUMENT_TYPE.BOOLEAN],
19791975 defaultValue: 'off',
19801976 enumList: commonEnumProviders.boolean('onOff')(),
19811977 }),
19821978 SlashCommandNamedArgument.fromProps({
19831979 name: 'okButton',
19841980 description: 't`text for the ok button'`,
19851981 typeList: [ARGUMENT_TYPE.STRING],
19861982 defaultValue: 'Ok',
19871983 }),
19881984 SlashCommandNamedArgument.fromProps({
19891985 name: 'rows',
19901986 description: 't`number of rows for the input field (lines being displayed)'`,
19911987 typeList: [ARGUMENT_TYPE.NUMBER],
19921988 }),
19931989 SlashCommandNamedArgument.fromProps({
19941990 name: 'onSuccess',
19951991 description: 't`closure to execute when the ok button is clicked or the input is closed as successful (via Enter, etc)'`,
19961992 typeList: [ARGUMENT_TYPE.CLOSURE],
19971993 }),
19981994 SlashCommandNamedArgument.fromProps({
19991995 name: 'onCancel',
20001996 description: 't`closure to execute when the cancel button is clicked or the input is closed as cancelled (via Escape, etc)'`,
20011997 typeList: [ARGUMENT_TYPE.CLOSURE],
20021998 }),
20031999 ],
20042000 unnamedArgumentList: [
20052001 SlashCommandArgument.fromProps({
20062002 description: 't`text to display'`,
20072003 typeList: [ARGUMENT_TYPE.STRING],
20082004 }),
20092005 ],
20102006 helpString: `
20112007 <div>
20122008 ${t`Shows a popup with the provided text and an input field.`}
20132009 ${t`The <code>default</code> argument is the default value of the input field, and the text argument is the text to display.`}
20142010 </div>
20152011 `,
20162012 }));
@@ -2018,15 +2014,15 @@ export function initDefaultSlashCommands() {
20182014 name: 'run',
20192015 aliases: ['call', 'exec'],
20202016 callback: runCallback,
20212017 returns: 't`result of the executed closure of QR'`,
20222018 namedArgumentList: [
20232019 new SlashCommandNamedArgument(
20242020 'args', 't`named arguments'`, [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.BOOLEAN, ARGUMENT_TYPE.LIST, ARGUMENT_TYPE.DICTIONARY], false, true,
20252021 ),
20262022 ],
20272023 unnamedArgumentList: [
20282024 SlashCommandArgument.fromProps({
20292025 description: 't`scoped variable or qr label'`,
20302026 typeList: [ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.CLOSURE],
20312027 isRequired: true,
20322028 enumProvider: (executor, scope) => [
@@ -2037,8 +2033,8 @@ export function initDefaultSlashCommands() {
20372033 ],
20382034 helpString: `
20392035 <div>
20402036 ${t`Runs a closure from a scoped variable, or a Quick Reply with the specified name from a currently active preset or from another preset.`}
20412037 ${t`Named arguments can be referenced in a QR with <code>{{arg::key}}</code>.`}
20422038 </div>
20432039 `,
20442040 }));
@@ -2048,14 +2044,14 @@ export function initDefaultSlashCommands() {
20482044 aliases: ['message'],
20492045 namedArgumentList: [
20502046 new SlashCommandNamedArgument(
20512047 'names', 't`show message author names'`, [ARGUMENT_TYPE.BOOLEAN], false, false, 'off', commonEnumProviders.boolean('onOff')(),
20522048 ),
20532049 new SlashCommandNamedArgument(
20542050 'hidden', 't`include hidden messages'`, [ARGUMENT_TYPE.BOOLEAN], false, false, 'on', commonEnumProviders.boolean('onOff')(),
20552051 ),
20562052 SlashCommandNamedArgument.fromProps({
20572053 name: 'role',
20582054 description: 't`filter messages by role'`,
20592055 typeList: [ARGUMENT_TYPE.STRING],
20602056 enumList: [
20612057 new SlashCommandEnumValue('system', null, enumTypes.enum, enumIcons.system),
@@ -2066,33 +2062,33 @@ export function initDefaultSlashCommands() {
20662062 ],
20672063 unnamedArgumentList: [
20682064 SlashCommandArgument.fromProps({
20692065 description: 't`message index (starts with 0) or range'`,
20702066 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE],
20712067 isRequired: true,
20722068 enumProvider: commonEnumProviders.messages(),
20732069 }),
20742070 ],
20752071 returns: 't`the specified message or range of messages as a string'`,
20762072 helpString: `
20772073 <div>
20782074 ${t`Returns the specified message or range of messages as a string.`}
20792075 </div>
20802076 <div>
20812077 ${t`Use the <code>hidden=off</code> argument to exclude hidden messages.`}
20822078 </div>
20832079 <div>
20842080 ${t`Use the <code>role</code> argument to filter messages by role. Possible values are: system, assistant, user.`}
20852081 </div>
20862082 <div>
20872083 <strong>${t`Examples:`}</strong>
20882084 <ul>
20892085 <li>
20902086 <pre><code>/messages 10</code></pre>
20912087 ${t`Returns the 10th message.`}
20922088 </li>
20932089 <li>
20942090 <pre><code>/messages names=on 5-10</code></pre>
20952091 ${t`Returns messages 5 through 10 with author names.`}
20962092 </li>
20972093 </ul>
20982094 </div>
@@ -2103,15 +2099,15 @@ export function initDefaultSlashCommands() {
21032099 callback: setInputCallback,
21042100 unnamedArgumentList: [
21052101 new SlashCommandArgument(
21062102 't`text'`, [ARGUMENT_TYPE.STRING], true,
21072103 ),
21082104 ],
21092105 helpString: `
21102106 <div>
21112107 ${t`Sets the user input to the specified text and passes it to the next command through the pipe.`}
21122108 </div>
21132109 <div>
21142110 <strong>${t`Example:`}</strong>
21152111 <ul>
21162112 <li>
21172113 <pre><code>/setinput Hello world</code></pre>
@@ -2123,57 +2119,57 @@ export function initDefaultSlashCommands() {
21232119 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
21242120 name: 'popup',
21252121 callback: popupCallback,
21262122 returns: 't`popup text'`,
21272123 namedArgumentList: [
21282124 SlashCommandNamedArgument.fromProps({
21292125 name: 'scroll',
21302126 description: 't`allows vertical scrolling of the content'`,
21312127 typeList: [ARGUMENT_TYPE.BOOLEAN],
21322128 enumList: commonEnumProviders.boolean('trueFalse')(),
21332129 defaultValue: 'true',
21342130 }),
21352131 SlashCommandNamedArgument.fromProps({
21362132 name: 'large',
21372133 description: 't`show large popup'`,
21382134 typeList: [ARGUMENT_TYPE.BOOLEAN],
21392135 enumList: commonEnumProviders.boolean('trueFalse')(),
21402136 defaultValue: 'false',
21412137 }),
21422138 SlashCommandNamedArgument.fromProps({
21432139 name: 'wide',
21442140 description: 't`show wide popup'`,
21452141 typeList: [ARGUMENT_TYPE.BOOLEAN],
21462142 enumList: commonEnumProviders.boolean('trueFalse')(),
21472143 defaultValue: 'false',
21482144 }),
21492145 SlashCommandNamedArgument.fromProps({
21502146 name: 'wider',
21512147 description: 't`show wider popup'`,
21522148 typeList: [ARGUMENT_TYPE.BOOLEAN],
21532149 enumList: commonEnumProviders.boolean('trueFalse')(),
21542150 defaultValue: 'false',
21552151 }),
21562152 SlashCommandNamedArgument.fromProps({
21572153 name: 'transparent',
21582154 description: 't`show transparent popup'`,
21592155 typeList: [ARGUMENT_TYPE.BOOLEAN],
21602156 enumList: commonEnumProviders.boolean('trueFalse')(),
21612157 defaultValue: 'false',
21622158 }),
21632159 SlashCommandNamedArgument.fromProps({
21642160 name: 'okButton',
21652161 description: 't`text for the OK button'`,
21662162 typeList: [ARGUMENT_TYPE.STRING],
21672163 defaultValue: 'OK',
21682164 }),
21692165 SlashCommandNamedArgument.fromProps({
21702166 name: 'cancelButton',
21712167 description: 't`text for the Cancel button'`,
21722168 typeList: [ARGUMENT_TYPE.STRING],
21732169 }),
21742170 SlashCommandNamedArgument.fromProps({
21752171 name: 'result',
21762172 description: 't`if enabled, returns the popup result (as an integer) instead of the popup text. Resolves to 1 for OK and 0 cancel button, empty string for exiting out.'`,
21772173 typeList: [ARGUMENT_TYPE.BOOLEAN],
21782174 enumList: commonEnumProviders.boolean('trueFalse')(),
21792175 defaultValue: 'false',
@@ -2181,18 +2177,18 @@ export function initDefaultSlashCommands() {
21812177 ],
21822178 unnamedArgumentList: [
21832179 SlashCommandArgument.fromProps({
21842180 description: 't`popup text'`,
21852181 typeList: [ARGUMENT_TYPE.STRING],
21862182 isRequired: true,
21872183 }),
21882184 ],
21892185 helpString: `
21902186 <div>
21912187 ${t`Shows a blocking popup with the specified text and buttons.`}
21922188 ${t`Returns the popup text.`}
21932189 </div>
21942190 <div>
21952191 <strong>${t`Example:`}</strong>
21962192 <ul>
21972193 <li>
21982194 <pre><code>/popup large=on wide=on okButton="Confirm" Please confirm this action.</code></pre>
@@ -2207,17 +2203,17 @@ export function initDefaultSlashCommands() {
22072203 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
22082204 name: 'buttons',
22092205 callback: buttonsCallback,
22102206 returns: 't`clicked button label (or array of labels if multiple is enabled)'`,
22112207 namedArgumentList: [
22122208 SlashCommandNamedArgument.fromProps({
22132209 name: 'labels',
22142210 description: 't`button labels'`,
22152211 typeList: [ARGUMENT_TYPE.LIST],
22162212 isRequired: true,
22172213 }),
22182214 SlashCommandNamedArgument.fromProps({
22192215 name: 'multiple',
22202216 description: 't`if enabled multiple buttons can be clicked/toggled, and all clicked buttons are returned as an array'`,
22212217 typeList: [ARGUMENT_TYPE.BOOLEAN],
22222218 enumList: commonEnumProviders.boolean('trueFalse')(),
22232219 defaultValue: 'false',
@@ -2225,18 +2221,18 @@ export function initDefaultSlashCommands() {
22252221 ],
22262222 unnamedArgumentList: [
22272223 SlashCommandArgument.fromProps({
22282224 description: 't`text'`,
22292225 typeList: [ARGUMENT_TYPE.STRING],
22302226 isRequired: true,
22312227 }),
22322228 ],
22332229 helpString: `
22342230 <div>
22352231 ${t`Shows a blocking popup with the specified text and buttons.`}
22362232 ${t`Returns the clicked button label into the pipe or empty string if canceled.`}
22372233 </div>
22382234 <div>
22392235 <strong>${t`Example:`}</strong>
22402236 <ul>
22412237 <li>
22422238 <pre><code>/buttons labels=["Yes","No"] Do you want to continue?</code></pre>
@@ -2248,14 +2244,14 @@ export function initDefaultSlashCommands() {
22482244 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
22492245 name: 'trimtokens',
22502246 callback: trimTokensCallback,
22512247 returns: 't`trimmed text'`,
22522248 namedArgumentList: [
22532249 new SlashCommandNamedArgument(
22542250 'limit', 't`number of tokens to keep'`, [ARGUMENT_TYPE.NUMBER], true,
22552251 ),
22562252 SlashCommandNamedArgument.fromProps({
22572253 name: 'direction',
22582254 description: 't`trim direction'`,
22592255 typeList: [ARGUMENT_TYPE.STRING],
22602256 isRequired: true,
22612257 enumList: [
@@ -2266,15 +2262,15 @@ export function initDefaultSlashCommands() {
22662262 ],
22672263 unnamedArgumentList: [
22682264 new SlashCommandArgument(
22692265 't`text'`, [ARGUMENT_TYPE.STRING], false,
22702266 ),
22712267 ],
22722268 helpString: `
22732269 <div>
22742270 ${t`Trims the start or end of text to the specified number of tokens.`}
22752271 </div>
22762272 <div>
22772273 <strong>${t`Example:`}</strong>
22782274 <ul>
22792275 <li>
22802276 <pre><code>/trimtokens limit=5 direction=start This is a long sentence with many words</code></pre>
@@ -2286,18 +2282,18 @@ export function initDefaultSlashCommands() {
22862282 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
22872283 name: 'trimstart',
22882284 callback: trimStartCallback,
22892285 returns: 't`trimmed text'`,
22902286 unnamedArgumentList: [
22912287 new SlashCommandArgument(
22922288 't`text'`, [ARGUMENT_TYPE.STRING], true,
22932289 ),
22942290 ],
22952291 helpString: `
22962292 <div>
22972293 ${t`Trims the text to the start of the first full sentence.`}
22982294 </div>
22992295 <div>
23002296 <strong>${t`Example:`}</strong>
23012297 <ul>
23022298 <li>
23032299 <pre><code>/trimstart This is a sentence. And here is another sentence.</code></pre>
@@ -2309,38 +2305,38 @@ export function initDefaultSlashCommands() {
23092305 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
23102306 name: 'trimend',
23112307 callback: trimEndCallback,
23122308 returns: 't`trimmed text'`,
23132309 unnamedArgumentList: [
23142310 new SlashCommandArgument(
23152311 't`text'`, [ARGUMENT_TYPE.STRING], true,
23162312 ),
23172313 ],
23182314 helpString: 't`Trims the text to the end of the last full sentence.'`,
23192315 }));
23202316 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
23212317 name: 'inject',
23222318 returns: 't`injection ID'`,
23232319 callback: injectCallback,
23242320 namedArgumentList: [
23252321 SlashCommandNamedArgument.fromProps({
23262322 name: 'id',
23272323 description: 't`injection ID'`,
23282324 typeList: [ARGUMENT_TYPE.STRING],
23292325 isRequired: false,
23302326 enumProvider: commonEnumProviders.injects,
23312327 }),
23322328 new SlashCommandNamedArgument(
23332329 'position', 't`injection position'`, [ARGUMENT_TYPE.STRING], false, false, 'after', ['before', 'after', 'chat', 'none'],
23342330 ),
23352331 new SlashCommandNamedArgument(
23362332 'depth', 't`injection depth'`, [ARGUMENT_TYPE.NUMBER], false, false, '4',
23372333 ),
23382334 new SlashCommandNamedArgument(
23392335 'scan', 't`include injection content into World Info scans'`, [ARGUMENT_TYPE.BOOLEAN], false, false, 'false',
23402336 ),
23412337 SlashCommandNamedArgument.fromProps({
23422338 name: 'role',
23432339 description: 't`role for in-chat injections'`,
23442340 typeList: [ARGUMENT_TYPE.STRING],
23452341 isRequired: false,
23462342 enumList: [
@@ -2350,11 +2346,11 @@ export function initDefaultSlashCommands() {
23502346 ],
23512347 }),
23522348 new SlashCommandNamedArgument(
23532349 'ephemeral', 't`remove injection after generation'`, [ARGUMENT_TYPE.BOOLEAN], false, false, 'false',
23542350 ),
23552351 SlashCommandNamedArgument.fromProps({
23562352 name: 'filter',
23572353 description: 't`if a filter is defined, an injection will only be performed if the closure returns true'`,
23582354 typeList: [ARGUMENT_TYPE.CLOSURE],
23592355 isRequired: false,
23602356 acceptsMultiple: false,
@@ -2362,20 +2358,20 @@ export function initDefaultSlashCommands() {
23622358 ],
23632359 unnamedArgumentList: [
23642360 new SlashCommandArgument(
23652361 't`text'`, [ARGUMENT_TYPE.STRING], false,
23662362 ),
23672363 ],
23682364 helpString: 't`Injects a text into the LLM prompt for the current chat. Requires a unique injection ID (will be auto-generated if not provided). Positions: "before" main prompt, "after" main prompt, in-"chat", hidden with "none" (default: after). Depth: injection depth for the prompt (default: 4). Role: role for in-chat injections (default: system). Scan: include injection content into World Info scans (default: false). Hidden injects in "none" position are not inserted into the prompt but can be used for triggering WI entries. Returns the injection ID.'`,
23692365 }));
23702366 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
23712367 name: 'listinjects',
23722368 callback: listInjectsCallback,
23732369 helpString: 't`Lists all script injections for the current chat. Displays injects in a popup by default. Use the <code>return</code> argument to change the return type.'`,
23742370 returns: 'Optionallst`Optionally the JSON object of script injections'`,
23752371 namedArgumentList: [
23762372 SlashCommandNamedArgument.fromProps({
23772373 name: 'return',
23782374 description: 't`The way how you want the return value to be provided'`,
23792375 typeList: [ARGUMENT_TYPE.STRING],
23802376 defaultValue: 'popup-html',
23812377 enumList: slashCommandReturnHelper.enumList({ allowPipe: false, allowObject: true, allowChat: true, allowPopup: true, allowTextVersion: false }),
@@ -2384,14 +2380,14 @@ export function initDefaultSlashCommands() {
23842380 // TODO remove some day
23852381 SlashCommandNamedArgument.fromProps({
23862382 name: 'format',
23872383 description: 't`!!! DEPRECATED - use "return" instead !!! output format'`,
23882384 typeList: [ARGUMENT_TYPE.STRING],
23892385 isRequired: true,
23902386 forceEnum: true,
23912387 enumList: [
23922388 new SlashCommandEnumValue('popup', 't`Show injects in a popup.'`, enumTypes.enum, enumIcons.default),
23932389 new SlashCommandEnumValue('chat', 't`Post a system message to the chat.'`, enumTypes.enum, enumIcons.default),
23942390 new SlashCommandEnumValue('none', 't`Just return the injects as a JSON object.'`, enumTypes.enum, enumIcons.default),
23952391 ],
23962392 }),
23972393 ],
@@ -2401,37 +2397,37 @@ export function initDefaultSlashCommands() {
24012397 aliases: ['flushinjects'],
24022398 unnamedArgumentList: [
24032399 SlashCommandArgument.fromProps({
24042400 description: 't`injection ID or a variable name pointing to ID'`,
24052401 typeList: [ARGUMENT_TYPE.STRING],
24062402 defaultValue: '',
24072403 enumProvider: commonEnumProviders.injects,
24082404 }),
24092405 ],
24102406 callback: flushInjectsCallback,
24112407 helpString: 't`Removes a script injection for the current chat. If no ID is provided, removes all script injections.'`,
24122408 }));
24132409 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
24142410 name: 'tokens',
24152411 callback: (_, text) => {
24162412 if (text instanceof SlashCommandClosure || Array.isArray(text)) throw new Error('t`Unnamed argument cannot be a closure for command /tokens'`);
24172413 return getTokenCountAsync(text).then(count => String(count));
24182414 },
24192415 returns: 't`number of tokens'`,
24202416 unnamedArgumentList: [
24212417 new SlashCommandArgument(
24222418 't`text'`, [ARGUMENT_TYPE.STRING], true,
24232419 ),
24242420 ],
24252421 helpString: 't`Counts the number of tokens in the provided text.'`,
24262422 }));
24272423 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
24282424 name: 'model',
24292425 callback: modelCallback,
24302426 returns: 't`current model'`,
24312427 namedArgumentList: [
24322428 SlashCommandNamedArgument.fromProps({
24332429 name: 'quiet',
24342430 description: 't`suppress the toast message on model change'`,
24352431 typeList: [ARGUMENT_TYPE.BOOLEAN],
24362432 defaultValue: 'false',
24372433 enumList: commonEnumProviders.boolean('trueFalse')(),
@@ -2439,22 +2435,22 @@ export function initDefaultSlashCommands() {
24392435 ],
24402436 unnamedArgumentList: [
24412437 SlashCommandArgument.fromProps({
24422438 description: 't`model name'`,
24432439 typeList: [ARGUMENT_TYPE.STRING],
24442440 enumProvider: () => getModelOptions(true)?.options?.map(option => new SlashCommandEnumValue(option.value, option.value !== option.text ? option.text : null)) ?? [],
24452441 }),
24462442 ],
24472443 helpString: 't`Sets the model for the current API. Gets the current model name if no argument is provided.'`,
24482444 }));
24492445 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
24502446 name: 'getpromptentry',
24512447 aliases: ['getpromptentries'],
24522448 callback: getPromptEntryCallback,
24532449 returns: 't`true/false state of prompt(s)'`,
24542450 namedArgumentList: [
24552451 SlashCommandNamedArgument.fromProps({
24562452 name: 'identifier',
24572453 description: 't`Prompt entry identifier(s) to retrieve'`,
24582454 typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST],
24592455 acceptsMultiple: true,
24602456 enumProvider: () =>
@@ -2464,7 +2460,7 @@ export function initDefaultSlashCommands() {
24642460 }),
24652461 SlashCommandNamedArgument.fromProps({
24662462 name: 'name',
24672463 description: 't`Prompt entry name(s) to retrieve'`,
24682464 typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST],
24692465 acceptsMultiple: true,
24702466 enumProvider: () =>
@@ -2474,7 +2470,7 @@ export function initDefaultSlashCommands() {
24742470 }),
24752471 SlashCommandNamedArgument.fromProps({
24762472 name: 'return',
24772473 description: 't`Whether the return will be simple, a list, or a dict.'`,
24782474 typeList: [ARGUMENT_TYPE.STRING],
24792475 defaultValue: 'simple',
24802476 enumList: ['simple', 'list', 'dict'],
@@ -2482,10 +2478,10 @@ export function initDefaultSlashCommands() {
24822478 ],
24832479 helpString: `
24842480 <div>
24852481 ${t`Gets the state of the specified prompt entries.`}
24862482 </div>
24872483 <div>
24882484 ${t`If <code>return</code> is <code>simple</code> (default) then the return will be a single value if only one value was retrieved; otherwise uses a dict (if the identifier parameter was used) or a list.`}
24892485 </div>
24902486 `,
24912487 }));
@@ -2496,7 +2492,7 @@ export function initDefaultSlashCommands() {
24962492 namedArgumentList: [
24972493 SlashCommandNamedArgument.fromProps({
24982494 name: 'identifier',
24992495 description: 't`Prompt entry identifier(s) to target'`,
25002496 typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST],
25012497 acceptsMultiple: true,
25022498 enumProvider: () => {
@@ -2506,7 +2502,7 @@ export function initDefaultSlashCommands() {
25062502 }),
25072503 SlashCommandNamedArgument.fromProps({
25082504 name: 'name',
25092505 description: 't`Prompt entry name(s) to target'`,
25102506 typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST],
25112507 acceptsMultiple: true,
25122508 enumProvider: () => {
@@ -2517,7 +2513,7 @@ export function initDefaultSlashCommands() {
25172513 ],
25182514 unnamedArgumentList: [
25192515 SlashCommandArgument.fromProps({
25202516 description: 't`Set entry/entries on or off'`,
25212517 typeList: [ARGUMENT_TYPE.STRING],
25222518 isRequired: true,
25232519 acceptsMultiple: false,
@@ -2525,16 +2521,16 @@ export function initDefaultSlashCommands() {
25252521 enumList: commonEnumProviders.boolean('onOffToggle')(),
25262522 }),
25272523 ],
25282524 helpString: 't`Sets the specified prompt manager entry/entries on or off.'`,
25292525 }));
25302526 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
25312527 name: 'pick-icon',
25322528 callback: async () => ((await showFontAwesomePicker()) ?? false).toString(),
25332529 returns: 't`The chosen icon name or false if cancelled.'`,
25342530 helpString: `
25352531 <div>${t`Opens a popup with all the available Font Awesome icons and returns the selected icon's name.`}</div>
25362532 <div>
25372533 <strong>${t`Example:`}</strong>
25382534 <ul>
25392535 <li>
25402536 <pre><code>/pick-icon |\n/if left={{pipe}} rule=eq right=false\n\telse={: /echo chosen icon: "{{pipe}}" :}\n\t{: /echo cancelled icon selection :}\n|</code></pre>
@@ -2546,12 +2542,12 @@ export function initDefaultSlashCommands() {
25462542 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
25472543 name: 'api-url',
25482544 callback: setApiUrlCallback,
25492545 returns: 't`the current API url'`,
25502546 aliases: ['server'],
25512547 namedArgumentList: [
25522548 SlashCommandNamedArgument.fromProps({
25532549 name: 'api',
25542550 description: 't`API to set/get the URL for - if not provided, current API is used'`,
25552551 typeList: [ARGUMENT_TYPE.STRING],
25562552 enumList: [
25572553 new SlashCommandEnumValue('custom', 'custom OpenAI-compatible', enumTypes.getBasedOnIndex(UNIQUE_APIS.findIndex(x => x === 'openai')), 'O'),
@@ -2561,14 +2557,14 @@ export function initDefaultSlashCommands() {
25612557 }),
25622558 SlashCommandNamedArgument.fromProps({
25632559 name: 'connect',
25642560 description: 't`Whether to auto-connect to the API after setting the URL'`,
25652561 typeList: [ARGUMENT_TYPE.BOOLEAN],
25662562 defaultValue: 'true',
25672563 enumList: commonEnumProviders.boolean('trueFalse')(),
25682564 }),
25692565 SlashCommandNamedArgument.fromProps({
25702566 name: 'quiet',
25712567 description: 't`suppress the toast message on API change'`,
25722568 typeList: [ARGUMENT_TYPE.BOOLEAN],
25732569 defaultValue: 'false',
25742570 enumList: commonEnumProviders.boolean('trueFalse')(),
@@ -2576,31 +2572,29 @@ export function initDefaultSlashCommands() {
25762572 ],
25772573 unnamedArgumentList: [
25782574 SlashCommandArgument.fromProps({
25792575 description: 't`API url to connect to'`,
25802576 typeList: [ARGUMENT_TYPE.STRING],
25812577 }),
25822578 ],
25832579 helpString: `
25842580 <div>
25852581 ${t`Set the API url / server url for the currently selected API, including the port. If no argument is provided, it will return the current API url.`}
25862582 </div>
25872583 <div>
25882584 ${t`If a manual API is provided to <b>set</b> the URL, make sure to set <code>connect=false</code>, as auto-connect only works for the currently selected API, or consider switching to it with <code>/api</code> first.`}
2589- or consider switching to it with <code>/api</code> first.
25902585 </div>
25912586 <div>
25922587 ${t`This slash command works for most of the Text Completion sources, KoboldAI Classic, and also Custom OpenAI compatible for the Chat Completion sources. If unsure which APIs are supported, check the auto-completion of the optional <code>api</code> argument of this command.`}
2593- check the auto-completion of the optional <code>api</code> argument of this command.
25942588 </div>
25952589 `,
25962590 }));
25972591 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
25982592 name: 'tokenizer',
25992593 callback: selectTokenizerCallback,
26002594 returns: 't`current tokenizer'`,
26012595 unnamedArgumentList: [
26022596 SlashCommandArgument.fromProps({
26032597 description: 't`tokenizer name'`,
26042598 typeList: [ARGUMENT_TYPE.STRING],
26052599 enumList: getAvailableTokenizers().map(tokenizer =>
26062600 new SlashCommandEnumValue(tokenizer.tokenizerKey, tokenizer.tokenizerName, enumTypes.enum, enumIcons.default)),
@@ -2608,10 +2602,10 @@ export function initDefaultSlashCommands() {
26082602 ],
26092603 helpString: `
26102604 <div>
26112605 ${t`Selects tokenizer by name. Gets the current tokenizer if no name is provided.`}
26122606 </div>
26132607 <div>
26142608 <strong>${t`Available tokenizers:`}</strong>
26152609 <pre><code>${getAvailableTokenizers().map(t => t.tokenizerKey).join(', ')}</code></pre>
26162610 </div>
26172611 `,
@@ -2620,58 +2614,58 @@ export function initDefaultSlashCommands() {
26202614 name: 'upper',
26212615 aliases: ['uppercase', 'to-upper'],
26222616 callback: (_, text) => typeof text === 'string' ? text.toUpperCase() : '',
26232617 returns: 't`uppercase string'`,
26242618 unnamedArgumentList: [
26252619 new SlashCommandArgument(
26262620 't`text to affect'`, [ARGUMENT_TYPE.STRING], true, false,
26272621 ),
26282622 ],
26292623 helpString: 't`Converts the provided string to uppercase.'`,
26302624 }));
26312625 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
26322626 name: 'lower',
26332627 aliases: ['lowercase', 'to-lower'],
26342628 callback: (_, text) => typeof text === 'string' ? text.toLowerCase() : '',
26352629 returns: 't`lowercase string'`,
26362630 unnamedArgumentList: [
26372631 new SlashCommandArgument(
26382632 't`text to affect'`, [ARGUMENT_TYPE.STRING], true, false,
26392633 ),
26402634 ],
26412635 helpString: 't`Converts the provided string to lowercase.'`,
26422636 }));
26432637 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
26442638 name: 'substr',
26452639 aliases: ['substring'],
26462640 callback: (arg, text) => typeof text === 'string' ? text.slice(...[Number(arg.start), arg.end && Number(arg.end)]) : '',
26472641 returns: 't`substring'`,
26482642 namedArgumentList: [
26492643 new SlashCommandNamedArgument(
26502644 'start', 't`start index'`, [ARGUMENT_TYPE.NUMBER], false, false,
26512645 ),
26522646 new SlashCommandNamedArgument(
26532647 'end', 't`end index'`, [ARGUMENT_TYPE.NUMBER], false, false,
26542648 ),
26552649 ],
26562650 unnamedArgumentList: [
26572651 new SlashCommandArgument(
26582652 't`text to affect'`, [ARGUMENT_TYPE.STRING], true, false,
26592653 ),
26602654 ],
26612655 helpString: `
26622656 <div>
26632657 ${t`Extracts text from the provided string.`}
26642658 </div>
26652659 <div>
26662660 ${t`If <code>start</code> is omitted, it's treated as 0.<br />`}
26672661 ${t`If <code>start</code> < 0, the index is counted from the end of the string.<br />`}
26682662 ${t`If <code>start</code> >= the string's length, an empty string is returned.<br />`}
26692663 ${t`If <code>end</code> is omitted, or if <code>end</code> >= the string's length, extracts to the end of the string.<br />`}
26702664 ${t`If <code>end</code> < 0, the index is counted from the end of the string.<br />`}
26712665 ${t`If <code>end</code> <= <code>start</code> after normalizing negative values, an empty string is returned.`}
26722666 </div>
26732667 <div>
26742668 <strong>${t`Example:`}</strong>
26752669 <pre>/let x The morning is upon us. || </pre>
26762670 <pre>/substr start=-3 {{var::x}} | /echo |/# us. ||</pre>
26772671 <pre>/substr start=-3 end=-1 {{var::x}} | /echo |/# us ||</pre>
@@ -2684,11 +2678,11 @@ export function initDefaultSlashCommands() {
26842678 name: 'is-mobile',
26852679 callback: () => String(isMobile()),
26862680 returns: ARGUMENT_TYPE.BOOLEAN,
26872681 helpString: 't`Returns true if the current device is a mobile device, false otherwise. Equivalent to <code>{{isMobile}}</code> macro.'`,
26882682 }));
26892683 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
26902684 name: 'chat-render',
26912685 helpString: 't`Renders a specified number of messages into the chat window. Displays all messages if no argument is provided.'`,
26922686 callback: async (args, number) => {
26932687 await showMoreMessages(number && !isNaN(Number(number)) ? Number(number) : Number.MAX_SAFE_INTEGER);
26942688 if (isTrueBoolean(String(args?.scroll ?? ''))) {
@@ -2699,7 +2693,7 @@ export function initDefaultSlashCommands() {
26992693 namedArgumentList: [
27002694 SlashCommandNamedArgument.fromProps({
27012695 name: 'scroll',
27022696 description: 't`scroll to the top after rendering'`,
27032697 typeList: [ARGUMENT_TYPE.BOOLEAN],
27042698 defaultValue: 'false',
27052699 enumList: commonEnumProviders.boolean('trueFalse')(),
@@ -2707,13 +2701,13 @@ export function initDefaultSlashCommands() {
27072701 ],
27082702 unnamedArgumentList: [
27092703 new SlashCommandArgument(
27102704 't`number of messages'`, [ARGUMENT_TYPE.NUMBER], false,
27112705 ),
27122706 ],
27132707 }));
27142708 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
27152709 name: 'chat-reload',
27162710 helpString: 't`Reloads the current chat.'`,
27172711 callback: async () => {
27182712 await reloadCurrentChat();
27192713 return '';
@@ -2724,7 +2718,7 @@ export function initDefaultSlashCommands() {
27242718 aliases: ['re'],
27252719 callback: (async ({ mode = 'literal', pattern, replacer = '' }, text) => {
27262720 if (!pattern) {
27272721 throw new Error('t`Argument of \'pattern=\' cannot be empty'`);
27282722 }
27292723 text = text.toString();
27302724 pattern = pattern.toString();
@@ -2735,42 +2729,42 @@ export function initDefaultSlashCommands() {
27352729 case 'regex':
27362730 return text.replace(regexFromString(pattern), replacer);
27372731 default:
27382732 throw new Error('t`Invalid \'/replace mode=\' argument specified!'`);
27392733 }
27402734 }),
27412735 returns: 't`replaced text'`,
27422736 namedArgumentList: [
27432737 SlashCommandNamedArgument.fromProps({
27442738 name: 'mode',
27452739 description: 't`Replaces occurrence(s) of a pattern'`,
27462740 typeList: [ARGUMENT_TYPE.STRING],
27472741 defaultValue: 'literal',
27482742 enumList: ['literal', 'regex'],
27492743 }),
27502744 new SlashCommandNamedArgument(
27512745 'pattern', 't`pattern to search with'`, [ARGUMENT_TYPE.STRING], true, false,
27522746 ),
27532747 new SlashCommandNamedArgument(
27542748 'replacer', 't`replacement text for matches'`, [ARGUMENT_TYPE.STRING], false, false, '',
27552749 ),
27562750 ],
27572751 unnamedArgumentList: [
27582752 new SlashCommandArgument(
27592753 't`text to affect'`, [ARGUMENT_TYPE.STRING], true, false,
27602754 ),
27612755 ],
27622756 helpString: `
27632757 <div>
27642758 ${t`Replaces text within the provided string based on the pattern.`}
27652759 </div>
27662760 <div>
27672761 ${t`If <code>mode</code> is <code>literal</code> (or omitted), <code>pattern</code> is a literal search string (case-sensitive).<br />`}
27682762 ${t`If <code>mode</code> is <code>regex</code>, <code>pattern</code> is parsed as an ECMAScript Regular Expression.<br />`}
27692763 ${t`The <code>replacer</code> replaces based on the <code>pattern</code> in the input text.<br />`}
27702764 ${t`If <code>replacer</code> is omitted, the replacement(s) will be an empty string.<br />`}
27712765 </div>
27722766 <div>
27732767 <strong>${t`Example:`}</strong>
27742768 <pre><code class="language-stscript">/let x Blue house and blue car || </code></pre>
27752769 <pre><code class="language-stscript">/replace pattern="blue" {{var::x}} | /echo |/# Blue house and car ||</code></pre>
27762770 <pre><code class="language-stscript">/replace pattern="blue" replacer="red" {{var::x}} | /echo |/# Blue house and red car ||</code></pre>
@@ -2783,34 +2777,34 @@ export function initDefaultSlashCommands() {
27832777 name: 'test',
27842778 callback: (({ pattern }, text) => {
27852779 if (!pattern) {
27862780 throw new Error('t`Argument of \'pattern=\' cannot be empty'`);
27872781 }
27882782 const re = regexFromString(pattern.toString());
27892783 if (!re) {
27902784 throw new Error('t`The value of \'pattern\' argument is not a valid regular expression.'`);
27912785 }
27922786 return JSON.stringify(re.test(text.toString()));
27932787 }),
27942788 returns: 'true | false',
27952789 namedArgumentList: [
27962790 new SlashCommandNamedArgument(
27972791 'pattern', 't`pattern to find'`, [ARGUMENT_TYPE.STRING], true, false,
27982792 ),
27992793 ],
28002794 unnamedArgumentList: [
28012795 new SlashCommandArgument(
28022796 't`text to test'`, [ARGUMENT_TYPE.STRING], true, false,
28032797 ),
28042798 ],
28052799 helpString: `
28062800 <div>
28072801 ${t`Tests text for a regular expression match.`}
28082802 </div>
28092803 <div>
28102804 ${t`Returns <code>true</code> if the match is found, <code>false</code> otherwise.`}
28112805 </div>
28122806 <div>
28132807 <strong>${t`Example:`}</strong>
28142808 <pre><code class="language-stscript">/let x Blue house and green car ||</code></pre>
28152809 <pre><code class="language-stscript">/test pattern="green" {{var::x}} | /echo |/# true ||</code></pre>
28162810 <pre><code class="language-stscript">/test pattern="blue" {{var::x}} | /echo |/# false ||</code></pre>
@@ -2822,11 +2816,11 @@ export function initDefaultSlashCommands() {
28222816 name: 'match',
28232817 callback: (({ pattern }, text) => {
28242818 if (!pattern) {
28252819 throw new Error('t`Argument of \'pattern=\' cannot be empty'`);
28262820 }
28272821 const re = regexFromString(pattern.toString());
28282822 if (!re) {
28292823 throw new Error('t`The value of \'pattern\' argument is not a valid regular expression.'`);
28302824 }
28312825 if (re.flags.includes('g')) {
28322826 return JSON.stringify([...text.toString().matchAll(re)]);
@@ -2835,28 +2829,26 @@ export function initDefaultSlashCommands() {
28352829 return match ? JSON.stringify(match) : '';
28362830 }
28372831 }),
28382832 returns: 't`group array for each match'`,
28392833 namedArgumentList: [
28402834 new SlashCommandNamedArgument(
28412835 'pattern', 't`pattern to find'`, [ARGUMENT_TYPE.STRING], true, false,
28422836 ),
28432837 ],
28442838 unnamedArgumentList: [
28452839 new SlashCommandArgument(
28462840 't`text to match against'`, [ARGUMENT_TYPE.STRING], true, false,
28472841 ),
28482842 ],
28492843 helpString: `
28502844 <div>
28512845 ${t`Retrieves regular expression matches in the given text`}
28522846 </div>
28532847 <div>
28542848 ${t`Returns an array of groups (with the first group being the full match). If the regex contains the global flag (i.e. <code>/g</code>), multiple nested arrays are returned for each match. If the regex is global, returns <code>[]</code> if no matches are found, otherwise it returns an empty string.`}
2855- multiple nested arrays are returned for each match. If the regex is global, returns <code>[]</code> if no matches are found,
2856- otherwise it returns an empty string.
28572849 </div>
28582850 <div>
28592851 <strong>${t`Example:`}</strong>
28602852 <pre><code class="language-stscript">/let x color_green green lamp color_blue ||</code></pre>
28612853 <pre><code class="language-stscript">/match pattern="green" {{var::x}} | /echo |/# [ "green" ] ||</code></pre>
28622854 <pre><code class="language-stscript">/match pattern="color_(\\w+)" {{var::x}} | /echo |/# [ "color_green", "green" ] ||</code></pre>
@@ -2910,7 +2902,7 @@ export function initDefaultSlashCommands() {
29102902 },
29112903 unnamedArgumentList: [
29122904 SlashCommandArgument.fromProps({
29132905 description: 't`The message index (0-based) to scroll to.'`,
29142906 typeList: [ARGUMENT_TYPE.NUMBER],
29152907 isRequired: true,
29162908 enumProvider: commonEnumProviders.messages(),
@@ -2918,20 +2910,20 @@ export function initDefaultSlashCommands() {
29182910 ],
29192911 helpString: `
29202912 <div>
29212913 ${t`Scrolls the chat view to the specified message index. Index starts at 0.`}
29222914 </div>
29232915 <div>
29242916 <strong>${t`Example:`}</strong> <pre><code>/chat-jump 10</code></pre> ${t`Scrolls to the 11th message (id=10).`}
29252917 </div>
29262918 `,
29272919 }));
29282920
29292921 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
29302922 name: 'clipboard-get',
29312923 returns: 't`clipboard text'`,
29322924 callback: async () => {
29332925 if (!navigator.clipboard) {
29342926 toastr.warning('t`Clipboard API not available in this context.'`);
29352927 return '';
29362928 }
29372929
@@ -2941,11 +2933,11 @@ export function initDefaultSlashCommands() {
29412933 }
29422934 catch (error) {
29432935 console.error('Error reading clipboard:', error);
29442936 toastr.warning('t`Failed to read clipboard text. Have you granted the permission?'`);
29452937 return '';
29462938 }
29472939 },
29482940 helpString: 't`Retrieves the text from the OS clipboard. Only works in secure contexts (HTTPS or localhost). Browser may ask for permission.'`,
29492941 }));
29502942
29512943 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
@@ -2956,13 +2948,13 @@ export function initDefaultSlashCommands() {
29562948 },
29572949 unnamedArgumentList: [
29582950 SlashCommandArgument.fromProps({
29592951 description: 't`text to copy to the clipboard'`,
29602952 typeList: [ARGUMENT_TYPE.STRING],
29612953 isRequired: true,
29622954 acceptsMultiple: false,
29632955 }),
29642956 ],
29652957 helpString: 't`Copies the provided text to the OS clipboard. Returns an empty string.'`,
29662958 }));
29672959
29682960
@@ -2974,10 +2966,10 @@ export function initDefaultSlashCommands() {
29742966 aliases: ['ppp'],
29752967 helpString: `
29762968 <div>
29772969 ${t`Sets a "Prompt Post-Processing" type. Gets the current selection if no value is provided.`}
29782970 </div>
29792971 <div>
29802972 <strong>${t`Examples:`}</strong>
29812973 </div>
29822974 <ul>
29832975 <li><pre><code class="language-stscript">/prompt-post-processing | /echo</code></pre></li>
@@ -2987,7 +2979,7 @@ export function initDefaultSlashCommands() {
29872979 namedArgumentList: [],
29882980 unnamedArgumentList: [
29892981 SlashCommandArgument.fromProps({
29902982 description: 't`value'`,
29912983 typeList: [ARGUMENT_TYPE.STRING],
29922984 acceptsMultiple: false,
29932985 isRequired: true,
@@ -3003,7 +2995,7 @@ export function initDefaultSlashCommands() {
30032995
30042996 const validValues = promptPostProcessingEnumProvider().map(option => option.value);
30052997 if (!validValues.includes(stringValue)) {
30062998 throw new Error(t`Invalid value "${stringValue}". Valid values are: ${validValues.join(', ')}`);
30072999 }
30083000
30093001 // 'none' value must be coerced to an empty string
@@ -3056,9 +3048,8 @@ function injectCallback(args, value) {
30563048 const filter = args?.filter instanceof SlashCommandClosure ? args.filter.rawText : null;
30573049 const filterFunction = args?.filter instanceof SlashCommandClosure ? closureToFilter(args.filter) : null;
30583050 value = value || '';
3059-
30603051 if (args?.filter && !String(filter ?? '').trim()) {
30613052 throw new Error('t`Failed to parse the filter argument. Make sure it is a valid non-empty closure.'`);
30623053 }
30633054
30643055 const prefixedId = `${SCRIPT_PROMPT_KEY}${id}`;
@@ -3102,10 +3093,10 @@ async function listInjectsCallback(args) {
31023093
31033094 // Old legacy return type handling
31043095 if (args.format) {
31053096 toastr.warning(t`Legacy argument 'format' with value '${args.format}' is deprecated. Please use 'return' instead. Routing to the correct return type...`, 't`Deprecation warning'`);
31063097 const type = String(args?.format).toLowerCase().trim();
31073098 if (!chat_metadata.script_injects || !Object.keys(chat_metadata.script_injects).length) {
31083099 type !== 'none' && toastr.info('t`No script injections for the current chat'`);
31093100 }
31103101 switch (type) {
31113102 case 'none':
@@ -3126,11 +3117,11 @@ async function listInjectsCallback(args) {
31263117 const injectsStr = Object.entries(injects)
31273118 .map(([id, inject]) => {
31283119 const position = Object.entries(extension_prompt_types);
31293120 const positionName = position.find(([_, value]) => value === inject.position)?.[0] ?? 't`unknown'`;
31303121 return `* **${id}**: <code>${inject.value}</code> (${positionName}, ${t`depth`}: ${inject.depth}, ${t`scan`}: ${inject.scan ?? false}, ${t`role`}: ${inject.role ?? extension_prompt_roles.SYSTEM})`;
31313122 })
31323123 .join('\n');
31333124 return `### ${t`Script injections:`}\n${injectsStr || 't`No script injections for the current chat'`}`;
31343125 };
31353126
31363127 return await slashCommandReturnHelper.doReturn(returnType ?? 'popup-html', chat_metadata.script_injects ?? {}, { objectToStringFunc: buildTextValue });
@@ -3381,7 +3372,7 @@ async function popupCallback(args, value) {
33813372 wide: isTrueBoolean(args?.wide),
33823373 wider: isTrueBoolean(args?.wider),
33833374 transparent: isTrueBoolean(args?.transparent),
33843375 okButton: args?.okButton !== undefined && typeof args?.okButton === 'string' ? args.okButton : 'Ok't`OK`,
33853376 cancelButton: args?.cancelButton !== undefined && typeof args?.cancelButton === 'string' ? args.cancelButton : null,
33863377 };
33873378 const result = await Popup.show.text(safeHeader, safeBody, popupOptions);
@@ -3418,7 +3409,7 @@ async function getMessagesCallback(args, value) {
34183409 return !isNarrator && mes.is_user;
34193410 }
34203411
34213412 throw new Error(t`Invalid role provided. Expected one of: system, assistant, user. Got: ${role}`);
34223413 };
34233414
34243415 const processMessage = async (mesId) => {
@@ -3453,7 +3444,7 @@ async function getMessagesCallback(args, value) {
34533444
34543445async function runCallback(args, name) {
34553446 if (!name) {
34563447 throw new Error('t`No name provided for /run command'`);
34573448 }
34583449
34593450 if (name instanceof SlashCommandClosure) {
@@ -3466,7 +3457,7 @@ async function runCallback(args, name) {
34663457 if (scope.existsVariable(name)) {
34673458 const closure = scope.getVariable(name);
34683459 if (!(closure instanceof SlashCommandClosure)) {
34693460 throw new Error(t`"${name}" is not callable.`);
34703461 }
34713462 closure.scope.parent = scope;
34723463 closure.breakController = new SlashCommandBreakController();
@@ -3487,7 +3478,7 @@ async function runCallback(args, name) {
34873478 }
34883479
34893480 if (typeof window['executeQuickReplyByName'] !== 'function') {
34903481 throw new Error('t`Quick Reply extension is not loaded'`);
34913482 }
34923483
34933484 try {
@@ -3499,7 +3490,7 @@ async function runCallback(args, name) {
34993490 };
35003491 return await window['executeQuickReplyByName'](name, args, options);
35013492 } catch (error) {
35023493 throw new Error(t`Error running Quick Reply "${name}": ${error.message}`);
35033494 }
35043495}
35053496
@@ -3509,8 +3500,8 @@ async function runCallback(args, name) {
35093500 * @param {string} [reason]
35103501 */
35113502function abortCallback({ _abortController, quiet }, reason) {
35123503 if (quiet instanceof SlashCommandClosure) throw new Error('t`argument \'quiet\' cannot be a closure for command /abort'`);
35133504 _abortController.abort((reason ?? '').toString().length == 0 ? 't`/abort command executed'` : reason, !isFalseBoolean(quiet?.toString() ?? 'true'));
35143505 return '';
35153506}
35163507
@@ -3536,7 +3527,7 @@ async function inputCallback(args, prompt) {
35363527 const popupOptions = {
35373528 large: isTrueBoolean(args?.large),
35383529 wide: isTrueBoolean(args?.wide),
35393530 okButton: args?.okButton !== undefined && typeof args?.okButton === 'string' ? args.okButton : 't`Ok'`,
35403531 rows: args?.rows !== undefined && typeof args?.rows === 'string' ? isNaN(Number(args.rows)) ? 4 : Number(args.rows) : 4,
35413532 };
35423533 // Do not remove this delay, otherwise the prompt will not show up
@@ -3549,7 +3540,7 @@ async function inputCallback(args, prompt) {
35493540 // Veryify if a cancel handler exists and it is valid
35503541 if (args?.onCancel) {
35513542 if (!(args.onCancel instanceof SlashCommandClosure)) {
35523543 throw new Error('t`argument \'onCancel\' must be a closure for command /input'`);
35533544 }
35543545 await args.onCancel.execute();
35553546 }
@@ -3557,7 +3548,7 @@ async function inputCallback(args, prompt) {
35573548 // Verify if an ok handler exists and it is valid
35583549 if (args?.onSuccess) {
35593550 if (!(args.onSuccess instanceof SlashCommandClosure)) {
35603551 throw new Error('t`argument \'onSuccess\' must be a closure for command /input'`);
35613552 }
35623553 await args.onSuccess.execute();
35633554 }
@@ -3705,7 +3696,7 @@ async function generateRawCallback(args, value) {
37053696 return result;
37063697 } catch (err) {
37073698 console.error('Error on /genraw generation', err);
37083699 toastr.error(err.message, 't`API Error'`, { preventDuplicates: true });
37093700 } finally {
37103701 if (lock) {
37113702 activateSendButtons();
@@ -3751,7 +3742,7 @@ async function generateCallback(args, value) {
37513742 return result;
37523743 } catch (err) {
37533744 console.error('Error on /gen generation', err);
37543745 toastr.error(err.message, 't`API Error'`, { preventDuplicates: true });
37553746 } finally {
37563747 if (lock) {
37573748 activateSendButtons();
@@ -3775,7 +3766,7 @@ async function echoCallback(args, value) {
37753766 }
37763767
37773768 if (args.severity && !['error', 'warning', 'success', 'info'].includes(args.severity)) {
37783769 toastr.warning(t`Invalid severity provided for /echo command: ${args.severity}`);
37793770 args.severity = null;
37803771 }
37813772
@@ -3808,7 +3799,7 @@ async function echoCallback(args, value) {
38083799 await args.onClick.execute();
38093800 };
38103801 } else {
38113802 toastr.warning('t`Invalid onClick provided for /echo command. This is not a closure'`);
38123803 }
38133804 }
38143805
@@ -3856,7 +3847,7 @@ async function addSwipeCallback(args, value) {
38563847 const lastMessage = chat[chat.length - 1];
38573848
38583849 if (!lastMessage) {
38593850 toastr.warning('t`No messages to add swipes to.'`);
38603851 return '';
38613852 }
38623853
@@ -3866,17 +3857,17 @@ async function addSwipeCallback(args, value) {
38663857 }
38673858
38683859 if (lastMessage.is_user) {
38693860 toastr.warning('t`Can\'t add swipes to user messages.'`);
38703861 return '';
38713862 }
38723863
38733864 if (lastMessage.is_system) {
38743865 toastr.warning('t`Can\'t add swipes to system messages.'`);
38753866 return '';
38763867 }
38773868
38783869 if (lastMessage.extra?.image) {
38793870 toastr.warning('t`Can\'t add swipes to message containing an image.'`);
38803871 return '';
38813872 }
38823873
@@ -3934,12 +3925,12 @@ async function askCharacter(args, text) {
39343925 // Not supported in group chats
39353926 // TODO: Maybe support group chats?
39363927 if (selected_group) {
39373928 toastr.warning('t`Cannot run /ask command in a group chat!'`);
39383929 return '';
39393930 }
39403931
39413932 if (!args.name) {
39423933 toastr.warning('t`You must specify a name of the character to ask.'`);
39433934 return '';
39443935 }
39453936
@@ -3948,7 +3939,7 @@ async function askCharacter(args, text) {
39483939 // Find the character
39493940 const character = findChar({ name: args?.name });
39503941 if (!character) {
39513942 toastr.error('t`Character not found.'`);
39523943 return '';
39533944 }
39543945
@@ -3995,7 +3986,7 @@ async function askCharacter(args, text) {
39953986 // Run generate and restore previous character
39963987 try {
39973988 eventSource.once(event_types.MESSAGE_RECEIVED, restoreCharacter);
39983989 toastr.info(t`Asking ${name} something...`);
39993990 askResult = await Generate('normal');
40003991 } catch (error) {
40013992 restoreCharacter();
@@ -4004,7 +3995,7 @@ async function askCharacter(args, text) {
40043995 if (String(this_chid) === String(prevChId)) {
40053996 await saveChatConditional();
40063997 } else {
40073998 toastr.error('t`It is strongly recommended to reload the page.'`, 't`Something went wrong'`);
40083999 }
40094000 }
40104001
@@ -4073,7 +4064,7 @@ function performGroupMemberAction(chid, action) {
40734064
40744065async function disableGroupMemberCallback(_, arg) {
40754066 if (!selected_group) {
40764067 toastr.warning('t`Cannot run /member-disable command outside of a group chat.'`);
40774068 return '';
40784069 }
40794070
@@ -4090,7 +4081,7 @@ async function disableGroupMemberCallback(_, arg) {
40904081
40914082async function enableGroupMemberCallback(_, arg) {
40924083 if (!selected_group) {
40934084 toastr.warning('t`Cannot run /member-enable command outside of a group chat.'`);
40944085 return '';
40954086 }
40964087
@@ -4107,7 +4098,7 @@ async function enableGroupMemberCallback(_, arg) {
41074098
41084099async function moveGroupMemberUpCallback(_, arg) {
41094100 if (!selected_group) {
41104101 toastr.warning('t`Cannot run /member-up command outside of a group chat.'`);
41114102 return '';
41124103 }
41134104
@@ -4124,7 +4115,7 @@ async function moveGroupMemberUpCallback(_, arg) {
41244115
41254116async function moveGroupMemberDownCallback(_, arg) {
41264117 if (!selected_group) {
41274118 toastr.warning('t`Cannot run /member-down command outside of a group chat.'`);
41284119 return '';
41294120 }
41304121
@@ -4141,12 +4132,12 @@ async function moveGroupMemberDownCallback(_, arg) {
41414132
41424133async function peekCallback(_, arg) {
41434134 if (!selected_group) {
41444135 toastr.warning('t`Cannot run /member-peek command outside of a group chat.'`);
41454136 return '';
41464137 }
41474138
41484139 if (is_group_generating) {
41494140 toastr.warning('t`Cannot run /member-peek command while the group reply is generating.'`);
41504141 return '';
41514142 }
41524143
@@ -4163,7 +4154,7 @@ async function peekCallback(_, arg) {
41634154
41644155async function countGroupMemberCallback() {
41654156 if (!selected_group) {
41664157 toastr.warning('t`Cannot run /member-count command outside of a group chat.'`);
41674158 return '';
41684159 }
41694160
@@ -4172,7 +4163,7 @@ async function countGroupMemberCallback() {
41724163
41734164async function removeGroupMemberCallback(_, arg) {
41744165 if (!selected_group) {
41754166 toastr.warning('t`Cannot run /member-remove command outside of a group chat.'`);
41764167 return '';
41774168 }
41784169
@@ -4189,7 +4180,7 @@ async function removeGroupMemberCallback(_, arg) {
41894180
41904181async function addGroupMemberCallback(_, name) {
41914182 if (!selected_group) {
41924183 toastr.warning('t`Cannot run /memberadd command outside of a group chat.'`);
41934184 return '';
41944185 }
41954186
@@ -4214,7 +4205,7 @@ async function addGroupMemberCallback(_, name) {
42144205 const avatar = character.avatar;
42154206
42164207 if (group.members.includes(avatar)) {
42174208 toastr.warning(t`${character.name} is already a member of this group.`);
42184209 return '';
42194210 }
42204211
@@ -4233,7 +4224,7 @@ async function triggerGenerationCallback(args, value) {
42334224 await waitUntilCondition(() => !is_send_press && !is_group_generating, 10000, 100);
42344225 } catch {
42354226 console.warn('Timeout waiting for generation unlock');
42364227 toastr.warning('t`Cannot run /trigger command while the reply is being generated.'`);
42374228 outerResolve(Promise.resolve(''));
42384229 return '';
42394230 }
@@ -4338,7 +4329,7 @@ async function deleteMessagesByNameCallback(_, name) {
43384329 await saveChatConditional();
43394330 await reloadCurrentChat();
43404331
43414332 toastr.info(t`Deleted ${messagesToDelete.length} messages from ${name}`);
43424333 return '';
43434334}
43444335
@@ -4382,7 +4373,7 @@ async function continueChatCallback(args, prompt) {
43824373 await waitUntilCondition(() => !is_send_press && !is_group_generating, 10000, 100);
43834374 } catch {
43844375 console.warn('Timeout waiting for generation unlock');
43854376 toastr.warning('t`Cannot run /continue command while the reply is being generated.'`);
43864377 return reject();
43874378 }
43884379
@@ -4412,14 +4403,14 @@ export async function generateSystemMessage(args, prompt) {
44124403
44134404 if (!prompt) {
44144405 console.warn('WARN: No prompt provided for /sysgen command');
44154406 toastr.warning('t`You must provide a prompt for the system message'`);
44164407 return '';
44174408 }
44184409
44194410 const trim = isTrueBoolean(args?.trim?.toString());
44204411
44214412 // Generate and regex the output if applicable
44224413 const toast = toastr.info('t`Please wait'`, 't`Generating...'`);
44234414 const message = await generateQuietPrompt({ quietPrompt: prompt, trimToSentence: trim });
44244415 toastr.clear(toast);
44254416
@@ -4444,7 +4435,7 @@ function setFlatModeCallback() {
44444435async function setNarratorName(_, text) {
44454436 const name = text || NARRATOR_NAME_DEFAULT;
44464437 chat_metadata[NARRATOR_NAME_KEY] = name;
44474438 toastr.info(t`System narrator name set to ${name}`);
44484439 await saveChatConditional();
44494440 return '';
44504441}
@@ -4461,10 +4452,10 @@ async function setNarratorName(_, text) {
44614452export function validateArrayArgString(arg, name, { allowUndefined = true } = {}) {
44624453 if (arg === undefined) {
44634454 if (allowUndefined) return undefined;
44644455 throw new Error(t`Argument "${name}" is undefined, but must be a string array`);
44654456 }
44664457 if (!Array.isArray(arg)) throw new Error(t`Argument "${name}" must be an array`);
44674458 if (!arg.every(x => typeof x === 'string')) throw new Error(t`Argument "${name}" must be an array of strings`);
44684459 return arg;
44694460}
44704461
@@ -4480,10 +4471,10 @@ export function validateArrayArgString(arg, name, { allowUndefined = true } = {}
44804471export function validateArrayArg(arg, name, { allowUndefined = true } = {}) {
44814472 if (arg === undefined) {
44824473 if (allowUndefined) return [];
44834474 throw new Error(t`Argument "${name}" is undefined, but must be an array of strings or closures`);
44844475 }
44854476 if (!Array.isArray(arg)) throw new Error(t`Argument "${name}" must be an array`);
44864477 if (!arg.every(x => typeof x === 'string' || x instanceof SlashCommandClosure)) throw new Error(t`Argument "${name}" must be an array of strings or closures`);
44874478 return arg;
44884479}
44894480
@@ -4528,7 +4519,7 @@ export async function sendMessageAs(args, text) {
45284519 if (!name) {
45294520 const namelessWarningKey = 'sendAsNamelessWarningShown';
45304521 if (accountStorage.getItem(namelessWarningKey) !== 'true') {
45314522 toastr.warning('t`To avoid confusion, please use /sendas name="Character Name"'`, 't`Name defaulted to {{char}}'`, { timeOut: 10000 });
45324523 accountStorage.setItem(namelessWarningKey, 'true');
45334524 }
45344525 name = name2;
@@ -4548,7 +4539,7 @@ export async function sendMessageAs(args, text) {
45484539
45494540 const avatarCharacter = args.avatar ? findChar({ name: args.avatar }) : character;
45504541 if (args.avatar && !avatarCharacter) {
45514542 toastr.warning(t`Character for avatar ${args.avatar} not found`);
45524543 return '';
45534544 }
45544545
@@ -4805,7 +4796,7 @@ function setBackgroundCallback(_, bg) {
48054796 const result = fuse.search(bg);
48064797
48074798 if (!result.length) {
48084799 toastr.error(t`No background found with name "${bg}"`);
48094800 return '';
48104801 }
48114802
@@ -4877,14 +4868,14 @@ function getModelOptions(quiet) {
48774868 const modelSelectItem = modelSelectMap.find(x => x.api == main_api && x.type == apiSubType)?.id;
48784869
48794870 if (!modelSelectItem) {
48804871 !quiet && toastr.info('t`Setting a model for your API is not supported or not implemented yet.'`);
48814872 return nullResult;
48824873 }
48834874
48844875 const modelSelectControl = document.getElementById(modelSelectItem);
48854876
48864877 if (!(modelSelectControl instanceof HTMLSelectElement) && !(modelSelectControl instanceof HTMLInputElement)) {
48874878 !quiet && toastr.error(t`Model select control not found: ${main_api}[${apiSubType}]`);
48884879 return nullResult;
48894880 }
48904881
@@ -4937,12 +4928,12 @@ function modelCallback(args, model) {
49374928 if (modelSelectControl instanceof HTMLInputElement) {
49384929 modelSelectControl.value = model;
49394930 $(modelSelectControl).trigger('input');
49404931 !quiet && toastr.success(t`Model set to "${model}"`);
49414932 return model;
49424933 }
49434934
49444935 if (!options.length) {
49454936 !quiet && toastr.warning('t`No model options found. Check your API settings.'`);
49464937 return '';
49474938 }
49484939
@@ -4965,10 +4956,10 @@ function modelCallback(args, model) {
49654956 if (newSelectedOption) {
49664957 modelSelectControl.value = newSelectedOption.value;
49674958 $(modelSelectControl).trigger('change');
49684959 !quiet && toastr.success(t`Model set to "${newSelectedOption.text}"`);
49694960 return newSelectedOption.value;
49704961 } else {
49714962 !quiet && toastr.warning(t`No model found with name "${model}"`);
49724963 return '';
49734964 }
49744965}
@@ -5149,7 +5140,7 @@ async function setApiUrlCallback({ api = null, connect = 'true', quiet = 'false'
51495140 }
51505141
51515142 if (!isCurrentlyCustomOpenai && autoConnect) {
51525143 toastr.warning('t`Custom OpenAI API is not the currently selected API, so we cannot do an auto-connect. Consider switching to it via /api beforehand.'`);
51535144 return '';
51545145 }
51555146
@@ -5170,7 +5161,7 @@ async function setApiUrlCallback({ api = null, connect = 'true', quiet = 'false'
51705161 }
51715162
51725163 if (!isCurrentlyKoboldClassic && autoConnect) {
51735164 toastr.warning('t`Kobold Classic API is not the currently selected API, so we cannot do an auto-connect. Consider switching to it via /api beforehand.'`);
51745165 return '';
51755166 }
51765167
@@ -5187,26 +5178,26 @@ async function setApiUrlCallback({ api = null, connect = 'true', quiet = 'false'
51875178
51885179 // Do some checks and get the api type we are targeting with this command
51895180 if (api && !Object.values(textgen_types).includes(api)) {
51905181 !isQuiet && toastr.warning(t`API '${api}' is not a valid text_gen API.`);
51915182 return '';
51925183 }
51935184 if (!api && !Object.values(textgen_types).includes(textgenerationwebui_settings.type)) {
51945185 !isQuiet && toastr.warning(t`API '${textgenerationwebui_settings.type}' is not a valid text_gen API.`);
51955186 return '';
51965187 }
51975188 if (!api && main_api !== 'textgenerationwebui') {
51985189 !isQuiet && toastr.warning(t`API type '${main_api}' does not support setting the server URL.`);
51995190 return '';
52005191 }
52015192 if (api && url && autoConnect && api !== textgenerationwebui_settings.type) {
52025193 !isQuiet && toastr.warning(t`API '${api}' is not the currently selected API, so we cannot do an auto-connect. Consider switching to it via /api beforehand.`);
52035194 return '';
52045195 }
52055196 const type = api || textgenerationwebui_settings.type;
52065197
52075198 const inputSelector = SERVER_INPUTS[type];
52085199 if (!inputSelector) {
52095200 !isQuiet && toastr.warning(t`API '${type}' does not have a server url input.`);
52105201 return '';
52115202 }
52125203
@@ -5239,7 +5230,7 @@ async function selectTokenizerCallback(_, name) {
52395230 const result = fuse.search(name);
52405231
52415232 if (result.length === 0) {
52425233 toastr.warning(t`Tokenizer "${name}" not found`);
52435234 return '';
52445235 }
52455236
@@ -5398,20 +5389,20 @@ export async function executeSlashCommandsOnChatInput(text, options = {}) {
53985389 document.querySelector('#form_sheld').classList.add('script_error');
53995390 result = new SlashCommandClosureResult();
54005391 result.isError = true;
54015392 result.errorMessage = e.message || 't`An unknown error occurred'`;
54025393 if (e.cause !== 'abort') {
54035394 if (e instanceof SlashCommandExecutionError) {
54045395 /**@type {SlashCommandExecutionError}*/
54055396 const ex = e;
54065397 const toast = `
54075398 <div>${ex.message}</div>
54085399 <div>${t`Line`}: ${ex.line} ${t`Column`}: ${ex.column}</div>
54095400 <pre style="text-align:left;">${ex.hint}</pre>
54105401 `;
54115402 const clickHint = '`<p>${t`Click to see details`}</p>'`;
54125403 toastr.error(
54135404 `${toast}${clickHint}`,
54145405 'SlashCommandExecutionErrorSlash Command Execution Error',
54155406 { escapeHtml: false, timeOut: 10000, onclick: () => callGenericPopup(toast, POPUP_TYPE.TEXT, '', { allowHorizontalScrolling: true, allowVerticalScrolling: true }) },
54165407 );
54175408 } else {
@@ -5462,10 +5453,10 @@ async function executeSlashCommandsWithOptions(text, options = {}) {
54625453 const ex = e;
54635454 const toast = `
54645455 <div>${ex.message}</div>
54655456 <div>${t`Line`}: ${ex.line} ${t`Column`}: ${ex.column}</div>
54665457 <pre style="text-align:left;">${ex.hint}</pre>
54675458 `;
54685459 const clickHint = '`<p>${t`Click to see details`}</p>'`;
54695460 toastr.error(
54705461 `${toast}${clickHint}`,
54715462 'SlashCommandParserError',
@@ -5481,7 +5472,7 @@ async function executeSlashCommandsWithOptions(text, options = {}) {
54815472 try {
54825473 const result = await closure.execute();
54835474 if (result.isAborted && !result.isQuietlyAborted) {
54845475 toastr.warning(result.abortReason, 't`Command execution aborted'`);
54855476 closure.abortController.signal.isQuiet = true;
54865477 }
54875478 return result;
public/scripts/slash-commands/SlashCommand.js+14 -15
@@ -7,13 +7,12 @@ import { SlashCommandDebugController } from './SlashCommandDebugController.js';
77import { SlashCommandScope } from './SlashCommandScope.js';
88
99/**
1010 * @typedef {NamedArgumentsCapture & {
1111 * _scope:SlashCommandScope,
1212 * _parserFlags:import('./SlashCommandParser.js').ParserFlags,
1313 * _abortController:SlashCommandAbortController,
1414 * _debugController:SlashCommandDebugController,
1515 * _hasUnnamedArgument:boolean,
16- * [id:string]:string|SlashCommandClosure|(string|SlashCommandClosure)[]|undefined,
1716 * }} NamedArguments
1817 */
1918
@@ -52,7 +51,7 @@ export class SlashCommand {
5251
5352
5453 /**@type {string}*/ name;
5554 /**@type {(namedArguments:{_scope:SlashCommandScope, _abortController:SlashCommandAbortController, [id:string]:string|SlashCommandClosure}NamedArguments, unnamedArguments:string|SlashCommandClosure|(string|SlashCommandClosure)[]UnnamedArguments)=>string|SlashCommandClosure|Promise<string|SlashCommandClosure>}*/ callback;
5655 /**@type {string}*/ helpString;
5756 /**@type {boolean}*/ splitUnnamedArgument = false;
5857 /**@type {Number}*/ splitUnnamedArgumentCount;
@@ -238,7 +237,7 @@ export class SlashCommand {
238237 const name = document.createElement('div'); {
239238 name.classList.add('name');
240239 name.classList.add('monospace');
241240 name.title = 'commandt`Command name'`;
242241 name.textContent = `/${key}`;
243242 head.append(name);
244243 }
@@ -284,19 +283,19 @@ export class SlashCommand {
284283 const argItem = document.createElement('div'); {
285284 argItem.classList.add('argument');
286285 argItem.classList.add('namedArgument');
287286 argItem.title = `${arg.isRequired ? ''t`Named argument` : 'optionalt`Optional '}named argument`;
288287 if (!arg.isRequired || (arg.defaultValue ?? false)) argItem.classList.add('optional');
289288 if (arg.acceptsMultiple) argItem.classList.add('multiple');
290289 const name = document.createElement('span'); {
291290 name.classList.add('argument-name');
292291 name.title = t`${argItem.title} - nameName`;
293292 name.textContent = arg.name;
294293 argItem.append(name);
295294 }
296295 if (arg.enumList.length > 0) {
297296 const enums = document.createElement('span'); {
298297 enums.classList.add('argument-enums');
299298 enums.title = t`${argItem.title} - acceptedAccepted values`;
300299 for (const e of arg.enumList) {
301300 const enumItem = document.createElement('span'); {
302301 enumItem.classList.add('argument-enum');
@@ -309,7 +308,7 @@ export class SlashCommand {
309308 } else {
310309 const types = document.createElement('span'); {
311310 types.classList.add('argument-types');
312311 types.title = t`${argItem.title} - acceptedAccepted types`;
313312 for (const t of arg.typeList) {
314313 const type = document.createElement('span'); {
315314 type.classList.add('argument-type');
@@ -325,7 +324,7 @@ export class SlashCommand {
325324 if (arg.defaultValue !== null) {
326325 const argDefault = document.createElement('div'); {
327326 argDefault.classList.add('argument-default');
328327 argDefault.title = 'defaultt`Default value'`;
329328 argDefault.textContent = arg.defaultValue.toString();
330329 argSpec.append(argDefault);
331330 }
@@ -348,13 +347,13 @@ export class SlashCommand {
348347 const argItem = document.createElement('div'); {
349348 argItem.classList.add('argument');
350349 argItem.classList.add('unnamedArgument');
351350 argItem.title = `${arg.isRequired ? ''t`Unnamed argument` : 'optionalt`Optional '}unnamed argument`;
352351 if (!arg.isRequired || (arg.defaultValue ?? false)) argItem.classList.add('optional');
353352 if (arg.acceptsMultiple) argItem.classList.add('multiple');
354353 if (arg.enumList.length > 0) {
355354 const enums = document.createElement('span'); {
356355 enums.classList.add('argument-enums');
357356 enums.title = t`${argItem.title} - acceptedAccepted values`;
358357 for (const e of arg.enumList) {
359358 const enumItem = document.createElement('span'); {
360359 enumItem.classList.add('argument-enum');
@@ -367,7 +366,7 @@ export class SlashCommand {
367366 } else {
368367 const types = document.createElement('span'); {
369368 types.classList.add('argument-types');
370369 types.title = t`${argItem.title} - acceptedAccepted types`;
371370 for (const t of arg.typeList) {
372371 const type = document.createElement('span'); {
373372 type.classList.add('argument-type');
@@ -383,7 +382,7 @@ export class SlashCommand {
383382 if (arg.defaultValue !== null) {
384383 const argDefault = document.createElement('div'); {
385384 argDefault.classList.add('argument-default');
386385 argDefault.title = 'defaultt`Default value'`;
387386 argDefault.textContent = arg.defaultValue.toString();
388387 argSpec.append(argDefault);
389388 }
@@ -402,7 +401,7 @@ export class SlashCommand {
402401 }
403402 const returns = document.createElement('span'); {
404403 returns.classList.add('returns');
405404 returns.title = [null, undefined, 'void'].includes(returnType) ? 'commandt`Command does not return anything'` : 'returnt`Return value'`;
406405 returns.textContent = returnType ?? 'void';
407406 body.append(returns);
408407 }
@@ -415,7 +414,7 @@ export class SlashCommand {
415414 help.innerHTML = helpString;
416415 for (const code of help.querySelectorAll('pre > code')) {
417416 code.classList.add('language-stscript');
418417 hljs.highlightElement(/**@type {HTMLElement}*/(code));
419418 }
420419 frag.append(help);
421420 }