mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Merge branch 'staging' into persona-improvements
This commit is contained in:
@ -59,7 +59,7 @@ import { autoSelectPersona, isPersonaLocked, retriggerFirstMessageOnEmptyChat, s
|
||||
import { addEphemeralStoppingString, chat_styles, flushEphemeralStoppingStrings, power_user } from './power-user.js';
|
||||
import { SERVER_INPUTS, textgen_types, textgenerationwebui_settings } from './textgen-settings.js';
|
||||
import { decodeTextTokens, getAvailableTokenizers, getFriendlyTokenizerName, getTextTokens, getTokenCountAsync, selectTokenizer } from './tokenizers.js';
|
||||
import { debounce, delay, equalsIgnoreCaseAndAccents, findChar, getCharIndex, isFalseBoolean, isTrueBoolean, onlyUnique, showFontAwesomePicker, stringToRange, trimToEndSentence, trimToStartSentence, waitUntilCondition } from './utils.js';
|
||||
import { debounce, delay, equalsIgnoreCaseAndAccents, findChar, getCharIndex, isFalseBoolean, isTrueBoolean, onlyUnique, regexFromString, showFontAwesomePicker, stringToRange, trimToEndSentence, trimToStartSentence, waitUntilCondition } from './utils.js';
|
||||
import { registerVariableCommands, resolveVariable } from './variables.js';
|
||||
import { background_settings } from './backgrounds.js';
|
||||
import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js';
|
||||
@ -76,6 +76,7 @@ import { SlashCommandBreakController } from './slash-commands/SlashCommandBreakC
|
||||
import { SlashCommandExecutionError } from './slash-commands/SlashCommandExecutionError.js';
|
||||
import { slashCommandReturnHelper } from './slash-commands/SlashCommandReturnHelper.js';
|
||||
import { t } from './i18n.js';
|
||||
import { accountStorage } from './util/AccountStorage.js';
|
||||
export {
|
||||
executeSlashCommands, executeSlashCommandsWithOptions, getSlashCommandsHelp, registerSlashCommand,
|
||||
};
|
||||
@ -283,7 +284,6 @@ export function initDefaultSlashCommands() {
|
||||
description: 'Character name - or unique character identifier (avatar key)',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
enumProvider: commonEnumProviders.characters('character'),
|
||||
forceEnum: false,
|
||||
}),
|
||||
],
|
||||
helpString: `
|
||||
@ -322,7 +322,6 @@ export function initDefaultSlashCommands() {
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: commonEnumProviders.characters('character'),
|
||||
forceEnum: false,
|
||||
}),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'avatar',
|
||||
@ -566,7 +565,6 @@ export function initDefaultSlashCommands() {
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: commonEnumProviders.characters('all'),
|
||||
forceEnum: true,
|
||||
}),
|
||||
],
|
||||
helpString: 'Opens up a chat with the character or group by its name',
|
||||
@ -781,6 +779,57 @@ export function initDefaultSlashCommands() {
|
||||
],
|
||||
helpString: 'Unhides a message from the prompt.',
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'member-get',
|
||||
aliases: ['getmember', 'memberget'],
|
||||
callback: (async ({ field = 'name' }, arg) => {
|
||||
if (!selected_group) {
|
||||
toastr.warning('Cannot run /member-get command outside of a group chat.');
|
||||
return '';
|
||||
}
|
||||
if (field === '') {
|
||||
toastr.warning('\'/member-get field=\' argument required!');
|
||||
return '';
|
||||
}
|
||||
field = field.toString();
|
||||
arg = arg.toString();
|
||||
if (!['name', 'index', 'id', 'avatar'].includes(field)) {
|
||||
toastr.warning('\'/member-get field=\' argument required!');
|
||||
return '';
|
||||
}
|
||||
const isId = !isNaN(parseInt(arg));
|
||||
const groupMember = findGroupMemberId(arg, true);
|
||||
if (!groupMember) {
|
||||
toastr.warn(`No group member found using ${isId ? 'id' : 'string'} ${arg}`);
|
||||
return '';
|
||||
}
|
||||
return groupMember[field];
|
||||
}),
|
||||
namedArgumentList: [
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'field',
|
||||
description: 'Whether to retrieve the name, index, id, or avatar.',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
defaultValue: 'name',
|
||||
enumList: [
|
||||
new SlashCommandEnumValue('name', 'Character name'),
|
||||
new SlashCommandEnumValue('index', 'Group member index'),
|
||||
new SlashCommandEnumValue('avatar', 'Character avatar'),
|
||||
new SlashCommandEnumValue('id', 'Character index'),
|
||||
],
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'member index (starts with 0), name, or avatar',
|
||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: commonEnumProviders.groupMembers(),
|
||||
}),
|
||||
],
|
||||
helpString: 'Retrieves a group member\'s name, index, id, or avatar.',
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'member-disable',
|
||||
callback: disableGroupMemberCallback,
|
||||
@ -891,7 +940,8 @@ export function initDefaultSlashCommands() {
|
||||
helpString: 'Moves a group member down in the group chat list.',
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'peek',
|
||||
name: 'member-peek',
|
||||
aliases: ['peek', 'memberpeek', 'peekmember'],
|
||||
callback: peekCallback,
|
||||
unnamedArgumentList: [
|
||||
SlashCommandArgument.fromProps({
|
||||
@ -1057,7 +1107,6 @@ export function initDefaultSlashCommands() {
|
||||
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,
|
||||
@ -1951,7 +2000,7 @@ export function initDefaultSlashCommands() {
|
||||
returns: 'uppercase string',
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'string', [ARGUMENT_TYPE.STRING], true, false,
|
||||
'text to affect', [ARGUMENT_TYPE.STRING], true, false,
|
||||
),
|
||||
],
|
||||
helpString: 'Converts the provided string to uppercase.',
|
||||
@ -1963,7 +2012,7 @@ export function initDefaultSlashCommands() {
|
||||
returns: 'lowercase string',
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'string', [ARGUMENT_TYPE.STRING], true, false,
|
||||
'text to affect', [ARGUMENT_TYPE.STRING], true, false,
|
||||
),
|
||||
],
|
||||
helpString: 'Converts the provided string to lowercase.',
|
||||
@ -1983,7 +2032,7 @@ export function initDefaultSlashCommands() {
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'string', [ARGUMENT_TYPE.STRING], true, false,
|
||||
'text to affect', [ARGUMENT_TYPE.STRING], true, false,
|
||||
),
|
||||
],
|
||||
helpString: `
|
||||
@ -2047,6 +2096,62 @@ export function initDefaultSlashCommands() {
|
||||
return '';
|
||||
},
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'replace',
|
||||
aliases: ['re'],
|
||||
callback: (async ({ mode = 'literal', pattern, replacer = '' }, text) => {
|
||||
if (pattern === '')
|
||||
throw new Error('Argument of \'pattern=\' cannot be empty');
|
||||
switch (mode) {
|
||||
case 'literal':
|
||||
return text.replaceAll(pattern, replacer);
|
||||
case 'regex':
|
||||
return text.replace(regexFromString(pattern), replacer);
|
||||
default:
|
||||
throw new Error('Invalid \'/replace mode=\' argument specified!');
|
||||
}
|
||||
}),
|
||||
returns: 'replaced text',
|
||||
namedArgumentList: [
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'mode',
|
||||
description: 'Replaces occurrence(s) of a pattern',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
defaultValue: 'literal',
|
||||
enumList: ['literal', 'regex'],
|
||||
}),
|
||||
new SlashCommandNamedArgument(
|
||||
'pattern', 'pattern to search with', [ARGUMENT_TYPE.STRING], true, false,
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'replacer', 'replacement text for matches', [ARGUMENT_TYPE.STRING], false, false, '',
|
||||
),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'text to affect', [ARGUMENT_TYPE.STRING], true, false,
|
||||
),
|
||||
],
|
||||
helpString: `
|
||||
<div>
|
||||
Replaces text within the provided string based on the pattern.
|
||||
</div>
|
||||
<div>
|
||||
If <code>mode</code> is <code>literal</code> (or omitted), <code>pattern</code> is a literal search string (case-sensitive).<br />
|
||||
If <code>mode</code> is <code>regex</code>, <code>pattern</code> is parsed as an ECMAScript Regular Expression.<br />
|
||||
The <code>replacer</code> replaces based on the <code>pattern</code> in the input text.<br />
|
||||
If <code>replacer</code> is omitted, the replacement(s) will be an empty string.<br />
|
||||
</div>
|
||||
<div>
|
||||
<strong>Example:</strong>
|
||||
<pre>/let x Blue house and blue car || </pre>
|
||||
<pre>/replace pattern="blue" {{var::x}} | /echo |/# Blue house and car ||</pre>
|
||||
<pre>/replace pattern="blue" replacer="red" {{var::x}} | /echo |/# Blue house and red car ||</pre>
|
||||
<pre>/replace mode=regex pattern="/blue/i" replacer="red" {{var::x}} | /echo |/# red house and blue car ||</pre>
|
||||
<pre>/replace mode=regex pattern="/blue/gi" replacer="red" {{var::x}} | /echo |/# red house and red car ||</pre>
|
||||
</div>
|
||||
`,
|
||||
}));
|
||||
|
||||
registerVariableCommands();
|
||||
}
|
||||
@ -3039,7 +3144,7 @@ function performGroupMemberAction(chid, action) {
|
||||
|
||||
async function disableGroupMemberCallback(_, arg) {
|
||||
if (!selected_group) {
|
||||
toastr.warning('Cannot run /disable command outside of a group chat.');
|
||||
toastr.warning('Cannot run /member-disable command outside of a group chat.');
|
||||
return '';
|
||||
}
|
||||
|
||||
@ -3056,7 +3161,7 @@ async function disableGroupMemberCallback(_, arg) {
|
||||
|
||||
async function enableGroupMemberCallback(_, arg) {
|
||||
if (!selected_group) {
|
||||
toastr.warning('Cannot run /enable command outside of a group chat.');
|
||||
toastr.warning('Cannot run /member-enable command outside of a group chat.');
|
||||
return '';
|
||||
}
|
||||
|
||||
@ -3073,7 +3178,7 @@ async function enableGroupMemberCallback(_, arg) {
|
||||
|
||||
async function moveGroupMemberUpCallback(_, arg) {
|
||||
if (!selected_group) {
|
||||
toastr.warning('Cannot run /memberup command outside of a group chat.');
|
||||
toastr.warning('Cannot run /member-up command outside of a group chat.');
|
||||
return '';
|
||||
}
|
||||
|
||||
@ -3090,7 +3195,7 @@ async function moveGroupMemberUpCallback(_, arg) {
|
||||
|
||||
async function moveGroupMemberDownCallback(_, arg) {
|
||||
if (!selected_group) {
|
||||
toastr.warning('Cannot run /memberdown command outside of a group chat.');
|
||||
toastr.warning('Cannot run /member-down command outside of a group chat.');
|
||||
return '';
|
||||
}
|
||||
|
||||
@ -3107,12 +3212,12 @@ async function moveGroupMemberDownCallback(_, arg) {
|
||||
|
||||
async function peekCallback(_, arg) {
|
||||
if (!selected_group) {
|
||||
toastr.warning('Cannot run /peek command outside of a group chat.');
|
||||
toastr.warning('Cannot run /member-peek command outside of a group chat.');
|
||||
return '';
|
||||
}
|
||||
|
||||
if (is_group_generating) {
|
||||
toastr.warning('Cannot run /peek command while the group reply is generating.');
|
||||
toastr.warning('Cannot run /member-peek command while the group reply is generating.');
|
||||
return '';
|
||||
}
|
||||
|
||||
@ -3129,12 +3234,7 @@ async function peekCallback(_, arg) {
|
||||
|
||||
async function removeGroupMemberCallback(_, arg) {
|
||||
if (!selected_group) {
|
||||
toastr.warning('Cannot run /memberremove command outside of a group chat.');
|
||||
return '';
|
||||
}
|
||||
|
||||
if (is_group_generating) {
|
||||
toastr.warning('Cannot run /memberremove command while the group reply is generating.');
|
||||
toastr.warning('Cannot run /member-remove command outside of a group chat.');
|
||||
return '';
|
||||
}
|
||||
|
||||
@ -3242,12 +3342,7 @@ function findPersonaByName(name) {
|
||||
}
|
||||
|
||||
async function sendUserMessageCallback(args, text) {
|
||||
if (!text) {
|
||||
toastr.warning('You must specify text to send');
|
||||
return;
|
||||
}
|
||||
|
||||
text = text.trim();
|
||||
text = String(text ?? '').trim();
|
||||
const compact = isTrueBoolean(args?.compact);
|
||||
const bias = extractMessageBias(text);
|
||||
|
||||
@ -3562,24 +3657,18 @@ export function getNameAndAvatarForMessage(character, name = null) {
|
||||
}
|
||||
|
||||
export async function sendMessageAs(args, text) {
|
||||
if (!text) {
|
||||
toastr.warning('You must specify text to send as');
|
||||
return '';
|
||||
}
|
||||
|
||||
let name = args.name?.trim();
|
||||
let mesText;
|
||||
|
||||
if (!name) {
|
||||
const namelessWarningKey = 'sendAsNamelessWarningShown';
|
||||
if (localStorage.getItem(namelessWarningKey) !== 'true') {
|
||||
if (accountStorage.getItem(namelessWarningKey) !== 'true') {
|
||||
toastr.warning('To avoid confusion, please use /sendas name="Character Name"', 'Name defaulted to {{char}}', { timeOut: 10000 });
|
||||
localStorage.setItem(namelessWarningKey, 'true');
|
||||
accountStorage.setItem(namelessWarningKey, 'true');
|
||||
}
|
||||
name = name2;
|
||||
}
|
||||
|
||||
mesText = text.trim();
|
||||
let mesText = String(text ?? '').trim();
|
||||
|
||||
// Requires a regex check after the slash command is pushed to output
|
||||
mesText = getRegexedString(mesText, regex_placement.SLASH_COMMAND, { characterOverride: name });
|
||||
@ -3657,11 +3746,7 @@ export async function sendMessageAs(args, text) {
|
||||
}
|
||||
|
||||
export async function sendNarratorMessage(args, text) {
|
||||
if (!text) {
|
||||
toastr.warning('You must specify text to send');
|
||||
return '';
|
||||
}
|
||||
|
||||
text = String(text ?? '');
|
||||
const name = chat_metadata[NARRATOR_NAME_KEY] || NARRATOR_NAME_DEFAULT;
|
||||
// Messages that do nothing but set bias will be hidden from the context
|
||||
const bias = extractMessageBias(text);
|
||||
@ -3752,18 +3837,13 @@ export async function promptQuietForLoudResponse(who, text) {
|
||||
}
|
||||
|
||||
async function sendCommentMessage(args, text) {
|
||||
if (!text) {
|
||||
toastr.warning('You must specify text to send');
|
||||
return '';
|
||||
}
|
||||
|
||||
const compact = isTrueBoolean(args?.compact);
|
||||
const message = {
|
||||
name: COMMENT_NAME_DEFAULT,
|
||||
is_user: false,
|
||||
is_system: true,
|
||||
send_date: getMessageTimeStamp(),
|
||||
mes: substituteParams(text.trim()),
|
||||
mes: substituteParams(String(text ?? '').trim()),
|
||||
force_avatar: comment_avatar,
|
||||
extra: {
|
||||
type: system_message_types.COMMENT,
|
||||
|
Reference in New Issue
Block a user