Merge branch 'staging' into connection-manager

f4da527d95f817e0f5077a072e2e8254fa0137ba

Cohee <18619528+Cohee1207@users.noreply.github.com>

3 files changed, +106 -37Showing whitespace changes
public/index.html+21 -12
@@ -1916,17 +1916,26 @@
1916 <form action="javascript:void(null);" method="post" enctype="multipart/form-data">1916 <form action="javascript:void(null);" method="post" enctype="multipart/form-data">
1917 <div id="kobold_horde_block">1917 <div id="kobold_horde_block">
1918 <ul>1918 <ul>
1919 <li data-i18n="Avoid sending sensitive information to the Horde.">1919 <li>
1920 Avoid sending sensitive information to the Horde.1920 <a target="_blank" href="https://aihorde.net/" data-i18n="KoboldAI Horde Website">
1921 <a target="_blank" href="https://docs.sillytavern.app/usage/api-connections/horde/" data-i18n="Review the Privacy statement">Review the Privacy statement</a>1921 KoboldAI Horde Website
1922 </a>
1923 </li>
1924 <li>
1925 <span data-i18n="Avoid sending sensitive information to the Horde.">Avoid sending sensitive information to the Horde.</span>
1926 <a target="_blank" href="https://docs.sillytavern.app/usage/api-connections/horde/" data-i18n="Review the Privacy statement">
1927 Review the Privacy statement
1928 </a>
1922 </li>1929 </li>
1923 <li>1930 <li>
1924 <a target="_blank" href="https://horde.koboldai.net/register" data-i18n="Register a Horde account for faster queue times">Register a Horde1931 <a target="_blank" href="https://aihorde.net/register" data-i18n="Register a Horde account for faster queue times">
1925 account for faster queue times</a>1932 Register a Horde account for faster queue times
1933 </a>
1926 </li>1934 </li>
1927 <li>1935 <li>
1928 <a target="_blank" href="https://github.com/Haidra-Org/horde-worker-reGen?tab=readme-ov-file#ai-horde-worker-regen" data-i18n="Learn how to contribute your idle GPU cycles to the Horde">Learn1936 <a target="_blank" href="https://github.com/Haidra-Org/horde-worker-reGen?tab=readme-ov-file#ai-horde-worker-regen" data-i18n="Learn how to contribute your idle GPU cycles to the Horde">
1929 how to contribute your idle GPU cycles to the Horde</a>1937 Learn how to contribute your idle GPU cycles to the Horde
1938 </a>
1930 </li>1939 </li>
1931 </ul>1940 </ul>
1932 <label for="horde_auto_adjust_context_length" class="checkbox_label">1941 <label for="horde_auto_adjust_context_length" class="checkbox_label">
@@ -1944,12 +1953,9 @@
1944 <small id="adjustedHordeParams">Context: --, Response: --</small>1953 <small id="adjustedHordeParams">Context: --, Response: --</small>
1945 <h4 data-i18n="API key">API key</h4>1954 <h4 data-i18n="API key">API key</h4>
1946 <small>1955 <small>
1947 <span data-i18n="Get it here:">Get it here: </span> <a target="_blank" href="https://horde.koboldai.net/register" data-i18n="Register">Register</a> (<a id="horde_kudos" href="javascript:void(0);" data-i18n="View my Kudos">View my Kudos</a>)<br>1956 <span data-i18n="Get it here:">Get it here: </span> <a target="_blank" href="https://aihorde.net/register" data-i18n="Register">Register</a> (<a id="horde_kudos" href="javascript:void(0);" data-i18n="View my Kudos">View my Kudos</a>)<br>
1948 <span data-i18n="Enter">Enter </span> <span class="monospace">0000000000</span> <span data-i18n="to use anonymous mode.">to use anonymous mode. </span>1957 <span data-i18n="Enter">Enter </span> <span class="monospace">0000000000</span> <span data-i18n="to use anonymous mode.">to use anonymous mode. </span>
1949 </small>1958 </small>
1950 <!-- <div>
1951 <a id="horde_kudos" href="javascript:void(0);">View my Kudos</a>
1952 </div> -->
1953 <div class="flex-container">1959 <div class="flex-container">
1954 <input id="horde_api_key" name="horde_api_key" class="text_pole flex1" type="text" placeholder="0000000000" autocomplete="off">1960 <input id="horde_api_key" name="horde_api_key" class="text_pole flex1" type="text" placeholder="0000000000" autocomplete="off">
1955 <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_horde"></div>1961 <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_horde"></div>
@@ -4333,7 +4339,10 @@
4333 </div>4339 </div>
4334 <div id="Backgrounds" class="drawer-content closedDrawer">4340 <div id="Backgrounds" class="drawer-content closedDrawer">
4335 <div class="flex-container">4341 <div class="flex-container">
4336 <div class="flex-container wide100p">4342 <div class="flex-container alignItemsBaseline wide100p">
4343 <h3 class="margin0 flex2" data-i18n="Background Image">
4344 Background Image
4345 </h3>
4337 <input id="bg-filter" data-i18n="[placeholder]Filter" placeholder="Filter" class="text_pole flex1" type="search" />4346 <input id="bg-filter" data-i18n="[placeholder]Filter" placeholder="Filter" class="text_pole flex1" type="search" />
4338 <div id="auto_background" class="menu_button menu_button_icon" data-i18n="[title]Automatically select a background based on the chat context" title="Automatically select a background based on the chat context.">4347 <div id="auto_background" class="menu_button menu_button_icon" data-i18n="[title]Automatically select a background based on the chat context" title="Automatically select a background based on the chat context.">
4339 <i class="fa-solid fa-wand-magic"></i>4348 <i class="fa-solid fa-wand-magic"></i>
public/scripts/popup.js+2 -2
@@ -92,7 +92,7 @@ const showPopupHelper = {
92 * @param {string?} header - The header text for the popup.92 * @param {string?} header - The header text for the popup.
93 * @param {string?} text - The main text for the popup.93 * @param {string?} text - The main text for the popup.
94 * @param {PopupOptions} [popupOptions={}] - Options for the popup.94 * @param {PopupOptions} [popupOptions={}] - Options for the popup.
95 * @return {Promise<POPUP_RESULT>} A Promise that resolves with the result of the user's interaction.95 * @return {Promise<POPUP_RESULT?>} A Promise that resolves with the result of the user's interaction.
96 */96 */
97 confirm: async (header, text, popupOptions = {}) => {97 confirm: async (header, text, popupOptions = {}) => {
98 const content = PopupUtils.BuildTextWithHeader(header, text);98 const content = PopupUtils.BuildTextWithHeader(header, text);
@@ -107,7 +107,7 @@ const showPopupHelper = {
107 * @param {string?} header - The header text for the popup.107 * @param {string?} header - The header text for the popup.
108 * @param {string?} text - The main text for the popup.108 * @param {string?} text - The main text for the popup.
109 * @param {PopupOptions} [popupOptions={}] - Options for the popup.109 * @param {PopupOptions} [popupOptions={}] - Options for the popup.
110 * @return {Promise<POPUP_RESULT>} A Promise that resolves with the result of the user's interaction.110 * @return {Promise<POPUP_RESULT?>} A Promise that resolves with the result of the user's interaction.
111 */111 */
112 text: async (header, text, popupOptions = {}) => {112 text: async (header, text, popupOptions = {}) => {
113 const content = PopupUtils.BuildTextWithHeader(header, text);113 const content = PopupUtils.BuildTextWithHeader(header, text);
public/scripts/slash-commands.js+83 -23
@@ -1267,20 +1267,59 @@ export function initDefaultSlashCommands() {
1267 callback: popupCallback,1267 callback: popupCallback,
1268 returns: 'popup text',1268 returns: 'popup text',
1269 namedArgumentList: [1269 namedArgumentList: [
1270 new SlashCommandNamedArgument(1270 SlashCommandNamedArgument.fromProps({
1271 'large', 'show large popup', [ARGUMENT_TYPE.BOOLEAN], false, false, null, commonEnumProviders.boolean('onOff')(),1271 name: 'large',
1272 ),1272 description: 'show large popup',
1273 new SlashCommandNamedArgument(1273 typeList: [ARGUMENT_TYPE.BOOLEAN],
1274 'wide', 'show wide popup', [ARGUMENT_TYPE.BOOLEAN], false, false, null, commonEnumProviders.boolean('onOff')(),1274 enumList: commonEnumProviders.boolean('trueFalse')(),
1275 ),1275 defaultValue: 'false',
1276 new SlashCommandNamedArgument(1276 }),
1277 'okButton', 'text for the OK button', [ARGUMENT_TYPE.STRING], false,1277 SlashCommandNamedArgument.fromProps({
1278 ),1278 name: 'wide',
1279 description: 'show wide popup',
1280 typeList: [ARGUMENT_TYPE.BOOLEAN],
1281 enumList: commonEnumProviders.boolean('trueFalse')(),
1282 defaultValue: 'false',
1283 }),
1284 SlashCommandNamedArgument.fromProps({
1285 name: 'wider',
1286 description: 'show wider popup',
1287 typeList: [ARGUMENT_TYPE.BOOLEAN],
1288 enumList: commonEnumProviders.boolean('trueFalse')(),
1289 defaultValue: 'false',
1290 }),
1291 SlashCommandNamedArgument.fromProps({
1292 name: 'transparent',
1293 description: 'show transparent popup',
1294 typeList: [ARGUMENT_TYPE.BOOLEAN],
1295 enumList: commonEnumProviders.boolean('trueFalse')(),
1296 defaultValue: 'false',
1297 }),
1298 SlashCommandNamedArgument.fromProps({
1299 name: 'okButton',
1300 description: 'text for the OK button',
1301 typeList: [ARGUMENT_TYPE.STRING],
1302 defaultValue: 'OK',
1303 }),
1304 SlashCommandNamedArgument.fromProps({
1305 name: 'cancelButton',
1306 description: 'text for the Cancel button',
1307 typeList: [ARGUMENT_TYPE.STRING],
1308 }),
1309 SlashCommandNamedArgument.fromProps({
1310 name: 'result',
1311 description: 'if enabled, returns the popup result (as an integer) instead of the popup text. Resolves to 1 for OK and 0 cancel button, empty string for exiting out.',
1312 typeList: [ARGUMENT_TYPE.BOOLEAN],
1313 enumList: commonEnumProviders.boolean('trueFalse')(),
1314 defaultValue: 'false',
1315 }),
1279 ],1316 ],
1280 unnamedArgumentList: [1317 unnamedArgumentList: [
1281 new SlashCommandArgument(1318 SlashCommandArgument.fromProps({
1282 'text', [ARGUMENT_TYPE.STRING], true,1319 description: 'popup text',
1283 ),1320 typeList: [ARGUMENT_TYPE.STRING],
1321 isRequired: true,
1322 }),
1284 ],1323 ],
1285 helpString: `1324 helpString: `
1286 <div>1325 <div>
@@ -1291,7 +1330,10 @@ export function initDefaultSlashCommands() {
1291 <strong>Example:</strong>1330 <strong>Example:</strong>
1292 <ul>1331 <ul>
1293 <li>1332 <li>
1294 <pre><code>/popup large=on wide=on okButton="Submit" Enter some text:</code></pre>1333 <pre><code>/popup large=on wide=on okButton="Confirm" Please confirm this action.</code></pre>
1334 </li>
1335 <li>
1336 <pre><code>/popup okButton="Left" cancelButton="Right" result=true Do you want to go left or right? | /echo 0 means right, 1 means left. Choice: {{pipe}}</code></pre>
1295 </li>1337 </li>
1296 </ul>1338 </ul>
1297 </div>1339 </div>
@@ -1574,6 +1616,13 @@ export function initDefaultSlashCommands() {
1574 defaultValue: 'true',1616 defaultValue: 'true',
1575 enumList: commonEnumProviders.boolean('trueFalse')(),1617 enumList: commonEnumProviders.boolean('trueFalse')(),
1576 }),1618 }),
1619 SlashCommandNamedArgument.fromProps({
1620 name: 'quiet',
1621 description: 'suppress the toast message on API change',
1622 typeList: [ARGUMENT_TYPE.BOOLEAN],
1623 defaultValue: 'false',
1624 enumList: commonEnumProviders.boolean('trueFalse')(),
1625 }),
1577 ],1626 ],
1578 unnamedArgumentList: [1627 unnamedArgumentList: [
1579 SlashCommandArgument.fromProps({1628 SlashCommandArgument.fromProps({
@@ -1882,16 +1931,21 @@ async function buttonsCallback(args, text) {
1882}1931}
18831932
1884async function popupCallback(args, value) {1933async function popupCallback(args, value) {
1885 const safeValue = DOMPurify.sanitize(value || '');1934 const safeBody = DOMPurify.sanitize(value || '');
1935 const safeHeader = args?.header && typeof args?.header === 'string' ? DOMPurify.sanitize(args.header) : null;
1936 const requestedResult = isTrueBoolean(args?.result);
1937
1938 /** @type {import('./popup.js').PopupOptions} */
1886 const popupOptions = {1939 const popupOptions = {
1887 large: isTrueBoolean(args?.large),1940 large: isTrueBoolean(args?.large),
1888 wide: isTrueBoolean(args?.wide),1941 wide: isTrueBoolean(args?.wide),
1942 wider: isTrueBoolean(args?.wider),
1943 transparent: isTrueBoolean(args?.transparent),
1889 okButton: args?.okButton !== undefined && typeof args?.okButton === 'string' ? args.okButton : 'Ok',1944 okButton: args?.okButton !== undefined && typeof args?.okButton === 'string' ? args.okButton : 'Ok',
1945 cancelButton: args?.cancelButton !== undefined && typeof args?.cancelButton === 'string' ? args.cancelButton : null,
1890 };1946 };
1891 await delay(1);1947 const result = await Popup.show.text(safeHeader, safeBody, popupOptions);
1892 await callGenericPopup(safeValue, POPUP_TYPE.TEXT, '', popupOptions);1948 return String(requestedResult ? result ?? '' : value);
1893 await delay(1);
1894 return String(value);
1895}1949}
18961950
1897async function getMessagesCallback(args, value) {1951async function getMessagesCallback(args, value) {
@@ -3530,10 +3584,12 @@ function setPromptEntryCallback(args, targetState) {
3530 * @param {object} args - named args3584 * @param {object} args - named args
3531 * @param {string?} [args.api=null] - the API name to set/get the URL for3585 * @param {string?} [args.api=null] - the API name to set/get the URL for
3532 * @param {string?} [args.connect=true] - whether to connect to the API after setting3586 * @param {string?} [args.connect=true] - whether to connect to the API after setting
3587 * @param {string?} [args.quiet=false] - whether to suppress toasts
3533 * @param {string} url - the API URL to set3588 * @param {string} url - the API URL to set
3534 * @returns {Promise<string>}3589 * @returns {Promise<string>}
3535 */3590 */
3536async function setApiUrlCallback({ api = null, connect = 'true' }, url) {3591async function setApiUrlCallback({ api = null, connect = 'true', quiet = 'false' }, url) {
3592 const isQuiet = isTrueBoolean(quiet);
3537 const autoConnect = isTrueBoolean(connect);3593 const autoConnect = isTrueBoolean(connect);
35383594
3539 // Special handling for Chat Completion Custom OpenAI compatible, that one can also support API url handling3595 // Special handling for Chat Completion Custom OpenAI compatible, that one can also support API url handling
@@ -3582,22 +3638,26 @@ async function setApiUrlCallback({ api = null, connect = 'true' }, url) {
35823638
3583 // Do some checks and get the api type we are targeting with this command3639 // Do some checks and get the api type we are targeting with this command
3584 if (api && !Object.values(textgen_types).includes(api)) {3640 if (api && !Object.values(textgen_types).includes(api)) {
3585 toastr.warning(`API '${api}' is not a valid text_gen API.`);3641 !isQuiet && toastr.warning(`API '${api}' is not a valid text_gen API.`);
3586 return '';3642 return '';
3587 }3643 }
3588 if (!api && !Object.values(textgen_types).includes(textgenerationwebui_settings.type)) {3644 if (!api && !Object.values(textgen_types).includes(textgenerationwebui_settings.type)) {
3589 toastr.warning(`API '${textgenerationwebui_settings.type}' is not a valid text_gen API.`);3645 !isQuiet && toastr.warning(`API '${textgenerationwebui_settings.type}' is not a valid text_gen API.`);
3646 return '';
3647 }
3648 if (!api && main_api !== 'textgenerationwebui') {
3649 !isQuiet && toastr.warning(`API type '${main_api}' does not support setting the server URL.`);
3590 return '';3650 return '';
3591 }3651 }
3592 if (api && url && autoConnect && api !== textgenerationwebui_settings.type) {3652 if (api && url && autoConnect && api !== textgenerationwebui_settings.type) {
3593 toastr.warning(`API '${api}' is not the currently selected API, so we cannot do an auto-connect. Consider switching to it via /api beforehand.`);3653 !isQuiet && toastr.warning(`API '${api}' is not the currently selected API, so we cannot do an auto-connect. Consider switching to it via /api beforehand.`);
3594 return '';3654 return '';
3595 }3655 }
3596 const type = api || textgenerationwebui_settings.type;3656 const type = api || textgenerationwebui_settings.type;
35973657
3598 const inputSelector = SERVER_INPUTS[type];3658 const inputSelector = SERVER_INPUTS[type];
3599 if (!inputSelector) {3659 if (!inputSelector) {
3600 toastr.warning(`API '${type}' does not have a server url input.`);3660 !isQuiet && toastr.warning(`API '${type}' does not have a server url input.`);
3601 return '';3661 return '';
3602 }3662 }
36033663