Merge pull request #2976 from SillyTavern/cc-async-count Chat Completion: switch to async token handling
Signed| @@ -315,7 +315,7 @@ class PromptManager { | ||
| 315 | 315 | */ |
| 316 | 316 | init(moduleConfiguration, serviceSettings) { |
| 317 | 317 | this.configuration = Object.assign(this.configuration, moduleConfiguration); |
| 318 | 318 | this.tokenHandler = this.tokenHandler || new TokenHandler(() => { throw new Error('Token handler not set'); }); |
| 319 | 319 | this.serviceSettings = serviceSettings; |
| 320 | 320 | this.containerElement = document.getElementById(this.configuration.containerIdentifier); |
| 321 | 321 | |
| @@ -60,7 +60,7 @@ import { | ||
| 60 | 60 | resetScrollHeight, |
| 61 | 61 | stringFormat, |
| 62 | 62 | } from './utils.js'; |
| 63 | 63 | import { countTokensOpenAIcountTokensOpenAIAsync, getTokenizerModel } from './tokenizers.js'; |
| 64 | 64 | import { isMobile } from './RossAscends-mods.js'; |
| 65 | 65 | import { saveLogprobsForActiveMessage } from './logprobs.js'; |
| 66 | 66 | import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; |
| @@ -671,14 +671,14 @@ async function populateChatHistory(messages, prompts, chatCompletion, type = nul | ||
| 671 | 671 | |
| 672 | 672 | // Reserve budget for new chat message |
| 673 | 673 | const newChat = selected_group ? oai_settings.new_group_chat_prompt : oai_settings.new_chat_prompt; |
| 674 | 674 | const newChatMessage = newawait Message.createAsync('system', substituteParams(newChat), 'newMainChat'); |
| 675 | 675 | chatCompletion.reserveBudget(newChatMessage); |
| 676 | 676 | |
| 677 | 677 | // Reserve budget for group nudge |
| 678 | 678 | let groupNudgeMessage = null; |
| 679 | 679 | const noGroupNudgeTypes = ['impersonate']; |
| 680 | 680 | if (selected_group && prompts.has('groupNudge') && !noGroupNudgeTypes.includes(type)) { |
| 681 | 681 | groupNudgeMessage = await Message.fromPromptfromPromptAsync(prompts.get('groupNudge')); |
| 682 | 682 | chatCompletion.reserveBudget(groupNudgeMessage); |
| 683 | 683 | } |
| 684 | 684 | |
| @@ -693,12 +693,12 @@ async function populateChatHistory(messages, prompts, chatCompletion, type = nul | ||
| 693 | 693 | }; |
| 694 | 694 | const continuePrompt = new Prompt(promptObject); |
| 695 | 695 | const preparedPrompt = promptManager.preparePrompt(continuePrompt); |
| 696 | 696 | continueMessage = await Message.fromPromptfromPromptAsync(preparedPrompt); |
| 697 | 697 | chatCompletion.reserveBudget(continueMessage); |
| 698 | 698 | } |
| 699 | 699 | |
| 700 | 700 | const lastChatPrompt = messages[messages.length - 1]; |
| 701 | 701 | const message = newawait Message.createAsync('user', oai_settings.send_if_empty, 'emptyUserMessageReplacement'); |
| 702 | 702 | if (lastChatPrompt && lastChatPrompt.role === 'assistant' && oai_settings.send_if_empty && chatCompletion.canAfford(message)) { |
| 703 | 703 | chatCompletion.insert(message, 'chatHistory'); |
| 704 | 704 | } |
| @@ -715,11 +715,11 @@ async function populateChatHistory(messages, prompts, chatCompletion, type = nul | ||
| 715 | 715 | // We do not want to mutate the prompt |
| 716 | 716 | const prompt = new Prompt(chatPrompt); |
| 717 | 717 | prompt.identifier = `chatHistory-${messages.length - index}`; |
| 718 | 718 | const chatMessage = await Message.fromPromptfromPromptAsync(promptManager.preparePrompt(prompt)); |
| 719 | 719 | |
| 720 | 720 | if (promptManager.serviceSettings.names_behavior === character_names_behavior.COMPLETION && prompt.name) { |
| 721 | 721 | const messageName = promptManager.isValidName(prompt.name) ? prompt.name : promptManager.sanitizeName(prompt.name); |
| 722 | 722 | await chatMessage.setName(messageName); |
| 723 | 723 | } |
| 724 | 724 | |
| 725 | 725 | if (imageInlining && chatPrompt.image) { |
| @@ -729,9 +729,9 @@ async function populateChatHistory(messages, prompts, chatCompletion, type = nul | ||
| 729 | 729 | if (canUseTools && Array.isArray(chatPrompt.invocations)) { |
| 730 | 730 | /** @type {import('./tool-calling.js').ToolInvocation[]} */ |
| 731 | 731 | const invocations = chatPrompt.invocations; |
| 732 | 732 | const toolCallMessage = newawait Message.createAsync(chatMessage.role, undefined, 'toolCall-' + chatMessage.identifier); |
| 733 | 733 | const toolResultMessages = await Promise.all(invocations.slice().reverse().map((invocation) => new Message.createAsync('tool', invocation.result || '[No content]', invocation.id))); |
| 734 | 734 | await toolCallMessage.setToolCalls(invocations); |
| 735 | 735 | if (chatCompletion.canAffordAll([toolCallMessage, ...toolResultMessages])) { |
| 736 | 736 | for (const resultMessage of toolResultMessages) { |
| 737 | 737 | chatCompletion.insertAtStart(resultMessage, 'chatHistory'); |
| @@ -748,7 +748,8 @@ async function populateChatHistory(messages, prompts, chatCompletion, type = nul | ||
| 748 | 748 | if (type === 'continue' && oai_settings.continue_prefill && chatPrompt === firstNonInjected) { |
| 749 | 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 | 750 | if (chatPrompt.role === 'assistant') { |
| 751 | 751 | const collectioncontinueMessage = new MessageCollection('continuePrefill', newawait Message.createAsync(chatMessage.role, substituteParams(oai_settings.assistant_prefill + '\n\n') + chatMessage.content, chatMessage.identifier)); |
| 752 | + const collection = new MessageCollection('continuePrefill', continueMessage); | |
| 752 | 753 | chatCompletion.add(collection, -1); |
| 753 | 754 | continue; |
| 754 | 755 | } |
| @@ -787,18 +788,17 @@ async function populateChatHistory(messages, prompts, chatCompletion, type = nul | ||
| 787 | 788 | * @param {ChatCompletion} chatCompletion - An instance of ChatCompletion class that will be populated with the prompts. |
| 788 | 789 | * @param {Object[]} messageExamples - Array containing all message examples. |
| 789 | 790 | */ |
| 790 | 791 | async function populateDialogueExamples(prompts, chatCompletion, messageExamples) { |
| 791 | 792 | if (!prompts.has('dialogueExamples')) { |
| 792 | 793 | return; |
| 793 | 794 | } |
| 794 | 795 | |
| 795 | 796 | chatCompletion.add(new MessageCollection('dialogueExamples'), prompts.index('dialogueExamples')); |
| 796 | 797 | if (Array.isArray(messageExamples) && messageExamples.length) { |
| 797 | 798 | const newExampleChat = newawait Message.createAsync('system', substituteParams(oai_settings.new_example_chat_prompt), 'newChat'); |
| 798 | 799 | for (const dialogue of [...messageExamples].forEach((dialogue, dialogueIndex) => { |
| 799 | 800 | letconst examplesAddeddialogueIndex = 0messageExamples.indexOf(dialogue); |
| 800 | - | |
| 801 | + const chatMessages = []; | |
| 801 | - if (chatCompletion.canAfford(newExampleChat)) chatCompletion.insert(newExampleChat, 'dialogueExamples'); | |
| 802 | 802 | |
| 803 | 803 | for (let promptIndex = 0; promptIndex < dialogue.length; promptIndex++) { |
| 804 | 804 | const prompt = dialogue[promptIndex]; |
| @@ -806,19 +806,20 @@ function populateDialogueExamples(prompts, chatCompletion, messageExamples) { | ||
| 806 | 806 | const content = prompt.content || ''; |
| 807 | 807 | const identifier = `dialogueExamples ${dialogueIndex}-${promptIndex}`; |
| 808 | 808 | |
| 809 | 809 | const chatMessage = newawait Message.createAsync(role, content, identifier); |
| 810 | 810 | await chatMessage.setName(prompt.name); |
| 811 | - if (!chatCompletion.canAfford(chatMessage)) { | |
| 811 | + chatMessages.push(chatMessage); | |
| 812 | + } | |
| 813 | + | |
| 814 | + if (!chatCompletion.canAffordAll([newExampleChat, ...chatMessages])) { | |
| 812 | 815 | break; |
| 813 | 816 | } |
| 817 | + | |
| 818 | + chatCompletion.insert(newExampleChat, 'dialogueExamples'); | |
| 819 | + for (const chatMessage of chatMessages) { | |
| 814 | 820 | chatCompletion.insert(chatMessage, 'dialogueExamples'); |
| 815 | - examplesAdded++; | |
| 816 | 821 | } |
| 817 | - | |
| 818 | - if (0 === examplesAdded) { | |
| 819 | - chatCompletion.removeLastFrom('dialogueExamples'); | |
| 820 | 822 | } |
| 821 | - }); | |
| 822 | 823 | } |
| 823 | 824 | } |
| 824 | 825 | |
| @@ -873,7 +874,7 @@ function getPromptRole(role) { | ||
| 873 | 874 | */ |
| 874 | 875 | async function populateChatCompletion(prompts, chatCompletion, { bias, quietPrompt, quietImage, type, cyclePrompt, messages, messageExamples }) { |
| 875 | 876 | // Helper function for preparing a prompt, that already exists within the prompt collection, for completion |
| 876 | 877 | const addToChatCompletion = async (source, target = null) => { |
| 877 | 878 | // We need the prompts array to determine a position for the source. |
| 878 | 879 | if (false === prompts.has(source)) return; |
| 879 | 880 | |
| @@ -891,30 +892,31 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | ||
| 891 | 892 | |
| 892 | 893 | const index = target ? prompts.index(target) : prompts.index(source); |
| 893 | 894 | const collection = new MessageCollection(source); |
| 894 | - collection.add(Message.fromPrompt(prompt)); | |
| 895 | + const message = await Message.fromPromptAsync(prompt); | |
| 896 | + collection.add(message); | |
| 895 | 897 | chatCompletion.add(collection, index); |
| 896 | 898 | }; |
| 897 | 899 | |
| 898 | 900 | chatCompletion.reserveBudget(3); // every reply is primed with <|start|>assistant<|message|> |
| 899 | 901 | // Character and world information |
| 900 | 902 | await addToChatCompletion('worldInfoBefore'); |
| 901 | 903 | await addToChatCompletion('main'); |
| 902 | 904 | await addToChatCompletion('worldInfoAfter'); |
| 903 | 905 | await addToChatCompletion('charDescription'); |
| 904 | 906 | await addToChatCompletion('charPersonality'); |
| 905 | 907 | await addToChatCompletion('scenario'); |
| 906 | 908 | await addToChatCompletion('personaDescription'); |
| 907 | 909 | |
| 908 | 910 | // Collection of control prompts that will always be positioned last |
| 909 | 911 | chatCompletion.setOverriddenPrompts(prompts.overriddenPrompts); |
| 910 | 912 | const controlPrompts = new MessageCollection('controlPrompts'); |
| 911 | 913 | |
| 912 | 914 | const impersonateMessage = await Message.fromPromptfromPromptAsync(prompts.get('impersonate')) ?? null; |
| 913 | 915 | if (type === 'impersonate') controlPrompts.add(impersonateMessage); |
| 914 | 916 | |
| 915 | 917 | // Add quiet prompt to control prompts |
| 916 | 918 | // This should always be last, even in control prompts. Add all further control prompts BEFORE this prompt |
| 917 | 919 | const quietPromptMessage = await Message.fromPromptfromPromptAsync(prompts.get('quietPrompt')) ?? null; |
| 918 | 920 | if (quietPromptMessage && quietPromptMessage.content) { |
| 919 | 921 | if (isImageInliningSupported() && quietImage) { |
| 920 | 922 | await quietPromptMessage.addImage(quietImage); |
| @@ -940,20 +942,23 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | ||
| 940 | 942 | return acc; |
| 941 | 943 | }, []); |
| 942 | 944 | |
| 943 | 945 | for (const identifier of [...systemPrompts, ...userRelativePrompts].forEach(identifier => addToChatCompletion(identifier)); { |
| 946 | + await addToChatCompletion(identifier); | |
| 947 | + } | |
| 944 | 948 | |
| 945 | 949 | // Add enhance definition instruction |
| 946 | 950 | if (prompts.has('enhanceDefinitions')) await addToChatCompletion('enhanceDefinitions'); |
| 947 | 951 | |
| 948 | 952 | // Bias |
| 949 | 953 | if (bias && bias.trim().length) await addToChatCompletion('bias'); |
| 950 | 954 | |
| 951 | 955 | // Tavern Extras - Summary |
| 952 | 956 | if (prompts.has('summary')) { |
| 953 | 957 | const summary = prompts.get('summary'); |
| 954 | 958 | |
| 955 | 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 | 967 | const authorsNote = prompts.get('authorsNote'); |
| 963 | 968 | |
| 964 | 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 | 977 | const vectorsMemory = prompts.get('vectorsMemory'); |
| 972 | 978 | |
| 973 | 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 | 987 | const vectorsDataBank = prompts.get('vectorsDataBank'); |
| 981 | 988 | |
| 982 | 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 | 997 | const smartContext = prompts.get('smartContext'); |
| 990 | 998 | |
| 991 | 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 | 1005 | // Other relative extension prompts |
| 997 | 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 | 1011 | // Pre-allocation of tokens for tool data |
| @@ -1003,7 +1013,7 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | ||
| 1003 | 1013 | const toolData = {}; |
| 1004 | 1014 | await ToolManager.registerFunctionToolsOpenAI(toolData); |
| 1005 | 1015 | const toolMessage = [{ role: 'user', content: JSON.stringify(toolData) }]; |
| 1006 | 1016 | const toolTokens = await tokenHandler.countcountAsync(toolMessage); |
| 1007 | 1017 | chatCompletion.reserveBudget(toolTokens); |
| 1008 | 1018 | } |
| 1009 | 1019 | |
| @@ -1012,11 +1022,11 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | ||
| 1012 | 1022 | |
| 1013 | 1023 | // Decide whether dialogue examples should always be added |
| 1014 | 1024 | if (power_user.pin_examples) { |
| 1015 | 1025 | await populateDialogueExamples(prompts, chatCompletion, messageExamples); |
| 1016 | 1026 | await populateChatHistory(messages, prompts, chatCompletion, type, cyclePrompt); |
| 1017 | 1027 | } else { |
| 1018 | 1028 | await populateChatHistory(messages, prompts, chatCompletion, type, cyclePrompt); |
| 1019 | 1029 | await populateDialogueExamples(prompts, chatCompletion, messageExamples); |
| 1020 | 1030 | } |
| 1021 | 1031 | |
| 1022 | 1032 | chatCompletion.freeBudget(controlPrompts); |
| @@ -1281,7 +1291,7 @@ export async function prepareOpenAIMessages({ | ||
| 1281 | 1291 | promptManager.setChatCompletion(chatCompletion); |
| 1282 | 1292 | |
| 1283 | 1293 | if (oai_settings.squash_system_messages && dryRun == false) { |
| 1284 | 1294 | await chatCompletion.squashSystemMessages(); |
| 1285 | 1295 | } |
| 1286 | 1296 | |
| 1287 | 1297 | // All information is up-to-date, render. |
| @@ -2127,8 +2137,11 @@ async function calculateLogitBias() { | ||
| 2127 | 2137 | } |
| 2128 | 2138 | |
| 2129 | 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 | 2145 | this.counts = { |
| 2133 | 2146 | 'start_chat': 0, |
| 2134 | 2147 | 'prompt': 0, |
| @@ -2157,8 +2170,15 @@ class TokenHandler { | ||
| 2157 | 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 | 2182 | this.counts[type] += token_count; |
| 2163 | 2183 | |
| 2164 | 2184 | return token_count; |
| @@ -2178,7 +2198,7 @@ class TokenHandler { | ||
| 2178 | 2198 | } |
| 2179 | 2199 | |
| 2180 | 2200 | |
| 2181 | 2201 | const tokenHandler = new TokenHandler(countTokensOpenAIcountTokensOpenAIAsync); |
| 2182 | 2202 | |
| 2183 | 2203 | // Thrown by ChatCompletion when a requested prompt couldn't be found. |
| 2184 | 2204 | class IdentifierNotFoundError extends Error { |
| @@ -2228,6 +2248,7 @@ class Message { | ||
| 2228 | 2248 | * @param {string} role - The role of the entity creating the message. |
| 2229 | 2249 | * @param {string} content - The actual content of the message. |
| 2230 | 2250 | * @param {string} identifier - A unique identifier for the message. |
| 2251 | + * @private Don't use this constructor directly. Use createAsync instead. | |
| 2231 | 2252 | */ |
| 2232 | 2253 | constructor(role, content, identifier) { |
| 2233 | 2254 | this.identifier = identifier; |
| @@ -2239,18 +2260,32 @@ class Message { | ||
| 2239 | 2260 | this.role = 'system'; |
| 2240 | 2261 | } |
| 2241 | 2262 | |
| 2242 | - if (typeof this.content === 'string' && this.content.length > 0) { | |
| 2243 | - this.tokens = tokenHandler.count({ role: this.role, content: this.content }); | |
| 2244 | - } else { | |
| 2245 | 2263 | this.tokens = 0; |
| 2246 | 2264 | } |
| 2265 | + | |
| 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 }); | |
| 2278 | + } | |
| 2279 | + | |
| 2280 | + return message; | |
| 2247 | 2281 | } |
| 2248 | 2282 | |
| 2249 | 2283 | /** |
| 2250 | 2284 | * Reconstruct the message from a tool invocation. |
| 2251 | 2285 | * @param {import('./tool-calling.js').ToolInvocation[]} invocations - The tool invocations to reconstruct the message from. |
| 2286 | + * @returns {Promise<void>} | |
| 2252 | 2287 | */ |
| 2253 | 2288 | async setToolCalls(invocations) { |
| 2254 | 2289 | this.tool_calls = invocations.map(i => ({ |
| 2255 | 2290 | id: i.id, |
| 2256 | 2291 | type: 'function', |
| @@ -2259,14 +2294,24 @@ class Message { | ||
| 2259 | 2294 | name: i.name, |
| 2260 | 2295 | }, |
| 2261 | 2296 | })); |
| 2262 | 2297 | this.tokens = await tokenHandler.countcountAsync({ 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 | 2306 | this.name = name; |
| 2267 | 2307 | this.tokens = await tokenHandler.countcountAsync({ 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 | 2315 | async addImage(image) { |
| 2271 | 2316 | const textContent = this.content; |
| 2272 | 2317 | const isDataUrl = isDataURL(image); |
| @@ -2356,13 +2401,13 @@ class Message { | ||
| 2356 | 2401 | } |
| 2357 | 2402 | |
| 2358 | 2403 | /** |
| 2359 | 2404 | * Create a new Message instance from a prompt asynchronously. |
| 2360 | 2405 | * @static |
| 2361 | 2406 | * @param {Object} prompt - The prompt object. |
| 2362 | 2407 | * @returns {Promise<Message>} A new instance of Message. |
| 2363 | 2408 | */ |
| 2364 | 2409 | static fromPromptfromPromptAsync(prompt) { |
| 2365 | 2410 | return new 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 | 2535 | * Combines consecutive system messages into one if they have no name attached. |
| 2536 | + * @returns {Promise<void>} | |
| 2491 | 2537 | */ |
| 2492 | 2538 | async squashSystemMessages() { |
| 2493 | 2539 | const excludeList = ['newMainChat', 'newChat', 'groupNudge']; |
| 2494 | 2540 | this.messages.collection = this.messages.flatten(); |
| 2495 | 2541 | |
| @@ -2509,7 +2555,7 @@ export class ChatCompletion { | ||
| 2509 | 2555 | if (shouldSquash(message)) { |
| 2510 | 2556 | if (lastMessage && shouldSquash(lastMessage)) { |
| 2511 | 2557 | lastMessage.content += '\n' + message.content; |
| 2512 | 2558 | lastMessage.tokens = await tokenHandler.countcountAsync({ role: lastMessage.role, content: lastMessage.content }); |
| 2513 | 2559 | } |
| 2514 | 2560 | else { |
| 2515 | 2561 | squashedMessages.push(message); |