From e09a7d1e7a5ba010bb1e0942cd1545f2125c0419 Mon Sep 17 00:00:00 2001 From: maver Date: Tue, 15 Aug 2023 19:40:22 +0200 Subject: [PATCH 1/8] Print stack to console on chatcompletion error --- public/scripts/openai.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/public/scripts/openai.js b/public/scripts/openai.js index 71b83b9f2..931cc4c38 100644 --- a/public/scripts/openai.js +++ b/public/scripts/openai.js @@ -806,8 +806,10 @@ function prepareOpenAIMessages({ promptManager.error = 'The name of at least one character contained whitespaces or special characters. Please check your user and character name.'; } else { toastr.error('An unknown error occurred while counting tokens. Further information may be available in console.') - chatCompletion.log('Unexpected error:'); + chatCompletion.log('----- Unexpected error while preparing prompts -----'); chatCompletion.log(error); + chatCompletion.log(error.stack); + chatCompletion.log('----------------------------------------------------'); } } finally { // Pass chat completion to prompt manager for inspection From 07be5588f4f6de39821a5e929ab09ea82737f835 Mon Sep 17 00:00:00 2001 From: maver Date: Tue, 15 Aug 2023 19:41:34 +0200 Subject: [PATCH 2/8] Implement configurable prompt order strategy for prompt manager global and character --- public/scripts/PromptManager.js | 102 +++++++++++++++++++++++++------- public/scripts/openai.js | 6 +- 2 files changed, 85 insertions(+), 23 deletions(-) diff --git a/public/scripts/PromptManager.js b/public/scripts/PromptManager.js index ed3dd704c..beaa402d2 100644 --- a/public/scripts/PromptManager.js +++ b/public/scripts/PromptManager.js @@ -168,6 +168,10 @@ function PromptManagerModule() { listIdentifier: '', listItemTemplateIdentifier: '', toggleDisabled: [], + promptOrder: { + strategy: 'global', + dummyId: 100000 + }, draggable: true, warningTokenThreshold: 1500, dangerTokenThreshold: 500, @@ -416,12 +420,26 @@ PromptManagerModule.prototype.init = function (moduleConfiguration, serviceSetti // Export all user prompts this.handleFullExport = () => { - const exportPrompts = this.serviceSettings.prompts.reduce((userPrompts, prompt) => { + const prompts = this.serviceSettings.prompts.reduce((userPrompts, prompt) => { if (false === prompt.system_prompt && false === prompt.marker) userPrompts.push(prompt); return userPrompts; }, []); - this.export({prompts: exportPrompts}, 'full', 'st-prompts'); + let promptOrder = []; + if ('global' === this.configuration.promptOrder.strategy) { + promptOrder = this.getPromptOrderForCharacter({id: this.configuration.promptOrder.dummyId}); + } else if ('character' === this.configuration.promptOrder.strategy) { + promptOrder = []; + } else { + throw new Error('Prompt order strategy not supported.') + } + + const exportPrompts = { + prompts: prompts, + prompt_order: promptOrder + } + + this.export(exportPrompts, 'full', 'st-prompts'); } // Export user prompts and order for this character @@ -554,7 +572,7 @@ PromptManagerModule.prototype.init = function (moduleConfiguration, serviceSetti this.saveServiceSettings().then(() => { this.hidePopup(); this.clearEditForm(); - this.renderDebounced() + this.renderDebounced(); }); }); @@ -694,6 +712,13 @@ PromptManagerModule.prototype.sanitizeServiceSettings = function () { this.serviceSettings.prompts = this.serviceSettings.prompts ?? []; this.serviceSettings.prompt_order = this.serviceSettings.prompt_order ?? []; + if ('global' === this.configuration.promptOrder.strategy) { + const dummyCharacter = {id: this.configuration.promptOrder.dummyId}; + const promptOrder = this.getPromptOrderForCharacter(dummyCharacter); + + if (0 === promptOrder.length) this.addPromptOrderForCharacter(dummyCharacter, promptManagerDefaultPromptOrder); + } + // Check whether the referenced prompts are present. this.serviceSettings.prompts.length === 0 ? this.setPrompts(chatCompletionDefaultPrompts.prompts) @@ -775,9 +800,10 @@ PromptManagerModule.prototype.isPromptToggleAllowed = function (prompt) { /** * Handle the deletion of a character by removing their prompt list and nullifying the active character if it was the one deleted. * @param {object} event - The event object containing the character's ID. - * @returns boolean + * @returns void */ PromptManagerModule.prototype.handleCharacterDeleted = function (event) { + if ('global' === this.configuration.promptOrder.strategy) return; this.removePromptOrderForCharacter(this.activeCharacter); if (this.activeCharacter.id === event.detail.id) this.activeCharacter = null; } @@ -788,12 +814,19 @@ PromptManagerModule.prototype.handleCharacterDeleted = function (event) { * @returns {void} */ PromptManagerModule.prototype.handleCharacterSelected = function (event) { - this.activeCharacter = {id: event.detail.id, ...event.detail.character}; - const promptOrder = this.getPromptOrderForCharacter(this.activeCharacter); + if ('global' === this.configuration.promptOrder.strategy) { + this.activeCharacter = {id: this.configuration.promptOrder.dummyId}; + } else if ('character' === this.configuration.promptOrder.strategy) { + console.log('FOO') + this.activeCharacter = {id: event.detail.id, ...event.detail.character}; + const promptOrder = this.getPromptOrderForCharacter(this.activeCharacter); - // ToDo: These should be passed as parameter or attached to the manager as a set of default options. - // Set default prompts and order for character. - if (0 === promptOrder.length) this.addPromptOrderForCharacter(this.activeCharacter, promptManagerDefaultPromptOrder); + // ToDo: These should be passed as parameter or attached to the manager as a set of default options. + // Set default prompts and order for character. + if (0 === promptOrder.length) this.addPromptOrderForCharacter(this.activeCharacter, promptManagerDefaultPromptOrder); + } else { + throw new Error('Unsupported prompt order mode.'); + } } /** @@ -802,7 +835,13 @@ PromptManagerModule.prototype.handleCharacterSelected = function (event) { * @param event */ PromptManagerModule.prototype.handleCharacterUpdated = function (event) { - this.activeCharacter = {id: event.detail.id, ...event.detail.character}; + if ('global' === this.configuration.promptOrder.strategy) { + this.activeCharacter = {id: this.configuration.promptOrder.dummyId}; + } else if ('character' === this.configuration.promptOrder.strategy) { + this.activeCharacter = {id: event.detail.id, ...event.detail.character}; + } else { + throw new Error ('Prompt order strategy not supported.') + } } /** @@ -811,11 +850,17 @@ PromptManagerModule.prototype.handleCharacterUpdated = function (event) { * @param event */ PromptManagerModule.prototype.handleGroupSelected = function (event) { - const characterDummy = {id: event.detail.id, group: event.detail.group}; - this.activeCharacter = characterDummy; - const promptOrder = this.getPromptOrderForCharacter(characterDummy); + if ('global' === this.configuration.promptOrder.strategy) { + this.activeCharacter = {id: this.configuration.promptOrder.dummyId}; + } else if ('character' === this.configuration.promptOrder.strategy) { + const characterDummy = {id: event.detail.id, group: event.detail.group}; + this.activeCharacter = characterDummy; + const promptOrder = this.getPromptOrderForCharacter(characterDummy); - if (0 === promptOrder.length) this.addPromptOrderForCharacter(characterDummy, promptManagerDefaultPromptOrder) + if (0 === promptOrder.length) this.addPromptOrderForCharacter(characterDummy, promptManagerDefaultPromptOrder) + } else { + throw new Error ('Prompt order strategy not supported.') + } } /** @@ -1225,10 +1270,14 @@ PromptManagerModule.prototype.renderPromptManager = function () { Export all - + ${ 'global' === this.configuration.promptOrder.strategy + ? '' + : `` } `; @@ -1254,7 +1303,7 @@ PromptManagerModule.prototype.renderPromptManager = function () { footerDiv.querySelector('#prompt-manager-import').addEventListener('click', this.handleImport); footerDiv.querySelector('#prompt-manager-export').addEventListener('click', showExportSelection); rangeBlockDiv.querySelector('.export-promptmanager-prompts-full').addEventListener('click', this.handleFullExport); - rangeBlockDiv.querySelector('.export-promptmanager-prompts-character').addEventListener('click', this.handleCharacterExport); + rangeBlockDiv.querySelector('.export-promptmanager-prompts-character')?.addEventListener('click', this.handleCharacterExport); const quickEditContainer = document.getElementById('quick-edit-container'); quickEditContainer.innerHTML = ''; @@ -1451,10 +1500,19 @@ PromptManagerModule.prototype.import = function (importData) { this.setPrompts(prompts); this.log('Prompt import succeeded'); - if ('character' === importData.type) { - const promptOrder = this.getPromptOrderForCharacter(this.activeCharacter); + let promptOrder = []; + if ('global' === this.configuration.promptOrder.strategy) { + const promptOrder = this.getPromptOrderForCharacter({id: this.configuration.promptOrder.dummyId}); Object.assign(promptOrder, importData.data.prompt_order); - this.log(`Prompt order import for character ${this.activeCharacter.name} completed`); + this.log(`Prompt order import succeeded`); + } else if ('character' === this.configuration.promptOrder.strategy) { + if ('character' === importData.type) { + const promptOrder = this.getPromptOrderForCharacter(this.activeCharacter); + Object.assign(promptOrder, importData.data.prompt_order); + this.log(`Prompt order import for character ${this.activeCharacter.name} succeeded`); + } + } else { + throw new Error('Prompt order strategy not supported.') } toastr.success('Prompt import complete.'); diff --git a/public/scripts/openai.js b/public/scripts/openai.js index 931cc4c38..8fdaf1f36 100644 --- a/public/scripts/openai.js +++ b/public/scripts/openai.js @@ -347,7 +347,11 @@ function setupChatCompletionPromptManager(openAiSettings) { nsfw: default_nsfw_prompt, jailbreak: default_jailbreak_prompt, enhanceDefinitions: default_enhance_definitions_prompt - } + }, + promptOrder: { + strategy: 'global', + dummyId: 100000 + }, }; promptManager.saveServiceSettings = () => { From 947289dffc632645dbd85fd6f834b11dd9d7c846 Mon Sep 17 00:00:00 2001 From: maver Date: Wed, 16 Aug 2023 19:01:09 +0200 Subject: [PATCH 3/8] Lock up configuration during prompt manager render --- public/scripts/PromptManager.js | 27 ++++++++++++++++++++------- public/scripts/openai.js | 2 +- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/public/scripts/PromptManager.js b/public/scripts/PromptManager.js index beaa402d2..ba3667172 100644 --- a/public/scripts/PromptManager.js +++ b/public/scripts/PromptManager.js @@ -181,7 +181,7 @@ function PromptManagerModule() { jailbreak: '', enhanceDefinitions: '' } - }; + } // Chatcompletion configuration object this.serviceSettings = null; @@ -588,12 +588,20 @@ PromptManagerModule.prototype.init = function (moduleConfiguration, serviceSetti * @param afterTryGenerate - Whether a dry run should be attempted before rendering */ PromptManagerModule.prototype.render = function (afterTryGenerate = true) { - if (main_api !== 'openai') return; + if (main_api !== 'openai' || + null === this.activeCharacter) return; - if (null === this.activeCharacter) return; this.error = null; - waitUntilCondition(() => !is_send_press && !is_group_generating, 1024 * 1024, 100).then(() => { + const stopPropagation = (event) => { + event.stopPropagation(); + } + + const configurationContainer = document.getElementById('ai_response_configuration'); + try { + // Lock configuration during render + configurationContainer.addEventListener('click', stopPropagation, true); + if (true === afterTryGenerate) { // Executed during dry-run for determining context composition this.profileStart('filling context'); @@ -613,9 +621,14 @@ PromptManagerModule.prototype.render = function (afterTryGenerate = true) { this.makeDraggable(); this.profileEnd('render'); } - }).catch(() => { - console.log('Timeout while waiting for send press to be false'); - }); + } catch (error) { + this.log('----- Unexpected error while rendering prompt manager -----'); + this.log(error); + this.log(error.stack); + this.log('-----------------------------------------------------------'); + } finally { + configurationContainer.removeEventListener('click', stopPropagation, true); + } } /** diff --git a/public/scripts/openai.js b/public/scripts/openai.js index 8fdaf1f36..5f231f181 100644 --- a/public/scripts/openai.js +++ b/public/scripts/openai.js @@ -1400,7 +1400,7 @@ class Message { this.content = content; if (this.content) { - this.tokens = tokenHandler.count({ role: this.role, content: this.content }) + this.tokens = tokenHandler.count({ role: this.role, content: this.content }); } else { this.tokens = 0; } From db5f815632abf26043f955f2b04f0422a9079f8b Mon Sep 17 00:00:00 2001 From: maver Date: Wed, 16 Aug 2023 19:28:27 +0200 Subject: [PATCH 4/8] Introduce a state lock to prompt manager render function --- public/scripts/PromptManager.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/public/scripts/PromptManager.js b/public/scripts/PromptManager.js index ba3667172..76c4c3ef3 100644 --- a/public/scripts/PromptManager.js +++ b/public/scripts/PromptManager.js @@ -183,6 +183,9 @@ function PromptManagerModule() { } } + // Either 0 for done or 1 for rendering + this.renderState = 0; + // Chatcompletion configuration object this.serviceSettings = null; @@ -589,8 +592,10 @@ PromptManagerModule.prototype.init = function (moduleConfiguration, serviceSetti */ PromptManagerModule.prototype.render = function (afterTryGenerate = true) { if (main_api !== 'openai' || - null === this.activeCharacter) return; + null === this.activeCharacter || + 1 === this.renderState) return; + this.renderState = 1; this.error = null; const stopPropagation = (event) => { @@ -627,6 +632,7 @@ PromptManagerModule.prototype.render = function (afterTryGenerate = true) { this.log(error.stack); this.log('-----------------------------------------------------------'); } finally { + this.renderState = 0; configurationContainer.removeEventListener('click', stopPropagation, true); } } From 6dc8f01ca70a4f2290f3fbf1b70f3aa439e5d0fa Mon Sep 17 00:00:00 2001 From: based Date: Sun, 20 Aug 2023 03:50:51 +1000 Subject: [PATCH 5/8] readded group nudge to end of prompt (needs proper integration into prompt manager) --- public/scripts/openai.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/public/scripts/openai.js b/public/scripts/openai.js index 7720ff94c..197b74f7e 100644 --- a/public/scripts/openai.js +++ b/public/scripts/openai.js @@ -747,6 +747,12 @@ function preparePromptsForChatCompletion(Scenario, charPersonality, name2, world prompts.set(jbReplacement, prompts.index('jailbreak')); } + // TODO: Integrate Group nudge into the prompt manager properly + if(selected_group) { + let group_nudge = {"role": "system", "content": `[Write the next reply only as ${name2}]`}; + openai_msgs.push(group_nudge); + } + // Allow subscribers to manipulate the prompts object eventSource.emit(event_types.OAI_BEFORE_CHATCOMPLETION, prompts); From 6f12ab29f035758ff3c95ace07bb2ec5a650df68 Mon Sep 17 00:00:00 2001 From: based Date: Sun, 20 Aug 2023 04:03:56 +1000 Subject: [PATCH 6/8] fixed {{group}} macro --- public/scripts/openai.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/scripts/openai.js b/public/scripts/openai.js index 197b74f7e..41a2d1d8b 100644 --- a/public/scripts/openai.js +++ b/public/scripts/openai.js @@ -455,9 +455,10 @@ function populateChatHistory(prompts, chatCompletion, type = null, cyclePrompt = // Chat History chatCompletion.add(new MessageCollection('chatHistory'), prompts.index('chatHistory')); + let names = (selected_group && groups.find(x => x.id === selected_group)?.members.map(member => characters.find(c => c.avatar === member)?.name).filter(Boolean).join(', ')) || ''; // Reserve budget for new chat message const newChat = selected_group ? oai_settings.new_group_chat_prompt : oai_settings.new_chat_prompt; - const newChatMessage = new Message('system', newChat, 'newMainChat'); + const newChatMessage = new Message('system', substituteParams(newChat, null, null, null, names), 'newMainChat'); chatCompletion.reserveBudget(newChatMessage); // Reserve budget for continue nudge From c2a4e2e52a207b076524fc073c2eea888b4ebb3f Mon Sep 17 00:00:00 2001 From: based Date: Sun, 20 Aug 2023 04:06:43 +1000 Subject: [PATCH 7/8] fix example dialogue nudge --- public/scripts/openai.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/public/scripts/openai.js b/public/scripts/openai.js index 41a2d1d8b..fde0ab075 100644 --- a/public/scripts/openai.js +++ b/public/scripts/openai.js @@ -518,9 +518,9 @@ function populateDialogueExamples(prompts, chatCompletion) { chatCompletion.add(new MessageCollection('dialogueExamples'), prompts.index('dialogueExamples')); if (openai_msgs_example.length) { const newExampleChat = new Message('system', oai_settings.new_example_chat_prompt, 'newChat'); - chatCompletion.reserveBudget(newExampleChat); - [...openai_msgs_example].forEach((dialogue, dialogueIndex) => { + chatCompletion.reserveBudget(newExampleChat); + chatCompletion.insert(newExampleChat, 'dialogueExamples'); dialogue.forEach((prompt, promptIndex) => { const role = 'system'; const content = prompt.content || ''; @@ -533,11 +533,6 @@ function populateDialogueExamples(prompts, chatCompletion) { } }); }); - - chatCompletion.freeBudget(newExampleChat); - - const chatExamples = chatCompletion.getMessages().getItemByIdentifier('dialogueExamples').getCollection(); - if (chatExamples.length) chatCompletion.insertAtStart(newExampleChat, 'dialogueExamples'); } } From b3377726c4b051b6ddbd0b76b7edacd3ecc8c619 Mon Sep 17 00:00:00 2001 From: based Date: Sun, 20 Aug 2023 04:23:12 +1000 Subject: [PATCH 8/8] Removed unnecessary token reserve --- public/scripts/openai.js | 1 - 1 file changed, 1 deletion(-) diff --git a/public/scripts/openai.js b/public/scripts/openai.js index fde0ab075..9224a3100 100644 --- a/public/scripts/openai.js +++ b/public/scripts/openai.js @@ -519,7 +519,6 @@ function populateDialogueExamples(prompts, chatCompletion) { if (openai_msgs_example.length) { const newExampleChat = new Message('system', oai_settings.new_example_chat_prompt, 'newChat'); [...openai_msgs_example].forEach((dialogue, dialogueIndex) => { - chatCompletion.reserveBudget(newExampleChat); chatCompletion.insert(newExampleChat, 'dialogueExamples'); dialogue.forEach((prompt, promptIndex) => { const role = 'system';