Add trim argument to /gen and /sysgen. Closes #4361

fb058816e86b71e769c2dbe3e50db24d5028676a

Cohee <18619528+Cohee1207@users.noreply.github.com>

2 files changed, +62 -9Showing whitespace changes
public/script.js+7 -3
@@ -2345,10 +2345,12 @@ export function getStoppingStrings(isImpersonate, isContinue) {
2345 * @prop {number} [responseLength] Maximum response length. If unset, the global default value is used.2345 * @prop {number} [responseLength] Maximum response length. If unset, the global default value is used.
2346 * @prop {number} [forceChId] Character ID to use for this generation run. Works in groups only.2346 * @prop {number} [forceChId] Character ID to use for this generation run. Works in groups only.
2347 * @prop {object} [jsonSchema] JSON schema to use for the structured generation. Usually requires a special instruction.2347 * @prop {object} [jsonSchema] JSON schema to use for the structured generation. Usually requires a special instruction.
2348 * @prop {boolean} [removeReasoning] Parses and removes the reasoning block according to reasoning format preferences
2349 * @prop {boolean} [trimToSentence] Whether to trim the response to the last complete sentence
2348 * @param {GenerateQuietPromptParams} params Parameters for the quiet prompt generation2350 * @param {GenerateQuietPromptParams} params Parameters for the quiet prompt generation
2349 * @returns {Promise<string>} Generated text. If using structured output, will contain a serialized JSON object.2351 * @returns {Promise<string>} Generated text. If using structured output, will contain a serialized JSON object.
2350 */2352 */
2351export async function generateQuietPrompt({ quietPrompt = '', quietToLoud = false, skipWIAN = false, quietImage = null, quietName = null, responseLength = null, forceChId = null, jsonSchema = null } = {}) {2353export async function generateQuietPrompt({ quietPrompt = '', quietToLoud = false, skipWIAN = false, quietImage = null, quietName = null, responseLength = null, forceChId = null, jsonSchema = null, removeReasoning = true, trimToSentence = false } = {}) {
2352 if (arguments.length > 0 && typeof arguments[0] !== 'object') {2354 if (arguments.length > 0 && typeof arguments[0] !== 'object') {
2353 console.trace('generateQuietPrompt called with positional arguments. Please use an object instead.');2355 console.trace('generateQuietPrompt called with positional arguments. Please use an object instead.');
2354 [quietPrompt, quietToLoud, skipWIAN, quietImage, quietName, responseLength, forceChId, jsonSchema] = arguments;2356 [quietPrompt, quietToLoud, skipWIAN, quietImage, quietName, responseLength, forceChId, jsonSchema] = arguments;
@@ -2372,8 +2374,10 @@ export async function generateQuietPrompt({ quietPrompt = '', quietToLoud = fals
2372 TempResponseLength.save(main_api, responseLength);2374 TempResponseLength.save(main_api, responseLength);
2373 eventHook = TempResponseLength.setupEventHook(main_api);2375 eventHook = TempResponseLength.setupEventHook(main_api);
2374 }2376 }
2375 const result = await Generate('quiet', generateOptions);2377 let result = await Generate('quiet', generateOptions);
2376 return removeReasoningFromString(result);2378 result = trimToSentence ? trimToEndSentence(result) : result;
2379 result = removeReasoning ? removeReasoningFromString(result) : result;
2380 return result;
2377 } finally {2381 } finally {
2378 if (responseLengthCustomized && TempResponseLength.isCustomized()) {2382 if (responseLengthCustomized && TempResponseLength.isCustomized()) {
2379 TempResponseLength.restore(main_api);2383 TempResponseLength.restore(main_api);
public/scripts/slash-commands.js+55 -6
@@ -1083,6 +1083,44 @@ export function initDefaultSlashCommands() {
1083 SlashCommandParser.addCommandObject(SlashCommand.fromProps({1083 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
1084 name: 'sysgen',1084 name: 'sysgen',
1085 callback: generateSystemMessage,1085 callback: generateSystemMessage,
1086 namedArgumentList: [
1087 SlashCommandNamedArgument.fromProps({
1088 name: 'trim',
1089 description: 'Trim the output by the last sentence boundary',
1090 typeList: [ARGUMENT_TYPE.BOOLEAN],
1091 defaultValue: 'false',
1092 isRequired: false,
1093 enumProvider: commonEnumProviders.boolean('trueFalse'),
1094 }),
1095 SlashCommandNamedArgument.fromProps({
1096 name: 'compact',
1097 description: 'Use a compact layout for the message',
1098 typeList: [ARGUMENT_TYPE.BOOLEAN],
1099 defaultValue: 'false',
1100 isRequired: false,
1101 acceptsMultiple: false,
1102 enumProvider: commonEnumProviders.boolean('trueFalse'),
1103 }),
1104 SlashCommandNamedArgument.fromProps({
1105 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.',
1107 typeList: [ARGUMENT_TYPE.NUMBER],
1108 enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
1109 }),
1110 SlashCommandNamedArgument.fromProps({
1111 name: 'name',
1112 description: 'Optional custom display name to use for this system narrator message.',
1113 typeList: [ARGUMENT_TYPE.STRING],
1114 }),
1115 SlashCommandNamedArgument.fromProps({
1116 name: 'return',
1117 description: 'The way how you want the return value to be provided',
1118 typeList: [ARGUMENT_TYPE.STRING],
1119 defaultValue: 'none',
1120 enumList: slashCommandReturnHelper.enumList({ allowObject: true }),
1121 forceEnum: true,
1122 }),
1123 ],
1086 unnamedArgumentList: [1124 unnamedArgumentList: [
1087 new SlashCommandArgument(1125 new SlashCommandArgument(
1088 'prompt', [ARGUMENT_TYPE.STRING], true,1126 'prompt', [ARGUMENT_TYPE.STRING], true,
@@ -1629,6 +1667,14 @@ export function initDefaultSlashCommands() {
1629 callback: generateCallback,1667 callback: generateCallback,
1630 returns: 'generated text',1668 returns: 'generated text',
1631 namedArgumentList: [1669 namedArgumentList: [
1670 SlashCommandNamedArgument.fromProps({
1671 name: 'trim',
1672 description: 'Trim the output by the last sentence boundary',
1673 typeList: [ARGUMENT_TYPE.BOOLEAN],
1674 defaultValue: 'false',
1675 isRequired: false,
1676 enumProvider: commonEnumProviders.boolean('trueFalse'),
1677 }),
1632 new SlashCommandNamedArgument(1678 new SlashCommandNamedArgument(
1633 'lock', 'lock user input during generation', [ARGUMENT_TYPE.BOOLEAN], false, false, null, commonEnumProviders.boolean('onOff')(),1679 'lock', 'lock user input during generation', [ARGUMENT_TYPE.BOOLEAN], false, false, null, commonEnumProviders.boolean('onOff')(),
1634 ),1680 ),
@@ -3679,6 +3725,7 @@ async function generateCallback(args, value) {
3679 // Prevent generate recursion3725 // Prevent generate recursion
3680 $('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles: true }));3726 $('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles: true }));
3681 const lock = isTrueBoolean(args?.lock);3727 const lock = isTrueBoolean(args?.lock);
3728 const trim = isTrueBoolean(args?.trim?.toString());
3682 const as = args?.as || 'system';3729 const as = args?.as || 'system';
3683 const quietToLoud = as === 'char';3730 const quietToLoud = as === 'char';
3684 const length = Number(resolveVariable(args?.length) ?? 0) || 0;3731 const length = Number(resolveVariable(args?.length) ?? 0) || 0;
@@ -3697,6 +3744,7 @@ async function generateCallback(args, value) {
3697 quietToLoud: quietToLoud,3744 quietToLoud: quietToLoud,
3698 quietName: char?.name ?? name,3745 quietName: char?.name ?? name,
3699 responseLength: length,3746 responseLength: length,
3747 trimToSentence: trim,
3700 };3748 };
3701 const result = await generateQuietPrompt(params);3749 const result = await generateQuietPrompt(params);
3702 return result;3750 return result;
@@ -4358,7 +4406,7 @@ async function continueChatCallback(args, prompt) {
4358 return '';4406 return '';
4359}4407}
43604408
4361export async function generateSystemMessage(_, prompt) {4409export async function generateSystemMessage(args, prompt) {
4362 $('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles: true }));4410 $('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles: true }));
43634411
4364 if (!prompt) {4412 if (!prompt) {
@@ -4367,13 +4415,14 @@ export async function generateSystemMessage(_, prompt) {
4367 return '';4415 return '';
4368 }4416 }
43694417
4418 const trim = isTrueBoolean(args?.trim?.toString());
4419
4370 // Generate and regex the output if applicable4420 // Generate and regex the output if applicable
4371 toastr.info('Please wait', 'Generating...');4421 const toast = toastr.info('Please wait', 'Generating...');
4372 let message = await generateQuietPrompt({ quietPrompt: prompt });4422 const message = await generateQuietPrompt({ quietPrompt: prompt, trimToSentence: trim });
4373 message = getRegexedString(message, regex_placement.SLASH_COMMAND);4423 toastr.clear(toast);
43744424
4375 sendNarratorMessage(_, message);4425 return await sendNarratorMessage(args, getRegexedString(message, regex_placement.SLASH_COMMAND));
4376 return '';
4377}4426}
43784427
4379function setStoryModeCallback() {4428function setStoryModeCallback() {