diff --git a/public/scripts/extensions/objective/index.js b/public/scripts/extensions/objective/index.js index 3485da1ec..781fdb98c 100644 --- a/public/scripts/extensions/objective/index.js +++ b/public/scripts/extensions/objective/index.js @@ -1,4 +1,4 @@ -import { chat_metadata } from "../../../script.js"; +import { chat_metadata, callPopup, saveSettingsDebounced } from "../../../script.js"; import { getContext, extension_settings, saveMetadataDebounced } from "../../extensions.js"; import { substituteParams, @@ -18,30 +18,30 @@ let currentTask = null let checkCounter = 0 -const objectivePrompts = { +const defaultPrompts = { "createTask": `Pause your roleplay and generate a list of tasks to complete an objective. Your next response must be formatted as a numbered list of plain text entries. Do not include anything but the numbered list. The list must be prioritized in the order that tasks must be completed. - The objective that you must make a numbered task list for is: [{{objective}}]. - The tasks created should take into account the character traits of {{char}}. These tasks may or may not involve {{user}} directly. Be sure to include the objective as the final task. +The objective that you must make a numbered task list for is: [{{objective}}]. +The tasks created should take into account the character traits of {{char}}. These tasks may or may not involve {{user}} directly. Be sure to include the objective as the final task. - Given an example objective of 'Make me a four course dinner', here is an example output: - 1. Determine what the courses will be - 2. Find recipes for each course - 3. Go shopping for supplies with {{user}} - 4. Cook the food - 5. Get {{user}} to set the table - 6. Serve the food - 7. Enjoy eating the meal with {{user}} +Given an example objective of 'Make me a four course dinner', here is an example output: +1. Determine what the courses will be +2. Find recipes for each course +3. Go shopping for supplies with {{user}} +4. Cook the food +5. Get {{user}} to set the table +6. Serve the food +7. Enjoy eating the meal with {{user}} `, "checkTaskCompleted": `Pause your roleplay. Determine if this task is completed: [{{task}}]. - To do this, examine the most recent messages. Your response must only contain either true or false, nothing other words. - Example output: - true - ` +To do this, examine the most recent messages. Your response must only contain either true or false, nothing other words. +Example output: +true + `, + 'currentTask':`Your current task is [{{task}}]. Balance existing roleplay with completing this task.` } -const extensionPrompt = "Your current task is [{{task}}]. Balance existing roleplay with completing this task." - +let objectivePrompts = defaultPrompts //###############################// //# Task Management #// @@ -80,7 +80,7 @@ function deleteTask(taskId){ // Call Quiet Generate to create task list using character context, then convert to tasks. Should not be called much. async function generateTasks() { - const prompt = substituteParams(objectivePrompts["createTask"].replace(/{{objective}}/gi, globalObjective)); + const prompt = substituteParams(objectivePrompts.createTask.replace(/{{objective}}/gi, globalObjective)); console.log(`Generating tasks for objective with prompt`) toastr.info('Generating tasks for objective', 'Please wait...'); const taskResponse = await generateQuietPrompt(prompt) @@ -108,7 +108,7 @@ async function checkTaskCompleted() { } checkCounter = $('#objective-check-frequency').val() - const prompt = substituteParams(objectivePrompts["checkTaskCompleted"].replace(/{{task}}/gi, currentTask.description)); + const prompt = substituteParams(objectivePrompts.checkTaskCompleted.replace(/{{task}}/gi, currentTask.description)); const taskResponse = (await generateQuietPrompt(prompt)).toLowerCase() // Check response if task complete @@ -142,7 +142,9 @@ function setCurrentTask(taskId = null) { // Now update the extension prompt if (description) { - const extensionPromptText = extensionPrompt.replace(/{{task}}/gi, description); + const extensionPromptText = objectivePrompts.currentTask.replace(/{{task}}/gi, description); + $('.objective-task').css({'border-color':'','border-width':''}) // Clear highlights + currentTask.descriptionSpan.css({'border-color':'yellow','border-width':'2px'}); // Highlight current task context.setExtensionPrompt(MODULE_NAME, extensionPromptText, 1, $('#objective-chat-depth').val()); console.info(`Current task in context.extensionPrompts.Objective is ${JSON.stringify(context.extensionPrompts.Objective)}`); } else { @@ -206,7 +208,7 @@ class ObjectiveTask { const template = `
- ${this.description} + ${this.description}

@@ -272,7 +274,8 @@ const defaultSettings = { tasks: [], chatDepth: 2, checkFrequency: 3, - hideTasks: false + hideTasks: false, + prompts: defaultPrompts, } // Convenient single call. Not much at the moment. @@ -297,6 +300,7 @@ function saveState() { checkFrequency: $('#objective-check-frequency').val(), chatDepth: $('#objective-chat-depth').val(), hideTasks: $('#objective-hide-tasks').prop('checked'), + prompts: objectivePrompts, } saveMetadataDebounced(); @@ -305,12 +309,12 @@ function saveState() { // Dump core state function debugObjectiveExtension() { console.log(JSON.stringify({ - "currentTask": currentTask.toSaveState(), - "currentChatId": currentChatId, - "checkCounter": checkCounter, + "currentTask": currentTask.description, "globalObjective": globalObjective, "globalTasks": globalTasks.map(v => {return v.toSaveState()}), - "extension_settings": chat_metadata['objective'], + "chat_metadata": chat_metadata['objective'], + "extension_settings": extension_settings['objective'], + "prompts": objectivePrompts }, null, 2)) } @@ -364,9 +368,113 @@ function onHideTasksInput() { saveState() } +function onEditPromptClick() { + let popupText = '' + popupText += ` +
+
+
+
+ + + + + + +
+
+ + + + + +
+
` + callPopup(popupText, 'text') + populateCustomPrompts() + + // Set current values + $('#objective-prompt-generate').val(objectivePrompts.createTask) + $('#objective-prompt-check').val(objectivePrompts.checkTaskCompleted) + $('#objective-prompt-extension-prompt').val(objectivePrompts.currentTask) + + // Handle value updates + $('#objective-prompt-generate').on('input', () => { + objectivePrompts.createTask = $('#objective-prompt-generate').val() + }) + $('#objective-prompt-check').on('input', () => { + objectivePrompts.checkTaskCompleted = $('#objective-prompt-check').val() + }) + $('#objective-prompt-extension-prompt').on('input', () => { + objectivePrompts.currentTask = $('#objective-prompt-extension-prompt').val() + }) + + // Handle save + $('#objective-custom-prompt-save').on('click', () => { + addCustomPrompt($('#objective-custom-prompt-name').val(), objectivePrompts) + }) + + // Handle delete + $('#objective-custom-prompt-delete').on('click', () => { + const optionSelected = $("#objective-prompt-load").find(':selected').val() + deleteCustomPrompt(optionSelected) + }) + + // Handle load + $('#objective-prompt-load').on('change', loadCustomPrompt) +} + +function addCustomPrompt(customPromptName, customPrompts) { + if (customPromptName == "") { + toastr.warning("Please set custom prompt name to save.") + return + } + Object.assign(extension_settings.objective.customPrompts[customPromptName], customPrompts) + saveSettingsDebounced() + populateCustomPrompts() +} + +function deleteCustomPrompt(customPromptName){ + if (customPromptName == "default"){ + toastr.error("Cannot delete default prompt") + return + } + delete extension_settings.objective.customPrompts[customPromptName] + saveSettingsDebounced() + populateCustomPrompts() + loadCustomPrompt() +} + +function loadCustomPrompt(){ + const optionSelected = $("#objective-prompt-load").find(':selected').val() + console.log(optionSelected) + objectivePrompts = extension_settings.objective.customPrompts[optionSelected] + + $('#objective-prompt-generate').val(objectivePrompts.createTask) + $('#objective-prompt-check').val(objectivePrompts.checkTaskCompleted) + $('#objective-prompt-extension-prompt').val(objectivePrompts.currentTask) +} + +function populateCustomPrompts(){ + // Populate saved prompts + $('#objective-prompt-load').empty() + for (const customPromptName in extension_settings.objective.customPrompts){ + const option = document.createElement('option'); + option.innerText = customPromptName; + option.value = customPromptName; + option.selected = customPromptName + $('#objective-prompt-load').append(option) + } +} + function loadSettings() { // Load/Init settings for chatId currentChatId = getContext().chatId + + // Init extension settings + if (Object.keys(extension_settings.objective).length === 0) { + Object.assign(extension_settings.objective, { 'customPrompts': {'default':defaultPrompts}}) + } // Bail on home screen if (currentChatId == undefined) { @@ -394,6 +502,7 @@ function loadSettings() { }) }); checkCounter = chat_metadata['objective'].checkFrequency + objectivePrompts = chat_metadata['objective'].prompts // Update UI elements $('#objective-counter').text(checkCounter) @@ -402,7 +511,7 @@ function loadSettings() { $('#objective-chat-depth').val(chat_metadata['objective'].chatDepth) $('#objective-check-frequency').val(chat_metadata['objective'].checkFrequency) $('#objective-hide-tasks').prop('checked', chat_metadata['objective'].hideTasks) - onHideTasksInput() + $('#objective-tasks').prop('hidden', $('#objective-hide-tasks').prop('checked')) setCurrentTask() } @@ -446,6 +555,9 @@ jQuery(() => { Messages until next AI task completion check 0 +
+ +

`; @@ -456,6 +568,7 @@ jQuery(() => { $('#objective-chat-depth').on('input', onChatDepthInput) $("#objective-check-frequency").on('input', onCheckFrequencyInput) $('#objective-hide-tasks').on('click', onHideTasksInput) + $('#objective_prompt_edit').on('click', onEditPromptClick) loadSettings() eventSource.on(event_types.CHAT_CHANGED, () => {