Add reasoning-collapse, reasoning-expand, reasoning-toggle slash commands with range support (#5296) * Initial plan * Add reasoning-collapse, reasoning-expand, reasoning-toggle slash commands Co-authored-by: Cohee1207 <18619528+Cohee1207@users.noreply.github.com> * Add message range support to reasoning commands and allChatRange macro Co-authored-by: Cohee1207 <18619528+Cohee1207@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Cohee1207 <18619528+Cohee1207@users.noreply.github.com>
Signed| @@ -549,7 +549,6 @@ | ||
| 549 | 549 | "resolved": "https://registry.npmjs.org/@jimp/custom/-/custom-0.22.12.tgz", |
| 550 | 550 | "integrity": "sha512-xcmww1O/JFP2MrlGUMd3Q78S3Qu6W3mYTXYuIqFq33EorgYHV/HqymHfXy9GjiCJ7OI+7lWx6nYFOzU7M4rd1Q==", |
| 551 | 551 | "license": "MIT", |
| 552 | - "peer": true, | |
| 553 | 552 | "dependencies": { |
| 554 | 553 | "@jimp/core": "^0.22.12" |
| 555 | 554 | } |
| @@ -1011,7 +1010,6 @@ | ||
| 1011 | 1010 | "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-1.6.0.tgz", |
| 1012 | 1011 | "integrity": "sha512-uSUD1mqXN9i1SGSz5ov3keRZ7S9L32/mAQG08wUwZiEi5FpbV0K8A8l1zkazAIZi9IJzLlTauRNU41Mi8IF9fA==", |
| 1013 | 1012 | "license": "MIT", |
| 1014 | - "peer": true, | |
| 1015 | 1013 | "dependencies": { |
| 1016 | 1014 | "@jimp/core": "1.6.0", |
| 1017 | 1015 | "@jimp/types": "1.6.0", |
| @@ -1043,7 +1041,6 @@ | ||
| 1043 | 1041 | "resolved": "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.22.12.tgz", |
| 1044 | 1042 | "integrity": "sha512-dghs92qM6MhHj0HrV2qAwKPMklQtjNpoYgAB94ysYpsXslhRTiPisueSIELRwZGEr0J0VUxpUY7HgJwlSIgGZw==", |
| 1045 | 1043 | "license": "MIT", |
| 1046 | - "peer": true, | |
| 1047 | 1044 | "dependencies": { |
| 1048 | 1045 | "@jimp/utils": "^0.22.12" |
| 1049 | 1046 | }, |
| @@ -1139,7 +1136,6 @@ | ||
| 1139 | 1136 | "resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.22.12.tgz", |
| 1140 | 1137 | "integrity": "sha512-xslz2ZoFZOPLY8EZ4dC29m168BtDx95D6K80TzgUi8gqT7LY6CsajWO0FAxDwHz6h0eomHMfyGX0stspBrTKnQ==", |
| 1141 | 1138 | "license": "MIT", |
| 1142 | - "peer": true, | |
| 1143 | 1139 | "dependencies": { |
| 1144 | 1140 | "@jimp/utils": "^0.22.12" |
| 1145 | 1141 | }, |
| @@ -1176,7 +1172,6 @@ | ||
| 1176 | 1172 | "resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.22.12.tgz", |
| 1177 | 1173 | "integrity": "sha512-xImhTE5BpS8xa+mAN6j4sMRWaUgUDLoaGHhJhpC+r7SKKErYDR0WQV4yCE4gP+N0gozD0F3Ka1LUSaMXrn7ZIA==", |
| 1178 | 1174 | "license": "MIT", |
| 1179 | - "peer": true, | |
| 1180 | 1175 | "dependencies": { |
| 1181 | 1176 | "@jimp/utils": "^0.22.12", |
| 1182 | 1177 | "tinycolor2": "^1.6.0" |
| @@ -1220,7 +1215,6 @@ | ||
| 1220 | 1215 | "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.22.12.tgz", |
| 1221 | 1216 | "integrity": "sha512-FNuUN0OVzRCozx8XSgP9MyLGMxNHHJMFt+LJuFjn1mu3k0VQxrzqbN06yIl46TVejhyAhcq5gLzqmSCHvlcBVw==", |
| 1222 | 1217 | "license": "MIT", |
| 1223 | - "peer": true, | |
| 1224 | 1218 | "dependencies": { |
| 1225 | 1219 | "@jimp/utils": "^0.22.12" |
| 1226 | 1220 | }, |
| @@ -1308,7 +1302,6 @@ | ||
| 1308 | 1302 | "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.22.12.tgz", |
| 1309 | 1303 | "integrity": "sha512-3NyTPlPbTnGKDIbaBgQ3HbE6wXbAlFfxHVERmrbqAi8R3r6fQPxpCauA8UVDnieg5eo04D0T8nnnNIX//i/sXg==", |
| 1310 | 1304 | "license": "MIT", |
| 1311 | - "peer": true, | |
| 1312 | 1305 | "dependencies": { |
| 1313 | 1306 | "@jimp/utils": "^0.22.12" |
| 1314 | 1307 | }, |
| @@ -1321,7 +1314,6 @@ | ||
| 1321 | 1314 | "resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.22.12.tgz", |
| 1322 | 1315 | "integrity": "sha512-9YNEt7BPAFfTls2FGfKBVgwwLUuKqy+E8bDGGEsOqHtbuhbshVGxN2WMZaD4gh5IDWvR+emmmPPWGgaYNYt1gA==", |
| 1323 | 1316 | "license": "MIT", |
| 1324 | - "peer": true, | |
| 1325 | 1317 | "dependencies": { |
| 1326 | 1318 | "@jimp/utils": "^0.22.12" |
| 1327 | 1319 | }, |
| @@ -1922,7 +1914,6 @@ | ||
| 1922 | 1914 | "integrity": "sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==", |
| 1923 | 1915 | "dev": true, |
| 1924 | 1916 | "license": "MIT", |
| 1925 | - "peer": true, | |
| 1926 | 1917 | "dependencies": { |
| 1927 | 1918 | "@types/body-parser": "*", |
| 1928 | 1919 | "@types/express-serve-static-core": "^4.17.33", |
| @@ -2612,7 +2603,6 @@ | ||
| 2612 | 2603 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", |
| 2613 | 2604 | "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", |
| 2614 | 2605 | "license": "MIT", |
| 2615 | - "peer": true, | |
| 2616 | 2606 | "bin": { |
| 2617 | 2607 | "acorn": "bin/acorn" |
| 2618 | 2608 | }, |
| @@ -3232,7 +3222,6 @@ | ||
| 3232 | 3222 | } |
| 3233 | 3223 | ], |
| 3234 | 3224 | "license": "MIT", |
| 3235 | - "peer": true, | |
| 3236 | 3225 | "dependencies": { |
| 3237 | 3226 | "baseline-browser-mapping": "^2.9.0", |
| 3238 | 3227 | "caniuse-lite": "^1.0.30001759", |
| @@ -4567,7 +4556,6 @@ | ||
| 4567 | 4556 | "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", |
| 4568 | 4557 | "dev": true, |
| 4569 | 4558 | "license": "MIT", |
| 4570 | - "peer": true, | |
| 4571 | 4559 | "dependencies": { |
| 4572 | 4560 | "@eslint-community/eslint-utils": "^4.2.0", |
| 4573 | 4561 | "@eslint-community/regexpp": "^4.6.1", |
| @@ -8125,7 +8113,6 @@ | ||
| 8125 | 8113 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", |
| 8126 | 8114 | "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", |
| 8127 | 8115 | "license": "MIT", |
| 8128 | - "peer": true, | |
| 8129 | 8116 | "dependencies": { |
| 8130 | 8117 | "fast-deep-equal": "^3.1.3", |
| 8131 | 8118 | "fast-uri": "^3.0.1", |
| @@ -653,6 +653,7 @@ export function evaluateMacros(content, env, postProcessFn) { | ||
| 653 | 653 | { regex: /{{firstDisplayedMessageId}}/gi, replace: () => String(getFirstDisplayedMessageId() ?? '') }, |
| 654 | 654 | { regex: /{{lastSwipeId}}/gi, replace: () => String(getLastSwipeId() ?? '') }, |
| 655 | 655 | { regex: /{{currentSwipeId}}/gi, replace: () => String(getCurrentSwipeId() ?? '') }, |
| 656 | + { regex: /{{allChatRange}}/gi, replace: () => chat.length === 0 ? '' : `0-${chat.length - 1}` }, | |
| 656 | 657 | { regex: /{{reverse:(.+?)}}/gi, replace: (_, str) => Array.from(str).reverse().join('') }, |
| 657 | 658 | { regex: /\{\{\/\/([\s\S]*?)\}\}/gm, replace: () => '' }, |
| 658 | 659 | { regex: /{{time}}/gi, replace: () => moment().format('LT') }, |
| @@ -66,6 +66,18 @@ export function registerChatMacros() { | ||
| 66 | 66 | returnType: MacroValueType.INTEGER, |
| 67 | 67 | handler: () => String(getCurrentSwipeId() ?? ''), |
| 68 | 68 | }); |
| 69 | + | |
| 70 | + MacroRegistry.registerMacro('allChatRange', { | |
| 71 | + category: MacroCategory.CHAT, | |
| 72 | + description: 'Range of all message IDs in the chat (e.g. "0-10"). Empty string if the chat is empty.', | |
| 73 | + returns: 'Range string from 0 to last message ID, or empty string.', | |
| 74 | + handler: () => { | |
| 75 | + if (!Array.isArray(chat) || chat.length === 0) { | |
| 76 | + return ''; | |
| 77 | + } | |
| 78 | + return `0-${chat.length - 1}`; | |
| 79 | + }, | |
| 80 | + }); | |
| 69 | 81 | } |
| 70 | 82 | |
| 71 | 83 | function getLastMessageId({ exclude_swipe_in_propress = true, filter = null } = {}) { |
| @@ -16,7 +16,7 @@ import { enumTypes, SlashCommandEnumValue } from './slash-commands/SlashCommandE | ||
| 16 | 16 | import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; |
| 17 | 17 | import { textgen_types, textgenerationwebui_settings } from './textgen-settings.js'; |
| 18 | 18 | import { applyStreamFadeIn } from './util/stream-fadein.js'; |
| 19 | 19 | import { copyText, escapeRegex, isFalseBoolean, isTrueBoolean, setDatasetProperty, stringToRange, trimSpaces } from './utils.js'; |
| 20 | 20 | |
| 21 | 21 | /** |
| 22 | 22 | * @typedef {object} ReasoningTemplate |
| @@ -1045,6 +1045,80 @@ function registerReasoningSlashCommands() { | ||
| 1045 | 1045 | </div> |
| 1046 | 1046 | `, |
| 1047 | 1047 | })); |
| 1048 | + | |
| 1049 | + /** | |
| 1050 | + * Gets the reasoning details elements for a message range. | |
| 1051 | + * @param {string} value Unnamed argument value (message ID or range) | |
| 1052 | + * @returns {JQuery<HTMLElement>|null} The reasoning details elements, or null if not found | |
| 1053 | + */ | |
| 1054 | + function getReasoningDetailsElements(value) { | |
| 1055 | + const range = value ? stringToRange(String(value), 0, chat.length - 1) : { start: chat.length - 1, end: chat.length - 1 }; | |
| 1056 | + if (!range) { | |
| 1057 | + toastr.warning(t`Invalid message ID or range: ${value}`); | |
| 1058 | + return null; | |
| 1059 | + } | |
| 1060 | + const selector = Array.from({ length: range.end - range.start + 1 }, (_, i) => | |
| 1061 | + `#chat [mesid="${range.start + i}"] .mes_reasoning_details`, | |
| 1062 | + ).join(','); | |
| 1063 | + const details = $(selector); | |
| 1064 | + if (details.length === 0) { | |
| 1065 | + toastr.warning(t`No reasoning blocks found for the specified messages.`); | |
| 1066 | + return null; | |
| 1067 | + } | |
| 1068 | + return details; | |
| 1069 | + } | |
| 1070 | + | |
| 1071 | + const reasoningVisibilityArgs = [ | |
| 1072 | + SlashCommandArgument.fromProps({ | |
| 1073 | + description: 'Message ID or range (e.g. 0-10). If not provided, the last message is used.', | |
| 1074 | + typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE], | |
| 1075 | + enumProvider: commonEnumProviders.messages(), | |
| 1076 | + }), | |
| 1077 | + ]; | |
| 1078 | + | |
| 1079 | + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | |
| 1080 | + name: 'reasoning-collapse', | |
| 1081 | + aliases: ['collapse-reasoning'], | |
| 1082 | + helpString: t`Collapse the reasoning block of a message or range of messages.`, | |
| 1083 | + unnamedArgumentList: reasoningVisibilityArgs, | |
| 1084 | + callback: (_args, value) => { | |
| 1085 | + const details = getReasoningDetailsElements(value); | |
| 1086 | + if (details) details.removeAttr('open'); | |
| 1087 | + return ''; | |
| 1088 | + }, | |
| 1089 | + })); | |
| 1090 | + | |
| 1091 | + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | |
| 1092 | + name: 'reasoning-expand', | |
| 1093 | + aliases: ['expand-reasoning'], | |
| 1094 | + helpString: t`Expand the reasoning block of a message or range of messages.`, | |
| 1095 | + unnamedArgumentList: reasoningVisibilityArgs, | |
| 1096 | + callback: (_args, value) => { | |
| 1097 | + const details = getReasoningDetailsElements(value); | |
| 1098 | + if (details) details.attr('open', ''); | |
| 1099 | + return ''; | |
| 1100 | + }, | |
| 1101 | + })); | |
| 1102 | + | |
| 1103 | + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | |
| 1104 | + name: 'reasoning-toggle', | |
| 1105 | + aliases: ['toggle-reasoning'], | |
| 1106 | + helpString: t`Toggle the reasoning block of a message or range of messages. Expanded blocks will be collapsed, and collapsed blocks will be expanded.`, | |
| 1107 | + unnamedArgumentList: reasoningVisibilityArgs, | |
| 1108 | + callback: (_args, value) => { | |
| 1109 | + const details = getReasoningDetailsElements(value); | |
| 1110 | + if (!details) return ''; | |
| 1111 | + details.each(function () { | |
| 1112 | + const $el = $(this); | |
| 1113 | + if ($el.attr('open') !== undefined) { | |
| 1114 | + $el.removeAttr('open'); | |
| 1115 | + } else { | |
| 1116 | + $el.attr('open', ''); | |
| 1117 | + } | |
| 1118 | + }); | |
| 1119 | + return ''; | |
| 1120 | + }, | |
| 1121 | + })); | |
| 1048 | 1122 | } |
| 1049 | 1123 | |
| 1050 | 1124 | function registerReasoningMacros() { |