Merge branch 'staging' into parser-followup-2

This commit is contained in:
LenAnderson
2024-06-23 11:37:00 -04:00
47 changed files with 2334 additions and 859 deletions

View File

@ -42,9 +42,9 @@ import { PARSER_FLAG, SlashCommandParser } from './slash-commands/SlashCommandPa
import { SlashCommandParserError } from './slash-commands/SlashCommandParserError.js';
import { getMessageTimeStamp } from './RossAscends-mods.js';
import { hideChatMessageRange } from './chats.js';
import { getContext, saveMetadataDebounced } from './extensions.js';
import { extension_settings, getContext, saveMetadataDebounced } from './extensions.js';
import { getRegexedString, regex_placement } from './extensions/regex/engine.js';
import { findGroupMemberId, groups, is_group_generating, openGroupById, resetSelectedGroup, saveGroupChat, selected_group } from './group-chats.js';
import { findGroupMemberId, getGroupMembers, groups, is_group_generating, openGroupById, resetSelectedGroup, saveGroupChat, selected_group } from './group-chats.js';
import { chat_completion_sources, oai_settings, setupChatCompletionPromptManager } from './openai.js';
import { autoSelectPersona, retriggerFirstMessageOnEmptyChat, user_avatar } from './personas.js';
import { addEphemeralStoppingString, chat_styles, flushEphemeralStoppingStrings, power_user } from './power-user.js';
@ -61,8 +61,9 @@ import { AutoComplete } from './autocomplete/AutoComplete.js';
import { SlashCommand } from './slash-commands/SlashCommand.js';
import { SlashCommandAbortController } from './slash-commands/SlashCommandAbortController.js';
import { SlashCommandNamedArgumentAssignment } from './slash-commands/SlashCommandNamedArgumentAssignment.js';
import { SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js';
import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js';
import { POPUP_TYPE, Popup, callGenericPopup } from './popup.js';
import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js';
import { SlashCommandDebugController } from './slash-commands/SlashCommandDebugController.js';
export {
executeSlashCommands, executeSlashCommandsWithOptions, getSlashCommandsHelp, registerSlashCommand,
@ -79,9 +80,16 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: '?',
callback: helpCommandCallback,
aliases: ['help'],
unnamedArgumentList: [new SlashCommandArgument(
'help topic', ARGUMENT_TYPE.STRING, false, false, null, ['slash', 'format', 'hotkeys', 'macros'],
)],
unnamedArgumentList: [SlashCommandArgument.fromProps({
description: 'help topic',
typeList: [ARGUMENT_TYPE.STRING],
enumList: [
new SlashCommandEnumValue('slash', 'slash commands (STscript)', enumTypes.command, '/'),
new SlashCommandEnumValue('macros', '{{macros}} (text replacement)', enumTypes.macro, enumIcons.macro),
new SlashCommandEnumValue('format', 'chat/text formatting', enumTypes.name, '★'),
new SlashCommandEnumValue('hotkeys', 'keyboard shortcuts', enumTypes.enum, '⏎'),
],
})],
helpString: 'Get help on macros, chat formatting and commands.',
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
@ -94,9 +102,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
),
],
unnamedArgumentList: [
new SlashCommandArgument(
'persona name', [ARGUMENT_TYPE.STRING], true,
),
SlashCommandArgument.fromProps({
description: 'persona name',
typeList: [ARGUMENT_TYPE.STRING],
isRequired: true,
enumProvider: commonEnumProviders.personas,
}),
],
helpString: 'Selects the given persona with its name and avatar (by name or avatar url). If no matching persona exists, applies a temporary name.',
aliases: ['name'],
@ -123,9 +134,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
typeList: [ARGUMENT_TYPE.STRING],
isRequired: true,
enumProvider: () => [...document.querySelectorAll('.bg_example')]
.map((it) => new SlashCommandEnumValue(it.getAttribute('bgfile')))
.filter(it => it.value?.length)
,
.map(it => new SlashCommandEnumValue(it.getAttribute('bgfile')))
.filter(it => it.value?.length),
}),
],
helpString: `
@ -146,16 +156,22 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'sendas',
callback: sendMessageAs,
namedArgumentList: [
SlashCommandNamedArgument.fromProps({
name: 'name',
description: 'Character name',
typeList: [ARGUMENT_TYPE.STRING],
isRequired: true,
enumProvider: commonEnumProviders.characters('character'),
forceEnum: false,
}),
new SlashCommandNamedArgument(
'name', 'Character name', [ARGUMENT_TYPE.STRING], true,
),
new SlashCommandNamedArgument(
'compact', 'Use compact layout', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false', ['true', 'false'],
'compact', 'Use compact layout', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false',
),
SlashCommandNamedArgument.fromProps({
name: 'at',
description: 'position to insert the message',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
enumProvider: commonEnumProviders.messages({ allowIdAfter: true, allowVars: true }),
}),
],
unnamedArgumentList: [
@ -198,6 +214,7 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'at',
description: 'position to insert the message',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
enumProvider: commonEnumProviders.messages({ allowIdAfter: true, allowVars: true }),
}),
],
unnamedArgumentList: [
@ -251,6 +268,7 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'at',
description: 'position to insert the message',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
enumProvider: commonEnumProviders.messages({ allowIdAfter: true, allowVars: true }),
}),
],
unnamedArgumentList: [
@ -334,10 +352,7 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
description: 'name',
typeList: [ARGUMENT_TYPE.STRING],
isRequired: true,
enumProvider: () => [
...characters.map(it => new SlashCommandEnumValue(it.name, null, 'qr', 'C')),
...groups.map(it => new SlashCommandEnumValue(it.name, null, 'variable', 'G')),
],
enumProvider: commonEnumProviders.characters('all'),
}),
],
helpString: 'Opens up a chat with the character or group by its name',
@ -385,7 +400,7 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
description: 'character name',
typeList: [ARGUMENT_TYPE.STRING],
isRequired: true,
enumProvider: () => characters.map(it => new SlashCommandEnumValue(it.name, null, 'qr', 'C')),
enumProvider: commonEnumProviders.characters('character'),
}),
],
unnamedArgumentList: [
@ -400,9 +415,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
callback: deleteMessagesByNameCallback,
namedArgumentList: [],
unnamedArgumentList: [
new SlashCommandArgument(
'name', [ARGUMENT_TYPE.STRING], true,
),
SlashCommandArgument.fromProps({
description: 'name',
typeList: [ARGUMENT_TYPE.STRING],
isRequired: true,
enumProvider: commonEnumProviders.characters('character'),
}),
],
aliases: ['cancel'],
helpString: `
@ -435,15 +453,18 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'at',
description: 'position to insert the message',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
enumProvider: commonEnumProviders.messages({ allowIdAfter: true, allowVars: true }),
}),
SlashCommandNamedArgument.fromProps({
name: 'name',
description: 'display name',
typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME],
defaultValue: '{{user}}',
enumProvider: () => [
...commonEnumProviders.characters('character')(),
...commonEnumProviders.variables('all')().map(x => { x.description = 'Variable'; return x; }),
],
}),
new SlashCommandNamedArgument(
'name',
'display name',
[ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME],
false,
false,
'{{user}}',
),
],
unnamedArgumentList: [
new SlashCommandArgument(
@ -488,6 +509,14 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
'false',
),
],
unnamedArgumentList: [
SlashCommandArgument.fromProps({
description: 'group member index (starts with 0) or name',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
isRequired: false,
enumProvider: commonEnumProviders.groupMembers(),
}),
],
helpString: `
<div>
Triggers a message generation. If in group, can trigger a message for the specified group member index or name.
@ -501,9 +530,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'hide',
callback: hideMessageCallback,
unnamedArgumentList: [
new SlashCommandArgument(
'message index or range', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE], true,
),
SlashCommandArgument.fromProps({
description: 'message index (starts with 0) or range',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE],
isRequired: true,
enumProvider: commonEnumProviders.messages(),
}),
],
helpString: 'Hides a chat message from the prompt.',
}));
@ -511,9 +543,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'unhide',
callback: unhideMessageCallback,
unnamedArgumentList: [
new SlashCommandArgument(
'message index or range', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE], true,
),
SlashCommandArgument.fromProps({
description: 'message index (starts with 0) or range',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE],
isRequired: true,
enumProvider: commonEnumProviders.messages(),
}),
],
helpString: 'Unhides a message from the prompt.',
}));
@ -522,9 +557,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
callback: disableGroupMemberCallback,
aliases: ['disable', 'disablemember', 'memberdisable'],
unnamedArgumentList: [
new SlashCommandArgument(
'member index or name', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], true,
),
SlashCommandArgument.fromProps({
description: 'member index (starts with 0) or name',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
isRequired: true,
enumProvider: commonEnumProviders.groupMembers(),
}),
],
helpString: 'Disables a group member from being drafted for replies.',
}));
@ -533,9 +571,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
aliases: ['enable', 'enablemember', 'memberenable'],
callback: enableGroupMemberCallback,
unnamedArgumentList: [
new SlashCommandArgument(
'member index or name', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], true,
),
SlashCommandArgument.fromProps({
description: 'member index (starts with 0) or name',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
isRequired: true,
enumProvider: commonEnumProviders.groupMembers(),
}),
],
helpString: 'Enables a group member to be drafted for replies.',
}));
@ -544,9 +585,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
callback: addGroupMemberCallback,
aliases: ['addmember', 'memberadd'],
unnamedArgumentList: [
new SlashCommandArgument(
'character name', [ARGUMENT_TYPE.STRING], true,
),
SlashCommandArgument.fromProps({
description: 'character name',
typeList: [ARGUMENT_TYPE.STRING],
isRequired: true,
enumProvider: () => selected_group ? commonEnumProviders.characters('character')() : [],
}),
],
helpString: `
<div>
@ -567,9 +611,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
callback: removeGroupMemberCallback,
aliases: ['removemember', 'memberremove'],
unnamedArgumentList: [
new SlashCommandArgument(
'member index or name', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], true,
),
SlashCommandArgument.fromProps({
description: 'member index (starts with 0) or name',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
isRequired: true,
enumProvider: commonEnumProviders.groupMembers(),
}),
],
helpString: `
<div>
@ -591,9 +638,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
callback: moveGroupMemberUpCallback,
aliases: ['upmember', 'memberup'],
unnamedArgumentList: [
new SlashCommandArgument(
'member index or name', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], true,
),
SlashCommandArgument.fromProps({
description: 'member index (starts with 0) or name',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
isRequired: true,
enumProvider: commonEnumProviders.groupMembers(),
}),
],
helpString: 'Moves a group member up in the group chat list.',
}));
@ -602,9 +652,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
callback: moveGroupMemberDownCallback,
aliases: ['downmember', 'memberdown'],
unnamedArgumentList: [
new SlashCommandArgument(
'member index or name', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], true,
),
SlashCommandArgument.fromProps({
description: 'member index (starts with 0) or name',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
isRequired: true,
enumProvider: commonEnumProviders.groupMembers(),
}),
],
helpString: 'Moves a group member down in the group chat list.',
}));
@ -612,9 +665,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'peek',
callback: peekCallback,
unnamedArgumentList: [
new SlashCommandArgument(
'message index or range', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE], false, true,
),
SlashCommandArgument.fromProps({
description: 'member index (starts with 0) or name',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
isRequired: true,
enumProvider: commonEnumProviders.groupMembers(),
}),
],
helpString: `
<div>
@ -624,12 +680,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
<strong>Examples:</strong>
<ul>
<li>
<pre><code>/peek 5</code></pre>
Shows the character card for the 5th message.
</li>
<li>
<pre><code>/peek 2-5</code></pre>
Shows the character cards for messages 2 through 5.
<pre><code>/peek Gloria</code></pre>
Shows the character card for the character named "Gloria".
</li>
</ul>
</div>
@ -640,9 +692,14 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
callback: deleteSwipeCallback,
aliases: ['swipedel'],
unnamedArgumentList: [
new SlashCommandArgument(
'1-based swipe id', [ARGUMENT_TYPE.NUMBER],
),
SlashCommandArgument.fromProps({
description: '1-based swipe id',
typeList: [ARGUMENT_TYPE.NUMBER],
isRequired: true,
enumProvider: () => Array.isArray(chat[chat.length - 1]?.swipes) ?
chat[chat.length - 1].swipes.map((/** @type {string} */ swipe, /** @type {number} */ i) => new SlashCommandEnumValue(String(i + 1), swipe, enumTypes.enum, enumIcons.message))
: [],
}),
],
helpString: `
<div>
@ -671,9 +728,18 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
new SlashCommandNamedArgument(
'title', 'title of the toast message', [ARGUMENT_TYPE.STRING], false,
),
new SlashCommandNamedArgument(
'severity', 'severity level of the toast message', [ARGUMENT_TYPE.STRING], false, false, null, ['info', 'warning', 'error', 'success'],
),
SlashCommandNamedArgument.fromProps({
name: 'severity',
description: 'severity level of the toast message',
typeList: [ARGUMENT_TYPE.STRING],
defaultValue: 'info',
enumProvider: () => [
new SlashCommandEnumValue('info', 'info', enumTypes.macro, ''),
new SlashCommandEnumValue('warning', 'warning', enumTypes.enum, '⚠️'),
new SlashCommandEnumValue('error', 'error', enumTypes.enum, '❗'),
new SlashCommandEnumValue('success', 'success', enumTypes.enum, '✅'),
],
}),
],
unnamedArgumentList: [
new SlashCommandArgument(
@ -700,17 +766,28 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
returns: 'generated text',
namedArgumentList: [
new SlashCommandNamedArgument(
'lock', 'lock user input during generation', [ARGUMENT_TYPE.BOOLEAN], false, false, null, ['on', 'off'],
),
new SlashCommandNamedArgument(
'name', 'in-prompt name for instruct mode', [ARGUMENT_TYPE.STRING], false, false, 'System',
'lock', 'lock user input during generation', [ARGUMENT_TYPE.BOOLEAN], false, false, null, commonEnumProviders.boolean('onOff')(),
),
SlashCommandNamedArgument.fromProps({
name: 'name',
description: 'in-prompt name for instruct mode',
typeList: [ARGUMENT_TYPE.STRING],
defaultValue: 'System',
enumProvider: () => [...commonEnumProviders.characters('character')(), new SlashCommandEnumValue('System', null, enumTypes.enum, enumIcons.assistant)],
forceEnum: false,
}),
new SlashCommandNamedArgument(
'length', 'API response length in tokens', [ARGUMENT_TYPE.NUMBER], false,
),
new SlashCommandNamedArgument(
'as', 'role of the output prompt', [ARGUMENT_TYPE.STRING], false, false, 'system', ['system', 'char'],
),
SlashCommandNamedArgument.fromProps({
name: 'as',
description: 'role of the output prompt',
typeList: [ARGUMENT_TYPE.STRING],
enumList: [
new SlashCommandEnumValue('system', null, enumTypes.enum, enumIcons.assistant),
new SlashCommandEnumValue('char', null, enumTypes.enum, enumIcons.character),
],
}),
],
unnamedArgumentList: [
new SlashCommandArgument(
@ -732,17 +809,23 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
returns: 'generated text',
namedArgumentList: [
new SlashCommandNamedArgument(
'lock', 'lock user input during generation', [ARGUMENT_TYPE.BOOLEAN], false, false, null, ['on', 'off'],
'lock', 'lock user input during generation', [ARGUMENT_TYPE.BOOLEAN], false, false, null, commonEnumProviders.boolean('onOff')(),
),
new SlashCommandNamedArgument(
'instruct', 'use instruct mode', [ARGUMENT_TYPE.BOOLEAN], false, false, 'on', ['on', 'off'],
'instruct', 'use instruct mode', [ARGUMENT_TYPE.BOOLEAN], false, false, 'on', commonEnumProviders.boolean('onOff')(),
),
new SlashCommandNamedArgument(
'stop', 'one-time custom stop strings', [ARGUMENT_TYPE.LIST], false,
),
new SlashCommandNamedArgument(
'as', 'role of the output prompt', [ARGUMENT_TYPE.STRING], false, false, 'system', ['system', 'char'],
),
SlashCommandNamedArgument.fromProps({
name: 'as',
description: 'role of the output prompt',
typeList: [ARGUMENT_TYPE.STRING],
enumList: [
new SlashCommandEnumValue('system', null, enumTypes.enum, enumIcons.assistant),
new SlashCommandEnumValue('char', null, enumTypes.enum, enumIcons.character),
],
}),
new SlashCommandNamedArgument(
'system', 'system prompt at the start', [ARGUMENT_TYPE.STRING], false,
),
@ -793,7 +876,6 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
description: 'Whether to suppress the toast message notifying about the /abort call.',
typeList: [ARGUMENT_TYPE.BOOLEAN],
defaultValue: 'true',
enumList: ['true', 'false'],
}),
],
unnamedArgumentList: [
@ -846,7 +928,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'pass',
callback: (_, arg) => arg,
callback: (_, arg) => {
// We do not support arrays of closures. Arrays of strings will be send as JSON
if (Array.isArray(arg) && arg.some(x => x instanceof SlashCommandClosure)) throw new Error('Command /pass does not support multiple closures');
if (Array.isArray(arg)) return JSON.stringify(arg);
return arg;
},
returns: 'the provided value',
unnamedArgumentList: [
new SlashCommandArgument(
@ -899,10 +986,10 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
'default', 'default value of the input field', [ARGUMENT_TYPE.STRING], false, false, '"string"',
),
new SlashCommandNamedArgument(
'large', 'show large input field', [ARGUMENT_TYPE.BOOLEAN], false, false, 'off', ['on', 'off'],
'large', 'show large input field', [ARGUMENT_TYPE.BOOLEAN], false, false, 'off', commonEnumProviders.boolean('onOff')(),
),
new SlashCommandNamedArgument(
'wide', 'show wide input field', [ARGUMENT_TYPE.BOOLEAN], false, false, 'off', ['on', 'off'],
'wide', 'show wide input field', [ARGUMENT_TYPE.BOOLEAN], false, false, 'off', commonEnumProviders.boolean('onOff')(),
),
new SlashCommandNamedArgument(
'okButton', 'text for the ok button', [ARGUMENT_TYPE.STRING], false,
@ -934,9 +1021,15 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
),
],
unnamedArgumentList: [
new SlashCommandArgument(
'scoped variable or qr label', [ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.STRING], true,
),
SlashCommandArgument.fromProps({
description: 'scoped variable or qr label',
typeList: [ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.STRING],
isRequired: true,
enumProvider: () => [
...commonEnumProviders.variables('scope')(),
...(typeof window['qrEnumProviderExecutables'] === 'function') ? window['qrEnumProviderExecutables']() : [],
],
}),
],
helpString: `
<div>
@ -951,19 +1044,29 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
aliases: ['message'],
namedArgumentList: [
new SlashCommandNamedArgument(
'names', 'show message author names', [ARGUMENT_TYPE.BOOLEAN], false, false, 'off', ['off', 'on'],
'names', 'show message author names', [ARGUMENT_TYPE.BOOLEAN], false, false, 'off', commonEnumProviders.boolean('onOff')(),
),
new SlashCommandNamedArgument(
'hidden', 'include hidden messages', [ARGUMENT_TYPE.BOOLEAN], false, false, 'on', ['off', 'on'],
),
new SlashCommandNamedArgument(
'role', 'filter messages by role', [ARGUMENT_TYPE.STRING], false, false, null, ['system', 'assistant', 'user'],
'hidden', 'include hidden messages', [ARGUMENT_TYPE.BOOLEAN], false, false, 'on', commonEnumProviders.boolean('onOff')(),
),
SlashCommandNamedArgument.fromProps({
name: 'role',
description: 'filter messages by role',
typeList: [ARGUMENT_TYPE.STRING],
enumList: [
new SlashCommandEnumValue('system', null, enumTypes.enum, enumIcons.system),
new SlashCommandEnumValue('assistant', null, enumTypes.enum, enumIcons.assistant),
new SlashCommandEnumValue('user', null, enumTypes.enum, enumIcons.user),
],
}),
],
unnamedArgumentList: [
new SlashCommandArgument(
'message index or range', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE], false, true,
),
SlashCommandArgument.fromProps({
description: 'message index (starts with 0) or range',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE],
isRequired: true,
enumProvider: commonEnumProviders.messages(),
}),
],
returns: 'the specified message or range of messages as a string',
helpString: `
@ -1019,10 +1122,10 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
returns: 'popup text',
namedArgumentList: [
new SlashCommandNamedArgument(
'large', 'show large popup', [ARGUMENT_TYPE.BOOLEAN], false, false, null, ['on', 'off'],
'large', 'show large popup', [ARGUMENT_TYPE.BOOLEAN], false, false, null, commonEnumProviders.boolean('onOff')(),
),
new SlashCommandNamedArgument(
'wide', 'show wide popup', [ARGUMENT_TYPE.BOOLEAN], false, false, null, ['on', 'off'],
'wide', 'show wide popup', [ARGUMENT_TYPE.BOOLEAN], false, false, null, commonEnumProviders.boolean('onOff')(),
),
new SlashCommandNamedArgument(
'okButton', 'text for the OK button', [ARGUMENT_TYPE.STRING], false,
@ -1085,9 +1188,16 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
new SlashCommandNamedArgument(
'limit', 'number of tokens to keep', [ARGUMENT_TYPE.NUMBER], true,
),
new SlashCommandNamedArgument(
'direction', 'trim direction', [ARGUMENT_TYPE.STRING], true, false, null, ['start', 'end'],
),
SlashCommandNamedArgument.fromProps({
name: 'direction',
description: 'trim direction',
typeList: [ARGUMENT_TYPE.STRING],
isRequired: true,
enumList: [
new SlashCommandEnumValue('start', null, enumTypes.enum, '⏪'),
new SlashCommandEnumValue('end', null, enumTypes.enum, '⏩'),
],
}),
],
unnamedArgumentList: [
new SlashCommandArgument(
@ -1146,9 +1256,17 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'inject',
callback: injectCallback,
namedArgumentList: [
new SlashCommandNamedArgument(
'id', 'injection ID', [ARGUMENT_TYPE.STRING], true,
),
SlashCommandNamedArgument.fromProps({
name: 'id',
description: 'injection ID or variable name pointing to ID',
typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME],
isRequired: true,
enumProvider: () => [
...commonEnumProviders.injects(),
...commonEnumProviders.variables('all')().map(x => { x.description = 'Variable'; return x; }),
],
}),
new SlashCommandNamedArgument(
'position', 'injection position', [ARGUMENT_TYPE.STRING], false, false, 'after', ['before', 'after', 'chat'],
),
@ -1158,11 +1276,19 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
new SlashCommandNamedArgument(
'scan', 'include injection content into World Info scans', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false',
),
SlashCommandNamedArgument.fromProps({
name: 'role',
description: 'role for in-chat injections',
typeList: [ARGUMENT_TYPE.STRING],
isRequired: false,
enumList: [
new SlashCommandEnumValue('system', null, enumTypes.enum, enumIcons.system),
new SlashCommandEnumValue('assistant', null, enumTypes.enum, enumIcons.assistant),
new SlashCommandEnumValue('user', null, enumTypes.enum, enumIcons.user),
],
}),
new SlashCommandNamedArgument(
'role', 'role for in-chat injections', [ARGUMENT_TYPE.STRING], false, false, 'system', ['system', 'user', 'assistant'],
),
new SlashCommandNamedArgument(
'ephemeral', 'remove injection after generation', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false', ['true', 'false'],
'ephemeral', 'remove injection after generation', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false',
),
],
unnamedArgumentList: [
@ -1181,16 +1307,25 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'flushinject',
aliases: ['flushinjects'],
unnamedArgumentList: [
new SlashCommandArgument(
'injection ID or a variable name pointing to ID', [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME], false, false, '',
),
SlashCommandArgument.fromProps({
description: 'injection ID or a variable name pointing to ID',
typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME],
defaultValue: '',
enumProvider: () => [
...commonEnumProviders.injects(),
...commonEnumProviders.variables('all')().map(x => { x.description = 'Variable'; return x; }),
],
}),
],
callback: flushInjectsCallback,
helpString: 'Removes a script injection for the current chat. If no ID is provided, removes all script injections.',
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'tokens',
callback: (_, text) => getTokenCountAsync(text),
callback: (_, text) => {
if (text instanceof SlashCommandClosure || Array.isArray(text)) throw new Error('Unnamed argument cannot be a closure for command /tokens');
return getTokenCountAsync(text).then(count => String(count));
},
returns: 'number of tokens',
unnamedArgumentList: [
new SlashCommandArgument(
@ -1204,9 +1339,11 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
callback: modelCallback,
returns: 'current model',
unnamedArgumentList: [
new SlashCommandArgument(
'model name', [ARGUMENT_TYPE.STRING], false,
),
SlashCommandArgument.fromProps({
description: 'model name',
typeList: [ARGUMENT_TYPE.STRING],
enumProvider: () => getModelOptions()?.options.map(option => new SlashCommandEnumValue(option.value, option.value !== option.text ? option.text : null)),
}),
],
helpString: 'Sets the model for the current API. Gets the current model name if no argument is provided.',
}));
@ -1215,12 +1352,28 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
aliases: ['setpromptentries'],
callback: setPromptEntryCallback,
namedArgumentList: [
new SlashCommandNamedArgument(
'identifier', 'Prompt entry identifier(s) to target', [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST], false, true,
),
new SlashCommandNamedArgument(
'name', 'Prompt entry name(s) to target', [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST], false, true,
),
SlashCommandNamedArgument.fromProps({
name: 'identifier',
description: 'Prompt entry identifier(s) to target',
typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST],
acceptsMultiple: true,
enumProvider: () => {
const promptManager = setupChatCompletionPromptManager(oai_settings);
const prompts = promptManager.serviceSettings.prompts;
return prompts.map(prompt => new SlashCommandEnumValue(prompt.identifier, prompt.name, enumTypes.enum));
},
}),
SlashCommandNamedArgument.fromProps({
name: 'name',
description: 'Prompt entry name(s) to target',
typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST],
acceptsMultiple: true,
enumProvider: () => {
const promptManager = setupChatCompletionPromptManager(oai_settings);
const prompts = promptManager.serviceSettings.prompts;
return prompts.map(prompt => new SlashCommandEnumValue(prompt.name, prompt.identifier, enumTypes.enum));
},
}),
],
unnamedArgumentList: [
SlashCommandArgument.fromProps({
@ -1229,7 +1382,7 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
isRequired: true,
acceptsMultiple: false,
defaultValue: 'toggle', // unnamed arguments don't support default values yet
enumList: ['on', 'off', 'toggle'],
enumList: commonEnumProviders.boolean('onOffToggle')(),
}),
],
helpString: 'Sets the specified prompt manager entry/entries on or off.',
@ -1506,7 +1659,7 @@ async function popupCallback(args, value) {
await delay(1);
await callGenericPopup(safeValue, POPUP_TYPE.TEXT, '', popupOptions);
await delay(1);
return value;
return String(value);
}
function getMessagesCallback(args, value) {
@ -1610,13 +1763,13 @@ async function runCallback(args, name) {
/**
*
* @param {object} param0
* @param {SlashCommandAbortController} param0._abortController
* @param {string} [param0.quiet]
* @param {import('./slash-commands/SlashCommand.js').NamedArguments} param0
* @param {string} [reason]
*/
function abortCallback({ _abortController, quiet }, reason) {
if (quiet instanceof SlashCommandClosure) throw new Error('argument \'quiet\' cannot be a closure for command /abort');
_abortController.abort((reason ?? '').toString().length == 0 ? '/abort command executed' : reason, !isFalseBoolean(quiet ?? 'true'));
return '';
}
async function delayCallback(_, amount) {
@ -1645,9 +1798,9 @@ async function inputCallback(args, prompt) {
};
// Do not remove this delay, otherwise the prompt will not show up
await delay(1);
const result = await callPopup(safeValue, 'input', defaultInput, popupOptions);
const result = await callGenericPopup(safeValue, POPUP_TYPE.INPUT, defaultInput, popupOptions);
await delay(1);
return result || '';
return String(result || '');
}
/**
@ -2767,12 +2920,11 @@ function setBackgroundCallback(_, bg) {
}
/**
* Sets a model for the current API.
* @param {object} _ Unused
* @param {string} model New model name
* @returns {string} New or existing model name
* Retrieves the available model options based on the currently selected main API and its subtype
*
* @returns {{control: HTMLSelectElement, options: HTMLOptionElement[]}?} An array of objects representing the available model options, or null if not supported
*/
function modelCallback(_, model) {
function getModelOptions() {
const modelSelectMap = [
{ id: 'model_togetherai_select', api: 'textgenerationwebui', type: textgen_types.TOGETHERAI },
{ id: 'openrouter_model', api: 'textgenerationwebui', type: textgen_types.OPENROUTER },
@ -2813,17 +2965,33 @@ function modelCallback(_, model) {
if (!modelSelectItem) {
toastr.info('Setting a model for your API is not supported or not implemented yet.');
return '';
return null;
}
const modelSelectControl = document.getElementById(modelSelectItem);
if (!(modelSelectControl instanceof HTMLSelectElement)) {
toastr.error(`Model select control not found: ${main_api}[${apiSubType}]`);
return '';
return null;
}
const options = Array.from(modelSelectControl.options);
return { control: modelSelectControl, options };
}
/**
* Sets a model for the current API.
* @param {object} _ Unused
* @param {string} model New model name
* @returns {string} New or existing model name
*/
function modelCallback(_, model) {
const { control: modelSelectControl, options } = getModelOptions();
// If no model was found, the reason was already logged, we just return here
if (options === null) {
return '';
}
if (!options.length) {
toastr.warning('No model options found. Check your API settings.');