Add trim argument to /gen and /sysgen. Closes #4361
| @@ -2345,10 +2345,12 @@ export function getStoppingStrings(isImpersonate, isContinue) { | ||
| 2345 | 2345 | * @prop {number} [responseLength] Maximum response length. If unset, the global default value is used. |
| 2346 | 2346 | * @prop {number} [forceChId] Character ID to use for this generation run. Works in groups only. |
| 2347 | 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 | 2350 | * @param {GenerateQuietPromptParams} params Parameters for the quiet prompt generation |
| 2349 | 2351 | * @returns {Promise<string>} Generated text. If using structured output, will contain a serialized JSON object. |
| 2350 | 2352 | */ |
| 2351 | 2353 | export async function generateQuietPrompt({ quietPrompt = '', quietToLoud = false, skipWIAN = false, quietImage = null, quietName = null, responseLength = null, forceChId = null, jsonSchema = null, removeReasoning = true, trimToSentence = false } = {}) { |
| 2352 | 2354 | if (arguments.length > 0 && typeof arguments[0] !== 'object') { |
| 2353 | 2355 | console.trace('generateQuietPrompt called with positional arguments. Please use an object instead.'); |
| 2354 | 2356 | [quietPrompt, quietToLoud, skipWIAN, quietImage, quietName, responseLength, forceChId, jsonSchema] = arguments; |
| @@ -2372,8 +2374,10 @@ export async function generateQuietPrompt({ quietPrompt = '', quietToLoud = fals | ||
| 2372 | 2374 | TempResponseLength.save(main_api, responseLength); |
| 2373 | 2375 | eventHook = TempResponseLength.setupEventHook(main_api); |
| 2374 | 2376 | } |
| 2375 | 2377 | constlet 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 | 2381 | } finally { |
| 2378 | 2382 | if (responseLengthCustomized && TempResponseLength.isCustomized()) { |
| 2379 | 2383 | TempResponseLength.restore(main_api); |
| @@ -1083,6 +1083,44 @@ export function initDefaultSlashCommands() { | ||
| 1083 | 1083 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1084 | 1084 | name: 'sysgen', |
| 1085 | 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 | 1124 | unnamedArgumentList: [ |
| 1087 | 1125 | new SlashCommandArgument( |
| 1088 | 1126 | 'prompt', [ARGUMENT_TYPE.STRING], true, |
| @@ -1629,6 +1667,14 @@ export function initDefaultSlashCommands() { | ||
| 1629 | 1667 | callback: generateCallback, |
| 1630 | 1668 | returns: 'generated text', |
| 1631 | 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 | 1678 | new SlashCommandNamedArgument( |
| 1633 | 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 | 3725 | // Prevent generate recursion |
| 3680 | 3726 | $('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles: true })); |
| 3681 | 3727 | const lock = isTrueBoolean(args?.lock); |
| 3728 | + const trim = isTrueBoolean(args?.trim?.toString()); | |
| 3682 | 3729 | const as = args?.as || 'system'; |
| 3683 | 3730 | const quietToLoud = as === 'char'; |
| 3684 | 3731 | const length = Number(resolveVariable(args?.length) ?? 0) || 0; |
| @@ -3697,6 +3744,7 @@ async function generateCallback(args, value) { | ||
| 3697 | 3744 | quietToLoud: quietToLoud, |
| 3698 | 3745 | quietName: char?.name ?? name, |
| 3699 | 3746 | responseLength: length, |
| 3747 | + trimToSentence: trim, | |
| 3700 | 3748 | }; |
| 3701 | 3749 | const result = await generateQuietPrompt(params); |
| 3702 | 3750 | return result; |
| @@ -4358,7 +4406,7 @@ async function continueChatCallback(args, prompt) { | ||
| 4358 | 4406 | return ''; |
| 4359 | 4407 | } |
| 4360 | 4408 | |
| 4361 | 4409 | export async function generateSystemMessage(_args, prompt) { |
| 4362 | 4410 | $('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles: true })); |
| 4363 | 4411 | |
| 4364 | 4412 | if (!prompt) { |
| @@ -4367,13 +4415,14 @@ export async function generateSystemMessage(_, prompt) { | ||
| 4367 | 4415 | return ''; |
| 4368 | 4416 | } |
| 4369 | 4417 | |
| 4418 | + const trim = isTrueBoolean(args?.trim?.toString()); | |
| 4419 | + | |
| 4370 | 4420 | // Generate and regex the output if applicable |
| 4371 | 4421 | const toast = toastr.info('Please wait', 'Generating...'); |
| 4372 | 4422 | letconst message = await generateQuietPrompt({ quietPrompt: prompt, trimToSentence: trim }); |
| 4373 | - message = getRegexedString(message, regex_placement.SLASH_COMMAND); | |
| 4423 | + toastr.clear(toast); | |
| 4374 | 4424 | |
| 4375 | 4425 | return await sendNarratorMessage(_args, getRegexedString(message, regex_placement.SLASH_COMMAND)); |
| 4376 | - return ''; | |
| 4377 | 4426 | } |
| 4378 | 4427 | |
| 4379 | 4428 | function setStoryModeCallback() { |