The THONKening

afae8d02be1e837b1dc5abc013fa011ab4c3d067

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

10 files changed, +113 -32Showing whitespace changes
public/index.html+1 -0
@@ -6229,6 +6229,7 @@
6229 <div class="mes_edit_cancel menu_button fa-solid fa-xmark" title="Cancel" data-i18n="[title]Cancel"></div>6229 <div class="mes_edit_cancel menu_button fa-solid fa-xmark" title="Cancel" data-i18n="[title]Cancel"></div>
6230 </div>6230 </div>
6231 </div>6231 </div>
6232 <div class="mes_reasoning"></div>
6232 <div class="mes_text"></div>6233 <div class="mes_text"></div>
6233 <div class="mes_img_container">6234 <div class="mes_img_container">
6234 <div class="mes_img_controls">6235 <div class="mes_img_controls">
public/script.js+61 -16
@@ -170,7 +170,7 @@ import {
170 isElementInViewport,170 isElementInViewport,
171 copyText,171 copyText,
172} from './scripts/utils.js';172} from './scripts/utils.js';
173import { debounce_timeout } from './scripts/constants.js';173import { debounce_timeout, THINK_BREAK } from './scripts/constants.js';
174174
175import { doDailyExtensionUpdatesCheck, extension_settings, initExtensions, loadExtensionSettings, runGenerationInterceptors, saveMetadataDebounced } from './scripts/extensions.js';175import { doDailyExtensionUpdatesCheck, extension_settings, initExtensions, loadExtensionSettings, runGenerationInterceptors, saveMetadataDebounced } from './scripts/extensions.js';
176import { COMMENT_NAME_DEFAULT, executeSlashCommandsOnChatInput, getSlashCommandsHelp, initDefaultSlashCommands, isExecutingCommandsFromChatInput, pauseScriptExecution, processChatSlashCommands, stopScriptExecution } from './scripts/slash-commands.js';176import { COMMENT_NAME_DEFAULT, executeSlashCommandsOnChatInput, getSlashCommandsHelp, initDefaultSlashCommands, isExecutingCommandsFromChatInput, pauseScriptExecution, processChatSlashCommands, stopScriptExecution } from './scripts/slash-commands.js';
@@ -2199,6 +2199,7 @@ function getMessageFromTemplate({
2199 isUser,2199 isUser,
2200 avatarImg,2200 avatarImg,
2201 bias,2201 bias,
2202 reasoning,
2202 isSystem,2203 isSystem,
2203 title,2204 title,
2204 timerValue,2205 timerValue,
@@ -2223,6 +2224,7 @@ function getMessageFromTemplate({
2223 mes.find('.avatar img').attr('src', avatarImg);2224 mes.find('.avatar img').attr('src', avatarImg);
2224 mes.find('.ch_name .name_text').text(characterName);2225 mes.find('.ch_name .name_text').text(characterName);
2225 mes.find('.mes_bias').html(bias);2226 mes.find('.mes_bias').html(bias);
2227 mes.find('.mes_reasoning').html(reasoning);
2226 mes.find('.timestamp').text(timestamp).attr('title', `${extra?.api ? extra.api + ' - ' : ''}${extra?.model ?? ''}`);2228 mes.find('.timestamp').text(timestamp).attr('title', `${extra?.api ? extra.api + ' - ' : ''}${extra?.model ?? ''}`);
2227 mes.find('.mesIDDisplay').text(`#${mesId}`);2229 mes.find('.mesIDDisplay').text(`#${mesId}`);
2228 tokenCount && mes.find('.tokenCounterDisplay').text(`${tokenCount}t`);2230 tokenCount && mes.find('.tokenCounterDisplay').text(`${tokenCount}t`);
@@ -2241,6 +2243,7 @@ export function updateMessageBlock(messageId, message) {
2241 const messageElement = $(`#chat [mesid="${messageId}"]`);2243 const messageElement = $(`#chat [mesid="${messageId}"]`);
2242 const text = message?.extra?.display_text ?? message.mes;2244 const text = message?.extra?.display_text ?? message.mes;
2243 messageElement.find('.mes_text').html(messageFormatting(text, message.name, message.is_system, message.is_user, messageId));2245 messageElement.find('.mes_text').html(messageFormatting(text, message.name, message.is_system, message.is_user, messageId));
2246 messageElement.find('.mes_reasoning').html(messageFormatting(message.extra?.reasoning ?? '', '', false, false, -1));
2244 addCopyToCodeBlocks(messageElement);2247 addCopyToCodeBlocks(messageElement);
2245 appendMediaToMessage(message, messageElement);2248 appendMediaToMessage(message, messageElement);
2246}2249}
@@ -2399,6 +2402,7 @@ export function addOneMessage(mes, { type = 'normal', insertAfter = null, scroll
2399 sanitizerOverrides,2402 sanitizerOverrides,
2400 );2403 );
2401 const bias = messageFormatting(mes.extra?.bias ?? '', '', false, false, -1);2404 const bias = messageFormatting(mes.extra?.bias ?? '', '', false, false, -1);
2405 const reasoning = messageFormatting(mes.extra?.reasoning ?? '', '', false, false, -1);
2402 let bookmarkLink = mes?.extra?.bookmark_link ?? '';2406 let bookmarkLink = mes?.extra?.bookmark_link ?? '';
24032407
2404 let params = {2408 let params = {
@@ -2408,6 +2412,7 @@ export function addOneMessage(mes, { type = 'normal', insertAfter = null, scroll
2408 isUser: mes.is_user,2412 isUser: mes.is_user,
2409 avatarImg: avatarImg,2413 avatarImg: avatarImg,
2410 bias: bias,2414 bias: bias,
2415 reasoning: reasoning,
2411 isSystem: isSystem,2416 isSystem: isSystem,
2412 title: title,2417 title: title,
2413 bookmarkLink: bookmarkLink,2418 bookmarkLink: bookmarkLink,
@@ -2467,6 +2472,7 @@ export function addOneMessage(mes, { type = 'normal', insertAfter = null, scroll
2467 const swipeMessage = chatElement.find(`[mesid="${chat.length - 1}"]`);2472 const swipeMessage = chatElement.find(`[mesid="${chat.length - 1}"]`);
2468 swipeMessage.attr('swipeid', params.swipeId);2473 swipeMessage.attr('swipeid', params.swipeId);
2469 swipeMessage.find('.mes_text').html(messageText).attr('title', title);2474 swipeMessage.find('.mes_text').html(messageText).attr('title', title);
2475 swipeMessage.find('.mes_reasoning').html(reasoning);
2470 swipeMessage.find('.timestamp').text(timestamp).attr('title', `${params.extra.api} - ${params.extra.model}`);2476 swipeMessage.find('.timestamp').text(timestamp).attr('title', `${params.extra.api} - ${params.extra.model}`);
2471 appendMediaToMessage(mes, swipeMessage);2477 appendMediaToMessage(mes, swipeMessage);
2472 if (power_user.timestamp_model_icon && params.extra?.api) {2478 if (power_user.timestamp_model_icon && params.extra?.api) {
@@ -3077,6 +3083,7 @@ class StreamingProcessor {
3077 this.messageTextDom = null;3083 this.messageTextDom = null;
3078 this.messageTimerDom = null;3084 this.messageTimerDom = null;
3079 this.messageTokenCounterDom = null;3085 this.messageTokenCounterDom = null;
3086 this.messageReasoningDom = null;
3080 /** @type {HTMLTextAreaElement} */3087 /** @type {HTMLTextAreaElement} */
3081 this.sendTextarea = document.querySelector('#send_textarea');3088 this.sendTextarea = document.querySelector('#send_textarea');
3082 this.type = type;3089 this.type = type;
@@ -3092,6 +3099,7 @@ class StreamingProcessor {
3092 /** @type {import('./scripts/logprobs.js').TokenLogprobs[]} */3099 /** @type {import('./scripts/logprobs.js').TokenLogprobs[]} */
3093 this.messageLogprobs = [];3100 this.messageLogprobs = [];
3094 this.toolCalls = [];3101 this.toolCalls = [];
3102 this.reasoning = '';
3095 }3103 }
30963104
3097 #checkDomElements(messageId) {3105 #checkDomElements(messageId) {
@@ -3100,6 +3108,7 @@ class StreamingProcessor {
3100 this.messageTextDom = this.messageDom?.querySelector('.mes_text');3108 this.messageTextDom = this.messageDom?.querySelector('.mes_text');
3101 this.messageTimerDom = this.messageDom?.querySelector('.mes_timer');3109 this.messageTimerDom = this.messageDom?.querySelector('.mes_timer');
3102 this.messageTokenCounterDom = this.messageDom?.querySelector('.tokenCounterDisplay');3110 this.messageTokenCounterDom = this.messageDom?.querySelector('.tokenCounterDisplay');
3111 this.messageReasoningDom = this.messageDom?.querySelector('.mes_reasoning');
3103 }3112 }
3104 }3113 }
31053114
@@ -3184,11 +3193,17 @@ class StreamingProcessor {
3184 chat[messageId]['gen_started'] = this.timeStarted;3193 chat[messageId]['gen_started'] = this.timeStarted;
3185 chat[messageId]['gen_finished'] = currentTime;3194 chat[messageId]['gen_finished'] = currentTime;
31863195
3187 if (currentTokenCount) {
3188 if (!chat[messageId]['extra']) {3196 if (!chat[messageId]['extra']) {
3189 chat[messageId]['extra'] = {};3197 chat[messageId]['extra'] = {};
3190 }3198 }
31913199
3200 if (this.reasoning && this.messageReasoningDom instanceof HTMLElement) {
3201 chat[messageId]['extra']['reasoning'] = this.reasoning;
3202 const formattedReasoning = messageFormatting(this.reasoning, '', false, false, -1);
3203 this.messageReasoningDom.innerHTML = formattedReasoning;
3204 }
3205
3206 if (currentTokenCount) {
3192 chat[messageId]['extra']['token_count'] = currentTokenCount;3207 chat[messageId]['extra']['token_count'] = currentTokenCount;
3193 if (this.messageTokenCounterDom instanceof HTMLElement) {3208 if (this.messageTokenCounterDom instanceof HTMLElement) {
3194 this.messageTokenCounterDom.textContent = `${currentTokenCount}t`;3209 this.messageTokenCounterDom.textContent = `${currentTokenCount}t`;
@@ -3320,7 +3335,7 @@ class StreamingProcessor {
3320 }3335 }
33213336
3322 /**3337 /**
3323 * @returns {Generator<{ text: string, swipes: string[], logprobs: import('./scripts/logprobs.js').TokenLogprobs, toolCalls: any[] }, void, void>}3338 * @returns {Generator<{ text: string, swipes: string[], logprobs: import('./scripts/logprobs.js').TokenLogprobs, toolCalls: any[], state: any }, void, void>}
3324 */3339 */
3325 *nullStreamingGeneration() {3340 *nullStreamingGeneration() {
3326 throw new Error('Generation function for streaming is not hooked up');3341 throw new Error('Generation function for streaming is not hooked up');
@@ -3342,7 +3357,7 @@ class StreamingProcessor {
3342 try {3357 try {
3343 const sw = new Stopwatch(1000 / power_user.streaming_fps);3358 const sw = new Stopwatch(1000 / power_user.streaming_fps);
3344 const timestamps = [];3359 const timestamps = [];
3345 for await (const { text, swipes, logprobs, toolCalls } of this.generator()) {3360 for await (const { text, swipes, logprobs, toolCalls, state } of this.generator()) {
3346 timestamps.push(Date.now());3361 timestamps.push(Date.now());
3347 if (this.isStopped) {3362 if (this.isStopped) {
3348 return;3363 return;
@@ -3354,6 +3369,7 @@ class StreamingProcessor {
3354 if (logprobs) {3369 if (logprobs) {
3355 this.messageLogprobs.push(...(Array.isArray(logprobs) ? logprobs : [logprobs]));3370 this.messageLogprobs.push(...(Array.isArray(logprobs) ? logprobs : [logprobs]));
3356 }3371 }
3372 this.reasoning = state?.reasoning ?? '';
3357 await eventSource.emit(event_types.STREAM_TOKEN_RECEIVED, text);3373 await eventSource.emit(event_types.STREAM_TOKEN_RECEIVED, text);
3358 await sw.tick(() => this.onProgressStreaming(this.messageId, this.continueMessage + text));3374 await sw.tick(() => this.onProgressStreaming(this.messageId, this.continueMessage + text));
3359 }3375 }
@@ -4741,6 +4757,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
4741 //const getData = await response.json();4757 //const getData = await response.json();
4742 let getMessage = extractMessageFromData(data);4758 let getMessage = extractMessageFromData(data);
4743 let title = extractTitleFromData(data);4759 let title = extractTitleFromData(data);
4760 let reasoning = extractReasoningFromData(data);
4744 kobold_horde_model = title;4761 kobold_horde_model = title;
47454762
4746 const swipes = extractMultiSwipes(data, type);4763 const swipes = extractMultiSwipes(data, type);
@@ -4767,10 +4784,10 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
4767 else {4784 else {
4768 // Without streaming we'll be having a full message on continuation. Treat it as a last chunk.4785 // Without streaming we'll be having a full message on continuation. Treat it as a last chunk.
4769 if (originalType !== 'continue') {4786 if (originalType !== 'continue') {
4770 ({ type, getMessage } = await saveReply(type, getMessage, false, title, swipes));4787 ({ type, getMessage } = await saveReply(type, getMessage, false, title, swipes, reasoning));
4771 }4788 }
4772 else {4789 else {
4773 ({ type, getMessage } = await saveReply('appendFinal', getMessage, false, title, swipes));4790 ({ type, getMessage } = await saveReply('appendFinal', getMessage, false, title, swipes, reasoning));
4774 }4791 }
47754792
4776 // This relies on `saveReply` having been called to add the message to the chat, so it must be last.4793 // This relies on `saveReply` having been called to add the message to the chat, so it must be last.
@@ -5649,16 +5666,15 @@ function parseAndSaveLogprobs(data, continueFrom) {
5649}5666}
56505667
5651/**5668/**
5652 * Extracts the message from the response data.5669 * Gets the text context from the response data.
5653 * @param {object} data Response data5670 * @param {object} data Response JSON data
5654 * @returns {string} Extracted message5671 * @returns {string} Extracted text
5655 */5672 */
5656function extractMessageFromData(data) {5673function getTextContextFromData(data) {
5657 if (typeof data === 'string') {5674 if (typeof data === 'string') {
5658 return data;5675 return data;
5659 }5676 }
56605677
5661 function getTextContext() {
5662 switch (main_api) {5678 switch (main_api) {
5663 case 'kobold':5679 case 'kobold':
5664 return data.results[0].text;5680 return data.results[0].text;
@@ -5675,17 +5691,41 @@ function extractMessageFromData(data) {
5675 }5691 }
5676}5692}
56775693
5678 const content = getTextContext();5694/**
5695 * Extracts the message from the response data.
5696 * @param {object} data Response data
5697 * @returns {string} Extracted message
5698 */
5699function extractMessageFromData(data){
5700 const content = String(getTextContextFromData(data) ?? '');
56795701
5680 if (main_api === 'openai' && oai_settings.chat_completion_source === chat_completion_sources.DEEPSEEK && oai_settings.show_thoughts) {5702 if (content.includes(THINK_BREAK)) {
5681 const thoughts = data?.choices?.[0]?.message?.reasoning_content ?? '';5703 return content.split(THINK_BREAK)[1];
5682 return [thoughts, content].filter(x => x).join('\n\n');
5683 }5704 }
56845705
5685 return content;5706 return content;
5686}5707}
56875708
5688/**5709/**
5710 * Extracts the reasoning from the response data.
5711 * @param {object} data Response data
5712 * @returns {string} Extracted reasoning
5713 */
5714function extractReasoningFromData(data) {
5715 const content = String(getTextContextFromData(data) ?? '');
5716
5717 if (content.includes(THINK_BREAK)) {
5718 return content.split(THINK_BREAK)[0];
5719 }
5720
5721 if (main_api === 'openai' && oai_settings.chat_completion_source === chat_completion_sources.DEEPSEEK && oai_settings.show_thoughts) {
5722 return data?.choices?.[0]?.message?.reasoning_content ?? '';
5723 }
5724
5725 return '';
5726}
5727
5728/**
5689 * Extracts multiswipe swipes from the response data.5729 * Extracts multiswipe swipes from the response data.
5690 * @param {Object} data Response data5730 * @param {Object} data Response data
5691 * @param {string} type Type of generation5731 * @param {string} type Type of generation
@@ -5865,7 +5905,7 @@ export function cleanUpMessage(getMessage, isImpersonate, isContinue, displayInc
5865 return getMessage;5905 return getMessage;
5866}5906}
58675907
5868export async function saveReply(type, getMessage, fromStreaming, title, swipes) {5908export async function saveReply(type, getMessage, fromStreaming, title, swipes, reasoning) {
5869 if (type != 'append' && type != 'continue' && type != 'appendFinal' && chat.length && (chat[chat.length - 1]['swipe_id'] === undefined ||5909 if (type != 'append' && type != 'continue' && type != 'appendFinal' && chat.length && (chat[chat.length - 1]['swipe_id'] === undefined ||
5870 chat[chat.length - 1]['is_user'])) {5910 chat[chat.length - 1]['is_user'])) {
5871 type = 'normal';5911 type = 'normal';
@@ -5890,6 +5930,7 @@ export async function saveReply(type, getMessage, fromStreaming, title, swipes)
5890 chat[chat.length - 1]['send_date'] = getMessageTimeStamp();5930 chat[chat.length - 1]['send_date'] = getMessageTimeStamp();
5891 chat[chat.length - 1]['extra']['api'] = getGeneratingApi();5931 chat[chat.length - 1]['extra']['api'] = getGeneratingApi();
5892 chat[chat.length - 1]['extra']['model'] = getGeneratingModel();5932 chat[chat.length - 1]['extra']['model'] = getGeneratingModel();
5933 chat[chat.length - 1]['extra']['reasoning'] = reasoning;
5893 if (power_user.message_token_count_enabled) {5934 if (power_user.message_token_count_enabled) {
5894 chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(chat[chat.length - 1]['mes'], 0);5935 chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(chat[chat.length - 1]['mes'], 0);
5895 }5936 }
@@ -5910,6 +5951,7 @@ export async function saveReply(type, getMessage, fromStreaming, title, swipes)
5910 chat[chat.length - 1]['send_date'] = getMessageTimeStamp();5951 chat[chat.length - 1]['send_date'] = getMessageTimeStamp();
5911 chat[chat.length - 1]['extra']['api'] = getGeneratingApi();5952 chat[chat.length - 1]['extra']['api'] = getGeneratingApi();
5912 chat[chat.length - 1]['extra']['model'] = getGeneratingModel();5953 chat[chat.length - 1]['extra']['model'] = getGeneratingModel();
5954 chat[chat.length - 1]['extra']['reasoning'] += reasoning;
5913 if (power_user.message_token_count_enabled) {5955 if (power_user.message_token_count_enabled) {
5914 chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(chat[chat.length - 1]['mes'], 0);5956 chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(chat[chat.length - 1]['mes'], 0);
5915 }5957 }
@@ -5927,6 +5969,7 @@ export async function saveReply(type, getMessage, fromStreaming, title, swipes)
5927 chat[chat.length - 1]['send_date'] = getMessageTimeStamp();5969 chat[chat.length - 1]['send_date'] = getMessageTimeStamp();
5928 chat[chat.length - 1]['extra']['api'] = getGeneratingApi();5970 chat[chat.length - 1]['extra']['api'] = getGeneratingApi();
5929 chat[chat.length - 1]['extra']['model'] = getGeneratingModel();5971 chat[chat.length - 1]['extra']['model'] = getGeneratingModel();
5972 chat[chat.length - 1]['extra']['reasoning'] += reasoning;
5930 if (power_user.message_token_count_enabled) {5973 if (power_user.message_token_count_enabled) {
5931 chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(chat[chat.length - 1]['mes'], 0);5974 chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(chat[chat.length - 1]['mes'], 0);
5932 }5975 }
@@ -5944,6 +5987,7 @@ export async function saveReply(type, getMessage, fromStreaming, title, swipes)
5944 chat[chat.length - 1]['send_date'] = getMessageTimeStamp();5987 chat[chat.length - 1]['send_date'] = getMessageTimeStamp();
5945 chat[chat.length - 1]['extra']['api'] = getGeneratingApi();5988 chat[chat.length - 1]['extra']['api'] = getGeneratingApi();
5946 chat[chat.length - 1]['extra']['model'] = getGeneratingModel();5989 chat[chat.length - 1]['extra']['model'] = getGeneratingModel();
5990 chat[chat.length - 1]['extra']['reasoning'] = reasoning;
5947 if (power_user.trim_spaces) {5991 if (power_user.trim_spaces) {
5948 getMessage = getMessage.trim();5992 getMessage = getMessage.trim();
5949 }5993 }
@@ -8646,6 +8690,7 @@ const swipe_right = () => {
8646 // resets the timer8690 // resets the timer
8647 swipeMessage.find('.mes_timer').html('');8691 swipeMessage.find('.mes_timer').html('');
8648 swipeMessage.find('.tokenCounterDisplay').text('');8692 swipeMessage.find('.tokenCounterDisplay').text('');
8693 swipeMessage.find('.mes_reasoning').html('');
8649 } else {8694 } else {
8650 //console.log('showing previously generated swipe candidate, or "..."');8695 //console.log('showing previously generated swipe candidate, or "..."');
8651 //console.log('onclick right swipe calling addOneMessage');8696 //console.log('onclick right swipe calling addOneMessage');
public/scripts/constants.js+5 -0
@@ -14,3 +14,8 @@ export const debounce_timeout = {
14 /** [5 sec] For delayed tasks, like auto-saving or completing batch operations that need a significant pause. */14 /** [5 sec] For delayed tasks, like auto-saving or completing batch operations that need a significant pause. */
15 extended: 5000,15 extended: 5000,
16};16};
17
18/**
19 * Custom boundary for splitting the text between the model's reasoning and the actual response.
20 */
21export const THINK_BREAK = '##�THINK_BREAK�##';
public/scripts/kai-settings.js+1 -1
@@ -188,7 +188,7 @@ export async function generateKoboldWithStreaming(generate_data, signal) {
188 if (data?.token) {188 if (data?.token) {
189 text += data.token;189 text += data.token;
190 }190 }
191 yield { text, swipes: [], toolCalls: [] };191 yield { text, swipes: [], toolCalls: [], state: {} };
192 }192 }
193 };193 };
194}194}
public/scripts/nai-settings.js+1 -1
@@ -746,7 +746,7 @@ export async function generateNovelWithStreaming(generate_data, signal) {
746 text += data.token;746 text += data.token;
747 }747 }
748748
749 yield { text, swipes: [], logprobs: parseNovelAILogprobs(data.logprobs), toolCalls: [] };749 yield { text, swipes: [], logprobs: parseNovelAILogprobs(data.logprobs), toolCalls: [], state: {} };
750 }750 }
751 };751 };
752}752}
public/scripts/openai.js+10 -9
@@ -2095,7 +2095,7 @@ async function sendOpenAIRequest(type, messages, signal) {
2095 let text = '';2095 let text = '';
2096 const swipes = [];2096 const swipes = [];
2097 const toolCalls = [];2097 const toolCalls = [];
2098 const state = {};2098 const state = { reasoning: '' };
2099 while (true) {2099 while (true) {
2100 const { done, value } = await reader.read();2100 const { done, value } = await reader.read();
2101 if (done) return;2101 if (done) return;
@@ -2113,7 +2113,7 @@ async function sendOpenAIRequest(type, messages, signal) {
21132113
2114 ToolManager.parseToolCalls(toolCalls, parsed);2114 ToolManager.parseToolCalls(toolCalls, parsed);
21152115
2116 yield { text, swipes: swipes, logprobs: parseChatCompletionLogprobs(parsed), toolCalls: toolCalls };2116 yield { text, swipes: swipes, logprobs: parseChatCompletionLogprobs(parsed), toolCalls: toolCalls, state: state };
2117 }2117 }
2118 };2118 };
2119 }2119 }
@@ -2150,16 +2150,17 @@ function getStreamingReply(data, state) {
2150 if (oai_settings.chat_completion_source === chat_completion_sources.CLAUDE) {2150 if (oai_settings.chat_completion_source === chat_completion_sources.CLAUDE) {
2151 return data?.delta?.text || '';2151 return data?.delta?.text || '';
2152 } else if (oai_settings.chat_completion_source === chat_completion_sources.MAKERSUITE) {2152 } else if (oai_settings.chat_completion_source === chat_completion_sources.MAKERSUITE) {
2153 return data?.candidates?.[0]?.content?.parts?.filter(x => oai_settings.show_thoughts || !x.thought)?.map(x => x.text)?.filter(x => x)?.join('\n\n') || '';2153 if (oai_settings.show_thoughts) {
2154 state.reasoning += (data?.candidates?.[0]?.content?.parts?.filter(x => x.thought)?.map(x => x.text)?.[0] || '');
2155 }
2156 return data?.candidates?.[0]?.content?.parts?.filter(x => !x.thought)?.map(x => x.text)?.[0] || '';
2154 } else if (oai_settings.chat_completion_source === chat_completion_sources.COHERE) {2157 } else if (oai_settings.chat_completion_source === chat_completion_sources.COHERE) {
2155 return data?.delta?.message?.content?.text || data?.delta?.message?.tool_plan || '';2158 return data?.delta?.message?.content?.text || data?.delta?.message?.tool_plan || '';
2156 } else if (oai_settings.chat_completion_source === chat_completion_sources.DEEPSEEK) {2159 } else if (oai_settings.chat_completion_source === chat_completion_sources.DEEPSEEK) {
2157 const hadThoughts = state.hadThoughts;2160 if (oai_settings.show_thoughts) {
2158 const thoughts = data.choices?.filter(x => oai_settings.show_thoughts || !x?.delta?.reasoning_content)?.[0]?.delta?.reasoning_content || '';2161 state.reasoning += (data.choices?.filter(x => x?.delta?.reasoning_content)?.[0]?.delta?.reasoning_content || '');
2159 const content = data.choices?.[0]?.delta?.content || '';2162 }
2160 state.hadThoughts = !!thoughts;2163 return data.choices?.[0]?.delta?.content || '';
2161 const separator = hadThoughts && !thoughts ? '\n\n' : '';
2162 return [thoughts, separator, content].filter(x => x).join('\n\n');
2163 } else {2164 } else {
2164 return data.choices?.[0]?.delta?.content ?? data.choices?.[0]?.message?.content ?? data.choices?.[0]?.text ?? '';2165 return data.choices?.[0]?.delta?.content ?? data.choices?.[0]?.message?.content ?? data.choices?.[0]?.text ?? '';
2165 }2166 }
public/scripts/textgen-settings.js+2 -1
@@ -986,6 +986,7 @@ export async function generateTextGenWithStreaming(generate_data, signal) {
986 let logprobs = null;986 let logprobs = null;
987 const swipes = [];987 const swipes = [];
988 const toolCalls = [];988 const toolCalls = [];
989 const state = {};
989 while (true) {990 while (true) {
990 const { done, value } = await reader.read();991 const { done, value } = await reader.read();
991 if (done) return;992 if (done) return;
@@ -1004,7 +1005,7 @@ export async function generateTextGenWithStreaming(generate_data, signal) {
1004 logprobs = parseTextgenLogprobs(newText, data.choices?.[0]?.logprobs || data?.completion_probabilities);1005 logprobs = parseTextgenLogprobs(newText, data.choices?.[0]?.logprobs || data?.completion_probabilities);
1005 }1006 }
10061007
1007 yield { text, swipes, logprobs, toolCalls };1008 yield { text, swipes, logprobs, toolCalls, state };
1008 }1009 }
1009 };1010 };
1010}1011}
public/style.css+25 -3
@@ -332,6 +332,23 @@ input[type='checkbox']:focus-visible {
332 color: var(--SmartThemeQuoteColor);332 color: var(--SmartThemeQuoteColor);
333}333}
334334
335.mes_reasoning {
336 display: block;
337 border: 1px solid var(--SmartThemeBorderColor);
338 background-color: var(--black30a);
339 border-radius: 5px;
340 padding: 5px;
341 margin: 5px 0;
342 overflow-y: auto;
343 max-height: 100px;
344}
345
346.mes_block:has(.edit_textarea) .mes_reasoning,
347.mes_bias:empty,
348.mes_reasoning:empty {
349 display: none;
350}
351
335.mes_text i,352.mes_text i,
336.mes_text em {353.mes_text em {
337 color: var(--SmartThemeEmColor);354 color: var(--SmartThemeEmColor);
@@ -1022,6 +1039,7 @@ body .panelControlBar {
1022 /*only affects bubblechat to make it sit nicely at the bottom*/1039 /*only affects bubblechat to make it sit nicely at the bottom*/
1023}1040}
10241041
1042.last_mes .mes_reasoning,
1025.last_mes .mes_text {1043.last_mes .mes_text {
1026 padding-right: 30px;1044 padding-right: 30px;
1027}1045}
@@ -1235,14 +1253,18 @@ body.swipeAllMessages .mes:not(.last_mes) .swipes-counter {
1235 overflow-y: clip;1253 overflow-y: clip;
1236}1254}
12371255
1238.mes_text {1256.mes_text,
1257.mes_reasoning {
1239 font-weight: 500;1258 font-weight: 500;
1240 line-height: calc(var(--mainFontSize) + .5rem);1259 line-height: calc(var(--mainFontSize) + .5rem);
1260 max-width: 100%;
1261 overflow-wrap: anywhere;
1262}
1263
1264.mes_text {
1241 padding-left: 0;1265 padding-left: 0;
1242 padding-top: 5px;1266 padding-top: 5px;
1243 padding-bottom: 5px;1267 padding-bottom: 5px;
1244 max-width: 100%;
1245 overflow-wrap: anywhere;
1246}1268}
12471269
1248br {1270br {
src/constants.js+5 -0
@@ -413,3 +413,8 @@ export const VLLM_KEYS = [
413 'guided_decoding_backend',413 'guided_decoding_backend',
414 'guided_whitespace_pattern',414 'guided_whitespace_pattern',
415];415];
416
417/**
418 * Custom boundary for splitting the text between the model's reasoning and the actual response.
419 */
420export const THINK_BREAK = '##�THINK_BREAK�##';
src/endpoints/backends/chat-completions.js+2 -1
@@ -7,6 +7,7 @@ import {
7 CHAT_COMPLETION_SOURCES,7 CHAT_COMPLETION_SOURCES,
8 GEMINI_SAFETY,8 GEMINI_SAFETY,
9 OPENROUTER_HEADERS,9 OPENROUTER_HEADERS,
10 THINK_BREAK,
10} from '../../constants.js';11} from '../../constants.js';
11import {12import {
12 forwardFetchResponse,13 forwardFetchResponse,
@@ -389,7 +390,7 @@ async function sendMakerSuiteRequest(request, response) {
389 responseContent.parts = responseContent.parts.filter(part => !part.thought);390 responseContent.parts = responseContent.parts.filter(part => !part.thought);
390 }391 }
391392
392 const responseText = typeof responseContent === 'string' ? responseContent : responseContent?.parts?.map(part => part.text)?.join('\n\n');393 const responseText = typeof responseContent === 'string' ? responseContent : responseContent?.parts?.map(part => part.text)?.join(THINK_BREAK);
393 if (!responseText) {394 if (!responseText) {
394 let message = 'Google AI Studio Candidate text empty';395 let message = 'Google AI Studio Candidate text empty';
395 console.log(message, generateResponseJson);396 console.log(message, generateResponseJson);