Migrate objective extension settings to chat_metadata

This commit is contained in:
SillyLossy
2023-06-01 12:34:33 +03:00
parent 9d418696e1
commit 9774f3b8c1
2 changed files with 105 additions and 70 deletions

View File

@ -1,10 +1,9 @@
import { callPopup, extension_prompt_types } from "../../../script.js"; import { chat_metadata } from "../../../script.js";
import { getContext, extension_settings } from "../../extensions.js"; import { getContext, extension_settings } from "../../extensions.js";
import { import {
substituteParams, substituteParams,
eventSource, eventSource,
event_types, event_types,
saveSettingsDebounced
} from "../../../script.js"; } from "../../../script.js";
const MODULE_NAME = "Objective" const MODULE_NAME = "Objective"
@ -31,7 +30,7 @@ const objectivePrompts = {
6. Serve the food 6. Serve the food
7. Enjoy eating the meal with {{user}} 7. Enjoy eating the meal with {{user}}
`, `,
"checkTaskCompleted": `Pause your roleplay. Determine if this task is completed: [{{task}}]. "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. To do this, examine the most recent messages. Your response must only contain either true or false, nothing other words.
Example output: Example output:
true true
@ -60,7 +59,7 @@ async function generateQuietPrompt(quiet_prompt) {
//###############################// //###############################//
// Accepts optional position. Defaults to adding to end of list. // Accepts optional position. Defaults to adding to end of list.
function addTask(description, position=null) { function addTask(description, position = null) {
position = position ? position != null : position = globalTasks.length position = position ? position != null : position = globalTasks.length
globalTasks.splice(position, 0, { globalTasks.splice(position, 0, {
"description": description, "description": description,
@ -70,13 +69,13 @@ function addTask(description, position=null) {
} }
// Get a task either by index or task description. Return current task if none specified // Get a task either by index or task description. Return current task if none specified
function getTask(index=null, taskDescription=null){ function getTask(index = null, taskDescription = null) {
let task = {} let task = {}
if (index == null && taskDescription==null) { if (index == null && taskDescription == null) {
task = currentTask task = currentTask
} else if (index != null){ } else if (index != null) {
task = globalObjective[index] task = globalObjective[index]
} else if (taskDescription != null){ } else if (taskDescription != null) {
task = globalTasks.find(task => { task = globalTasks.find(task => {
return true ? task.description == description : false return true ? task.description == description : false
}) })
@ -97,6 +96,7 @@ function completeTask(task) {
async function generateTasks() { 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`) console.log(`Generating tasks for objective with prompt`)
toastr.info('Generating tasks for objective', 'Please wait...');
const taskResponse = await generateQuietPrompt(prompt) const taskResponse = await generateQuietPrompt(prompt)
globalTasks = [] globalTasks = []
const numberedListPattern = /^\d+\./ const numberedListPattern = /^\d+\./
@ -104,22 +104,23 @@ async function generateTasks() {
// Add numbered tasks, store them without the numbers. // Add numbered tasks, store them without the numbers.
for (const task of taskResponse.split('\n')) { for (const task of taskResponse.split('\n')) {
if (task.match(numberedListPattern) != null) { if (task.match(numberedListPattern) != null) {
addTask(task.replace(numberedListPattern,'').trim()) addTask(task.replace(numberedListPattern, '').trim())
} }
} }
updateUiTaskList() updateUiTaskList()
console.info(`Response for Objective: '${globalObjective}' was \n'${taskResponse}', \nwhich created tasks \n${JSON.stringify(globalTasks, null, 2)} `) console.info(`Response for Objective: '${globalObjective}' was \n'${taskResponse}', \nwhich created tasks \n${JSON.stringify(globalTasks, null, 2)} `)
toastr.success(`Generated ${globalTasks.length} tasks`, 'Done!');
} }
// Call Quiet Generate to check if a task is completed // Call Quiet Generate to check if a task is completed
async function checkTaskCompleted() { async function checkTaskCompleted() {
// Make sure there are tasks and check is enabled // Make sure there are tasks and check is enabled
if (currentTask == {} || $('#objective-check-frequency').val() == 0){ if (currentTask == {} || $('#objective-check-frequency').val() == 0) {
return return
} }
// Check only at specified interval // Check only at specified interval
if (checkCounter > 0){ if (checkCounter > 0) {
return return
} }
checkCounter = $('#objective-check-frequency').val() checkCounter = $('#objective-check-frequency').val()
@ -128,7 +129,7 @@ async function checkTaskCompleted() {
const taskResponse = (await generateQuietPrompt(prompt)).toLowerCase() const taskResponse = (await generateQuietPrompt(prompt)).toLowerCase()
// Check response if task complete // Check response if task complete
if (taskResponse.includes("true")){ if (taskResponse.includes("true")) {
console.info(`Character determined task '${JSON.stringify(currentTask)} is completed.`) console.info(`Character determined task '${JSON.stringify(currentTask)} is completed.`)
completeTask(getTask()) completeTask(getTask())
} else if (!(taskResponse.includes("false"))) { } else if (!(taskResponse.includes("false"))) {
@ -143,26 +144,26 @@ async function checkTaskCompleted() {
function setCurrentTask(index = null) { function setCurrentTask(index = null) {
const context = getContext(); const context = getContext();
let currentTask = {}; let currentTask = {};
if (index === null) { if (index === null) {
currentTask = globalTasks.find(task => !task.completed) || {}; currentTask = globalTasks.find(task => !task.completed) || {};
} else if (index >= 0 && index < globalTasks.length) { } else if (index >= 0 && index < globalTasks.length) {
currentTask = globalTasks[index]; currentTask = globalTasks[index];
} }
const { description } = currentTask; const { description } = currentTask;
const injectPromptsTask = injectPrompts["task"].replace(/{{task}}/gi, description); const injectPromptsTask = injectPrompts["task"].replace(/{{task}}/gi, description);
if (description) { if (description) {
context.setExtensionPrompt(MODULE_NAME, injectPromptsTask, 1, $('#objective-chat-depth').val()); context.setExtensionPrompt(MODULE_NAME, injectPromptsTask, 1, $('#objective-chat-depth').val());
console.info(`Current task in context.extensionPrompts.Objective is ${JSON.stringify(context.extensionPrompts.Objective)}`); console.info(`Current task in context.extensionPrompts.Objective is ${JSON.stringify(context.extensionPrompts.Objective)}`);
} else { } else {
context.setExtensionPrompt(MODULE_NAME, ''); context.setExtensionPrompt(MODULE_NAME, '');
console.info(`No current task`); console.info(`No current task`);
} }
saveState(); saveState();
} }
@ -175,37 +176,43 @@ const defaultSettings = {
objective: "", objective: "",
tasks: [], tasks: [],
chatDepth: 2, chatDepth: 2,
checkFrequency:3, checkFrequency: 3,
hideTasks: false hideTasks: false
} }
// Convenient single call. Not much at the moment. // Convenient single call. Not much at the moment.
function resetState(){ function resetState() {
loadSettings(); loadSettings();
} }
// //
function saveState(){ function saveState() {
if (currentChatId == ""){ const context = getContext();
currentChatId = getContext().chatId
if (currentChatId == "") {
currentChatId = context.chatId
} }
extension_settings.objective[currentChatId].objective = globalObjective
extension_settings.objective[currentChatId].tasks = globalTasks chat_metadata['objective'] = {
extension_settings.objective[currentChatId].checkFrequency = $('#objective-check-frequency').val() objective: globalObjective,
extension_settings.objective[currentChatId].chatDepth = $('#objective-chat-depth').val() tasks: globalTasks,
extension_settings.objective[currentChatId].hideTasks = $('#objective-hide-tasks').prop('checked') checkFrequency: $('#objective-check-frequency').val(),
saveSettingsDebounced() chatDepth: $('#objective-chat-depth').val(),
hideTasks: $('#objective-hide-tasks').prop('checked'),
}
context.saveMetadata();
} }
// Dump core state // Dump core state
function debugObjectiveExtension(){ function debugObjectiveExtension() {
console.log(JSON.stringify({ console.log(JSON.stringify({
"currentTask": currentTask, "currentTask": currentTask,
"currentChatId": currentChatId, "currentChatId": currentChatId,
"checkCounter": checkCounter, "checkCounter": checkCounter,
"globalObjective": globalObjective, "globalObjective": globalObjective,
"globalTasks": globalTasks, "globalTasks": globalTasks,
"extension_settings": extension_settings.objective[currentChatId], "extension_settings": chat_metadata['objective'],
}, null, 2)) }, null, 2))
} }
@ -221,22 +228,22 @@ function addUiTask(taskIndex, taskComplete, taskDescription) {
<span class="text_pole" style="display: block" id="objective-task-description-${taskIndex}" contenteditable>${taskDescription}</span> <span class="text_pole" style="display: block" id="objective-task-description-${taskIndex}" contenteditable>${taskDescription}</span>
</div><br> </div><br>
`; `;
// Add the filled out template // Add the filled out template
$('#objective-tasks').append(template); $('#objective-tasks').append(template);
// Add event listeners and set properties // Add event listeners and set properties
$(`#objective-task-complete-${taskIndex}`).prop('checked', taskComplete); $(`#objective-task-complete-${taskIndex}`).prop('checked', taskComplete);
$(`#objective-task-complete-${taskIndex}`).on('click', event => { $(`#objective-task-complete-${taskIndex}`).on('click', event => {
const index = Number(event.target.id.split('-').pop()); const index = Number(event.target.id.split('-').pop());
globalTasks[index].completed = event.target.checked; globalTasks[index].completed = event.target.checked;
setCurrentTask(); setCurrentTask();
}); });
$(`#objective-task-description-${taskIndex}`).on('keyup', event => { $(`#objective-task-description-${taskIndex}`).on('keyup', event => {
const index = Number(event.target.id.split('-').pop()); const index = Number(event.target.id.split('-').pop());
globalTasks[index].description = event.target.textContent; globalTasks[index].description = event.target.textContent;
}); });
} }
// Populate UI task list // Populate UI task list
function updateUiTaskList() { function updateUiTaskList() {
@ -268,8 +275,8 @@ function onCheckFrequencyInput() {
saveState() saveState()
} }
function onHideTasksInput(){ function onHideTasksInput() {
$('#objective-tasks').prop('hidden',$('#objective-hide-tasks').prop('checked')) $('#objective-tasks').prop('hidden', $('#objective-hide-tasks').prop('checked'))
saveState() saveState()
} }
@ -281,23 +288,29 @@ function loadSettings() {
if (currentChatId == undefined) { if (currentChatId == undefined) {
return return
} }
if (!(currentChatId in extension_settings.objective)) {
extension_settings.objective[currentChatId] = {} // Migrate existing settings
Object.assign(extension_settings.objective[currentChatId], defaultSettings) if (currentChatId in extension_settings.objective) {
chat_metadata['objective'] = extension_settings.objective[currentChatId];
delete extension_settings.objective[currentChatId];
}
if (!('objective' in chat_metadata)) {
Object.assign(chat_metadata, { objective: defaultSettings });
} }
// Update globals // Update globals
globalObjective = extension_settings.objective[currentChatId].objective globalObjective = chat_metadata['objective'].objective
globalTasks = extension_settings.objective[currentChatId].tasks globalTasks = chat_metadata['objective'].tasks
checkCounter = extension_settings.objective[currentChatId].checkFrequency checkCounter = chat_metadata['objective'].checkFrequency
// Update UI elements // Update UI elements
$('#objective-counter').text(checkCounter) $('#objective-counter').text(checkCounter)
$("#objective-text").text(globalObjective) $("#objective-text").text(globalObjective)
updateUiTaskList() updateUiTaskList()
$('#objective-chat-depth').val(extension_settings.objective[currentChatId].chatDepth) $('#objective-chat-depth').val(chat_metadata['objective'].chatDepth)
$('#objective-check-frequency').val(extension_settings.objective[currentChatId].checkFrequency) $('#objective-check-frequency').val(chat_metadata['objective'].checkFrequency)
$('#objective-hide-tasks').prop('checked',extension_settings.objective[currentChatId].hideTasks) $('#objective-hide-tasks').prop('checked', chat_metadata['objective'].hideTasks)
onHideTasksInput() onHideTasksInput()
setCurrentTask() setCurrentTask()
} }
@ -313,32 +326,42 @@ jQuery(() => {
<div class="inline-drawer-content"> <div class="inline-drawer-content">
<label for="objective-text"><small>Enter an objective and generate tasks. The AI will attempt to complete tasks autonomously</small></label> <label for="objective-text"><small>Enter an objective and generate tasks. The AI will attempt to complete tasks autonomously</small></label>
<textarea id="objective-text" type="text" class="text_pole textarea_compact" rows="4"></textarea> <textarea id="objective-text" type="text" class="text_pole textarea_compact" rows="4"></textarea>
<label class="checkbox_label"><input id="objective-generate" class="menu_button" type="submit" value="Generate Tasks" /> <div class="objective_block">
<small>Automatically generate tasks for Objective. Takes a moment.</small></label></br> <input id="objective-generate" class="menu_button" type="submit" value="Generate Tasks" />
<small>Automatically generate tasks for Objective. Takes a moment.</small>
</div>
</br>
<label class="checkbox_label"><input id="objective-hide-tasks" type="checkbox"> Hide Tasks</label><br> <label class="checkbox_label"><input id="objective-hide-tasks" type="checkbox"> Hide Tasks</label><br>
<div id="objective-tasks"> </div> <div id="objective-tasks"> </div>
<label for="objective-chat-depth">In-chat @ Depth</label> <div class="objective_block">
<input id="objective-chat-depth" class="text_pole widthUnset" type="number" min="0" max="99" /><br> <div class="objective_block objective_block_control flex1">
<label for="objective-check-frequency">Task Check Frequency</label> <label for="objective-chat-depth">In-chat @ Depth</label>
<input id="objective-check-frequency" class="text_pole widthUnset" type="number" min="" max="99" /><small> (0 = disabled) </small><br> <input id="objective-chat-depth" class="text_pole widthUnset" type="number" min="0" max="99" />
<span> Messages until next AI task completion check <span id="objective-counter">0</span></span> </div>
<div class="objective_block objective_block_control flex1">
<label for="objective-check-frequency">Task Check Frequency</label>
<input id="objective-check-frequency" class="text_pole widthUnset" type="number" min="0" max="99" />
<small>(0 = disabled)</small>
</div>
</div>
<span> Messages until next AI task completion check <span id="objective-counter">0</span></span>
<hr class="sysHR"> <hr class="sysHR">
</div> </div>
</div>`; </div>`;
$('#extensions_settings').append(settingsHtml); $('#extensions_settings').append(settingsHtml);
$('#objective-generate').on('click', onGenerateObjectiveClick) $('#objective-generate').on('click', onGenerateObjectiveClick)
$('#objective-chat-depth').on('input',onChatDepthInput) $('#objective-chat-depth').on('input', onChatDepthInput)
$("#objective-check-frequency").on('input',onCheckFrequencyInput) $("#objective-check-frequency").on('input', onCheckFrequencyInput)
$('#objective-hide-tasks').on('click', onHideTasksInput) $('#objective-hide-tasks').on('click', onHideTasksInput)
loadSettings() loadSettings()
eventSource.on(event_types.CHAT_CHANGED, () => { eventSource.on(event_types.CHAT_CHANGED, () => {
resetState() resetState()
}); });
eventSource.on(event_types.MESSAGE_RECEIVED, () => { eventSource.on(event_types.MESSAGE_RECEIVED, () => {
if (currentChatId == undefined){ if (currentChatId == undefined) {
return return
} }
if ($("#objective-check-frequency").val() > 0) { if ($("#objective-check-frequency").val() > 0) {

View File

@ -1,4 +1,16 @@
#objective-counter { #objective-counter {
font-weight: 600; font-weight: 600;
color: orange; color: orange;
} }
.objective_block {
display: flex;
flex-direction: row;
align-items: center;
column-gap: 10px;
}
.objective_block_control small,
.objective_block_control label {
width: max-content;
}