mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
tasks are now a class. fix various bugs
This commit is contained in:
@ -61,28 +61,27 @@ async function generateQuietPrompt(quiet_prompt) {
|
|||||||
function addTask(description, index = null) {
|
function addTask(description, index = null) {
|
||||||
index = index != null ? index: index = globalTasks.length
|
index = index != null ? index: index = globalTasks.length
|
||||||
globalTasks.splice(index, 0, new ObjectiveTask(
|
globalTasks.splice(index, 0, new ObjectiveTask(
|
||||||
index,
|
{description: description}
|
||||||
description,
|
|
||||||
))
|
))
|
||||||
saveState()
|
saveState()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a task either by index or task description. Return current task if none specified
|
|
||||||
function getTask(index = null, taskDescription = null) {
|
// Return the task and index or throw an error
|
||||||
let task = {}
|
function getTaskById(taskId){
|
||||||
if (index == null && taskDescription == null) {
|
if (taskId == null) {
|
||||||
task = currentTask
|
throw `Null task id`
|
||||||
} else if (index != null) {
|
}
|
||||||
task = globalTasks[index]
|
const index = globalTasks.findIndex((task) => task.id === taskId);
|
||||||
} else if (taskDescription != null) {
|
if (index !== -1) {
|
||||||
task = globalTasks.find(task => {
|
return { task: globalTasks[index], index: index };
|
||||||
return task.description == description ? true: false
|
} else {
|
||||||
})
|
throw `Cannot find task with ${taskId}`
|
||||||
}
|
}
|
||||||
return task
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteTask(index){
|
function deleteTask(taskId){
|
||||||
|
const { task, index } = getTaskById(taskId)
|
||||||
globalTasks.splice(index, 1)
|
globalTasks.splice(index, 1)
|
||||||
setCurrentTask()
|
setCurrentTask()
|
||||||
updateUiTaskList()
|
updateUiTaskList()
|
||||||
@ -102,18 +101,18 @@ async function generateTasks() {
|
|||||||
// Create tasks from generated task list
|
// Create tasks from generated task list
|
||||||
for (const task of taskResponse.split('\n').map(x => x.trim())) {
|
for (const task of taskResponse.split('\n').map(x => x.trim())) {
|
||||||
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.map(v => {return v.toSaveState()}), null, 2)} `)
|
||||||
toastr.success(`Generated ${globalTasks.length} tasks`, 'Done!');
|
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
|
// Make sure there are tasks
|
||||||
if (currentTask == null) {
|
if (jQuery.isEmptyObject(currentTask)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
checkCounter = $('#objective-check-frequency').val()
|
checkCounter = $('#objective-check-frequency').val()
|
||||||
@ -123,7 +122,7 @@ async function checkTaskCompleted() {
|
|||||||
|
|
||||||
// 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.toSaveState())} is completed.`)
|
||||||
currentTask.completeTask()
|
currentTask.completeTask()
|
||||||
} else if (!(taskResponse.includes("false"))) {
|
} else if (!(taskResponse.includes("false"))) {
|
||||||
console.warn(`checkTaskCompleted response did not contain true or false. taskResponse: ${taskResponse}`)
|
console.warn(`checkTaskCompleted response did not contain true or false. taskResponse: ${taskResponse}`)
|
||||||
@ -134,23 +133,22 @@ async function checkTaskCompleted() {
|
|||||||
|
|
||||||
|
|
||||||
// Set a task in extensionPrompt context. Defaults to first incomplete
|
// Set a task in extensionPrompt context. Defaults to first incomplete
|
||||||
function setCurrentTask(index = null) {
|
function setCurrentTask(taskId = null) {
|
||||||
const context = getContext();
|
const context = getContext();
|
||||||
currentTask = {};
|
currentTask = {};
|
||||||
|
|
||||||
// Set current task to either the next incomplete task, or the index if valid value is specified
|
// Set current task to either the next incomplete task, or the index
|
||||||
if (index === null) {
|
if (taskId === null) {
|
||||||
currentTask = globalTasks.find(task => !task.completed) || {};
|
currentTask = globalTasks.find(task => !task.completed) || {};
|
||||||
} else {
|
} else {
|
||||||
if (index >= 0 && index < globalTasks.length){
|
const { _, index } = getTaskById(taskId)
|
||||||
toastr.error(`Invalide task index ${index} specified. Must be between 0 and ${globalTasks.length}`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
currentTask = globalTasks[index];
|
currentTask = globalTasks[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the task description and add to extension prompt
|
// Get the task description and add to extension prompt
|
||||||
const { description } = currentTask.description;
|
const description = currentTask.description || null;
|
||||||
|
|
||||||
|
// Now update the extension prompt
|
||||||
|
|
||||||
if (description) {
|
if (description) {
|
||||||
const extensionPromptText = extensionPrompt.replace(/{{task}}/gi, description);
|
const extensionPromptText = extensionPrompt.replace(/{{task}}/gi, description);
|
||||||
@ -164,9 +162,19 @@ function setCurrentTask(index = null) {
|
|||||||
saveState();
|
saveState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let taskIdCounter = 0
|
||||||
|
function getNextTaskId(){
|
||||||
|
// Make sure id does not exist
|
||||||
|
while (globalTasks.find(task => task.id == taskIdCounter) != undefined) {
|
||||||
|
taskIdCounter += 1
|
||||||
|
}
|
||||||
|
const nextId = taskIdCounter
|
||||||
|
console.log(`TaskID assigned: ${nextId}`)
|
||||||
|
taskIdCounter += 1
|
||||||
|
return nextId
|
||||||
|
}
|
||||||
class ObjectiveTask {
|
class ObjectiveTask {
|
||||||
// Task State
|
id
|
||||||
index
|
|
||||||
description
|
description
|
||||||
completed
|
completed
|
||||||
parent
|
parent
|
||||||
@ -179,10 +187,18 @@ class ObjectiveTask {
|
|||||||
deleteTaskButton
|
deleteTaskButton
|
||||||
addTaskButton
|
addTaskButton
|
||||||
|
|
||||||
constructor (index, description, parent=null) {
|
constructor ({id=undefined, description, completed=false, parent=null}) {
|
||||||
this.index = index
|
|
||||||
this.description = description
|
this.description = description
|
||||||
this.parent = parent
|
this.parent = parent
|
||||||
|
this.children = []
|
||||||
|
this.completed = completed
|
||||||
|
|
||||||
|
// Generate a new ID if none specified
|
||||||
|
if (id==undefined){
|
||||||
|
this.id = getNextTaskId()
|
||||||
|
} else {
|
||||||
|
this.id=id
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -197,72 +213,64 @@ class ObjectiveTask {
|
|||||||
// Add a single task to the UI and attach event listeners for user edits
|
// Add a single task to the UI and attach event listeners for user edits
|
||||||
addUiElement() {
|
addUiElement() {
|
||||||
const template = `
|
const template = `
|
||||||
<div id="objective-task-label-${this.index}" class="flex1 checkbox_label">
|
<div id="objective-task-label-${this.id}" class="flex1 checkbox_label">
|
||||||
<span>${this.index}</span>
|
<input id="objective-task-complete-${this.id}" type="checkbox">
|
||||||
<input id="objective-task-complete-${this.index}" type="checkbox">
|
<span class="text_pole" style="display: block" id="objective-task-description-${this.id}" contenteditable>${this.description}</span>
|
||||||
<span class="text_pole" style="display: block" id="objective-task-description-${this.index}" contenteditable>${this.description}</span>
|
<div id="objective-task-delete-${this.id}" class="objective-task-button fa-solid fa-xmark fa-2x" title="Delete Task"></div>
|
||||||
<div id="objective-task-delete-${this.index}" class="objective-task-button fa-solid fa-xmark fa-2x" title="Delete Task"></div>
|
<div id="objective-task-add-${this.id}" class="objective-task-button fa-solid fa-plus fa-2x" title="Add Task"></div>
|
||||||
<div id="objective-task-add-${this.index}" class="objective-task-button fa-solid fa-plus fa-2x" title="Add Task"></div>
|
|
||||||
</div><br>
|
</div><br>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// Add the filled out template
|
// Add the filled out template
|
||||||
$('#objective-tasks').append(template);
|
$('#objective-tasks').append(template);
|
||||||
|
|
||||||
this.completedCheckbox = $(`#objective-task-complete-${this.index}`);
|
this.completedCheckbox = $(`#objective-task-complete-${this.id}`);
|
||||||
this.descriptionSpan = $(`#objective-task-description-${this.index}`);
|
this.descriptionSpan = $(`#objective-task-description-${this.id}`);
|
||||||
this.addButton = $(`#objective-task-add-${this.index}`);
|
this.addButton = $(`#objective-task-add-${this.id}`);
|
||||||
this.deleteButton = $(`#objective-task-delete-${this.index}`);
|
this.deleteButton = $(`#objective-task-delete-${this.id}`);
|
||||||
|
|
||||||
// Add event listeners and set properties
|
// Add event listeners and set properties
|
||||||
$(`#objective-task-complete-${this.index}`).prop('checked', this.completed);
|
$(`#objective-task-complete-${this.id}`).prop('checked', this.completed);
|
||||||
$(`#objective-task-complete-${this.index}`).on('click', () => (this.onCompleteClick()));
|
$(`#objective-task-complete-${this.id}`).on('click', () => (this.onCompleteClick()));
|
||||||
$(`#objective-task-description-${this.index}`).on('keyup', () => (this.onDescriptionUpdate()));
|
$(`#objective-task-description-${this.id}`).on('keyup', () => (this.onDescriptionUpdate()));
|
||||||
$(`#objective-task-delete-${this.index}`).on('click', () => (this.onDeleteClick()));
|
$(`#objective-task-description-${this.id}`).on('focusout', () => (this.onDescriptionFocusout()));
|
||||||
$(`#objective-task-add-${this.index}`).on('click', () => (this.onAddClick()));
|
$(`#objective-task-delete-${this.id}`).on('click', () => (this.onDeleteClick()));
|
||||||
|
$(`#objective-task-add-${this.id}`).on('click', () => (this.onAddClick()));
|
||||||
}
|
}
|
||||||
|
|
||||||
onCompleteClick(){
|
onCompleteClick(){
|
||||||
this.completed = this.completedCheckbox.val()
|
this.completed = this.completedCheckbox.prop('checked')
|
||||||
setCurrentTask();
|
setCurrentTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
onDescriptionUpdate(){
|
onDescriptionUpdate(){
|
||||||
this.description = this.descriptionSpan.val();
|
this.description = this.descriptionSpan.text();
|
||||||
|
}
|
||||||
|
onDescriptionFocusout(){
|
||||||
|
setCurrentTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
onDeleteClick(){
|
onDeleteClick(){
|
||||||
deleteTask(this.index);
|
deleteTask(this.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
onAddClick(){
|
onAddClick(){
|
||||||
addTask("", this.index + 1);
|
const {_, index} = getTaskById(this.id)
|
||||||
|
addTask("", index + 1);
|
||||||
setCurrentTask();
|
setCurrentTask();
|
||||||
updateUiTaskList();
|
updateUiTaskList();
|
||||||
}
|
}
|
||||||
|
|
||||||
toSaveState() {
|
toSaveState() {
|
||||||
return {
|
return {
|
||||||
"index":this.index,
|
"id":this.id,
|
||||||
"description":this.description,
|
"description":this.description,
|
||||||
"completed":this.completed,
|
"completed":this.completed,
|
||||||
|
"parent": this.parent,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TaskManager {
|
|
||||||
tasks = {}
|
|
||||||
|
|
||||||
constructor (){
|
|
||||||
}
|
|
||||||
|
|
||||||
addTask (description, index, parent) {
|
|
||||||
if (this.tasks){}
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteTask (index) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
//###############################//
|
//###############################//
|
||||||
//# UI AND Settings #//
|
//# UI AND Settings #//
|
||||||
//###############################//
|
//###############################//
|
||||||
@ -306,11 +314,11 @@ function saveState() {
|
|||||||
// Dump core state
|
// Dump core state
|
||||||
function debugObjectiveExtension() {
|
function debugObjectiveExtension() {
|
||||||
console.log(JSON.stringify({
|
console.log(JSON.stringify({
|
||||||
"currentTask": currentTask,
|
"currentTask": currentTask.toSaveState(),
|
||||||
"currentChatId": currentChatId,
|
"currentChatId": currentChatId,
|
||||||
"checkCounter": checkCounter,
|
"checkCounter": checkCounter,
|
||||||
"globalObjective": globalObjective,
|
"globalObjective": globalObjective,
|
||||||
"globalTasks": globalTasks,
|
"globalTasks": globalTasks.map(v => {return v.toSaveState()}),
|
||||||
"extension_settings": chat_metadata['objective'],
|
"extension_settings": chat_metadata['objective'],
|
||||||
}, null, 2))
|
}, null, 2))
|
||||||
}
|
}
|
||||||
@ -338,14 +346,6 @@ function updateUiTaskList() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addManualTaskCheckUi() {
|
|
||||||
$('#extensionsMenu').prepend(`
|
|
||||||
<div id="objective-task-manual-check-menu-item" class="list-group-item flex-container flexGap5">
|
|
||||||
<div id="objective-task-manual-check" class="extensionsMenuExtensionButton fa-regular fa-square-check"/></div>
|
|
||||||
Manual Task Check
|
|
||||||
</div>`)
|
|
||||||
$('#objective-task-manual-check-menu-item').attr('title', 'Trigger AI check of completed tasks').on('click', checkTaskCompleted)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trigger creation of new tasks with given objective.
|
// Trigger creation of new tasks with given objective.
|
||||||
async function onGenerateObjectiveClick() {
|
async function onGenerateObjectiveClick() {
|
||||||
@ -393,7 +393,14 @@ function loadSettings() {
|
|||||||
|
|
||||||
// Update globals
|
// Update globals
|
||||||
globalObjective = chat_metadata['objective'].objective
|
globalObjective = chat_metadata['objective'].objective
|
||||||
globalTasks = chat_metadata['objective'].tasks.map((task, index) => {return new ObjectiveTask(index, task.description)})
|
globalTasks = chat_metadata['objective'].tasks.map(task => {
|
||||||
|
return new ObjectiveTask({
|
||||||
|
id: task.id,
|
||||||
|
description: task.description,
|
||||||
|
completed: task.completed,
|
||||||
|
parent: task.parent,
|
||||||
|
})
|
||||||
|
});
|
||||||
checkCounter = chat_metadata['objective'].checkFrequency
|
checkCounter = chat_metadata['objective'].checkFrequency
|
||||||
|
|
||||||
// Update UI elements
|
// Update UI elements
|
||||||
@ -407,6 +414,15 @@ function loadSettings() {
|
|||||||
setCurrentTask()
|
setCurrentTask()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addManualTaskCheckUi() {
|
||||||
|
$('#extensionsMenu').prepend(`
|
||||||
|
<div id="objective-task-manual-check-menu-item" class="list-group-item flex-container flexGap5">
|
||||||
|
<div id="objective-task-manual-check" class="extensionsMenuExtensionButton fa-regular fa-square-check"/></div>
|
||||||
|
Manual Task Check
|
||||||
|
</div>`)
|
||||||
|
$('#objective-task-manual-check-menu-item').attr('title', 'Trigger AI check of completed tasks').on('click', checkTaskCompleted)
|
||||||
|
}
|
||||||
|
|
||||||
jQuery(() => {
|
jQuery(() => {
|
||||||
const settingsHtml = `
|
const settingsHtml = `
|
||||||
<div class="objective-settings">
|
<div class="objective-settings">
|
||||||
@ -429,7 +445,8 @@ jQuery(() => {
|
|||||||
<div class="objective_block objective_block_control flex1">
|
<div class="objective_block objective_block_control flex1">
|
||||||
<label for="objective-chat-depth">In-chat @ Depth</label>
|
<label for="objective-chat-depth">In-chat @ Depth</label>
|
||||||
<input id="objective-chat-depth" class="text_pole widthUnset" type="number" min="0" max="99" />
|
<input id="objective-chat-depth" class="text_pole widthUnset" type="number" min="0" max="99" />
|
||||||
</div>
|
</div>
|
||||||
|
<br>
|
||||||
<div class="objective_block objective_block_control flex1">
|
<div class="objective_block objective_block_control flex1">
|
||||||
<label for="objective-check-frequency">Task Check Frequency</label>
|
<label for="objective-check-frequency">Task Check Frequency</label>
|
||||||
<input id="objective-check-frequency" class="text_pole widthUnset" type="number" min="0" max="99" />
|
<input id="objective-check-frequency" class="text_pole widthUnset" type="number" min="0" max="99" />
|
||||||
|
Reference in New Issue
Block a user