Formatting setting to send reasoning back to the model Supersedes #3352
| @@ -1981,7 +1981,7 @@ | |||
| 1981 | <label for="openai_show_thoughts" class="checkbox_label widthFreeExpand"> | 1981 | <label for="openai_show_thoughts" class="checkbox_label widthFreeExpand"> |
| 1982 | <input id="openai_show_thoughts" type="checkbox" /> | 1982 | <input id="openai_show_thoughts" type="checkbox" /> |
| 1983 | <span> | 1983 | <span> |
| 1984 | <span data-i18n="Show model thoughts">Show model thoughts</span> | 1984 | <span data-i18n="Show model reasoning">Show model reasoning</span> |
| 1985 | <i class="opacity50p fa-solid fa-circle-info" title="Gemini 2.0 Thinking / DeepSeek Reasoner"></i> | 1985 | <i class="opacity50p fa-solid fa-circle-info" title="Gemini 2.0 Thinking / DeepSeek Reasoner"></i> |
| 1986 | </span> | 1986 | </span> |
| 1987 | </label> | 1987 | </label> |
| @@ -3800,6 +3800,39 @@ | |||
| 3800 | </div> | 3800 | </div> |
| 3801 | </div> | 3801 | </div> |
| 3802 | <div> | 3802 | <div> |
| 3803 | <h4 class="standoutHeader"> | ||
| 3804 | <span data-i18n="Reasoning">Reasoning</span> | ||
| 3805 | </h4> | ||
| 3806 | <div> | ||
| 3807 | <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"> | ||
| 3808 | <input id="reasoning_add_to_prompts" type="checkbox" /> | ||
| 3809 | <small data-i18n="Add Reasoning to Prompts"> | ||
| 3810 | Add Reasoning to Prompts | ||
| 3811 | </small> | ||
| 3812 | </label> | ||
| 3813 | <div class="flex-container"> | ||
| 3814 | <div class="flex1" title="Inserted before the reasoning content." data-i18n="[title]reasoning_prefix"> | ||
| 3815 | <small data-i18n="Prefix">Prefix</small> | ||
| 3816 | <textarea id="reasoning_prefix" class="text_pole textarea_compact autoSetHeight"></textarea> | ||
| 3817 | </div> | ||
| 3818 | <div class="flex1" title="Inserted after the reasoning content." data-i18n="[title]reasoning_suffix"> | ||
| 3819 | <small data-i18n="Suffix">Suffix</small> | ||
| 3820 | <textarea id="reasoning_suffix" class="text_pole textarea_compact autoSetHeight"></textarea> | ||
| 3821 | </div> | ||
| 3822 | </div> | ||
| 3823 | <div class="flex-container"> | ||
| 3824 | <div class="flex1" title="Inserted between the reasoning and the message content." data-i18n="[title]reasoning_separator"> | ||
| 3825 | <small data-i18n="Separator">Separator</small> | ||
| 3826 | <textarea id="reasoning_separator" class="text_pole textarea_compact autoSetHeight"></textarea> | ||
| 3827 | </div> | ||
| 3828 | <div class="flex1" title="Maximum number of reasoning blocks to be added per prompt, counting from the last message." data-i18n="[title]reasoning_max_additions"> | ||
| 3829 | <small data-i18n="Max Additions">Max Additions</small> | ||
| 3830 | <input id="reasoning_max_additions" class="text_pole textarea_compact" type="number" min="0" max="999"></textarea> | ||
| 3831 | </div> | ||
| 3832 | </div> | ||
| 3833 | </div> | ||
| 3834 | </div> | ||
| 3835 | <div> | ||
| 3803 | <h4 class="standoutHeader" data-i18n="Miscellaneous">Miscellaneous</h4> | 3836 | <h4 class="standoutHeader" data-i18n="Miscellaneous">Miscellaneous</h4> |
| 3804 | <div> | 3837 | <div> |
| 3805 | <small> | 3838 | <small> |
| @@ -6221,11 +6254,10 @@ | |||
| 6221 | <div class="mes_edit_buttons"> | 6254 | <div class="mes_edit_buttons"> |
| 6222 | <div class="mes_edit_done menu_button fa-solid fa-check" title="Confirm" data-i18n="[title]Confirm"></div> | 6255 | <div class="mes_edit_done menu_button fa-solid fa-check" title="Confirm" data-i18n="[title]Confirm"></div> |
| 6223 | <div class="mes_edit_copy menu_button fa-solid fa-copy" title="Copy this message" data-i18n="[title]Copy this message"></div> | 6256 | <div class="mes_edit_copy menu_button fa-solid fa-copy" title="Copy this message" data-i18n="[title]Copy this message"></div> |
| 6224 | <div class="mes_edit_delete menu_button fa-solid fa-trash-can" title="Delete this message" data-i18n="[title]Delete this message"> | 6257 | <div class="mes_edit_add_reasoning menu_button fa-solid fa-lightbulb" title="Add a reasoning block" data-i18n="[title]Add a reasoning block"></div> |
| 6225 | </div> | 6258 | <div class="mes_edit_delete menu_button fa-solid fa-trash-can" title="Delete this message" data-i18n="[title]Delete this message"></div> |
| 6226 | <div class="mes_edit_up menu_button fa-solid fa-chevron-up " title="Move message up" data-i18n="[title]Move message up"></div> | 6259 | <div class="mes_edit_up menu_button fa-solid fa-chevron-up " title="Move message up" data-i18n="[title]Move message up"></div> |
| 6227 | <div class="mes_edit_down menu_button fa-solid fa-chevron-down" title="Move message down" data-i18n="[title]Move message down"> | 6260 | <div class="mes_edit_down menu_button fa-solid fa-chevron-down" title="Move message down" data-i18n="[title]Move message down"></div> |
| 6228 | </div> | ||
| 6229 | <div class="mes_edit_cancel menu_button fa-solid fa-xmark" title="Cancel" data-i18n="[title]Cancel"></div> | 6261 | <div class="mes_edit_cancel menu_button fa-solid fa-xmark" title="Cancel" data-i18n="[title]Cancel"></div> |
| 6230 | </div> | 6262 | </div> |
| 6231 | </div> | 6263 | </div> |
| @@ -1385,7 +1385,7 @@ | |||
| 1385 | "enable_functions_desc_1": "Autorise l'utilisation", | 1385 | "enable_functions_desc_1": "Autorise l'utilisation", |
| 1386 | "enable_functions_desc_2": "outils de fonction", | 1386 | "enable_functions_desc_2": "outils de fonction", |
| 1387 | "enable_functions_desc_3": "Peut être utilisé par diverses extensions pour fournir des fonctionnalités supplémentaires.", | 1387 | "enable_functions_desc_3": "Peut être utilisé par diverses extensions pour fournir des fonctionnalités supplémentaires.", |
| 1388 | "Show model thoughts": "Afficher les pensées du modèle", | 1388 | "Show model reasoning": "Afficher les pensées du modèle", |
| 1389 | "Display the model's internal thoughts in the response.": "Afficher les pensées internes du modèle dans la réponse.", | 1389 | "Display the model's internal thoughts in the response.": "Afficher les pensées internes du modèle dans la réponse.", |
| 1390 | "Confirm token parsing with": "Confirmer l'analyse des tokens avec", | 1390 | "Confirm token parsing with": "Confirmer l'analyse des tokens avec", |
| 1391 | "openai_logit_bias_no_items": "Aucun élément", | 1391 | "openai_logit_bias_no_items": "Aucun élément", |
| @@ -266,7 +266,7 @@ | |||
| 266 | "Use system prompt": "使用系统提示词", | 266 | "Use system prompt": "使用系统提示词", |
| 267 | "Merges_all_system_messages_desc_1": "合并所有系统消息,直到第一条具有非系统角色的消息,然后通过", | 267 | "Merges_all_system_messages_desc_1": "合并所有系统消息,直到第一条具有非系统角色的消息,然后通过", |
| 268 | "Merges_all_system_messages_desc_2": "字段发送。", | 268 | "Merges_all_system_messages_desc_2": "字段发送。", |
| 269 | "Show model thoughts": "展示思维链", | 269 | "Show model reasoning": "展示思维链", |
| 270 | "Display the model's internal thoughts in the response.": "展示模型在回复时的内部思维链。", | 270 | "Display the model's internal thoughts in the response.": "展示模型在回复时的内部思维链。", |
| 271 | "Assistant Prefill": "AI预填", | 271 | "Assistant Prefill": "AI预填", |
| 272 | "Expand the editor": "展开编辑器", | 272 | "Expand the editor": "展开编辑器", |
| @@ -2357,7 +2357,7 @@ | |||
| 2357 | "Forbid": "禁止", | 2357 | "Forbid": "禁止", |
| 2358 | "Aphrodite only. Determines the order of samplers. Skew is always applied post-softmax, so it's not included here.": "僅限 Aphrodite 使用。決定採樣器的順序。偏移總是在 softmax 後應用,因此不包括在此。", | 2358 | "Aphrodite only. Determines the order of samplers. Skew is always applied post-softmax, so it's not included here.": "僅限 Aphrodite 使用。決定採樣器的順序。偏移總是在 softmax 後應用,因此不包括在此。", |
| 2359 | "Aphrodite only. Determines the order of samplers.": "僅限 Aphrodite 使用。決定採樣器的順序。", | 2359 | "Aphrodite only. Determines the order of samplers.": "僅限 Aphrodite 使用。決定採樣器的順序。", |
| 2360 | "Show model thoughts": "顯示模型思維鏈", | 2360 | "Show model reasoning": "顯示模型思維鏈", |
| 2361 | "Display the model's internal thoughts in the response.": "在回應中顯示模型的思維鏈(內部思考過程)。", | 2361 | "Display the model's internal thoughts in the response.": "在回應中顯示模型的思維鏈(內部思考過程)。", |
| 2362 | "Generic (OpenAI-compatible) [LM Studio, LiteLLM, etc.]": "通用(兼容 OpenAI)[LM Studio, LiteLLM 等]", | 2362 | "Generic (OpenAI-compatible) [LM Studio, LiteLLM, etc.]": "通用(兼容 OpenAI)[LM Studio, LiteLLM 等]", |
| 2363 | "Model ID (optional)": "模型 ID(可選)", | 2363 | "Model ID (optional)": "模型 ID(可選)", |
| @@ -238,7 +238,7 @@ import { getBackgrounds, initBackgrounds, loadBackgroundSettings, background_set | |||
| 238 | import { hideLoader, showLoader } from './scripts/loader.js'; | 238 | import { hideLoader, showLoader } from './scripts/loader.js'; |
| 239 | import { BulkEditOverlay, CharacterContextMenu } from './scripts/BulkEditOverlay.js'; | 239 | import { BulkEditOverlay, CharacterContextMenu } from './scripts/BulkEditOverlay.js'; |
| 240 | import { loadFeatherlessModels, loadMancerModels, loadOllamaModels, loadTogetherAIModels, loadInfermaticAIModels, loadOpenRouterModels, loadVllmModels, loadAphroditeModels, loadDreamGenModels, initTextGenModels, loadTabbyModels, loadGenericModels } from './scripts/textgen-models.js'; | 240 | import { loadFeatherlessModels, loadMancerModels, loadOllamaModels, loadTogetherAIModels, loadInfermaticAIModels, loadOpenRouterModels, loadVllmModels, loadAphroditeModels, loadDreamGenModels, initTextGenModels, loadTabbyModels, loadGenericModels } from './scripts/textgen-models.js'; |
| 241 | import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, decodeStyleTags, encodeStyleTags, isExternalMediaAllowed, getCurrentEntityId, preserveNeutralChat, restoreNeutralChat } from './scripts/chats.js'; | 241 | import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, decodeStyleTags, encodeStyleTags, isExternalMediaAllowed, getCurrentEntityId, preserveNeutralChat, restoreNeutralChat, PromptReasoning } from './scripts/chats.js'; |
| 242 | import { getPresetManager, initPresetManager } from './scripts/preset-manager.js'; | 242 | import { getPresetManager, initPresetManager } from './scripts/preset-manager.js'; |
| 243 | import { evaluateMacros, getLastMessageId, initMacros } from './scripts/macros.js'; | 243 | import { evaluateMacros, getLastMessageId, initMacros } from './scripts/macros.js'; |
| 244 | import { currentUser, setUserControls } from './scripts/user.js'; | 244 | import { currentUser, setUserControls } from './scripts/user.js'; |
| @@ -3844,6 +3844,11 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 3844 | coreChat.pop(); | 3844 | coreChat.pop(); |
| 3845 | } | 3845 | } |
| 3846 | 3846 | ||
| 3847 | const reasoning = new PromptReasoning(); | ||
| 3848 | for (let i = coreChat.length - 1; i >= 0; i--) { | ||
| 3849 | coreChat[i] = { ...coreChat[i], mes: reasoning.addToMessage(coreChat[i].mes, coreChat[i].extra?.reasoning) }; | ||
| 3850 | } | ||
| 3851 | |||
| 3847 | coreChat = await Promise.all(coreChat.map(async (chatItem, index) => { | 3852 | coreChat = await Promise.all(coreChat.map(async (chatItem, index) => { |
| 3848 | let message = chatItem.mes; | 3853 | let message = chatItem.mes; |
| 3849 | let regexType = chatItem.is_user ? regex_placement.USER_INPUT : regex_placement.AI_OUTPUT; | 3854 | let regexType = chatItem.is_user ? regex_placement.USER_INPUT : regex_placement.AI_OUTPUT; |
| @@ -8034,7 +8039,7 @@ function updateEditArrowClasses() { | |||
| 8034 | } | 8039 | } |
| 8035 | } | 8040 | } |
| 8036 | 8041 | ||
| 8037 | function closeMessageEditor() { | 8042 | export function closeMessageEditor() { |
| 8038 | if (this_edit_mes_id) { | 8043 | if (this_edit_mes_id) { |
| 8039 | $(`#chat .mes[mesid="${this_edit_mes_id}"] .mes_edit_cancel`).click(); | 8044 | $(`#chat .mes[mesid="${this_edit_mes_id}"] .mes_edit_cancel`).click(); |
| 8040 | } | 8045 | } |
| @@ -24,6 +24,8 @@ import { | |||
| 24 | updateChatMetadata, | 24 | updateChatMetadata, |
| 25 | system_message_types, | 25 | system_message_types, |
| 26 | updateMessageBlock, | 26 | updateMessageBlock, |
| 27 | closeMessageEditor, | ||
| 28 | substituteParams, | ||
| 27 | } from '../script.js'; | 29 | } from '../script.js'; |
| 28 | import { selected_group } from './group-chats.js'; | 30 | import { selected_group } from './group-chats.js'; |
| 29 | import { power_user } from './power-user.js'; | 31 | import { power_user } from './power-user.js'; |
| @@ -1418,6 +1420,47 @@ export function registerFileConverter(mimeType, converter) { | |||
| 1418 | converters[mimeType] = converter; | 1420 | converters[mimeType] = converter; |
| 1419 | } | 1421 | } |
| 1420 | 1422 | ||
| 1423 | /** | ||
| 1424 | * Helper class for adding reasoning to messages. | ||
| 1425 | * Keeps track of the number of reasoning additions. | ||
| 1426 | */ | ||
| 1427 | export class PromptReasoning { | ||
| 1428 | static REASONING_PLACEHOLDER = '\u200B'; | ||
| 1429 | |||
| 1430 | constructor() { | ||
| 1431 | this.counter = 0; | ||
| 1432 | } | ||
| 1433 | |||
| 1434 | /** | ||
| 1435 | * Add reasoning to a message according to the power user settings. | ||
| 1436 | * @param {string} content Message content | ||
| 1437 | * @param {string} reasoning Message reasoning | ||
| 1438 | * @returns {string} Message content with reasoning | ||
| 1439 | */ | ||
| 1440 | addToMessage(content, reasoning) { | ||
| 1441 | // Disabled or reached limit of additions | ||
| 1442 | if (!power_user.reasoning.add_to_prompts || this.counter >= power_user.reasoning.max_additions) { | ||
| 1443 | return content; | ||
| 1444 | } | ||
| 1445 | |||
| 1446 | // No reasoning provided or a placeholder | ||
| 1447 | if (!reasoning || reasoning === PromptReasoning.REASONING_PLACEHOLDER) { | ||
| 1448 | return content; | ||
| 1449 | } | ||
| 1450 | |||
| 1451 | // Increment the counter | ||
| 1452 | this.counter++; | ||
| 1453 | |||
| 1454 | // Substitute macros in variable parts | ||
| 1455 | const prefix = substituteParams(power_user.reasoning.prefix || ''); | ||
| 1456 | const separator = substituteParams(power_user.reasoning.separator || ''); | ||
| 1457 | const suffix = substituteParams(power_user.reasoning.suffix || ''); | ||
| 1458 | |||
| 1459 | // Combine parts with reasoning and content | ||
| 1460 | return `${prefix}${reasoning}${suffix}${separator}${content}`; | ||
| 1461 | } | ||
| 1462 | } | ||
| 1463 | |||
| 1421 | jQuery(function () { | 1464 | jQuery(function () { |
| 1422 | $(document).on('click', '.mes_hide', async function () { | 1465 | $(document).on('click', '.mes_hide', async function () { |
| 1423 | const messageBlock = $(this).closest('.mes'); | 1466 | const messageBlock = $(this).closest('.mes'); |
| @@ -1574,6 +1617,25 @@ jQuery(function () { | |||
| 1574 | e.preventDefault(); | 1617 | e.preventDefault(); |
| 1575 | }); | 1618 | }); |
| 1576 | 1619 | ||
| 1620 | $(document).on('click', '.mes_edit_add_reasoning', async function () { | ||
| 1621 | const mesBlock = $(this).closest('.mes'); | ||
| 1622 | const mesId = Number(mesBlock.attr('mesid')); | ||
| 1623 | const message = chat[mesId]; | ||
| 1624 | if (!message?.extra){ | ||
| 1625 | return; | ||
| 1626 | } | ||
| 1627 | |||
| 1628 | if (message.extra.reasoning) { | ||
| 1629 | toastr.info(t`Reasoning already exists.`, t`Edit Message`); | ||
| 1630 | return; | ||
| 1631 | } | ||
| 1632 | |||
| 1633 | message.extra.reasoning = PromptReasoning.REASONING_PLACEHOLDER; | ||
| 1634 | await saveChatConditional(); | ||
| 1635 | closeMessageEditor(); | ||
| 1636 | updateMessageBlock(mesId, message); | ||
| 1637 | }); | ||
| 1638 | |||
| 1577 | $(document).on('click', '.mes_reasoning_delete', async function (e) { | 1639 | $(document).on('click', '.mes_reasoning_delete', async function (e) { |
| 1578 | e.stopPropagation(); | 1640 | e.stopPropagation(); |
| 1579 | e.preventDefault(); | 1641 | e.preventDefault(); |
| @@ -253,6 +253,14 @@ let power_user = { | |||
| 253 | content: 'Write {{char}}\'s next reply in a fictional chat between {{char}} and {{user}}.', | 253 | content: 'Write {{char}}\'s next reply in a fictional chat between {{char}} and {{user}}.', |
| 254 | }, | 254 | }, |
| 255 | 255 | ||
| 256 | reasoning: { | ||
| 257 | add_to_prompts: false, | ||
| 258 | prefix: '<think>\n', | ||
| 259 | suffix: '\n</think>', | ||
| 260 | separator: '\n', | ||
| 261 | max_additions: 1, | ||
| 262 | }, | ||
| 263 | |||
| 256 | personas: {}, | 264 | personas: {}, |
| 257 | default_persona: null, | 265 | default_persona: null, |
| 258 | persona_descriptions: {}, | 266 | persona_descriptions: {}, |
| @@ -1613,6 +1621,7 @@ async function loadPowerUserSettings(settings, data) { | |||
| 1613 | loadMovingUIState(); | 1621 | loadMovingUIState(); |
| 1614 | loadCharListState(); | 1622 | loadCharListState(); |
| 1615 | toggleMDHotkeyIconDisplay(); | 1623 | toggleMDHotkeyIconDisplay(); |
| 1624 | loadReasoningSettings(); | ||
| 1616 | } | 1625 | } |
| 1617 | 1626 | ||
| 1618 | function toggleMDHotkeyIconDisplay() { | 1627 | function toggleMDHotkeyIconDisplay() { |
| @@ -1629,6 +1638,38 @@ function loadCharListState() { | |||
| 1629 | document.body.classList.toggle('charListGrid', power_user.charListGrid); | 1638 | document.body.classList.toggle('charListGrid', power_user.charListGrid); |
| 1630 | } | 1639 | } |
| 1631 | 1640 | ||
| 1641 | function loadReasoningSettings() { | ||
| 1642 | $('#reasoning_add_to_prompts').prop('checked', power_user.reasoning.add_to_prompts); | ||
| 1643 | $('#reasoning_add_to_prompts').on('change', function () { | ||
| 1644 | power_user.reasoning.add_to_prompts = !!$(this).prop('checked'); | ||
| 1645 | saveSettingsDebounced(); | ||
| 1646 | }); | ||
| 1647 | |||
| 1648 | $('#reasoning_prefix').val(power_user.reasoning.prefix); | ||
| 1649 | $('#reasoning_prefix').on('input', function () { | ||
| 1650 | power_user.reasoning.prefix = String($(this).val()); | ||
| 1651 | saveSettingsDebounced(); | ||
| 1652 | }); | ||
| 1653 | |||
| 1654 | $('#reasoning_suffix').val(power_user.reasoning.suffix); | ||
| 1655 | $('#reasoning_suffix').on('input', function () { | ||
| 1656 | power_user.reasoning.suffix = String($(this).val()); | ||
| 1657 | saveSettingsDebounced(); | ||
| 1658 | }); | ||
| 1659 | |||
| 1660 | $('#reasoning_separator').val(power_user.reasoning.separator); | ||
| 1661 | $('#reasoning_separator').on('input', function () { | ||
| 1662 | power_user.reasoning.separator = String($(this).val()); | ||
| 1663 | saveSettingsDebounced(); | ||
| 1664 | }); | ||
| 1665 | |||
| 1666 | $('#reasoning_max_additions').val(power_user.reasoning.max_additions); | ||
| 1667 | $('#reasoning_max_additions').on('input', function () { | ||
| 1668 | power_user.reasoning.max_additions = Number($(this).val()); | ||
| 1669 | saveSettingsDebounced(); | ||
| 1670 | }); | ||
| 1671 | } | ||
| 1672 | |||
| 1632 | function loadMovingUIState() { | 1673 | function loadMovingUIState() { |
| 1633 | if (!isMobile() | 1674 | if (!isMobile() |
| 1634 | && power_user.movingUIState | 1675 | && power_user.movingUIState |