Chat Completion: switch to async token handling
| @@ -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', ); | |
| 752 | 753 | chatCompletion.add(collection, -1); |
| 753 | 754 | continue; |
| 754 | 755 | } |
| @@ -787,15 +788,16 @@ 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) => { |
| 800 | + const dialogueIndex = messageExamples.indexOf(dialogue); | |
| 799 | 801 | let examplesAdded = 0; |
| 800 | 802 | |
| 801 | 803 | if (chatCompletion.canAfford(newExampleChat)) chatCompletion.insert(newExampleChat, 'dialogueExamples'); |
| @@ -806,8 +808,8 @@ function populateDialogueExamples(prompts, chatCompletion, messageExamples) { | ||
| 806 | 808 | const content = prompt.content || ''; |
| 807 | 809 | const identifier = `dialogueExamples ${dialogueIndex}-${promptIndex}`; |
| 808 | 810 | |
| 809 | 811 | const chatMessage = newawait Message.createAsync(role, content, identifier); |
| 810 | 812 | await chatMessage.setName(prompt.name); |
| 811 | 813 | if (!chatCompletion.canAfford(chatMessage)) { |
| 812 | 814 | break; |
| 813 | 815 | } |
| @@ -818,7 +820,7 @@ function populateDialogueExamples(prompts, chatCompletion, messageExamples) { | ||
| 818 | 820 | if (0 === examplesAdded) { |
| 819 | 821 | chatCompletion.removeLastFrom('dialogueExamples'); |
| 820 | 822 | } |
| 821 | 823 | }); |
| 822 | 824 | } |
| 823 | 825 | } |
| 824 | 826 | |
| @@ -873,7 +875,7 @@ function getPromptRole(role) { | ||
| 873 | 875 | */ |
| 874 | 876 | async function populateChatCompletion(prompts, chatCompletion, { bias, quietPrompt, quietImage, type, cyclePrompt, messages, messageExamples }) { |
| 875 | 877 | // Helper function for preparing a prompt, that already exists within the prompt collection, for completion |
| 876 | 878 | const addToChatCompletion = async (source, target = null) => { |
| 877 | 879 | // We need the prompts array to determine a position for the source. |
| 878 | 880 | if (false === prompts.has(source)) return; |
| 879 | 881 | |
| @@ -891,30 +893,31 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | ||
| 891 | 893 | |
| 892 | 894 | const index = target ? prompts.index(target) : prompts.index(source); |
| 893 | 895 | const collection = new MessageCollection(source); |
| 894 | - collection.add(Message.fromPrompt(prompt)); | |
| 896 | + const message = await Message.fromPromptAsync(prompt); | |
| 897 | + collection.add(message); | |
| 895 | 898 | chatCompletion.add(collection, index); |
| 896 | 899 | }; |
| 897 | 900 | |
| 898 | 901 | chatCompletion.reserveBudget(3); // every reply is primed with <|start|>assistant<|message|> |
| 899 | 902 | // Character and world information |
| 900 | 903 | await addToChatCompletion('worldInfoBefore'); |
| 901 | 904 | await addToChatCompletion('main'); |
| 902 | 905 | await addToChatCompletion('worldInfoAfter'); |
| 903 | 906 | await addToChatCompletion('charDescription'); |
| 904 | 907 | await addToChatCompletion('charPersonality'); |
| 905 | 908 | await addToChatCompletion('scenario'); |
| 906 | 909 | await addToChatCompletion('personaDescription'); |
| 907 | 910 | |
| 908 | 911 | // Collection of control prompts that will always be positioned last |
| 909 | 912 | chatCompletion.setOverriddenPrompts(prompts.overriddenPrompts); |
| 910 | 913 | const controlPrompts = new MessageCollection('controlPrompts'); |
| 911 | 914 | |
| 912 | 915 | const impersonateMessage = await Message.fromPromptfromPromptAsync(prompts.get('impersonate')) ?? null; |
| 913 | 916 | if (type === 'impersonate') controlPrompts.add(impersonateMessage); |
| 914 | 917 | |
| 915 | 918 | // Add quiet prompt to control prompts |
| 916 | 919 | // This should always be last, even in control prompts. Add all further control prompts BEFORE this prompt |
| 917 | 920 | const quietPromptMessage = await Message.fromPromptfromPromptAsync(prompts.get('quietPrompt')) ?? null; |
| 918 | 921 | if (quietPromptMessage && quietPromptMessage.content) { |
| 919 | 922 | if (isImageInliningSupported() && quietImage) { |
| 920 | 923 | await quietPromptMessage.addImage(quietImage); |
| @@ -940,20 +943,23 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | ||
| 940 | 943 | return acc; |
| 941 | 944 | }, []); |
| 942 | 945 | |
| 943 | 946 | for (const identifier of [...systemPrompts, ...userRelativePrompts].forEach(identifier => addToChatCompletion(identifier)); { |
| 947 | + await addToChatCompletion(identifier); | |
| 948 | + } | |
| 944 | 949 | |
| 945 | 950 | // Add enhance definition instruction |
| 946 | 951 | if (prompts.has('enhanceDefinitions')) await addToChatCompletion('enhanceDefinitions'); |
| 947 | 952 | |
| 948 | 953 | // Bias |
| 949 | 954 | if (bias && bias.trim().length) await addToChatCompletion('bias'); |
| 950 | 955 | |
| 951 | 956 | // Tavern Extras - Summary |
| 952 | 957 | if (prompts.has('summary')) { |
| 953 | 958 | const summary = prompts.get('summary'); |
| 954 | 959 | |
| 955 | 960 | if (summary.position) { |
| 956 | - chatCompletion.insert(Message.fromPrompt(summary), 'main', summary.position); | |
| 961 | + const message = await Message.fromPromptAsync(summary); | |
| 962 | + chatCompletion.insert(message, 'main', summary.position); | |
| 957 | 963 | } |
| 958 | 964 | } |
| 959 | 965 | |
| @@ -962,7 +968,8 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | ||
| 962 | 968 | const authorsNote = prompts.get('authorsNote'); |
| 963 | 969 | |
| 964 | 970 | if (authorsNote.position) { |
| 965 | - chatCompletion.insert(Message.fromPrompt(authorsNote), 'main', authorsNote.position); | |
| 971 | + const message = await Message.fromPromptAsync(authorsNote); | |
| 972 | + chatCompletion.insert(message, 'main', authorsNote.position); | |
| 966 | 973 | } |
| 967 | 974 | } |
| 968 | 975 | |
| @@ -971,7 +978,8 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | ||
| 971 | 978 | const vectorsMemory = prompts.get('vectorsMemory'); |
| 972 | 979 | |
| 973 | 980 | if (vectorsMemory.position) { |
| 974 | - chatCompletion.insert(Message.fromPrompt(vectorsMemory), 'main', vectorsMemory.position); | |
| 981 | + const message = await Message.fromPromptAsync(vectorsMemory); | |
| 982 | + chatCompletion.insert(message, 'main', vectorsMemory.position); | |
| 975 | 983 | } |
| 976 | 984 | } |
| 977 | 985 | |
| @@ -980,7 +988,8 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | ||
| 980 | 988 | const vectorsDataBank = prompts.get('vectorsDataBank'); |
| 981 | 989 | |
| 982 | 990 | if (vectorsDataBank.position) { |
| 983 | - chatCompletion.insert(Message.fromPrompt(vectorsDataBank), 'main', vectorsDataBank.position); | |
| 991 | + const message = await Message.fromPromptAsync(vectorsDataBank); | |
| 992 | + chatCompletion.insert(message, 'main', vectorsDataBank.position); | |
| 984 | 993 | } |
| 985 | 994 | } |
| 986 | 995 | |
| @@ -989,13 +998,15 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | ||
| 989 | 998 | const smartContext = prompts.get('smartContext'); |
| 990 | 999 | |
| 991 | 1000 | if (smartContext.position) { |
| 992 | - chatCompletion.insert(Message.fromPrompt(smartContext), 'main', smartContext.position); | |
| 1001 | + const message = await Message.fromPromptAsync(smartContext); | |
| 1002 | + chatCompletion.insert(message, 'main', smartContext.position); | |
| 993 | 1003 | } |
| 994 | 1004 | } |
| 995 | 1005 | |
| 996 | 1006 | // Other relative extension prompts |
| 997 | 1007 | for (const prompt of prompts.collection.filter(p => p.extension && p.position)) { |
| 998 | - chatCompletion.insert(Message.fromPrompt(prompt), 'main', prompt.position); | |
| 1008 | + const message = await Message.fromPromptAsync(prompt); | |
| 1009 | + chatCompletion.insert(message, 'main', prompt.position); | |
| 999 | 1010 | } |
| 1000 | 1011 | |
| 1001 | 1012 | // Pre-allocation of tokens for tool data |
| @@ -1003,7 +1014,7 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | ||
| 1003 | 1014 | const toolData = {}; |
| 1004 | 1015 | await ToolManager.registerFunctionToolsOpenAI(toolData); |
| 1005 | 1016 | const toolMessage = [{ role: 'user', content: JSON.stringify(toolData) }]; |
| 1006 | 1017 | const toolTokens = await tokenHandler.countcountAsync(toolMessage); |
| 1007 | 1018 | chatCompletion.reserveBudget(toolTokens); |
| 1008 | 1019 | } |
| 1009 | 1020 | |
| @@ -1012,11 +1023,11 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | ||
| 1012 | 1023 | |
| 1013 | 1024 | // Decide whether dialogue examples should always be added |
| 1014 | 1025 | if (power_user.pin_examples) { |
| 1015 | 1026 | await populateDialogueExamples(prompts, chatCompletion, messageExamples); |
| 1016 | 1027 | await populateChatHistory(messages, prompts, chatCompletion, type, cyclePrompt); |
| 1017 | 1028 | } else { |
| 1018 | 1029 | await populateChatHistory(messages, prompts, chatCompletion, type, cyclePrompt); |
| 1019 | 1030 | await populateDialogueExamples(prompts, chatCompletion, messageExamples); |
| 1020 | 1031 | } |
| 1021 | 1032 | |
| 1022 | 1033 | chatCompletion.freeBudget(controlPrompts); |
| @@ -1281,7 +1292,7 @@ export async function prepareOpenAIMessages({ | ||
| 1281 | 1292 | promptManager.setChatCompletion(chatCompletion); |
| 1282 | 1293 | |
| 1283 | 1294 | if (oai_settings.squash_system_messages && dryRun == false) { |
| 1284 | 1295 | await chatCompletion.squashSystemMessages(); |
| 1285 | 1296 | } |
| 1286 | 1297 | |
| 1287 | 1298 | // All information is up-to-date, render. |
| @@ -2127,8 +2138,11 @@ async function calculateLogitBias() { | ||
| 2127 | 2138 | } |
| 2128 | 2139 | |
| 2129 | 2140 | class TokenHandler { |
| 2130 | - constructor(countTokenFn) { | |
| 2141 | + /** | |
| 2131 | - this.countTokenFn = countTokenFn; | |
| 2142 | + * @param {(messages: object[] | object, full?: boolean) => Promise<number>} countTokenAsyncFn Function to count tokens | |
| 2143 | + */ | |
| 2144 | + constructor(countTokenAsyncFn) { | |
| 2145 | + this.countTokenAsyncFn = countTokenAsyncFn; | |
| 2132 | 2146 | this.counts = { |
| 2133 | 2147 | 'start_chat': 0, |
| 2134 | 2148 | 'prompt': 0, |
| @@ -2157,8 +2171,15 @@ class TokenHandler { | ||
| 2157 | 2171 | this.counts[type] -= value; |
| 2158 | 2172 | } |
| 2159 | 2173 | |
| 2160 | - count(messages, full, type) { | |
| 2174 | + /** | |
| 2161 | - const token_count = this.countTokenFn(messages, full); | |
| 2175 | + * Count tokens for a message or messages. | |
| 2176 | + * @param {object|any[]} messages Messages to count tokens for | |
| 2177 | + * @param {boolean} [full] Count full tokens | |
| 2178 | + * @param {string} [type] Identifier for the token count | |
| 2179 | + * @returns {Promise<number>} The token count | |
| 2180 | + */ | |
| 2181 | + async countAsync(messages, full, type) { | |
| 2182 | + const token_count = await this.countTokenAsyncFn(messages, full); | |
| 2162 | 2183 | this.counts[type] += token_count; |
| 2163 | 2184 | |
| 2164 | 2185 | return token_count; |
| @@ -2178,7 +2199,7 @@ class TokenHandler { | ||
| 2178 | 2199 | } |
| 2179 | 2200 | |
| 2180 | 2201 | |
| 2181 | 2202 | const tokenHandler = new TokenHandler(countTokensOpenAIcountTokensOpenAIAsync); |
| 2182 | 2203 | |
| 2183 | 2204 | // Thrown by ChatCompletion when a requested prompt couldn't be found. |
| 2184 | 2205 | class IdentifierNotFoundError extends Error { |
| @@ -2228,6 +2249,7 @@ class Message { | ||
| 2228 | 2249 | * @param {string} role - The role of the entity creating the message. |
| 2229 | 2250 | * @param {string} content - The actual content of the message. |
| 2230 | 2251 | * @param {string} identifier - A unique identifier for the message. |
| 2252 | + * @private Don't use this constructor directly. Use createAsync instead. | |
| 2231 | 2253 | */ |
| 2232 | 2254 | constructor(role, content, identifier) { |
| 2233 | 2255 | this.identifier = identifier; |
| @@ -2239,18 +2261,32 @@ class Message { | ||
| 2239 | 2261 | this.role = 'system'; |
| 2240 | 2262 | } |
| 2241 | 2263 | |
| 2242 | - if (typeof this.content === 'string' && this.content.length > 0) { | |
| 2264 | + this.tokens = 0; | |
| 2243 | - this.tokens = tokenHandler.count({ role: this.role, content: this.content }); | |
| 2265 | + } | |
| 2244 | - } else { | |
| 2266 | + | |
| 2245 | - this.tokens = 0; | |
| 2267 | + /** | |
| 2268 | + * Create a new Message instance. | |
| 2269 | + * @param {string} role | |
| 2270 | + * @param {string} content | |
| 2271 | + * @param {string} identifier | |
| 2272 | + * @returns {Promise<Message>} Message instance | |
| 2273 | + */ | |
| 2274 | + static async createAsync(role, content, identifier) { | |
| 2275 | + const message = new Message(role, content, identifier); | |
| 2276 | + | |
| 2277 | + if (typeof message.content === 'string' && message.content.length > 0) { | |
| 2278 | + message.tokens = await tokenHandler.countAsync({ role: message.role, content: message.content }); | |
| 2246 | 2279 | } |
| 2280 | + | |
| 2281 | + return message; | |
| 2247 | 2282 | } |
| 2248 | 2283 | |
| 2249 | 2284 | /** |
| 2250 | 2285 | * Reconstruct the message from a tool invocation. |
| 2251 | 2286 | * @param {import('./tool-calling.js').ToolInvocation[]} invocations - The tool invocations to reconstruct the message from. |
| 2287 | + * @returns {Promise<void>} | |
| 2252 | 2288 | */ |
| 2253 | 2289 | async setToolCalls(invocations) { |
| 2254 | 2290 | this.tool_calls = invocations.map(i => ({ |
| 2255 | 2291 | id: i.id, |
| 2256 | 2292 | type: 'function', |
| @@ -2259,12 +2295,17 @@ class Message { | ||
| 2259 | 2295 | name: i.name, |
| 2260 | 2296 | }, |
| 2261 | 2297 | })); |
| 2262 | 2298 | this.tokens = await tokenHandler.countcountAsync({ role: this.role, tool_calls: JSON.stringify(this.tool_calls) }); |
| 2263 | 2299 | } |
| 2264 | 2300 | |
| 2265 | - setName(name) { | |
| 2301 | + /** | |
| 2302 | + * Add a name to the message. | |
| 2303 | + * @param {string} name Name to set for the message. | |
| 2304 | + * @returns {Promise<void>} | |
| 2305 | + */ | |
| 2306 | + async setName(name) { | |
| 2266 | 2307 | this.name = name; |
| 2267 | 2308 | this.tokens = await tokenHandler.countcountAsync({ role: this.role, content: this.content, name: this.name }); |
| 2268 | 2309 | } |
| 2269 | 2310 | |
| 2270 | 2311 | async addImage(image) { |
| @@ -2356,13 +2397,13 @@ class Message { | ||
| 2356 | 2397 | } |
| 2357 | 2398 | |
| 2358 | 2399 | /** |
| 2359 | 2400 | * Create a new Message instance from a prompt asynchronously. |
| 2360 | 2401 | * @static |
| 2361 | 2402 | * @param {Object} prompt - The prompt object. |
| 2362 | 2403 | * @returns {Promise<Message>} A new instance of Message. |
| 2363 | 2404 | */ |
| 2364 | 2405 | static fromPromptasync fromPromptAsync(prompt) { |
| 2365 | 2406 | return new Message.createAsync(prompt.role, prompt.content, prompt.identifier); |
| 2366 | 2407 | } |
| 2367 | 2408 | |
| 2368 | 2409 | /** |
| @@ -2488,8 +2529,9 @@ export class ChatCompletion { | ||
| 2488 | 2529 | |
| 2489 | 2530 | /** |
| 2490 | 2531 | * Combines consecutive system messages into one if they have no name attached. |
| 2532 | + * @returns {Promise<void>} | |
| 2491 | 2533 | */ |
| 2492 | 2534 | async squashSystemMessages() { |
| 2493 | 2535 | const excludeList = ['newMainChat', 'newChat', 'groupNudge']; |
| 2494 | 2536 | this.messages.collection = this.messages.flatten(); |
| 2495 | 2537 | |
| @@ -2509,7 +2551,7 @@ export class ChatCompletion { | ||
| 2509 | 2551 | if (shouldSquash(message)) { |
| 2510 | 2552 | if (lastMessage && shouldSquash(lastMessage)) { |
| 2511 | 2553 | lastMessage.content += '\n' + message.content; |
| 2512 | 2554 | lastMessage.tokens = await tokenHandler.countcountAsync({ role: lastMessage.role, content: lastMessage.content }); |
| 2513 | 2555 | } |
| 2514 | 2556 | else { |
| 2515 | 2557 | squashedMessages.push(message); |