CC/PM: Add generation type trigger prompt filter (#4281) * CC/PM: Add generation type trigger prompt filter Closes #4276 * Fix element cast type * Narrower element types * Change trigger to multiple select * Extract class scope function * Fix control name * Add 'enabled' property to Prompt class and update type annotations in PromptManager methods * Clarify placeholder of multiselect
Signed| @@ -112,6 +112,10 @@ | |||
| 112 | flex-direction: column; | 112 | flex-direction: column; |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | .completion_prompt_manager_popup_entry_form .select2-container { | ||
| 116 | margin: 5px 0; | ||
| 117 | } | ||
| 118 | |||
| 115 | #completion_prompt_manager_popup .completion_prompt_manager_popup_entry_form_control:has(#completion_prompt_manager_popup_entry_form_prompt) { | 119 | #completion_prompt_manager_popup .completion_prompt_manager_popup_entry_form_control:has(#completion_prompt_manager_popup_entry_form_prompt) { |
| 116 | flex: 1; | 120 | flex: 1; |
| 117 | display: flex; | 121 | display: flex; |
| @@ -6720,6 +6720,22 @@ | |||
| 6720 | </select> | 6720 | </select> |
| 6721 | <div class="text_muted" data-i18n="To whom this message will be attributed.">To whom this message will be attributed.</div> | 6721 | <div class="text_muted" data-i18n="To whom this message will be attributed.">To whom this message will be attributed.</div> |
| 6722 | </div> | 6722 | </div> |
| 6723 | <div class="completion_prompt_manager_popup_entry_form_control flex1"> | ||
| 6724 | <label for="completion_prompt_manager_popup_entry_form_injection_trigger"> | ||
| 6725 | <span data-i18n="Triggers">Triggers</span> | ||
| 6726 | </label> | ||
| 6727 | <select id="completion_prompt_manager_popup_entry_form_injection_trigger" class="text_pole" name="injection_trigger" multiple> | ||
| 6728 | <option data-i18n="Normal" value="normal">Normal</option> | ||
| 6729 | <option data-i18n="Continue" value="continue">Continue</option> | ||
| 6730 | <option data-i18n="Impersonate" value="impersonate">Impersonate</option> | ||
| 6731 | <option data-i18n="Swipe" value="swipe">Swipe</option> | ||
| 6732 | <option data-i18n="Regenerate" value="regenerate">Regenerate</option> | ||
| 6733 | <option data-i18n="Quiet" value="quiet">Quiet</option> | ||
| 6734 | </select> | ||
| 6735 | <div class="text_muted" data-i18n="Filter to specific generation types."> | ||
| 6736 | Filter to specific generation types. | ||
| 6737 | </div> | ||
| 6738 | </div> | ||
| 6723 | </div> | 6739 | </div> |
| 6724 | <div class="flex-container gap10px"> | 6740 | <div class="flex-container gap10px"> |
| 6725 | <div class="completion_prompt_manager_popup_entry_form_control flex1"> | 6741 | <div class="completion_prompt_manager_popup_entry_form_control flex1"> |
| @@ -3540,7 +3540,6 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 3540 | 'impersonate', | 3540 | 'impersonate', |
| 3541 | 'quiet', | 3541 | 'quiet', |
| 3542 | 'continue', | 3542 | 'continue', |
| 3543 | 'ask_command', | ||
| 3544 | ]; | 3543 | ]; |
| 3545 | //for normal messages sent from user.. | 3544 | //for normal messages sent from user.. |
| 3546 | if ((textareaText != '' || (hasPendingFileAttachment() && !noAttachTypes.includes(type))) && !automatic_trigger && type !== 'quiet' && !dryRun) { | 3545 | if ((textareaText != '' || (hasPendingFileAttachment() && !noAttachTypes.includes(type))) && !automatic_trigger && type !== 'quiet' && !dryRun) { |
| @@ -4380,7 +4379,6 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 4380 | cyclePrompt: cyclePrompt, | 4379 | cyclePrompt: cyclePrompt, |
| 4381 | systemPromptOverride: system, | 4380 | systemPromptOverride: system, |
| 4382 | jailbreakPromptOverride: jailbreak, | 4381 | jailbreakPromptOverride: jailbreak, |
| 4383 | personaDescription: persona, | ||
| 4384 | messages: oaiMessages, | 4382 | messages: oaiMessages, |
| 4385 | messageExamples: oaiMessageExamples, | 4383 | messageExamples: oaiMessageExamples, |
| 4386 | }, dryRun); | 4384 | }, dryRun); |
| @@ -6,7 +6,7 @@ import { event_types, eventSource, is_send_press, main_api, substituteParams } f | |||
| 6 | import { is_group_generating } from './group-chats.js'; | 6 | import { is_group_generating } from './group-chats.js'; |
| 7 | import { Message, MessageCollection, TokenHandler } from './openai.js'; | 7 | import { Message, MessageCollection, TokenHandler } from './openai.js'; |
| 8 | import { power_user } from './power-user.js'; | 8 | import { power_user } from './power-user.js'; |
| 9 | import { debounce, waitUntilCondition, escapeHtml } from './utils.js'; | 9 | import { debounce, waitUntilCondition, escapeHtml, uuidv4 } from './utils.js'; |
| 10 | import { debounce_timeout } from './constants.js'; | 10 | import { debounce_timeout } from './constants.js'; |
| 11 | import { renderTemplateAsync } from './templates.js'; | 11 | import { renderTemplateAsync } from './templates.js'; |
| 12 | import { Popup } from './popup.js'; | 12 | import { Popup } from './popup.js'; |
| @@ -29,6 +29,7 @@ function debouncePromise(func, delay) { | |||
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | const DEFAULT_DEPTH = 4; | 31 | const DEFAULT_DEPTH = 4; |
| 32 | const DEFAULT_ORDER = 100; | ||
| 32 | 33 | ||
| 33 | /** | 34 | /** |
| 34 | * @enum {number} | 35 | * @enum {number} |
| @@ -77,25 +78,108 @@ const registerPromptManagerMigration = () => { | |||
| 77 | * Represents a prompt. | 78 | * Represents a prompt. |
| 78 | */ | 79 | */ |
| 79 | class Prompt { | 80 | class Prompt { |
| 80 | identifier; role; content; name; system_prompt; position; injection_position; injection_depth; injection_order; forbid_overrides; extension; | 81 | /** |
| 82 | * Indicates if the prompt is enabled. | ||
| 83 | * @type {boolean} | ||
| 84 | */ | ||
| 85 | enabled; | ||
| 86 | |||
| 87 | /** | ||
| 88 | * Unique identifier for the prompt. | ||
| 89 | * @type {string} | ||
| 90 | */ | ||
| 91 | identifier; | ||
| 92 | |||
| 93 | /** | ||
| 94 | * Role of the prompt, e.g., 'system', 'user', etc. | ||
| 95 | * @type {string} | ||
| 96 | */ | ||
| 97 | role; | ||
| 98 | |||
| 99 | /** | ||
| 100 | * Content of the prompt. | ||
| 101 | * @type {string} | ||
| 102 | */ | ||
| 103 | content; | ||
| 104 | |||
| 105 | /** | ||
| 106 | * Display name of the prompt. | ||
| 107 | * @type {string} | ||
| 108 | */ | ||
| 109 | name; | ||
| 110 | |||
| 111 | /** | ||
| 112 | * Indicates if the prompt is a system prompt. | ||
| 113 | * @type {boolean} | ||
| 114 | */ | ||
| 115 | system_prompt; | ||
| 116 | |||
| 117 | /** | ||
| 118 | * Position of the prompt in the prompt list. | ||
| 119 | * @type {string|number} | ||
| 120 | */ | ||
| 121 | position; | ||
| 122 | |||
| 123 | /** | ||
| 124 | * Inject position of the prompt (relative = 0 or in-chat = 1) | ||
| 125 | * @type {number} | ||
| 126 | */ | ||
| 127 | injection_position; | ||
| 128 | |||
| 129 | /** | ||
| 130 | * Depth of the prompt in the chat. | ||
| 131 | * @type {number} | ||
| 132 | */ | ||
| 133 | injection_depth; | ||
| 134 | |||
| 135 | /** | ||
| 136 | * Order of the prompt in the chat. | ||
| 137 | * @type {number} | ||
| 138 | */ | ||
| 139 | injection_order; | ||
| 140 | |||
| 141 | /** | ||
| 142 | * Indicates if the prompt should not be overridden. | ||
| 143 | * @type {boolean} | ||
| 144 | */ | ||
| 145 | forbid_overrides; | ||
| 146 | |||
| 147 | /** | ||
| 148 | * Prompt is added by an extension. | ||
| 149 | * @type {boolean} | ||
| 150 | */ | ||
| 151 | extension; | ||
| 152 | |||
| 153 | /** | ||
| 154 | * A list of generation type triggers for the prompt injection. | ||
| 155 | * @type {string[]} | ||
| 156 | */ | ||
| 157 | injection_trigger; | ||
| 158 | |||
| 159 | /** | ||
| 160 | * Indicates if the prompt is a marker prompt. | ||
| 161 | * @type {boolean} | ||
| 162 | */ | ||
| 163 | marker; | ||
| 81 | 164 | ||
| 82 | /** | 165 | /** |
| 83 | * Create a new Prompt instance. | 166 | * Create a new Prompt instance. |
| 84 | * | 167 | * |
| 85 | * @param {Object} param0 - Object containing the properties of the prompt. | 168 | * @param {Object} [param0] - Object containing the properties of the prompt. |
| 86 | * @param {string} param0.identifier - The unique identifier of the prompt. | 169 | * @param {string} [param0.identifier] - The unique identifier of the prompt. |
| 87 | * @param {string} param0.role - The role associated with the prompt. | 170 | * @param {string} [param0.role] - The role associated with the prompt. |
| 88 | * @param {string} param0.content - The content of the prompt. | 171 | * @param {string} [param0.content] - The content of the prompt. |
| 89 | * @param {string} [param0.name] - The name of the prompt. | 172 | * @param {string} [param0.name] - The name of the prompt. |
| 90 | * @param {boolean} [param0.system_prompt] - Indicates if the prompt is a system prompt. | 173 | * @param {boolean} [param0.system_prompt] - Indicates if the prompt is a system prompt. |
| 91 | * @param {string} [param0.position] - The position of the prompt in the prompt list. | 174 | * @param {string|number} [param0.position] - The position of the prompt in the prompt list. |
| 92 | * @param {number} [param0.injection_position] - The insert position of the prompt. | 175 | * @param {number} [param0.injection_position] - The insert position of the prompt. |
| 93 | * @param {number} [param0.injection_depth] - The depth of the prompt in the chat. | 176 | * @param {number} [param0.injection_depth] - The depth of the prompt in the chat. |
| 94 | * @param {number} [param0.injection_order] - The order of the prompt in the chat. | 177 | * @param {number} [param0.injection_order] - The order of the prompt in the chat. |
| 178 | * @param {string[]} [param0.injection_trigger] - The generation type trigger for the prompt injection. | ||
| 95 | * @param {boolean} [param0.forbid_overrides] - Indicates if the prompt should not be overridden. | 179 | * @param {boolean} [param0.forbid_overrides] - Indicates if the prompt should not be overridden. |
| 96 | * @param {boolean} [param0.extension] - Prompt is added by an extension. | 180 | * @param {boolean} [param0.extension] - Prompt is added by an extension. |
| 97 | */ | 181 | */ |
| 98 | constructor({ identifier, role, content, name, system_prompt, position, injection_depth, injection_position, forbid_overrides, extension, injection_order } = {}) { | 182 | constructor({ identifier, role, content, name, system_prompt, position, injection_depth, injection_position, forbid_overrides, extension, injection_order, injection_trigger } = {}) { |
| 99 | this.identifier = identifier; | 183 | this.identifier = identifier; |
| 100 | this.role = role; | 184 | this.role = role; |
| 101 | this.content = content; | 185 | this.content = content; |
| @@ -106,7 +190,8 @@ class Prompt { | |||
| 106 | this.injection_position = injection_position; | 190 | this.injection_position = injection_position; |
| 107 | this.forbid_overrides = forbid_overrides; | 191 | this.forbid_overrides = forbid_overrides; |
| 108 | this.extension = extension ?? false; | 192 | this.extension = extension ?? false; |
| 109 | this.injection_order = injection_order ?? 100; | 193 | this.injection_order = injection_order ?? DEFAULT_ORDER; |
| 194 | this.injection_trigger = injection_trigger ?? []; | ||
| 110 | } | 195 | } |
| 111 | } | 196 | } |
| 112 | 197 | ||
| @@ -114,7 +199,16 @@ class Prompt { | |||
| 114 | * Representing a collection of prompts. | 199 | * Representing a collection of prompts. |
| 115 | */ | 200 | */ |
| 116 | export class PromptCollection { | 201 | export class PromptCollection { |
| 202 | /** | ||
| 203 | * List of Prompts in the collection. | ||
| 204 | * @type {Prompt[]} | ||
| 205 | */ | ||
| 117 | collection = []; | 206 | collection = []; |
| 207 | |||
| 208 | /** | ||
| 209 | * List of identifiers of prompts that have been overridden. | ||
| 210 | * @type {string[]} | ||
| 211 | */ | ||
| 118 | overriddenPrompts = []; | 212 | overriddenPrompts = []; |
| 119 | 213 | ||
| 120 | /** | 214 | /** |
| @@ -129,7 +223,7 @@ export class PromptCollection { | |||
| 129 | /** | 223 | /** |
| 130 | * Checks if the provided instances are of the Prompt class. | 224 | * Checks if the provided instances are of the Prompt class. |
| 131 | * | 225 | * |
| 132 | * @param {...any} prompts - Instances to check. | 226 | * @param {...Prompt} prompts - Instances to check. |
| 133 | * @throws Will throw an error if one or more instances are not of the Prompt class. | 227 | * @throws Will throw an error if one or more instances are not of the Prompt class. |
| 134 | */ | 228 | */ |
| 135 | checkPromptInstance(...prompts) { | 229 | checkPromptInstance(...prompts) { |
| @@ -191,6 +285,12 @@ export class PromptCollection { | |||
| 191 | return this.index(identifier) !== -1; | 285 | return this.index(identifier) !== -1; |
| 192 | } | 286 | } |
| 193 | 287 | ||
| 288 | /** | ||
| 289 | * Overrides a prompt at a specific position in the collection. | ||
| 290 | * | ||
| 291 | * @param {Prompt} prompt - The Prompt instance to override. | ||
| 292 | * @param {number} position - The position in the collection to override the Prompt instance. | ||
| 293 | */ | ||
| 194 | override(prompt, position) { | 294 | override(prompt, position) { |
| 195 | this.set(prompt, position); | 295 | this.set(prompt, position); |
| 196 | this.overriddenPrompts.push(prompt.identifier); | 296 | this.overriddenPrompts.push(prompt.identifier); |
| @@ -274,7 +374,7 @@ class PromptManager { | |||
| 274 | this.tryGenerate = async () => { }; | 374 | this.tryGenerate = async () => { }; |
| 275 | 375 | ||
| 276 | /** Called to persist the configuration, must return a promise */ | 376 | /** Called to persist the configuration, must return a promise */ |
| 277 | this.saveServiceSettings = () => { }; | 377 | this.saveServiceSettings = () => { return Promise.resolve(); }; |
| 278 | 378 | ||
| 279 | /** Toggle prompt button click */ | 379 | /** Toggle prompt button click */ |
| 280 | this.handleToggle = () => { }; | 380 | this.handleToggle = () => { }; |
| @@ -444,32 +544,51 @@ class PromptManager { | |||
| 444 | break; | 544 | break; |
| 445 | } | 545 | } |
| 446 | 546 | ||
| 447 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_name').value = prompt.name; | 547 | const nameField = /** @type {HTMLInputElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_name')); |
| 448 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_role').value = 'system'; | 548 | const roleField = /** @type {HTMLSelectElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_role')); |
| 449 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_prompt').value = prompt.content ?? ''; | 549 | const promptField = /** @type {HTMLTextAreaElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_prompt')); |
| 450 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_position').value = prompt.injection_position ?? 0; | 550 | const injectionPositionField = /** @type {HTMLSelectElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_position')); |
| 451 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_depth').value = prompt.injection_depth ?? DEFAULT_DEPTH; | 551 | const injectionDepthField = /** @type {HTMLInputElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_depth')); |
| 452 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_order').value = prompt.injection_order ?? 100; | 552 | const injectionOrderField = /** @type {HTMLInputElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_order')); |
| 453 | document.getElementById(this.configuration.prefix + 'prompt_manager_depth_block').style.visibility = prompt.injection_position === INJECTION_POSITION.ABSOLUTE ? 'visible' : 'hidden'; | 553 | const injectionTriggerField = /** @type {HTMLSelectElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_trigger')); |
| 454 | document.getElementById(this.configuration.prefix + 'prompt_manager_order_block').style.visibility = prompt.injection_position === INJECTION_POSITION.ABSOLUTE ? 'visible' : 'hidden'; | 554 | const depthBlock = /** @type {HTMLDivElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_depth_block')); |
| 455 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_forbid_overrides').checked = prompt.forbid_overrides ?? false; | 555 | const orderBlock = /** @type {HTMLDivElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_order_block')); |
| 456 | document.getElementById(this.configuration.prefix + 'prompt_manager_forbid_overrides_block').style.visibility = this.overridablePrompts.includes(prompt.identifier) ? 'visible' : 'hidden'; | 556 | const forbidOverridesField = /** @type {HTMLInputElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_forbid_overrides')); |
| 457 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_prompt').disabled = prompt.marker ?? false; | 557 | const forbidOverridesBlock = /** @type {HTMLDivElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_forbid_overrides_block')); |
| 458 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_source_block').style.display = isPulledPrompt ? '' : 'none'; | 558 | const entrySourceBlock = /** @type {HTMLDivElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_source_block')); |
| 559 | const entrySource = /** @type {HTMLSpanElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_source')); | ||
| 560 | |||
| 561 | nameField.value = prompt.name; | ||
| 562 | roleField.value = 'system'; | ||
| 563 | promptField.value = prompt.content ?? ''; | ||
| 564 | injectionPositionField.value = (prompt.injection_position ?? 0).toString(); | ||
| 565 | injectionDepthField.value = (prompt.injection_depth ?? DEFAULT_DEPTH).toString(); | ||
| 566 | injectionOrderField.value = (prompt.injection_order ?? DEFAULT_ORDER).toString(); | ||
| 567 | Array.from(injectionTriggerField.options).forEach(option => { | ||
| 568 | option.selected = false; | ||
| 569 | }); | ||
| 570 | injectionTriggerField.dispatchEvent(new Event('change', { bubbles: true })); | ||
| 571 | depthBlock.style.visibility = prompt.injection_position === INJECTION_POSITION.ABSOLUTE ? 'visible' : 'hidden'; | ||
| 572 | orderBlock.style.visibility = prompt.injection_position === INJECTION_POSITION.ABSOLUTE ? 'visible' : 'hidden'; | ||
| 573 | forbidOverridesField.checked = prompt.forbid_overrides ?? false; | ||
| 574 | forbidOverridesBlock.style.visibility = this.overridablePrompts.includes(prompt.identifier) ? 'visible' : 'hidden'; | ||
| 575 | promptField.disabled = prompt.marker ?? false; | ||
| 576 | entrySourceBlock.style.display = isPulledPrompt ? '' : 'none'; | ||
| 459 | 577 | ||
| 460 | if (isPulledPrompt) { | 578 | if (isPulledPrompt) { |
| 461 | const sourceName = this.promptSources[promptId]; | 579 | const sourceName = this.promptSources[promptId]; |
| 462 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_source').textContent = sourceName; | 580 | entrySource.textContent = sourceName; |
| 463 | } | 581 | } |
| 464 | 582 | ||
| 465 | if (!this.systemPrompts.includes(promptId)) { | 583 | if (!this.systemPrompts.includes(promptId)) { |
| 466 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_position').removeAttribute('disabled'); | 584 | injectionPositionField.removeAttribute('disabled'); |
| 467 | } | 585 | } |
| 468 | }; | 586 | }; |
| 469 | 587 | ||
| 470 | // Append prompt to selected character | 588 | // Append prompt to selected character |
| 471 | this.handleAppendPrompt = (event) => { | 589 | this.handleAppendPrompt = (event) => { |
| 472 | const promptID = document.getElementById(this.configuration.prefix + 'prompt_manager_footer_append_prompt').value; | 590 | const appendPromptFooter = /** @type {HTMLSelectElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_footer_append_prompt')); |
| 591 | const promptID = appendPromptFooter.value; | ||
| 473 | const prompt = this.getPromptById(promptID); | 592 | const prompt = this.getPromptById(promptID); |
| 474 | 593 | ||
| 475 | if (prompt) { | 594 | if (prompt) { |
| @@ -483,7 +602,8 @@ class PromptManager { | |||
| 483 | this.handleDeletePrompt = async (event) => { | 602 | this.handleDeletePrompt = async (event) => { |
| 484 | Popup.show.confirm(t`Are you sure you want to delete this prompt?`, null).then((userChoice) => { | 603 | Popup.show.confirm(t`Are you sure you want to delete this prompt?`, null).then((userChoice) => { |
| 485 | if (!userChoice) return; | 604 | if (!userChoice) return; |
| 486 | const promptID = document.getElementById(this.configuration.prefix + 'prompt_manager_footer_append_prompt').value; | 605 | const appendPromptFooter = /** @type {HTMLSelectElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_footer_append_prompt')); |
| 606 | const promptID = appendPromptFooter.value; | ||
| 487 | const prompt = this.getPromptById(promptID); | 607 | const prompt = this.getPromptById(promptID); |
| 488 | 608 | ||
| 489 | if (prompt && true === this.isPromptDeletionAllowed(prompt)) { | 609 | if (prompt && true === this.isPromptDeletionAllowed(prompt)) { |
| @@ -566,6 +686,7 @@ class PromptManager { | |||
| 566 | fileOpener.accept = '.json'; | 686 | fileOpener.accept = '.json'; |
| 567 | 687 | ||
| 568 | fileOpener.addEventListener('change', (event) => { | 688 | fileOpener.addEventListener('change', (event) => { |
| 689 | if (!(event.target instanceof HTMLInputElement)) return; | ||
| 569 | const file = event.target.files[0]; | 690 | const file = event.target.files[0]; |
| 570 | if (!file) return; | 691 | if (!file) return; |
| 571 | 692 | ||
| @@ -575,7 +696,7 @@ class PromptManager { | |||
| 575 | const fileContent = event.target.result; | 696 | const fileContent = event.target.result; |
| 576 | 697 | ||
| 577 | try { | 698 | try { |
| 578 | const data = JSON.parse(fileContent); | 699 | const data = JSON.parse(fileContent.toString()); |
| 579 | this.import(data); | 700 | this.import(data); |
| 580 | } catch (err) { | 701 | } catch (err) { |
| 581 | toastr.error(t`An error occurred while importing prompts. More info available in console.`); | 702 | toastr.error(t`An error occurred while importing prompts. More info available in console.`); |
| @@ -615,7 +736,7 @@ class PromptManager { | |||
| 615 | 736 | ||
| 616 | // Update edit form if present | 737 | // Update edit form if present |
| 617 | // @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent | 738 | // @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent |
| 618 | const popupEditFormPrompt = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_prompt'); | 739 | const popupEditFormPrompt = /** @type {HTMLTextAreaElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_prompt')); |
| 619 | if (popupEditFormPrompt.offsetParent) { | 740 | if (popupEditFormPrompt.offsetParent) { |
| 620 | popupEditFormPrompt.value = prompt.content; | 741 | popupEditFormPrompt.value = prompt.content; |
| 621 | } | 742 | } |
| @@ -673,6 +794,7 @@ class PromptManager { | |||
| 673 | 794 | ||
| 674 | // Trigger re-render when token settings are changed | 795 | // Trigger re-render when token settings are changed |
| 675 | document.getElementById('openai_max_context').addEventListener('change', (event) => { | 796 | document.getElementById('openai_max_context').addEventListener('change', (event) => { |
| 797 | if (!(event.target instanceof HTMLInputElement)) return; | ||
| 676 | this.serviceSettings.openai_max_context = event.target.value; | 798 | this.serviceSettings.openai_max_context = event.target.value; |
| 677 | if (this.activeCharacter) this.renderDebounced(); | 799 | if (this.activeCharacter) this.renderDebounced(); |
| 678 | }); | 800 | }); |
| @@ -778,23 +900,33 @@ class PromptManager { | |||
| 778 | 900 | ||
| 779 | /** | 901 | /** |
| 780 | * Update a prompt with the values from the HTML form. | 902 | * Update a prompt with the values from the HTML form. |
| 781 | * @param {object} prompt - The prompt to be updated. | 903 | * @param {Partial<Prompt>} prompt - The prompt to be updated. |
| 782 | * @returns {void} | 904 | * @returns {void} |
| 783 | */ | 905 | */ |
| 784 | updatePromptWithPromptEditForm(prompt) { | 906 | updatePromptWithPromptEditForm(prompt) { |
| 785 | prompt.name = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_name').value; | 907 | const nameField = /** @type {HTMLInputElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_name')); |
| 786 | prompt.role = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_role').value; | 908 | const roleField = /** @type {HTMLSelectElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_role')); |
| 787 | prompt.content = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_prompt').value; | 909 | const promptField = /** @type {HTMLTextAreaElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_prompt')); |
| 788 | prompt.injection_position = Number(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_position').value); | 910 | const injectionPositionField = /** @type {HTMLSelectElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_position')); |
| 789 | prompt.injection_depth = Number(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_depth').value); | 911 | const injectionDepthField = /** @type {HTMLInputElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_depth')); |
| 790 | prompt.injection_order = Number(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_order').value); | 912 | const injectionOrderField = /** @type {HTMLInputElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_order')); |
| 791 | prompt.forbid_overrides = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_forbid_overrides').checked; | 913 | const injectionTriggerField = /** @type {HTMLSelectElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_trigger')); |
| 914 | const forbidOverridesField = /** @type {HTMLInputElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_forbid_overrides')); | ||
| 915 | |||
| 916 | prompt.name = nameField.value; | ||
| 917 | prompt.role = roleField.value; | ||
| 918 | prompt.content = promptField.value; | ||
| 919 | prompt.injection_position = Number(injectionPositionField.value); | ||
| 920 | prompt.injection_depth = Number(injectionDepthField.value); | ||
| 921 | prompt.injection_order = Number(injectionOrderField.value); | ||
| 922 | prompt.injection_trigger = Array.from(injectionTriggerField.selectedOptions).map(option => option.value); | ||
| 923 | prompt.forbid_overrides = forbidOverridesField.checked; | ||
| 792 | } | 924 | } |
| 793 | 925 | ||
| 794 | /** | 926 | /** |
| 795 | * Find a prompt by its identifier and update it with the provided object. | 927 | * Find a prompt by its identifier and update it with the provided object. |
| 796 | * @param {string} identifier - The identifier of the prompt. | 928 | * @param {string} identifier - The identifier of the prompt. |
| 797 | * @param {object} updatePrompt - An object with properties to be updated in the prompt. | 929 | * @param {Prompt} updatePrompt - An object with properties to be updated in the prompt. |
| 798 | * @returns {void} | 930 | * @returns {void} |
| 799 | */ | 931 | */ |
| 800 | updatePromptByIdentifier(identifier, updatePrompt) { | 932 | updatePromptByIdentifier(identifier, updatePrompt) { |
| @@ -804,7 +936,7 @@ class PromptManager { | |||
| 804 | 936 | ||
| 805 | /** | 937 | /** |
| 806 | * Iterate over an array of prompts, find each one by its identifier, and update them with the provided data. | 938 | * Iterate over an array of prompts, find each one by its identifier, and update them with the provided data. |
| 807 | * @param {object[]} prompts - An array of prompt updates. | 939 | * @param {Prompt[]} prompts - An array of prompt updates. |
| 808 | * @returns {void} | 940 | * @returns {void} |
| 809 | */ | 941 | */ |
| 810 | updatePrompts(prompts) { | 942 | updatePrompts(prompts) { |
| @@ -826,7 +958,7 @@ class PromptManager { | |||
| 826 | 958 | ||
| 827 | /** | 959 | /** |
| 828 | * Add a prompt to the current character's prompt list. | 960 | * Add a prompt to the current character's prompt list. |
| 829 | * @param {object} prompt - The prompt to be added. | 961 | * @param {Prompt} prompt - The prompt to be added. |
| 830 | * @param {object} character - The character whose prompt list will be updated. | 962 | * @param {object} character - The character whose prompt list will be updated. |
| 831 | * @returns {void} | 963 | * @returns {void} |
| 832 | */ | 964 | */ |
| @@ -839,7 +971,7 @@ class PromptManager { | |||
| 839 | 971 | ||
| 840 | /** | 972 | /** |
| 841 | * Remove a prompt from the current character's prompt list. | 973 | * Remove a prompt from the current character's prompt list. |
| 842 | * @param {object} prompt - The prompt to be removed. | 974 | * @param {Prompt} prompt - The prompt to be removed. |
| 843 | * @param {object} character - The character whose prompt list will be updated. | 975 | * @param {object} character - The character whose prompt list will be updated. |
| 844 | * @returns {void} | 976 | * @returns {void} |
| 845 | */ | 977 | */ |
| @@ -853,7 +985,7 @@ class PromptManager { | |||
| 853 | 985 | ||
| 854 | /** | 986 | /** |
| 855 | * Create a new prompt and add it to the list of prompts. | 987 | * Create a new prompt and add it to the list of prompts. |
| 856 | * @param {object} prompt - The prompt to be added. | 988 | * @param {Partial<Prompt>} prompt - The prompt to be added. |
| 857 | * @param {string} identifier - The identifier for the new prompt. | 989 | * @param {string} identifier - The identifier for the new prompt. |
| 858 | * @returns {void} | 990 | * @returns {void} |
| 859 | */ | 991 | */ |
| @@ -931,7 +1063,7 @@ class PromptManager { | |||
| 931 | 1063 | ||
| 932 | /** | 1064 | /** |
| 933 | * Check whether a prompt can be inspected. | 1065 | * Check whether a prompt can be inspected. |
| 934 | * @param {object} prompt - The prompt to check. | 1066 | * @param {Prompt} prompt - The prompt to check. |
| 935 | * @returns {boolean} True if the prompt is a marker, false otherwise. | 1067 | * @returns {boolean} True if the prompt is a marker, false otherwise. |
| 936 | */ | 1068 | */ |
| 937 | isPromptInspectionAllowed(prompt) { | 1069 | isPromptInspectionAllowed(prompt) { |
| @@ -940,7 +1072,7 @@ class PromptManager { | |||
| 940 | 1072 | ||
| 941 | /** | 1073 | /** |
| 942 | * Check whether a prompt can be deleted. System prompts cannot be deleted. | 1074 | * Check whether a prompt can be deleted. System prompts cannot be deleted. |
| 943 | * @param {object} prompt - The prompt to check. | 1075 | * @param {Prompt} prompt - The prompt to check. |
| 944 | * @returns {boolean} True if the prompt can be deleted, false otherwise. | 1076 | * @returns {boolean} True if the prompt can be deleted, false otherwise. |
| 945 | */ | 1077 | */ |
| 946 | isPromptDeletionAllowed(prompt) { | 1078 | isPromptDeletionAllowed(prompt) { |
| @@ -949,7 +1081,7 @@ class PromptManager { | |||
| 949 | 1081 | ||
| 950 | /** | 1082 | /** |
| 951 | * Check whether a prompt can be edited. | 1083 | * Check whether a prompt can be edited. |
| 952 | * @param {object} prompt - The prompt to check. | 1084 | * @param {Prompt} prompt - The prompt to check. |
| 953 | * @returns {boolean} True if the prompt can be edited, false otherwise. | 1085 | * @returns {boolean} True if the prompt can be edited, false otherwise. |
| 954 | */ | 1086 | */ |
| 955 | isPromptEditAllowed(prompt) { | 1087 | isPromptEditAllowed(prompt) { |
| @@ -966,7 +1098,7 @@ class PromptManager { | |||
| 966 | 1098 | ||
| 967 | /** | 1099 | /** |
| 968 | * Check whether a prompt can be toggled on or off. | 1100 | * Check whether a prompt can be toggled on or off. |
| 969 | * @param {object} prompt - The prompt to check. | 1101 | * @param {Prompt} prompt - The prompt to check. |
| 970 | * @returns {boolean} True if the prompt can be deleted, false otherwise. | 1102 | * @returns {boolean} True if the prompt can be deleted, false otherwise. |
| 971 | */ | 1103 | */ |
| 972 | isPromptToggleAllowed(prompt) { | 1104 | isPromptToggleAllowed(prompt) { |
| @@ -1062,7 +1194,7 @@ class PromptManager { | |||
| 1062 | 1194 | ||
| 1063 | /** | 1195 | /** |
| 1064 | * Get the prompts for a specific character. Can be filtered to only include enabled prompts. | 1196 | * Get the prompts for a specific character. Can be filtered to only include enabled prompts. |
| 1065 | * @returns {object[]} The prompts for the character. | 1197 | * @returns {Prompt[]} The prompts for the character. |
| 1066 | * @param character | 1198 | * @param character |
| 1067 | * @param onlyEnabled | 1199 | * @param onlyEnabled |
| 1068 | */ | 1200 | */ |
| @@ -1075,7 +1207,7 @@ class PromptManager { | |||
| 1075 | /** | 1207 | /** |
| 1076 | * Get the order of prompts for a specific character. If no character is specified or the character doesn't have a prompt list, an empty array is returned. | 1208 | * Get the order of prompts for a specific character. If no character is specified or the character doesn't have a prompt list, an empty array is returned. |
| 1077 | * @param {object|null} character - The character to get the prompt list for. | 1209 | * @param {object|null} character - The character to get the prompt list for. |
| 1078 | * @returns {object[]} The prompt list for the character, or an empty array. | 1210 | * @returns {Partial<Prompt>[]} The prompt list for the character, or an empty array. |
| 1079 | */ | 1211 | */ |
| 1080 | getPromptOrderForCharacter(character) { | 1212 | getPromptOrderForCharacter(character) { |
| 1081 | return !character ? [] : (this.serviceSettings.prompt_order.find(list => String(list.character_id) === String(character.id))?.order ?? []); | 1213 | return !character ? [] : (this.serviceSettings.prompt_order.find(list => String(list.character_id) === String(character.id))?.order ?? []); |
| @@ -1083,7 +1215,7 @@ class PromptManager { | |||
| 1083 | 1215 | ||
| 1084 | /** | 1216 | /** |
| 1085 | * Set the prompts for the manager. | 1217 | * Set the prompts for the manager. |
| 1086 | * @param {object[]} prompts - The prompts to be set. | 1218 | * @param {Partial<Prompt>[]} prompts - The prompts to be set. |
| 1087 | * @returns {void} | 1219 | * @returns {void} |
| 1088 | */ | 1220 | */ |
| 1089 | setPrompts(prompts) { | 1221 | setPrompts(prompts) { |
| @@ -1125,7 +1257,7 @@ class PromptManager { | |||
| 1125 | /** | 1257 | /** |
| 1126 | * Finds and returns a prompt by its identifier. | 1258 | * Finds and returns a prompt by its identifier. |
| 1127 | * @param {string} identifier - Identifier of the prompt | 1259 | * @param {string} identifier - Identifier of the prompt |
| 1128 | * @returns {Object|null} The prompt object, or null if not found | 1260 | * @returns {Prompt|null} The prompt object, or null if not found |
| 1129 | */ | 1261 | */ |
| 1130 | getPromptById(identifier) { | 1262 | getPromptById(identifier) { |
| 1131 | return this.serviceSettings.prompts.find(item => item && item.identifier === identifier) ?? null; | 1263 | return this.serviceSettings.prompts.find(item => item && item.identifier === identifier) ?? null; |
| @@ -1143,9 +1275,9 @@ class PromptManager { | |||
| 1143 | /** | 1275 | /** |
| 1144 | * Enriches a generic object, creating a new prompt object in the process | 1276 | * Enriches a generic object, creating a new prompt object in the process |
| 1145 | * | 1277 | * |
| 1146 | * @param {Object} prompt - Prompt object | 1278 | * @param {Partial<Prompt>} prompt - Prompt object |
| 1147 | * @param original | 1279 | * @param original |
| 1148 | * @returns {Object} An object with "role" and "content" properties | 1280 | * @returns {Prompt} An object with "role" and "content" properties |
| 1149 | */ | 1281 | */ |
| 1150 | preparePrompt(prompt, original = null) { | 1282 | preparePrompt(prompt, original = null) { |
| 1151 | const groupMembers = this.getActiveGroupCharacters(); | 1283 | const groupMembers = this.getActiveGroupCharacters(); |
| @@ -1184,7 +1316,7 @@ class PromptManager { | |||
| 1184 | 1316 | ||
| 1185 | const debouncedSaveServiceSettings = debouncePromise(() => this.saveServiceSettings(), 300); | 1317 | const debouncedSaveServiceSettings = debouncePromise(() => this.saveServiceSettings(), 300); |
| 1186 | 1318 | ||
| 1187 | const textarea = document.getElementById(textareaIdentifier); | 1319 | const textarea = /** @type {HTMLTextAreaElement} */(document.getElementById(textareaIdentifier)); |
| 1188 | textarea.addEventListener('blur', () => { | 1320 | textarea.addEventListener('blur', () => { |
| 1189 | prompt.content = textarea.value; | 1321 | prompt.content = textarea.value; |
| 1190 | this.updatePromptByIdentifier(identifier, prompt); | 1322 | this.updatePromptByIdentifier(identifier, prompt); |
| @@ -1193,9 +1325,15 @@ class PromptManager { | |||
| 1193 | 1325 | ||
| 1194 | } | 1326 | } |
| 1195 | 1327 | ||
| 1328 | /** | ||
| 1329 | * Updates the quick edit textarea for a specific prompt. | ||
| 1330 | * @param {string} identifier - The identifier of the prompt. | ||
| 1331 | * @param {Prompt} prompt - The updated prompt object. | ||
| 1332 | * @returns {string} The ID of the updated textarea element. | ||
| 1333 | */ | ||
| 1196 | updateQuickEdit(identifier, prompt) { | 1334 | updateQuickEdit(identifier, prompt) { |
| 1197 | const elementId = `${identifier}_prompt_quick_edit_textarea`; | 1335 | const elementId = `${identifier}_prompt_quick_edit_textarea`; |
| 1198 | const textarea = document.getElementById(elementId); | 1336 | const textarea = /** @type {HTMLTextAreaElement} */(document.getElementById(elementId)); |
| 1199 | textarea.value = prompt.content; | 1337 | textarea.value = prompt.content; |
| 1200 | 1338 | ||
| 1201 | return elementId; | 1339 | return elementId; |
| @@ -1220,30 +1358,35 @@ class PromptManager { | |||
| 1220 | 1358 | ||
| 1221 | /** | 1359 | /** |
| 1222 | * Loads a given prompt into the edit form fields. | 1360 | * Loads a given prompt into the edit form fields. |
| 1223 | * @param {Object} prompt - Prompt object with properties 'name', 'role', 'content', and 'system_prompt' | 1361 | * @param {Partial<Prompt>} prompt - Prompt object with properties 'name', 'role', 'content', and 'system_prompt' |
| 1224 | */ | 1362 | */ |
| 1225 | loadPromptIntoEditForm(prompt) { | 1363 | loadPromptIntoEditForm(prompt) { |
| 1226 | const nameField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_name'); | 1364 | const nameField = /** @type {HTMLInputElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_name')); |
| 1227 | const roleField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_role'); | 1365 | const roleField = /** @type {HTMLSelectElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_role')); |
| 1228 | const promptField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_prompt'); | 1366 | const promptField = /** @type {HTMLTextAreaElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_prompt')); |
| 1229 | const injectionPositionField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_position'); | 1367 | const injectionPositionField = /** @type {HTMLSelectElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_position')); |
| 1230 | const injectionDepthField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_depth'); | 1368 | const injectionDepthField = /** @type {HTMLInputElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_depth')); |
| 1231 | const injectionOrderField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_order'); | 1369 | const injectionOrderField = /** @type {HTMLInputElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_order')); |
| 1232 | const injectionDepthBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_depth_block'); | 1370 | const injectionTriggerField = /** @type {HTMLSelectElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_trigger')); |
| 1233 | const injectionOrderBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_order_block'); | 1371 | const injectionDepthBlock = /** @type {HTMLDivElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_depth_block')); |
| 1234 | const forbidOverridesField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_forbid_overrides'); | 1372 | const injectionOrderBlock = /** @type {HTMLDivElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_order_block')); |
| 1235 | const forbidOverridesBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_forbid_overrides_block'); | 1373 | const forbidOverridesField = /** @type {HTMLInputElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_forbid_overrides')); |
| 1236 | const entrySourceBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_source_block'); | 1374 | const forbidOverridesBlock = /** @type {HTMLDivElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_forbid_overrides_block')); |
| 1237 | const entrySource = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_source'); | 1375 | const entrySourceBlock = /** @type {HTMLDivElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_source_block')); |
| 1376 | const entrySource = /** @type {HTMLSpanElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_source')); | ||
| 1238 | const isPulledPrompt = Object.keys(this.promptSources).includes(prompt.identifier); | 1377 | const isPulledPrompt = Object.keys(this.promptSources).includes(prompt.identifier); |
| 1239 | 1378 | ||
| 1240 | nameField.value = prompt.name ?? ''; | 1379 | nameField.value = prompt.name ?? ''; |
| 1241 | roleField.value = prompt.role || 'system'; | 1380 | roleField.value = prompt.role || 'system'; |
| 1242 | promptField.value = prompt.content ?? ''; | 1381 | promptField.value = prompt.content ?? ''; |
| 1243 | promptField.disabled = prompt.marker ?? false; | 1382 | promptField.disabled = prompt.marker ?? false; |
| 1244 | injectionPositionField.value = prompt.injection_position ?? INJECTION_POSITION.RELATIVE; | 1383 | injectionPositionField.value = (prompt.injection_position ?? INJECTION_POSITION.RELATIVE).toString(); |
| 1245 | injectionDepthField.value = prompt.injection_depth ?? DEFAULT_DEPTH; | 1384 | injectionDepthField.value = (prompt.injection_depth ?? DEFAULT_DEPTH).toString(); |
| 1246 | injectionOrderField.value = prompt.injection_order ?? 100; | 1385 | injectionOrderField.value = (prompt.injection_order ?? DEFAULT_ORDER).toString(); |
| 1386 | Array.from(injectionTriggerField.options).forEach(option => { | ||
| 1387 | option.selected = Array.isArray(prompt.injection_trigger) && prompt.injection_trigger.includes(option.value); | ||
| 1388 | }); | ||
| 1389 | injectionTriggerField.dispatchEvent(new Event('change', { bubbles: true })); | ||
| 1247 | injectionDepthBlock.style.visibility = prompt.injection_position === INJECTION_POSITION.ABSOLUTE ? 'visible' : 'hidden'; | 1390 | injectionDepthBlock.style.visibility = prompt.injection_position === INJECTION_POSITION.ABSOLUTE ? 'visible' : 'hidden'; |
| 1248 | injectionOrderBlock.style.visibility = prompt.injection_position === INJECTION_POSITION.ABSOLUTE ? 'visible' : 'hidden'; | 1391 | injectionOrderBlock.style.visibility = prompt.injection_position === INJECTION_POSITION.ABSOLUTE ? 'visible' : 'hidden'; |
| 1249 | injectionPositionField.removeAttribute('disabled'); | 1392 | injectionPositionField.removeAttribute('disabled'); |
| @@ -1335,17 +1478,19 @@ class PromptManager { | |||
| 1335 | const editArea = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_edit'); | 1478 | const editArea = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_edit'); |
| 1336 | editArea.style.display = 'none'; | 1479 | editArea.style.display = 'none'; |
| 1337 | 1480 | ||
| 1338 | const nameField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_name'); | 1481 | const nameField = /** @type {HTMLInputElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_name')); |
| 1339 | const roleField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_role'); | 1482 | const roleField = /** @type {HTMLSelectElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_role')); |
| 1340 | const promptField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_prompt'); | 1483 | const promptField = /** @type {HTMLTextAreaElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_prompt')); |
| 1341 | const injectionPositionField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_position'); | 1484 | const injectionPositionField = /** @type {HTMLSelectElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_position')); |
| 1342 | const injectionDepthField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_depth'); | 1485 | const injectionDepthField = /** @type {HTMLInputElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_depth')); |
| 1343 | const injectionDepthBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_depth_block'); | 1486 | const injectionDepthBlock = /** @type {HTMLDivElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_depth_block')); |
| 1344 | const injectionOrderBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_order_block'); | 1487 | const injectionOrderBlock = /** @type {HTMLDivElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_order_block')); |
| 1345 | const forbidOverridesField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_forbid_overrides'); | 1488 | const injectionOrderField = /** @type {HTMLInputElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_order')); |
| 1346 | const forbidOverridesBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_forbid_overrides_block'); | 1489 | const injectionTriggerField = /** @type {HTMLSelectElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_trigger')); |
| 1347 | const entrySourceBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_source_block'); | 1490 | const forbidOverridesField = /** @type {HTMLInputElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_forbid_overrides')); |
| 1348 | const entrySource = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_source'); | 1491 | const forbidOverridesBlock = /** @type {HTMLDivElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_forbid_overrides_block')); |
| 1492 | const entrySourceBlock = /** @type {HTMLDivElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_source_block')); | ||
| 1493 | const entrySource = /** @type {HTMLSpanElement} */(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_source')); | ||
| 1349 | 1494 | ||
| 1350 | nameField.value = ''; | 1495 | nameField.value = ''; |
| 1351 | roleField.selectedIndex = 0; | 1496 | roleField.selectedIndex = 0; |
| @@ -1353,7 +1498,9 @@ class PromptManager { | |||
| 1353 | promptField.disabled = false; | 1498 | promptField.disabled = false; |
| 1354 | injectionPositionField.selectedIndex = 0; | 1499 | injectionPositionField.selectedIndex = 0; |
| 1355 | injectionPositionField.removeAttribute('disabled'); | 1500 | injectionPositionField.removeAttribute('disabled'); |
| 1356 | injectionDepthField.value = DEFAULT_DEPTH; | 1501 | injectionDepthField.value = DEFAULT_DEPTH.toString(); |
| 1502 | injectionOrderField.value = DEFAULT_ORDER.toString(); | ||
| 1503 | injectionTriggerField.value = ''; | ||
| 1357 | injectionDepthBlock.style.visibility = 'unset'; | 1504 | injectionDepthBlock.style.visibility = 'unset'; |
| 1358 | injectionOrderBlock.style.visibility = 'unset'; | 1505 | injectionOrderBlock.style.visibility = 'unset'; |
| 1359 | forbidOverridesBlock.style.visibility = 'unset'; | 1506 | forbidOverridesBlock.style.visibility = 'unset'; |
| @@ -1373,22 +1520,30 @@ class PromptManager { | |||
| 1373 | 1520 | ||
| 1374 | /** | 1521 | /** |
| 1375 | * Returns a full list of prompts whose content markers have been substituted. | 1522 | * Returns a full list of prompts whose content markers have been substituted. |
| 1523 | * @param {string} generationType - The type of generation, e.g., 'continue' or 'quiet'. | ||
| 1376 | * @returns {PromptCollection} A PromptCollection object | 1524 | * @returns {PromptCollection} A PromptCollection object |
| 1377 | */ | 1525 | */ |
| 1378 | getPromptCollection() { | 1526 | getPromptCollection(generationType) { |
| 1527 | generationType = String(generationType || 'normal').toLowerCase().trim(); | ||
| 1528 | const promptCollection = new PromptCollection(); | ||
| 1379 | const promptOrder = this.getPromptOrderForCharacter(this.activeCharacter); | 1529 | const promptOrder = this.getPromptOrderForCharacter(this.activeCharacter); |
| 1380 | 1530 | ||
| 1381 | const promptCollection = new PromptCollection(); | ||
| 1382 | promptOrder.forEach(entry => { | 1531 | promptOrder.forEach(entry => { |
| 1383 | if (true === entry.enabled) { | 1532 | const prompt = this.getPromptById(entry.identifier); |
| 1384 | const prompt = this.getPromptById(entry.identifier); | 1533 | const allowedTrigger = entry.enabled && this.shouldTrigger(prompt, generationType); |
| 1385 | if (prompt) promptCollection.add(this.preparePrompt(prompt)); | 1534 | |
| 1386 | } else if (!entry.enabled && entry.identifier === 'main') { | 1535 | if (!prompt) { |
| 1536 | return; | ||
| 1537 | } | ||
| 1538 | |||
| 1539 | if (allowedTrigger) { | ||
| 1540 | promptCollection.add(this.preparePrompt(prompt)); | ||
| 1541 | } else if (entry.identifier === 'main') { | ||
| 1387 | // Some extensions require main prompt to be present for relative inserts. | 1542 | // Some extensions require main prompt to be present for relative inserts. |
| 1388 | // So we make a GMO-free vegan replacement. | 1543 | // So we make a GMO-free vegan replacement. |
| 1389 | const prompt = structuredClone(this.getPromptById(entry.identifier)); | 1544 | const replacementPrompt = structuredClone(prompt); |
| 1390 | prompt.content = ''; | 1545 | replacementPrompt.content = ''; |
| 1391 | if (prompt) promptCollection.add(this.preparePrompt(prompt)); | 1546 | promptCollection.add(this.preparePrompt(replacementPrompt)); |
| 1392 | } | 1547 | } |
| 1393 | }); | 1548 | }); |
| 1394 | 1549 | ||
| @@ -1396,6 +1551,18 @@ class PromptManager { | |||
| 1396 | } | 1551 | } |
| 1397 | 1552 | ||
| 1398 | /** | 1553 | /** |
| 1554 | * Checks if a prompt should be triggered based on its injection triggers. | ||
| 1555 | * @param {Prompt} prompt - The prompt to check. | ||
| 1556 | * @param {string} generationType - The type of generation to check against. | ||
| 1557 | * @returns {boolean} True if the prompt should be triggered, false otherwise. | ||
| 1558 | */ | ||
| 1559 | shouldTrigger(prompt, generationType) { | ||
| 1560 | if (!Array.isArray(prompt?.injection_trigger)) return true; | ||
| 1561 | if (!prompt.injection_trigger.length) return true; | ||
| 1562 | return prompt.injection_trigger.includes(generationType); | ||
| 1563 | } | ||
| 1564 | |||
| 1565 | /** | ||
| 1399 | * Setter for messages property | 1566 | * Setter for messages property |
| 1400 | * | 1567 | * |
| 1401 | * @param {import('./openai.js').MessageCollection} messages | 1568 | * @param {import('./openai.js').MessageCollection} messages |
| @@ -1807,11 +1974,7 @@ class PromptManager { | |||
| 1807 | * @returns {string} A string representation of an uuid4 | 1974 | * @returns {string} A string representation of an uuid4 |
| 1808 | */ | 1975 | */ |
| 1809 | getUuidv4() { | 1976 | getUuidv4() { |
| 1810 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { | 1977 | return uuidv4(); |
| 1811 | let r = Math.random() * 16 | 0, | ||
| 1812 | v = c === 'x' ? r : (r & 0x3 | 0x8); | ||
| 1813 | return v.toString(16); | ||
| 1814 | }); | ||
| 1815 | } | 1978 | } |
| 1816 | 1979 | ||
| 1817 | /** | 1980 | /** |
| @@ -921,7 +921,6 @@ async function generateGroupWrapper(by_auto_mode, type = null, params = {}) { | |||
| 921 | for (const chId of activatedMembers) { | 921 | for (const chId of activatedMembers) { |
| 922 | throwIfAborted(); | 922 | throwIfAborted(); |
| 923 | deactivateSendButtons(); | 923 | deactivateSendButtons(); |
| 924 | const generateType = type == 'swipe' || type == 'impersonate' || type == 'quiet' || type == 'continue' ? type : 'group_chat'; | ||
| 925 | setCharacterId(chId); | 924 | setCharacterId(chId); |
| 926 | setCharacterName(characters[chId].name); | 925 | setCharacterName(characters[chId].name); |
| 927 | if (power_user.show_group_chat_queue) { | 926 | if (power_user.show_group_chat_queue) { |
| @@ -930,6 +929,7 @@ async function generateGroupWrapper(by_auto_mode, type = null, params = {}) { | |||
| 930 | await eventSource.emit(event_types.GROUP_MEMBER_DRAFTED, chId); | 929 | await eventSource.emit(event_types.GROUP_MEMBER_DRAFTED, chId); |
| 931 | 930 | ||
| 932 | // Wait for generation to finish | 931 | // Wait for generation to finish |
| 932 | const generateType = ['swipe', 'impersonate', 'quiet', 'continue'].includes(type) ? type : 'normal'; | ||
| 933 | textResult = await Generate(generateType, { automatic_trigger: by_auto_mode, ...(params || {}) }); | 933 | textResult = await Generate(generateType, { automatic_trigger: by_auto_mode, ...(params || {}) }); |
| 934 | let messageChunk = textResult?.messageChunk; | 934 | let messageChunk = textResult?.messageChunk; |
| 935 | 935 | ||
| @@ -1255,12 +1255,12 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | |||
| 1255 | * @param {string} options.quietPrompt - The quiet prompt to be used in the conversation. | 1255 | * @param {string} options.quietPrompt - The quiet prompt to be used in the conversation. |
| 1256 | * @param {string} options.bias - The bias to be added in the conversation. | 1256 | * @param {string} options.bias - The bias to be added in the conversation. |
| 1257 | * @param {Object} options.extensionPrompts - An object containing additional prompts. | 1257 | * @param {Object} options.extensionPrompts - An object containing additional prompts. |
| 1258 | * @param {string} options.systemPromptOverride | 1258 | * @param {string} options.systemPromptOverride - Character card override of the main prompt |
| 1259 | * @param {string} options.jailbreakPromptOverride | 1259 | * @param {string} options.jailbreakPromptOverride - Character card override of the PHI |
| 1260 | * @param {string} options.personaDescription | 1260 | * @param {string} options.type - The type of generation that triggered the prompt |
| 1261 | * @returns {Promise<Object>} prompts - The prepared and merged system and user-defined prompts. | 1261 | * @returns {Promise<Object>} prompts - The prepared and merged system and user-defined prompts. |
| 1262 | */ | 1262 | */ |
| 1263 | async function preparePromptsForChatCompletion({ scenario, charPersonality, name2, worldInfoBefore, worldInfoAfter, charDescription, quietPrompt, bias, extensionPrompts, systemPromptOverride, jailbreakPromptOverride, personaDescription }) { | 1263 | async function preparePromptsForChatCompletion({ scenario, charPersonality, name2, worldInfoBefore, worldInfoAfter, charDescription, quietPrompt, bias, extensionPrompts, systemPromptOverride, jailbreakPromptOverride, type }) { |
| 1264 | const scenarioText = scenario && oai_settings.scenario_format ? substituteParams(oai_settings.scenario_format) : (scenario || ''); | 1264 | const scenarioText = scenario && oai_settings.scenario_format ? substituteParams(oai_settings.scenario_format) : (scenario || ''); |
| 1265 | const charPersonalityText = charPersonality && oai_settings.personality_format ? substituteParams(oai_settings.personality_format) : (charPersonality || ''); | 1265 | const charPersonalityText = charPersonality && oai_settings.personality_format ? substituteParams(oai_settings.personality_format) : (charPersonality || ''); |
| 1266 | const groupNudge = substituteParams(oai_settings.group_nudge_prompt); | 1266 | const groupNudge = substituteParams(oai_settings.group_nudge_prompt); |
| @@ -1363,7 +1363,7 @@ async function preparePromptsForChatCompletion({ scenario, charPersonality, name | |||
| 1363 | } | 1363 | } |
| 1364 | 1364 | ||
| 1365 | // This is the prompt order defined by the user | 1365 | // This is the prompt order defined by the user |
| 1366 | const prompts = promptManager.getPromptCollection(); | 1366 | const prompts = promptManager.getPromptCollection(type); |
| 1367 | 1367 | ||
| 1368 | // Merge system prompts with prompt manager prompts | 1368 | // Merge system prompts with prompt manager prompts |
| 1369 | systemPrompts.forEach(prompt => { | 1369 | systemPrompts.forEach(prompt => { |
| @@ -1429,7 +1429,6 @@ async function preparePromptsForChatCompletion({ scenario, charPersonality, name | |||
| 1429 | * @param {string} content.cyclePrompt - The last prompt used for chat message continuation. | 1429 | * @param {string} content.cyclePrompt - The last prompt used for chat message continuation. |
| 1430 | * @param {string} content.systemPromptOverride - The system prompt override. | 1430 | * @param {string} content.systemPromptOverride - The system prompt override. |
| 1431 | * @param {string} content.jailbreakPromptOverride - The jailbreak prompt override. | 1431 | * @param {string} content.jailbreakPromptOverride - The jailbreak prompt override. |
| 1432 | * @param {string} content.personaDescription - The persona description. | ||
| 1433 | * @param {object} content.extensionPrompts - An array of additional prompts. | 1432 | * @param {object} content.extensionPrompts - An array of additional prompts. |
| 1434 | * @param {object[]} content.messages - An array of messages to be used as chat history. | 1433 | * @param {object[]} content.messages - An array of messages to be used as chat history. |
| 1435 | * @param {string[]} content.messageExamples - An array of messages to be used as dialogue examples. | 1434 | * @param {string[]} content.messageExamples - An array of messages to be used as dialogue examples. |
| @@ -1451,7 +1450,6 @@ export async function prepareOpenAIMessages({ | |||
| 1451 | cyclePrompt, | 1450 | cyclePrompt, |
| 1452 | systemPromptOverride, | 1451 | systemPromptOverride, |
| 1453 | jailbreakPromptOverride, | 1452 | jailbreakPromptOverride, |
| 1454 | personaDescription, | ||
| 1455 | messages, | 1453 | messages, |
| 1456 | messageExamples, | 1454 | messageExamples, |
| 1457 | }, dryRun) { | 1455 | }, dryRun) { |
| @@ -1478,7 +1476,7 @@ export async function prepareOpenAIMessages({ | |||
| 1478 | extensionPrompts, | 1476 | extensionPrompts, |
| 1479 | systemPromptOverride, | 1477 | systemPromptOverride, |
| 1480 | jailbreakPromptOverride, | 1478 | jailbreakPromptOverride, |
| 1481 | personaDescription, | 1479 | type, |
| 1482 | }); | 1480 | }); |
| 1483 | 1481 | ||
| 1484 | // Fill the chat completion with as much context as the budget allows | 1482 | // Fill the chat completion with as much context as the budget allows |
| @@ -6429,6 +6427,11 @@ export function initOpenAI() { | |||
| 6429 | width: '100%', | 6427 | width: '100%', |
| 6430 | templateResult: getAimlapiModelTemplate, | 6428 | templateResult: getAimlapiModelTemplate, |
| 6431 | }); | 6429 | }); |
| 6430 | $('#completion_prompt_manager_popup_entry_form_injection_trigger').select2({ | ||
| 6431 | placeholder: t`All types (default)`, | ||
| 6432 | width: '100%', | ||
| 6433 | closeOnSelect: false, | ||
| 6434 | }); | ||
| 6432 | } | 6435 | } |
| 6433 | 6436 | ||
| 6434 | $('#openrouter_providers_chat').on('change', function () { | 6437 | $('#openrouter_providers_chat').on('change', function () { |
| @@ -3947,7 +3947,7 @@ async function askCharacter(args, text) { | |||
| 3947 | try { | 3947 | try { |
| 3948 | eventSource.once(event_types.MESSAGE_RECEIVED, restoreCharacter); | 3948 | eventSource.once(event_types.MESSAGE_RECEIVED, restoreCharacter); |
| 3949 | toastr.info(`Asking ${name} something...`); | 3949 | toastr.info(`Asking ${name} something...`); |
| 3950 | askResult = await Generate('ask_command'); | 3950 | askResult = await Generate('normal'); |
| 3951 | } catch (error) { | 3951 | } catch (error) { |
| 3952 | restoreCharacter(); | 3952 | restoreCharacter(); |
| 3953 | console.error('Error running /ask command', error); | 3953 | console.error('Error running /ask command', error); |