mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-02-18 21:20:39 +01:00
Merge pull request #3413 from SillyTavern/thinking-is-stylish
Thinking is stylish - if you are not cool, I don't know how to help you
This commit is contained in:
commit
5494e89fdb
@ -3789,6 +3789,12 @@
|
||||
Auto-Parse Reasoning
|
||||
</small>
|
||||
</label>
|
||||
<label class="checkbox_label" for="reasoning_auto_expand" title="Automatically expand reasoning blocks." data-i18n="[title]reasoning_auto_expand">
|
||||
<input id="reasoning_auto_expand" type="checkbox" />
|
||||
<small data-i18n="Auto-Expand Reasoning">
|
||||
Auto-Expand Reasoning
|
||||
</small>
|
||||
</label>
|
||||
<label class="checkbox_label" for="reasoning_add_to_prompts" title="Add existing reasoning blocks to prompts. To add a new reasoning block, use the message edit menu." data-i18n="[title]reasoning_add_to_prompts">
|
||||
<input id="reasoning_add_to_prompts" type="checkbox" />
|
||||
<small data-i18n="Add Reasoning to Prompts">
|
||||
@ -6248,14 +6254,19 @@
|
||||
</div>
|
||||
</div>
|
||||
<details class="mes_reasoning_details">
|
||||
<summary class="mes_reasoning_summary">
|
||||
<span data-i18n="Reasoning">Reasoning</span>
|
||||
<div class="mes_reasoning_actions">
|
||||
<div class="mes_reasoning_edit_done mes_button fa-solid fa-check" title="Confirm" data-i18n="[title]Confirmedit"></div>
|
||||
<div class="mes_reasoning_edit_cancel mes_button fa-solid fa-xmark" title="Cancel edit" data-i18n="[title]Cancel edit"></div>
|
||||
<div class="mes_reasoning_edit mes_button fa-solid fa-pencil" title="Edit reasoning" data-i18n="[title]Edit reasoning"></div>
|
||||
<summary class="mes_reasoning_summary flex-container">
|
||||
<div class="mes_reasoning_header_block flex-container">
|
||||
<div class="mes_reasoning_header flex-container">
|
||||
<span class="mes_reasoning_header_title" data-i18n="Thought for some time">Thought for some time</span>
|
||||
<div class="mes_reasoning_arrow fa-solid fa-chevron-up"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mes_reasoning_actions flex-container">
|
||||
<div class="mes_reasoning_edit_done menu_button edit_button fa-solid fa-check" title="Confirm" data-i18n="[title]Confirmedit"></div>
|
||||
<div class="mes_reasoning_delete menu_button edit_button fa-solid fa-trash-can" title="Remove reasoning" data-i18n="[title]Remove reasoning"></div>
|
||||
<div class="mes_reasoning_edit_cancel menu_button edit_button fa-solid fa-xmark" title="Cancel edit" data-i18n="[title]Cancel edit"></div>
|
||||
<div class="mes_reasoning_copy mes_button fa-solid fa-copy" title="Copy reasoning" data-i18n="[title]Copy reasoning"></div>
|
||||
<div class="mes_reasoning_delete mes_button fa-solid fa-trash-can" title="Remove reasoning" data-i18n="[title]Remove reasoning"></div>
|
||||
<div class="mes_reasoning_edit mes_button fa-solid fa-pencil" title="Edit reasoning" data-i18n="[title]Edit reasoning"></div>
|
||||
</div>
|
||||
</summary>
|
||||
<div class="mes_reasoning"></div>
|
||||
|
169
public/script.js
169
public/script.js
@ -225,7 +225,7 @@ import {
|
||||
instruct_presets,
|
||||
selectContextPreset,
|
||||
} from './scripts/instruct-mode.js';
|
||||
import { initLocales, t } from './scripts/i18n.js';
|
||||
import { getCurrentLocale, initLocales, t } from './scripts/i18n.js';
|
||||
import { getFriendlyTokenizerName, getTokenCount, getTokenCountAsync, initTokenizers, saveTokenCache, TOKENIZER_SUPPORTED_KEY } from './scripts/tokenizers.js';
|
||||
import {
|
||||
user_avatar,
|
||||
@ -495,6 +495,7 @@ export const event_types = {
|
||||
/** @deprecated The event is aliased to STREAM_TOKEN_RECEIVED. */
|
||||
SMOOTH_STREAM_TOKEN_RECEIVED: 'stream_token_received',
|
||||
STREAM_TOKEN_RECEIVED: 'stream_token_received',
|
||||
STREAM_REASONING_DONE: 'stream_reasoning_done',
|
||||
FILE_ATTACHMENT_DELETED: 'file_attachment_deleted',
|
||||
WORLDINFO_FORCE_ACTIVATE: 'worldinfo_force_activate',
|
||||
OPEN_CHARACTER_LIBRARY: 'open_character_library',
|
||||
@ -2189,26 +2190,29 @@ function insertSVGIcon(mes, extra) {
|
||||
modelName = extra.api;
|
||||
}
|
||||
|
||||
const image = new Image();
|
||||
// Add classes for styling and identification
|
||||
image.classList.add('icon-svg', 'timestamp-icon');
|
||||
image.src = `/img/${modelName}.svg`;
|
||||
image.title = `${extra?.api ? extra.api + ' - ' : ''}${extra?.model ?? ''}`;
|
||||
|
||||
image.onload = async function () {
|
||||
// Check if an SVG already exists adjacent to the timestamp
|
||||
let existingSVG = mes.find('.timestamp').next('.timestamp-icon');
|
||||
|
||||
if (existingSVG.length) {
|
||||
// Replace existing SVG
|
||||
existingSVG.replaceWith(image);
|
||||
} else {
|
||||
// Append the new SVG if none exists
|
||||
mes.find('.timestamp').after(image);
|
||||
}
|
||||
|
||||
await SVGInject(image);
|
||||
const insertOrReplaceSVG = (image, className, targetSelector, insertBefore) => {
|
||||
image.onload = async function () {
|
||||
let existingSVG = insertBefore ? mes.find(targetSelector).prev(`.${className}`) : mes.find(targetSelector).next(`.${className}`);
|
||||
if (existingSVG.length) {
|
||||
existingSVG.replaceWith(image);
|
||||
} else {
|
||||
if (insertBefore) mes.find(targetSelector).before(image);
|
||||
else mes.find(targetSelector).after(image);
|
||||
}
|
||||
await SVGInject(image);
|
||||
};
|
||||
};
|
||||
|
||||
const createModelImage = (className, targetSelector, insertBefore) => {
|
||||
const image = new Image();
|
||||
image.classList.add('icon-svg', className);
|
||||
image.src = `/img/${modelName}.svg`;
|
||||
image.title = `${extra?.api ? extra.api + ' - ' : ''}${extra?.model ?? ''}`;
|
||||
insertOrReplaceSVG(image, className, targetSelector, insertBefore);
|
||||
};
|
||||
|
||||
createModelImage('timestamp-icon', '.timestamp');
|
||||
createModelImage('thinking-icon', '.mes_reasoning_header_title', true);
|
||||
}
|
||||
|
||||
|
||||
@ -2220,6 +2224,7 @@ function getMessageFromTemplate({
|
||||
avatarImg,
|
||||
bias,
|
||||
reasoning,
|
||||
reasoningDuration,
|
||||
isSystem,
|
||||
title,
|
||||
timerValue,
|
||||
@ -2252,6 +2257,13 @@ function getMessageFromTemplate({
|
||||
timerValue && mes.find('.mes_timer').attr('title', timerTitle).text(timerValue);
|
||||
bookmarkLink && updateBookmarkDisplay(mes);
|
||||
|
||||
if (reasoning) {
|
||||
mes.addClass('reasoning');
|
||||
}
|
||||
if (reasoningDuration) {
|
||||
updateReasoningTimeUI(mes.find('.mes_reasoning_header_title')[0], reasoningDuration, { forceEnd: true });
|
||||
}
|
||||
|
||||
if (power_user.timestamp_model_icon && extra?.api) {
|
||||
insertSVGIcon(mes, extra);
|
||||
}
|
||||
@ -2269,6 +2281,7 @@ export function updateMessageBlock(messageId, message) {
|
||||
const text = message?.extra?.display_text ?? message.mes;
|
||||
messageElement.find('.mes_text').html(messageFormatting(text, message.name, message.is_system, message.is_user, messageId, {}, false));
|
||||
messageElement.find('.mes_reasoning').html(messageFormatting(message.extra?.reasoning ?? '', '', false, false, messageId, {}, true));
|
||||
messageElement.toggleClass('reasoning', !!message.extra?.reasoning);
|
||||
addCopyToCodeBlocks(messageElement);
|
||||
appendMediaToMessage(message, messageElement);
|
||||
}
|
||||
@ -2439,6 +2452,7 @@ export function addOneMessage(mes, { type = 'normal', insertAfter = null, scroll
|
||||
avatarImg: avatarImg,
|
||||
bias: bias,
|
||||
reasoning: reasoning,
|
||||
reasoningDuration: mes.extra?.reasoning_duration,
|
||||
isSystem: isSystem,
|
||||
title: title,
|
||||
bookmarkLink: bookmarkLink,
|
||||
@ -3108,8 +3122,12 @@ class StreamingProcessor {
|
||||
this.messageDom = null;
|
||||
this.messageTextDom = null;
|
||||
this.messageTimerDom = null;
|
||||
/** @type {HTMLElement} */
|
||||
this.messageTokenCounterDom = null;
|
||||
/** @type {HTMLElement} */
|
||||
this.messageReasoningDom = null;
|
||||
/** @type {HTMLElement} */
|
||||
this.messageReasoningHeaderDom = null;
|
||||
/** @type {HTMLTextAreaElement} */
|
||||
this.sendTextarea = document.querySelector('#send_textarea');
|
||||
this.type = type;
|
||||
@ -3126,6 +3144,15 @@ class StreamingProcessor {
|
||||
this.messageLogprobs = [];
|
||||
this.toolCalls = [];
|
||||
this.reasoning = '';
|
||||
this.reasoningStartTime = null;
|
||||
this.reasoningEndTime = null;
|
||||
}
|
||||
|
||||
#reasoningDuration() {
|
||||
if (this.reasoningStartTime && this.reasoningEndTime) {
|
||||
return (this.reasoningEndTime - this.reasoningStartTime);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
#checkDomElements(messageId) {
|
||||
@ -3135,6 +3162,7 @@ class StreamingProcessor {
|
||||
this.messageTimerDom = this.messageDom?.querySelector('.mes_timer');
|
||||
this.messageTokenCounterDom = this.messageDom?.querySelector('.tokenCounterDisplay');
|
||||
this.messageReasoningDom = this.messageDom?.querySelector('.mes_reasoning');
|
||||
this.messageReasoningHeaderDom = this.messageDom?.querySelector('.mes_reasoning_header_title');
|
||||
}
|
||||
}
|
||||
|
||||
@ -3182,7 +3210,7 @@ class StreamingProcessor {
|
||||
return messageId;
|
||||
}
|
||||
|
||||
onProgressStreaming(messageId, text, isFinal) {
|
||||
async onProgressStreaming(messageId, text, isFinal) {
|
||||
const isImpersonate = this.type == 'impersonate';
|
||||
const isContinue = this.type == 'continue';
|
||||
|
||||
@ -3209,6 +3237,8 @@ class StreamingProcessor {
|
||||
this.sendTextarea.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
}
|
||||
else {
|
||||
const mesChanged = chat[messageId]['mes'] !== processedText;
|
||||
|
||||
this.#checkDomElements(messageId);
|
||||
this.#updateMessageBlockVisibility();
|
||||
const currentTime = new Date();
|
||||
@ -3221,11 +3251,25 @@ class StreamingProcessor {
|
||||
}
|
||||
|
||||
if (this.reasoning) {
|
||||
chat[messageId]['extra']['reasoning'] = power_user.trim_spaces ? this.reasoning.trim() : this.reasoning;
|
||||
const reasoning = power_user.trim_spaces ? this.reasoning.trim() : this.reasoning;
|
||||
const reasoningChanged = chat[messageId]['extra']['reasoning'] !== reasoning;
|
||||
chat[messageId]['extra']['reasoning'] = reasoning;
|
||||
|
||||
if (reasoningChanged && this.reasoningStartTime === null) {
|
||||
this.reasoningStartTime = Date.now();
|
||||
}
|
||||
if (!reasoningChanged && mesChanged && this.reasoningStartTime !== null && this.reasoningEndTime === null) {
|
||||
this.reasoningEndTime = Date.now();
|
||||
}
|
||||
await this.#updateReasoningTime(messageId);
|
||||
|
||||
if (this.messageReasoningDom instanceof HTMLElement) {
|
||||
const formattedReasoning = messageFormatting(this.reasoning, '', false, false, messageId, {}, true);
|
||||
this.messageReasoningDom.innerHTML = formattedReasoning;
|
||||
}
|
||||
if (this.messageDom instanceof HTMLElement) {
|
||||
this.messageDom.classList.add('reasoning');
|
||||
}
|
||||
}
|
||||
|
||||
// Don't waste time calculating token count for streaming
|
||||
@ -3271,11 +3315,24 @@ class StreamingProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
async #updateReasoningTime(messageId, { forceEnd = false } = {}) {
|
||||
const duration = this.#reasoningDuration();
|
||||
chat[messageId]['extra']['reasoning_duration'] = duration;
|
||||
updateReasoningTimeUI(this.messageReasoningHeaderDom, duration, { forceEnd: forceEnd });
|
||||
await eventSource.emit(event_types.STREAM_REASONING_DONE, this.reasoning, duration);
|
||||
}
|
||||
|
||||
async onFinishStreaming(messageId, text) {
|
||||
this.hideMessageButtons(this.messageId);
|
||||
this.onProgressStreaming(messageId, text, true);
|
||||
await this.onProgressStreaming(messageId, text, true);
|
||||
addCopyToCodeBlocks($(`#chat .mes[mesid="${messageId}"]`));
|
||||
|
||||
// Ensure reasoning finish time is recorded if not already
|
||||
if (this.reasoningStartTime !== null && this.reasoningEndTime === null) {
|
||||
this.reasoningEndTime = Date.now();
|
||||
await this.#updateReasoningTime(messageId, { forceEnd: true });
|
||||
}
|
||||
|
||||
if (Array.isArray(this.swipes) && this.swipes.length > 0) {
|
||||
const message = chat[messageId];
|
||||
const swipeInfo = {
|
||||
@ -3377,7 +3434,7 @@ class StreamingProcessor {
|
||||
}
|
||||
this.reasoning = getRegexedString(state?.reasoning ?? '', regex_placement.REASONING);
|
||||
await eventSource.emit(event_types.STREAM_TOKEN_RECEIVED, text);
|
||||
await sw.tick(() => this.onProgressStreaming(this.messageId, this.continueMessage + text));
|
||||
await sw.tick(async () => await this.onProgressStreaming(this.messageId, this.continueMessage + text));
|
||||
}
|
||||
const seconds = (timestamps[timestamps.length - 1] - timestamps[0]) / 1000;
|
||||
console.warn(`Stream stats: ${timestamps.length} tokens, ${seconds.toFixed(2)} seconds, rate: ${Number(timestamps.length / seconds).toFixed(2)} TPS`);
|
||||
@ -5737,6 +5794,25 @@ function extractReasoningFromData(data) {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the Reasoning controls
|
||||
* @param {HTMLElement} element The element to update
|
||||
* @param {number?} duration The duration of the reasoning in milliseconds
|
||||
* @param {object} [options={}] Options for the function
|
||||
* @param {boolean} [options.forceEnd=false] If true, there will be no "Thinking..." when no duration exists
|
||||
*/
|
||||
function updateReasoningTimeUI(element, duration, { forceEnd = false } = {}) {
|
||||
if (duration) {
|
||||
const durationStr = moment.duration(duration).locale(getCurrentLocale()).humanize({ s: 50, ss: 9 });
|
||||
element.textContent = t`Thought for ${durationStr}`;
|
||||
} else if (forceEnd) {
|
||||
element.textContent = t`Thought for some time`;
|
||||
} else {
|
||||
element.textContent = t`Thinking...`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extracts multiswipe swipes from the response data.
|
||||
* @param {Object} data Response data
|
||||
@ -7118,8 +7194,10 @@ export function setGenerationParamsFromPreset(preset) {
|
||||
// Common code for message editor done and auto-save
|
||||
function updateMessage(div) {
|
||||
const mesBlock = div.closest('.mes_block');
|
||||
let text = mesBlock.find('.edit_textarea').val();
|
||||
const mes = chat[this_edit_mes_id];
|
||||
let text = mesBlock.find('.edit_textarea').val()
|
||||
?? mesBlock.find('.mes_text').text();
|
||||
const mesElement = div.closest('.mes');
|
||||
const mes = chat[mesElement.attr('mesid')];
|
||||
|
||||
let regexPlacement;
|
||||
if (mes.is_user) {
|
||||
@ -7238,6 +7316,11 @@ async function messageEditDone(div) {
|
||||
appendMediaToMessage(mes, div.closest('.mes'));
|
||||
addCopyToCodeBlocks(div.closest('.mes'));
|
||||
|
||||
const reasoningEditDone = mesBlock.find('.mes_reasoning_edit_done:visible');
|
||||
if (reasoningEditDone.length > 0) {
|
||||
reasoningEditDone.trigger('click');
|
||||
}
|
||||
|
||||
await eventSource.emit(event_types.MESSAGE_UPDATED, this_edit_mes_id);
|
||||
this_edit_mes_id = undefined;
|
||||
await saveChatConditional();
|
||||
@ -10745,6 +10828,12 @@ jQuery(async function () {
|
||||
var edit_mes_id = $(this).closest('.mes').attr('mesid');
|
||||
this_edit_mes_id = edit_mes_id;
|
||||
|
||||
// Also edit reasoning, if it exists
|
||||
const reasoningEdit = $(this).closest('.mes_block').find('.mes_reasoning_edit:visible');
|
||||
if (reasoningEdit.length > 0) {
|
||||
reasoningEdit.trigger('click');
|
||||
}
|
||||
|
||||
var text = chat[edit_mes_id]['mes'];
|
||||
if (chat[edit_mes_id]['is_user']) {
|
||||
this_edit_mes_chname = name1;
|
||||
@ -10783,6 +10872,18 @@ jQuery(async function () {
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('click', '.mes_reasoning_header', function () {
|
||||
// If we are in message edit mode and reasoning area is closed, a click opens and edits it
|
||||
const mes = $(this).closest('.mes');
|
||||
const mesEditArea = mes.find('#curEditTextarea');
|
||||
if (mesEditArea.length) {
|
||||
const summary = $(mes).find('.mes_reasoning_summary');
|
||||
if (!summary.attr('open')) {
|
||||
summary.find('.mes_reasoning_edit').trigger('click');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('input', '#curEditTextarea', function () {
|
||||
if (power_user.auto_save_msg_edits === true) {
|
||||
messageEditAuto($(this));
|
||||
@ -10878,6 +10979,11 @@ jQuery(async function () {
|
||||
appendMediaToMessage(chat[this_edit_mes_id], $(this).closest('.mes'));
|
||||
addCopyToCodeBlocks($(this).closest('.mes'));
|
||||
|
||||
const reasoningEditDone = $(this).closest('.mes_block').find('.mes_reasoning_edit_cancel:visible');
|
||||
if (reasoningEditDone.length > 0) {
|
||||
reasoningEditDone.trigger('click');
|
||||
}
|
||||
|
||||
await eventSource.emit(event_types.MESSAGE_UPDATED, this_edit_mes_id);
|
||||
this_edit_mes_id = undefined;
|
||||
});
|
||||
@ -11332,6 +11438,17 @@ jQuery(async function () {
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('click', '.mes_reasoning_summary', function () {
|
||||
// If you toggle summary header while editing reasoning, yup - we just cancel it
|
||||
$(this).closest('.mes').find('.mes_reasoning_edit_cancel:visible').trigger('click');
|
||||
});
|
||||
|
||||
$(document).on('click', '.mes_reasoning_details', function (e) {
|
||||
if (!e.target.closest('.mes_reasoning_actions') && !e.target.closest('.mes_reasoning_header')) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
$(document).keyup(function (e) {
|
||||
if (e.key === 'Escape') {
|
||||
const isEditVisible = $('#curEditTextarea').is(':visible') || $('.reasoning_edit_textarea').length > 0;
|
||||
|
@ -1063,12 +1063,19 @@ export function initRossMods() {
|
||||
// Ctrl+Enter for Regeneration Last Response. If editing, accept the edits instead
|
||||
if (event.ctrlKey && event.key == 'Enter') {
|
||||
const editMesDone = $('.mes_edit_done:visible');
|
||||
const reasoningMesDone = $('.mes_reasoning_edit_done:visible');
|
||||
if (editMesDone.length > 0) {
|
||||
console.debug('Accepting edits with Ctrl+Enter');
|
||||
$('#send_textarea').focus();
|
||||
$('#send_textarea').trigger('focus');
|
||||
editMesDone.trigger('click');
|
||||
return;
|
||||
} else if (is_send_press == false) {
|
||||
} else if (reasoningMesDone.length > 0) {
|
||||
console.debug('Accepting edits with Ctrl+Enter');
|
||||
$('#send_textarea').trigger('focus');
|
||||
reasoningMesDone.trigger('click');
|
||||
return;
|
||||
}
|
||||
else if (is_send_press == false) {
|
||||
const skipConfirmKey = 'RegenerateWithCtrlEnter';
|
||||
const skipConfirm = LoadLocalBool(skipConfirmKey);
|
||||
function doRegenerate() {
|
||||
@ -1082,7 +1089,9 @@ export function initRossMods() {
|
||||
let regenerateWithCtrlEnter = false;
|
||||
const result = await Popup.show.confirm('Regenerate Message', 'Are you sure you want to regenerate the latest message?', {
|
||||
customInputs: [{ id: 'regenerateWithCtrlEnter', label: 'Don\'t ask again' }],
|
||||
onClose: (popup) => regenerateWithCtrlEnter = popup.inputResults.get('regenerateWithCtrlEnter') ?? false,
|
||||
onClose: (popup) => {
|
||||
regenerateWithCtrlEnter = popup.inputResults.get('regenerateWithCtrlEnter') ?? false;
|
||||
},
|
||||
});
|
||||
if (!result) {
|
||||
return;
|
||||
|
@ -256,6 +256,7 @@ let power_user = {
|
||||
reasoning: {
|
||||
auto_parse: false,
|
||||
add_to_prompts: false,
|
||||
auto_expand: false,
|
||||
prefix: '<think>\n',
|
||||
suffix: '\n</think>',
|
||||
separator: '\n\n',
|
||||
|
@ -22,6 +22,18 @@ function getMessageFromJquery(element) {
|
||||
return { messageId: messageId, message, messageBlock };
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the auto-expand state of reasoning blocks.
|
||||
*/
|
||||
function toggleReasoningAutoExpand() {
|
||||
const reasoningBlocks = document.querySelectorAll('details.mes_reasoning_details');
|
||||
reasoningBlocks.forEach((block) => {
|
||||
if (block instanceof HTMLDetailsElement) {
|
||||
block.open = power_user.reasoning.auto_expand;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class for adding reasoning to messages.
|
||||
* Keeps track of the number of reasoning additions.
|
||||
@ -118,6 +130,13 @@ function loadReasoningSettings() {
|
||||
power_user.reasoning.auto_parse = !!$(this).prop('checked');
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#reasoning_auto_expand').prop('checked', power_user.reasoning.auto_expand);
|
||||
$('#reasoning_auto_expand').on('change', function () {
|
||||
power_user.reasoning.auto_expand = !!$(this).prop('checked');
|
||||
toggleReasoningAutoExpand();
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
}
|
||||
|
||||
function registerReasoningSlashCommands() {
|
||||
@ -288,6 +307,8 @@ function setReasoningEventHandlers() {
|
||||
await saveChatConditional();
|
||||
updateMessageBlock(messageId, message);
|
||||
textarea.remove();
|
||||
|
||||
messageBlock.find('.mes_edit_done:visible').trigger('click');
|
||||
});
|
||||
|
||||
$(document).on('click', '.mes_reasoning_edit_cancel', function (e) {
|
||||
@ -297,6 +318,8 @@ function setReasoningEventHandlers() {
|
||||
const { messageBlock } = getMessageFromJquery(this);
|
||||
const textarea = messageBlock.find('.reasoning_edit_textarea');
|
||||
textarea.remove();
|
||||
|
||||
messageBlock.find('.mes_reasoning_edit_cancel:visible').trigger('click');
|
||||
});
|
||||
|
||||
$(document).on('click', '.mes_edit_add_reasoning', async function () {
|
||||
@ -311,9 +334,8 @@ function setReasoningEventHandlers() {
|
||||
}
|
||||
|
||||
message.extra.reasoning = PromptReasoning.REASONING_PLACEHOLDER;
|
||||
await saveChatConditional();
|
||||
closeMessageEditor();
|
||||
updateMessageBlock(messageId, message);
|
||||
await saveChatConditional();
|
||||
});
|
||||
|
||||
$(document).on('click', '.mes_reasoning_delete', async function (e) {
|
||||
@ -441,6 +463,7 @@ function registerReasoningAppEvents() {
|
||||
|
||||
export function initReasoning() {
|
||||
loadReasoningSettings();
|
||||
toggleReasoningAutoExpand();
|
||||
setReasoningEventHandlers();
|
||||
registerReasoningSlashCommands();
|
||||
registerReasoningMacros();
|
||||
|
112
public/style.css
112
public/style.css
@ -106,6 +106,8 @@
|
||||
--tool-cool-color-picker-btn-bg: transparent;
|
||||
--tool-cool-color-picker-btn-border-color: transparent;
|
||||
|
||||
--mes-right-spacing: 30px;
|
||||
|
||||
--avatar-base-height: 50px;
|
||||
--avatar-base-width: 50px;
|
||||
--avatar-base-border-radius: 2px;
|
||||
@ -342,18 +344,59 @@ input[type='checkbox']:focus-visible {
|
||||
|
||||
.mes_reasoning {
|
||||
display: block;
|
||||
border: 1px solid var(--SmartThemeBorderColor);
|
||||
background-color: var(--black30a);
|
||||
border-radius: 5px;
|
||||
border-left: 2px solid var(--SmartThemeEmColor);
|
||||
border-radius: 2px;
|
||||
padding: 5px;
|
||||
margin: 5px 0;
|
||||
padding-left: 14px;
|
||||
margin-bottom: 0.5em;
|
||||
overflow-y: auto;
|
||||
color: var(--SmartThemeEmColor);
|
||||
}
|
||||
|
||||
.mes_reasoning_summary {
|
||||
.mes_reasoning_details {
|
||||
margin-right: var(--mes-right-spacing);
|
||||
}
|
||||
|
||||
.mes_reasoning_details .mes_reasoning_summary {
|
||||
margin-right: calc(var(--mes-right-spacing) * -1);
|
||||
}
|
||||
|
||||
.mes_reasoning *:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.mes_reasoning em,
|
||||
.mes_reasoning i,
|
||||
.mes_reasoning u,
|
||||
.mes_reasoning q,
|
||||
.mes_reasoning blockquote {
|
||||
filter: saturate(0.5);
|
||||
}
|
||||
|
||||
.mes_reasoning_details .mes_reasoning em {
|
||||
color: color-mix(in srgb, var(--SmartThemeEmColor) 67%, var(--SmartThemeBlurTintColor) 33%)
|
||||
}
|
||||
|
||||
.mes_reasoning_header_block {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.mes_reasoning_header {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
margin: 2px;
|
||||
user-select: none;
|
||||
margin: 0.5em 2px;
|
||||
padding: 7px 14px;
|
||||
padding-right: calc(0.7em + 14px);
|
||||
border-radius: 10px;
|
||||
background-color: var(--grey30);
|
||||
font-size: calc(var(--mainFontSize) * 0.9);
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
/* TWIMC: Remove with custom CSS to show the icon */
|
||||
.mes_reasoning_header > .icon-svg {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@supports not selector(:has(*)) {
|
||||
@ -365,27 +408,27 @@ input[type='checkbox']:focus-visible {
|
||||
.mes_bias:empty,
|
||||
.mes_reasoning:empty,
|
||||
.mes_reasoning_details:has(.mes_reasoning:empty),
|
||||
.mes_block:has(.edit_textarea) .mes_reasoning_details,
|
||||
.mes_reasoning_details:not([open]) .mes_reasoning_actions,
|
||||
.mes_reasoning_details:has(.reasoning_edit_textarea) .mes_reasoning,
|
||||
.mes_reasoning_details:not(:has(.reasoning_edit_textarea)) .mes_reasoning_actions .mes_button.mes_reasoning_edit_done,
|
||||
.mes_reasoning_details:not(:has(.reasoning_edit_textarea)) .mes_reasoning_actions .mes_button.mes_reasoning_edit_cancel,
|
||||
.mes_reasoning_details:has(.reasoning_edit_textarea) .mes_reasoning_actions .mes_button:not(.mes_reasoning_edit_done, .mes_reasoning_edit_cancel) {
|
||||
.mes_reasoning_details:has(.reasoning_edit_textarea) .mes_reasoning_header,
|
||||
.mes_reasoning_details:not(:has(.reasoning_edit_textarea)) .mes_reasoning_actions .edit_button,
|
||||
.mes_reasoning_details:has(.reasoning_edit_textarea) .mes_reasoning_actions .mes_button:not(.edit_button),
|
||||
.mes_block:has(.edit_textarea):has(.reasoning_edit_textarea) .mes_reasoning_actions {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mes_reasoning_actions {
|
||||
.mes_reasoning_details .mes_reasoning_arrow {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
top: 50%;
|
||||
right: 7px;
|
||||
transform: translateY(-50%);
|
||||
font-size: calc(var(--mainFontSize) * 0.7);
|
||||
width: calc(var(--mainFontSize) * 0.7);
|
||||
height: calc(var(--mainFontSize) * 0.7);
|
||||
}
|
||||
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-end;
|
||||
transition: all 200ms;
|
||||
overflow-x: hidden;
|
||||
padding: 1px;
|
||||
.mes_reasoning_details:not([open]) .mes_reasoning_arrow {
|
||||
transform: translateY(-50%) rotate(180deg);
|
||||
}
|
||||
|
||||
.mes_reasoning_summary>span {
|
||||
@ -1100,13 +1143,8 @@ body .panelControlBar {
|
||||
/*only affects bubblechat to make it sit nicely at the bottom*/
|
||||
}
|
||||
|
||||
.last_mes:has(.mes_text:empty):has(.mes_reasoning_details[open]) .mes_reasoning:not(:empty) {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.last_mes .mes_reasoning,
|
||||
.last_mes .mes_text {
|
||||
padding-right: 30px;
|
||||
.last_mes:has(.mes_text:empty):has(.mes_reasoning_details) .mes_reasoning:not(:empty) {
|
||||
margin-bottom: var(--mes-right-spacing);
|
||||
}
|
||||
|
||||
/* SWIPE RELATED STYLES*/
|
||||
@ -1330,6 +1368,7 @@ body.swipeAllMessages .mes:not(.last_mes) .swipes-counter {
|
||||
padding-left: 0;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
padding-right: var(--mes-right-spacing);
|
||||
}
|
||||
|
||||
br {
|
||||
@ -3000,6 +3039,7 @@ input[type=search]:focus::-webkit-search-cancel-button {
|
||||
.mes_block .ch_name {
|
||||
max-width: 100%;
|
||||
min-height: 22px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
/*applies to both groups and solos chars in the char list*/
|
||||
@ -4224,7 +4264,13 @@ input[type="range"]::-webkit-slider-thumb {
|
||||
transition: 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.mes_edit_buttons .menu_button {
|
||||
.mes_reasoning_actions {
|
||||
margin: 0;
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
.mes_edit_buttons .menu_button,
|
||||
.mes_reasoning_actions .edit_button {
|
||||
opacity: 0.5;
|
||||
padding: 0px;
|
||||
font-size: 1rem;
|
||||
@ -4237,6 +4283,12 @@ input[type="range"]::-webkit-slider-thumb {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.mes_reasoning_actions .edit_button {
|
||||
margin-bottom: 0.5em;
|
||||
opacity: 1;
|
||||
filter: brightness(0.7);
|
||||
}
|
||||
|
||||
.mes_reasoning_edit_cancel,
|
||||
.mes_edit_cancel.menu_button {
|
||||
background-color: var(--crimson70a);
|
||||
@ -4263,6 +4315,10 @@ input[type="range"]::-webkit-slider-thumb {
|
||||
field-sizing: content;
|
||||
}
|
||||
|
||||
.mes.reasoning .mes_edit_add_reasoning {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#anchor_order {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user