Merge pull request #3606 from SillyTavern/reasoning-continue-fix Fix continue duplicating reasoning block

5d255d758ebb2516e54342edae04d2e18a3ae443

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

Signed
2 files changed, +57 -8Ignore whitespace
public/script.js+15 -5
@@ -3135,8 +3135,9 @@ class StreamingProcessor {
3135 * @param {boolean} forceName2 If true, force the use of name23135 * @param {boolean} forceName2 If true, force the use of name2
3136 * @param {Date} timeStarted Date when generation was started3136 * @param {Date} timeStarted Date when generation was started
3137 * @param {string} continueMessage Previous message if the type is 'continue'3137 * @param {string} continueMessage Previous message if the type is 'continue'
3138 * @param {PromptReasoning} promptReasoning Prompt reasoning instance
3138 */3139 */
3139 constructor(type, forceName2, timeStarted, continueMessage) {3140 constructor(type, forceName2, timeStarted, continueMessage, promptReasoning) {
3140 this.result = '';3141 this.result = '';
3141 this.messageId = -1;3142 this.messageId = -1;
3142 /** @type {HTMLElement} */3143 /** @type {HTMLElement} */
@@ -3164,6 +3165,8 @@ class StreamingProcessor {
3164 this.toolCalls = [];3165 this.toolCalls = [];
3165 // Initialize reasoning in its own handler3166 // Initialize reasoning in its own handler
3166 this.reasoningHandler = new ReasoningHandler(timeStarted);3167 this.reasoningHandler = new ReasoningHandler(timeStarted);
3168 /** @type {PromptReasoning} */
3169 this.promptReasoning = promptReasoning;
3167 }3170 }
31683171
3169 #checkDomElements(messageId) {3172 #checkDomElements(messageId) {
@@ -3192,6 +3195,10 @@ class StreamingProcessor {
3192 }3195 }
31933196
3194 async onStartStreaming(text) {3197 async onStartStreaming(text) {
3198 if (this.type === 'continue' && this.promptReasoning.prefixReasoning) {
3199 this.reasoningHandler.initContinue(this.promptReasoning);
3200 }
3201
3195 let messageId = -1;3202 let messageId = -1;
31963203
3197 if (this.type == 'impersonate') {3204 if (this.type == 'impersonate') {
@@ -3882,13 +3889,13 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
3882 };3889 };
3883 }));3890 }));
38843891
3885 const reasoning = new PromptReasoning();3892 const promptReasoning = new PromptReasoning();
3886 for (let i = coreChat.length - 1; i >= 0; i--) {3893 for (let i = coreChat.length - 1; i >= 0; i--) {
3887 const depth = coreChat.length - i - 1;3894 const depth = coreChat.length - i - 1;
3888 const isPrefix = isContinue && i === coreChat.length - 1;3895 const isPrefix = isContinue && i === coreChat.length - 1;
3889 coreChat[i] = {3896 coreChat[i] = {
3890 ...coreChat[i],3897 ...coreChat[i],
3891 mes: reasoning.addToMessage(3898 mes: promptReasoning.addToMessage(
3892 coreChat[i].mes,3899 coreChat[i].mes,
3893 getRegexedString(3900 getRegexedString(
3894 String(coreChat[i].extra?.reasoning ?? ''),3901 String(coreChat[i].extra?.reasoning ?? ''),
@@ -3896,9 +3903,10 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
3896 { isPrompt: true, depth: depth },3903 { isPrompt: true, depth: depth },
3897 ),3904 ),
3898 isPrefix,3905 isPrefix,
3906 coreChat[i].extra?.reasoning_duration,
3899 ),3907 ),
3900 };3908 };
3901 if (reasoning.isLimitReached()) {3909 if (promptReasoning.isLimitReached()) {
3902 break;3910 break;
3903 }3911 }
3904 }3912 }
@@ -4723,7 +4731,8 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
4723 console.debug(`pushed prompt bits to itemizedPrompts array. Length is now: ${itemizedPrompts.length}`);4731 console.debug(`pushed prompt bits to itemizedPrompts array. Length is now: ${itemizedPrompts.length}`);
47244732
4725 if (isStreamingEnabled() && type !== 'quiet') {4733 if (isStreamingEnabled() && type !== 'quiet') {
4726 streamingProcessor = new StreamingProcessor(type, force_name2, generation_started, continue_mag);4734 continue_mag = promptReasoning.removePrefix(continue_mag);
4735 streamingProcessor = new StreamingProcessor(type, force_name2, generation_started, continue_mag, promptReasoning);
4727 if (isContinue) {4736 if (isContinue) {
4728 // Save reply does add cycle text to the prompt, so it's not needed here4737 // Save reply does add cycle text to the prompt, so it's not needed here
4729 streamingProcessor.firstMessageText = '';4738 streamingProcessor.firstMessageText = '';
@@ -4824,6 +4833,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
4824 }4833 }
48254834
4826 if (isContinue) {4835 if (isContinue) {
4836 continue_mag = promptReasoning.removePrefix(continue_mag);
4827 getMessage = continue_mag + getMessage;4837 getMessage = continue_mag + getMessage;
4828 }4838 }
48294839
public/scripts/reasoning.js+42 -3
@@ -189,6 +189,17 @@ export class ReasoningHandler {
189 }189 }
190190
191 /**191 /**
192 * Sets the reasoning state when continuing a prompt.
193 * @param {PromptReasoning} promptReasoning Prompt reasoning object
194 */
195 initContinue(promptReasoning) {
196 this.reasoning = promptReasoning.prefixReasoning;
197 this.state = ReasoningState.Done;
198 this.startTime = this.initialTime;
199 this.endTime = promptReasoning.prefixDuration ? new Date(this.initialTime.getTime() + promptReasoning.prefixDuration) : null;
200 }
201
202 /**
192 * Initializes the reasoning handler for a specific message.203 * Initializes the reasoning handler for a specific message.
193 *204 *
194 * Can be used to update the DOM elements or read other reasoning states.205 * Can be used to update the DOM elements or read other reasoning states.
@@ -514,6 +525,9 @@ export class PromptReasoning {
514525
515 constructor() {526 constructor() {
516 this.counter = 0;527 this.counter = 0;
528 this.prefixLength = -1;
529 this.prefixReasoning = '';
530 this.prefixDuration = null;
517 }531 }
518532
519 /**533 /**
@@ -533,9 +547,10 @@ export class PromptReasoning {
533 * @param {string} content Message content547 * @param {string} content Message content
534 * @param {string} reasoning Message reasoning548 * @param {string} reasoning Message reasoning
535 * @param {boolean} isPrefix Whether this is the last message prefix549 * @param {boolean} isPrefix Whether this is the last message prefix
550 * @param {number?} duration Duration of the reasoning
536 * @returns {string} Message content with reasoning551 * @returns {string} Message content with reasoning
537 */552 */
538 addToMessage(content, reasoning, isPrefix) {553 addToMessage(content, reasoning, isPrefix, duration) {
539 // Disabled or reached limit of additions554 // Disabled or reached limit of additions
540 if (!isPrefix && (!power_user.reasoning.add_to_prompts || this.counter >= power_user.reasoning.max_additions)) {555 if (!isPrefix && (!power_user.reasoning.add_to_prompts || this.counter >= power_user.reasoning.max_additions)) {
541 return content;556 return content;
@@ -556,11 +571,35 @@ export class PromptReasoning {
556571
557 // Combine parts with reasoning only572 // Combine parts with reasoning only
558 if (isPrefix && !content) {573 if (isPrefix && !content) {
559 return `${prefix}${reasoning}`;574 const formattedReasoning = `${prefix}${reasoning}`;
575 if (isPrefix) {
576 this.prefixReasoning = reasoning;
577 this.prefixLength = formattedReasoning.length;
578 this.prefixDuration = duration;
579 }
580 return formattedReasoning;
560 }581 }
561582
562 // Combine parts with reasoning and content583 // Combine parts with reasoning and content
563 return `${prefix}${reasoning}${suffix}${separator}${content}`;584 const formattedReasoning = `${prefix}${reasoning}${suffix}${separator}`;
585 if (isPrefix) {
586 this.prefixReasoning = reasoning;
587 this.prefixLength = formattedReasoning.length;
588 this.prefixDuration = duration;
589 }
590 return `${formattedReasoning}${content}`;
591 }
592
593 /**
594 * Removes the reasoning prefix from the content.
595 * @param {string} content Content with the reasoning prefix
596 * @returns {string} Content without the reasoning prefix
597 */
598 removePrefix(content) {
599 if (this.prefixLength > 0) {
600 return content.slice(this.prefixLength);
601 }
602 return content;
564 }603 }
565}604}
566605