Add regex processing for reasoning blocks
| @@ -1993,9 +1993,10 @@ export async function sendTextareaMessage() { | |||
| 1993 | * @param {boolean} isUser If the message was sent by the user | 1993 | * @param {boolean} isUser If the message was sent by the user |
| 1994 | * @param {number} messageId Message index in chat array | 1994 | * @param {number} messageId Message index in chat array |
| 1995 | * @param {object} [sanitizerOverrides] DOMPurify sanitizer option overrides | 1995 | * @param {object} [sanitizerOverrides] DOMPurify sanitizer option overrides |
| 1996 | * @param {boolean} [isReasoning] If the message is reasoning output | ||
| 1996 | * @returns {string} HTML string | 1997 | * @returns {string} HTML string |
| 1997 | */ | 1998 | */ |
| 1998 | export function messageFormatting(mes, ch_name, isSystem, isUser, messageId, sanitizerOverrides = {}) { | 1999 | export function messageFormatting(mes, ch_name, isSystem, isUser, messageId, sanitizerOverrides = {}, isReasoning = false) { |
| 1999 | if (!mes) { | 2000 | if (!mes) { |
| 2000 | return ''; | 2001 | return ''; |
| 2001 | } | 2002 | } |
| @@ -2029,6 +2030,9 @@ export function messageFormatting(mes, ch_name, isSystem, isUser, messageId, san | |||
| 2029 | if (!isSystem) { | 2030 | if (!isSystem) { |
| 2030 | function getRegexPlacement() { | 2031 | function getRegexPlacement() { |
| 2031 | try { | 2032 | try { |
| 2033 | if (isReasoning) { | ||
| 2034 | return regex_placement.REASONING; | ||
| 2035 | } | ||
| 2032 | if (isUser) { | 2036 | if (isUser) { |
| 2033 | return regex_placement.USER_INPUT; | 2037 | return regex_placement.USER_INPUT; |
| 2034 | } else if (chat[messageId]?.extra?.type === 'narrator') { | 2038 | } else if (chat[messageId]?.extra?.type === 'narrator') { |
| @@ -2250,8 +2254,8 @@ function getMessageFromTemplate({ | |||
| 2250 | export function updateMessageBlock(messageId, message) { | 2254 | export function updateMessageBlock(messageId, message) { |
| 2251 | const messageElement = $(`#chat [mesid="${messageId}"]`); | 2255 | const messageElement = $(`#chat [mesid="${messageId}"]`); |
| 2252 | const text = message?.extra?.display_text ?? message.mes; | 2256 | const text = message?.extra?.display_text ?? message.mes; |
| 2253 | messageElement.find('.mes_text').html(messageFormatting(text, message.name, message.is_system, message.is_user, messageId)); | 2257 | messageElement.find('.mes_text').html(messageFormatting(text, message.name, message.is_system, message.is_user, messageId, {}, false)); |
| 2254 | messageElement.find('.mes_reasoning').html(messageFormatting(message.extra?.reasoning ?? '', '', false, false, -1)); | 2258 | messageElement.find('.mes_reasoning').html(messageFormatting(message.extra?.reasoning ?? '', '', false, false, messageId, {}, true)); |
| 2255 | addCopyToCodeBlocks(messageElement); | 2259 | addCopyToCodeBlocks(messageElement); |
| 2256 | appendMediaToMessage(message, messageElement); | 2260 | appendMediaToMessage(message, messageElement); |
| 2257 | } | 2261 | } |
| @@ -2408,9 +2412,10 @@ export function addOneMessage(mes, { type = 'normal', insertAfter = null, scroll | |||
| 2408 | mes.is_user, | 2412 | mes.is_user, |
| 2409 | chat.indexOf(mes), | 2413 | chat.indexOf(mes), |
| 2410 | sanitizerOverrides, | 2414 | sanitizerOverrides, |
| 2415 | false, | ||
| 2411 | ); | 2416 | ); |
| 2412 | const bias = messageFormatting(mes.extra?.bias ?? '', '', false, false, -1); | 2417 | const bias = messageFormatting(mes.extra?.bias ?? '', '', false, false, -1, {}, false); |
| 2413 | const reasoning = messageFormatting(mes.extra?.reasoning ?? '', '', false, false, -1); | 2418 | const reasoning = messageFormatting(mes.extra?.reasoning ?? '', '', false, false, chat.indexOf(mes), {}, true); |
| 2414 | let bookmarkLink = mes?.extra?.bookmark_link ?? ''; | 2419 | let bookmarkLink = mes?.extra?.bookmark_link ?? ''; |
| 2415 | 2420 | ||
| 2416 | let params = { | 2421 | let params = { |
| @@ -3205,7 +3210,7 @@ class StreamingProcessor { | |||
| 3205 | if (this.reasoning) { | 3210 | if (this.reasoning) { |
| 3206 | chat[messageId]['extra']['reasoning'] = this.reasoning; | 3211 | chat[messageId]['extra']['reasoning'] = this.reasoning; |
| 3207 | if (this.messageReasoningDom instanceof HTMLElement) { | 3212 | if (this.messageReasoningDom instanceof HTMLElement) { |
| 3208 | const formattedReasoning = messageFormatting(this.reasoning, '', false, false, -1); | 3213 | const formattedReasoning = messageFormatting(this.reasoning, '', false, false, messageId, {}, true); |
| 3209 | this.messageReasoningDom.innerHTML = formattedReasoning; | 3214 | this.messageReasoningDom.innerHTML = formattedReasoning; |
| 3210 | } | 3215 | } |
| 3211 | } | 3216 | } |
| @@ -3232,6 +3237,8 @@ class StreamingProcessor { | |||
| 3232 | chat[messageId].is_system, | 3237 | chat[messageId].is_system, |
| 3233 | chat[messageId].is_user, | 3238 | chat[messageId].is_user, |
| 3234 | messageId, | 3239 | messageId, |
| 3240 | {}, | ||
| 3241 | false, | ||
| 3235 | ); | 3242 | ); |
| 3236 | if (this.messageTextDom instanceof HTMLElement) { | 3243 | if (this.messageTextDom instanceof HTMLElement) { |
| 3237 | this.messageTextDom.innerHTML = formattedText; | 3244 | this.messageTextDom.innerHTML = formattedText; |
| @@ -3383,7 +3390,7 @@ class StreamingProcessor { | |||
| 3383 | if (logprobs) { | 3390 | if (logprobs) { |
| 3384 | this.messageLogprobs.push(...(Array.isArray(logprobs) ? logprobs : [logprobs])); | 3391 | this.messageLogprobs.push(...(Array.isArray(logprobs) ? logprobs : [logprobs])); |
| 3385 | } | 3392 | } |
| 3386 | this.reasoning = state?.reasoning ?? ''; | 3393 | this.reasoning = getRegexedString(state?.reasoning ?? '', regex_placement.REASONING); |
| 3387 | await eventSource.emit(event_types.STREAM_TOKEN_RECEIVED, text); | 3394 | await eventSource.emit(event_types.STREAM_TOKEN_RECEIVED, text); |
| 3388 | await sw.tick(() => this.onProgressStreaming(this.messageId, this.continueMessage + text)); | 3395 | await sw.tick(() => this.onProgressStreaming(this.messageId, this.continueMessage + text)); |
| 3389 | } | 3396 | } |
| @@ -3850,14 +3857,6 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 3850 | coreChat.pop(); | 3857 | coreChat.pop(); |
| 3851 | } | 3858 | } |
| 3852 | 3859 | ||
| 3853 | const reasoning = new PromptReasoning(); | ||
| 3854 | for (let i = coreChat.length - 1; i >= 0; i--) { | ||
| 3855 | if (reasoning.isLimitReached()) { | ||
| 3856 | break; | ||
| 3857 | } | ||
| 3858 | coreChat[i] = { ...coreChat[i], mes: reasoning.addToMessage(coreChat[i].mes, coreChat[i].extra?.reasoning) }; | ||
| 3859 | } | ||
| 3860 | |||
| 3861 | coreChat = await Promise.all(coreChat.map(async (chatItem, index) => { | 3860 | coreChat = await Promise.all(coreChat.map(async (chatItem, index) => { |
| 3862 | let message = chatItem.mes; | 3861 | let message = chatItem.mes; |
| 3863 | let regexType = chatItem.is_user ? regex_placement.USER_INPUT : regex_placement.AI_OUTPUT; | 3862 | let regexType = chatItem.is_user ? regex_placement.USER_INPUT : regex_placement.AI_OUTPUT; |
| @@ -3877,6 +3876,25 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 3877 | }; | 3876 | }; |
| 3878 | })); | 3877 | })); |
| 3879 | 3878 | ||
| 3879 | const reasoning = new PromptReasoning(); | ||
| 3880 | for (let i = coreChat.length - 1; i >= 0; i--) { | ||
| 3881 | if (reasoning.isLimitReached()) { | ||
| 3882 | break; | ||
| 3883 | } | ||
| 3884 | const depth = coreChat.length - i - 1; | ||
| 3885 | coreChat[i] = { | ||
| 3886 | mes: reasoning.addToMessage( | ||
| 3887 | coreChat[i].mes, | ||
| 3888 | getRegexedString( | ||
| 3889 | coreChat[i].extra?.reasoning, | ||
| 3890 | regex_placement.REASONING, | ||
| 3891 | { isPrompt: true, depth: depth }, | ||
| 3892 | ), | ||
| 3893 | ), | ||
| 3894 | ...coreChat[i], | ||
| 3895 | }; | ||
| 3896 | } | ||
| 3897 | |||
| 3880 | // Determine token limit | 3898 | // Determine token limit |
| 3881 | let this_max_context = getMaxContextSize(); | 3899 | let this_max_context = getMaxContextSize(); |
| 3882 | 3900 | ||
| @@ -4785,6 +4803,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 4785 | const swipes = extractMultiSwipes(data, type); | 4803 | const swipes = extractMultiSwipes(data, type); |
| 4786 | 4804 | ||
| 4787 | messageChunk = cleanUpMessage(getMessage, isImpersonate, isContinue, false); | 4805 | messageChunk = cleanUpMessage(getMessage, isImpersonate, isContinue, false); |
| 4806 | reasoning = getRegexedString(reasoning, regex_placement.REASONING); | ||
| 4788 | 4807 | ||
| 4789 | if (isContinue) { | 4808 | if (isContinue) { |
| 4790 | getMessage = continue_mag + getMessage; | 4809 | getMessage = continue_mag + getMessage; |
| @@ -7177,9 +7196,11 @@ function messageEditAuto(div) { | |||
| 7177 | mes.is_system, | 7196 | mes.is_system, |
| 7178 | mes.is_user, | 7197 | mes.is_user, |
| 7179 | this_edit_mes_id, | 7198 | this_edit_mes_id, |
| 7199 | {}, | ||
| 7200 | false, | ||
| 7180 | )); | 7201 | )); |
| 7181 | mesBlock.find('.mes_bias').empty(); | 7202 | mesBlock.find('.mes_bias').empty(); |
| 7182 | mesBlock.find('.mes_bias').append(messageFormatting(bias, '', false, false, -1)); | 7203 | mesBlock.find('.mes_bias').append(messageFormatting(bias, '', false, false, -1, {}, false)); |
| 7183 | saveChatDebounced(); | 7204 | saveChatDebounced(); |
| 7184 | } | 7205 | } |
| 7185 | 7206 | ||
| @@ -7201,10 +7222,12 @@ async function messageEditDone(div) { | |||
| 7201 | mes.is_system, | 7222 | mes.is_system, |
| 7202 | mes.is_user, | 7223 | mes.is_user, |
| 7203 | this_edit_mes_id, | 7224 | this_edit_mes_id, |
| 7225 | {}, | ||
| 7226 | false, | ||
| 7204 | ), | 7227 | ), |
| 7205 | ); | 7228 | ); |
| 7206 | mesBlock.find('.mes_bias').empty(); | 7229 | mesBlock.find('.mes_bias').empty(); |
| 7207 | mesBlock.find('.mes_bias').append(messageFormatting(bias, '', false, false, -1)); | 7230 | mesBlock.find('.mes_bias').append(messageFormatting(bias, '', false, false, -1, {}, false)); |
| 7208 | appendMediaToMessage(mes, div.closest('.mes')); | 7231 | appendMediaToMessage(mes, div.closest('.mes')); |
| 7209 | addCopyToCodeBlocks(div.closest('.mes')); | 7232 | addCopyToCodeBlocks(div.closest('.mes')); |
| 7210 | 7233 | ||
| @@ -10841,6 +10864,8 @@ jQuery(async function () { | |||
| 10841 | chat[this_edit_mes_id].is_system, | 10864 | chat[this_edit_mes_id].is_system, |
| 10842 | chat[this_edit_mes_id].is_user, | 10865 | chat[this_edit_mes_id].is_user, |
| 10843 | this_edit_mes_id, | 10866 | this_edit_mes_id, |
| 10867 | {}, | ||
| 10868 | false, | ||
| 10844 | )); | 10869 | )); |
| 10845 | appendMediaToMessage(chat[this_edit_mes_id], $(this).closest('.mes')); | 10870 | appendMediaToMessage(chat[this_edit_mes_id], $(this).closest('.mes')); |
| 10846 | addCopyToCodeBlocks($(this).closest('.mes')); | 10871 | addCopyToCodeBlocks($(this).closest('.mes')); |
| @@ -94,6 +94,12 @@ | |||
| 94 | <span data-i18n="World Info">World Info</span> | 94 | <span data-i18n="World Info">World Info</span> |
| 95 | </label> | 95 | </label> |
| 96 | </div> | 96 | </div> |
| 97 | <div data-i18n="[title]ext_regex_reasoning_desc" title="Reasoning block contents. When 'Only Format Prompt' is checked, it will also affect the reasoning contents added to the prompt."> | ||
| 98 | <label class="checkbox flex-container"> | ||
| 99 | <input type="checkbox" name="replace_position" value="6"> | ||
| 100 | <span data-i18n="Reasoning">Reasoning</span> | ||
| 101 | </label> | ||
| 102 | </div> | ||
| 97 | <div class="flex-container wide100p marginTop5"> | 103 | <div class="flex-container wide100p marginTop5"> |
| 98 | <div class="flex1 flex-container flexNoGap"> | 104 | <div class="flex1 flex-container flexNoGap"> |
| 99 | <small data-i18n="[title]ext_regex_min_depth_desc" title="When applied to prompts or display, only affect messages that are at least N levels deep. 0 = last message, 1 = penultimate message, etc. Only counts WI entries @Depth and usable messages, i.e. not hidden or system."> | 105 | <small data-i18n="[title]ext_regex_min_depth_desc" title="When applied to prompts or display, only affect messages that are at least N levels deep. 0 = last message, 1 = penultimate message, etc. Only counts WI entries @Depth and usable messages, i.e. not hidden or system."> |
| @@ -20,6 +20,7 @@ const regex_placement = { | |||
| 20 | SLASH_COMMAND: 3, | 20 | SLASH_COMMAND: 3, |
| 21 | // 4 - sendAs (legacy) | 21 | // 4 - sendAs (legacy) |
| 22 | WORLD_INFO: 5, | 22 | WORLD_INFO: 5, |
| 23 | REASONING: 6, | ||
| 23 | }; | 24 | }; |
| 24 | 25 | ||
| 25 | export const substitute_find_regex = { | 26 | export const substitute_find_regex = { |