Formatting setting to send reasoning back to the model Supersedes #3352
| @@ -1981,7 +1981,7 @@ | ||
| 1981 | 1981 | <label for="openai_show_thoughts" class="checkbox_label widthFreeExpand"> |
| 1982 | 1982 | <input id="openai_show_thoughts" type="checkbox" /> |
| 1983 | 1983 | <span> |
| 1984 | 1984 | <span data-i18n="Show model thoughtsreasoning">Show model thoughtsreasoning</span> |
| 1985 | 1985 | <i class="opacity50p fa-solid fa-circle-info" title="Gemini 2.0 Thinking / DeepSeek Reasoner"></i> |
| 1986 | 1986 | </span> |
| 1987 | 1987 | </label> |
| @@ -3800,6 +3800,39 @@ | ||
| 3800 | 3800 | </div> |
| 3801 | 3801 | </div> |
| 3802 | 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 | 3836 | <h4 class="standoutHeader" data-i18n="Miscellaneous">Miscellaneous</h4> |
| 3804 | 3837 | <div> |
| 3805 | 3838 | <small> |
| @@ -6221,11 +6254,10 @@ | ||
| 6221 | 6254 | <div class="mes_edit_buttons"> |
| 6222 | 6255 | <div class="mes_edit_done menu_button fa-solid fa-check" title="Confirm" data-i18n="[title]Confirm"></div> |
| 6223 | 6256 | <div class="mes_edit_copy menu_button fa-solid fa-copy" title="Copy this message" data-i18n="[title]Copy this message"></div> |
| 6224 | 6257 | <div class="mes_edit_deletemes_edit_add_reasoning menu_button fa-solid fa-trash-canlightbulb" title="DeleteAdd thisa messagereasoning block" data-i18n="[title]DeleteAdd thisa messagereasoning 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 | 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 | 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 | 6261 | <div class="mes_edit_cancel menu_button fa-solid fa-xmark" title="Cancel" data-i18n="[title]Cancel"></div> |
| 6230 | 6262 | </div> |
| 6231 | 6263 | </div> |
| @@ -1385,7 +1385,7 @@ | ||
| 1385 | 1385 | "enable_functions_desc_1": "Autorise l'utilisation", |
| 1386 | 1386 | "enable_functions_desc_2": "outils de fonction", |
| 1387 | 1387 | "enable_functions_desc_3": "Peut être utilisé par diverses extensions pour fournir des fonctionnalités supplémentaires.", |
| 1388 | 1388 | "Show model thoughtsreasoning": "Afficher les pensées du modèle", |
| 1389 | 1389 | "Display the model's internal thoughts in the response.": "Afficher les pensées internes du modèle dans la réponse.", |
| 1390 | 1390 | "Confirm token parsing with": "Confirmer l'analyse des tokens avec", |
| 1391 | 1391 | "openai_logit_bias_no_items": "Aucun élément", |
| @@ -266,7 +266,7 @@ | ||
| 266 | 266 | "Use system prompt": "使用系统提示词", |
| 267 | 267 | "Merges_all_system_messages_desc_1": "合并所有系统消息,直到第一条具有非系统角色的消息,然后通过", |
| 268 | 268 | "Merges_all_system_messages_desc_2": "字段发送。", |
| 269 | 269 | "Show model thoughtsreasoning": "展示思维链", |
| 270 | 270 | "Display the model's internal thoughts in the response.": "展示模型在回复时的内部思维链。", |
| 271 | 271 | "Assistant Prefill": "AI预填", |
| 272 | 272 | "Expand the editor": "展开编辑器", |
| @@ -2357,7 +2357,7 @@ | ||
| 2357 | 2357 | "Forbid": "禁止", |
| 2358 | 2358 | "Aphrodite only. Determines the order of samplers. Skew is always applied post-softmax, so it's not included here.": "僅限 Aphrodite 使用。決定採樣器的順序。偏移總是在 softmax 後應用,因此不包括在此。", |
| 2359 | 2359 | "Aphrodite only. Determines the order of samplers.": "僅限 Aphrodite 使用。決定採樣器的順序。", |
| 2360 | 2360 | "Show model thoughtsreasoning": "顯示模型思維鏈", |
| 2361 | 2361 | "Display the model's internal thoughts in the response.": "在回應中顯示模型的思維鏈(內部思考過程)。", |
| 2362 | 2362 | "Generic (OpenAI-compatible) [LM Studio, LiteLLM, etc.]": "通用(兼容 OpenAI)[LM Studio, LiteLLM 等]", |
| 2363 | 2363 | "Model ID (optional)": "模型 ID(可選)", |
| @@ -238,7 +238,7 @@ import { getBackgrounds, initBackgrounds, loadBackgroundSettings, background_set | ||
| 238 | 238 | import { hideLoader, showLoader } from './scripts/loader.js'; |
| 239 | 239 | import { BulkEditOverlay, CharacterContextMenu } from './scripts/BulkEditOverlay.js'; |
| 240 | 240 | import { loadFeatherlessModels, loadMancerModels, loadOllamaModels, loadTogetherAIModels, loadInfermaticAIModels, loadOpenRouterModels, loadVllmModels, loadAphroditeModels, loadDreamGenModels, initTextGenModels, loadTabbyModels, loadGenericModels } from './scripts/textgen-models.js'; |
| 241 | 241 | import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, decodeStyleTags, encodeStyleTags, isExternalMediaAllowed, getCurrentEntityId, preserveNeutralChat, restoreNeutralChat, PromptReasoning } from './scripts/chats.js'; |
| 242 | 242 | import { getPresetManager, initPresetManager } from './scripts/preset-manager.js'; |
| 243 | 243 | import { evaluateMacros, getLastMessageId, initMacros } from './scripts/macros.js'; |
| 244 | 244 | import { currentUser, setUserControls } from './scripts/user.js'; |
| @@ -3844,6 +3844,11 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | ||
| 3844 | 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 | 3852 | coreChat = await Promise.all(coreChat.map(async (chatItem, index) => { |
| 3848 | 3853 | let message = chatItem.mes; |
| 3849 | 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 | 8042 | export function closeMessageEditor() { |
| 8038 | 8043 | if (this_edit_mes_id) { |
| 8039 | 8044 | $(`#chat .mes[mesid="${this_edit_mes_id}"] .mes_edit_cancel`).click(); |
| 8040 | 8045 | } |
| @@ -24,6 +24,8 @@ import { | ||
| 24 | 24 | updateChatMetadata, |
| 25 | 25 | system_message_types, |
| 26 | 26 | updateMessageBlock, |
| 27 | + closeMessageEditor, | |
| 28 | + substituteParams, | |
| 27 | 29 | } from '../script.js'; |
| 28 | 30 | import { selected_group } from './group-chats.js'; |
| 29 | 31 | import { power_user } from './power-user.js'; |
| @@ -1418,6 +1420,47 @@ export function registerFileConverter(mimeType, converter) { | ||
| 1418 | 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 | 1464 | jQuery(function () { |
| 1422 | 1465 | $(document).on('click', '.mes_hide', async function () { |
| 1423 | 1466 | const messageBlock = $(this).closest('.mes'); |
| @@ -1574,6 +1617,25 @@ jQuery(function () { | ||
| 1574 | 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 | 1639 | $(document).on('click', '.mes_reasoning_delete', async function (e) { |
| 1578 | 1640 | e.stopPropagation(); |
| 1579 | 1641 | e.preventDefault(); |
| @@ -253,6 +253,14 @@ let power_user = { | ||
| 253 | 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 | 264 | personas: {}, |
| 257 | 265 | default_persona: null, |
| 258 | 266 | persona_descriptions: {}, |
| @@ -1613,6 +1621,7 @@ async function loadPowerUserSettings(settings, data) { | ||
| 1613 | 1621 | loadMovingUIState(); |
| 1614 | 1622 | loadCharListState(); |
| 1615 | 1623 | toggleMDHotkeyIconDisplay(); |
| 1624 | + loadReasoningSettings(); | |
| 1616 | 1625 | } |
| 1617 | 1626 | |
| 1618 | 1627 | function toggleMDHotkeyIconDisplay() { |
| @@ -1629,6 +1638,38 @@ function loadCharListState() { | ||
| 1629 | 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 | 1673 | function loadMovingUIState() { |
| 1633 | 1674 | if (!isMobile() |
| 1634 | 1675 | && power_user.movingUIState |