Implement a priority for prompt injections in CC (#3978)

* Implement a priority for prompt injections in CC

Adds a numeric order for injected prompts, 0 being default and placed at the top, and higher numbers placing further down. If two messages have the same priority, then order is determined by role as was before.

* Update data-i18n for new setting field

* Rename priority to order, sort higher first/lower last

* Hide order when position is relative, adjust hint text

* Fix type error

* Fix capitalization

* Cut UI texts

* Reposition text labels

---------

Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
This commit is contained in:
Kristian Schlikow
2025-05-12 22:59:54 +02:00
committed by GitHub
parent e25a033caa
commit 8100a542e2
18 changed files with 91 additions and 53 deletions

View File

@ -77,7 +77,7 @@ const registerPromptManagerMigration = () => {
* Represents a prompt.
*/
class Prompt {
identifier; role; content; name; system_prompt; position; injection_position; injection_depth; forbid_overrides; extension;
identifier; role; content; name; system_prompt; position; injection_position; injection_depth; injection_order; forbid_overrides; extension;
/**
* Create a new Prompt instance.
@ -91,10 +91,11 @@ class Prompt {
* @param {string} [param0.position] - The position of the prompt in the prompt list.
* @param {number} [param0.injection_position] - The insert position of the prompt.
* @param {number} [param0.injection_depth] - The depth of the prompt in the chat.
* @param {number} [param0.injection_order] - The order of the prompt in the chat.
* @param {boolean} [param0.forbid_overrides] - Indicates if the prompt should not be overridden.
* @param {boolean} [param0.extension] - Prompt is added by an extension.
*/
constructor({ identifier, role, content, name, system_prompt, position, injection_depth, injection_position, forbid_overrides, extension }) {
constructor({ identifier, role, content, name, system_prompt, position, injection_depth, injection_position, forbid_overrides, extension, injection_order } = {}) {
this.identifier = identifier;
this.role = role;
this.content = content;
@ -105,6 +106,7 @@ class Prompt {
this.injection_position = injection_position;
this.forbid_overrides = forbid_overrides;
this.extension = extension ?? false;
this.injection_order = injection_order ?? 0;
}
}
@ -447,7 +449,9 @@ class PromptManager {
document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_prompt').value = prompt.content ?? '';
document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_position').value = prompt.injection_position ?? 0;
document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_depth').value = prompt.injection_depth ?? DEFAULT_DEPTH;
document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_order').value = prompt.injection_order ?? 0;
document.getElementById(this.configuration.prefix + 'prompt_manager_depth_block').style.visibility = prompt.injection_position === INJECTION_POSITION.ABSOLUTE ? 'visible' : 'hidden';
document.getElementById(this.configuration.prefix + 'prompt_manager_order_block').style.visibility = prompt.injection_position === INJECTION_POSITION.ABSOLUTE ? 'visible' : 'hidden';
document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_forbid_overrides').checked = prompt.forbid_overrides ?? false;
document.getElementById(this.configuration.prefix + 'prompt_manager_forbid_overrides_block').style.visibility = this.overridablePrompts.includes(prompt.identifier) ? 'visible' : 'hidden';
document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_prompt').disabled = prompt.marker ?? false;
@ -782,6 +786,7 @@ class PromptManager {
prompt.content = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_prompt').value;
prompt.injection_position = Number(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_position').value);
prompt.injection_depth = Number(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_depth').value);
prompt.injection_order = Number(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_order').value);
prompt.forbid_overrides = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_forbid_overrides').checked;
}
@ -1222,7 +1227,9 @@ class PromptManager {
const promptField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_prompt');
const injectionPositionField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_position');
const injectionDepthField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_depth');
const injectionOrderField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_order');
const injectionDepthBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_depth_block');
const injectionOrderBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_order_block');
const forbidOverridesField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_forbid_overrides');
const forbidOverridesBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_forbid_overrides_block');
const entrySourceBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_source_block');
@ -1235,7 +1242,9 @@ class PromptManager {
promptField.disabled = prompt.marker ?? false;
injectionPositionField.value = prompt.injection_position ?? INJECTION_POSITION.RELATIVE;
injectionDepthField.value = prompt.injection_depth ?? DEFAULT_DEPTH;
injectionOrderField.value = prompt.injection_order ?? 0;
injectionDepthBlock.style.visibility = prompt.injection_position === INJECTION_POSITION.ABSOLUTE ? 'visible' : 'hidden';
injectionOrderBlock.style.visibility = prompt.injection_position === INJECTION_POSITION.ABSOLUTE ? 'visible' : 'hidden';
injectionPositionField.removeAttribute('disabled');
forbidOverridesField.checked = prompt.forbid_overrides ?? false;
forbidOverridesBlock.style.visibility = this.overridablePrompts.includes(prompt.identifier) ? 'visible' : 'hidden';
@ -1267,11 +1276,14 @@ class PromptManager {
handleInjectionPositionChange(event) {
const injectionDepthBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_depth_block');
const injectionOrderBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_order_block');
const injectionPosition = Number(event.target.value);
if (injectionPosition === INJECTION_POSITION.ABSOLUTE) {
injectionDepthBlock.style.visibility = 'visible';
injectionOrderBlock.style.visibility = 'visible';
} else {
injectionDepthBlock.style.visibility = 'hidden';
injectionOrderBlock.style.visibility = 'hidden';
}
}
@ -1328,6 +1340,7 @@ class PromptManager {
const injectionPositionField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_position');
const injectionDepthField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_depth');
const injectionDepthBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_depth_block');
const injectionOrderBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_order_block');
const forbidOverridesField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_forbid_overrides');
const forbidOverridesBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_forbid_overrides_block');
const entrySourceBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_source_block');
@ -1341,6 +1354,7 @@ class PromptManager {
injectionPositionField.removeAttribute('disabled');
injectionDepthField.value = DEFAULT_DEPTH;
injectionDepthBlock.style.visibility = 'unset';
injectionOrderBlock.style.visibility = 'unset';
forbidOverridesBlock.style.visibility = 'unset';
forbidOverridesField.checked = false;
entrySourceBlock.style.display = 'none';

View File

@ -760,22 +760,40 @@ async function populationInjectionPrompts(prompts, messages) {
// Get prompts for current depth
const depthPrompts = prompts.filter(prompt => prompt.injection_depth === i && prompt.content);
// Order of priority (most important go lower)
const roles = ['system', 'user', 'assistant'];
const roleMessages = [];
const separator = '\n';
const wrap = false;
for (const role of roles) {
// Get prompts for current role
const rolePrompts = depthPrompts.filter(prompt => prompt.role === role).map(x => x.content).join(separator);
// Get extension prompt
const extensionPrompt = await getExtensionPrompt(extension_prompt_types.IN_CHAT, i, separator, roleTypes[role], wrap);
// Group prompts by priority
const orderGroups = {};
for (const prompt of depthPrompts) {
const order = prompt.injection_order || 0;
if (!orderGroups[order]) {
orderGroups[order] = [];
}
orderGroups[order].push(prompt);
}
const jointPrompt = [rolePrompts, extensionPrompt].filter(x => x).map(x => x.trim()).join(separator);
// Process each order group in order (b - a = low to high ; a - b = high to low)
const orders = Object.keys(orderGroups).sort((a, b) => +a - +b);
for (const order of orders) {
const orderPrompts = orderGroups[order];
if (jointPrompt && jointPrompt.length) {
roleMessages.push({ 'role': role, 'content': jointPrompt, injected: true });
// Order of priority for roles (most important go lower)
const roles = ['system', 'user', 'assistant'];
for (const role of roles) {
const rolePrompts = orderPrompts
.filter(prompt => prompt.role === role)
.map(x => x.content)
.join(separator);
// Get extension prompt
const extensionPrompt = await getExtensionPrompt(extension_prompt_types.IN_CHAT, i, separator, roleTypes[role], wrap);
const jointPrompt = [rolePrompts, extensionPrompt].filter(x => x).map(x => x.trim()).join(separator);
if (jointPrompt && jointPrompt.length) {
roleMessages.push({ 'role': role, 'content': jointPrompt, injected: true });
}
}
}
@ -1314,6 +1332,8 @@ async function preparePromptsForChatCompletion({ scenario, charPersonality, name
prompt.injection_position = collectionPrompt.injection_position ?? prompt.injection_position;
// Depth for In-Chat
prompt.injection_depth = collectionPrompt.injection_depth ?? prompt.injection_depth;
// Priority for In-Chat
prompt.injection_order = collectionPrompt.injection_order ?? prompt.injection_order;
// Role (system, user, assistant)
prompt.role = collectionPrompt.role ?? prompt.role;
}