Merge branch 'staging' into google-tts
| @@ -21,6 +21,15 @@ module.exports = { | |||
| 21 | }, | 21 | }, |
| 22 | }, | 22 | }, |
| 23 | { | 23 | { |
| 24 | files: ['*.cjs'], | ||
| 25 | parserOptions: { | ||
| 26 | sourceType: 'commonjs', | ||
| 27 | }, | ||
| 28 | env: { | ||
| 29 | node: true, | ||
| 30 | }, | ||
| 31 | }, | ||
| 32 | { | ||
| 24 | files: ['src/**/*.mjs'], | 33 | files: ['src/**/*.mjs'], |
| 25 | parserOptions: { | 34 | parserOptions: { |
| 26 | sourceType: 'module', | 35 | sourceType: 'module', |
| @@ -74,6 +83,7 @@ module.exports = { | |||
| 74 | 'docker/**', | 83 | 'docker/**', |
| 75 | 'plugins/**', | 84 | 'plugins/**', |
| 76 | '**/*.min.js', | 85 | '**/*.min.js', |
| 86 | 'public/scripts/extensions/quick-reply/lib/**', | ||
| 77 | ], | 87 | ], |
| 78 | rules: { | 88 | rules: { |
| 79 | 'no-unused-vars': ['error', { args: 'none' }], | 89 | 'no-unused-vars': ['error', { args: 'none' }], |
| @@ -12,7 +12,8 @@ | |||
| 12 | "**/dist/**", | 12 | "**/dist/**", |
| 13 | "**/.git/**", | 13 | "**/.git/**", |
| 14 | "lib/**", | 14 | "lib/**", |
| 15 | "**/*.min.js" | 15 | "**/*.min.js", |
| 16 | "scripts/extensions/quick-reply/lib/**" | ||
| 16 | ], | 17 | ], |
| 17 | "typeAcquisition": { | 18 | "typeAcquisition": { |
| 18 | "include": [ | 19 | "include": [ |
| @@ -7,7 +7,6 @@ import { | |||
| 7 | event_types, | 7 | event_types, |
| 8 | eventSource, | 8 | eventSource, |
| 9 | getCharacters, | 9 | getCharacters, |
| 10 | getPastCharacterChats, | ||
| 11 | getRequestHeaders, | 10 | getRequestHeaders, |
| 12 | buildAvatarList, | 11 | buildAvatarList, |
| 13 | characterToEntity, | 12 | characterToEntity, |
| @@ -315,7 +315,7 @@ class PromptManager { | |||
| 315 | */ | 315 | */ |
| 316 | init(moduleConfiguration, serviceSettings) { | 316 | init(moduleConfiguration, serviceSettings) { |
| 317 | this.configuration = Object.assign(this.configuration, moduleConfiguration); | 317 | this.configuration = Object.assign(this.configuration, moduleConfiguration); |
| 318 | this.tokenHandler = this.tokenHandler || new TokenHandler(); | 318 | this.tokenHandler = this.tokenHandler || new TokenHandler(() => { throw new Error('Token handler not set'); }); |
| 319 | this.serviceSettings = serviceSettings; | 319 | this.serviceSettings = serviceSettings; |
| 320 | this.containerElement = document.getElementById(this.configuration.containerIdentifier); | 320 | this.containerElement = document.getElementById(this.configuration.containerIdentifier); |
| 321 | 321 | ||
| @@ -148,7 +148,7 @@ export function initDynamicStyles() { | |||
| 148 | // Start observing the head for any new added stylesheets | 148 | // Start observing the head for any new added stylesheets |
| 149 | observer.observe(document.head, { | 149 | observer.observe(document.head, { |
| 150 | childList: true, | 150 | childList: true, |
| 151 | subtree: true | 151 | subtree: true, |
| 152 | }); | 152 | }); |
| 153 | 153 | ||
| 154 | // Process all stylesheets on initial load | 154 | // Process all stylesheets on initial load |
| @@ -1,6 +1,6 @@ | |||
| 1 | import { ensureImageFormatSupported, getBase64Async, isTrueBoolean, saveBase64AsFile } from '../../utils.js'; | 1 | import { ensureImageFormatSupported, getBase64Async, isTrueBoolean, saveBase64AsFile } from '../../utils.js'; |
| 2 | import { getContext, getApiUrl, doExtrasFetch, extension_settings, modules, renderExtensionTemplateAsync } from '../../extensions.js'; | 2 | import { getContext, getApiUrl, doExtrasFetch, extension_settings, modules, renderExtensionTemplateAsync } from '../../extensions.js'; |
| 3 | import { appendMediaToMessage, callPopup, eventSource, event_types, getRequestHeaders, main_api, saveChatConditional, saveSettingsDebounced, substituteParamsExtended } from '../../../script.js'; | 3 | import { appendMediaToMessage, callPopup, eventSource, event_types, getRequestHeaders, saveChatConditional, saveSettingsDebounced, substituteParamsExtended } from '../../../script.js'; |
| 4 | import { getMessageTimeStamp } from '../../RossAscends-mods.js'; | 4 | import { getMessageTimeStamp } from '../../RossAscends-mods.js'; |
| 5 | import { SECRET_KEYS, secret_state } from '../../secrets.js'; | 5 | import { SECRET_KEYS, secret_state } from '../../secrets.js'; |
| 6 | import { getMultimodalCaption } from '../shared.js'; | 6 | import { getMultimodalCaption } from '../shared.js'; |
| @@ -1,8 +1,6 @@ | |||
| 1 | import { | 1 | import { |
| 2 | saveSettingsDebounced, | 2 | saveSettingsDebounced, |
| 3 | systemUserName, | 3 | systemUserName, |
| 4 | hideSwipeButtons, | ||
| 5 | showSwipeButtons, | ||
| 6 | getRequestHeaders, | 4 | getRequestHeaders, |
| 7 | event_types, | 5 | event_types, |
| 8 | eventSource, | 6 | eventSource, |
| @@ -2210,7 +2208,7 @@ function processReply(str) { | |||
| 2210 | str = str.replaceAll('“', ''); | 2208 | str = str.replaceAll('“', ''); |
| 2211 | str = str.replaceAll('\n', ', '); | 2209 | str = str.replaceAll('\n', ', '); |
| 2212 | str = str.normalize('NFD'); | 2210 | str = str.normalize('NFD'); |
| 2213 | str = str.replace(/[^a-zA-Z0-9\.,:_(){}<>[\]\-']+/g, ' '); | 2211 | str = str.replace(/[^a-zA-Z0-9.,:_(){}<>[\]\-']+/g, ' '); |
| 2214 | str = str.replace(/\s+/g, ' '); // Collapse multiple whitespaces into one | 2212 | str = str.replace(/\s+/g, ' '); // Collapse multiple whitespaces into one |
| 2215 | str = str.trim(); | 2213 | str = str.trim(); |
| 2216 | 2214 | ||
| @@ -183,9 +183,9 @@ function redirectToHome() { | |||
| 183 | // After a login theres no need to preserve the | 183 | // After a login theres no need to preserve the |
| 184 | // noauto (if present) | 184 | // noauto (if present) |
| 185 | const urlParams = new URLSearchParams(window.location.search); | 185 | const urlParams = new URLSearchParams(window.location.search); |
| 186 | 186 | ||
| 187 | urlParams.delete('noauto'); | 187 | urlParams.delete('noauto'); |
| 188 | 188 | ||
| 189 | window.location.href = '/' + urlParams.toString(); | 189 | window.location.href = '/' + urlParams.toString(); |
| 190 | } | 190 | } |
| 191 | 191 | ||
| @@ -464,7 +464,7 @@ export function evaluateMacros(content, env) { | |||
| 464 | content = content.replace(/{{firstIncludedMessageId}}/gi, () => String(getFirstIncludedMessageId() ?? '')); | 464 | content = content.replace(/{{firstIncludedMessageId}}/gi, () => String(getFirstIncludedMessageId() ?? '')); |
| 465 | content = content.replace(/{{lastSwipeId}}/gi, () => String(getLastSwipeId() ?? '')); | 465 | content = content.replace(/{{lastSwipeId}}/gi, () => String(getLastSwipeId() ?? '')); |
| 466 | content = content.replace(/{{currentSwipeId}}/gi, () => String(getCurrentSwipeId() ?? '')); | 466 | content = content.replace(/{{currentSwipeId}}/gi, () => String(getCurrentSwipeId() ?? '')); |
| 467 | content = content.replace(/{{reverse\:(.+?)}}/gi, (_, str) => Array.from(str).reverse().join('')); | 467 | content = content.replace(/{{reverse:(.+?)}}/gi, (_, str) => Array.from(str).reverse().join('')); |
| 468 | 468 | ||
| 469 | content = content.replace(/\{\{\/\/([\s\S]*?)\}\}/gm, ''); | 469 | content = content.replace(/\{\{\/\/([\s\S]*?)\}\}/gm, ''); |
| 470 | 470 | ||
| @@ -60,7 +60,7 @@ import { | |||
| 60 | resetScrollHeight, | 60 | resetScrollHeight, |
| 61 | stringFormat, | 61 | stringFormat, |
| 62 | } from './utils.js'; | 62 | } from './utils.js'; |
| 63 | import { countTokensOpenAI, getTokenizerModel } from './tokenizers.js'; | 63 | import { countTokensOpenAIAsync, getTokenizerModel } from './tokenizers.js'; |
| 64 | import { isMobile } from './RossAscends-mods.js'; | 64 | import { isMobile } from './RossAscends-mods.js'; |
| 65 | import { saveLogprobsForActiveMessage } from './logprobs.js'; | 65 | import { saveLogprobsForActiveMessage } from './logprobs.js'; |
| 66 | import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; | 66 | import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; |
| @@ -671,14 +671,14 @@ async function populateChatHistory(messages, prompts, chatCompletion, type = nul | |||
| 671 | 671 | ||
| 672 | // Reserve budget for new chat message | 672 | // Reserve budget for new chat message |
| 673 | const newChat = selected_group ? oai_settings.new_group_chat_prompt : oai_settings.new_chat_prompt; | 673 | const newChat = selected_group ? oai_settings.new_group_chat_prompt : oai_settings.new_chat_prompt; |
| 674 | const newChatMessage = new Message('system', substituteParams(newChat), 'newMainChat'); | 674 | const newChatMessage = await Message.createAsync('system', substituteParams(newChat), 'newMainChat'); |
| 675 | chatCompletion.reserveBudget(newChatMessage); | 675 | chatCompletion.reserveBudget(newChatMessage); |
| 676 | 676 | ||
| 677 | // Reserve budget for group nudge | 677 | // Reserve budget for group nudge |
| 678 | let groupNudgeMessage = null; | 678 | let groupNudgeMessage = null; |
| 679 | const noGroupNudgeTypes = ['impersonate']; | 679 | const noGroupNudgeTypes = ['impersonate']; |
| 680 | if (selected_group && prompts.has('groupNudge') && !noGroupNudgeTypes.includes(type)) { | 680 | if (selected_group && prompts.has('groupNudge') && !noGroupNudgeTypes.includes(type)) { |
| 681 | groupNudgeMessage = Message.fromPrompt(prompts.get('groupNudge')); | 681 | groupNudgeMessage = await Message.fromPromptAsync(prompts.get('groupNudge')); |
| 682 | chatCompletion.reserveBudget(groupNudgeMessage); | 682 | chatCompletion.reserveBudget(groupNudgeMessage); |
| 683 | } | 683 | } |
| 684 | 684 | ||
| @@ -693,12 +693,12 @@ async function populateChatHistory(messages, prompts, chatCompletion, type = nul | |||
| 693 | }; | 693 | }; |
| 694 | const continuePrompt = new Prompt(promptObject); | 694 | const continuePrompt = new Prompt(promptObject); |
| 695 | const preparedPrompt = promptManager.preparePrompt(continuePrompt); | 695 | const preparedPrompt = promptManager.preparePrompt(continuePrompt); |
| 696 | continueMessage = Message.fromPrompt(preparedPrompt); | 696 | continueMessage = await Message.fromPromptAsync(preparedPrompt); |
| 697 | chatCompletion.reserveBudget(continueMessage); | 697 | chatCompletion.reserveBudget(continueMessage); |
| 698 | } | 698 | } |
| 699 | 699 | ||
| 700 | const lastChatPrompt = messages[messages.length - 1]; | 700 | const lastChatPrompt = messages[messages.length - 1]; |
| 701 | const message = new Message('user', oai_settings.send_if_empty, 'emptyUserMessageReplacement'); | 701 | const message = await Message.createAsync('user', oai_settings.send_if_empty, 'emptyUserMessageReplacement'); |
| 702 | if (lastChatPrompt && lastChatPrompt.role === 'assistant' && oai_settings.send_if_empty && chatCompletion.canAfford(message)) { | 702 | if (lastChatPrompt && lastChatPrompt.role === 'assistant' && oai_settings.send_if_empty && chatCompletion.canAfford(message)) { |
| 703 | chatCompletion.insert(message, 'chatHistory'); | 703 | chatCompletion.insert(message, 'chatHistory'); |
| 704 | } | 704 | } |
| @@ -715,11 +715,11 @@ async function populateChatHistory(messages, prompts, chatCompletion, type = nul | |||
| 715 | // We do not want to mutate the prompt | 715 | // We do not want to mutate the prompt |
| 716 | const prompt = new Prompt(chatPrompt); | 716 | const prompt = new Prompt(chatPrompt); |
| 717 | prompt.identifier = `chatHistory-${messages.length - index}`; | 717 | prompt.identifier = `chatHistory-${messages.length - index}`; |
| 718 | const chatMessage = Message.fromPrompt(promptManager.preparePrompt(prompt)); | 718 | const chatMessage = await Message.fromPromptAsync(promptManager.preparePrompt(prompt)); |
| 719 | 719 | ||
| 720 | if (promptManager.serviceSettings.names_behavior === character_names_behavior.COMPLETION && prompt.name) { | 720 | if (promptManager.serviceSettings.names_behavior === character_names_behavior.COMPLETION && prompt.name) { |
| 721 | const messageName = promptManager.isValidName(prompt.name) ? prompt.name : promptManager.sanitizeName(prompt.name); | 721 | const messageName = promptManager.isValidName(prompt.name) ? prompt.name : promptManager.sanitizeName(prompt.name); |
| 722 | chatMessage.setName(messageName); | 722 | await chatMessage.setName(messageName); |
| 723 | } | 723 | } |
| 724 | 724 | ||
| 725 | if (imageInlining && chatPrompt.image) { | 725 | if (imageInlining && chatPrompt.image) { |
| @@ -729,9 +729,9 @@ async function populateChatHistory(messages, prompts, chatCompletion, type = nul | |||
| 729 | if (canUseTools && Array.isArray(chatPrompt.invocations)) { | 729 | if (canUseTools && Array.isArray(chatPrompt.invocations)) { |
| 730 | /** @type {import('./tool-calling.js').ToolInvocation[]} */ | 730 | /** @type {import('./tool-calling.js').ToolInvocation[]} */ |
| 731 | const invocations = chatPrompt.invocations; | 731 | const invocations = chatPrompt.invocations; |
| 732 | const toolCallMessage = new Message(chatMessage.role, undefined, 'toolCall-' + chatMessage.identifier); | 732 | const toolCallMessage = await Message.createAsync(chatMessage.role, undefined, 'toolCall-' + chatMessage.identifier); |
| 733 | const toolResultMessages = invocations.slice().reverse().map((invocation) => new Message('tool', invocation.result || '[No content]', invocation.id)); | 733 | const toolResultMessages = await Promise.all(invocations.slice().reverse().map((invocation) => Message.createAsync('tool', invocation.result || '[No content]', invocation.id))); |
| 734 | toolCallMessage.setToolCalls(invocations); | 734 | await toolCallMessage.setToolCalls(invocations); |
| 735 | if (chatCompletion.canAffordAll([toolCallMessage, ...toolResultMessages])) { | 735 | if (chatCompletion.canAffordAll([toolCallMessage, ...toolResultMessages])) { |
| 736 | for (const resultMessage of toolResultMessages) { | 736 | for (const resultMessage of toolResultMessages) { |
| 737 | chatCompletion.insertAtStart(resultMessage, 'chatHistory'); | 737 | chatCompletion.insertAtStart(resultMessage, 'chatHistory'); |
| @@ -748,7 +748,8 @@ async function populateChatHistory(messages, prompts, chatCompletion, type = nul | |||
| 748 | if (type === 'continue' && oai_settings.continue_prefill && chatPrompt === firstNonInjected) { | 748 | if (type === 'continue' && oai_settings.continue_prefill && chatPrompt === firstNonInjected) { |
| 749 | // in case we are using continue_prefill and the latest message is an assistant message, we want to prepend the users assistant prefill on the message | 749 | // in case we are using continue_prefill and the latest message is an assistant message, we want to prepend the users assistant prefill on the message |
| 750 | if (chatPrompt.role === 'assistant') { | 750 | if (chatPrompt.role === 'assistant') { |
| 751 | const collection = new MessageCollection('continuePrefill', new Message(chatMessage.role, substituteParams(oai_settings.assistant_prefill + '\n\n') + chatMessage.content, chatMessage.identifier)); | 751 | const continueMessage = await Message.createAsync(chatMessage.role, substituteParams(oai_settings.assistant_prefill + '\n\n') + chatMessage.content, chatMessage.identifier); |
| 752 | const collection = new MessageCollection('continuePrefill', continueMessage); | ||
| 752 | chatCompletion.add(collection, -1); | 753 | chatCompletion.add(collection, -1); |
| 753 | continue; | 754 | continue; |
| 754 | } | 755 | } |
| @@ -787,18 +788,17 @@ async function populateChatHistory(messages, prompts, chatCompletion, type = nul | |||
| 787 | * @param {ChatCompletion} chatCompletion - An instance of ChatCompletion class that will be populated with the prompts. | 788 | * @param {ChatCompletion} chatCompletion - An instance of ChatCompletion class that will be populated with the prompts. |
| 788 | * @param {Object[]} messageExamples - Array containing all message examples. | 789 | * @param {Object[]} messageExamples - Array containing all message examples. |
| 789 | */ | 790 | */ |
| 790 | function populateDialogueExamples(prompts, chatCompletion, messageExamples) { | 791 | async function populateDialogueExamples(prompts, chatCompletion, messageExamples) { |
| 791 | if (!prompts.has('dialogueExamples')) { | 792 | if (!prompts.has('dialogueExamples')) { |
| 792 | return; | 793 | return; |
| 793 | } | 794 | } |
| 794 | 795 | ||
| 795 | chatCompletion.add(new MessageCollection('dialogueExamples'), prompts.index('dialogueExamples')); | 796 | chatCompletion.add(new MessageCollection('dialogueExamples'), prompts.index('dialogueExamples')); |
| 796 | if (Array.isArray(messageExamples) && messageExamples.length) { | 797 | if (Array.isArray(messageExamples) && messageExamples.length) { |
| 797 | const newExampleChat = new Message('system', substituteParams(oai_settings.new_example_chat_prompt), 'newChat'); | 798 | const newExampleChat = await Message.createAsync('system', substituteParams(oai_settings.new_example_chat_prompt), 'newChat'); |
| 798 | [...messageExamples].forEach((dialogue, dialogueIndex) => { | 799 | for (const dialogue of [...messageExamples]) { |
| 799 | let examplesAdded = 0; | 800 | const dialogueIndex = messageExamples.indexOf(dialogue); |
| 800 | 801 | const chatMessages = []; | |
| 801 | if (chatCompletion.canAfford(newExampleChat)) chatCompletion.insert(newExampleChat, 'dialogueExamples'); | ||
| 802 | 802 | ||
| 803 | for (let promptIndex = 0; promptIndex < dialogue.length; promptIndex++) { | 803 | for (let promptIndex = 0; promptIndex < dialogue.length; promptIndex++) { |
| 804 | const prompt = dialogue[promptIndex]; | 804 | const prompt = dialogue[promptIndex]; |
| @@ -806,19 +806,20 @@ function populateDialogueExamples(prompts, chatCompletion, messageExamples) { | |||
| 806 | const content = prompt.content || ''; | 806 | const content = prompt.content || ''; |
| 807 | const identifier = `dialogueExamples ${dialogueIndex}-${promptIndex}`; | 807 | const identifier = `dialogueExamples ${dialogueIndex}-${promptIndex}`; |
| 808 | 808 | ||
| 809 | const chatMessage = new Message(role, content, identifier); | 809 | const chatMessage = await Message.createAsync(role, content, identifier); |
| 810 | chatMessage.setName(prompt.name); | 810 | await chatMessage.setName(prompt.name); |
| 811 | if (!chatCompletion.canAfford(chatMessage)) { | 811 | chatMessages.push(chatMessage); |
| 812 | break; | ||
| 813 | } | ||
| 814 | chatCompletion.insert(chatMessage, 'dialogueExamples'); | ||
| 815 | examplesAdded++; | ||
| 816 | } | 812 | } |
| 817 | 813 | ||
| 818 | if (0 === examplesAdded) { | 814 | if (!chatCompletion.canAffordAll([newExampleChat, ...chatMessages])) { |
| 819 | chatCompletion.removeLastFrom('dialogueExamples'); | 815 | break; |
| 820 | } | 816 | } |
| 821 | }); | 817 | |
| 818 | chatCompletion.insert(newExampleChat, 'dialogueExamples'); | ||
| 819 | for (const chatMessage of chatMessages) { | ||
| 820 | chatCompletion.insert(chatMessage, 'dialogueExamples'); | ||
| 821 | } | ||
| 822 | } | ||
| 822 | } | 823 | } |
| 823 | } | 824 | } |
| 824 | 825 | ||
| @@ -873,7 +874,7 @@ function getPromptRole(role) { | |||
| 873 | */ | 874 | */ |
| 874 | async function populateChatCompletion(prompts, chatCompletion, { bias, quietPrompt, quietImage, type, cyclePrompt, messages, messageExamples }) { | 875 | async function populateChatCompletion(prompts, chatCompletion, { bias, quietPrompt, quietImage, type, cyclePrompt, messages, messageExamples }) { |
| 875 | // Helper function for preparing a prompt, that already exists within the prompt collection, for completion | 876 | // Helper function for preparing a prompt, that already exists within the prompt collection, for completion |
| 876 | const addToChatCompletion = (source, target = null) => { | 877 | const addToChatCompletion = async (source, target = null) => { |
| 877 | // We need the prompts array to determine a position for the source. | 878 | // We need the prompts array to determine a position for the source. |
| 878 | if (false === prompts.has(source)) return; | 879 | if (false === prompts.has(source)) return; |
| 879 | 880 | ||
| @@ -891,30 +892,31 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | |||
| 891 | 892 | ||
| 892 | const index = target ? prompts.index(target) : prompts.index(source); | 893 | const index = target ? prompts.index(target) : prompts.index(source); |
| 893 | const collection = new MessageCollection(source); | 894 | const collection = new MessageCollection(source); |
| 894 | collection.add(Message.fromPrompt(prompt)); | 895 | const message = await Message.fromPromptAsync(prompt); |
| 896 | collection.add(message); | ||
| 895 | chatCompletion.add(collection, index); | 897 | chatCompletion.add(collection, index); |
| 896 | }; | 898 | }; |
| 897 | 899 | ||
| 898 | chatCompletion.reserveBudget(3); // every reply is primed with <|start|>assistant<|message|> | 900 | chatCompletion.reserveBudget(3); // every reply is primed with <|start|>assistant<|message|> |
| 899 | // Character and world information | 901 | // Character and world information |
| 900 | addToChatCompletion('worldInfoBefore'); | 902 | await addToChatCompletion('worldInfoBefore'); |
| 901 | addToChatCompletion('main'); | 903 | await addToChatCompletion('main'); |
| 902 | addToChatCompletion('worldInfoAfter'); | 904 | await addToChatCompletion('worldInfoAfter'); |
| 903 | addToChatCompletion('charDescription'); | 905 | await addToChatCompletion('charDescription'); |
| 904 | addToChatCompletion('charPersonality'); | 906 | await addToChatCompletion('charPersonality'); |
| 905 | addToChatCompletion('scenario'); | 907 | await addToChatCompletion('scenario'); |
| 906 | addToChatCompletion('personaDescription'); | 908 | await addToChatCompletion('personaDescription'); |
| 907 | 909 | ||
| 908 | // Collection of control prompts that will always be positioned last | 910 | // Collection of control prompts that will always be positioned last |
| 909 | chatCompletion.setOverriddenPrompts(prompts.overriddenPrompts); | 911 | chatCompletion.setOverriddenPrompts(prompts.overriddenPrompts); |
| 910 | const controlPrompts = new MessageCollection('controlPrompts'); | 912 | const controlPrompts = new MessageCollection('controlPrompts'); |
| 911 | 913 | ||
| 912 | const impersonateMessage = Message.fromPrompt(prompts.get('impersonate')) ?? null; | 914 | const impersonateMessage = await Message.fromPromptAsync(prompts.get('impersonate')) ?? null; |
| 913 | if (type === 'impersonate') controlPrompts.add(impersonateMessage); | 915 | if (type === 'impersonate') controlPrompts.add(impersonateMessage); |
| 914 | 916 | ||
| 915 | // Add quiet prompt to control prompts | 917 | // Add quiet prompt to control prompts |
| 916 | // This should always be last, even in control prompts. Add all further control prompts BEFORE this prompt | 918 | // This should always be last, even in control prompts. Add all further control prompts BEFORE this prompt |
| 917 | const quietPromptMessage = Message.fromPrompt(prompts.get('quietPrompt')) ?? null; | 919 | const quietPromptMessage = await Message.fromPromptAsync(prompts.get('quietPrompt')) ?? null; |
| 918 | if (quietPromptMessage && quietPromptMessage.content) { | 920 | if (quietPromptMessage && quietPromptMessage.content) { |
| 919 | if (isImageInliningSupported() && quietImage) { | 921 | if (isImageInliningSupported() && quietImage) { |
| 920 | await quietPromptMessage.addImage(quietImage); | 922 | await quietPromptMessage.addImage(quietImage); |
| @@ -940,20 +942,23 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | |||
| 940 | return acc; | 942 | return acc; |
| 941 | }, []); | 943 | }, []); |
| 942 | 944 | ||
| 943 | [...systemPrompts, ...userRelativePrompts].forEach(identifier => addToChatCompletion(identifier)); | 945 | for (const identifier of [...systemPrompts, ...userRelativePrompts]) { |
| 946 | await addToChatCompletion(identifier); | ||
| 947 | } | ||
| 944 | 948 | ||
| 945 | // Add enhance definition instruction | 949 | // Add enhance definition instruction |
| 946 | if (prompts.has('enhanceDefinitions')) addToChatCompletion('enhanceDefinitions'); | 950 | if (prompts.has('enhanceDefinitions')) await addToChatCompletion('enhanceDefinitions'); |
| 947 | 951 | ||
| 948 | // Bias | 952 | // Bias |
| 949 | if (bias && bias.trim().length) addToChatCompletion('bias'); | 953 | if (bias && bias.trim().length) await addToChatCompletion('bias'); |
| 950 | 954 | ||
| 951 | // Tavern Extras - Summary | 955 | // Tavern Extras - Summary |
| 952 | if (prompts.has('summary')) { | 956 | if (prompts.has('summary')) { |
| 953 | const summary = prompts.get('summary'); | 957 | const summary = prompts.get('summary'); |
| 954 | 958 | ||
| 955 | if (summary.position) { | 959 | if (summary.position) { |
| 956 | chatCompletion.insert(Message.fromPrompt(summary), 'main', summary.position); | 960 | const message = await Message.fromPromptAsync(summary); |
| 961 | chatCompletion.insert(message, 'main', summary.position); | ||
| 957 | } | 962 | } |
| 958 | } | 963 | } |
| 959 | 964 | ||
| @@ -962,7 +967,8 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | |||
| 962 | const authorsNote = prompts.get('authorsNote'); | 967 | const authorsNote = prompts.get('authorsNote'); |
| 963 | 968 | ||
| 964 | if (authorsNote.position) { | 969 | if (authorsNote.position) { |
| 965 | chatCompletion.insert(Message.fromPrompt(authorsNote), 'main', authorsNote.position); | 970 | const message = await Message.fromPromptAsync(authorsNote); |
| 971 | chatCompletion.insert(message, 'main', authorsNote.position); | ||
| 966 | } | 972 | } |
| 967 | } | 973 | } |
| 968 | 974 | ||
| @@ -971,7 +977,8 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | |||
| 971 | const vectorsMemory = prompts.get('vectorsMemory'); | 977 | const vectorsMemory = prompts.get('vectorsMemory'); |
| 972 | 978 | ||
| 973 | if (vectorsMemory.position) { | 979 | if (vectorsMemory.position) { |
| 974 | chatCompletion.insert(Message.fromPrompt(vectorsMemory), 'main', vectorsMemory.position); | 980 | const message = await Message.fromPromptAsync(vectorsMemory); |
| 981 | chatCompletion.insert(message, 'main', vectorsMemory.position); | ||
| 975 | } | 982 | } |
| 976 | } | 983 | } |
| 977 | 984 | ||
| @@ -980,7 +987,8 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | |||
| 980 | const vectorsDataBank = prompts.get('vectorsDataBank'); | 987 | const vectorsDataBank = prompts.get('vectorsDataBank'); |
| 981 | 988 | ||
| 982 | if (vectorsDataBank.position) { | 989 | if (vectorsDataBank.position) { |
| 983 | chatCompletion.insert(Message.fromPrompt(vectorsDataBank), 'main', vectorsDataBank.position); | 990 | const message = await Message.fromPromptAsync(vectorsDataBank); |
| 991 | chatCompletion.insert(message, 'main', vectorsDataBank.position); | ||
| 984 | } | 992 | } |
| 985 | } | 993 | } |
| 986 | 994 | ||
| @@ -989,13 +997,15 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | |||
| 989 | const smartContext = prompts.get('smartContext'); | 997 | const smartContext = prompts.get('smartContext'); |
| 990 | 998 | ||
| 991 | if (smartContext.position) { | 999 | if (smartContext.position) { |
| 992 | chatCompletion.insert(Message.fromPrompt(smartContext), 'main', smartContext.position); | 1000 | const message = await Message.fromPromptAsync(smartContext); |
| 1001 | chatCompletion.insert(message, 'main', smartContext.position); | ||
| 993 | } | 1002 | } |
| 994 | } | 1003 | } |
| 995 | 1004 | ||
| 996 | // Other relative extension prompts | 1005 | // Other relative extension prompts |
| 997 | for (const prompt of prompts.collection.filter(p => p.extension && p.position)) { | 1006 | for (const prompt of prompts.collection.filter(p => p.extension && p.position)) { |
| 998 | chatCompletion.insert(Message.fromPrompt(prompt), 'main', prompt.position); | 1007 | const message = await Message.fromPromptAsync(prompt); |
| 1008 | chatCompletion.insert(message, 'main', prompt.position); | ||
| 999 | } | 1009 | } |
| 1000 | 1010 | ||
| 1001 | // Pre-allocation of tokens for tool data | 1011 | // Pre-allocation of tokens for tool data |
| @@ -1003,7 +1013,7 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | |||
| 1003 | const toolData = {}; | 1013 | const toolData = {}; |
| 1004 | await ToolManager.registerFunctionToolsOpenAI(toolData); | 1014 | await ToolManager.registerFunctionToolsOpenAI(toolData); |
| 1005 | const toolMessage = [{ role: 'user', content: JSON.stringify(toolData) }]; | 1015 | const toolMessage = [{ role: 'user', content: JSON.stringify(toolData) }]; |
| 1006 | const toolTokens = tokenHandler.count(toolMessage); | 1016 | const toolTokens = await tokenHandler.countAsync(toolMessage); |
| 1007 | chatCompletion.reserveBudget(toolTokens); | 1017 | chatCompletion.reserveBudget(toolTokens); |
| 1008 | } | 1018 | } |
| 1009 | 1019 | ||
| @@ -1012,11 +1022,11 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | |||
| 1012 | 1022 | ||
| 1013 | // Decide whether dialogue examples should always be added | 1023 | // Decide whether dialogue examples should always be added |
| 1014 | if (power_user.pin_examples) { | 1024 | if (power_user.pin_examples) { |
| 1015 | populateDialogueExamples(prompts, chatCompletion, messageExamples); | 1025 | await populateDialogueExamples(prompts, chatCompletion, messageExamples); |
| 1016 | await populateChatHistory(messages, prompts, chatCompletion, type, cyclePrompt); | 1026 | await populateChatHistory(messages, prompts, chatCompletion, type, cyclePrompt); |
| 1017 | } else { | 1027 | } else { |
| 1018 | await populateChatHistory(messages, prompts, chatCompletion, type, cyclePrompt); | 1028 | await populateChatHistory(messages, prompts, chatCompletion, type, cyclePrompt); |
| 1019 | populateDialogueExamples(prompts, chatCompletion, messageExamples); | 1029 | await populateDialogueExamples(prompts, chatCompletion, messageExamples); |
| 1020 | } | 1030 | } |
| 1021 | 1031 | ||
| 1022 | chatCompletion.freeBudget(controlPrompts); | 1032 | chatCompletion.freeBudget(controlPrompts); |
| @@ -1281,7 +1291,7 @@ export async function prepareOpenAIMessages({ | |||
| 1281 | promptManager.setChatCompletion(chatCompletion); | 1291 | promptManager.setChatCompletion(chatCompletion); |
| 1282 | 1292 | ||
| 1283 | if (oai_settings.squash_system_messages && dryRun == false) { | 1293 | if (oai_settings.squash_system_messages && dryRun == false) { |
| 1284 | chatCompletion.squashSystemMessages(); | 1294 | await chatCompletion.squashSystemMessages(); |
| 1285 | } | 1295 | } |
| 1286 | 1296 | ||
| 1287 | // All information is up-to-date, render. | 1297 | // All information is up-to-date, render. |
| @@ -2127,8 +2137,11 @@ async function calculateLogitBias() { | |||
| 2127 | } | 2137 | } |
| 2128 | 2138 | ||
| 2129 | class TokenHandler { | 2139 | class TokenHandler { |
| 2130 | constructor(countTokenFn) { | 2140 | /** |
| 2131 | this.countTokenFn = countTokenFn; | 2141 | * @param {(messages: object[] | object, full?: boolean) => Promise<number>} countTokenAsyncFn Function to count tokens |
| 2142 | */ | ||
| 2143 | constructor(countTokenAsyncFn) { | ||
| 2144 | this.countTokenAsyncFn = countTokenAsyncFn; | ||
| 2132 | this.counts = { | 2145 | this.counts = { |
| 2133 | 'start_chat': 0, | 2146 | 'start_chat': 0, |
| 2134 | 'prompt': 0, | 2147 | 'prompt': 0, |
| @@ -2157,8 +2170,15 @@ class TokenHandler { | |||
| 2157 | this.counts[type] -= value; | 2170 | this.counts[type] -= value; |
| 2158 | } | 2171 | } |
| 2159 | 2172 | ||
| 2160 | count(messages, full, type) { | 2173 | /** |
| 2161 | const token_count = this.countTokenFn(messages, full); | 2174 | * Count tokens for a message or messages. |
| 2175 | * @param {object|any[]} messages Messages to count tokens for | ||
| 2176 | * @param {boolean} [full] Count full tokens | ||
| 2177 | * @param {string} [type] Identifier for the token count | ||
| 2178 | * @returns {Promise<number>} The token count | ||
| 2179 | */ | ||
| 2180 | async countAsync(messages, full, type) { | ||
| 2181 | const token_count = await this.countTokenAsyncFn(messages, full); | ||
| 2162 | this.counts[type] += token_count; | 2182 | this.counts[type] += token_count; |
| 2163 | 2183 | ||
| 2164 | return token_count; | 2184 | return token_count; |
| @@ -2178,7 +2198,7 @@ class TokenHandler { | |||
| 2178 | } | 2198 | } |
| 2179 | 2199 | ||
| 2180 | 2200 | ||
| 2181 | const tokenHandler = new TokenHandler(countTokensOpenAI); | 2201 | const tokenHandler = new TokenHandler(countTokensOpenAIAsync); |
| 2182 | 2202 | ||
| 2183 | // Thrown by ChatCompletion when a requested prompt couldn't be found. | 2203 | // Thrown by ChatCompletion when a requested prompt couldn't be found. |
| 2184 | class IdentifierNotFoundError extends Error { | 2204 | class IdentifierNotFoundError extends Error { |
| @@ -2228,6 +2248,7 @@ class Message { | |||
| 2228 | * @param {string} role - The role of the entity creating the message. | 2248 | * @param {string} role - The role of the entity creating the message. |
| 2229 | * @param {string} content - The actual content of the message. | 2249 | * @param {string} content - The actual content of the message. |
| 2230 | * @param {string} identifier - A unique identifier for the message. | 2250 | * @param {string} identifier - A unique identifier for the message. |
| 2251 | * @private Don't use this constructor directly. Use createAsync instead. | ||
| 2231 | */ | 2252 | */ |
| 2232 | constructor(role, content, identifier) { | 2253 | constructor(role, content, identifier) { |
| 2233 | this.identifier = identifier; | 2254 | this.identifier = identifier; |
| @@ -2239,18 +2260,32 @@ class Message { | |||
| 2239 | this.role = 'system'; | 2260 | this.role = 'system'; |
| 2240 | } | 2261 | } |
| 2241 | 2262 | ||
| 2242 | if (typeof this.content === 'string' && this.content.length > 0) { | 2263 | this.tokens = 0; |
| 2243 | this.tokens = tokenHandler.count({ role: this.role, content: this.content }); | 2264 | } |
| 2244 | } else { | 2265 | |
| 2245 | this.tokens = 0; | 2266 | /** |
| 2267 | * Create a new Message instance. | ||
| 2268 | * @param {string} role | ||
| 2269 | * @param {string} content | ||
| 2270 | * @param {string} identifier | ||
| 2271 | * @returns {Promise<Message>} Message instance | ||
| 2272 | */ | ||
| 2273 | static async createAsync(role, content, identifier) { | ||
| 2274 | const message = new Message(role, content, identifier); | ||
| 2275 | |||
| 2276 | if (typeof message.content === 'string' && message.content.length > 0) { | ||
| 2277 | message.tokens = await tokenHandler.countAsync({ role: message.role, content: message.content }); | ||
| 2246 | } | 2278 | } |
| 2279 | |||
| 2280 | return message; | ||
| 2247 | } | 2281 | } |
| 2248 | 2282 | ||
| 2249 | /** | 2283 | /** |
| 2250 | * Reconstruct the message from a tool invocation. | 2284 | * Reconstruct the message from a tool invocation. |
| 2251 | * @param {import('./tool-calling.js').ToolInvocation[]} invocations | 2285 | * @param {import('./tool-calling.js').ToolInvocation[]} invocations - The tool invocations to reconstruct the message from. |
| 2286 | * @returns {Promise<void>} | ||
| 2252 | */ | 2287 | */ |
| 2253 | setToolCalls(invocations) { | 2288 | async setToolCalls(invocations) { |
| 2254 | this.tool_calls = invocations.map(i => ({ | 2289 | this.tool_calls = invocations.map(i => ({ |
| 2255 | id: i.id, | 2290 | id: i.id, |
| 2256 | type: 'function', | 2291 | type: 'function', |
| @@ -2259,14 +2294,24 @@ class Message { | |||
| 2259 | name: i.name, | 2294 | name: i.name, |
| 2260 | }, | 2295 | }, |
| 2261 | })); | 2296 | })); |
| 2262 | this.tokens = tokenHandler.count({ role: this.role, tool_calls: JSON.stringify(this.tool_calls) }); | 2297 | this.tokens = await tokenHandler.countAsync({ role: this.role, tool_calls: JSON.stringify(this.tool_calls) }); |
| 2263 | } | 2298 | } |
| 2264 | 2299 | ||
| 2265 | setName(name) { | 2300 | /** |
| 2301 | * Add a name to the message. | ||
| 2302 | * @param {string} name Name to set for the message. | ||
| 2303 | * @returns {Promise<void>} | ||
| 2304 | */ | ||
| 2305 | async setName(name) { | ||
| 2266 | this.name = name; | 2306 | this.name = name; |
| 2267 | this.tokens = tokenHandler.count({ role: this.role, content: this.content, name: this.name }); | 2307 | this.tokens = await tokenHandler.countAsync({ role: this.role, content: this.content, name: this.name }); |
| 2268 | } | 2308 | } |
| 2269 | 2309 | ||
| 2310 | /** | ||
| 2311 | * Adds an image to the message. | ||
| 2312 | * @param {string} image Image URL or Data URL. | ||
| 2313 | * @returns {Promise<void>} | ||
| 2314 | */ | ||
| 2270 | async addImage(image) { | 2315 | async addImage(image) { |
| 2271 | const textContent = this.content; | 2316 | const textContent = this.content; |
| 2272 | const isDataUrl = isDataURL(image); | 2317 | const isDataUrl = isDataURL(image); |
| @@ -2356,13 +2401,13 @@ class Message { | |||
| 2356 | } | 2401 | } |
| 2357 | 2402 | ||
| 2358 | /** | 2403 | /** |
| 2359 | * Create a new Message instance from a prompt. | 2404 | * Create a new Message instance from a prompt asynchronously. |
| 2360 | * @static | 2405 | * @static |
| 2361 | * @param {Object} prompt - The prompt object. | 2406 | * @param {Object} prompt - The prompt object. |
| 2362 | * @returns {Message} A new instance of Message. | 2407 | * @returns {Promise<Message>} A new instance of Message. |
| 2363 | */ | 2408 | */ |
| 2364 | static fromPrompt(prompt) { | 2409 | static fromPromptAsync(prompt) { |
| 2365 | return new Message(prompt.role, prompt.content, prompt.identifier); | 2410 | return Message.createAsync(prompt.role, prompt.content, prompt.identifier); |
| 2366 | } | 2411 | } |
| 2367 | 2412 | ||
| 2368 | /** | 2413 | /** |
| @@ -2488,8 +2533,9 @@ export class ChatCompletion { | |||
| 2488 | 2533 | ||
| 2489 | /** | 2534 | /** |
| 2490 | * Combines consecutive system messages into one if they have no name attached. | 2535 | * Combines consecutive system messages into one if they have no name attached. |
| 2536 | * @returns {Promise<void>} | ||
| 2491 | */ | 2537 | */ |
| 2492 | squashSystemMessages() { | 2538 | async squashSystemMessages() { |
| 2493 | const excludeList = ['newMainChat', 'newChat', 'groupNudge']; | 2539 | const excludeList = ['newMainChat', 'newChat', 'groupNudge']; |
| 2494 | this.messages.collection = this.messages.flatten(); | 2540 | this.messages.collection = this.messages.flatten(); |
| 2495 | 2541 | ||
| @@ -2509,7 +2555,7 @@ export class ChatCompletion { | |||
| 2509 | if (shouldSquash(message)) { | 2555 | if (shouldSquash(message)) { |
| 2510 | if (lastMessage && shouldSquash(lastMessage)) { | 2556 | if (lastMessage && shouldSquash(lastMessage)) { |
| 2511 | lastMessage.content += '\n' + message.content; | 2557 | lastMessage.content += '\n' + message.content; |
| 2512 | lastMessage.tokens = tokenHandler.count({ role: lastMessage.role, content: lastMessage.content }); | 2558 | lastMessage.tokens = await tokenHandler.countAsync({ role: lastMessage.role, content: lastMessage.content }); |
| 2513 | } | 2559 | } |
| 2514 | else { | 2560 | else { |
| 2515 | squashedMessages.push(message); | 2561 | squashedMessages.push(message); |
| @@ -4,7 +4,6 @@ import { textgenerationwebui_settings as textgen_settings, textgen_types } from | |||
| 4 | import { tokenizers } from './tokenizers.js'; | 4 | import { tokenizers } from './tokenizers.js'; |
| 5 | import { renderTemplateAsync } from './templates.js'; | 5 | import { renderTemplateAsync } from './templates.js'; |
| 6 | import { POPUP_TYPE, callGenericPopup } from './popup.js'; | 6 | import { POPUP_TYPE, callGenericPopup } from './popup.js'; |
| 7 | import { PAGINATION_TEMPLATE } from './utils.js'; | ||
| 8 | 7 | ||
| 9 | let mancerModels = []; | 8 | let mancerModels = []; |
| 10 | let togetherModels = []; | 9 | let togetherModels = []; |
| @@ -1,6 +1,5 @@ | |||
| 1 | import { chat_metadata, getCurrentChatId, saveSettingsDebounced, sendSystemMessage, system_message_types } from '../script.js'; | 1 | import { chat_metadata, getCurrentChatId, saveSettingsDebounced } from '../script.js'; |
| 2 | import { extension_settings, saveMetadataDebounced } from './extensions.js'; | 2 | import { extension_settings, saveMetadataDebounced } from './extensions.js'; |
| 3 | import { callGenericPopup, POPUP_TYPE } from './popup.js'; | ||
| 4 | import { executeSlashCommandsWithOptions } from './slash-commands.js'; | 3 | import { executeSlashCommandsWithOptions } from './slash-commands.js'; |
| 5 | import { SlashCommand } from './slash-commands/SlashCommand.js'; | 4 | import { SlashCommand } from './slash-commands/SlashCommand.js'; |
| 6 | import { SlashCommandAbortController } from './slash-commands/SlashCommandAbortController.js'; | 5 | import { SlashCommandAbortController } from './slash-commands/SlashCommandAbortController.js'; |
| @@ -4565,6 +4565,7 @@ function convertCharacterBook(characterBook) { | |||
| 4565 | sticky: entry.extensions?.sticky ?? null, | 4565 | sticky: entry.extensions?.sticky ?? null, |
| 4566 | cooldown: entry.extensions?.cooldown ?? null, | 4566 | cooldown: entry.extensions?.cooldown ?? null, |
| 4567 | delay: entry.extensions?.delay ?? null, | 4567 | delay: entry.extensions?.delay ?? null, |
| 4568 | extensions: entry.extensions ?? {}, | ||
| 4568 | }; | 4569 | }; |
| 4569 | }); | 4570 | }); |
| 4570 | 4571 | ||
| @@ -468,6 +468,7 @@ function convertWorldInfoToCharacterBook(name, entries) { | |||
| 468 | position: entry.position == 0 ? 'before_char' : 'after_char', | 468 | position: entry.position == 0 ? 'before_char' : 'after_char', |
| 469 | use_regex: true, // ST keys are always regex | 469 | use_regex: true, // ST keys are always regex |
| 470 | extensions: { | 470 | extensions: { |
| 471 | ...entry.extensions, | ||
| 471 | position: entry.position, | 472 | position: entry.position, |
| 472 | exclude_recursion: entry.excludeRecursion, | 473 | exclude_recursion: entry.excludeRecursion, |
| 473 | display_index: entry.displayIndex, | 474 | display_index: entry.displayIndex, |