chchar slash cmd (#4916)

* Add an additional slash command to change a message's character and avatar.

* Refactor message character change command to update message sender's name

* Fix default value

* Allow setting unbound message names

---------

Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
This commit is contained in:
AphidGit
2025-12-27 00:24:00 +01:00
committed by GitHub
parent e7c9496a61
commit af495cefbd
+112 -1
View File
@@ -1,5 +1,5 @@
import { Fuse, DOMPurify } from '../lib.js';
import { canUseNegativeLookbehind, copyText, flashHighlight } from './utils.js';
import { canUseNegativeLookbehind, copyText, findPersona, flashHighlight } from './utils.js';
import {
Generate,
@@ -7,6 +7,7 @@ import {
addOneMessage,
characters,
chat,
chatElement,
chat_metadata,
comment_avatar,
deactivateSendButtons,
@@ -764,6 +765,50 @@ export function initDefaultSlashCommands() {
</div>
`,
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'message-name',
callback: changeMessageName,
returns: 'The updated name of the message sender',
namedArgumentList: [
SlashCommandNamedArgument.fromProps({
name: 'at',
description: 'the ID of the message to modify (index-based, corresponding to message id). If omitted, the last message is chosen.\nNegative values are accepted and will work similarly to how \'depth\' usually works. For example, -1 will modify the message right before the last message in chat. At must be nonzero.',
typeList: [ARGUMENT_TYPE.NUMBER],
defaultValue: '',
enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
}),
],
unnamedArgumentList: [
SlashCommandArgument.fromProps({
description: 'Persona name, character name, or unique character identifier (avatar key)',
typeList: [ARGUMENT_TYPE.STRING],
isRequired: true,
enumProvider: (executor) => {
let modifyAt = Number(executor.namedArgumentList.find(arg => arg.name === 'at')?.value ?? (chat.length - 1));
if (!isNaN(modifyAt) && (modifyAt < 0 || Object.is(modifyAt, -0))) {
modifyAt = chat.length + modifyAt;
}
return chat[modifyAt]?.is_user
? commonEnumProviders.personas()
: commonEnumProviders.characters('character')();
},
}),
],
helpString: `
<div>
Changes the name of a message sender to one of your choice.
</div>
<div>
<strong>Example:</strong>
<ul>
<li>
<pre><code>/message-name at=-2 "Chloe"</code></pre>
Will change the third message from the bottom to be sent by "Chloe".
</li>
</ul>
</div>
`,
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'sendas',
rawQuotes: true,
@@ -4510,6 +4555,72 @@ export function getNameAndAvatarForMessage(character, name = null) {
};
}
/**
* Changes the character name on a message at a given index.
* @param {object?} args - Named arguments
* @param {string} name - Name to change to.
*
* @returns {Promise<string>} The updated message name.
*/
export async function changeMessageName(args, name) {
name = String(name ?? '').trim();
if (!name) {
toastr.warning(t`You must provide a name to change the message to.`);
return '';
}
let modifyAt = Number(args?.at ?? (chat.length - 1));
// Convert possible depth parameter to index
if (!isNaN(modifyAt) && (modifyAt < 0 || Object.is(modifyAt, -0))) {
// Negative value means going back from current chat length. (E.g.: 8 messages, Depth 1 means insert at index 7)
modifyAt = chat.length + modifyAt;
}
const message = chat[modifyAt];
if (!message) {
toastr.warning(t`No message found at the specified index.`);
return '';
}
let newName = '';
if (message.is_user) {
const persona = findPersona({ name: name });
if (persona) {
message.name = newName = persona.name;
message.force_avatar = getThumbnailUrl('persona', persona.avatar);
message.original_avatar = persona.avatar;
} else {
message.name = newName = name;
message.force_avatar = default_avatar;
message.original_avatar = default_avatar;
}
} else {
const character = findChar({ name: name });
if (character) {
const characterInfo = getNameAndAvatarForMessage(character, name);
message.name = newName = characterInfo.name;
message.force_avatar = characterInfo.force_avatar;
message.original_avatar = characterInfo.original_avatar;
} else {
message.name = newName = name;
message.force_avatar = default_avatar;
message.original_avatar = default_avatar;
}
}
await eventSource.emit(event_types.MESSAGE_EDITED, modifyAt);
const existingMessage = chatElement.find(`.mes[mesid="${modifyAt}"]`);
if (existingMessage.length) {
addOneMessage(message, { forceId: modifyAt, insertAfter: modifyAt, scroll: false });
existingMessage.remove();
}
await eventSource.emit(event_types.MESSAGE_UPDATED, modifyAt);
await saveChatConditional();
return newName;
}
export async function sendMessageAs(args, text) {
let name = args.name?.trim();