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, +516 -526Showing whitespace changes
public/scripts/slash-commands.js+502 -511
@@ -229,7 +229,7 @@ export function initDefaultSlashCommands() {
229 SlashCommandParser.addCommandObject(SlashCommand.fromProps({229 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
230 name: 'dupe',230 name: 'dupe',
231 callback: duplicateCharacter,231 callback: duplicateCharacter,
232 helpString: 'Duplicates the currently selected character.',232 helpString: t`Duplicates the currently selected character.`,
233 }));233 }));
234 SlashCommandParser.addCommandObject(SlashCommand.fromProps({234 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
235 name: 'api',235 name: 'api',
@@ -306,11 +306,11 @@ export function initDefaultSlashCommands() {
306 toastr.clear(toast);306 toastr.clear(toast);
307 return text?.toString()?.trim() ?? '';307 return text?.toString()?.trim() ?? '';
308 },308 },
309 returns: 'the current API',309 returns: t`the current API`,
310 namedArgumentList: [310 namedArgumentList: [
311 SlashCommandNamedArgument.fromProps({311 SlashCommandNamedArgument.fromProps({
312 name: 'quiet',312 name: 'quiet',
313 description: 'Suppress the toast message on connection',313 description: t`Suppress the toast message on connection`,
314 typeList: [ARGUMENT_TYPE.BOOLEAN],314 typeList: [ARGUMENT_TYPE.BOOLEAN],
315 defaultValue: 'false',315 defaultValue: 'false',
316 enumList: commonEnumProviders.boolean('trueFalse')(),316 enumList: commonEnumProviders.boolean('trueFalse')(),
@@ -318,7 +318,7 @@ export function initDefaultSlashCommands() {
318 ],318 ],
319 unnamedArgumentList: [319 unnamedArgumentList: [
320 SlashCommandArgument.fromProps({320 SlashCommandArgument.fromProps({
321 description: 'API to connect to',321 description: t`API to connect to`,
322 typeList: [ARGUMENT_TYPE.STRING],322 typeList: [ARGUMENT_TYPE.STRING],
323 enumList: Object.entries(CONNECT_API_MAP).sort(([a], [b]) => a.localeCompare(b)).map(([api, { selected }]) =>323 enumList: Object.entries(CONNECT_API_MAP).sort(([a], [b]) => a.localeCompare(b)).map(([api, { selected }]) =>
324 new SlashCommandEnumValue(api, selected, enumTypes.getBasedOnIndex(UNIQUE_APIS.findIndex(x => x === selected)),324 new SlashCommandEnumValue(api, selected, enumTypes.getBasedOnIndex(UNIQUE_APIS.findIndex(x => x === selected)),
@@ -327,10 +327,10 @@ export function initDefaultSlashCommands() {
327 ],327 ],
328 helpString: `328 helpString: `
329 <div>329 <div>
330 Connect to an API. If no argument is provided, it will return the currently connected API.330 ${t`Connect to an API. If no argument is provided, it will return the currently connected API.`}
331 </div>331 </div>
332 <div>332 <div>
333 <strong>Available APIs:</strong>333 <strong>${t`Available APIs:`}</strong>
334 <pre><code>${Object.keys(CONNECT_API_MAP).sort((a, b) => a.localeCompare(b)).join(', ')}</code></pre>334 <pre><code>${Object.keys(CONNECT_API_MAP).sort((a, b) => a.localeCompare(b)).join(', ')}</code></pre>
335 </div>335 </div>
336 `,336 `,
@@ -367,7 +367,7 @@ export function initDefaultSlashCommands() {
367 namedArgumentList: [367 namedArgumentList: [
368 new SlashCommandNamedArgument(368 new SlashCommandNamedArgument(
369 'await',369 'await',
370 'Whether to await for the triggered generation before continuing',370 t`Whether to await for the triggered generation before continuing`,
371 [ARGUMENT_TYPE.BOOLEAN],371 [ARGUMENT_TYPE.BOOLEAN],
372 false,372 false,
373 false,373 false,
@@ -381,13 +381,13 @@ export function initDefaultSlashCommands() {
381 ],381 ],
382 helpString: `382 helpString: `
383 <div>383 <div>
384 Calls an impersonation response, with an optional additional prompt.384 ${t`Calls an impersonation response, with an optional additional prompt.`}
385 </div>385 </div>
386 <div>386 <div>
387 If <code>await=true</code> named argument is passed, the command will wait for the impersonation to end before continuing.387 ${t`If <code>await=true</code> named argument is passed, the command will wait for the impersonation to end before continuing.`}
388 </div>388 </div>
389 <div>389 <div>
390 <strong>Example:</strong>390 <strong>${t`Example:`}</strong>
391 <ul>391 <ul>
392 <li>392 <li>
393 <pre><code class="language-stscript">/impersonate What is the meaning of life?</code></pre>393 <pre><code class="language-stscript">/impersonate What is the meaning of life?</code></pre>
@@ -426,7 +426,7 @@ export function initDefaultSlashCommands() {
426 $(currentChatDeleteButton).trigger('click', { fromSlashCommand: true });426 $(currentChatDeleteButton).trigger('click', { fromSlashCommand: true });
427 }));427 }));
428 },428 },
429 helpString: 'Deletes the current chat.',429 helpString: t`Deletes the current chat.`,
430 }));430 }));
431 SlashCommandParser.addCommandObject(SlashCommand.fromProps({431 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
432 name: 'renamechat',432 name: 'renamechat',
@@ -449,18 +449,18 @@ export function initDefaultSlashCommands() {
449 },449 },
450 unnamedArgumentList: [450 unnamedArgumentList: [
451 new SlashCommandArgument(451 new SlashCommandArgument(
452 'new chat name', [ARGUMENT_TYPE.STRING], true,452 t`new chat name`, [ARGUMENT_TYPE.STRING], true,
453 ),453 ),
454 ],454 ],
455 helpString: 'Renames the current chat.',455 helpString: t`Renames the current chat.`,
456 }));456 }));
457 SlashCommandParser.addCommandObject(SlashCommand.fromProps({457 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
458 name: 'getchatname',458 name: 'getchatname',
459 callback: async function doGetChatName() {459 callback: async function doGetChatName() {
460 return getCurrentChatDetails().sessionName;460 return getCurrentChatDetails().sessionName;
461 },461 },
462 returns: 'chat file name',462 returns: t`chat file name`,
463 helpString: 'Returns the name of the current chat file into the pipe.',463 helpString: t`Returns the name of the current chat file into the pipe.`,
464 }));464 }));
465 SlashCommandParser.addCommandObject(SlashCommand.fromProps({465 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
466 name: 'closechat',466 name: 'closechat',
@@ -468,7 +468,7 @@ export function initDefaultSlashCommands() {
468 $('#option_close_chat').trigger('click');468 $('#option_close_chat').trigger('click');
469 return '';469 return '';
470 },470 },
471 helpString: 'Closes the current chat.',471 helpString: t`Closes the current chat.`,
472 }));472 }));
473 SlashCommandParser.addCommandObject(SlashCommand.fromProps({473 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
474 name: 'tempchat',474 name: 'tempchat',
@@ -476,7 +476,7 @@ export function initDefaultSlashCommands() {
476 return new Promise((resolve, reject) => {476 return new Promise((resolve, reject) => {
477 const eventCallback = async (chatId) => {477 const eventCallback = async (chatId) => {
478 if (chatId) {478 if (chatId) {
479 return reject('Not in a temporary chat');479 return reject(t`Not in a temporary chat`);
480 }480 }
481 await newAssistantChat({ temporary: true });481 await newAssistantChat({ temporary: true });
482 return resolve('');482 return resolve('');
@@ -484,12 +484,12 @@ export function initDefaultSlashCommands() {
484 eventSource.once(event_types.CHAT_CHANGED, eventCallback);484 eventSource.once(event_types.CHAT_CHANGED, eventCallback);
485 $('#option_close_chat').trigger('click');485 $('#option_close_chat').trigger('click');
486 setTimeout(() => {486 setTimeout(() => {
487 reject('Failed to open temporary chat');487 reject(t`Failed to open temporary chat`);
488 eventSource.removeListener(event_types.CHAT_CHANGED, eventCallback);488 eventSource.removeListener(event_types.CHAT_CHANGED, eventCallback);
489 }, debounce_timeout.relaxed);489 }, debounce_timeout.relaxed);
490 });490 });
491 },491 },
492 helpString: 'Opens a temporary chat with Assistant.',492 helpString: t`Opens a temporary chat with Assistant.`,
493 }));493 }));
494 SlashCommandParser.addCommandObject(SlashCommand.fromProps({494 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
495 name: 'panels',495 name: 'panels',
@@ -498,17 +498,17 @@ export function initDefaultSlashCommands() {
498 return '';498 return '';
499 },499 },
500 aliases: ['togglepanels'],500 aliases: ['togglepanels'],
501 helpString: 'Toggle UI panels on/off',501 helpString: t`Toggle UI panels on/off`,
502 }));502 }));
503 SlashCommandParser.addCommandObject(SlashCommand.fromProps({503 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
504 name: 'forcesave',504 name: 'forcesave',
505 callback: async function () {505 callback: async function () {
506 await saveSettings();506 await saveSettings();
507 await saveChatConditional();507 await saveChatConditional();
508 toastr.success('Chat and settings saved.');508 toastr.success(t`Chat and settings saved.`);
509 return '';509 return '';
510 },510 },
511 helpString: 'Forces a save of the current chat and settings',511 helpString: t`Forces a save of the current chat and settings`,
512 }));512 }));
513 SlashCommandParser.addCommandObject(SlashCommand.fromProps({513 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
514 name: 'instruct',514 name: 'instruct',
@@ -531,18 +531,18 @@ export function initDefaultSlashCommands() {
531 selectInstructPreset(foundName, { quiet: quiet });531 selectInstructPreset(foundName, { quiet: quiet });
532 return foundName;532 return foundName;
533 },533 },
534 returns: 'current template',534 returns: t`current template`,
535 namedArgumentList: [535 namedArgumentList: [
536 SlashCommandNamedArgument.fromProps({536 SlashCommandNamedArgument.fromProps({
537 name: 'quiet',537 name: 'quiet',
538 description: 'Suppress the toast message on template change',538 description: t`Suppress the toast message on template change`,
539 typeList: [ARGUMENT_TYPE.BOOLEAN],539 typeList: [ARGUMENT_TYPE.BOOLEAN],
540 defaultValue: 'false',540 defaultValue: 'false',
541 enumList: commonEnumProviders.boolean('trueFalse')(),541 enumList: commonEnumProviders.boolean('trueFalse')(),
542 }),542 }),
543 SlashCommandNamedArgument.fromProps({543 SlashCommandNamedArgument.fromProps({
544 name: 'forceGet',544 name: 'forceGet',
545 description: 'Force getting a name even if instruct mode is disabled',545 description: t`Force getting a name even if instruct mode is disabled`,
546 typeList: [ARGUMENT_TYPE.BOOLEAN],546 typeList: [ARGUMENT_TYPE.BOOLEAN],
547 defaultValue: 'false',547 defaultValue: 'false',
548 enumList: commonEnumProviders.boolean('trueFalse')(),548 enumList: commonEnumProviders.boolean('trueFalse')(),
@@ -550,18 +550,18 @@ export function initDefaultSlashCommands() {
550 ],550 ],
551 unnamedArgumentList: [551 unnamedArgumentList: [
552 SlashCommandArgument.fromProps({552 SlashCommandArgument.fromProps({
553 description: 'instruct template name',553 description: t`instruct template name`,
554 typeList: [ARGUMENT_TYPE.STRING],554 typeList: [ARGUMENT_TYPE.STRING],
555 enumProvider: () => instruct_presets.map(preset => new SlashCommandEnumValue(preset.name, null, enumTypes.enum, enumIcons.preset)),555 enumProvider: () => instruct_presets.map(preset => new SlashCommandEnumValue(preset.name, null, enumTypes.enum, enumIcons.preset)),
556 }),556 }),
557 ],557 ],
558 helpString: `558 helpString: `
559 <div>559 <div>
560 Selects instruct mode template by name. Enables instruct mode if not already enabled.560 ${t`Selects instruct mode template by name. Enables instruct mode if not already enabled.`}
561 Gets the current instruct template if no name is provided and instruct mode is enabled or <code>forceGet=true</code> is passed.561 ${t`Gets the current instruct template if no name is provided and instruct mode is enabled or <code>forceGet=true</code> is passed.`}
562 </div>562 </div>
563 <div>563 <div>
564 <strong>Example:</strong>564 <strong>${t`Example:`}</strong>
565 <ul>565 <ul>
566 <li>566 <li>
567 <pre><code class="language-stscript">/instruct creative</code></pre>567 <pre><code class="language-stscript">/instruct creative</code></pre>
@@ -573,20 +573,20 @@ export function initDefaultSlashCommands() {
573 SlashCommandParser.addCommandObject(SlashCommand.fromProps({573 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
574 name: 'instruct-on',574 name: 'instruct-on',
575 callback: enableInstructCallback,575 callback: enableInstructCallback,
576 helpString: 'Enables instruct mode.',576 helpString: t`Enables instruct mode.`,
577 }));577 }));
578 SlashCommandParser.addCommandObject(SlashCommand.fromProps({578 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
579 name: 'instruct-off',579 name: 'instruct-off',
580 callback: disableInstructCallback,580 callback: disableInstructCallback,
581 helpString: 'Disables instruct mode',581 helpString: t`Disables instruct mode`,
582 }));582 }));
583 SlashCommandParser.addCommandObject(SlashCommand.fromProps({583 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
584 name: 'instruct-state',584 name: 'instruct-state',
585 aliases: ['instruct-toggle'],585 aliases: ['instruct-toggle'],
586 helpString: 'Gets the current instruct mode state. If an argument is provided, it will set the instruct mode state.',586 helpString: t`Gets the current instruct mode state. If an argument is provided, it will set the instruct mode state.`,
587 unnamedArgumentList: [587 unnamedArgumentList: [
588 SlashCommandArgument.fromProps({588 SlashCommandArgument.fromProps({
589 description: 'instruct mode state',589 description: t`instruct mode state`,
590 typeList: [ARGUMENT_TYPE.BOOLEAN],590 typeList: [ARGUMENT_TYPE.BOOLEAN],
591 enumList: commonEnumProviders.boolean('trueFalse')(),591 enumList: commonEnumProviders.boolean('trueFalse')(),
592 }),592 }),
@@ -622,11 +622,11 @@ export function initDefaultSlashCommands() {
622 selectContextPreset(foundName, { quiet: quiet });622 selectContextPreset(foundName, { quiet: quiet });
623 return foundName;623 return foundName;
624 },624 },
625 returns: 'template name',625 returns: t`template name`,
626 namedArgumentList: [626 namedArgumentList: [
627 SlashCommandNamedArgument.fromProps({627 SlashCommandNamedArgument.fromProps({
628 name: 'quiet',628 name: 'quiet',
629 description: 'Suppress the toast message on template change',629 description: t`Suppress the toast message on template change`,
630 typeList: [ARGUMENT_TYPE.BOOLEAN],630 typeList: [ARGUMENT_TYPE.BOOLEAN],
631 defaultValue: 'false',631 defaultValue: 'false',
632 enumList: commonEnumProviders.boolean('trueFalse')(),632 enumList: commonEnumProviders.boolean('trueFalse')(),
@@ -634,12 +634,12 @@ export function initDefaultSlashCommands() {
634 ],634 ],
635 unnamedArgumentList: [635 unnamedArgumentList: [
636 SlashCommandArgument.fromProps({636 SlashCommandArgument.fromProps({
637 description: 'context template name',637 description: t`context template name`,
638 typeList: [ARGUMENT_TYPE.STRING],638 typeList: [ARGUMENT_TYPE.STRING],
639 enumProvider: () => context_presets.map(preset => new SlashCommandEnumValue(preset.name, null, enumTypes.enum, enumIcons.preset)),639 enumProvider: () => context_presets.map(preset => new SlashCommandEnumValue(preset.name, null, enumTypes.enum, enumIcons.preset)),
640 }),640 }),
641 ],641 ],
642 helpString: 'Selects context template by name. Gets the current template if no name is provided',642 helpString: t`Selects context template by name. Gets the current template if no name is provided`,
643 }));643 }));
644 SlashCommandParser.addCommandObject(SlashCommand.fromProps({644 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
645 name: 'chat-manager',645 name: 'chat-manager',
@@ -648,32 +648,32 @@ export function initDefaultSlashCommands() {
648 return '';648 return '';
649 },649 },
650 aliases: ['chat-history', 'manage-chats'],650 aliases: ['chat-history', 'manage-chats'],
651 helpString: 'Opens the chat manager for the current character/group.',651 helpString: t`Opens the chat manager for the current character/group.`,
652 }));652 }));
653 SlashCommandParser.addCommandObject(SlashCommand.fromProps({653 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
654 name: '?',654 name: '?',
655 callback: helpCommandCallback,655 callback: helpCommandCallback,
656 aliases: ['help'],656 aliases: ['help'],
657 unnamedArgumentList: [SlashCommandArgument.fromProps({657 unnamedArgumentList: [SlashCommandArgument.fromProps({
658 description: 'help topic',658 description: t`help topic`,
659 typeList: [ARGUMENT_TYPE.STRING],659 typeList: [ARGUMENT_TYPE.STRING],
660 enumList: [660 enumList: [
661 new SlashCommandEnumValue('slash', 'slash commands (STscript)', enumTypes.command, '/'),661 new SlashCommandEnumValue('slash', t`slash commands (STscript)`, enumTypes.command, '/'),
662 new SlashCommandEnumValue('macros', '{{macros}} (text replacement)', enumTypes.macro, enumIcons.macro),662 new SlashCommandEnumValue('macros', t`{{macros}} (text replacement)`, enumTypes.macro, enumIcons.macro),
663 new SlashCommandEnumValue('format', 'chat/text formatting', enumTypes.name, '★'),663 new SlashCommandEnumValue('format', t`chat/text formatting`, enumTypes.name, '★'),
664 new SlashCommandEnumValue('hotkeys', 'keyboard shortcuts', enumTypes.enum, '⏎'),664 new SlashCommandEnumValue('hotkeys', t`keyboard shortcuts`, enumTypes.enum, '⏎'),
665 ],665 ],
666 })],666 })],
667 helpString: 'Get help on macros, chat formatting and commands.',667 helpString: t`Get help on macros, chat formatting and commands.`,
668 }));668 }));
669 SlashCommandParser.addCommandObject(SlashCommand.fromProps({669 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
670 name: 'bg',670 name: 'bg',
671 callback: setBackgroundCallback,671 callback: setBackgroundCallback,
672 aliases: ['background'],672 aliases: ['background'],
673 returns: 'the current background',673 returns: t`the current background`,
674 unnamedArgumentList: [674 unnamedArgumentList: [
675 SlashCommandArgument.fromProps({675 SlashCommandArgument.fromProps({
676 description: 'background filename',676 description: t`background filename`,
677 typeList: [ARGUMENT_TYPE.STRING],677 typeList: [ARGUMENT_TYPE.STRING],
678 enumProvider: () => [...document.querySelectorAll('.bg_example')]678 enumProvider: () => [...document.querySelectorAll('.bg_example')]
679 .map(it => new SlashCommandEnumValue(it.getAttribute('bgfile')))679 .map(it => new SlashCommandEnumValue(it.getAttribute('bgfile')))
@@ -682,13 +682,13 @@ export function initDefaultSlashCommands() {
682 ],682 ],
683 helpString: `683 helpString: `
684 <div>684 <div>
685 Sets a background according to the provided filename. Partial names allowed.685 ${t`Sets a background according to the provided filename. Partial names allowed.`}
686 </div>686 </div>
687 <div>687 <div>
688 If no background is provided, this will return the currently selected background.688 ${t`If no background is provided, this will return the currently selected background.`}
689 </div>689 </div>
690 <div>690 <div>
691 <strong>Example:</strong>691 <strong>${t`Example:`}</strong>
692 <ul>692 <ul>
693 <li>693 <li>
694 <pre><code>/bg beach.jpg</code></pre>694 <pre><code>/bg beach.jpg</code></pre>
@@ -704,31 +704,31 @@ export function initDefaultSlashCommands() {
704 name: 'char-find',704 name: 'char-find',
705 aliases: ['findchar'],705 aliases: ['findchar'],
706 callback: (args, name) => {706 callback: (args, name) => {
707 if (typeof name !== 'string') throw new Error('name must be a string');707 if (typeof name !== 'string') throw new Error(t`name must be a string`);
708 if (args.preferCurrent instanceof SlashCommandClosure || Array.isArray(args.preferCurrent)) throw new Error('preferCurrent cannot be a closure or array');708 if (args.preferCurrent instanceof SlashCommandClosure || Array.isArray(args.preferCurrent)) throw new Error(t`preferCurrent cannot be a closure or array`);
709 if (args.quiet instanceof SlashCommandClosure || Array.isArray(args.quiet)) throw new Error('quiet cannot be a closure or array');709 if (args.quiet instanceof SlashCommandClosure || Array.isArray(args.quiet)) throw new Error(t`quiet cannot be a closure or array`);
710710
711 const char = findChar({ name: name, filteredByTags: validateArrayArgString(args.tag, 'tag'), preferCurrentChar: !isFalseBoolean(args.preferCurrent), quiet: isTrueBoolean(args.quiet) });711 const char = findChar({ name: name, filteredByTags: validateArrayArgString(args.tag, 'tag'), preferCurrentChar: !isFalseBoolean(args.preferCurrent), quiet: isTrueBoolean(args.quiet) });
712 return char?.avatar ?? '';712 return char?.avatar ?? '';
713 },713 },
714 returns: 'the avatar key (unique identifier) of the character',714 returns: t`the avatar key (unique identifier) of the character`,
715 namedArgumentList: [715 namedArgumentList: [
716 SlashCommandNamedArgument.fromProps({716 SlashCommandNamedArgument.fromProps({
717 name: 'tag',717 name: 'tag',
718 description: 'Supply one or more tags to filter down to the correct character for the provided name, if multiple characters have the same name.',718 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.`,
719 typeList: [ARGUMENT_TYPE.STRING],719 typeList: [ARGUMENT_TYPE.STRING],
720 enumProvider: commonEnumProviders.tags('assigned'),720 enumProvider: commonEnumProviders.tags('assigned'),
721 acceptsMultiple: true,721 acceptsMultiple: true,
722 }),722 }),
723 SlashCommandNamedArgument.fromProps({723 SlashCommandNamedArgument.fromProps({
724 name: 'preferCurrent',724 name: 'preferCurrent',
725 description: 'Prefer current character or characters in a group, if multiple characters match',725 description: t`Prefer current character or characters in a group, if multiple characters match`,
726 typeList: [ARGUMENT_TYPE.BOOLEAN],726 typeList: [ARGUMENT_TYPE.BOOLEAN],
727 defaultValue: 'true',727 defaultValue: 'true',
728 }),728 }),
729 SlashCommandNamedArgument.fromProps({729 SlashCommandNamedArgument.fromProps({
730 name: 'quiet',730 name: 'quiet',
731 description: 'Do not show warning if multiple charactrers are found',731 description: t`Do not show warning if multiple charactrers are found`,
732 typeList: [ARGUMENT_TYPE.BOOLEAN],732 typeList: [ARGUMENT_TYPE.BOOLEAN],
733 defaultValue: 'false',733 defaultValue: 'false',
734 enumProvider: commonEnumProviders.boolean('trueFalse'),734 enumProvider: commonEnumProviders.boolean('trueFalse'),
@@ -736,31 +736,29 @@ export function initDefaultSlashCommands() {
736 ],736 ],
737 unnamedArgumentList: [737 unnamedArgumentList: [
738 SlashCommandArgument.fromProps({738 SlashCommandArgument.fromProps({
739 description: 'Character name - or unique character identifier (avatar key)',739 description: t`Character name - or unique character identifier (avatar key)`,
740 typeList: [ARGUMENT_TYPE.STRING],740 typeList: [ARGUMENT_TYPE.STRING],
741 enumProvider: commonEnumProviders.characters('character'),741 enumProvider: commonEnumProviders.characters('character'),
742 }),742 }),
743 ],743 ],
744 helpString: `744 helpString: `
745 <div>745 <div>
746 Searches for a character and returns its avatar key.746 ${t`Searches for a character and returns its avatar key.`}
747 </div>747 </div>
748 <div>748 <div>
749 This can be used to choose the correct character for something like <code>/sendas</code> or other commands in need of a character name749 ${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.
751 </div>750 </div>
752 <div>751 <div>
753 <strong>Example:</strong>752 <strong>${t`Example:`}</strong>
754 <ul>753 <ul>
755 <li>754 <li>
756 <pre><code>/char-find name="Chloe"</code></pre>755 <pre><code>/char-find name="Chloe"</code></pre>
757 Returns the avatar key for "Chloe".756 ${t`Returns the avatar key for "Chloe".`}
758 </li>757 </li>
759 <li>758 <li>
760 <pre><code>/search name="Chloe" tag="friend"</code></pre>759 <pre><code>/search name="Chloe" tag="friend"</code></pre>
761 Returns the avatar key for the character "Chloe" that is tagged with "friend".760 ${t`Returns the avatar key for the character "Chloe" that is tagged with "friend".`}
762 This is useful if you for example have multiple characters named "Chloe", and the others are "foe", "goddess", or anything else,761 ${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.
764 </li>762 </li>
765 </ul>763 </ul>
766 </div>764 </div>
@@ -770,36 +768,36 @@ export function initDefaultSlashCommands() {
770 name: 'sendas',768 name: 'sendas',
771 rawQuotes: true,769 rawQuotes: true,
772 callback: sendMessageAs,770 callback: sendMessageAs,
773 returns: 'Optionally the text of the sent message, if specified in the "return" argument',771 returns: t`Optionally the text of the sent message, if specified in the "return" argument`,
774 namedArgumentList: [772 namedArgumentList: [
775 SlashCommandNamedArgument.fromProps({773 SlashCommandNamedArgument.fromProps({
776 name: 'name',774 name: 'name',
777 description: 'Character name - or unique character identifier (avatar key)',775 description: t`Character name - or unique character identifier (avatar key)`,
778 typeList: [ARGUMENT_TYPE.STRING],776 typeList: [ARGUMENT_TYPE.STRING],
779 isRequired: true,777 isRequired: true,
780 enumProvider: commonEnumProviders.characters('character'),778 enumProvider: commonEnumProviders.characters('character'),
781 }),779 }),
782 SlashCommandNamedArgument.fromProps({780 SlashCommandNamedArgument.fromProps({
783 name: 'avatar',781 name: 'avatar',
784 description: 'Character avatar override (Can be either avatar key or just the character name to pull the avatar from)',782 description: t`Character avatar override (Can be either avatar key or just the character name to pull the avatar from)`,
785 typeList: [ARGUMENT_TYPE.STRING],783 typeList: [ARGUMENT_TYPE.STRING],
786 enumProvider: commonEnumProviders.characters('character'),784 enumProvider: commonEnumProviders.characters('character'),
787 }),785 }),
788 SlashCommandNamedArgument.fromProps({786 SlashCommandNamedArgument.fromProps({
789 name: 'compact',787 name: 'compact',
790 description: 'Use compact layout',788 description: t`Use compact layout`,
791 typeList: [ARGUMENT_TYPE.BOOLEAN],789 typeList: [ARGUMENT_TYPE.BOOLEAN],
792 defaultValue: 'false',790 defaultValue: 'false',
793 }),791 }),
794 SlashCommandNamedArgument.fromProps({792 SlashCommandNamedArgument.fromProps({
795 name: 'at',793 name: 'at',
796 description: '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.',794 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.`,
797 typeList: [ARGUMENT_TYPE.NUMBER],795 typeList: [ARGUMENT_TYPE.NUMBER],
798 enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),796 enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
799 }),797 }),
800 SlashCommandNamedArgument.fromProps({798 SlashCommandNamedArgument.fromProps({
801 name: 'return',799 name: 'return',
802 description: 'The way how you want the return value to be provided',800 description: t`The way how you want the return value to be provided`,
803 typeList: [ARGUMENT_TYPE.STRING],801 typeList: [ARGUMENT_TYPE.STRING],
804 defaultValue: 'none',802 defaultValue: 'none',
805 enumList: slashCommandReturnHelper.enumList({ allowObject: true }),803 enumList: slashCommandReturnHelper.enumList({ allowObject: true }),
@@ -807,7 +805,7 @@ export function initDefaultSlashCommands() {
807 }),805 }),
808 SlashCommandNamedArgument.fromProps({806 SlashCommandNamedArgument.fromProps({
809 name: 'raw',807 name: 'raw',
810 description: 'If true, does not alter quoted literal unnamed arguments',808 description: t`If true, does not alter quoted literal unnamed arguments`,
811 typeList: [ARGUMENT_TYPE.BOOLEAN],809 typeList: [ARGUMENT_TYPE.BOOLEAN],
812 defaultValue: 'true',810 defaultValue: 'true',
813 enumProvider: commonEnumProviders.boolean('trueFalse'),811 enumProvider: commonEnumProviders.boolean('trueFalse'),
@@ -821,23 +819,23 @@ export function initDefaultSlashCommands() {
821 ],819 ],
822 helpString: `820 helpString: `
823 <div>821 <div>
824 Sends a message as a specific character. Uses the character avatar if it exists in the characters list.822 ${t`Sends a message as a specific character. Uses the character avatar if it exists in the characters list.`}
825 </div>823 </div>
826 <div>824 <div>
827 <strong>Example:</strong>825 <strong>${t`Example:`}</strong>
828 <ul>826 <ul>
829 <li>827 <li>
830 <pre><code>/sendas name="Chloe" Hello, guys!</code></pre>828 <pre><code>/sendas name="Chloe" Hello, guys!</code></pre>
831 will send "Hello, guys!" from "Chloe".829 ${t`will send "Hello, guys!" from "Chloe".`}
832 </li>830 </li>
833 <li>831 <li>
834 <pre><code>/sendas name="Chloe" avatar="BigBadBoss" Hehehe, I am the big bad evil, fear me.</code></pre>832 <pre><code>/sendas name="Chloe" avatar="BigBadBoss" Hehehe, I am the big bad evil, fear me.</code></pre>
835 will send a message as the character "Chloe", but utilizing the avatar from a character named "BigBadBoss".833 ${t`will send a message as the character "Chloe", but utilizing the avatar from a character named "BigBadBoss".`}
836 </li>834 </li>
837 </ul>835 </ul>
838 </div>836 </div>
839 <div>837 <div>
840 If "compact" is set to true, the message is sent using a compact layout.838 ${t`If "compact" is set to true, the message is sent using a compact layout.`}
841 </div>839 </div>
842 `,840 `,
843 }));841 }));
@@ -846,11 +844,11 @@ export function initDefaultSlashCommands() {
846 rawQuotes: true,844 rawQuotes: true,
847 callback: sendNarratorMessage,845 callback: sendNarratorMessage,
848 aliases: ['nar'],846 aliases: ['nar'],
849 returns: 'Optionally the text of the sent message, if specified in the "return" argument',847 returns: t`Optionally the text of the sent message, if specified in the "return" argument`,
850 namedArgumentList: [848 namedArgumentList: [
851 new SlashCommandNamedArgument(849 new SlashCommandNamedArgument(
852 'compact',850 'compact',
853 'compact layout',851 t`compact layout`,
854 [ARGUMENT_TYPE.BOOLEAN],852 [ARGUMENT_TYPE.BOOLEAN],
855 false,853 false,
856 false,854 false,
@@ -858,18 +856,18 @@ export function initDefaultSlashCommands() {
858 ),856 ),
859 SlashCommandNamedArgument.fromProps({857 SlashCommandNamedArgument.fromProps({
860 name: 'at',858 name: 'at',
861 description: '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.',859 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.`,
862 typeList: [ARGUMENT_TYPE.NUMBER],860 typeList: [ARGUMENT_TYPE.NUMBER],
863 enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),861 enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
864 }),862 }),
865 SlashCommandNamedArgument.fromProps({863 SlashCommandNamedArgument.fromProps({
866 name: 'name',864 name: 'name',
867 description: 'Optional custom display name to use for this system narrator message.',865 description: t`Optional custom display name to use for this system narrator message.`,
868 typeList: [ARGUMENT_TYPE.STRING],866 typeList: [ARGUMENT_TYPE.STRING],
869 }),867 }),
870 SlashCommandNamedArgument.fromProps({868 SlashCommandNamedArgument.fromProps({
871 name: 'return',869 name: 'return',
872 description: 'The way how you want the return value to be provided',870 description: t`The way how you want the return value to be provided`,
873 typeList: [ARGUMENT_TYPE.STRING],871 typeList: [ARGUMENT_TYPE.STRING],
874 defaultValue: 'none',872 defaultValue: 'none',
875 enumList: slashCommandReturnHelper.enumList({ allowObject: true }),873 enumList: slashCommandReturnHelper.enumList({ allowObject: true }),
@@ -877,7 +875,7 @@ export function initDefaultSlashCommands() {
877 }),875 }),
878 SlashCommandNamedArgument.fromProps({876 SlashCommandNamedArgument.fromProps({
879 name: 'raw',877 name: 'raw',
880 description: 'If true, does not alter quoted literal unnamed arguments',878 description: t`If true, does not alter quoted literal unnamed arguments`,
881 typeList: [ARGUMENT_TYPE.BOOLEAN],879 typeList: [ARGUMENT_TYPE.BOOLEAN],
882 defaultValue: 'true',880 defaultValue: 'true',
883 enumProvider: commonEnumProviders.boolean('trueFalse'),881 enumProvider: commonEnumProviders.boolean('trueFalse'),
@@ -891,13 +889,13 @@ export function initDefaultSlashCommands() {
891 ],889 ],
892 helpString: `890 helpString: `
893 <div>891 <div>
894 Sends a message as a system narrator.892 ${t`Sends a message as a system narrator.`}
895 </div>893 </div>
896 <div>894 <div>
897 If <code>compact</code> is set to <code>true</code>, the message is sent using a compact layout.895 ${t`If <code>compact</code> is set to <code>true</code>, the message is sent using a compact layout.`}
898 </div>896 </div>
899 <div>897 <div>
900 <strong>Example:</strong>898 <strong>${t`Example:`}</strong>
901 <ul>899 <ul>
902 <li>900 <li>
903 <pre><code>/sys The sun sets in the west.</code></pre>901 <pre><code>/sys The sun sets in the west.</code></pre>
@@ -914,20 +912,20 @@ export function initDefaultSlashCommands() {
914 callback: setNarratorName,912 callback: setNarratorName,
915 unnamedArgumentList: [913 unnamedArgumentList: [
916 new SlashCommandArgument(914 new SlashCommandArgument(
917 'name', [ARGUMENT_TYPE.STRING], false,915 t`name`, [ARGUMENT_TYPE.STRING], false,
918 ),916 ),
919 ],917 ],
920 helpString: 'Sets a name for future system narrator messages in this chat (display only). Default: System. Leave empty to reset.',918 helpString: t`Sets a name for future system narrator messages in this chat (display only). Default: System. Leave empty to reset.`,
921 }));919 }));
922 SlashCommandParser.addCommandObject(SlashCommand.fromProps({920 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
923 name: 'comment',921 name: 'comment',
924 rawQuotes: true,922 rawQuotes: true,
925 callback: sendCommentMessage,923 callback: sendCommentMessage,
926 returns: 'Optionally the text of the sent message, if specified in the "return" argument',924 returns: t`Optionally the text of the sent message, if specified in the "return" argument`,
927 namedArgumentList: [925 namedArgumentList: [
928 new SlashCommandNamedArgument(926 new SlashCommandNamedArgument(
929 'compact',927 'compact',
930 'Whether to use a compact layout',928 t`Whether to use a compact layout`,
931 [ARGUMENT_TYPE.BOOLEAN],929 [ARGUMENT_TYPE.BOOLEAN],
932 false,930 false,
933 false,931 false,
@@ -935,13 +933,13 @@ export function initDefaultSlashCommands() {
935 ),933 ),
936 SlashCommandNamedArgument.fromProps({934 SlashCommandNamedArgument.fromProps({
937 name: 'at',935 name: 'at',
938 description: '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.',936 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.`,
939 typeList: [ARGUMENT_TYPE.NUMBER],937 typeList: [ARGUMENT_TYPE.NUMBER],
940 enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),938 enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
941 }),939 }),
942 SlashCommandNamedArgument.fromProps({940 SlashCommandNamedArgument.fromProps({
943 name: 'return',941 name: 'return',
944 description: 'The way how you want the return value to be provided',942 description: t`The way how you want the return value to be provided`,
945 typeList: [ARGUMENT_TYPE.STRING],943 typeList: [ARGUMENT_TYPE.STRING],
946 defaultValue: 'none',944 defaultValue: 'none',
947 enumList: slashCommandReturnHelper.enumList({ allowObject: true }),945 enumList: slashCommandReturnHelper.enumList({ allowObject: true }),
@@ -949,7 +947,7 @@ export function initDefaultSlashCommands() {
949 }),947 }),
950 SlashCommandNamedArgument.fromProps({948 SlashCommandNamedArgument.fromProps({
951 name: 'raw',949 name: 'raw',
952 description: 'If true, does not alter quoted literal unnamed arguments',950 description: t`If true, does not alter quoted literal unnamed arguments`,
953 typeList: [ARGUMENT_TYPE.BOOLEAN],951 typeList: [ARGUMENT_TYPE.BOOLEAN],
954 defaultValue: 'true',952 defaultValue: 'true',
955 enumProvider: commonEnumProviders.boolean('trueFalse'),953 enumProvider: commonEnumProviders.boolean('trueFalse'),
@@ -965,13 +963,13 @@ export function initDefaultSlashCommands() {
965 ],963 ],
966 helpString: `964 helpString: `
967 <div>965 <div>
968 Adds a note/comment message not part of the chat.966 ${t`Adds a note/comment message not part of the chat.`}
969 </div>967 </div>
970 <div>968 <div>
971 If <code>compact</code> is set to <code>true</code>, the message is sent using a compact layout.969 ${t`If <code>compact</code> is set to <code>true</code>, the message is sent using a compact layout.`}
972 </div>970 </div>
973 <div>971 <div>
974 <strong>Example:</strong>972 <strong>${t`Example:`}</strong>
975 <ul>973 <ul>
976 <li>974 <li>
977 <pre><code>/comment This is a comment</code></pre>975 <pre><code>/comment This is a comment</code></pre>
@@ -987,19 +985,19 @@ export function initDefaultSlashCommands() {
987 name: 'single',985 name: 'single',
988 callback: setStoryModeCallback,986 callback: setStoryModeCallback,
989 aliases: ['story'],987 aliases: ['story'],
990 helpString: 'Sets the message style to single document mode without names or avatars visible.',988 helpString: t`Sets the message style to single document mode without names or avatars visible.`,
991 }));989 }));
992 SlashCommandParser.addCommandObject(SlashCommand.fromProps({990 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
993 name: 'bubble',991 name: 'bubble',
994 callback: setBubbleModeCallback,992 callback: setBubbleModeCallback,
995 aliases: ['bubbles'],993 aliases: ['bubbles'],
996 helpString: 'Sets the message style to bubble chat mode.',994 helpString: t`Sets the message style to bubble chat mode.`,
997 }));995 }));
998 SlashCommandParser.addCommandObject(SlashCommand.fromProps({996 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
999 name: 'flat',997 name: 'flat',
1000 callback: setFlatModeCallback,998 callback: setFlatModeCallback,
1001 aliases: ['default'],999 aliases: ['default'],
1002 helpString: 'Sets the message style to flat chat mode.',1000 helpString: t`Sets the message style to flat chat mode.`,
1003 }));1001 }));
1004 SlashCommandParser.addCommandObject(SlashCommand.fromProps({1002 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
1005 name: 'continue',1003 name: 'continue',
@@ -1008,7 +1006,7 @@ export function initDefaultSlashCommands() {
1008 namedArgumentList: [1006 namedArgumentList: [
1009 new SlashCommandNamedArgument(1007 new SlashCommandNamedArgument(
1010 'await',1008 'await',
1011 'Whether to await for the continued generation before proceeding',1009 t`Whether to await for the continued generation before proceeding`,
1012 [ARGUMENT_TYPE.BOOLEAN],1010 [ARGUMENT_TYPE.BOOLEAN],
1013 false,1011 false,
1014 false,1012 false,
@@ -1022,21 +1020,21 @@ export function initDefaultSlashCommands() {
1022 ],1020 ],
1023 helpString: `1021 helpString: `
1024 <div>1022 <div>
1025 Continues the last message in the chat, with an optional additional prompt.1023 ${t`Continues the last message in the chat, with an optional additional prompt.`}
1026 </div>1024 </div>
1027 <div>1025 <div>
1028 If <code>await=true</code> named argument is passed, the command will await for the continued generation before proceeding.1026 ${t`If <code>await=true</code> named argument is passed, the command will await for the continued generation before proceeding.`}
1029 </div>1027 </div>
1030 <div>1028 <div>
1031 <strong>Example:</strong>1029 <strong>${t`Example:`}</strong>
1032 <ul>1030 <ul>
1033 <li>1031 <li>
1034 <pre><code>/continue</code></pre>1032 <pre><code>/continue</code></pre>
1035 Continues the chat with no additional prompt and immediately proceeds to the next command.1033 ${t`Continues the chat with no additional prompt and immediately proceeds to the next command.`}
1036 </li>1034 </li>
1037 <li>1035 <li>
1038 <pre><code>/continue await=true Let's explore this further...</code></pre>1036 <pre><code>/continue await=true Let's explore this further...</code></pre>
1039 Continues the chat with the provided prompt and waits for the generation to finish.1037 ${t`Continues the chat with the provided prompt and waits for the generation to finish.`}
1040 </li>1038 </li>
1041 </ul>1039 </ul>
1042 </div>1040 </div>
@@ -1045,16 +1043,16 @@ export function initDefaultSlashCommands() {
1045 SlashCommandParser.addCommandObject(SlashCommand.fromProps({1043 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
1046 name: 'go',1044 name: 'go',
1047 callback: goToCharacterCallback,1045 callback: goToCharacterCallback,
1048 returns: 'The character/group name',1046 returns: t`The character/group name`,
1049 unnamedArgumentList: [1047 unnamedArgumentList: [
1050 SlashCommandArgument.fromProps({1048 SlashCommandArgument.fromProps({
1051 description: 'Character name - or unique character identifier (avatar key)',1049 description: t`Character name - or unique character identifier (avatar key)`,
1052 typeList: [ARGUMENT_TYPE.STRING],1050 typeList: [ARGUMENT_TYPE.STRING],
1053 isRequired: true,1051 isRequired: true,
1054 enumProvider: commonEnumProviders.characters('all'),1052 enumProvider: commonEnumProviders.characters('all'),
1055 }),1053 }),
1056 ],1054 ],
1057 helpString: 'Opens up a chat with the character or group by its name',1055 helpString: t`Opens up a chat with the character or group by its name`,
1058 aliases: ['char'],1056 aliases: ['char'],
1059 }));1057 }));
1060 SlashCommandParser.addCommandObject(SlashCommand.fromProps({1058 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
@@ -1064,21 +1062,21 @@ export function initDefaultSlashCommands() {
1064 const renamed = await renameCharacter(name, { silent: isTrueBoolean(silent), renameChats: chats !== null ? isTrueBoolean(chats) : null });1062 const renamed = await renameCharacter(name, { silent: isTrueBoolean(silent), renameChats: chats !== null ? isTrueBoolean(chats) : null });
1065 return String(renamed);1063 return String(renamed);
1066 },1064 },
1067 returns: 'true/false - Whether the rename was successful',1065 returns: t`true/false - Whether the rename was successful`,
1068 namedArgumentList: [1066 namedArgumentList: [
1069 new SlashCommandNamedArgument(1067 new SlashCommandNamedArgument(
1070 'silent', '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',1068 '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',
1071 ),1069 ),
1072 new SlashCommandNamedArgument(1070 new SlashCommandNamedArgument(
1073 'chats', 'Rename char in all previous chats', [ARGUMENT_TYPE.BOOLEAN], false, false, '<null>',1071 'chats', t`Rename char in all previous chats`, [ARGUMENT_TYPE.BOOLEAN], false, false, '<null>',
1074 ),1072 ),
1075 ],1073 ],
1076 unnamedArgumentList: [1074 unnamedArgumentList: [
1077 new SlashCommandArgument(1075 new SlashCommandArgument(
1078 'new char name', [ARGUMENT_TYPE.STRING], true,1076 t`new char name`, [ARGUMENT_TYPE.STRING], true,
1079 ),1077 ),
1080 ],1078 ],
1081 helpString: 'Renames the current character.',1079 helpString: t`Renames the current character.`,
1082 }));1080 }));
1083 SlashCommandParser.addCommandObject(SlashCommand.fromProps({1081 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
1084 name: 'sysgen',1082 name: 'sysgen',
@@ -1086,7 +1084,7 @@ export function initDefaultSlashCommands() {
1086 namedArgumentList: [1084 namedArgumentList: [
1087 SlashCommandNamedArgument.fromProps({1085 SlashCommandNamedArgument.fromProps({
1088 name: 'trim',1086 name: 'trim',
1089 description: 'Trim the output by the last sentence boundary',1087 description: t`Trim the output by the last sentence boundary`,
1090 typeList: [ARGUMENT_TYPE.BOOLEAN],1088 typeList: [ARGUMENT_TYPE.BOOLEAN],
1091 defaultValue: 'false',1089 defaultValue: 'false',
1092 isRequired: false,1090 isRequired: false,
@@ -1094,7 +1092,7 @@ export function initDefaultSlashCommands() {
1094 }),1092 }),
1095 SlashCommandNamedArgument.fromProps({1093 SlashCommandNamedArgument.fromProps({
1096 name: 'compact',1094 name: 'compact',
1097 description: 'Use a compact layout for the message',1095 description: t`Use a compact layout for the message`,
1098 typeList: [ARGUMENT_TYPE.BOOLEAN],1096 typeList: [ARGUMENT_TYPE.BOOLEAN],
1099 defaultValue: 'false',1097 defaultValue: 'false',
1100 isRequired: false,1098 isRequired: false,
@@ -1103,18 +1101,18 @@ export function initDefaultSlashCommands() {
1103 }),1101 }),
1104 SlashCommandNamedArgument.fromProps({1102 SlashCommandNamedArgument.fromProps({
1105 name: 'at',1103 name: 'at',
1106 description: '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.',1104 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.`,
1107 typeList: [ARGUMENT_TYPE.NUMBER],1105 typeList: [ARGUMENT_TYPE.NUMBER],
1108 enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),1106 enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
1109 }),1107 }),
1110 SlashCommandNamedArgument.fromProps({1108 SlashCommandNamedArgument.fromProps({
1111 name: 'name',1109 name: 'name',
1112 description: 'Optional custom display name to use for this system narrator message.',1110 description: t`Optional custom display name to use for this system narrator message.`,
1113 typeList: [ARGUMENT_TYPE.STRING],1111 typeList: [ARGUMENT_TYPE.STRING],
1114 }),1112 }),
1115 SlashCommandNamedArgument.fromProps({1113 SlashCommandNamedArgument.fromProps({
1116 name: 'return',1114 name: 'return',
1117 description: 'The way how you want the return value to be provided',1115 description: t`The way how you want the return value to be provided`,
1118 typeList: [ARGUMENT_TYPE.STRING],1116 typeList: [ARGUMENT_TYPE.STRING],
1119 defaultValue: 'none',1117 defaultValue: 'none',
1120 enumList: slashCommandReturnHelper.enumList({ allowObject: true }),1118 enumList: slashCommandReturnHelper.enumList({ allowObject: true }),
@@ -1126,23 +1124,23 @@ export function initDefaultSlashCommands() {
1126 'prompt', [ARGUMENT_TYPE.STRING], true,1124 'prompt', [ARGUMENT_TYPE.STRING], true,
1127 ),1125 ),
1128 ],1126 ],
1129 helpString: 'Generates a system message using a specified prompt.',1127 helpString: t`Generates a system message using a specified prompt.`,
1130 }));1128 }));
1131 SlashCommandParser.addCommandObject(SlashCommand.fromProps({1129 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
1132 name: 'ask',1130 name: 'ask',
1133 callback: askCharacter,1131 callback: askCharacter,
1134 returns: 'Optionally the text of the sent message, if specified in the "return" argument',1132 returns: t`Optionally the text of the sent message, if specified in the "return" argument`,
1135 namedArgumentList: [1133 namedArgumentList: [
1136 SlashCommandNamedArgument.fromProps({1134 SlashCommandNamedArgument.fromProps({
1137 name: 'name',1135 name: 'name',
1138 description: 'Character name - or unique character identifier (avatar key)',1136 description: t`Character name - or unique character identifier (avatar key)`,
1139 typeList: [ARGUMENT_TYPE.STRING],1137 typeList: [ARGUMENT_TYPE.STRING],
1140 isRequired: true,1138 isRequired: true,
1141 enumProvider: commonEnumProviders.characters('character'),1139 enumProvider: commonEnumProviders.characters('character'),
1142 }),1140 }),
1143 SlashCommandNamedArgument.fromProps({1141 SlashCommandNamedArgument.fromProps({
1144 name: 'return',1142 name: 'return',
1145 description: 'The way how you want the return value to be provided',1143 description: t`The way how you want the return value to be provided`,
1146 typeList: [ARGUMENT_TYPE.STRING],1144 typeList: [ARGUMENT_TYPE.STRING],
1147 defaultValue: 'pipe',1145 defaultValue: 'pipe',
1148 enumList: slashCommandReturnHelper.enumList({ allowObject: true }),1146 enumList: slashCommandReturnHelper.enumList({ allowObject: true }),
@@ -1154,7 +1152,7 @@ export function initDefaultSlashCommands() {
1154 'prompt', [ARGUMENT_TYPE.STRING], false, false,1152 'prompt', [ARGUMENT_TYPE.STRING], false, false,
1155 ),1153 ),
1156 ],1154 ],
1157 helpString: 'Asks a specified character card a prompt. Character name must be provided in a named argument.',1155 helpString: t`Asks a specified character card a prompt. Character name must be provided in a named argument.`,
1158 }));1156 }));
1159 SlashCommandParser.addCommandObject(SlashCommand.fromProps({1157 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
1160 name: 'delname',1158 name: 'delname',
@@ -1162,7 +1160,7 @@ export function initDefaultSlashCommands() {
1162 namedArgumentList: [],1160 namedArgumentList: [],
1163 unnamedArgumentList: [1161 unnamedArgumentList: [
1164 SlashCommandArgument.fromProps({1162 SlashCommandArgument.fromProps({
1165 description: 'Character name - or unique character identifier (avatar key)',1163 description: t`Character name - or unique character identifier (avatar key)`,
1166 typeList: [ARGUMENT_TYPE.STRING],1164 typeList: [ARGUMENT_TYPE.STRING],
1167 isRequired: true,1165 isRequired: true,
1168 enumProvider: commonEnumProviders.characters('character'),1166 enumProvider: commonEnumProviders.characters('character'),
@@ -1171,10 +1169,10 @@ export function initDefaultSlashCommands() {
1171 aliases: ['cancel'],1169 aliases: ['cancel'],
1172 helpString: `1170 helpString: `
1173 <div>1171 <div>
1174 Deletes all messages attributed to a specified name.1172 ${t`Deletes all messages attributed to a specified name.`}
1175 </div>1173 </div>
1176 <div>1174 <div>
1177 <strong>Example:</strong>1175 <strong>${t`Example:`}</strong>
1178 <ul>1176 <ul>
1179 <li>1177 <li>
1180 <pre><code>/delname John</code></pre>1178 <pre><code>/delname John</code></pre>
@@ -1187,11 +1185,11 @@ export function initDefaultSlashCommands() {
1187 name: 'send',1185 name: 'send',
1188 rawQuotes: true,1186 rawQuotes: true,
1189 callback: sendUserMessageCallback,1187 callback: sendUserMessageCallback,
1190 returns: 'Optionally the text of the sent message, if specified in the "return" argument',1188 returns: t`Optionally the text of the sent message, if specified in the "return" argument`,
1191 namedArgumentList: [1189 namedArgumentList: [
1192 new SlashCommandNamedArgument(1190 new SlashCommandNamedArgument(
1193 'compact',1191 'compact',
1194 'whether to use a compact layout',1192 t`whether to use a compact layout`,
1195 [ARGUMENT_TYPE.BOOLEAN],1193 [ARGUMENT_TYPE.BOOLEAN],
1196 false,1194 false,
1197 false,1195 false,
@@ -1199,20 +1197,20 @@ export function initDefaultSlashCommands() {
1199 ),1197 ),
1200 SlashCommandNamedArgument.fromProps({1198 SlashCommandNamedArgument.fromProps({
1201 name: 'at',1199 name: 'at',
1202 description: '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.',1200 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.`,
1203 typeList: [ARGUMENT_TYPE.NUMBER],1201 typeList: [ARGUMENT_TYPE.NUMBER],
1204 enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),1202 enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
1205 }),1203 }),
1206 SlashCommandNamedArgument.fromProps({1204 SlashCommandNamedArgument.fromProps({
1207 name: 'name',1205 name: 'name',
1208 description: 'display name',1206 description: t`display name`,
1209 typeList: [ARGUMENT_TYPE.STRING],1207 typeList: [ARGUMENT_TYPE.STRING],
1210 defaultValue: '{{user}}',1208 defaultValue: '{{user}}',
1211 enumProvider: commonEnumProviders.personas,1209 enumProvider: commonEnumProviders.personas,
1212 }),1210 }),
1213 SlashCommandNamedArgument.fromProps({1211 SlashCommandNamedArgument.fromProps({
1214 name: 'return',1212 name: 'return',
1215 description: 'The way how you want the return value to be provided',1213 description: t`The way how you want the return value to be provided`,
1216 typeList: [ARGUMENT_TYPE.STRING],1214 typeList: [ARGUMENT_TYPE.STRING],
1217 defaultValue: 'none',1215 defaultValue: 'none',
1218 enumList: slashCommandReturnHelper.enumList({ allowObject: true }),1216 enumList: slashCommandReturnHelper.enumList({ allowObject: true }),
@@ -1220,7 +1218,7 @@ export function initDefaultSlashCommands() {
1220 }),1218 }),
1221 SlashCommandNamedArgument.fromProps({1219 SlashCommandNamedArgument.fromProps({
1222 name: 'raw',1220 name: 'raw',
1223 description: 'If true, does not alter quoted literal unnamed arguments',1221 description: t`If true, does not alter quoted literal unnamed arguments`,
1224 typeList: [ARGUMENT_TYPE.BOOLEAN],1222 typeList: [ARGUMENT_TYPE.BOOLEAN],
1225 defaultValue: 'true',1223 defaultValue: 'true',
1226 enumProvider: commonEnumProviders.boolean('trueFalse'),1224 enumProvider: commonEnumProviders.boolean('trueFalse'),
@@ -1236,16 +1234,16 @@ export function initDefaultSlashCommands() {
1236 ],1234 ],
1237 helpString: `1235 helpString: `
1238 <div>1236 <div>
1239 Adds a user message to the chat log without triggering a generation.1237 ${t`Adds a user message to the chat log without triggering a generation.`}
1240 </div>1238 </div>
1241 <div>1239 <div>
1242 If <code>compact</code> is set to <code>true</code>, the message is sent using a compact layout.1240 ${t`If <code>compact</code> is set to <code>true</code>, the message is sent using a compact layout.`}
1243 </div>1241 </div>
1244 <div>1242 <div>
1245 If <code>name</code> is set, it will be displayed as the message sender. Can be an empty for no name.1243 ${t`If <code>name</code> is set, it will be displayed as the message sender. Can be an empty for no name.`}
1246 </div>1244 </div>
1247 <div>1245 <div>
1248 <strong>Example:</strong>1246 <strong>${t`Example:`}</strong>
1249 <ul>1247 <ul>
1250 <li>1248 <li>
1251 <pre><code>/send Hello there!</code></pre>1249 <pre><code>/send Hello there!</code></pre>
@@ -1263,7 +1261,7 @@ export function initDefaultSlashCommands() {
1263 namedArgumentList: [1261 namedArgumentList: [
1264 new SlashCommandNamedArgument(1262 new SlashCommandNamedArgument(
1265 'await',1263 'await',
1266 'Whether to await for the triggered generation before continuing',1264 t`Whether to await for the triggered generation before continuing`,
1267 [ARGUMENT_TYPE.BOOLEAN],1265 [ARGUMENT_TYPE.BOOLEAN],
1268 false,1266 false,
1269 false,1267 false,
@@ -1272,7 +1270,7 @@ export function initDefaultSlashCommands() {
1272 ],1270 ],
1273 unnamedArgumentList: [1271 unnamedArgumentList: [
1274 SlashCommandArgument.fromProps({1272 SlashCommandArgument.fromProps({
1275 description: 'group member index (starts with 0) or name',1273 description: t`group member index (starts with 0) or name`,
1276 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],1274 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
1277 isRequired: false,1275 isRequired: false,
1278 enumProvider: commonEnumProviders.groupMembers(),1276 enumProvider: commonEnumProviders.groupMembers(),
@@ -1280,10 +1278,10 @@ export function initDefaultSlashCommands() {
1280 ],1278 ],
1281 helpString: `1279 helpString: `
1282 <div>1280 <div>
1283 Triggers a message generation. If in group, can trigger a message for the specified group member index or name.1281 ${t`Triggers a message generation. If in group, can trigger a message for the specified group member index or name.`}
1284 </div>1282 </div>
1285 <div>1283 <div>
1286 If <code>await=true</code> named argument is passed, the command will await for the triggered generation before continuing.1284 ${t`If <code>await=true</code> named argument is passed, the command will await for the triggered generation before continuing.`}
1287 </div>1285 </div>
1288 `,1286 `,
1289 }));1287 }));
@@ -1293,7 +1291,7 @@ export function initDefaultSlashCommands() {
1293 namedArgumentList: [1291 namedArgumentList: [
1294 SlashCommandNamedArgument.fromProps({1292 SlashCommandNamedArgument.fromProps({
1295 name: 'name',1293 name: 'name',
1296 description: 'only hide messages from a certain character or persona',1294 description: t`only hide messages from a certain character or persona`,
1297 typeList: [ARGUMENT_TYPE.STRING],1295 typeList: [ARGUMENT_TYPE.STRING],
1298 enumProvider: commonEnumProviders.messageNames,1296 enumProvider: commonEnumProviders.messageNames,
1299 isRequired: false,1297 isRequired: false,
@@ -1302,13 +1300,13 @@ export function initDefaultSlashCommands() {
1302 ],1300 ],
1303 unnamedArgumentList: [1301 unnamedArgumentList: [
1304 SlashCommandArgument.fromProps({1302 SlashCommandArgument.fromProps({
1305 description: 'message index (starts with 0) or range, defaults to the last message index if not provided',1303 description: t`message index (starts with 0) or range, defaults to the last message index if not provided`,
1306 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE],1304 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE],
1307 isRequired: false,1305 isRequired: false,
1308 enumProvider: commonEnumProviders.messages(),1306 enumProvider: commonEnumProviders.messages(),
1309 }),1307 }),
1310 ],1308 ],
1311 helpString: 'Hides a chat message from the prompt.',1309 helpString: t`Hides a chat message from the prompt.`,
1312 }));1310 }));
1313 SlashCommandParser.addCommandObject(SlashCommand.fromProps({1311 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
1314 name: 'unhide',1312 name: 'unhide',
@@ -1316,7 +1314,7 @@ export function initDefaultSlashCommands() {
1316 namedArgumentList: [1314 namedArgumentList: [
1317 SlashCommandNamedArgument.fromProps({1315 SlashCommandNamedArgument.fromProps({
1318 name: 'name',1316 name: 'name',
1319 description: 'only unhide messages from a certain character or persona',1317 description: t`only unhide messages from a certain character or persona`,
1320 typeList: [ARGUMENT_TYPE.STRING],1318 typeList: [ARGUMENT_TYPE.STRING],
1321 enumProvider: commonEnumProviders.messageNames,1319 enumProvider: commonEnumProviders.messageNames,
1322 isRequired: false,1320 isRequired: false,
@@ -1325,36 +1323,36 @@ export function initDefaultSlashCommands() {
1325 ],1323 ],
1326 unnamedArgumentList: [1324 unnamedArgumentList: [
1327 SlashCommandArgument.fromProps({1325 SlashCommandArgument.fromProps({
1328 description: 'message index (starts with 0) or range, defaults to the last message index if not provided',1326 description: t`message index (starts with 0) or range, defaults to the last message index if not provided`,
1329 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE],1327 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE],
1330 isRequired: false,1328 isRequired: false,
1331 enumProvider: commonEnumProviders.messages(),1329 enumProvider: commonEnumProviders.messages(),
1332 }),1330 }),
1333 ],1331 ],
1334 helpString: 'Unhides a message from the prompt.',1332 helpString: t`Unhides a message from the prompt.`,
1335 }));1333 }));
1336 SlashCommandParser.addCommandObject(SlashCommand.fromProps({1334 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
1337 name: 'member-get',1335 name: 'member-get',
1338 aliases: ['getmember', 'memberget'],1336 aliases: ['getmember', 'memberget'],
1339 callback: (async ({ field = 'name' }, arg) => {1337 callback: (async ({ field = 'name' }, arg) => {
1340 if (!selected_group) {1338 if (!selected_group) {
1341 toastr.warning('Cannot run /member-get command outside of a group chat.');1339 toastr.warning(t`Cannot run /member-get command outside of a group chat.`);
1342 return '';1340 return '';
1343 }1341 }
1344 if (field === '') {1342 if (field === '') {
1345 toastr.warning('\'/member-get field=\' argument required!');1343 toastr.warning(t`'/member-get field=' argument required!`);
1346 return '';1344 return '';
1347 }1345 }
1348 field = field.toString();1346 field = field.toString();
1349 arg = arg.toString();1347 arg = arg.toString();
1350 if (!['name', 'index', 'id', 'avatar'].includes(field)) {1348 if (!['name', 'index', 'id', 'avatar'].includes(field)) {
1351 toastr.warning('\'/member-get field=\' argument required!');1349 toastr.warning(t`'/member-get field=' argument required!`);
1352 return '';1350 return '';
1353 }1351 }
1354 const isId = !isNaN(parseInt(arg));1352 const isId = !isNaN(parseInt(arg));
1355 const groupMember = findGroupMemberId(arg, true);1353 const groupMember = findGroupMemberId(arg, true);
1356 if (!groupMember) {1354 if (!groupMember) {
1357 toastr.warning(`No group member found using ${isId ? 'id' : 'string'} ${arg}`);1355 toastr.warning(t`No group member found using ${isId ? 'id' : 'string'} ${arg}`);
1358 return '';1356 return '';
1359 }1357 }
1360 return groupMember[field];1358 return groupMember[field];
@@ -1362,27 +1360,27 @@ export function initDefaultSlashCommands() {
1362 namedArgumentList: [1360 namedArgumentList: [
1363 SlashCommandNamedArgument.fromProps({1361 SlashCommandNamedArgument.fromProps({
1364 name: 'field',1362 name: 'field',
1365 description: 'Whether to retrieve the name, index, id, or avatar.',1363 description: t`Whether to retrieve the name, index, id, or avatar.`,
1366 typeList: [ARGUMENT_TYPE.STRING],1364 typeList: [ARGUMENT_TYPE.STRING],
1367 isRequired: true,1365 isRequired: true,
1368 defaultValue: 'name',1366 defaultValue: 'name',
1369 enumList: [1367 enumList: [
1370 new SlashCommandEnumValue('name', 'Character name'),1368 new SlashCommandEnumValue('name', t`Character name`),
1371 new SlashCommandEnumValue('index', 'Group member index'),1369 new SlashCommandEnumValue('index', t`Group member index`),
1372 new SlashCommandEnumValue('avatar', 'Character avatar'),1370 new SlashCommandEnumValue('avatar', t`Character avatar`),
1373 new SlashCommandEnumValue('id', 'Character index'),1371 new SlashCommandEnumValue('id', t`Character index`),
1374 ],1372 ],
1375 }),1373 }),
1376 ],1374 ],
1377 unnamedArgumentList: [1375 unnamedArgumentList: [
1378 SlashCommandArgument.fromProps({1376 SlashCommandArgument.fromProps({
1379 description: 'member index (starts with 0), name, or avatar',1377 description: t`member index (starts with 0), name, or avatar`,
1380 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],1378 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
1381 isRequired: true,1379 isRequired: true,
1382 enumProvider: commonEnumProviders.groupMembers(),1380 enumProvider: commonEnumProviders.groupMembers(),
1383 }),1381 }),
1384 ],1382 ],
1385 helpString: 'Retrieves a group member\'s name, index, id, or avatar.',1383 helpString: t`Retrieves a group member's name, index, id, or avatar.`,
1386 }));1384 }));
1387 SlashCommandParser.addCommandObject(SlashCommand.fromProps({1385 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
1388 name: 'member-disable',1386 name: 'member-disable',
@@ -1390,13 +1388,13 @@ export function initDefaultSlashCommands() {
1390 aliases: ['disable', 'disablemember', 'memberdisable'],1388 aliases: ['disable', 'disablemember', 'memberdisable'],
1391 unnamedArgumentList: [1389 unnamedArgumentList: [
1392 SlashCommandArgument.fromProps({1390 SlashCommandArgument.fromProps({
1393 description: 'member index (starts with 0) or name',1391 description: t`member index (starts with 0) or name`,
1394 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],1392 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
1395 isRequired: true,1393 isRequired: true,
1396 enumProvider: commonEnumProviders.groupMembers(),1394 enumProvider: commonEnumProviders.groupMembers(),
1397 }),1395 }),
1398 ],1396 ],
1399 helpString: 'Disables a group member from being drafted for replies.',1397 helpString: t`Disables a group member from being drafted for replies.`,
1400 }));1398 }));
1401 SlashCommandParser.addCommandObject(SlashCommand.fromProps({1399 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
1402 name: 'member-enable',1400 name: 'member-enable',
@@ -1404,13 +1402,13 @@ export function initDefaultSlashCommands() {
1404 callback: enableGroupMemberCallback,1402 callback: enableGroupMemberCallback,
1405 unnamedArgumentList: [1403 unnamedArgumentList: [
1406 SlashCommandArgument.fromProps({1404 SlashCommandArgument.fromProps({
1407 description: 'member index (starts with 0) or name',1405 description: t`member index (starts with 0) or name`,
1408 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],1406 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
1409 isRequired: true,1407 isRequired: true,
1410 enumProvider: commonEnumProviders.groupMembers(),1408 enumProvider: commonEnumProviders.groupMembers(),
1411 }),1409 }),
1412 ],1410 ],
1413 helpString: 'Enables a group member to be drafted for replies.',1411 helpString: t`Enables a group member to be drafted for replies.`,
1414 }));1412 }));
1415 SlashCommandParser.addCommandObject(SlashCommand.fromProps({1413 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
1416 name: 'member-add',1414 name: 'member-add',
@@ -1418,7 +1416,7 @@ export function initDefaultSlashCommands() {
1418 aliases: ['addmember', 'memberadd'],1416 aliases: ['addmember', 'memberadd'],
1419 unnamedArgumentList: [1417 unnamedArgumentList: [
1420 SlashCommandArgument.fromProps({1418 SlashCommandArgument.fromProps({
1421 description: 'Character name - or unique character identifier (avatar key)',1419 description: t`Character name - or unique character identifier (avatar key)`,
1422 typeList: [ARGUMENT_TYPE.STRING],1420 typeList: [ARGUMENT_TYPE.STRING],
1423 isRequired: true,1421 isRequired: true,
1424 enumProvider: () => selected_group ? commonEnumProviders.characters('character')() : [],1422 enumProvider: () => selected_group ? commonEnumProviders.characters('character')() : [],
@@ -1426,10 +1424,10 @@ export function initDefaultSlashCommands() {
1426 ],1424 ],
1427 helpString: `1425 helpString: `
1428 <div>1426 <div>
1429 Adds a new group member to the group chat.1427 ${t`Adds a new group member to the group chat.`}
1430 </div>1428 </div>
1431 <div>1429 <div>
1432 <strong>Example:</strong>1430 <strong>${t`Example:`}</strong>
1433 <ul>1431 <ul>
1434 <li>1432 <li>
1435 <pre><code>/member-add John Doe</code></pre>1433 <pre><code>/member-add John Doe</code></pre>
@@ -1444,7 +1442,7 @@ export function initDefaultSlashCommands() {
1444 aliases: ['removemember', 'memberremove'],1442 aliases: ['removemember', 'memberremove'],
1445 unnamedArgumentList: [1443 unnamedArgumentList: [
1446 SlashCommandArgument.fromProps({1444 SlashCommandArgument.fromProps({
1447 description: 'member index (starts with 0) or name',1445 description: t`member index (starts with 0) or name`,
1448 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],1446 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
1449 isRequired: true,1447 isRequired: true,
1450 enumProvider: commonEnumProviders.groupMembers(),1448 enumProvider: commonEnumProviders.groupMembers(),
@@ -1452,10 +1450,10 @@ export function initDefaultSlashCommands() {
1452 ],1450 ],
1453 helpString: `1451 helpString: `
1454 <div>1452 <div>
1455 Removes a group member from the group chat.1453 ${t`Removes a group member from the group chat.`}
1456 </div>1454 </div>
1457 <div>1455 <div>
1458 <strong>Example:</strong>1456 <strong>${t`Example:`}</strong>
1459 <ul>1457 <ul>
1460 <li>1458 <li>
1461 <pre><code>/member-remove 2</code></pre>1459 <pre><code>/member-remove 2</code></pre>
@@ -1471,13 +1469,13 @@ export function initDefaultSlashCommands() {
1471 aliases: ['upmember', 'memberup'],1469 aliases: ['upmember', 'memberup'],
1472 unnamedArgumentList: [1470 unnamedArgumentList: [
1473 SlashCommandArgument.fromProps({1471 SlashCommandArgument.fromProps({
1474 description: 'member index (starts with 0) or name',1472 description: t`member index (starts with 0) or name`,
1475 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],1473 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
1476 isRequired: true,1474 isRequired: true,
1477 enumProvider: commonEnumProviders.groupMembers(),1475 enumProvider: commonEnumProviders.groupMembers(),
1478 }),1476 }),
1479 ],1477 ],
1480 helpString: 'Moves a group member up in the group chat list.',1478 helpString: t`Moves a group member up in the group chat list.`,
1481 }));1479 }));
1482 SlashCommandParser.addCommandObject(SlashCommand.fromProps({1480 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
1483 name: 'member-down',1481 name: 'member-down',
@@ -1485,13 +1483,13 @@ export function initDefaultSlashCommands() {
1485 aliases: ['downmember', 'memberdown'],1483 aliases: ['downmember', 'memberdown'],
1486 unnamedArgumentList: [1484 unnamedArgumentList: [
1487 SlashCommandArgument.fromProps({1485 SlashCommandArgument.fromProps({
1488 description: 'member index (starts with 0) or name',1486 description: t`member index (starts with 0) or name`,
1489 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],1487 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
1490 isRequired: true,1488 isRequired: true,
1491 enumProvider: commonEnumProviders.groupMembers(),1489 enumProvider: commonEnumProviders.groupMembers(),
1492 }),1490 }),
1493 ],1491 ],
1494 helpString: 'Moves a group member down in the group chat list.',1492 helpString: t`Moves a group member down in the group chat list.`,
1495 }));1493 }));
1496 SlashCommandParser.addCommandObject(SlashCommand.fromProps({1494 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
1497 name: 'member-peek',1495 name: 'member-peek',
@@ -1499,7 +1497,7 @@ export function initDefaultSlashCommands() {
1499 callback: peekCallback,1497 callback: peekCallback,
1500 unnamedArgumentList: [1498 unnamedArgumentList: [
1501 SlashCommandArgument.fromProps({1499 SlashCommandArgument.fromProps({
1502 description: 'member index (starts with 0) or name',1500 description: t`member index (starts with 0) or name`,
1503 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],1501 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
1504 isRequired: true,1502 isRequired: true,
1505 enumProvider: commonEnumProviders.groupMembers(),1503 enumProvider: commonEnumProviders.groupMembers(),
@@ -1507,14 +1505,14 @@ export function initDefaultSlashCommands() {
1507 ],1505 ],
1508 helpString: `1506 helpString: `
1509 <div>1507 <div>
1510 Shows a group member character card without switching chats.1508 ${t`Shows a group member character card without switching chats.`}
1511 </div>1509 </div>
1512 <div>1510 <div>
1513 <strong>Examples:</strong>1511 <strong>${t`Examples:`}</strong>
1514 <ul>1512 <ul>
1515 <li>1513 <li>
1516 <pre><code>/peek Gloria</code></pre>1514 <pre><code>/peek Gloria</code></pre>
1517 Shows the character card for the character named "Gloria".1515 ${t`Shows the character card for the character named "Gloria".`}
1518 </li>1516 </li>
1519 </ul>1517 </ul>
1520 </div>1518 </div>
@@ -1524,16 +1522,16 @@ export function initDefaultSlashCommands() {
1524 name: 'member-count',1522 name: 'member-count',
1525 callback: countGroupMemberCallback,1523 callback: countGroupMemberCallback,
1526 aliases: ['countmember', 'membercount'],1524 aliases: ['countmember', 'membercount'],
1527 helpString: 'Returns the total number of group members in the group chat list.',1525 helpString: t`Returns the total number of group members in the group chat list.`,
1528 }));1526 }));
1529 SlashCommandParser.addCommandObject(SlashCommand.fromProps({1527 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
1530 name: 'delswipe',1528 name: 'delswipe',
1531 callback: deleteSwipeCallback,1529 callback: deleteSwipeCallback,
1532 returns: 'the new, currently selected swipe id',1530 returns: t`the new, currently selected swipe id`,
1533 aliases: ['swipedel'],1531 aliases: ['swipedel'],
1534 unnamedArgumentList: [1532 unnamedArgumentList: [
1535 SlashCommandArgument.fromProps({1533 SlashCommandArgument.fromProps({
1536 description: '1-based swipe id',1534 description: t`1-based swipe id`,
1537 typeList: [ARGUMENT_TYPE.NUMBER],1535 typeList: [ARGUMENT_TYPE.NUMBER],
1538 isRequired: true,1536 isRequired: true,
1539 enumProvider: () => Array.isArray(chat[chat.length - 1]?.swipes) ?1537 enumProvider: () => Array.isArray(chat[chat.length - 1]?.swipes) ?
@@ -1543,18 +1541,18 @@ export function initDefaultSlashCommands() {
1543 ],1541 ],
1544 helpString: `1542 helpString: `
1545 <div>1543 <div>
1546 Deletes a swipe from the last chat message. If swipe id is not provided, it deletes the current swipe.1544 ${t`Deletes a swipe from the last chat message. If swipe id is not provided, it deletes the current swipe.`}
1547 </div>1545 </div>
1548 <div>1546 <div>
1549 <strong>Example:</strong>1547 <strong>${t`Example:`}</strong>
1550 <ul>1548 <ul>
1551 <li>1549 <li>
1552 <pre><code>/delswipe</code></pre>1550 <pre><code>/delswipe</code></pre>
1553 Deletes the current swipe.1551 ${t`Deletes the current swipe.`}
1554 </li>1552 </li>
1555 <li>1553 <li>
1556 <pre><code>/delswipe 2</code></pre>1554 <pre><code>/delswipe 2</code></pre>
1557 Deletes the second swipe from the last chat message.1555 ${t`Deletes the second swipe from the last chat message.`}
1558 </li>1556 </li>
1559 </ul>1557 </ul>
1560 </div>1558 </div>
@@ -1564,14 +1562,14 @@ export function initDefaultSlashCommands() {
1564 name: 'echo',1562 name: 'echo',
1565 rawQuotes: true,1563 rawQuotes: true,
1566 callback: echoCallback,1564 callback: echoCallback,
1567 returns: 'the text',1565 returns: t`the text`,
1568 namedArgumentList: [1566 namedArgumentList: [
1569 new SlashCommandNamedArgument(1567 new SlashCommandNamedArgument(
1570 'title', 'title of the toast message', [ARGUMENT_TYPE.STRING], false,1568 'title', t`title of the toast message`, [ARGUMENT_TYPE.STRING], false,
1571 ),1569 ),
1572 SlashCommandNamedArgument.fromProps({1570 SlashCommandNamedArgument.fromProps({
1573 name: 'severity',1571 name: 'severity',
1574 description: 'severity level of the toast message',1572 description: t`severity level of the toast message`,
1575 typeList: [ARGUMENT_TYPE.STRING],1573 typeList: [ARGUMENT_TYPE.STRING],
1576 defaultValue: 'info',1574 defaultValue: 'info',
1577 enumProvider: () => [1575 enumProvider: () => [
@@ -1583,54 +1581,54 @@ export function initDefaultSlashCommands() {
1583 }),1581 }),
1584 SlashCommandNamedArgument.fromProps({1582 SlashCommandNamedArgument.fromProps({
1585 name: 'timeout',1583 name: 'timeout',
1586 description: 'time in milliseconds to display the toast message. Set this and \'extendedTimeout\' to 0 to show indefinitely until dismissed.',1584 description: t`time in milliseconds to display the toast message. Set this and 'extendedTimeout' to 0 to show indefinitely until dismissed.`,
1587 typeList: [ARGUMENT_TYPE.NUMBER],1585 typeList: [ARGUMENT_TYPE.NUMBER],
1588 defaultValue: `${toastr.options.timeOut}`,1586 defaultValue: `${toastr.options.timeOut}`,
1589 }),1587 }),
1590 SlashCommandNamedArgument.fromProps({1588 SlashCommandNamedArgument.fromProps({
1591 name: 'extendedTimeout',1589 name: 'extendedTimeout',
1592 description: 'time in milliseconds to display the toast message. Set this and \'timeout\' to 0 to show indefinitely until dismissed.',1590 description: t`time in milliseconds to display the toast message. Set this and 'timeout' to 0 to show indefinitely until dismissed.`,
1593 typeList: [ARGUMENT_TYPE.NUMBER],1591 typeList: [ARGUMENT_TYPE.NUMBER],
1594 defaultValue: `${toastr.options.extendedTimeOut}`,1592 defaultValue: `${toastr.options.extendedTimeOut}`,
1595 }),1593 }),
1596 SlashCommandNamedArgument.fromProps({1594 SlashCommandNamedArgument.fromProps({
1597 name: 'preventDuplicates',1595 name: 'preventDuplicates',
1598 description: 'prevent duplicate toasts with the same message from being displayed.',1596 description: t`prevent duplicate toasts with the same message from being displayed.`,
1599 typeList: [ARGUMENT_TYPE.BOOLEAN],1597 typeList: [ARGUMENT_TYPE.BOOLEAN],
1600 defaultValue: 'false',1598 defaultValue: 'false',
1601 enumList: commonEnumProviders.boolean('trueFalse')(),1599 enumList: commonEnumProviders.boolean('trueFalse')(),
1602 }),1600 }),
1603 SlashCommandNamedArgument.fromProps({1601 SlashCommandNamedArgument.fromProps({
1604 name: 'awaitDismissal',1602 name: 'awaitDismissal',
1605 description: 'wait for the toast to be dismissed before continuing.',1603 description: t`wait for the toast to be dismissed before continuing.`,
1606 typeList: [ARGUMENT_TYPE.BOOLEAN],1604 typeList: [ARGUMENT_TYPE.BOOLEAN],
1607 defaultValue: 'false',1605 defaultValue: 'false',
1608 enumList: commonEnumProviders.boolean('trueFalse')(),1606 enumList: commonEnumProviders.boolean('trueFalse')(),
1609 }),1607 }),
1610 SlashCommandNamedArgument.fromProps({1608 SlashCommandNamedArgument.fromProps({
1611 name: 'cssClass',1609 name: 'cssClass',
1612 description: 'additional CSS class to add to the toast message (e.g. for custom styling)',1610 description: t`additional CSS class to add to the toast message (e.g. for custom styling)`,
1613 typeList: [ARGUMENT_TYPE.STRING],1611 typeList: [ARGUMENT_TYPE.STRING],
1614 }),1612 }),
1615 SlashCommandNamedArgument.fromProps({1613 SlashCommandNamedArgument.fromProps({
1616 name: 'color',1614 name: 'color',
1617 description: '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.',1615 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.`,
1618 }),1616 }),
1619 SlashCommandNamedArgument.fromProps({1617 SlashCommandNamedArgument.fromProps({
1620 name: 'escapeHtml',1618 name: 'escapeHtml',
1621 description: 'whether to escape HTML in the toast message.',1619 description: t`whether to escape HTML in the toast message.`,
1622 typeList: [ARGUMENT_TYPE.BOOLEAN],1620 typeList: [ARGUMENT_TYPE.BOOLEAN],
1623 defaultValue: 'true',1621 defaultValue: 'true',
1624 enumList: commonEnumProviders.boolean('trueFalse')(),1622 enumList: commonEnumProviders.boolean('trueFalse')(),
1625 }),1623 }),
1626 SlashCommandNamedArgument.fromProps({1624 SlashCommandNamedArgument.fromProps({
1627 name: 'onClick',1625 name: 'onClick',
1628 description: '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.',1626 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.`,
1629 typeList: [ARGUMENT_TYPE.CLOSURE],1627 typeList: [ARGUMENT_TYPE.CLOSURE],
1630 }),1628 }),
1631 SlashCommandNamedArgument.fromProps({1629 SlashCommandNamedArgument.fromProps({
1632 name: 'raw',1630 name: 'raw',
1633 description: 'If true, does not alter quoted literal unnamed arguments',1631 description: t`If true, does not alter quoted literal unnamed arguments`,
1634 typeList: [ARGUMENT_TYPE.BOOLEAN],1632 typeList: [ARGUMENT_TYPE.BOOLEAN],
1635 defaultValue: 'true',1633 defaultValue: 'true',
1636 enumProvider: commonEnumProviders.boolean('trueFalse'),1634 enumProvider: commonEnumProviders.boolean('trueFalse'),
@@ -1665,32 +1663,32 @@ export function initDefaultSlashCommands() {
1665 SlashCommandParser.addCommandObject(SlashCommand.fromProps({1663 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
1666 name: 'gen',1664 name: 'gen',
1667 callback: generateCallback,1665 callback: generateCallback,
1668 returns: 'generated text',1666 returns: t`generated text`,
1669 namedArgumentList: [1667 namedArgumentList: [
1670 SlashCommandNamedArgument.fromProps({1668 SlashCommandNamedArgument.fromProps({
1671 name: 'trim',1669 name: 'trim',
1672 description: 'Trim the output by the last sentence boundary',1670 description: t`Trim the output by the last sentence boundary`,
1673 typeList: [ARGUMENT_TYPE.BOOLEAN],1671 typeList: [ARGUMENT_TYPE.BOOLEAN],
1674 defaultValue: 'false',1672 defaultValue: 'false',
1675 isRequired: false,1673 isRequired: false,
1676 enumProvider: commonEnumProviders.boolean('trueFalse'),1674 enumProvider: commonEnumProviders.boolean('trueFalse'),
1677 }),1675 }),
1678 new SlashCommandNamedArgument(1676 new SlashCommandNamedArgument(
1679 'lock', 'lock user input during generation', [ARGUMENT_TYPE.BOOLEAN], false, false, null, commonEnumProviders.boolean('onOff')(),1677 'lock', t`lock user input during generation`, [ARGUMENT_TYPE.BOOLEAN], false, false, null, commonEnumProviders.boolean('onOff')(),
1680 ),1678 ),
1681 SlashCommandNamedArgument.fromProps({1679 SlashCommandNamedArgument.fromProps({
1682 name: 'name',1680 name: 'name',
1683 description: 'in-prompt character name for instruct mode (or unique character identifier (avatar key), which will be used as name)',1681 description: t`in-prompt character name for instruct mode (or unique character identifier (avatar key), which will be used as name)`,
1684 typeList: [ARGUMENT_TYPE.STRING],1682 typeList: [ARGUMENT_TYPE.STRING],
1685 defaultValue: 'System',1683 defaultValue: 'System',
1686 enumProvider: () => [...commonEnumProviders.characters('character')(), new SlashCommandEnumValue('System', null, enumTypes.enum, enumIcons.assistant)],1684 enumProvider: () => [...commonEnumProviders.characters('character')(), new SlashCommandEnumValue('System', null, enumTypes.enum, enumIcons.assistant)],
1687 }),1685 }),
1688 new SlashCommandNamedArgument(1686 new SlashCommandNamedArgument(
1689 'length', 'API response length in tokens', [ARGUMENT_TYPE.NUMBER], false,1687 'length', t`API response length in tokens`, [ARGUMENT_TYPE.NUMBER], false,
1690 ),1688 ),
1691 SlashCommandNamedArgument.fromProps({1689 SlashCommandNamedArgument.fromProps({
1692 name: 'as',1690 name: 'as',
1693 description: 'role of the output prompt',1691 description: t`role of the output prompt`,
1694 typeList: [ARGUMENT_TYPE.STRING],1692 typeList: [ARGUMENT_TYPE.STRING],
1695 enumList: [1693 enumList: [
1696 new SlashCommandEnumValue('system', null, enumTypes.enum, enumIcons.assistant),1694 new SlashCommandEnumValue('system', null, enumTypes.enum, enumIcons.assistant),
@@ -1705,30 +1703,30 @@ export function initDefaultSlashCommands() {
1705 ],1703 ],
1706 helpString: `1704 helpString: `
1707 <div>1705 <div>
1708 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").1706 ${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").`}
1709 </div>1707 </div>
1710 <div>1708 <div>
1711 "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.1709 ${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.`}
1712 </div>1710 </div>
1713 `,1711 `,
1714 }));1712 }));
1715 SlashCommandParser.addCommandObject(SlashCommand.fromProps({1713 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
1716 name: 'genraw',1714 name: 'genraw',
1717 callback: generateRawCallback,1715 callback: generateRawCallback,
1718 returns: 'generated text',1716 returns: t`generated text`,
1719 namedArgumentList: [1717 namedArgumentList: [
1720 new SlashCommandNamedArgument(1718 new SlashCommandNamedArgument(
1721 'lock', 'lock user input during generation', [ARGUMENT_TYPE.BOOLEAN], false, false, 'off', commonEnumProviders.boolean('onOff')(),1719 'lock', t`lock user input during generation`, [ARGUMENT_TYPE.BOOLEAN], false, false, 'off', commonEnumProviders.boolean('onOff')(),
1722 ),1720 ),
1723 new SlashCommandNamedArgument(1721 new SlashCommandNamedArgument(
1724 'instruct', 'use instruct mode', [ARGUMENT_TYPE.BOOLEAN], false, false, 'on', commonEnumProviders.boolean('onOff')(),1722 'instruct', t`use instruct mode`, [ARGUMENT_TYPE.BOOLEAN], false, false, 'on', commonEnumProviders.boolean('onOff')(),
1725 ),1723 ),
1726 new SlashCommandNamedArgument(1724 new SlashCommandNamedArgument(
1727 'stop', 'one-time custom stop strings', [ARGUMENT_TYPE.LIST], false, false, '[]',1725 'stop', t`one-time custom stop strings`, [ARGUMENT_TYPE.LIST], false, false, '[]',
1728 ),1726 ),
1729 SlashCommandNamedArgument.fromProps({1727 SlashCommandNamedArgument.fromProps({
1730 name: 'as',1728 name: 'as',
1731 description: 'role of the output prompt',1729 description: t`role of the output prompt`,
1732 defaultValue: 'system',1730 defaultValue: 'system',
1733 typeList: [ARGUMENT_TYPE.STRING],1731 typeList: [ARGUMENT_TYPE.STRING],
1734 enumList: [1732 enumList: [
@@ -1737,16 +1735,16 @@ export function initDefaultSlashCommands() {
1737 ],1735 ],
1738 }),1736 }),
1739 new SlashCommandNamedArgument(1737 new SlashCommandNamedArgument(
1740 'system', 'system prompt at the start', [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME], false,1738 'system', t`system prompt at the start`, [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME], false,
1741 ),1739 ),
1742 new SlashCommandNamedArgument(1740 new SlashCommandNamedArgument(
1743 'prefill', 'prefill prompt at the end', [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME], false,1741 'prefill', t`prefill prompt at the end`, [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME], false,
1744 ),1742 ),
1745 new SlashCommandNamedArgument(1743 new SlashCommandNamedArgument(
1746 'length', 'API response length in tokens', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME], false,1744 'length', t`API response length in tokens`, [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME], false,
1747 ),1745 ),
1748 new SlashCommandNamedArgument(1746 new SlashCommandNamedArgument(
1749 'trim', 'trim {{user}} and {{char}} prefixes from the output', [ARGUMENT_TYPE.BOOLEAN], false, false, 'on', commonEnumProviders.boolean('onOff')(),1747 'trim', t`trim {{user}} and {{char}} prefixes from the output`, [ARGUMENT_TYPE.BOOLEAN], false, false, 'on', commonEnumProviders.boolean('onOff')(),
1750 ),1748 ),
1751 ],1749 ],
1752 unnamedArgumentList: [1750 unnamedArgumentList: [
@@ -1756,31 +1754,31 @@ export function initDefaultSlashCommands() {
1756 ],1754 ],
1757 helpString: `1755 helpString: `
1758 <div>1756 <div>
1759 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.1757 ${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.`}
1760 </div>1758 </div>
1761 <div>1759 <div>
1762 Use instruct=off to skip instruct formatting, e.g. <pre><code>/genraw instruct=off Why is the sky blue?</code></pre>1760 ${t`Use instruct=off to skip instruct formatting, e.g. <pre><code>/genraw instruct=off Why is the sky blue?</code></pre>`}
1763 </div>1761 </div>
1764 <div>1762 <div>
1765 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>1763 ${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>`}
1766 </div>1764 </div>
1767 <div>1765 <div>
1768 "as" argument controls the role of the output prompt: system (default) or char. "system" argument adds an (optional) system prompt at the start.1766 ${t`"as" argument controls the role of the output prompt: system (default) or char. "system" argument adds an (optional) system prompt at the start.`}
1769 </div>1767 </div>
1770 <div>1768 <div>
1771 If "length" argument is provided as a number in tokens, allows to temporarily override an API response length.1769 ${t`If "length" argument is provided as a number in tokens, allows to temporarily override an API response length.`}
1772 </div>1770 </div>
1773 `,1771 `,
1774 }));1772 }));
1775 SlashCommandParser.addCommandObject(SlashCommand.fromProps({1773 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
1776 name: 'addswipe',1774 name: 'addswipe',
1777 callback: addSwipeCallback,1775 callback: addSwipeCallback,
1778 returns: 'the new swipe id',1776 returns: t`the new swipe id`,
1779 aliases: ['swipeadd'],1777 aliases: ['swipeadd'],
1780 namedArgumentList: [1778 namedArgumentList: [
1781 SlashCommandNamedArgument.fromProps({1779 SlashCommandNamedArgument.fromProps({
1782 name: 'switch',1780 name: 'switch',
1783 description: 'switch to the new swipe',1781 description: t`switch to the new swipe`,
1784 typeList: [ARGUMENT_TYPE.BOOLEAN],1782 typeList: [ARGUMENT_TYPE.BOOLEAN],
1785 enumList: commonEnumProviders.boolean()(),1783 enumList: commonEnumProviders.boolean()(),
1786 }),1784 }),
@@ -1792,10 +1790,10 @@ export function initDefaultSlashCommands() {
1792 ],1790 ],
1793 helpString: `1791 helpString: `
1794 <div>1792 <div>
1795 Adds a swipe to the last chat message.1793 ${t`Adds a swipe to the last chat message.`}
1796 </div>1794 </div>
1797 <div>1795 <div>
1798 Use switch=true to switch to directly switch to the new swipe.1796 ${t`Use switch=true to switch to directly switch to the new swipe.`}
1799 </div>`,1797 </div>`,
1800 }));1798 }));
1801 SlashCommandParser.addCommandObject(SlashCommand.fromProps({1799 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
@@ -1804,14 +1802,13 @@ export function initDefaultSlashCommands() {
1804 const stopped = stopGeneration();1802 const stopped = stopGeneration();
1805 return String(stopped);1803 return String(stopped);
1806 },1804 },
1807 returns: 'true/false, whether the generation was running and got stopped',1805 returns: t`true/false, whether the generation was running and got stopped`,
1808 helpString: `1806 helpString: `
1809 <div>1807 <div>
1810 Stops the generation and any streaming if it is currently running.1808 ${t`Stops the generation and any streaming if it is currently running.`}
1811 </div>1809 </div>
1812 <div>1810 <div>
1813 Note: This command cannot be executed from the chat input, as sending any message or script from there is blocked during generation.1811 ${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.
1815 </div>1812 </div>
1816 `,1813 `,
1817 aliases: ['generate-stop'],1814 aliases: ['generate-stop'],
@@ -1822,27 +1819,27 @@ export function initDefaultSlashCommands() {
1822 namedArgumentList: [1819 namedArgumentList: [
1823 SlashCommandNamedArgument.fromProps({1820 SlashCommandNamedArgument.fromProps({
1824 name: 'quiet',1821 name: 'quiet',
1825 description: 'Whether to suppress the toast message notifying about the /abort call.',1822 description: t`Whether to suppress the toast message notifying about the /abort call.`,
1826 typeList: [ARGUMENT_TYPE.BOOLEAN],1823 typeList: [ARGUMENT_TYPE.BOOLEAN],
1827 defaultValue: 'true',1824 defaultValue: 'true',
1828 }),1825 }),
1829 ],1826 ],
1830 unnamedArgumentList: [1827 unnamedArgumentList: [
1831 SlashCommandArgument.fromProps({1828 SlashCommandArgument.fromProps({
1832 description: 'The reason for aborting command execution. Shown when quiet=false',1829 description: t`The reason for aborting command execution. Shown when quiet=false`,
1833 typeList: [ARGUMENT_TYPE.STRING],1830 typeList: [ARGUMENT_TYPE.STRING],
1834 }),1831 }),
1835 ],1832 ],
1836 helpString: 'Aborts the slash command batch execution.',1833 helpString: t`Aborts the slash command batch execution.`,
1837 }));1834 }));
1838 SlashCommandParser.addCommandObject(SlashCommand.fromProps({1835 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
1839 name: 'fuzzy',1836 name: 'fuzzy',
1840 callback: fuzzyCallback,1837 callback: fuzzyCallback,
1841 returns: 'matching item',1838 returns: t`matching item`,
1842 namedArgumentList: [1839 namedArgumentList: [
1843 SlashCommandNamedArgument.fromProps({1840 SlashCommandNamedArgument.fromProps({
1844 name: 'list',1841 name: 'list',
1845 description: 'list of items to match against',1842 description: t`list of items to match against`,
1846 acceptsMultiple: false,1843 acceptsMultiple: false,
1847 isRequired: true,1844 isRequired: true,
1848 typeList: [ARGUMENT_TYPE.LIST, ARGUMENT_TYPE.VARIABLE_NAME],1845 typeList: [ARGUMENT_TYPE.LIST, ARGUMENT_TYPE.VARIABLE_NAME],
@@ -1850,7 +1847,7 @@ export function initDefaultSlashCommands() {
1850 }),1847 }),
1851 SlashCommandNamedArgument.fromProps({1848 SlashCommandNamedArgument.fromProps({
1852 name: 'threshold',1849 name: 'threshold',
1853 description: 'fuzzy match threshold (0.0 to 1.0)',1850 description: t`fuzzy match threshold (0.0 to 1.0)`,
1854 typeList: [ARGUMENT_TYPE.NUMBER],1851 typeList: [ARGUMENT_TYPE.NUMBER],
1855 isRequired: false,1852 isRequired: false,
1856 defaultValue: '0.4',1853 defaultValue: '0.4',
@@ -1858,44 +1855,43 @@ export function initDefaultSlashCommands() {
1858 }),1855 }),
1859 SlashCommandNamedArgument.fromProps({1856 SlashCommandNamedArgument.fromProps({
1860 name: 'mode',1857 name: 'mode',
1861 description: 'fuzzy match mode',1858 description: t`fuzzy match mode`,
1862 typeList: [ARGUMENT_TYPE.STRING],1859 typeList: [ARGUMENT_TYPE.STRING],
1863 isRequired: false,1860 isRequired: false,
1864 defaultValue: 'first',1861 defaultValue: 'first',
1865 acceptsMultiple: false,1862 acceptsMultiple: false,
1866 enumList: [1863 enumList: [
1867 new SlashCommandEnumValue('first', 'first match below the threshold', enumTypes.enum, enumIcons.default),1864 new SlashCommandEnumValue('first', t`first match below the threshold`, enumTypes.enum, enumIcons.default),
1868 new SlashCommandEnumValue('best', 'best match below the threshold', enumTypes.enum, enumIcons.default),1865 new SlashCommandEnumValue('best', t`best match below the threshold`, enumTypes.enum, enumIcons.default),
1869 ],1866 ],
1870 }),1867 }),
1871 ],1868 ],
1872 unnamedArgumentList: [1869 unnamedArgumentList: [
1873 new SlashCommandArgument(1870 new SlashCommandArgument(
1874 'text to search', [ARGUMENT_TYPE.STRING], true,1871 t`text to search`, [ARGUMENT_TYPE.STRING], true,
1875 ),1872 ),
1876 ],1873 ],
1877 helpString: `1874 helpString: `
1878 <div>1875 <div>
1879 Performs a fuzzy match of each item in the <code>list</code> against the <code>text to search</code>.1876 ${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.
1881 </div>1877 </div>
1882 <div>1878 <div>
1883 The optional <code>threshold</code> (default is 0.4) allows control over the match strictness.1879 ${t`The optional <code>threshold</code> (default is 0.4) allows control over the match strictness.`}
1884 A low value (min 0.0) means the match is very strict.1880 ${t`A low value (min 0.0) means the match is very strict.`}
1885 At 1.0 (max) the match is very loose and will match anything.1881 ${t`At 1.0 (max) the match is very loose and will match anything.`}
1886 </div>1882 </div>
1887 <div>1883 <div>
1888 The optional <code>mode</code> argument allows to control the behavior when multiple items match the text.1884 ${t`The optional <code>mode</code> argument allows to control the behavior when multiple items match the text.`}
1889 <ul>1885 <ul>
1890 <li><code>first</code> (default) returns the first match below the threshold.</li>1886 <li>${t`<code>first</code> (default) returns the first match below the threshold.`}</li>
1891 <li><code>best</code> returns the best match below the threshold.</li>1887 <li>${t`<code>best</code> returns the best match below the threshold.`}</li>
1892 </ul>1888 </ul>
1893 </div>1889 </div>
1894 <div>1890 <div>
1895 The returned value passes to the next command through the pipe.1891 ${t`The returned value passes to the next command through the pipe.`}
1896 </div>1892 </div>
1897 <div>1893 <div>
1898 <strong>Example:</strong>1894 <strong>${t`Example:`}</strong>
1899 <ul>1895 <ul>
1900 <li>1896 <li>
1901 <pre><code>/fuzzy list=["a","b","c"] threshold=0.4 abc</code></pre>1897 <pre><code>/fuzzy list=["a","b","c"] threshold=0.4 abc</code></pre>
@@ -1908,23 +1904,23 @@ export function initDefaultSlashCommands() {
1908 name: 'pass',1904 name: 'pass',
1909 callback: (_, arg) => {1905 callback: (_, arg) => {
1910 // We do not support arrays of closures. Arrays of strings will be send as JSON1906 // We do not support arrays of closures. Arrays of strings will be send as JSON
1911 if (Array.isArray(arg) && arg.some(x => x instanceof SlashCommandClosure)) throw new Error('Command /pass does not support multiple closures');1907 if (Array.isArray(arg) && arg.some(x => x instanceof SlashCommandClosure)) throw new Error(t`Command /pass does not support multiple closures`);
1912 if (Array.isArray(arg)) return JSON.stringify(arg);1908 if (Array.isArray(arg)) return JSON.stringify(arg);
1913 return arg;1909 return arg;
1914 },1910 },
1915 returns: 'the provided value',1911 returns: t`the provided value`,
1916 unnamedArgumentList: [1912 unnamedArgumentList: [
1917 new SlashCommandArgument(1913 new SlashCommandArgument(
1918 'text', [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.BOOLEAN, ARGUMENT_TYPE.LIST, ARGUMENT_TYPE.DICTIONARY, ARGUMENT_TYPE.CLOSURE], true,1914 t`text`, [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.BOOLEAN, ARGUMENT_TYPE.LIST, ARGUMENT_TYPE.DICTIONARY, ARGUMENT_TYPE.CLOSURE], true,
1919 ),1915 ),
1920 ],1916 ],
1921 aliases: ['return'],1917 aliases: ['return'],
1922 helpString: `1918 helpString: `
1923 <div>1919 <div>
1924 <pre><span class="monospace">/pass (text)</span> – passes the text to the next command through the pipe.</pre>1920 <pre><span class="monospace">/pass (text)</span> – ${t`passes the text to the next command through the pipe.`}</pre>
1925 </div>1921 </div>
1926 <div>1922 <div>
1927 <strong>Example:</strong>1923 <strong>${t`Example:`}</strong>
1928 <ul>1924 <ul>
1929 <li><pre><code>/pass Hello world</code></pre></li>1925 <li><pre><code>/pass Hello world</code></pre></li>
1930 </ul>1926 </ul>
@@ -1937,15 +1933,15 @@ export function initDefaultSlashCommands() {
1937 aliases: ['wait', 'sleep'],1933 aliases: ['wait', 'sleep'],
1938 unnamedArgumentList: [1934 unnamedArgumentList: [
1939 new SlashCommandArgument(1935 new SlashCommandArgument(
1940 'milliseconds', [ARGUMENT_TYPE.NUMBER], true,1936 t`milliseconds`, [ARGUMENT_TYPE.NUMBER], true,
1941 ),1937 ),
1942 ],1938 ],
1943 helpString: `1939 helpString: `
1944 <div>1940 <div>
1945 Delays the next command in the pipe by the specified number of milliseconds.1941 ${t`Delays the next command in the pipe by the specified number of milliseconds.`}
1946 </div>1942 </div>
1947 <div>1943 <div>
1948 <strong>Example:</strong>1944 <strong>${t`Example:`}</strong>
1949 <ul>1945 <ul>
1950 <li>1946 <li>
1951 <pre><code>/delay 1000</code></pre>1947 <pre><code>/delay 1000</code></pre>
@@ -1958,59 +1954,59 @@ export function initDefaultSlashCommands() {
1958 name: 'input',1954 name: 'input',
1959 aliases: ['prompt'],1955 aliases: ['prompt'],
1960 callback: inputCallback,1956 callback: inputCallback,
1961 returns: 'user input',1957 returns: t`user input`,
1962 namedArgumentList: [1958 namedArgumentList: [
1963 SlashCommandNamedArgument.fromProps({1959 SlashCommandNamedArgument.fromProps({
1964 name: 'default',1960 name: 'default',
1965 description: 'default value of the input field',1961 description: t`default value of the input field`,
1966 typeList: [ARGUMENT_TYPE.STRING],1962 typeList: [ARGUMENT_TYPE.STRING],
1967 }),1963 }),
1968 SlashCommandNamedArgument.fromProps({1964 SlashCommandNamedArgument.fromProps({
1969 name: 'large',1965 name: 'large',
1970 description: 'popup window will be shown larger in height, with more space for content (input field needs to be sized via \'rows\' argument)',1966 description: t`popup window will be shown larger in height, with more space for content (input field needs to be sized via 'rows' argument)`,
1971 typeList: [ARGUMENT_TYPE.BOOLEAN],1967 typeList: [ARGUMENT_TYPE.BOOLEAN],
1972 defaultValue: 'off',1968 defaultValue: 'off',
1973 enumList: commonEnumProviders.boolean('onOff')(),1969 enumList: commonEnumProviders.boolean('onOff')(),
1974 }),1970 }),
1975 SlashCommandNamedArgument.fromProps({1971 SlashCommandNamedArgument.fromProps({
1976 name: 'wide',1972 name: 'wide',
1977 description: 'popup window will be shown wider, with a wider input field',1973 description: t`popup window will be shown wider, with a wider input field`,
1978 typeList: [ARGUMENT_TYPE.BOOLEAN],1974 typeList: [ARGUMENT_TYPE.BOOLEAN],
1979 defaultValue: 'off',1975 defaultValue: 'off',
1980 enumList: commonEnumProviders.boolean('onOff')(),1976 enumList: commonEnumProviders.boolean('onOff')(),
1981 }),1977 }),
1982 SlashCommandNamedArgument.fromProps({1978 SlashCommandNamedArgument.fromProps({
1983 name: 'okButton',1979 name: 'okButton',
1984 description: 'text for the ok button',1980 description: t`text for the ok button`,
1985 typeList: [ARGUMENT_TYPE.STRING],1981 typeList: [ARGUMENT_TYPE.STRING],
1986 defaultValue: 'Ok',1982 defaultValue: 'Ok',
1987 }),1983 }),
1988 SlashCommandNamedArgument.fromProps({1984 SlashCommandNamedArgument.fromProps({
1989 name: 'rows',1985 name: 'rows',
1990 description: 'number of rows for the input field (lines being displayed)',1986 description: t`number of rows for the input field (lines being displayed)`,
1991 typeList: [ARGUMENT_TYPE.NUMBER],1987 typeList: [ARGUMENT_TYPE.NUMBER],
1992 }),1988 }),
1993 SlashCommandNamedArgument.fromProps({1989 SlashCommandNamedArgument.fromProps({
1994 name: 'onSuccess',1990 name: 'onSuccess',
1995 description: 'closure to execute when the ok button is clicked or the input is closed as successful (via Enter, etc)',1991 description: t`closure to execute when the ok button is clicked or the input is closed as successful (via Enter, etc)`,
1996 typeList: [ARGUMENT_TYPE.CLOSURE],1992 typeList: [ARGUMENT_TYPE.CLOSURE],
1997 }),1993 }),
1998 SlashCommandNamedArgument.fromProps({1994 SlashCommandNamedArgument.fromProps({
1999 name: 'onCancel',1995 name: 'onCancel',
2000 description: 'closure to execute when the cancel button is clicked or the input is closed as cancelled (via Escape, etc)',1996 description: t`closure to execute when the cancel button is clicked or the input is closed as cancelled (via Escape, etc)`,
2001 typeList: [ARGUMENT_TYPE.CLOSURE],1997 typeList: [ARGUMENT_TYPE.CLOSURE],
2002 }),1998 }),
2003 ],1999 ],
2004 unnamedArgumentList: [2000 unnamedArgumentList: [
2005 SlashCommandArgument.fromProps({2001 SlashCommandArgument.fromProps({
2006 description: 'text to display',2002 description: t`text to display`,
2007 typeList: [ARGUMENT_TYPE.STRING],2003 typeList: [ARGUMENT_TYPE.STRING],
2008 }),2004 }),
2009 ],2005 ],
2010 helpString: `2006 helpString: `
2011 <div>2007 <div>
2012 Shows a popup with the provided text and an input field.2008 ${t`Shows a popup with the provided text and an input field.`}
2013 The <code>default</code> argument is the default value of the input field, and the text argument is the text to display.2009 ${t`The <code>default</code> argument is the default value of the input field, and the text argument is the text to display.`}
2014 </div>2010 </div>
2015 `,2011 `,
2016 }));2012 }));
@@ -2018,15 +2014,15 @@ export function initDefaultSlashCommands() {
2018 name: 'run',2014 name: 'run',
2019 aliases: ['call', 'exec'],2015 aliases: ['call', 'exec'],
2020 callback: runCallback,2016 callback: runCallback,
2021 returns: 'result of the executed closure of QR',2017 returns: t`result of the executed closure of QR`,
2022 namedArgumentList: [2018 namedArgumentList: [
2023 new SlashCommandNamedArgument(2019 new SlashCommandNamedArgument(
2024 'args', 'named arguments', [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.BOOLEAN, ARGUMENT_TYPE.LIST, ARGUMENT_TYPE.DICTIONARY], false, true,2020 'args', t`named arguments`, [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.BOOLEAN, ARGUMENT_TYPE.LIST, ARGUMENT_TYPE.DICTIONARY], false, true,
2025 ),2021 ),
2026 ],2022 ],
2027 unnamedArgumentList: [2023 unnamedArgumentList: [
2028 SlashCommandArgument.fromProps({2024 SlashCommandArgument.fromProps({
2029 description: 'scoped variable or qr label',2025 description: t`scoped variable or qr label`,
2030 typeList: [ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.CLOSURE],2026 typeList: [ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.CLOSURE],
2031 isRequired: true,2027 isRequired: true,
2032 enumProvider: (executor, scope) => [2028 enumProvider: (executor, scope) => [
@@ -2037,8 +2033,8 @@ export function initDefaultSlashCommands() {
2037 ],2033 ],
2038 helpString: `2034 helpString: `
2039 <div>2035 <div>
2040 Runs a closure from a scoped variable, or a Quick Reply with the specified name from a currently active preset or from another preset.2036 ${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.`}
2041 Named arguments can be referenced in a QR with <code>{{arg::key}}</code>.2037 ${t`Named arguments can be referenced in a QR with <code>{{arg::key}}</code>.`}
2042 </div>2038 </div>
2043 `,2039 `,
2044 }));2040 }));
@@ -2048,14 +2044,14 @@ export function initDefaultSlashCommands() {
2048 aliases: ['message'],2044 aliases: ['message'],
2049 namedArgumentList: [2045 namedArgumentList: [
2050 new SlashCommandNamedArgument(2046 new SlashCommandNamedArgument(
2051 'names', 'show message author names', [ARGUMENT_TYPE.BOOLEAN], false, false, 'off', commonEnumProviders.boolean('onOff')(),2047 'names', t`show message author names`, [ARGUMENT_TYPE.BOOLEAN], false, false, 'off', commonEnumProviders.boolean('onOff')(),
2052 ),2048 ),
2053 new SlashCommandNamedArgument(2049 new SlashCommandNamedArgument(
2054 'hidden', 'include hidden messages', [ARGUMENT_TYPE.BOOLEAN], false, false, 'on', commonEnumProviders.boolean('onOff')(),2050 'hidden', t`include hidden messages`, [ARGUMENT_TYPE.BOOLEAN], false, false, 'on', commonEnumProviders.boolean('onOff')(),
2055 ),2051 ),
2056 SlashCommandNamedArgument.fromProps({2052 SlashCommandNamedArgument.fromProps({
2057 name: 'role',2053 name: 'role',
2058 description: 'filter messages by role',2054 description: t`filter messages by role`,
2059 typeList: [ARGUMENT_TYPE.STRING],2055 typeList: [ARGUMENT_TYPE.STRING],
2060 enumList: [2056 enumList: [
2061 new SlashCommandEnumValue('system', null, enumTypes.enum, enumIcons.system),2057 new SlashCommandEnumValue('system', null, enumTypes.enum, enumIcons.system),
@@ -2066,33 +2062,33 @@ export function initDefaultSlashCommands() {
2066 ],2062 ],
2067 unnamedArgumentList: [2063 unnamedArgumentList: [
2068 SlashCommandArgument.fromProps({2064 SlashCommandArgument.fromProps({
2069 description: 'message index (starts with 0) or range',2065 description: t`message index (starts with 0) or range`,
2070 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE],2066 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE],
2071 isRequired: true,2067 isRequired: true,
2072 enumProvider: commonEnumProviders.messages(),2068 enumProvider: commonEnumProviders.messages(),
2073 }),2069 }),
2074 ],2070 ],
2075 returns: 'the specified message or range of messages as a string',2071 returns: t`the specified message or range of messages as a string`,
2076 helpString: `2072 helpString: `
2077 <div>2073 <div>
2078 Returns the specified message or range of messages as a string.2074 ${t`Returns the specified message or range of messages as a string.`}
2079 </div>2075 </div>
2080 <div>2076 <div>
2081 Use the <code>hidden=off</code> argument to exclude hidden messages.2077 ${t`Use the <code>hidden=off</code> argument to exclude hidden messages.`}
2082 </div>2078 </div>
2083 <div>2079 <div>
2084 Use the <code>role</code> argument to filter messages by role. Possible values are: system, assistant, user.2080 ${t`Use the <code>role</code> argument to filter messages by role. Possible values are: system, assistant, user.`}
2085 </div>2081 </div>
2086 <div>2082 <div>
2087 <strong>Examples:</strong>2083 <strong>${t`Examples:`}</strong>
2088 <ul>2084 <ul>
2089 <li>2085 <li>
2090 <pre><code>/messages 10</code></pre>2086 <pre><code>/messages 10</code></pre>
2091 Returns the 10th message.2087 ${t`Returns the 10th message.`}
2092 </li>2088 </li>
2093 <li>2089 <li>
2094 <pre><code>/messages names=on 5-10</code></pre>2090 <pre><code>/messages names=on 5-10</code></pre>
2095 Returns messages 5 through 10 with author names.2091 ${t`Returns messages 5 through 10 with author names.`}
2096 </li>2092 </li>
2097 </ul>2093 </ul>
2098 </div>2094 </div>
@@ -2103,15 +2099,15 @@ export function initDefaultSlashCommands() {
2103 callback: setInputCallback,2099 callback: setInputCallback,
2104 unnamedArgumentList: [2100 unnamedArgumentList: [
2105 new SlashCommandArgument(2101 new SlashCommandArgument(
2106 'text', [ARGUMENT_TYPE.STRING], true,2102 t`text`, [ARGUMENT_TYPE.STRING], true,
2107 ),2103 ),
2108 ],2104 ],
2109 helpString: `2105 helpString: `
2110 <div>2106 <div>
2111 Sets the user input to the specified text and passes it to the next command through the pipe.2107 ${t`Sets the user input to the specified text and passes it to the next command through the pipe.`}
2112 </div>2108 </div>
2113 <div>2109 <div>
2114 <strong>Example:</strong>2110 <strong>${t`Example:`}</strong>
2115 <ul>2111 <ul>
2116 <li>2112 <li>
2117 <pre><code>/setinput Hello world</code></pre>2113 <pre><code>/setinput Hello world</code></pre>
@@ -2123,57 +2119,57 @@ export function initDefaultSlashCommands() {
2123 SlashCommandParser.addCommandObject(SlashCommand.fromProps({2119 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
2124 name: 'popup',2120 name: 'popup',
2125 callback: popupCallback,2121 callback: popupCallback,
2126 returns: 'popup text',2122 returns: t`popup text`,
2127 namedArgumentList: [2123 namedArgumentList: [
2128 SlashCommandNamedArgument.fromProps({2124 SlashCommandNamedArgument.fromProps({
2129 name: 'scroll',2125 name: 'scroll',
2130 description: 'allows vertical scrolling of the content',2126 description: t`allows vertical scrolling of the content`,
2131 typeList: [ARGUMENT_TYPE.BOOLEAN],2127 typeList: [ARGUMENT_TYPE.BOOLEAN],
2132 enumList: commonEnumProviders.boolean('trueFalse')(),2128 enumList: commonEnumProviders.boolean('trueFalse')(),
2133 defaultValue: 'true',2129 defaultValue: 'true',
2134 }),2130 }),
2135 SlashCommandNamedArgument.fromProps({2131 SlashCommandNamedArgument.fromProps({
2136 name: 'large',2132 name: 'large',
2137 description: 'show large popup',2133 description: t`show large popup`,
2138 typeList: [ARGUMENT_TYPE.BOOLEAN],2134 typeList: [ARGUMENT_TYPE.BOOLEAN],
2139 enumList: commonEnumProviders.boolean('trueFalse')(),2135 enumList: commonEnumProviders.boolean('trueFalse')(),
2140 defaultValue: 'false',2136 defaultValue: 'false',
2141 }),2137 }),
2142 SlashCommandNamedArgument.fromProps({2138 SlashCommandNamedArgument.fromProps({
2143 name: 'wide',2139 name: 'wide',
2144 description: 'show wide popup',2140 description: t`show wide popup`,
2145 typeList: [ARGUMENT_TYPE.BOOLEAN],2141 typeList: [ARGUMENT_TYPE.BOOLEAN],
2146 enumList: commonEnumProviders.boolean('trueFalse')(),2142 enumList: commonEnumProviders.boolean('trueFalse')(),
2147 defaultValue: 'false',2143 defaultValue: 'false',
2148 }),2144 }),
2149 SlashCommandNamedArgument.fromProps({2145 SlashCommandNamedArgument.fromProps({
2150 name: 'wider',2146 name: 'wider',
2151 description: 'show wider popup',2147 description: t`show wider popup`,
2152 typeList: [ARGUMENT_TYPE.BOOLEAN],2148 typeList: [ARGUMENT_TYPE.BOOLEAN],
2153 enumList: commonEnumProviders.boolean('trueFalse')(),2149 enumList: commonEnumProviders.boolean('trueFalse')(),
2154 defaultValue: 'false',2150 defaultValue: 'false',
2155 }),2151 }),
2156 SlashCommandNamedArgument.fromProps({2152 SlashCommandNamedArgument.fromProps({
2157 name: 'transparent',2153 name: 'transparent',
2158 description: 'show transparent popup',2154 description: t`show transparent popup`,
2159 typeList: [ARGUMENT_TYPE.BOOLEAN],2155 typeList: [ARGUMENT_TYPE.BOOLEAN],
2160 enumList: commonEnumProviders.boolean('trueFalse')(),2156 enumList: commonEnumProviders.boolean('trueFalse')(),
2161 defaultValue: 'false',2157 defaultValue: 'false',
2162 }),2158 }),
2163 SlashCommandNamedArgument.fromProps({2159 SlashCommandNamedArgument.fromProps({
2164 name: 'okButton',2160 name: 'okButton',
2165 description: 'text for the OK button',2161 description: t`text for the OK button`,
2166 typeList: [ARGUMENT_TYPE.STRING],2162 typeList: [ARGUMENT_TYPE.STRING],
2167 defaultValue: 'OK',2163 defaultValue: 'OK',
2168 }),2164 }),
2169 SlashCommandNamedArgument.fromProps({2165 SlashCommandNamedArgument.fromProps({
2170 name: 'cancelButton',2166 name: 'cancelButton',
2171 description: 'text for the Cancel button',2167 description: t`text for the Cancel button`,
2172 typeList: [ARGUMENT_TYPE.STRING],2168 typeList: [ARGUMENT_TYPE.STRING],
2173 }),2169 }),
2174 SlashCommandNamedArgument.fromProps({2170 SlashCommandNamedArgument.fromProps({
2175 name: 'result',2171 name: 'result',
2176 description: '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.',2172 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.`,
2177 typeList: [ARGUMENT_TYPE.BOOLEAN],2173 typeList: [ARGUMENT_TYPE.BOOLEAN],
2178 enumList: commonEnumProviders.boolean('trueFalse')(),2174 enumList: commonEnumProviders.boolean('trueFalse')(),
2179 defaultValue: 'false',2175 defaultValue: 'false',
@@ -2181,18 +2177,18 @@ export function initDefaultSlashCommands() {
2181 ],2177 ],
2182 unnamedArgumentList: [2178 unnamedArgumentList: [
2183 SlashCommandArgument.fromProps({2179 SlashCommandArgument.fromProps({
2184 description: 'popup text',2180 description: t`popup text`,
2185 typeList: [ARGUMENT_TYPE.STRING],2181 typeList: [ARGUMENT_TYPE.STRING],
2186 isRequired: true,2182 isRequired: true,
2187 }),2183 }),
2188 ],2184 ],
2189 helpString: `2185 helpString: `
2190 <div>2186 <div>
2191 Shows a blocking popup with the specified text and buttons.2187 ${t`Shows a blocking popup with the specified text and buttons.`}
2192 Returns the popup text.2188 ${t`Returns the popup text.`}
2193 </div>2189 </div>
2194 <div>2190 <div>
2195 <strong>Example:</strong>2191 <strong>${t`Example:`}</strong>
2196 <ul>2192 <ul>
2197 <li>2193 <li>
2198 <pre><code>/popup large=on wide=on okButton="Confirm" Please confirm this action.</code></pre>2194 <pre><code>/popup large=on wide=on okButton="Confirm" Please confirm this action.</code></pre>
@@ -2207,17 +2203,17 @@ export function initDefaultSlashCommands() {
2207 SlashCommandParser.addCommandObject(SlashCommand.fromProps({2203 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
2208 name: 'buttons',2204 name: 'buttons',
2209 callback: buttonsCallback,2205 callback: buttonsCallback,
2210 returns: 'clicked button label (or array of labels if multiple is enabled)',2206 returns: t`clicked button label (or array of labels if multiple is enabled)`,
2211 namedArgumentList: [2207 namedArgumentList: [
2212 SlashCommandNamedArgument.fromProps({2208 SlashCommandNamedArgument.fromProps({
2213 name: 'labels',2209 name: 'labels',
2214 description: 'button labels',2210 description: t`button labels`,
2215 typeList: [ARGUMENT_TYPE.LIST],2211 typeList: [ARGUMENT_TYPE.LIST],
2216 isRequired: true,2212 isRequired: true,
2217 }),2213 }),
2218 SlashCommandNamedArgument.fromProps({2214 SlashCommandNamedArgument.fromProps({
2219 name: 'multiple',2215 name: 'multiple',
2220 description: 'if enabled multiple buttons can be clicked/toggled, and all clicked buttons are returned as an array',2216 description: t`if enabled multiple buttons can be clicked/toggled, and all clicked buttons are returned as an array`,
2221 typeList: [ARGUMENT_TYPE.BOOLEAN],2217 typeList: [ARGUMENT_TYPE.BOOLEAN],
2222 enumList: commonEnumProviders.boolean('trueFalse')(),2218 enumList: commonEnumProviders.boolean('trueFalse')(),
2223 defaultValue: 'false',2219 defaultValue: 'false',
@@ -2225,18 +2221,18 @@ export function initDefaultSlashCommands() {
2225 ],2221 ],
2226 unnamedArgumentList: [2222 unnamedArgumentList: [
2227 SlashCommandArgument.fromProps({2223 SlashCommandArgument.fromProps({
2228 description: 'text',2224 description: t`text`,
2229 typeList: [ARGUMENT_TYPE.STRING],2225 typeList: [ARGUMENT_TYPE.STRING],
2230 isRequired: true,2226 isRequired: true,
2231 }),2227 }),
2232 ],2228 ],
2233 helpString: `2229 helpString: `
2234 <div>2230 <div>
2235 Shows a blocking popup with the specified text and buttons.2231 ${t`Shows a blocking popup with the specified text and buttons.`}
2236 Returns the clicked button label into the pipe or empty string if canceled.2232 ${t`Returns the clicked button label into the pipe or empty string if canceled.`}
2237 </div>2233 </div>
2238 <div>2234 <div>
2239 <strong>Example:</strong>2235 <strong>${t`Example:`}</strong>
2240 <ul>2236 <ul>
2241 <li>2237 <li>
2242 <pre><code>/buttons labels=["Yes","No"] Do you want to continue?</code></pre>2238 <pre><code>/buttons labels=["Yes","No"] Do you want to continue?</code></pre>
@@ -2248,14 +2244,14 @@ export function initDefaultSlashCommands() {
2248 SlashCommandParser.addCommandObject(SlashCommand.fromProps({2244 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
2249 name: 'trimtokens',2245 name: 'trimtokens',
2250 callback: trimTokensCallback,2246 callback: trimTokensCallback,
2251 returns: 'trimmed text',2247 returns: t`trimmed text`,
2252 namedArgumentList: [2248 namedArgumentList: [
2253 new SlashCommandNamedArgument(2249 new SlashCommandNamedArgument(
2254 'limit', 'number of tokens to keep', [ARGUMENT_TYPE.NUMBER], true,2250 'limit', t`number of tokens to keep`, [ARGUMENT_TYPE.NUMBER], true,
2255 ),2251 ),
2256 SlashCommandNamedArgument.fromProps({2252 SlashCommandNamedArgument.fromProps({
2257 name: 'direction',2253 name: 'direction',
2258 description: 'trim direction',2254 description: t`trim direction`,
2259 typeList: [ARGUMENT_TYPE.STRING],2255 typeList: [ARGUMENT_TYPE.STRING],
2260 isRequired: true,2256 isRequired: true,
2261 enumList: [2257 enumList: [
@@ -2266,15 +2262,15 @@ export function initDefaultSlashCommands() {
2266 ],2262 ],
2267 unnamedArgumentList: [2263 unnamedArgumentList: [
2268 new SlashCommandArgument(2264 new SlashCommandArgument(
2269 'text', [ARGUMENT_TYPE.STRING], false,2265 t`text`, [ARGUMENT_TYPE.STRING], false,
2270 ),2266 ),
2271 ],2267 ],
2272 helpString: `2268 helpString: `
2273 <div>2269 <div>
2274 Trims the start or end of text to the specified number of tokens.2270 ${t`Trims the start or end of text to the specified number of tokens.`}
2275 </div>2271 </div>
2276 <div>2272 <div>
2277 <strong>Example:</strong>2273 <strong>${t`Example:`}</strong>
2278 <ul>2274 <ul>
2279 <li>2275 <li>
2280 <pre><code>/trimtokens limit=5 direction=start This is a long sentence with many words</code></pre>2276 <pre><code>/trimtokens limit=5 direction=start This is a long sentence with many words</code></pre>
@@ -2286,18 +2282,18 @@ export function initDefaultSlashCommands() {
2286 SlashCommandParser.addCommandObject(SlashCommand.fromProps({2282 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
2287 name: 'trimstart',2283 name: 'trimstart',
2288 callback: trimStartCallback,2284 callback: trimStartCallback,
2289 returns: 'trimmed text',2285 returns: t`trimmed text`,
2290 unnamedArgumentList: [2286 unnamedArgumentList: [
2291 new SlashCommandArgument(2287 new SlashCommandArgument(
2292 'text', [ARGUMENT_TYPE.STRING], true,2288 t`text`, [ARGUMENT_TYPE.STRING], true,
2293 ),2289 ),
2294 ],2290 ],
2295 helpString: `2291 helpString: `
2296 <div>2292 <div>
2297 Trims the text to the start of the first full sentence.2293 ${t`Trims the text to the start of the first full sentence.`}
2298 </div>2294 </div>
2299 <div>2295 <div>
2300 <strong>Example:</strong>2296 <strong>${t`Example:`}</strong>
2301 <ul>2297 <ul>
2302 <li>2298 <li>
2303 <pre><code>/trimstart This is a sentence. And here is another sentence.</code></pre>2299 <pre><code>/trimstart This is a sentence. And here is another sentence.</code></pre>
@@ -2309,38 +2305,38 @@ export function initDefaultSlashCommands() {
2309 SlashCommandParser.addCommandObject(SlashCommand.fromProps({2305 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
2310 name: 'trimend',2306 name: 'trimend',
2311 callback: trimEndCallback,2307 callback: trimEndCallback,
2312 returns: 'trimmed text',2308 returns: t`trimmed text`,
2313 unnamedArgumentList: [2309 unnamedArgumentList: [
2314 new SlashCommandArgument(2310 new SlashCommandArgument(
2315 'text', [ARGUMENT_TYPE.STRING], true,2311 t`text`, [ARGUMENT_TYPE.STRING], true,
2316 ),2312 ),
2317 ],2313 ],
2318 helpString: 'Trims the text to the end of the last full sentence.',2314 helpString: t`Trims the text to the end of the last full sentence.`,
2319 }));2315 }));
2320 SlashCommandParser.addCommandObject(SlashCommand.fromProps({2316 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
2321 name: 'inject',2317 name: 'inject',
2322 returns: 'injection ID',2318 returns: t`injection ID`,
2323 callback: injectCallback,2319 callback: injectCallback,
2324 namedArgumentList: [2320 namedArgumentList: [
2325 SlashCommandNamedArgument.fromProps({2321 SlashCommandNamedArgument.fromProps({
2326 name: 'id',2322 name: 'id',
2327 description: 'injection ID',2323 description: t`injection ID`,
2328 typeList: [ARGUMENT_TYPE.STRING],2324 typeList: [ARGUMENT_TYPE.STRING],
2329 isRequired: false,2325 isRequired: false,
2330 enumProvider: commonEnumProviders.injects,2326 enumProvider: commonEnumProviders.injects,
2331 }),2327 }),
2332 new SlashCommandNamedArgument(2328 new SlashCommandNamedArgument(
2333 'position', 'injection position', [ARGUMENT_TYPE.STRING], false, false, 'after', ['before', 'after', 'chat', 'none'],2329 'position', t`injection position`, [ARGUMENT_TYPE.STRING], false, false, 'after', ['before', 'after', 'chat', 'none'],
2334 ),2330 ),
2335 new SlashCommandNamedArgument(2331 new SlashCommandNamedArgument(
2336 'depth', 'injection depth', [ARGUMENT_TYPE.NUMBER], false, false, '4',2332 'depth', t`injection depth`, [ARGUMENT_TYPE.NUMBER], false, false, '4',
2337 ),2333 ),
2338 new SlashCommandNamedArgument(2334 new SlashCommandNamedArgument(
2339 'scan', 'include injection content into World Info scans', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false',2335 'scan', t`include injection content into World Info scans`, [ARGUMENT_TYPE.BOOLEAN], false, false, 'false',
2340 ),2336 ),
2341 SlashCommandNamedArgument.fromProps({2337 SlashCommandNamedArgument.fromProps({
2342 name: 'role',2338 name: 'role',
2343 description: 'role for in-chat injections',2339 description: t`role for in-chat injections`,
2344 typeList: [ARGUMENT_TYPE.STRING],2340 typeList: [ARGUMENT_TYPE.STRING],
2345 isRequired: false,2341 isRequired: false,
2346 enumList: [2342 enumList: [
@@ -2350,11 +2346,11 @@ export function initDefaultSlashCommands() {
2350 ],2346 ],
2351 }),2347 }),
2352 new SlashCommandNamedArgument(2348 new SlashCommandNamedArgument(
2353 'ephemeral', 'remove injection after generation', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false',2349 'ephemeral', t`remove injection after generation`, [ARGUMENT_TYPE.BOOLEAN], false, false, 'false',
2354 ),2350 ),
2355 SlashCommandNamedArgument.fromProps({2351 SlashCommandNamedArgument.fromProps({
2356 name: 'filter',2352 name: 'filter',
2357 description: 'if a filter is defined, an injection will only be performed if the closure returns true',2353 description: t`if a filter is defined, an injection will only be performed if the closure returns true`,
2358 typeList: [ARGUMENT_TYPE.CLOSURE],2354 typeList: [ARGUMENT_TYPE.CLOSURE],
2359 isRequired: false,2355 isRequired: false,
2360 acceptsMultiple: false,2356 acceptsMultiple: false,
@@ -2362,20 +2358,20 @@ export function initDefaultSlashCommands() {
2362 ],2358 ],
2363 unnamedArgumentList: [2359 unnamedArgumentList: [
2364 new SlashCommandArgument(2360 new SlashCommandArgument(
2365 'text', [ARGUMENT_TYPE.STRING], false,2361 t`text`, [ARGUMENT_TYPE.STRING], false,
2366 ),2362 ),
2367 ],2363 ],
2368 helpString: '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.',2364 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.`,
2369 }));2365 }));
2370 SlashCommandParser.addCommandObject(SlashCommand.fromProps({2366 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
2371 name: 'listinjects',2367 name: 'listinjects',
2372 callback: listInjectsCallback,2368 callback: listInjectsCallback,
2373 helpString: '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.',2369 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.`,
2374 returns: 'Optionalls the JSON object of script injections',2370 returns: t`Optionally the JSON object of script injections`,
2375 namedArgumentList: [2371 namedArgumentList: [
2376 SlashCommandNamedArgument.fromProps({2372 SlashCommandNamedArgument.fromProps({
2377 name: 'return',2373 name: 'return',
2378 description: 'The way how you want the return value to be provided',2374 description: t`The way how you want the return value to be provided`,
2379 typeList: [ARGUMENT_TYPE.STRING],2375 typeList: [ARGUMENT_TYPE.STRING],
2380 defaultValue: 'popup-html',2376 defaultValue: 'popup-html',
2381 enumList: slashCommandReturnHelper.enumList({ allowPipe: false, allowObject: true, allowChat: true, allowPopup: true, allowTextVersion: false }),2377 enumList: slashCommandReturnHelper.enumList({ allowPipe: false, allowObject: true, allowChat: true, allowPopup: true, allowTextVersion: false }),
@@ -2384,14 +2380,14 @@ export function initDefaultSlashCommands() {
2384 // TODO remove some day2380 // TODO remove some day
2385 SlashCommandNamedArgument.fromProps({2381 SlashCommandNamedArgument.fromProps({
2386 name: 'format',2382 name: 'format',
2387 description: '!!! DEPRECATED - use "return" instead !!! output format',2383 description: t`!!! DEPRECATED - use "return" instead !!! output format`,
2388 typeList: [ARGUMENT_TYPE.STRING],2384 typeList: [ARGUMENT_TYPE.STRING],
2389 isRequired: true,2385 isRequired: true,
2390 forceEnum: true,2386 forceEnum: true,
2391 enumList: [2387 enumList: [
2392 new SlashCommandEnumValue('popup', 'Show injects in a popup.', enumTypes.enum, enumIcons.default),2388 new SlashCommandEnumValue('popup', t`Show injects in a popup.`, enumTypes.enum, enumIcons.default),
2393 new SlashCommandEnumValue('chat', 'Post a system message to the chat.', enumTypes.enum, enumIcons.default),2389 new SlashCommandEnumValue('chat', t`Post a system message to the chat.`, enumTypes.enum, enumIcons.default),
2394 new SlashCommandEnumValue('none', 'Just return the injects as a JSON object.', enumTypes.enum, enumIcons.default),2390 new SlashCommandEnumValue('none', t`Just return the injects as a JSON object.`, enumTypes.enum, enumIcons.default),
2395 ],2391 ],
2396 }),2392 }),
2397 ],2393 ],
@@ -2401,37 +2397,37 @@ export function initDefaultSlashCommands() {
2401 aliases: ['flushinjects'],2397 aliases: ['flushinjects'],
2402 unnamedArgumentList: [2398 unnamedArgumentList: [
2403 SlashCommandArgument.fromProps({2399 SlashCommandArgument.fromProps({
2404 description: 'injection ID or a variable name pointing to ID',2400 description: t`injection ID or a variable name pointing to ID`,
2405 typeList: [ARGUMENT_TYPE.STRING],2401 typeList: [ARGUMENT_TYPE.STRING],
2406 defaultValue: '',2402 defaultValue: '',
2407 enumProvider: commonEnumProviders.injects,2403 enumProvider: commonEnumProviders.injects,
2408 }),2404 }),
2409 ],2405 ],
2410 callback: flushInjectsCallback,2406 callback: flushInjectsCallback,
2411 helpString: 'Removes a script injection for the current chat. If no ID is provided, removes all script injections.',2407 helpString: t`Removes a script injection for the current chat. If no ID is provided, removes all script injections.`,
2412 }));2408 }));
2413 SlashCommandParser.addCommandObject(SlashCommand.fromProps({2409 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
2414 name: 'tokens',2410 name: 'tokens',
2415 callback: (_, text) => {2411 callback: (_, text) => {
2416 if (text instanceof SlashCommandClosure || Array.isArray(text)) throw new Error('Unnamed argument cannot be a closure for command /tokens');2412 if (text instanceof SlashCommandClosure || Array.isArray(text)) throw new Error(t`Unnamed argument cannot be a closure for command /tokens`);
2417 return getTokenCountAsync(text).then(count => String(count));2413 return getTokenCountAsync(text).then(count => String(count));
2418 },2414 },
2419 returns: 'number of tokens',2415 returns: t`number of tokens`,
2420 unnamedArgumentList: [2416 unnamedArgumentList: [
2421 new SlashCommandArgument(2417 new SlashCommandArgument(
2422 'text', [ARGUMENT_TYPE.STRING], true,2418 t`text`, [ARGUMENT_TYPE.STRING], true,
2423 ),2419 ),
2424 ],2420 ],
2425 helpString: 'Counts the number of tokens in the provided text.',2421 helpString: t`Counts the number of tokens in the provided text.`,
2426 }));2422 }));
2427 SlashCommandParser.addCommandObject(SlashCommand.fromProps({2423 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
2428 name: 'model',2424 name: 'model',
2429 callback: modelCallback,2425 callback: modelCallback,
2430 returns: 'current model',2426 returns: t`current model`,
2431 namedArgumentList: [2427 namedArgumentList: [
2432 SlashCommandNamedArgument.fromProps({2428 SlashCommandNamedArgument.fromProps({
2433 name: 'quiet',2429 name: 'quiet',
2434 description: 'suppress the toast message on model change',2430 description: t`suppress the toast message on model change`,
2435 typeList: [ARGUMENT_TYPE.BOOLEAN],2431 typeList: [ARGUMENT_TYPE.BOOLEAN],
2436 defaultValue: 'false',2432 defaultValue: 'false',
2437 enumList: commonEnumProviders.boolean('trueFalse')(),2433 enumList: commonEnumProviders.boolean('trueFalse')(),
@@ -2439,22 +2435,22 @@ export function initDefaultSlashCommands() {
2439 ],2435 ],
2440 unnamedArgumentList: [2436 unnamedArgumentList: [
2441 SlashCommandArgument.fromProps({2437 SlashCommandArgument.fromProps({
2442 description: 'model name',2438 description: t`model name`,
2443 typeList: [ARGUMENT_TYPE.STRING],2439 typeList: [ARGUMENT_TYPE.STRING],
2444 enumProvider: () => getModelOptions(true)?.options?.map(option => new SlashCommandEnumValue(option.value, option.value !== option.text ? option.text : null)) ?? [],2440 enumProvider: () => getModelOptions(true)?.options?.map(option => new SlashCommandEnumValue(option.value, option.value !== option.text ? option.text : null)) ?? [],
2445 }),2441 }),
2446 ],2442 ],
2447 helpString: 'Sets the model for the current API. Gets the current model name if no argument is provided.',2443 helpString: t`Sets the model for the current API. Gets the current model name if no argument is provided.`,
2448 }));2444 }));
2449 SlashCommandParser.addCommandObject(SlashCommand.fromProps({2445 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
2450 name: 'getpromptentry',2446 name: 'getpromptentry',
2451 aliases: ['getpromptentries'],2447 aliases: ['getpromptentries'],
2452 callback: getPromptEntryCallback,2448 callback: getPromptEntryCallback,
2453 returns: 'true/false state of prompt(s)',2449 returns: t`true/false state of prompt(s)`,
2454 namedArgumentList: [2450 namedArgumentList: [
2455 SlashCommandNamedArgument.fromProps({2451 SlashCommandNamedArgument.fromProps({
2456 name: 'identifier',2452 name: 'identifier',
2457 description: 'Prompt entry identifier(s) to retrieve',2453 description: t`Prompt entry identifier(s) to retrieve`,
2458 typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST],2454 typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST],
2459 acceptsMultiple: true,2455 acceptsMultiple: true,
2460 enumProvider: () =>2456 enumProvider: () =>
@@ -2464,7 +2460,7 @@ export function initDefaultSlashCommands() {
2464 }),2460 }),
2465 SlashCommandNamedArgument.fromProps({2461 SlashCommandNamedArgument.fromProps({
2466 name: 'name',2462 name: 'name',
2467 description: 'Prompt entry name(s) to retrieve',2463 description: t`Prompt entry name(s) to retrieve`,
2468 typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST],2464 typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST],
2469 acceptsMultiple: true,2465 acceptsMultiple: true,
2470 enumProvider: () =>2466 enumProvider: () =>
@@ -2474,7 +2470,7 @@ export function initDefaultSlashCommands() {
2474 }),2470 }),
2475 SlashCommandNamedArgument.fromProps({2471 SlashCommandNamedArgument.fromProps({
2476 name: 'return',2472 name: 'return',
2477 description: 'Whether the return will be simple, a list, or a dict.',2473 description: t`Whether the return will be simple, a list, or a dict.`,
2478 typeList: [ARGUMENT_TYPE.STRING],2474 typeList: [ARGUMENT_TYPE.STRING],
2479 defaultValue: 'simple',2475 defaultValue: 'simple',
2480 enumList: ['simple', 'list', 'dict'],2476 enumList: ['simple', 'list', 'dict'],
@@ -2482,10 +2478,10 @@ export function initDefaultSlashCommands() {
2482 ],2478 ],
2483 helpString: `2479 helpString: `
2484 <div>2480 <div>
2485 Gets the state of the specified prompt entries.2481 ${t`Gets the state of the specified prompt entries.`}
2486 </div>2482 </div>
2487 <div>2483 <div>
2488 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.2484 ${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.`}
2489 </div>2485 </div>
2490 `,2486 `,
2491 }));2487 }));
@@ -2496,7 +2492,7 @@ export function initDefaultSlashCommands() {
2496 namedArgumentList: [2492 namedArgumentList: [
2497 SlashCommandNamedArgument.fromProps({2493 SlashCommandNamedArgument.fromProps({
2498 name: 'identifier',2494 name: 'identifier',
2499 description: 'Prompt entry identifier(s) to target',2495 description: t`Prompt entry identifier(s) to target`,
2500 typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST],2496 typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST],
2501 acceptsMultiple: true,2497 acceptsMultiple: true,
2502 enumProvider: () => {2498 enumProvider: () => {
@@ -2506,7 +2502,7 @@ export function initDefaultSlashCommands() {
2506 }),2502 }),
2507 SlashCommandNamedArgument.fromProps({2503 SlashCommandNamedArgument.fromProps({
2508 name: 'name',2504 name: 'name',
2509 description: 'Prompt entry name(s) to target',2505 description: t`Prompt entry name(s) to target`,
2510 typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST],2506 typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST],
2511 acceptsMultiple: true,2507 acceptsMultiple: true,
2512 enumProvider: () => {2508 enumProvider: () => {
@@ -2517,7 +2513,7 @@ export function initDefaultSlashCommands() {
2517 ],2513 ],
2518 unnamedArgumentList: [2514 unnamedArgumentList: [
2519 SlashCommandArgument.fromProps({2515 SlashCommandArgument.fromProps({
2520 description: 'Set entry/entries on or off',2516 description: t`Set entry/entries on or off`,
2521 typeList: [ARGUMENT_TYPE.STRING],2517 typeList: [ARGUMENT_TYPE.STRING],
2522 isRequired: true,2518 isRequired: true,
2523 acceptsMultiple: false,2519 acceptsMultiple: false,
@@ -2525,16 +2521,16 @@ export function initDefaultSlashCommands() {
2525 enumList: commonEnumProviders.boolean('onOffToggle')(),2521 enumList: commonEnumProviders.boolean('onOffToggle')(),
2526 }),2522 }),
2527 ],2523 ],
2528 helpString: 'Sets the specified prompt manager entry/entries on or off.',2524 helpString: t`Sets the specified prompt manager entry/entries on or off.`,
2529 }));2525 }));
2530 SlashCommandParser.addCommandObject(SlashCommand.fromProps({2526 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
2531 name: 'pick-icon',2527 name: 'pick-icon',
2532 callback: async () => ((await showFontAwesomePicker()) ?? false).toString(),2528 callback: async () => ((await showFontAwesomePicker()) ?? false).toString(),
2533 returns: 'The chosen icon name or false if cancelled.',2529 returns: t`The chosen icon name or false if cancelled.`,
2534 helpString: `2530 helpString: `
2535 <div>Opens a popup with all the available Font Awesome icons and returns the selected icon's name.</div>2531 <div>${t`Opens a popup with all the available Font Awesome icons and returns the selected icon's name.`}</div>
2536 <div>2532 <div>
2537 <strong>Example:</strong>2533 <strong>${t`Example:`}</strong>
2538 <ul>2534 <ul>
2539 <li>2535 <li>
2540 <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>2536 <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() {
2546 SlashCommandParser.addCommandObject(SlashCommand.fromProps({2542 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
2547 name: 'api-url',2543 name: 'api-url',
2548 callback: setApiUrlCallback,2544 callback: setApiUrlCallback,
2549 returns: 'the current API url',2545 returns: t`the current API url`,
2550 aliases: ['server'],2546 aliases: ['server'],
2551 namedArgumentList: [2547 namedArgumentList: [
2552 SlashCommandNamedArgument.fromProps({2548 SlashCommandNamedArgument.fromProps({
2553 name: 'api',2549 name: 'api',
2554 description: 'API to set/get the URL for - if not provided, current API is used',2550 description: t`API to set/get the URL for - if not provided, current API is used`,
2555 typeList: [ARGUMENT_TYPE.STRING],2551 typeList: [ARGUMENT_TYPE.STRING],
2556 enumList: [2552 enumList: [
2557 new SlashCommandEnumValue('custom', 'custom OpenAI-compatible', enumTypes.getBasedOnIndex(UNIQUE_APIS.findIndex(x => x === 'openai')), 'O'),2553 new SlashCommandEnumValue('custom', 'custom OpenAI-compatible', enumTypes.getBasedOnIndex(UNIQUE_APIS.findIndex(x => x === 'openai')), 'O'),
@@ -2561,14 +2557,14 @@ export function initDefaultSlashCommands() {
2561 }),2557 }),
2562 SlashCommandNamedArgument.fromProps({2558 SlashCommandNamedArgument.fromProps({
2563 name: 'connect',2559 name: 'connect',
2564 description: 'Whether to auto-connect to the API after setting the URL',2560 description: t`Whether to auto-connect to the API after setting the URL`,
2565 typeList: [ARGUMENT_TYPE.BOOLEAN],2561 typeList: [ARGUMENT_TYPE.BOOLEAN],
2566 defaultValue: 'true',2562 defaultValue: 'true',
2567 enumList: commonEnumProviders.boolean('trueFalse')(),2563 enumList: commonEnumProviders.boolean('trueFalse')(),
2568 }),2564 }),
2569 SlashCommandNamedArgument.fromProps({2565 SlashCommandNamedArgument.fromProps({
2570 name: 'quiet',2566 name: 'quiet',
2571 description: 'suppress the toast message on API change',2567 description: t`suppress the toast message on API change`,
2572 typeList: [ARGUMENT_TYPE.BOOLEAN],2568 typeList: [ARGUMENT_TYPE.BOOLEAN],
2573 defaultValue: 'false',2569 defaultValue: 'false',
2574 enumList: commonEnumProviders.boolean('trueFalse')(),2570 enumList: commonEnumProviders.boolean('trueFalse')(),
@@ -2576,31 +2572,29 @@ export function initDefaultSlashCommands() {
2576 ],2572 ],
2577 unnamedArgumentList: [2573 unnamedArgumentList: [
2578 SlashCommandArgument.fromProps({2574 SlashCommandArgument.fromProps({
2579 description: 'API url to connect to',2575 description: t`API url to connect to`,
2580 typeList: [ARGUMENT_TYPE.STRING],2576 typeList: [ARGUMENT_TYPE.STRING],
2581 }),2577 }),
2582 ],2578 ],
2583 helpString: `2579 helpString: `
2584 <div>2580 <div>
2585 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.2581 ${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.`}
2586 </div>2582 </div>
2587 <div>2583 <div>
2588 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,2584 ${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.
2590 </div>2585 </div>
2591 <div>2586 <div>
2592 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,2587 ${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.
2594 </div>2588 </div>
2595 `,2589 `,
2596 }));2590 }));
2597 SlashCommandParser.addCommandObject(SlashCommand.fromProps({2591 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
2598 name: 'tokenizer',2592 name: 'tokenizer',
2599 callback: selectTokenizerCallback,2593 callback: selectTokenizerCallback,
2600 returns: 'current tokenizer',2594 returns: t`current tokenizer`,
2601 unnamedArgumentList: [2595 unnamedArgumentList: [
2602 SlashCommandArgument.fromProps({2596 SlashCommandArgument.fromProps({
2603 description: 'tokenizer name',2597 description: t`tokenizer name`,
2604 typeList: [ARGUMENT_TYPE.STRING],2598 typeList: [ARGUMENT_TYPE.STRING],
2605 enumList: getAvailableTokenizers().map(tokenizer =>2599 enumList: getAvailableTokenizers().map(tokenizer =>
2606 new SlashCommandEnumValue(tokenizer.tokenizerKey, tokenizer.tokenizerName, enumTypes.enum, enumIcons.default)),2600 new SlashCommandEnumValue(tokenizer.tokenizerKey, tokenizer.tokenizerName, enumTypes.enum, enumIcons.default)),
@@ -2608,10 +2602,10 @@ export function initDefaultSlashCommands() {
2608 ],2602 ],
2609 helpString: `2603 helpString: `
2610 <div>2604 <div>
2611 Selects tokenizer by name. Gets the current tokenizer if no name is provided.2605 ${t`Selects tokenizer by name. Gets the current tokenizer if no name is provided.`}
2612 </div>2606 </div>
2613 <div>2607 <div>
2614 <strong>Available tokenizers:</strong>2608 <strong>${t`Available tokenizers:`}</strong>
2615 <pre><code>${getAvailableTokenizers().map(t => t.tokenizerKey).join(', ')}</code></pre>2609 <pre><code>${getAvailableTokenizers().map(t => t.tokenizerKey).join(', ')}</code></pre>
2616 </div>2610 </div>
2617 `,2611 `,
@@ -2620,58 +2614,58 @@ export function initDefaultSlashCommands() {
2620 name: 'upper',2614 name: 'upper',
2621 aliases: ['uppercase', 'to-upper'],2615 aliases: ['uppercase', 'to-upper'],
2622 callback: (_, text) => typeof text === 'string' ? text.toUpperCase() : '',2616 callback: (_, text) => typeof text === 'string' ? text.toUpperCase() : '',
2623 returns: 'uppercase string',2617 returns: t`uppercase string`,
2624 unnamedArgumentList: [2618 unnamedArgumentList: [
2625 new SlashCommandArgument(2619 new SlashCommandArgument(
2626 'text to affect', [ARGUMENT_TYPE.STRING], true, false,2620 t`text to affect`, [ARGUMENT_TYPE.STRING], true, false,
2627 ),2621 ),
2628 ],2622 ],
2629 helpString: 'Converts the provided string to uppercase.',2623 helpString: t`Converts the provided string to uppercase.`,
2630 }));2624 }));
2631 SlashCommandParser.addCommandObject(SlashCommand.fromProps({2625 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
2632 name: 'lower',2626 name: 'lower',
2633 aliases: ['lowercase', 'to-lower'],2627 aliases: ['lowercase', 'to-lower'],
2634 callback: (_, text) => typeof text === 'string' ? text.toLowerCase() : '',2628 callback: (_, text) => typeof text === 'string' ? text.toLowerCase() : '',
2635 returns: 'lowercase string',2629 returns: t`lowercase string`,
2636 unnamedArgumentList: [2630 unnamedArgumentList: [
2637 new SlashCommandArgument(2631 new SlashCommandArgument(
2638 'text to affect', [ARGUMENT_TYPE.STRING], true, false,2632 t`text to affect`, [ARGUMENT_TYPE.STRING], true, false,
2639 ),2633 ),
2640 ],2634 ],
2641 helpString: 'Converts the provided string to lowercase.',2635 helpString: t`Converts the provided string to lowercase.`,
2642 }));2636 }));
2643 SlashCommandParser.addCommandObject(SlashCommand.fromProps({2637 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
2644 name: 'substr',2638 name: 'substr',
2645 aliases: ['substring'],2639 aliases: ['substring'],
2646 callback: (arg, text) => typeof text === 'string' ? text.slice(...[Number(arg.start), arg.end && Number(arg.end)]) : '',2640 callback: (arg, text) => typeof text === 'string' ? text.slice(...[Number(arg.start), arg.end && Number(arg.end)]) : '',
2647 returns: 'substring',2641 returns: t`substring`,
2648 namedArgumentList: [2642 namedArgumentList: [
2649 new SlashCommandNamedArgument(2643 new SlashCommandNamedArgument(
2650 'start', 'start index', [ARGUMENT_TYPE.NUMBER], false, false,2644 'start', t`start index`, [ARGUMENT_TYPE.NUMBER], false, false,
2651 ),2645 ),
2652 new SlashCommandNamedArgument(2646 new SlashCommandNamedArgument(
2653 'end', 'end index', [ARGUMENT_TYPE.NUMBER], false, false,2647 'end', t`end index`, [ARGUMENT_TYPE.NUMBER], false, false,
2654 ),2648 ),
2655 ],2649 ],
2656 unnamedArgumentList: [2650 unnamedArgumentList: [
2657 new SlashCommandArgument(2651 new SlashCommandArgument(
2658 'text to affect', [ARGUMENT_TYPE.STRING], true, false,2652 t`text to affect`, [ARGUMENT_TYPE.STRING], true, false,
2659 ),2653 ),
2660 ],2654 ],
2661 helpString: `2655 helpString: `
2662 <div>2656 <div>
2663 Extracts text from the provided string.2657 ${t`Extracts text from the provided string.`}
2664 </div>2658 </div>
2665 <div>2659 <div>
2666 If <code>start</code> is omitted, it's treated as 0.<br />2660 ${t`If <code>start</code> is omitted, it's treated as 0.<br />`}
2667 If <code>start</code> < 0, the index is counted from the end of the string.<br />2661 ${t`If <code>start</code> < 0, the index is counted from the end of the string.<br />`}
2668 If <code>start</code> >= the string's length, an empty string is returned.<br />2662 ${t`If <code>start</code> >= the string's length, an empty string is returned.<br />`}
2669 If <code>end</code> is omitted, or if <code>end</code> >= the string's length, extracts to the end of the string.<br />2663 ${t`If <code>end</code> is omitted, or if <code>end</code> >= the string's length, extracts to the end of the string.<br />`}
2670 If <code>end</code> < 0, the index is counted from the end of the string.<br />2664 ${t`If <code>end</code> < 0, the index is counted from the end of the string.<br />`}
2671 If <code>end</code> <= <code>start</code> after normalizing negative values, an empty string is returned.2665 ${t`If <code>end</code> <= <code>start</code> after normalizing negative values, an empty string is returned.`}
2672 </div>2666 </div>
2673 <div>2667 <div>
2674 <strong>Example:</strong>2668 <strong>${t`Example:`}</strong>
2675 <pre>/let x The morning is upon us. || </pre>2669 <pre>/let x The morning is upon us. || </pre>
2676 <pre>/substr start=-3 {{var::x}} | /echo |/# us. ||</pre>2670 <pre>/substr start=-3 {{var::x}} | /echo |/# us. ||</pre>
2677 <pre>/substr start=-3 end=-1 {{var::x}} | /echo |/# us ||</pre>2671 <pre>/substr start=-3 end=-1 {{var::x}} | /echo |/# us ||</pre>
@@ -2684,11 +2678,11 @@ export function initDefaultSlashCommands() {
2684 name: 'is-mobile',2678 name: 'is-mobile',
2685 callback: () => String(isMobile()),2679 callback: () => String(isMobile()),
2686 returns: ARGUMENT_TYPE.BOOLEAN,2680 returns: ARGUMENT_TYPE.BOOLEAN,
2687 helpString: 'Returns true if the current device is a mobile device, false otherwise. Equivalent to <code>{{isMobile}}</code> macro.',2681 helpString: t`Returns true if the current device is a mobile device, false otherwise. Equivalent to <code>{{isMobile}}</code> macro.`,
2688 }));2682 }));
2689 SlashCommandParser.addCommandObject(SlashCommand.fromProps({2683 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
2690 name: 'chat-render',2684 name: 'chat-render',
2691 helpString: 'Renders a specified number of messages into the chat window. Displays all messages if no argument is provided.',2685 helpString: t`Renders a specified number of messages into the chat window. Displays all messages if no argument is provided.`,
2692 callback: async (args, number) => {2686 callback: async (args, number) => {
2693 await showMoreMessages(number && !isNaN(Number(number)) ? Number(number) : Number.MAX_SAFE_INTEGER);2687 await showMoreMessages(number && !isNaN(Number(number)) ? Number(number) : Number.MAX_SAFE_INTEGER);
2694 if (isTrueBoolean(String(args?.scroll ?? ''))) {2688 if (isTrueBoolean(String(args?.scroll ?? ''))) {
@@ -2699,7 +2693,7 @@ export function initDefaultSlashCommands() {
2699 namedArgumentList: [2693 namedArgumentList: [
2700 SlashCommandNamedArgument.fromProps({2694 SlashCommandNamedArgument.fromProps({
2701 name: 'scroll',2695 name: 'scroll',
2702 description: 'scroll to the top after rendering',2696 description: t`scroll to the top after rendering`,
2703 typeList: [ARGUMENT_TYPE.BOOLEAN],2697 typeList: [ARGUMENT_TYPE.BOOLEAN],
2704 defaultValue: 'false',2698 defaultValue: 'false',
2705 enumList: commonEnumProviders.boolean('trueFalse')(),2699 enumList: commonEnumProviders.boolean('trueFalse')(),
@@ -2707,13 +2701,13 @@ export function initDefaultSlashCommands() {
2707 ],2701 ],
2708 unnamedArgumentList: [2702 unnamedArgumentList: [
2709 new SlashCommandArgument(2703 new SlashCommandArgument(
2710 'number of messages', [ARGUMENT_TYPE.NUMBER], false,2704 t`number of messages`, [ARGUMENT_TYPE.NUMBER], false,
2711 ),2705 ),
2712 ],2706 ],
2713 }));2707 }));
2714 SlashCommandParser.addCommandObject(SlashCommand.fromProps({2708 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
2715 name: 'chat-reload',2709 name: 'chat-reload',
2716 helpString: 'Reloads the current chat.',2710 helpString: t`Reloads the current chat.`,
2717 callback: async () => {2711 callback: async () => {
2718 await reloadCurrentChat();2712 await reloadCurrentChat();
2719 return '';2713 return '';
@@ -2724,7 +2718,7 @@ export function initDefaultSlashCommands() {
2724 aliases: ['re'],2718 aliases: ['re'],
2725 callback: (async ({ mode = 'literal', pattern, replacer = '' }, text) => {2719 callback: (async ({ mode = 'literal', pattern, replacer = '' }, text) => {
2726 if (!pattern) {2720 if (!pattern) {
2727 throw new Error('Argument of \'pattern=\' cannot be empty');2721 throw new Error(t`Argument of 'pattern=' cannot be empty`);
2728 }2722 }
2729 text = text.toString();2723 text = text.toString();
2730 pattern = pattern.toString();2724 pattern = pattern.toString();
@@ -2735,42 +2729,42 @@ export function initDefaultSlashCommands() {
2735 case 'regex':2729 case 'regex':
2736 return text.replace(regexFromString(pattern), replacer);2730 return text.replace(regexFromString(pattern), replacer);
2737 default:2731 default:
2738 throw new Error('Invalid \'/replace mode=\' argument specified!');2732 throw new Error(t`Invalid '/replace mode=' argument specified!`);
2739 }2733 }
2740 }),2734 }),
2741 returns: 'replaced text',2735 returns: t`replaced text`,
2742 namedArgumentList: [2736 namedArgumentList: [
2743 SlashCommandNamedArgument.fromProps({2737 SlashCommandNamedArgument.fromProps({
2744 name: 'mode',2738 name: 'mode',
2745 description: 'Replaces occurrence(s) of a pattern',2739 description: t`Replaces occurrence(s) of a pattern`,
2746 typeList: [ARGUMENT_TYPE.STRING],2740 typeList: [ARGUMENT_TYPE.STRING],
2747 defaultValue: 'literal',2741 defaultValue: 'literal',
2748 enumList: ['literal', 'regex'],2742 enumList: ['literal', 'regex'],
2749 }),2743 }),
2750 new SlashCommandNamedArgument(2744 new SlashCommandNamedArgument(
2751 'pattern', 'pattern to search with', [ARGUMENT_TYPE.STRING], true, false,2745 'pattern', t`pattern to search with`, [ARGUMENT_TYPE.STRING], true, false,
2752 ),2746 ),
2753 new SlashCommandNamedArgument(2747 new SlashCommandNamedArgument(
2754 'replacer', 'replacement text for matches', [ARGUMENT_TYPE.STRING], false, false, '',2748 'replacer', t`replacement text for matches`, [ARGUMENT_TYPE.STRING], false, false, '',
2755 ),2749 ),
2756 ],2750 ],
2757 unnamedArgumentList: [2751 unnamedArgumentList: [
2758 new SlashCommandArgument(2752 new SlashCommandArgument(
2759 'text to affect', [ARGUMENT_TYPE.STRING], true, false,2753 t`text to affect`, [ARGUMENT_TYPE.STRING], true, false,
2760 ),2754 ),
2761 ],2755 ],
2762 helpString: `2756 helpString: `
2763 <div>2757 <div>
2764 Replaces text within the provided string based on the pattern.2758 ${t`Replaces text within the provided string based on the pattern.`}
2765 </div>2759 </div>
2766 <div>2760 <div>
2767 If <code>mode</code> is <code>literal</code> (or omitted), <code>pattern</code> is a literal search string (case-sensitive).<br />2761 ${t`If <code>mode</code> is <code>literal</code> (or omitted), <code>pattern</code> is a literal search string (case-sensitive).<br />`}
2768 If <code>mode</code> is <code>regex</code>, <code>pattern</code> is parsed as an ECMAScript Regular Expression.<br />2762 ${t`If <code>mode</code> is <code>regex</code>, <code>pattern</code> is parsed as an ECMAScript Regular Expression.<br />`}
2769 The <code>replacer</code> replaces based on the <code>pattern</code> in the input text.<br />2763 ${t`The <code>replacer</code> replaces based on the <code>pattern</code> in the input text.<br />`}
2770 If <code>replacer</code> is omitted, the replacement(s) will be an empty string.<br />2764 ${t`If <code>replacer</code> is omitted, the replacement(s) will be an empty string.<br />`}
2771 </div>2765 </div>
2772 <div>2766 <div>
2773 <strong>Example:</strong>2767 <strong>${t`Example:`}</strong>
2774 <pre><code class="language-stscript">/let x Blue house and blue car || </code></pre>2768 <pre><code class="language-stscript">/let x Blue house and blue car || </code></pre>
2775 <pre><code class="language-stscript">/replace pattern="blue" {{var::x}} | /echo |/# Blue house and car ||</code></pre>2769 <pre><code class="language-stscript">/replace pattern="blue" {{var::x}} | /echo |/# Blue house and car ||</code></pre>
2776 <pre><code class="language-stscript">/replace pattern="blue" replacer="red" {{var::x}} | /echo |/# Blue house and red car ||</code></pre>2770 <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() {
2783 name: 'test',2777 name: 'test',
2784 callback: (({ pattern }, text) => {2778 callback: (({ pattern }, text) => {
2785 if (!pattern) {2779 if (!pattern) {
2786 throw new Error('Argument of \'pattern=\' cannot be empty');2780 throw new Error(t`Argument of 'pattern=' cannot be empty`);
2787 }2781 }
2788 const re = regexFromString(pattern.toString());2782 const re = regexFromString(pattern.toString());
2789 if (!re) {2783 if (!re) {
2790 throw new Error('The value of \'pattern\' argument is not a valid regular expression.');2784 throw new Error(t`The value of 'pattern' argument is not a valid regular expression.`);
2791 }2785 }
2792 return JSON.stringify(re.test(text.toString()));2786 return JSON.stringify(re.test(text.toString()));
2793 }),2787 }),
2794 returns: 'true | false',2788 returns: 'true | false',
2795 namedArgumentList: [2789 namedArgumentList: [
2796 new SlashCommandNamedArgument(2790 new SlashCommandNamedArgument(
2797 'pattern', 'pattern to find', [ARGUMENT_TYPE.STRING], true, false,2791 'pattern', t`pattern to find`, [ARGUMENT_TYPE.STRING], true, false,
2798 ),2792 ),
2799 ],2793 ],
2800 unnamedArgumentList: [2794 unnamedArgumentList: [
2801 new SlashCommandArgument(2795 new SlashCommandArgument(
2802 'text to test', [ARGUMENT_TYPE.STRING], true, false,2796 t`text to test`, [ARGUMENT_TYPE.STRING], true, false,
2803 ),2797 ),
2804 ],2798 ],
2805 helpString: `2799 helpString: `
2806 <div>2800 <div>
2807 Tests text for a regular expression match.2801 ${t`Tests text for a regular expression match.`}
2808 </div>2802 </div>
2809 <div>2803 <div>
2810 Returns <code>true</code> if the match is found, <code>false</code> otherwise.2804 ${t`Returns <code>true</code> if the match is found, <code>false</code> otherwise.`}
2811 </div>2805 </div>
2812 <div>2806 <div>
2813 <strong>Example:</strong>2807 <strong>${t`Example:`}</strong>
2814 <pre><code class="language-stscript">/let x Blue house and green car ||</code></pre>2808 <pre><code class="language-stscript">/let x Blue house and green car ||</code></pre>
2815 <pre><code class="language-stscript">/test pattern="green" {{var::x}} | /echo |/# true ||</code></pre>2809 <pre><code class="language-stscript">/test pattern="green" {{var::x}} | /echo |/# true ||</code></pre>
2816 <pre><code class="language-stscript">/test pattern="blue" {{var::x}} | /echo |/# false ||</code></pre>2810 <pre><code class="language-stscript">/test pattern="blue" {{var::x}} | /echo |/# false ||</code></pre>
@@ -2822,11 +2816,11 @@ export function initDefaultSlashCommands() {
2822 name: 'match',2816 name: 'match',
2823 callback: (({ pattern }, text) => {2817 callback: (({ pattern }, text) => {
2824 if (!pattern) {2818 if (!pattern) {
2825 throw new Error('Argument of \'pattern=\' cannot be empty');2819 throw new Error(t`Argument of 'pattern=' cannot be empty`);
2826 }2820 }
2827 const re = regexFromString(pattern.toString());2821 const re = regexFromString(pattern.toString());
2828 if (!re) {2822 if (!re) {
2829 throw new Error('The value of \'pattern\' argument is not a valid regular expression.');2823 throw new Error(t`The value of 'pattern' argument is not a valid regular expression.`);
2830 }2824 }
2831 if (re.flags.includes('g')) {2825 if (re.flags.includes('g')) {
2832 return JSON.stringify([...text.toString().matchAll(re)]);2826 return JSON.stringify([...text.toString().matchAll(re)]);
@@ -2835,28 +2829,26 @@ export function initDefaultSlashCommands() {
2835 return match ? JSON.stringify(match) : '';2829 return match ? JSON.stringify(match) : '';
2836 }2830 }
2837 }),2831 }),
2838 returns: 'group array for each match',2832 returns: t`group array for each match`,
2839 namedArgumentList: [2833 namedArgumentList: [
2840 new SlashCommandNamedArgument(2834 new SlashCommandNamedArgument(
2841 'pattern', 'pattern to find', [ARGUMENT_TYPE.STRING], true, false,2835 'pattern', t`pattern to find`, [ARGUMENT_TYPE.STRING], true, false,
2842 ),2836 ),
2843 ],2837 ],
2844 unnamedArgumentList: [2838 unnamedArgumentList: [
2845 new SlashCommandArgument(2839 new SlashCommandArgument(
2846 'text to match against', [ARGUMENT_TYPE.STRING], true, false,2840 t`text to match against`, [ARGUMENT_TYPE.STRING], true, false,
2847 ),2841 ),
2848 ],2842 ],
2849 helpString: `2843 helpString: `
2850 <div>2844 <div>
2851 Retrieves regular expression matches in the given text2845 ${t`Retrieves regular expression matches in the given text`}
2852 </div>2846 </div>
2853 <div>2847 <div>
2854 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>),2848 ${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.
2857 </div>2849 </div>
2858 <div>2850 <div>
2859 <strong>Example:</strong>2851 <strong>${t`Example:`}</strong>
2860 <pre><code class="language-stscript">/let x color_green green lamp color_blue ||</code></pre>2852 <pre><code class="language-stscript">/let x color_green green lamp color_blue ||</code></pre>
2861 <pre><code class="language-stscript">/match pattern="green" {{var::x}} | /echo |/# [ "green" ] ||</code></pre>2853 <pre><code class="language-stscript">/match pattern="green" {{var::x}} | /echo |/# [ "green" ] ||</code></pre>
2862 <pre><code class="language-stscript">/match pattern="color_(\\w+)" {{var::x}} | /echo |/# [ "color_green", "green" ] ||</code></pre>2854 <pre><code class="language-stscript">/match pattern="color_(\\w+)" {{var::x}} | /echo |/# [ "color_green", "green" ] ||</code></pre>
@@ -2910,7 +2902,7 @@ export function initDefaultSlashCommands() {
2910 },2902 },
2911 unnamedArgumentList: [2903 unnamedArgumentList: [
2912 SlashCommandArgument.fromProps({2904 SlashCommandArgument.fromProps({
2913 description: 'The message index (0-based) to scroll to.',2905 description: t`The message index (0-based) to scroll to.`,
2914 typeList: [ARGUMENT_TYPE.NUMBER],2906 typeList: [ARGUMENT_TYPE.NUMBER],
2915 isRequired: true,2907 isRequired: true,
2916 enumProvider: commonEnumProviders.messages(),2908 enumProvider: commonEnumProviders.messages(),
@@ -2918,20 +2910,20 @@ export function initDefaultSlashCommands() {
2918 ],2910 ],
2919 helpString: `2911 helpString: `
2920 <div>2912 <div>
2921 Scrolls the chat view to the specified message index. Index starts at 0.2913 ${t`Scrolls the chat view to the specified message index. Index starts at 0.`}
2922 </div>2914 </div>
2923 <div>2915 <div>
2924 <strong>Example:</strong> <pre><code>/chat-jump 10</code></pre> Scrolls to the 11th message (id=10).2916 <strong>${t`Example:`}</strong> <pre><code>/chat-jump 10</code></pre> ${t`Scrolls to the 11th message (id=10).`}
2925 </div>2917 </div>
2926 `,2918 `,
2927 }));2919 }));
29282920
2929 SlashCommandParser.addCommandObject(SlashCommand.fromProps({2921 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
2930 name: 'clipboard-get',2922 name: 'clipboard-get',
2931 returns: 'clipboard text',2923 returns: t`clipboard text`,
2932 callback: async () => {2924 callback: async () => {
2933 if (!navigator.clipboard) {2925 if (!navigator.clipboard) {
2934 toastr.warning('Clipboard API not available in this context.');2926 toastr.warning(t`Clipboard API not available in this context.`);
2935 return '';2927 return '';
2936 }2928 }
29372929
@@ -2941,11 +2933,11 @@ export function initDefaultSlashCommands() {
2941 }2933 }
2942 catch (error) {2934 catch (error) {
2943 console.error('Error reading clipboard:', error);2935 console.error('Error reading clipboard:', error);
2944 toastr.warning('Failed to read clipboard text. Have you granted the permission?');2936 toastr.warning(t`Failed to read clipboard text. Have you granted the permission?`);
2945 return '';2937 return '';
2946 }2938 }
2947 },2939 },
2948 helpString: 'Retrieves the text from the OS clipboard. Only works in secure contexts (HTTPS or localhost). Browser may ask for permission.',2940 helpString: t`Retrieves the text from the OS clipboard. Only works in secure contexts (HTTPS or localhost). Browser may ask for permission.`,
2949 }));2941 }));
29502942
2951 SlashCommandParser.addCommandObject(SlashCommand.fromProps({2943 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
@@ -2956,13 +2948,13 @@ export function initDefaultSlashCommands() {
2956 },2948 },
2957 unnamedArgumentList: [2949 unnamedArgumentList: [
2958 SlashCommandArgument.fromProps({2950 SlashCommandArgument.fromProps({
2959 description: 'text to copy to the clipboard',2951 description: t`text to copy to the clipboard`,
2960 typeList: [ARGUMENT_TYPE.STRING],2952 typeList: [ARGUMENT_TYPE.STRING],
2961 isRequired: true,2953 isRequired: true,
2962 acceptsMultiple: false,2954 acceptsMultiple: false,
2963 }),2955 }),
2964 ],2956 ],
2965 helpString: 'Copies the provided text to the OS clipboard. Returns an empty string.',2957 helpString: t`Copies the provided text to the OS clipboard. Returns an empty string.`,
2966 }));2958 }));
29672959
29682960
@@ -2974,10 +2966,10 @@ export function initDefaultSlashCommands() {
2974 aliases: ['ppp'],2966 aliases: ['ppp'],
2975 helpString: `2967 helpString: `
2976 <div>2968 <div>
2977 Sets a "Prompt Post-Processing" type. Gets the current selection if no value is provided.2969 ${t`Sets a "Prompt Post-Processing" type. Gets the current selection if no value is provided.`}
2978 </div>2970 </div>
2979 <div>2971 <div>
2980 <strong>Examples:</strong>2972 <strong>${t`Examples:`}</strong>
2981 </div>2973 </div>
2982 <ul>2974 <ul>
2983 <li><pre><code class="language-stscript">/prompt-post-processing | /echo</code></pre></li>2975 <li><pre><code class="language-stscript">/prompt-post-processing | /echo</code></pre></li>
@@ -2987,7 +2979,7 @@ export function initDefaultSlashCommands() {
2987 namedArgumentList: [],2979 namedArgumentList: [],
2988 unnamedArgumentList: [2980 unnamedArgumentList: [
2989 SlashCommandArgument.fromProps({2981 SlashCommandArgument.fromProps({
2990 description: 'value',2982 description: t`value`,
2991 typeList: [ARGUMENT_TYPE.STRING],2983 typeList: [ARGUMENT_TYPE.STRING],
2992 acceptsMultiple: false,2984 acceptsMultiple: false,
2993 isRequired: true,2985 isRequired: true,
@@ -3003,7 +2995,7 @@ export function initDefaultSlashCommands() {
30032995
3004 const validValues = promptPostProcessingEnumProvider().map(option => option.value);2996 const validValues = promptPostProcessingEnumProvider().map(option => option.value);
3005 if (!validValues.includes(stringValue)) {2997 if (!validValues.includes(stringValue)) {
3006 throw new Error(`Invalid value "${stringValue}". Valid values are: ${validValues.join(', ')}`);2998 throw new Error(t`Invalid value "${stringValue}". Valid values are: ${validValues.join(', ')}`);
3007 }2999 }
30083000
3009 // 'none' value must be coerced to an empty string3001 // 'none' value must be coerced to an empty string
@@ -3056,9 +3048,8 @@ function injectCallback(args, value) {
3056 const filter = args?.filter instanceof SlashCommandClosure ? args.filter.rawText : null;3048 const filter = args?.filter instanceof SlashCommandClosure ? args.filter.rawText : null;
3057 const filterFunction = args?.filter instanceof SlashCommandClosure ? closureToFilter(args.filter) : null;3049 const filterFunction = args?.filter instanceof SlashCommandClosure ? closureToFilter(args.filter) : null;
3058 value = value || '';3050 value = value || '';
3059
3060 if (args?.filter && !String(filter ?? '').trim()) {3051 if (args?.filter && !String(filter ?? '').trim()) {
3061 throw new Error('Failed to parse the filter argument. Make sure it is a valid non-empty closure.');3052 throw new Error(t`Failed to parse the filter argument. Make sure it is a valid non-empty closure.`);
3062 }3053 }
30633054
3064 const prefixedId = `${SCRIPT_PROMPT_KEY}${id}`;3055 const prefixedId = `${SCRIPT_PROMPT_KEY}${id}`;
@@ -3102,10 +3093,10 @@ async function listInjectsCallback(args) {
31023093
3103 // Old legacy return type handling3094 // Old legacy return type handling
3104 if (args.format) {3095 if (args.format) {
3105 toastr.warning(`Legacy argument 'format' with value '${args.format}' is deprecated. Please use 'return' instead. Routing to the correct return type...`, 'Deprecation warning');3096 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`);
3106 const type = String(args?.format).toLowerCase().trim();3097 const type = String(args?.format).toLowerCase().trim();
3107 if (!chat_metadata.script_injects || !Object.keys(chat_metadata.script_injects).length) {3098 if (!chat_metadata.script_injects || !Object.keys(chat_metadata.script_injects).length) {
3108 type !== 'none' && toastr.info('No script injections for the current chat');3099 type !== 'none' && toastr.info(t`No script injections for the current chat`);
3109 }3100 }
3110 switch (type) {3101 switch (type) {
3111 case 'none':3102 case 'none':
@@ -3126,11 +3117,11 @@ async function listInjectsCallback(args) {
3126 const injectsStr = Object.entries(injects)3117 const injectsStr = Object.entries(injects)
3127 .map(([id, inject]) => {3118 .map(([id, inject]) => {
3128 const position = Object.entries(extension_prompt_types);3119 const position = Object.entries(extension_prompt_types);
3129 const positionName = position.find(([_, value]) => value === inject.position)?.[0] ?? 'unknown';3120 const positionName = position.find(([_, value]) => value === inject.position)?.[0] ?? t`unknown`;
3130 return `* **${id}**: <code>${inject.value}</code> (${positionName}, depth: ${inject.depth}, scan: ${inject.scan ?? false}, role: ${inject.role ?? extension_prompt_roles.SYSTEM})`;3121 return `* **${id}**: <code>${inject.value}</code> (${positionName}, ${t`depth`}: ${inject.depth}, ${t`scan`}: ${inject.scan ?? false}, ${t`role`}: ${inject.role ?? extension_prompt_roles.SYSTEM})`;
3131 })3122 })
3132 .join('\n');3123 .join('\n');
3133 return `### Script injections:\n${injectsStr || 'No script injections for the current chat'}`;3124 return `### ${t`Script injections:`}\n${injectsStr || t`No script injections for the current chat`}`;
3134 };3125 };
31353126
3136 return await slashCommandReturnHelper.doReturn(returnType ?? 'popup-html', chat_metadata.script_injects ?? {}, { objectToStringFunc: buildTextValue });3127 return await slashCommandReturnHelper.doReturn(returnType ?? 'popup-html', chat_metadata.script_injects ?? {}, { objectToStringFunc: buildTextValue });
@@ -3381,7 +3372,7 @@ async function popupCallback(args, value) {
3381 wide: isTrueBoolean(args?.wide),3372 wide: isTrueBoolean(args?.wide),
3382 wider: isTrueBoolean(args?.wider),3373 wider: isTrueBoolean(args?.wider),
3383 transparent: isTrueBoolean(args?.transparent),3374 transparent: isTrueBoolean(args?.transparent),
3384 okButton: args?.okButton !== undefined && typeof args?.okButton === 'string' ? args.okButton : 'Ok',3375 okButton: args?.okButton !== undefined && typeof args?.okButton === 'string' ? args.okButton : t`OK`,
3385 cancelButton: args?.cancelButton !== undefined && typeof args?.cancelButton === 'string' ? args.cancelButton : null,3376 cancelButton: args?.cancelButton !== undefined && typeof args?.cancelButton === 'string' ? args.cancelButton : null,
3386 };3377 };
3387 const result = await Popup.show.text(safeHeader, safeBody, popupOptions);3378 const result = await Popup.show.text(safeHeader, safeBody, popupOptions);
@@ -3418,7 +3409,7 @@ async function getMessagesCallback(args, value) {
3418 return !isNarrator && mes.is_user;3409 return !isNarrator && mes.is_user;
3419 }3410 }
34203411
3421 throw new Error(`Invalid role provided. Expected one of: system, assistant, user. Got: ${role}`);3412 throw new Error(t`Invalid role provided. Expected one of: system, assistant, user. Got: ${role}`);
3422 };3413 };
34233414
3424 const processMessage = async (mesId) => {3415 const processMessage = async (mesId) => {
@@ -3453,7 +3444,7 @@ async function getMessagesCallback(args, value) {
34533444
3454async function runCallback(args, name) {3445async function runCallback(args, name) {
3455 if (!name) {3446 if (!name) {
3456 throw new Error('No name provided for /run command');3447 throw new Error(t`No name provided for /run command`);
3457 }3448 }
34583449
3459 if (name instanceof SlashCommandClosure) {3450 if (name instanceof SlashCommandClosure) {
@@ -3466,7 +3457,7 @@ async function runCallback(args, name) {
3466 if (scope.existsVariable(name)) {3457 if (scope.existsVariable(name)) {
3467 const closure = scope.getVariable(name);3458 const closure = scope.getVariable(name);
3468 if (!(closure instanceof SlashCommandClosure)) {3459 if (!(closure instanceof SlashCommandClosure)) {
3469 throw new Error(`"${name}" is not callable.`);3460 throw new Error(t`"${name}" is not callable.`);
3470 }3461 }
3471 closure.scope.parent = scope;3462 closure.scope.parent = scope;
3472 closure.breakController = new SlashCommandBreakController();3463 closure.breakController = new SlashCommandBreakController();
@@ -3487,7 +3478,7 @@ async function runCallback(args, name) {
3487 }3478 }
34883479
3489 if (typeof window['executeQuickReplyByName'] !== 'function') {3480 if (typeof window['executeQuickReplyByName'] !== 'function') {
3490 throw new Error('Quick Reply extension is not loaded');3481 throw new Error(t`Quick Reply extension is not loaded`);
3491 }3482 }
34923483
3493 try {3484 try {
@@ -3499,7 +3490,7 @@ async function runCallback(args, name) {
3499 };3490 };
3500 return await window['executeQuickReplyByName'](name, args, options);3491 return await window['executeQuickReplyByName'](name, args, options);
3501 } catch (error) {3492 } catch (error) {
3502 throw new Error(`Error running Quick Reply "${name}": ${error.message}`);3493 throw new Error(t`Error running Quick Reply "${name}": ${error.message}`);
3503 }3494 }
3504}3495}
35053496
@@ -3509,8 +3500,8 @@ async function runCallback(args, name) {
3509 * @param {string} [reason]3500 * @param {string} [reason]
3510 */3501 */
3511function abortCallback({ _abortController, quiet }, reason) {3502function abortCallback({ _abortController, quiet }, reason) {
3512 if (quiet instanceof SlashCommandClosure) throw new Error('argument \'quiet\' cannot be a closure for command /abort');3503 if (quiet instanceof SlashCommandClosure) throw new Error(t`argument 'quiet' cannot be a closure for command /abort`);
3513 _abortController.abort((reason ?? '').toString().length == 0 ? '/abort command executed' : reason, !isFalseBoolean(quiet?.toString() ?? 'true'));3504 _abortController.abort((reason ?? '').toString().length == 0 ? t`/abort command executed` : reason, !isFalseBoolean(quiet?.toString() ?? 'true'));
3514 return '';3505 return '';
3515}3506}
35163507
@@ -3536,7 +3527,7 @@ async function inputCallback(args, prompt) {
3536 const popupOptions = {3527 const popupOptions = {
3537 large: isTrueBoolean(args?.large),3528 large: isTrueBoolean(args?.large),
3538 wide: isTrueBoolean(args?.wide),3529 wide: isTrueBoolean(args?.wide),
3539 okButton: args?.okButton !== undefined && typeof args?.okButton === 'string' ? args.okButton : 'Ok',3530 okButton: args?.okButton !== undefined && typeof args?.okButton === 'string' ? args.okButton : t`Ok`,
3540 rows: args?.rows !== undefined && typeof args?.rows === 'string' ? isNaN(Number(args.rows)) ? 4 : Number(args.rows) : 4,3531 rows: args?.rows !== undefined && typeof args?.rows === 'string' ? isNaN(Number(args.rows)) ? 4 : Number(args.rows) : 4,
3541 };3532 };
3542 // Do not remove this delay, otherwise the prompt will not show up3533 // Do not remove this delay, otherwise the prompt will not show up
@@ -3549,7 +3540,7 @@ async function inputCallback(args, prompt) {
3549 // Veryify if a cancel handler exists and it is valid3540 // Veryify if a cancel handler exists and it is valid
3550 if (args?.onCancel) {3541 if (args?.onCancel) {
3551 if (!(args.onCancel instanceof SlashCommandClosure)) {3542 if (!(args.onCancel instanceof SlashCommandClosure)) {
3552 throw new Error('argument \'onCancel\' must be a closure for command /input');3543 throw new Error(t`argument 'onCancel' must be a closure for command /input`);
3553 }3544 }
3554 await args.onCancel.execute();3545 await args.onCancel.execute();
3555 }3546 }
@@ -3557,7 +3548,7 @@ async function inputCallback(args, prompt) {
3557 // Verify if an ok handler exists and it is valid3548 // Verify if an ok handler exists and it is valid
3558 if (args?.onSuccess) {3549 if (args?.onSuccess) {
3559 if (!(args.onSuccess instanceof SlashCommandClosure)) {3550 if (!(args.onSuccess instanceof SlashCommandClosure)) {
3560 throw new Error('argument \'onSuccess\' must be a closure for command /input');3551 throw new Error(t`argument 'onSuccess' must be a closure for command /input`);
3561 }3552 }
3562 await args.onSuccess.execute();3553 await args.onSuccess.execute();
3563 }3554 }
@@ -3705,7 +3696,7 @@ async function generateRawCallback(args, value) {
3705 return result;3696 return result;
3706 } catch (err) {3697 } catch (err) {
3707 console.error('Error on /genraw generation', err);3698 console.error('Error on /genraw generation', err);
3708 toastr.error(err.message, 'API Error', { preventDuplicates: true });3699 toastr.error(err.message, t`API Error`, { preventDuplicates: true });
3709 } finally {3700 } finally {
3710 if (lock) {3701 if (lock) {
3711 activateSendButtons();3702 activateSendButtons();
@@ -3751,7 +3742,7 @@ async function generateCallback(args, value) {
3751 return result;3742 return result;
3752 } catch (err) {3743 } catch (err) {
3753 console.error('Error on /gen generation', err);3744 console.error('Error on /gen generation', err);
3754 toastr.error(err.message, 'API Error', { preventDuplicates: true });3745 toastr.error(err.message, t`API Error`, { preventDuplicates: true });
3755 } finally {3746 } finally {
3756 if (lock) {3747 if (lock) {
3757 activateSendButtons();3748 activateSendButtons();
@@ -3775,7 +3766,7 @@ async function echoCallback(args, value) {
3775 }3766 }
37763767
3777 if (args.severity && !['error', 'warning', 'success', 'info'].includes(args.severity)) {3768 if (args.severity && !['error', 'warning', 'success', 'info'].includes(args.severity)) {
3778 toastr.warning(`Invalid severity provided for /echo command: ${args.severity}`);3769 toastr.warning(t`Invalid severity provided for /echo command: ${args.severity}`);
3779 args.severity = null;3770 args.severity = null;
3780 }3771 }
37813772
@@ -3808,7 +3799,7 @@ async function echoCallback(args, value) {
3808 await args.onClick.execute();3799 await args.onClick.execute();
3809 };3800 };
3810 } else {3801 } else {
3811 toastr.warning('Invalid onClick provided for /echo command. This is not a closure');3802 toastr.warning(t`Invalid onClick provided for /echo command. This is not a closure`);
3812 }3803 }
3813 }3804 }
38143805
@@ -3856,7 +3847,7 @@ async function addSwipeCallback(args, value) {
3856 const lastMessage = chat[chat.length - 1];3847 const lastMessage = chat[chat.length - 1];
38573848
3858 if (!lastMessage) {3849 if (!lastMessage) {
3859 toastr.warning('No messages to add swipes to.');3850 toastr.warning(t`No messages to add swipes to.`);
3860 return '';3851 return '';
3861 }3852 }
38623853
@@ -3866,17 +3857,17 @@ async function addSwipeCallback(args, value) {
3866 }3857 }
38673858
3868 if (lastMessage.is_user) {3859 if (lastMessage.is_user) {
3869 toastr.warning('Can\'t add swipes to user messages.');3860 toastr.warning(t`Can't add swipes to user messages.`);
3870 return '';3861 return '';
3871 }3862 }
38723863
3873 if (lastMessage.is_system) {3864 if (lastMessage.is_system) {
3874 toastr.warning('Can\'t add swipes to system messages.');3865 toastr.warning(t`Can't add swipes to system messages.`);
3875 return '';3866 return '';
3876 }3867 }
38773868
3878 if (lastMessage.extra?.image) {3869 if (lastMessage.extra?.image) {
3879 toastr.warning('Can\'t add swipes to message containing an image.');3870 toastr.warning(t`Can't add swipes to message containing an image.`);
3880 return '';3871 return '';
3881 }3872 }
38823873
@@ -3934,12 +3925,12 @@ async function askCharacter(args, text) {
3934 // Not supported in group chats3925 // Not supported in group chats
3935 // TODO: Maybe support group chats?3926 // TODO: Maybe support group chats?
3936 if (selected_group) {3927 if (selected_group) {
3937 toastr.warning('Cannot run /ask command in a group chat!');3928 toastr.warning(t`Cannot run /ask command in a group chat!`);
3938 return '';3929 return '';
3939 }3930 }
39403931
3941 if (!args.name) {3932 if (!args.name) {
3942 toastr.warning('You must specify a name of the character to ask.');3933 toastr.warning(t`You must specify a name of the character to ask.`);
3943 return '';3934 return '';
3944 }3935 }
39453936
@@ -3948,7 +3939,7 @@ async function askCharacter(args, text) {
3948 // Find the character3939 // Find the character
3949 const character = findChar({ name: args?.name });3940 const character = findChar({ name: args?.name });
3950 if (!character) {3941 if (!character) {
3951 toastr.error('Character not found.');3942 toastr.error(t`Character not found.`);
3952 return '';3943 return '';
3953 }3944 }
39543945
@@ -3995,7 +3986,7 @@ async function askCharacter(args, text) {
3995 // Run generate and restore previous character3986 // Run generate and restore previous character
3996 try {3987 try {
3997 eventSource.once(event_types.MESSAGE_RECEIVED, restoreCharacter);3988 eventSource.once(event_types.MESSAGE_RECEIVED, restoreCharacter);
3998 toastr.info(`Asking ${name} something...`);3989 toastr.info(t`Asking ${name} something...`);
3999 askResult = await Generate('normal');3990 askResult = await Generate('normal');
4000 } catch (error) {3991 } catch (error) {
4001 restoreCharacter();3992 restoreCharacter();
@@ -4004,7 +3995,7 @@ async function askCharacter(args, text) {
4004 if (String(this_chid) === String(prevChId)) {3995 if (String(this_chid) === String(prevChId)) {
4005 await saveChatConditional();3996 await saveChatConditional();
4006 } else {3997 } else {
4007 toastr.error('It is strongly recommended to reload the page.', 'Something went wrong');3998 toastr.error(t`It is strongly recommended to reload the page.`, t`Something went wrong`);
4008 }3999 }
4009 }4000 }
40104001
@@ -4073,7 +4064,7 @@ function performGroupMemberAction(chid, action) {
40734064
4074async function disableGroupMemberCallback(_, arg) {4065async function disableGroupMemberCallback(_, arg) {
4075 if (!selected_group) {4066 if (!selected_group) {
4076 toastr.warning('Cannot run /member-disable command outside of a group chat.');4067 toastr.warning(t`Cannot run /member-disable command outside of a group chat.`);
4077 return '';4068 return '';
4078 }4069 }
40794070
@@ -4090,7 +4081,7 @@ async function disableGroupMemberCallback(_, arg) {
40904081
4091async function enableGroupMemberCallback(_, arg) {4082async function enableGroupMemberCallback(_, arg) {
4092 if (!selected_group) {4083 if (!selected_group) {
4093 toastr.warning('Cannot run /member-enable command outside of a group chat.');4084 toastr.warning(t`Cannot run /member-enable command outside of a group chat.`);
4094 return '';4085 return '';
4095 }4086 }
40964087
@@ -4107,7 +4098,7 @@ async function enableGroupMemberCallback(_, arg) {
41074098
4108async function moveGroupMemberUpCallback(_, arg) {4099async function moveGroupMemberUpCallback(_, arg) {
4109 if (!selected_group) {4100 if (!selected_group) {
4110 toastr.warning('Cannot run /member-up command outside of a group chat.');4101 toastr.warning(t`Cannot run /member-up command outside of a group chat.`);
4111 return '';4102 return '';
4112 }4103 }
41134104
@@ -4124,7 +4115,7 @@ async function moveGroupMemberUpCallback(_, arg) {
41244115
4125async function moveGroupMemberDownCallback(_, arg) {4116async function moveGroupMemberDownCallback(_, arg) {
4126 if (!selected_group) {4117 if (!selected_group) {
4127 toastr.warning('Cannot run /member-down command outside of a group chat.');4118 toastr.warning(t`Cannot run /member-down command outside of a group chat.`);
4128 return '';4119 return '';
4129 }4120 }
41304121
@@ -4141,12 +4132,12 @@ async function moveGroupMemberDownCallback(_, arg) {
41414132
4142async function peekCallback(_, arg) {4133async function peekCallback(_, arg) {
4143 if (!selected_group) {4134 if (!selected_group) {
4144 toastr.warning('Cannot run /member-peek command outside of a group chat.');4135 toastr.warning(t`Cannot run /member-peek command outside of a group chat.`);
4145 return '';4136 return '';
4146 }4137 }
41474138
4148 if (is_group_generating) {4139 if (is_group_generating) {
4149 toastr.warning('Cannot run /member-peek command while the group reply is generating.');4140 toastr.warning(t`Cannot run /member-peek command while the group reply is generating.`);
4150 return '';4141 return '';
4151 }4142 }
41524143
@@ -4163,7 +4154,7 @@ async function peekCallback(_, arg) {
41634154
4164async function countGroupMemberCallback() {4155async function countGroupMemberCallback() {
4165 if (!selected_group) {4156 if (!selected_group) {
4166 toastr.warning('Cannot run /member-count command outside of a group chat.');4157 toastr.warning(t`Cannot run /member-count command outside of a group chat.`);
4167 return '';4158 return '';
4168 }4159 }
41694160
@@ -4172,7 +4163,7 @@ async function countGroupMemberCallback() {
41724163
4173async function removeGroupMemberCallback(_, arg) {4164async function removeGroupMemberCallback(_, arg) {
4174 if (!selected_group) {4165 if (!selected_group) {
4175 toastr.warning('Cannot run /member-remove command outside of a group chat.');4166 toastr.warning(t`Cannot run /member-remove command outside of a group chat.`);
4176 return '';4167 return '';
4177 }4168 }
41784169
@@ -4189,7 +4180,7 @@ async function removeGroupMemberCallback(_, arg) {
41894180
4190async function addGroupMemberCallback(_, name) {4181async function addGroupMemberCallback(_, name) {
4191 if (!selected_group) {4182 if (!selected_group) {
4192 toastr.warning('Cannot run /memberadd command outside of a group chat.');4183 toastr.warning(t`Cannot run /memberadd command outside of a group chat.`);
4193 return '';4184 return '';
4194 }4185 }
41954186
@@ -4214,7 +4205,7 @@ async function addGroupMemberCallback(_, name) {
4214 const avatar = character.avatar;4205 const avatar = character.avatar;
42154206
4216 if (group.members.includes(avatar)) {4207 if (group.members.includes(avatar)) {
4217 toastr.warning(`${character.name} is already a member of this group.`);4208 toastr.warning(t`${character.name} is already a member of this group.`);
4218 return '';4209 return '';
4219 }4210 }
42204211
@@ -4233,7 +4224,7 @@ async function triggerGenerationCallback(args, value) {
4233 await waitUntilCondition(() => !is_send_press && !is_group_generating, 10000, 100);4224 await waitUntilCondition(() => !is_send_press && !is_group_generating, 10000, 100);
4234 } catch {4225 } catch {
4235 console.warn('Timeout waiting for generation unlock');4226 console.warn('Timeout waiting for generation unlock');
4236 toastr.warning('Cannot run /trigger command while the reply is being generated.');4227 toastr.warning(t`Cannot run /trigger command while the reply is being generated.`);
4237 outerResolve(Promise.resolve(''));4228 outerResolve(Promise.resolve(''));
4238 return '';4229 return '';
4239 }4230 }
@@ -4338,7 +4329,7 @@ async function deleteMessagesByNameCallback(_, name) {
4338 await saveChatConditional();4329 await saveChatConditional();
4339 await reloadCurrentChat();4330 await reloadCurrentChat();
43404331
4341 toastr.info(`Deleted ${messagesToDelete.length} messages from ${name}`);4332 toastr.info(t`Deleted ${messagesToDelete.length} messages from ${name}`);
4342 return '';4333 return '';
4343}4334}
43444335
@@ -4382,7 +4373,7 @@ async function continueChatCallback(args, prompt) {
4382 await waitUntilCondition(() => !is_send_press && !is_group_generating, 10000, 100);4373 await waitUntilCondition(() => !is_send_press && !is_group_generating, 10000, 100);
4383 } catch {4374 } catch {
4384 console.warn('Timeout waiting for generation unlock');4375 console.warn('Timeout waiting for generation unlock');
4385 toastr.warning('Cannot run /continue command while the reply is being generated.');4376 toastr.warning(t`Cannot run /continue command while the reply is being generated.`);
4386 return reject();4377 return reject();
4387 }4378 }
43884379
@@ -4412,14 +4403,14 @@ export async function generateSystemMessage(args, prompt) {
44124403
4413 if (!prompt) {4404 if (!prompt) {
4414 console.warn('WARN: No prompt provided for /sysgen command');4405 console.warn('WARN: No prompt provided for /sysgen command');
4415 toastr.warning('You must provide a prompt for the system message');4406 toastr.warning(t`You must provide a prompt for the system message`);
4416 return '';4407 return '';
4417 }4408 }
44184409
4419 const trim = isTrueBoolean(args?.trim?.toString());4410 const trim = isTrueBoolean(args?.trim?.toString());
44204411
4421 // Generate and regex the output if applicable4412 // Generate and regex the output if applicable
4422 const toast = toastr.info('Please wait', 'Generating...');4413 const toast = toastr.info(t`Please wait`, t`Generating...`);
4423 const message = await generateQuietPrompt({ quietPrompt: prompt, trimToSentence: trim });4414 const message = await generateQuietPrompt({ quietPrompt: prompt, trimToSentence: trim });
4424 toastr.clear(toast);4415 toastr.clear(toast);
44254416
@@ -4444,7 +4435,7 @@ function setFlatModeCallback() {
4444async function setNarratorName(_, text) {4435async function setNarratorName(_, text) {
4445 const name = text || NARRATOR_NAME_DEFAULT;4436 const name = text || NARRATOR_NAME_DEFAULT;
4446 chat_metadata[NARRATOR_NAME_KEY] = name;4437 chat_metadata[NARRATOR_NAME_KEY] = name;
4447 toastr.info(`System narrator name set to ${name}`);4438 toastr.info(t`System narrator name set to ${name}`);
4448 await saveChatConditional();4439 await saveChatConditional();
4449 return '';4440 return '';
4450}4441}
@@ -4461,10 +4452,10 @@ async function setNarratorName(_, text) {
4461export function validateArrayArgString(arg, name, { allowUndefined = true } = {}) {4452export function validateArrayArgString(arg, name, { allowUndefined = true } = {}) {
4462 if (arg === undefined) {4453 if (arg === undefined) {
4463 if (allowUndefined) return undefined;4454 if (allowUndefined) return undefined;
4464 throw new Error(`Argument "${name}" is undefined, but must be a string array`);4455 throw new Error(t`Argument "${name}" is undefined, but must be a string array`);
4465 }4456 }
4466 if (!Array.isArray(arg)) throw new Error(`Argument "${name}" must be an array`);4457 if (!Array.isArray(arg)) throw new Error(t`Argument "${name}" must be an array`);
4467 if (!arg.every(x => typeof x === 'string')) throw new Error(`Argument "${name}" must be an array of strings`);4458 if (!arg.every(x => typeof x === 'string')) throw new Error(t`Argument "${name}" must be an array of strings`);
4468 return arg;4459 return arg;
4469}4460}
44704461
@@ -4480,10 +4471,10 @@ export function validateArrayArgString(arg, name, { allowUndefined = true } = {}
4480export function validateArrayArg(arg, name, { allowUndefined = true } = {}) {4471export function validateArrayArg(arg, name, { allowUndefined = true } = {}) {
4481 if (arg === undefined) {4472 if (arg === undefined) {
4482 if (allowUndefined) return [];4473 if (allowUndefined) return [];
4483 throw new Error(`Argument "${name}" is undefined, but must be an array of strings or closures`);4474 throw new Error(t`Argument "${name}" is undefined, but must be an array of strings or closures`);
4484 }4475 }
4485 if (!Array.isArray(arg)) throw new Error(`Argument "${name}" must be an array`);4476 if (!Array.isArray(arg)) throw new Error(t`Argument "${name}" must be an array`);
4486 if (!arg.every(x => typeof x === 'string' || x instanceof SlashCommandClosure)) throw new Error(`Argument "${name}" must be an array of strings or closures`);4477 if (!arg.every(x => typeof x === 'string' || x instanceof SlashCommandClosure)) throw new Error(t`Argument "${name}" must be an array of strings or closures`);
4487 return arg;4478 return arg;
4488}4479}
44894480
@@ -4528,7 +4519,7 @@ export async function sendMessageAs(args, text) {
4528 if (!name) {4519 if (!name) {
4529 const namelessWarningKey = 'sendAsNamelessWarningShown';4520 const namelessWarningKey = 'sendAsNamelessWarningShown';
4530 if (accountStorage.getItem(namelessWarningKey) !== 'true') {4521 if (accountStorage.getItem(namelessWarningKey) !== 'true') {
4531 toastr.warning('To avoid confusion, please use /sendas name="Character Name"', 'Name defaulted to {{char}}', { timeOut: 10000 });4522 toastr.warning(t`To avoid confusion, please use /sendas name="Character Name"`, t`Name defaulted to {{char}}`, { timeOut: 10000 });
4532 accountStorage.setItem(namelessWarningKey, 'true');4523 accountStorage.setItem(namelessWarningKey, 'true');
4533 }4524 }
4534 name = name2;4525 name = name2;
@@ -4548,7 +4539,7 @@ export async function sendMessageAs(args, text) {
45484539
4549 const avatarCharacter = args.avatar ? findChar({ name: args.avatar }) : character;4540 const avatarCharacter = args.avatar ? findChar({ name: args.avatar }) : character;
4550 if (args.avatar && !avatarCharacter) {4541 if (args.avatar && !avatarCharacter) {
4551 toastr.warning(`Character for avatar ${args.avatar} not found`);4542 toastr.warning(t`Character for avatar ${args.avatar} not found`);
4552 return '';4543 return '';
4553 }4544 }
45544545
@@ -4805,7 +4796,7 @@ function setBackgroundCallback(_, bg) {
4805 const result = fuse.search(bg);4796 const result = fuse.search(bg);
48064797
4807 if (!result.length) {4798 if (!result.length) {
4808 toastr.error(`No background found with name "${bg}"`);4799 toastr.error(t`No background found with name "${bg}"`);
4809 return '';4800 return '';
4810 }4801 }
48114802
@@ -4877,14 +4868,14 @@ function getModelOptions(quiet) {
4877 const modelSelectItem = modelSelectMap.find(x => x.api == main_api && x.type == apiSubType)?.id;4868 const modelSelectItem = modelSelectMap.find(x => x.api == main_api && x.type == apiSubType)?.id;
48784869
4879 if (!modelSelectItem) {4870 if (!modelSelectItem) {
4880 !quiet && toastr.info('Setting a model for your API is not supported or not implemented yet.');4871 !quiet && toastr.info(t`Setting a model for your API is not supported or not implemented yet.`);
4881 return nullResult;4872 return nullResult;
4882 }4873 }
48834874
4884 const modelSelectControl = document.getElementById(modelSelectItem);4875 const modelSelectControl = document.getElementById(modelSelectItem);
48854876
4886 if (!(modelSelectControl instanceof HTMLSelectElement) && !(modelSelectControl instanceof HTMLInputElement)) {4877 if (!(modelSelectControl instanceof HTMLSelectElement) && !(modelSelectControl instanceof HTMLInputElement)) {
4887 !quiet && toastr.error(`Model select control not found: ${main_api}[${apiSubType}]`);4878 !quiet && toastr.error(t`Model select control not found: ${main_api}[${apiSubType}]`);
4888 return nullResult;4879 return nullResult;
4889 }4880 }
48904881
@@ -4937,12 +4928,12 @@ function modelCallback(args, model) {
4937 if (modelSelectControl instanceof HTMLInputElement) {4928 if (modelSelectControl instanceof HTMLInputElement) {
4938 modelSelectControl.value = model;4929 modelSelectControl.value = model;
4939 $(modelSelectControl).trigger('input');4930 $(modelSelectControl).trigger('input');
4940 !quiet && toastr.success(`Model set to "${model}"`);4931 !quiet && toastr.success(t`Model set to "${model}"`);
4941 return model;4932 return model;
4942 }4933 }
49434934
4944 if (!options.length) {4935 if (!options.length) {
4945 !quiet && toastr.warning('No model options found. Check your API settings.');4936 !quiet && toastr.warning(t`No model options found. Check your API settings.`);
4946 return '';4937 return '';
4947 }4938 }
49484939
@@ -4965,10 +4956,10 @@ function modelCallback(args, model) {
4965 if (newSelectedOption) {4956 if (newSelectedOption) {
4966 modelSelectControl.value = newSelectedOption.value;4957 modelSelectControl.value = newSelectedOption.value;
4967 $(modelSelectControl).trigger('change');4958 $(modelSelectControl).trigger('change');
4968 !quiet && toastr.success(`Model set to "${newSelectedOption.text}"`);4959 !quiet && toastr.success(t`Model set to "${newSelectedOption.text}"`);
4969 return newSelectedOption.value;4960 return newSelectedOption.value;
4970 } else {4961 } else {
4971 !quiet && toastr.warning(`No model found with name "${model}"`);4962 !quiet && toastr.warning(t`No model found with name "${model}"`);
4972 return '';4963 return '';
4973 }4964 }
4974}4965}
@@ -5149,7 +5140,7 @@ async function setApiUrlCallback({ api = null, connect = 'true', quiet = 'false'
5149 }5140 }
51505141
5151 if (!isCurrentlyCustomOpenai && autoConnect) {5142 if (!isCurrentlyCustomOpenai && autoConnect) {
5152 toastr.warning('Custom OpenAI API is not the currently selected API, so we cannot do an auto-connect. Consider switching to it via /api beforehand.');5143 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.`);
5153 return '';5144 return '';
5154 }5145 }
51555146
@@ -5170,7 +5161,7 @@ async function setApiUrlCallback({ api = null, connect = 'true', quiet = 'false'
5170 }5161 }
51715162
5172 if (!isCurrentlyKoboldClassic && autoConnect) {5163 if (!isCurrentlyKoboldClassic && autoConnect) {
5173 toastr.warning('Kobold Classic API is not the currently selected API, so we cannot do an auto-connect. Consider switching to it via /api beforehand.');5164 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.`);
5174 return '';5165 return '';
5175 }5166 }
51765167
@@ -5187,26 +5178,26 @@ async function setApiUrlCallback({ api = null, connect = 'true', quiet = 'false'
51875178
5188 // Do some checks and get the api type we are targeting with this command5179 // Do some checks and get the api type we are targeting with this command
5189 if (api && !Object.values(textgen_types).includes(api)) {5180 if (api && !Object.values(textgen_types).includes(api)) {
5190 !isQuiet && toastr.warning(`API '${api}' is not a valid text_gen API.`);5181 !isQuiet && toastr.warning(t`API '${api}' is not a valid text_gen API.`);
5191 return '';5182 return '';
5192 }5183 }
5193 if (!api && !Object.values(textgen_types).includes(textgenerationwebui_settings.type)) {5184 if (!api && !Object.values(textgen_types).includes(textgenerationwebui_settings.type)) {
5194 !isQuiet && toastr.warning(`API '${textgenerationwebui_settings.type}' is not a valid text_gen API.`);5185 !isQuiet && toastr.warning(t`API '${textgenerationwebui_settings.type}' is not a valid text_gen API.`);
5195 return '';5186 return '';
5196 }5187 }
5197 if (!api && main_api !== 'textgenerationwebui') {5188 if (!api && main_api !== 'textgenerationwebui') {
5198 !isQuiet && toastr.warning(`API type '${main_api}' does not support setting the server URL.`);5189 !isQuiet && toastr.warning(t`API type '${main_api}' does not support setting the server URL.`);
5199 return '';5190 return '';
5200 }5191 }
5201 if (api && url && autoConnect && api !== textgenerationwebui_settings.type) {5192 if (api && url && autoConnect && api !== textgenerationwebui_settings.type) {
5202 !isQuiet && toastr.warning(`API '${api}' is not the currently selected API, so we cannot do an auto-connect. Consider switching to it via /api beforehand.`);5193 !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.`);
5203 return '';5194 return '';
5204 }5195 }
5205 const type = api || textgenerationwebui_settings.type;5196 const type = api || textgenerationwebui_settings.type;
52065197
5207 const inputSelector = SERVER_INPUTS[type];5198 const inputSelector = SERVER_INPUTS[type];
5208 if (!inputSelector) {5199 if (!inputSelector) {
5209 !isQuiet && toastr.warning(`API '${type}' does not have a server url input.`);5200 !isQuiet && toastr.warning(t`API '${type}' does not have a server url input.`);
5210 return '';5201 return '';
5211 }5202 }
52125203
@@ -5239,7 +5230,7 @@ async function selectTokenizerCallback(_, name) {
5239 const result = fuse.search(name);5230 const result = fuse.search(name);
52405231
5241 if (result.length === 0) {5232 if (result.length === 0) {
5242 toastr.warning(`Tokenizer "${name}" not found`);5233 toastr.warning(t`Tokenizer "${name}" not found`);
5243 return '';5234 return '';
5244 }5235 }
52455236
@@ -5398,17 +5389,17 @@ export async function executeSlashCommandsOnChatInput(text, options = {}) {
5398 document.querySelector('#form_sheld').classList.add('script_error');5389 document.querySelector('#form_sheld').classList.add('script_error');
5399 result = new SlashCommandClosureResult();5390 result = new SlashCommandClosureResult();
5400 result.isError = true;5391 result.isError = true;
5401 result.errorMessage = e.message || 'An unknown error occurred';5392 result.errorMessage = e.message || t`An unknown error occurred`;
5402 if (e.cause !== 'abort') {5393 if (e.cause !== 'abort') {
5403 if (e instanceof SlashCommandExecutionError) {5394 if (e instanceof SlashCommandExecutionError) {
5404 /**@type {SlashCommandExecutionError}*/5395 /**@type {SlashCommandExecutionError}*/
5405 const ex = e;5396 const ex = e;
5406 const toast = `5397 const toast = `
5407 <div>${ex.message}</div>5398 <div>${ex.message}</div>
5408 <div>Line: ${ex.line} Column: ${ex.column}</div>5399 <div>${t`Line`}: ${ex.line} ${t`Column`}: ${ex.column}</div>
5409 <pre style="text-align:left;">${ex.hint}</pre>5400 <pre style="text-align:left;">${ex.hint}</pre>
5410 `;5401 `;
5411 const clickHint = '<p>Click to see details</p>';5402 const clickHint = `<p>${t`Click to see details`}</p>`;
5412 toastr.error(5403 toastr.error(
5413 `${toast}${clickHint}`,5404 `${toast}${clickHint}`,
5414 'Slash Command Execution Error',5405 'Slash Command Execution Error',
@@ -5462,10 +5453,10 @@ async function executeSlashCommandsWithOptions(text, options = {}) {
5462 const ex = e;5453 const ex = e;
5463 const toast = `5454 const toast = `
5464 <div>${ex.message}</div>5455 <div>${ex.message}</div>
5465 <div>Line: ${ex.line} Column: ${ex.column}</div>5456 <div>${t`Line`}: ${ex.line} ${t`Column`}: ${ex.column}</div>
5466 <pre style="text-align:left;">${ex.hint}</pre>5457 <pre style="text-align:left;">${ex.hint}</pre>
5467 `;5458 `;
5468 const clickHint = '<p>Click to see details</p>';5459 const clickHint = `<p>${t`Click to see details`}</p>`;
5469 toastr.error(5460 toastr.error(
5470 `${toast}${clickHint}`,5461 `${toast}${clickHint}`,
5471 'SlashCommandParserError',5462 'SlashCommandParserError',
@@ -5481,7 +5472,7 @@ async function executeSlashCommandsWithOptions(text, options = {}) {
5481 try {5472 try {
5482 const result = await closure.execute();5473 const result = await closure.execute();
5483 if (result.isAborted && !result.isQuietlyAborted) {5474 if (result.isAborted && !result.isQuietlyAborted) {
5484 toastr.warning(result.abortReason, 'Command execution aborted');5475 toastr.warning(result.abortReason, t`Command execution aborted`);
5485 closure.abortController.signal.isQuiet = true;5476 closure.abortController.signal.isQuiet = true;
5486 }5477 }
5487 return result;5478 return result;
public/scripts/slash-commands/SlashCommand.js+14 -15
@@ -7,13 +7,12 @@ import { SlashCommandDebugController } from './SlashCommandDebugController.js';
7import { SlashCommandScope } from './SlashCommandScope.js';7import { SlashCommandScope } from './SlashCommandScope.js';
88
9/**9/**
10 * @typedef {{10 * @typedef {NamedArgumentsCapture & {
11 * _scope:SlashCommandScope,11 * _scope:SlashCommandScope,
12 * _parserFlags:import('./SlashCommandParser.js').ParserFlags,12 * _parserFlags:import('./SlashCommandParser.js').ParserFlags,
13 * _abortController:SlashCommandAbortController,13 * _abortController:SlashCommandAbortController,
14 * _debugController:SlashCommandDebugController,14 * _debugController:SlashCommandDebugController,
15 * _hasUnnamedArgument:boolean,15 * _hasUnnamedArgument:boolean,
16 * [id:string]:string|SlashCommandClosure|(string|SlashCommandClosure)[]|undefined,
17 * }} NamedArguments16 * }} NamedArguments
18 */17 */
1918
@@ -52,7 +51,7 @@ export class SlashCommand {
5251
5352
54 /**@type {string}*/ name;53 /**@type {string}*/ name;
55 /**@type {(namedArguments:{_scope:SlashCommandScope, _abortController:SlashCommandAbortController, [id:string]:string|SlashCommandClosure}, unnamedArguments:string|SlashCommandClosure|(string|SlashCommandClosure)[])=>string|SlashCommandClosure|Promise<string|SlashCommandClosure>}*/ callback;54 /**@type {(namedArguments:NamedArguments, unnamedArguments:UnnamedArguments)=>string|SlashCommandClosure|Promise<string|SlashCommandClosure>}*/ callback;
56 /**@type {string}*/ helpString;55 /**@type {string}*/ helpString;
57 /**@type {boolean}*/ splitUnnamedArgument = false;56 /**@type {boolean}*/ splitUnnamedArgument = false;
58 /**@type {Number}*/ splitUnnamedArgumentCount;57 /**@type {Number}*/ splitUnnamedArgumentCount;
@@ -238,7 +237,7 @@ export class SlashCommand {
238 const name = document.createElement('div'); {237 const name = document.createElement('div'); {
239 name.classList.add('name');238 name.classList.add('name');
240 name.classList.add('monospace');239 name.classList.add('monospace');
241 name.title = 'command name';240 name.title = t`Command name`;
242 name.textContent = `/${key}`;241 name.textContent = `/${key}`;
243 head.append(name);242 head.append(name);
244 }243 }
@@ -284,19 +283,19 @@ export class SlashCommand {
284 const argItem = document.createElement('div'); {283 const argItem = document.createElement('div'); {
285 argItem.classList.add('argument');284 argItem.classList.add('argument');
286 argItem.classList.add('namedArgument');285 argItem.classList.add('namedArgument');
287 argItem.title = `${arg.isRequired ? '' : 'optional '}named argument`;286 argItem.title = arg.isRequired ? t`Named argument` : t`Optional named argument`;
288 if (!arg.isRequired || (arg.defaultValue ?? false)) argItem.classList.add('optional');287 if (!arg.isRequired || (arg.defaultValue ?? false)) argItem.classList.add('optional');
289 if (arg.acceptsMultiple) argItem.classList.add('multiple');288 if (arg.acceptsMultiple) argItem.classList.add('multiple');
290 const name = document.createElement('span'); {289 const name = document.createElement('span'); {
291 name.classList.add('argument-name');290 name.classList.add('argument-name');
292 name.title = `${argItem.title} - name`;291 name.title = t`${argItem.title} - Name`;
293 name.textContent = arg.name;292 name.textContent = arg.name;
294 argItem.append(name);293 argItem.append(name);
295 }294 }
296 if (arg.enumList.length > 0) {295 if (arg.enumList.length > 0) {
297 const enums = document.createElement('span'); {296 const enums = document.createElement('span'); {
298 enums.classList.add('argument-enums');297 enums.classList.add('argument-enums');
299 enums.title = `${argItem.title} - accepted values`;298 enums.title = t`${argItem.title} - Accepted values`;
300 for (const e of arg.enumList) {299 for (const e of arg.enumList) {
301 const enumItem = document.createElement('span'); {300 const enumItem = document.createElement('span'); {
302 enumItem.classList.add('argument-enum');301 enumItem.classList.add('argument-enum');
@@ -309,7 +308,7 @@ export class SlashCommand {
309 } else {308 } else {
310 const types = document.createElement('span'); {309 const types = document.createElement('span'); {
311 types.classList.add('argument-types');310 types.classList.add('argument-types');
312 types.title = `${argItem.title} - accepted types`;311 types.title = t`${argItem.title} - Accepted types`;
313 for (const t of arg.typeList) {312 for (const t of arg.typeList) {
314 const type = document.createElement('span'); {313 const type = document.createElement('span'); {
315 type.classList.add('argument-type');314 type.classList.add('argument-type');
@@ -325,7 +324,7 @@ export class SlashCommand {
325 if (arg.defaultValue !== null) {324 if (arg.defaultValue !== null) {
326 const argDefault = document.createElement('div'); {325 const argDefault = document.createElement('div'); {
327 argDefault.classList.add('argument-default');326 argDefault.classList.add('argument-default');
328 argDefault.title = 'default value';327 argDefault.title = t`Default value`;
329 argDefault.textContent = arg.defaultValue.toString();328 argDefault.textContent = arg.defaultValue.toString();
330 argSpec.append(argDefault);329 argSpec.append(argDefault);
331 }330 }
@@ -348,13 +347,13 @@ export class SlashCommand {
348 const argItem = document.createElement('div'); {347 const argItem = document.createElement('div'); {
349 argItem.classList.add('argument');348 argItem.classList.add('argument');
350 argItem.classList.add('unnamedArgument');349 argItem.classList.add('unnamedArgument');
351 argItem.title = `${arg.isRequired ? '' : 'optional '}unnamed argument`;350 argItem.title = arg.isRequired ? t`Unnamed argument` : t`Optional unnamed argument`;
352 if (!arg.isRequired || (arg.defaultValue ?? false)) argItem.classList.add('optional');351 if (!arg.isRequired || (arg.defaultValue ?? false)) argItem.classList.add('optional');
353 if (arg.acceptsMultiple) argItem.classList.add('multiple');352 if (arg.acceptsMultiple) argItem.classList.add('multiple');
354 if (arg.enumList.length > 0) {353 if (arg.enumList.length > 0) {
355 const enums = document.createElement('span'); {354 const enums = document.createElement('span'); {
356 enums.classList.add('argument-enums');355 enums.classList.add('argument-enums');
357 enums.title = `${argItem.title} - accepted values`;356 enums.title = t`${argItem.title} - Accepted values`;
358 for (const e of arg.enumList) {357 for (const e of arg.enumList) {
359 const enumItem = document.createElement('span'); {358 const enumItem = document.createElement('span'); {
360 enumItem.classList.add('argument-enum');359 enumItem.classList.add('argument-enum');
@@ -367,7 +366,7 @@ export class SlashCommand {
367 } else {366 } else {
368 const types = document.createElement('span'); {367 const types = document.createElement('span'); {
369 types.classList.add('argument-types');368 types.classList.add('argument-types');
370 types.title = `${argItem.title} - accepted types`;369 types.title = t`${argItem.title} - Accepted types`;
371 for (const t of arg.typeList) {370 for (const t of arg.typeList) {
372 const type = document.createElement('span'); {371 const type = document.createElement('span'); {
373 type.classList.add('argument-type');372 type.classList.add('argument-type');
@@ -383,7 +382,7 @@ export class SlashCommand {
383 if (arg.defaultValue !== null) {382 if (arg.defaultValue !== null) {
384 const argDefault = document.createElement('div'); {383 const argDefault = document.createElement('div'); {
385 argDefault.classList.add('argument-default');384 argDefault.classList.add('argument-default');
386 argDefault.title = 'default value';385 argDefault.title = t`Default value`;
387 argDefault.textContent = arg.defaultValue.toString();386 argDefault.textContent = arg.defaultValue.toString();
388 argSpec.append(argDefault);387 argSpec.append(argDefault);
389 }388 }
@@ -402,7 +401,7 @@ export class SlashCommand {
402 }401 }
403 const returns = document.createElement('span'); {402 const returns = document.createElement('span'); {
404 returns.classList.add('returns');403 returns.classList.add('returns');
405 returns.title = [null, undefined, 'void'].includes(returnType) ? 'command does not return anything' : 'return value';404 returns.title = [null, undefined, 'void'].includes(returnType) ? t`Command does not return anything` : t`Return value`;
406 returns.textContent = returnType ?? 'void';405 returns.textContent = returnType ?? 'void';
407 body.append(returns);406 body.append(returns);
408 }407 }
@@ -415,7 +414,7 @@ export class SlashCommand {
415 help.innerHTML = helpString;414 help.innerHTML = helpString;
416 for (const code of help.querySelectorAll('pre > code')) {415 for (const code of help.querySelectorAll('pre > code')) {
417 code.classList.add('language-stscript');416 code.classList.add('language-stscript');
418 hljs.highlightElement(code);417 hljs.highlightElement(/**@type {HTMLElement}*/(code));
419 }418 }
420 frag.append(help);419 frag.append(help);
421 }420 }