Move reasoning stuff to reasoning.js
| @@ -225,7 +225,7 @@ import { | |||
| 225 | instruct_presets, | 225 | instruct_presets, |
| 226 | selectContextPreset, | 226 | selectContextPreset, |
| 227 | } from './scripts/instruct-mode.js'; | 227 | } from './scripts/instruct-mode.js'; |
| 228 | import { getCurrentLocale, initLocales, t } from './scripts/i18n.js'; | 228 | import { initLocales, t } from './scripts/i18n.js'; |
| 229 | import { getFriendlyTokenizerName, getTokenCount, getTokenCountAsync, initTokenizers, saveTokenCache, TOKENIZER_SUPPORTED_KEY } from './scripts/tokenizers.js'; | 229 | import { getFriendlyTokenizerName, getTokenCount, getTokenCountAsync, initTokenizers, saveTokenCache, TOKENIZER_SUPPORTED_KEY } from './scripts/tokenizers.js'; |
| 230 | import { | 230 | import { |
| 231 | user_avatar, | 231 | user_avatar, |
| @@ -269,7 +269,7 @@ import { initSettingsSearch } from './scripts/setting-search.js'; | |||
| 269 | import { initBulkEdit } from './scripts/bulk-edit.js'; | 269 | import { initBulkEdit } from './scripts/bulk-edit.js'; |
| 270 | import { deriveTemplatesFromChatTemplate } from './scripts/chat-templates.js'; | 270 | import { deriveTemplatesFromChatTemplate } from './scripts/chat-templates.js'; |
| 271 | import { getContext } from './scripts/st-context.js'; | 271 | import { getContext } from './scripts/st-context.js'; |
| 272 | import { initReasoning, PromptReasoning } from './scripts/reasoning.js'; | 272 | import { extractReasoningFromData, initReasoning, PromptReasoning, updateReasoningTimeUI } from './scripts/reasoning.js'; |
| 273 | 273 | ||
| 274 | // API OBJECT FOR EXTERNAL WIRING | 274 | // API OBJECT FOR EXTERNAL WIRING |
| 275 | globalThis.SillyTavern = { | 275 | globalThis.SillyTavern = { |
| @@ -5764,56 +5764,6 @@ function extractMessageFromData(data) { | |||
| 5764 | } | 5764 | } |
| 5765 | 5765 | ||
| 5766 | /** | 5766 | /** |
| 5767 | * Extracts the reasoning from the response data. | ||
| 5768 | * @param {object} data Response data | ||
| 5769 | * @returns {string} Extracted reasoning | ||
| 5770 | */ | ||
| 5771 | function extractReasoningFromData(data) { | ||
| 5772 | switch (main_api) { | ||
| 5773 | case 'textgenerationwebui': | ||
| 5774 | switch (textgen_settings.type) { | ||
| 5775 | case textgen_types.OPENROUTER: | ||
| 5776 | return data?.choices?.[0]?.reasoning ?? ''; | ||
| 5777 | } | ||
| 5778 | break; | ||
| 5779 | |||
| 5780 | case 'openai': | ||
| 5781 | if (!oai_settings.show_thoughts) break; | ||
| 5782 | |||
| 5783 | switch (oai_settings.chat_completion_source) { | ||
| 5784 | case chat_completion_sources.DEEPSEEK: | ||
| 5785 | return data?.choices?.[0]?.message?.reasoning_content ?? ''; | ||
| 5786 | case chat_completion_sources.OPENROUTER: | ||
| 5787 | return data?.choices?.[0]?.message?.reasoning ?? ''; | ||
| 5788 | case chat_completion_sources.MAKERSUITE: | ||
| 5789 | return data?.responseContent?.parts?.filter(part => part.thought)?.map(part => part.text)?.join('\n\n') ?? ''; | ||
| 5790 | } | ||
| 5791 | break; | ||
| 5792 | } | ||
| 5793 | |||
| 5794 | return ''; | ||
| 5795 | } | ||
| 5796 | |||
| 5797 | /** | ||
| 5798 | * Updates the Reasoning controls | ||
| 5799 | * @param {HTMLElement} element The element to update | ||
| 5800 | * @param {number?} duration The duration of the reasoning in milliseconds | ||
| 5801 | * @param {object} [options={}] Options for the function | ||
| 5802 | * @param {boolean} [options.forceEnd=false] If true, there will be no "Thinking..." when no duration exists | ||
| 5803 | */ | ||
| 5804 | function updateReasoningTimeUI(element, duration, { forceEnd = false } = {}) { | ||
| 5805 | if (duration) { | ||
| 5806 | const durationStr = moment.duration(duration).locale(getCurrentLocale()).humanize({ s: 50, ss: 9 }); | ||
| 5807 | element.textContent = t`Thought for ${durationStr}`; | ||
| 5808 | } else if (forceEnd) { | ||
| 5809 | element.textContent = t`Thought for some time`; | ||
| 5810 | } else { | ||
| 5811 | element.textContent = t`Thinking...`; | ||
| 5812 | } | ||
| 5813 | } | ||
| 5814 | |||
| 5815 | |||
| 5816 | /** | ||
| 5817 | * Extracts multiswipe swipes from the response data. | 5767 | * Extracts multiswipe swipes from the response data. |
| 5818 | * @param {Object} data Response data | 5768 | * @param {Object} data Response data |
| 5819 | * @param {string} type Type of generation | 5769 | * @param {string} type Type of generation |
| @@ -10872,18 +10822,6 @@ jQuery(async function () { | |||
| 10872 | } | 10822 | } |
| 10873 | }); | 10823 | }); |
| 10874 | 10824 | ||
| 10875 | $(document).on('click', '.mes_reasoning_header', function () { | ||
| 10876 | // If we are in message edit mode and reasoning area is closed, a click opens and edits it | ||
| 10877 | const mes = $(this).closest('.mes'); | ||
| 10878 | const mesEditArea = mes.find('#curEditTextarea'); | ||
| 10879 | if (mesEditArea.length) { | ||
| 10880 | const summary = $(mes).find('.mes_reasoning_summary'); | ||
| 10881 | if (!summary.attr('open')) { | ||
| 10882 | summary.find('.mes_reasoning_edit').trigger('click'); | ||
| 10883 | } | ||
| 10884 | } | ||
| 10885 | }); | ||
| 10886 | |||
| 10887 | $(document).on('input', '#curEditTextarea', function () { | 10825 | $(document).on('input', '#curEditTextarea', function () { |
| 10888 | if (power_user.auto_save_msg_edits === true) { | 10826 | if (power_user.auto_save_msg_edits === true) { |
| 10889 | messageEditAuto($(this)); | 10827 | messageEditAuto($(this)); |
| @@ -11438,17 +11376,6 @@ jQuery(async function () { | |||
| 11438 | } | 11376 | } |
| 11439 | }); | 11377 | }); |
| 11440 | 11378 | ||
| 11441 | $(document).on('click', '.mes_reasoning_summary', function () { | ||
| 11442 | // If you toggle summary header while editing reasoning, yup - we just cancel it | ||
| 11443 | $(this).closest('.mes').find('.mes_reasoning_edit_cancel:visible').trigger('click'); | ||
| 11444 | }); | ||
| 11445 | |||
| 11446 | $(document).on('click', '.mes_reasoning_details', function (e) { | ||
| 11447 | if (!e.target.closest('.mes_reasoning_actions') && !e.target.closest('.mes_reasoning_header')) { | ||
| 11448 | e.preventDefault(); | ||
| 11449 | } | ||
| 11450 | }); | ||
| 11451 | |||
| 11452 | $(document).keyup(function (e) { | 11379 | $(document).keyup(function (e) { |
| 11453 | if (e.key === 'Escape') { | 11380 | if (e.key === 'Escape') { |
| 11454 | const isEditVisible = $('#curEditTextarea').is(':visible') || $('.reasoning_edit_textarea').length > 0; | 11381 | const isEditVisible = $('#curEditTextarea').is(':visible') || $('.reasoning_edit_textarea').length > 0; |
| @@ -1,13 +1,18 @@ | |||
| 1 | import { chat, closeMessageEditor, event_types, eventSource, saveChatConditional, saveSettingsDebounced, substituteParams, updateMessageBlock } from '../script.js'; | 1 | import { |
| 2 | moment, | ||
| 3 | } from '../lib.js'; | ||
| 4 | import { chat, closeMessageEditor, event_types, eventSource, main_api, saveChatConditional, saveSettingsDebounced, substituteParams, updateMessageBlock } from '../script.js'; | ||
| 2 | import { getRegexedString, regex_placement } from './extensions/regex/engine.js'; | 5 | import { getRegexedString, regex_placement } from './extensions/regex/engine.js'; |
| 3 | import { t } from './i18n.js'; | 6 | import { getCurrentLocale, t } from './i18n.js'; |
| 4 | import { MacrosParser } from './macros.js'; | 7 | import { MacrosParser } from './macros.js'; |
| 8 | import { chat_completion_sources, oai_settings } from './openai.js'; | ||
| 5 | import { Popup } from './popup.js'; | 9 | import { Popup } from './popup.js'; |
| 6 | import { power_user } from './power-user.js'; | 10 | import { power_user } from './power-user.js'; |
| 7 | import { SlashCommand } from './slash-commands/SlashCommand.js'; | 11 | import { SlashCommand } from './slash-commands/SlashCommand.js'; |
| 8 | import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js'; | 12 | import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js'; |
| 9 | import { commonEnumProviders } from './slash-commands/SlashCommandCommonEnumsProvider.js'; | 13 | import { commonEnumProviders } from './slash-commands/SlashCommandCommonEnumsProvider.js'; |
| 10 | import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; | 14 | import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; |
| 15 | import { textgen_types, textgenerationwebui_settings } from './textgen-settings.js'; | ||
| 11 | import { copyText, escapeRegex, isFalseBoolean } from './utils.js'; | 16 | import { copyText, escapeRegex, isFalseBoolean } from './utils.js'; |
| 12 | 17 | ||
| 13 | /** | 18 | /** |
| @@ -35,6 +40,55 @@ function toggleReasoningAutoExpand() { | |||
| 35 | } | 40 | } |
| 36 | 41 | ||
| 37 | /** | 42 | /** |
| 43 | * Extracts the reasoning from the response data. | ||
| 44 | * @param {object} data Response data | ||
| 45 | * @returns {string} Extracted reasoning | ||
| 46 | */ | ||
| 47 | export function extractReasoningFromData(data) { | ||
| 48 | switch (main_api) { | ||
| 49 | case 'textgenerationwebui': | ||
| 50 | switch (textgenerationwebui_settings.type) { | ||
| 51 | case textgen_types.OPENROUTER: | ||
| 52 | return data?.choices?.[0]?.reasoning ?? ''; | ||
| 53 | } | ||
| 54 | break; | ||
| 55 | |||
| 56 | case 'openai': | ||
| 57 | if (!oai_settings.show_thoughts) break; | ||
| 58 | |||
| 59 | switch (oai_settings.chat_completion_source) { | ||
| 60 | case chat_completion_sources.DEEPSEEK: | ||
| 61 | return data?.choices?.[0]?.message?.reasoning_content ?? ''; | ||
| 62 | case chat_completion_sources.OPENROUTER: | ||
| 63 | return data?.choices?.[0]?.message?.reasoning ?? ''; | ||
| 64 | case chat_completion_sources.MAKERSUITE: | ||
| 65 | return data?.responseContent?.parts?.filter(part => part.thought)?.map(part => part.text)?.join('\n\n') ?? ''; | ||
| 66 | } | ||
| 67 | break; | ||
| 68 | } | ||
| 69 | |||
| 70 | return ''; | ||
| 71 | } | ||
| 72 | |||
| 73 | /** | ||
| 74 | * Updates the Reasoning controls | ||
| 75 | * @param {HTMLElement} element The element to update | ||
| 76 | * @param {number?} duration The duration of the reasoning in milliseconds | ||
| 77 | * @param {object} [options={}] Options for the function | ||
| 78 | * @param {boolean} [options.forceEnd=false] If true, there will be no "Thinking..." when no duration exists | ||
| 79 | */ | ||
| 80 | export function updateReasoningTimeUI(element, duration, { forceEnd = false } = {}) { | ||
| 81 | if (duration) { | ||
| 82 | const durationStr = moment.duration(duration).locale(getCurrentLocale()).humanize({ s: 50, ss: 9 }); | ||
| 83 | element.textContent = t`Thought for ${durationStr}`; | ||
| 84 | } else if (forceEnd) { | ||
| 85 | element.textContent = t`Thought for some time`; | ||
| 86 | } else { | ||
| 87 | element.textContent = t`Thinking...`; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | /** | ||
| 38 | * Helper class for adding reasoning to messages. | 92 | * Helper class for adding reasoning to messages. |
| 39 | * Keeps track of the number of reasoning additions. | 93 | * Keeps track of the number of reasoning additions. |
| 40 | */ | 94 | */ |
| @@ -247,6 +301,29 @@ function registerReasoningMacros() { | |||
| 247 | } | 301 | } |
| 248 | 302 | ||
| 249 | function setReasoningEventHandlers() { | 303 | function setReasoningEventHandlers() { |
| 304 | $(document).on('click', '.mes_reasoning_summary', function () { | ||
| 305 | // If you toggle summary header while editing reasoning, yup - we just cancel it | ||
| 306 | $(this).closest('.mes').find('.mes_reasoning_edit_cancel:visible').trigger('click'); | ||
| 307 | }); | ||
| 308 | |||
| 309 | $(document).on('click', '.mes_reasoning_details', function (e) { | ||
| 310 | if (!e.target.closest('.mes_reasoning_actions') && !e.target.closest('.mes_reasoning_header')) { | ||
| 311 | e.preventDefault(); | ||
| 312 | } | ||
| 313 | }); | ||
| 314 | |||
| 315 | $(document).on('click', '.mes_reasoning_header', function () { | ||
| 316 | // If we are in message edit mode and reasoning area is closed, a click opens and edits it | ||
| 317 | const mes = $(this).closest('.mes'); | ||
| 318 | const mesEditArea = mes.find('#curEditTextarea'); | ||
| 319 | if (mesEditArea.length) { | ||
| 320 | const summary = $(mes).find('.mes_reasoning_summary'); | ||
| 321 | if (!summary.attr('open')) { | ||
| 322 | summary.find('.mes_reasoning_edit').trigger('click'); | ||
| 323 | } | ||
| 324 | } | ||
| 325 | }); | ||
| 326 | |||
| 250 | $(document).on('click', '.mes_reasoning_copy', (e) => { | 327 | $(document).on('click', '.mes_reasoning_copy', (e) => { |
| 251 | e.stopPropagation(); | 328 | e.stopPropagation(); |
| 252 | e.preventDefault(); | 329 | e.preventDefault(); |