} translated or not
+ */
+async function translateIncomingMessageReasoning(messageId) {
+ const context = getContext();
+ const message = context.chat[messageId];
+
+ if (!message) {
+ return false;
+ }
+
+ if (typeof message.extra !== 'object') {
+ message.extra = {};
+ }
+
+ if (!message.extra.reasoning || isGeneratingSwipe(messageId)) {
+ return false;
+ }
+
+ const textToTranslate = substituteParams(message.extra.reasoning, context.name1, message.name);
+ const translation = await translate(textToTranslate, extension_settings.translate.target_language);
+ message.extra.reasoning_display_text = translation;
+
+ updateReasoningUI(Number(messageId));
+ return true;
}
async function translateProviderOneRing(text, lang) {
@@ -535,6 +582,7 @@ async function onTranslateChatClick() {
toastr.info(`${chat.length} message(s) queued for translation.`, 'Please wait...');
for (let i = 0; i < chat.length; i++) {
+ await translateIncomingMessageReasoning(i);
await translateIncomingMessage(i);
}
@@ -561,6 +609,7 @@ async function onTranslationsClearClick() {
for (const mes of chat) {
if (mes.extra) {
delete mes.extra.display_text;
+ delete mes.extra.reasoning_display_text;
}
}
@@ -573,12 +622,47 @@ async function translateMessageEdit(messageId) {
const chat = context.chat;
const message = chat[messageId];
- if (message.is_system || extension_settings.translate.auto_mode == autoModeOptions.NONE) {
- return;
+ let anyChange = false;
+ if (message.is_system || (extension_settings.translate.auto_mode == autoModeOptions.NONE && message.extra?.display_text)) {
+ delete message.extra.display_text;
+ updateMessageBlock(messageId, message);
+ anyChange = true;
+ } else if ((message.is_user && shouldTranslate(outgoingTypes)) || (!message.is_user && shouldTranslate(incomingTypes))) {
+ await translateIncomingMessage(messageId);
+ anyChange = true;
}
- if ((message.is_user && shouldTranslate(outgoingTypes)) || (!message.is_user && shouldTranslate(incomingTypes))) {
- await translateIncomingMessage(messageId);
+ if (anyChange) {
+ await context.saveChat();
+ }
+}
+
+async function translateMessageReasoningEdit(messageId) {
+ const context = getContext();
+ const chat = context.chat;
+ const message = chat[messageId];
+
+ let anyChange = false;
+ if (message.is_system || (extension_settings.translate.auto_mode == autoModeOptions.NONE && message.extra?.reasoning_display_text)) {
+ delete message.extra.reasoning_display_text;
+ updateReasoningUI(Number(messageId));
+ anyChange = true;
+ } else if ((message.is_user && shouldTranslate(outgoingTypes)) || (!message.is_user && shouldTranslate(incomingTypes))) {
+ anyChange = await translateIncomingMessageReasoning(messageId);
+ }
+
+ if (anyChange) {
+ await context.saveChat();
+ }
+}
+
+async function removeReasoningDisplayText(messageId) {
+ const context = getContext();
+ const message = context.chat[messageId];
+ if (message.extra?.reasoning_display_text) {
+ delete message.extra.reasoning_display_text;
+ updateReasoningUI(Number(messageId));
+ await context.saveChat();
}
}
@@ -588,22 +672,36 @@ async function onMessageTranslateClick() {
const message = context.chat[messageId];
// If the message is already translated, revert it back to the original text
+ let alreadyTranslated = false;
if (message?.extra?.display_text) {
delete message.extra.display_text;
- updateMessageBlock(messageId, message);
+ updateMessageBlock(Number(messageId), message);
+ alreadyTranslated = true;
}
+ if (message?.extra?.reasoning_display_text) {
+ delete message.extra.reasoning_display_text;
+ updateReasoningUI(Number(messageId));
+ alreadyTranslated = true;
+ }
+
// If the message is not translated, translate it
- else {
+ if (!alreadyTranslated) {
+ await translateIncomingMessageReasoning(messageId);
await translateIncomingMessage(messageId);
}
await context.saveChat();
}
-const handleIncomingMessage = createEventHandler(translateIncomingMessage, () => shouldTranslate(incomingTypes));
+const handleIncomingMessage = createEventHandler(async (messageId) => {
+ await translateIncomingMessageReasoning(messageId);
+ await translateIncomingMessage(messageId);
+}, () => shouldTranslate(incomingTypes));
const handleOutgoingMessage = createEventHandler(translateOutgoingMessage, () => shouldTranslate(outgoingTypes));
const handleImpersonateReady = createEventHandler(translateImpersonate, () => shouldTranslate(incomingTypes));
const handleMessageEdit = createEventHandler(translateMessageEdit, () => true);
+const handleMessageReasoningEdit = createEventHandler(translateMessageReasoningEdit, () => true);
+const handleMessageReasoningDelete = createEventHandler(removeReasoningDisplayText, () => true);
globalThis.translate = translate;
@@ -717,6 +815,8 @@ jQuery(async () => {
eventSource.on(event_types.MESSAGE_SWIPED, handleIncomingMessage);
eventSource.on(event_types.IMPERSONATE_READY, handleImpersonateReady);
eventSource.on(event_types.MESSAGE_UPDATED, handleMessageEdit);
+ eventSource.on(event_types.MESSAGE_REASONING_EDITED, handleMessageReasoningEdit);
+ eventSource.on(event_types.MESSAGE_REASONING_DELETED, handleMessageReasoningDelete);
document.body.classList.add('translate');
diff --git a/public/scripts/reasoning.js b/public/scripts/reasoning.js
index 5e846e4d8..139380e64 100644
--- a/public/scripts/reasoning.js
+++ b/public/scripts/reasoning.js
@@ -167,6 +167,8 @@ export class ReasoningHandler {
this.type = null;
/** @type {string} The reasoning output */
this.reasoning = '';
+ /** @type {string?} The reasoning output display in case of translate or other */
+ this.reasoningDisplayText = null;
/** @type {Date} When the reasoning started */
this.startTime = null;
/** @type {Date} When the reasoning ended */
@@ -234,6 +236,7 @@ export class ReasoningHandler {
this.type = extra?.reasoning_type;
this.reasoning = extra?.reasoning ?? '';
+ this.reasoningDisplayText = extra?.reasoning_display_text ?? null;
if (this.state !== ReasoningState.None) {
this.initialTime = new Date(chat[messageId].gen_started);
@@ -249,6 +252,7 @@ export class ReasoningHandler {
this.state = this.#isHiddenReasoningModel ? ReasoningState.Thinking : ReasoningState.None;
this.type = null;
this.reasoning = '';
+ this.reasoningDisplayText = null;
this.initialTime = new Date();
this.startTime = null;
this.endTime = null;
@@ -434,7 +438,7 @@ export class ReasoningHandler {
setDatasetProperty(this.messageReasoningDetailsDom, 'type', this.type);
// Update the reasoning message
- const reasoning = trimSpaces(this.reasoning);
+ const reasoning = trimSpaces(this.reasoningDisplayText ?? this.reasoning);
const displayReasoning = messageFormatting(reasoning, '', false, false, messageId, {}, true);
this.messageReasoningContentDom.innerHTML = displayReasoning;
@@ -888,12 +892,17 @@ function setReasoningEventHandlers() {
}
const textarea = messageBlock.find('.reasoning_edit_textarea');
- updateReasoningFromValue(message, String(textarea.val()));
+ const newReasoning = String(textarea.val());
+ textarea.remove();
+ if (newReasoning === message.extra.reasoning) {
+ return;
+ }
+ updateReasoningFromValue(message, newReasoning);
await saveChatConditional();
updateMessageBlock(messageId, message);
- textarea.remove();
messageBlock.find('.mes_edit_done:visible').trigger('click');
+ await eventSource.emit(event_types.MESSAGE_REASONING_EDITED, messageId);
});
$(document).on('click', '.mes_reasoning_edit_cancel', function (e) {
@@ -955,6 +964,7 @@ function setReasoningEventHandlers() {
updateMessageBlock(messageId, message);
const textarea = messageBlock.find('.reasoning_edit_textarea');
textarea.remove();
+ await eventSource.emit(event_types.MESSAGE_REASONING_DELETED, messageId);
});
$(document).on('pointerup', '.mes_reasoning_copy', async function () {
diff --git a/public/scripts/st-context.js b/public/scripts/st-context.js
index cfe55d379..27eaf77af 100644
--- a/public/scripts/st-context.js
+++ b/public/scripts/st-context.js
@@ -79,6 +79,7 @@ import { timestampToMoment, uuidv4 } from './utils.js';
import { getGlobalVariable, getLocalVariable, setGlobalVariable, setLocalVariable } from './variables.js';
import { convertCharacterBook, loadWorldInfo, saveWorldInfo, updateWorldInfoList } from './world-info.js';
import { ChatCompletionService, TextCompletionService } from './custom-request.js';
+import { updateReasoningUI } from './reasoning.js';
export function getContext() {
return {
@@ -211,6 +212,7 @@ export function getContext() {
clearChat,
ChatCompletionService,
TextCompletionService,
+ updateReasoningUI,
unshallowCharacter,
unshallowGroupMembers,
};
From e9cf606c70e2cba2aade710acfdfc6b6ca28bb3b Mon Sep 17 00:00:00 2001
From: Cohee <18619528+Cohee1207@users.noreply.github.com>
Date: Thu, 6 Mar 2025 22:23:35 +0200
Subject: [PATCH 14/16] Add backend-provided websearch connectors for
OpenRouter and Gemini
---
public/index.html | 11 ++++++++
public/scripts/openai.js | 12 +++++++++
src/endpoints/backends/chat-completions.js | 29 ++++++++++++++++++++++
3 files changed, 52 insertions(+)
diff --git a/public/index.html b/public/index.html
index aab2a0c11..6724c399f 100644
--- a/public/index.html
+++ b/public/index.html
@@ -1951,6 +1951,17 @@
+
+
+
+
+ Use search capabilities provided by the backend.
+
+
+
-
+