Add generation type triggers to world info (#4286) * Add generation type triggers to world info * Simplify includes check * Refactor getEntryField validation and default value handling * Remove invalid attribute * Check for a valid trigger
Signed| @@ -286,6 +286,13 @@ select.keyselect+span.select2-container .select2-selection--multiple { | |||
| 286 | display: none; | 286 | display: none; |
| 287 | } | 287 | } |
| 288 | 288 | ||
| 289 | .world_entry label[for="__invisible"] { | ||
| 290 | visibility: hidden; | ||
| 291 | pointer-events: none; | ||
| 292 | opacity: 0; | ||
| 293 | width: 0; | ||
| 294 | } | ||
| 295 | |||
| 289 | #WIMultiSelector .select2-container .select2-selection--multiple { | 296 | #WIMultiSelector .select2-container .select2-selection--multiple { |
| 290 | max-height: 25vh; | 297 | max-height: 25vh; |
| 291 | overflow-y: auto; | 298 | overflow-y: auto; |
| @@ -6494,6 +6494,30 @@ | |||
| 6494 | </select> | 6494 | </select> |
| 6495 | </div> | 6495 | </div> |
| 6496 | </div> | 6496 | </div> |
| 6497 | <div class="flex4"> | ||
| 6498 | <div class="flex-container justifySpaceBetween"> | ||
| 6499 | <small> | ||
| 6500 | <span data-i18n="Filter to Generation Triggers"> | ||
| 6501 | Filter to Generation Triggers | ||
| 6502 | </span> | ||
| 6503 | </small> | ||
| 6504 | <!-- Not a real control. Used to make label heights even. --> | ||
| 6505 | <label class="checkbox_label" for="__invisible"> | ||
| 6506 | <input type="checkbox" name="__invisible"> | ||
| 6507 | <span><small> </small></span> | ||
| 6508 | </label> | ||
| 6509 | </div> | ||
| 6510 | <div class="range-block-range"> | ||
| 6511 | <select name="triggers" multiple> | ||
| 6512 | <option data-i18n="Normal" value="normal">Normal</option> | ||
| 6513 | <option data-i18n="Continue" value="continue">Continue</option> | ||
| 6514 | <option data-i18n="Impersonate" value="impersonate">Impersonate</option> | ||
| 6515 | <option data-i18n="Swipe" value="swipe">Swipe</option> | ||
| 6516 | <option data-i18n="Regenerate" value="regenerate">Regenerate</option> | ||
| 6517 | <option data-i18n="Quiet" value="quiet">Quiet</option> | ||
| 6518 | </select> | ||
| 6519 | </div> | ||
| 6520 | </div> | ||
| 6497 | </div> | 6521 | </div> |
| 6498 | <div name="WIEntryBottomControls" class="flex-container flex1 justifySpaceBetween world_entry_form_horizontal"> | 6522 | <div name="WIEntryBottomControls" class="flex-container flex1 justifySpaceBetween world_entry_form_horizontal"> |
| 6499 | <div class="flex-container flexFlowColumn flexNoGap wi-enter-footer-text"> | 6523 | <div class="flex-container flexFlowColumn flexNoGap wi-enter-footer-text"> |
| @@ -176,7 +176,7 @@ import { | |||
| 176 | renderPaginationDropdown, | 176 | renderPaginationDropdown, |
| 177 | paginationDropdownChangeHandler, | 177 | paginationDropdownChangeHandler, |
| 178 | } from './scripts/utils.js'; | 178 | } from './scripts/utils.js'; |
| 179 | import { debounce_timeout, IGNORE_SYMBOL } from './scripts/constants.js'; | 179 | import { debounce_timeout, GENERATION_TYPE_TRIGGERS, IGNORE_SYMBOL } from './scripts/constants.js'; |
| 180 | 180 | ||
| 181 | import { cancelDebouncedMetadataSave, doDailyExtensionUpdatesCheck, extension_settings, initExtensions, loadExtensionSettings, runGenerationInterceptors, saveMetadataDebounced } from './scripts/extensions.js'; | 181 | import { cancelDebouncedMetadataSave, doDailyExtensionUpdatesCheck, extension_settings, initExtensions, loadExtensionSettings, runGenerationInterceptors, saveMetadataDebounced } from './scripts/extensions.js'; |
| 182 | import { COMMENT_NAME_DEFAULT, CONNECT_API_MAP, executeSlashCommandsOnChatInput, initDefaultSlashCommands, isExecutingCommandsFromChatInput, pauseScriptExecution, stopScriptExecution, UNIQUE_APIS } from './scripts/slash-commands.js'; | 182 | import { COMMENT_NAME_DEFAULT, CONNECT_API_MAP, executeSlashCommandsOnChatInput, initDefaultSlashCommands, isExecutingCommandsFromChatInput, pauseScriptExecution, stopScriptExecution, UNIQUE_APIS } from './scripts/slash-commands.js'; |
| @@ -3721,6 +3721,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 3721 | // Make quiet prompt available for WIAN | 3721 | // Make quiet prompt available for WIAN |
| 3722 | setExtensionPrompt('QUIET_PROMPT', quiet_prompt || '', extension_prompt_types.IN_PROMPT, 0, true); | 3722 | setExtensionPrompt('QUIET_PROMPT', quiet_prompt || '', extension_prompt_types.IN_PROMPT, 0, true); |
| 3723 | const chatForWI = coreChat.map(x => world_info_include_names ? `${x.name}: ${x.mes}` : x.mes).reverse(); | 3723 | const chatForWI = coreChat.map(x => world_info_include_names ? `${x.name}: ${x.mes}` : x.mes).reverse(); |
| 3724 | /** @type {import('./scripts/world-info.js').WIGlobalScanData} */ | ||
| 3724 | const globalScanData = { | 3725 | const globalScanData = { |
| 3725 | personaDescription: persona, | 3726 | personaDescription: persona, |
| 3726 | characterDescription: description, | 3727 | characterDescription: description, |
| @@ -3728,6 +3729,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 3728 | characterDepthPrompt: charDepthPrompt, | 3729 | characterDepthPrompt: charDepthPrompt, |
| 3729 | scenario: scenario, | 3730 | scenario: scenario, |
| 3730 | creatorNotes: creatorNotes, | 3731 | creatorNotes: creatorNotes, |
| 3732 | trigger: GENERATION_TYPE_TRIGGERS.includes(type) ? type : 'normal', | ||
| 3731 | }; | 3733 | }; |
| 3732 | const { worldInfoString, worldInfoBefore, worldInfoAfter, worldInfoExamples, worldInfoDepth } = await getWorldInfoPrompt(chatForWI, this_max_context, dryRun, globalScanData); | 3734 | const { worldInfoString, worldInfoBefore, worldInfoAfter, worldInfoExamples, worldInfoDepth } = await getWorldInfoPrompt(chatForWI, this_max_context, dryRun, globalScanData); |
| 3733 | setExtensionPrompt('QUIET_PROMPT', '', extension_prompt_types.IN_PROMPT, 0, true); | 3735 | setExtensionPrompt('QUIET_PROMPT', '', extension_prompt_types.IN_PROMPT, 0, true); |
| @@ -28,3 +28,15 @@ export const IGNORE_SYMBOL = Symbol.for('ignore'); | |||
| 28 | * https://ai.google.dev/gemini-api/docs/video-understanding#supported-formats | 28 | * https://ai.google.dev/gemini-api/docs/video-understanding#supported-formats |
| 29 | */ | 29 | */ |
| 30 | export const VIDEO_EXTENSIONS = ['mp4', 'avi', 'mov', 'wmv', 'flv', 'webm', '3gp', 'mkv', 'mpg']; | 30 | export const VIDEO_EXTENSIONS = ['mp4', 'avi', 'mov', 'wmv', 'flv', 'webm', '3gp', 'mkv', 'mpg']; |
| 31 | |||
| 32 | /** | ||
| 33 | * Known generation triggers that can be passed to Generate function. | ||
| 34 | */ | ||
| 35 | export const GENERATION_TYPE_TRIGGERS = [ | ||
| 36 | 'normal', | ||
| 37 | 'continue', | ||
| 38 | 'impersonate', | ||
| 39 | 'swipe', | ||
| 40 | 'regenerate', | ||
| 41 | 'quiet', | ||
| 42 | ]; | ||
| @@ -9,7 +9,7 @@ import { FILTER_TYPES, FilterHelper } from './filters.js'; | |||
| 9 | import { getTokenCountAsync } from './tokenizers.js'; | 9 | import { getTokenCountAsync } from './tokenizers.js'; |
| 10 | import { power_user } from './power-user.js'; | 10 | import { power_user } from './power-user.js'; |
| 11 | import { getTagKeyForEntity } from './tags.js'; | 11 | import { getTagKeyForEntity } from './tags.js'; |
| 12 | import { debounce_timeout } from './constants.js'; | 12 | import { debounce_timeout, GENERATION_TYPE_TRIGGERS } from './constants.js'; |
| 13 | import { getRegexedString, regex_placement } from './extensions/regex/engine.js'; | 13 | import { getRegexedString, regex_placement } from './extensions/regex/engine.js'; |
| 14 | import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; | 14 | import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; |
| 15 | import { SlashCommand } from './slash-commands/SlashCommand.js'; | 15 | import { SlashCommand } from './slash-commands/SlashCommand.js'; |
| @@ -107,6 +107,7 @@ const KNOWN_DECORATORS = ['@@activate', '@@dont_activate']; | |||
| 107 | * @property {string} characterDepthPrompt Character depth prompt (sometimes referred to as character notes) | 107 | * @property {string} characterDepthPrompt Character depth prompt (sometimes referred to as character notes) |
| 108 | * @property {string} scenario Character defined scenario | 108 | * @property {string} scenario Character defined scenario |
| 109 | * @property {string} creatorNotes Character creator notes | 109 | * @property {string} creatorNotes Character creator notes |
| 110 | * @property {string} trigger The type that triggered the scan, e.g. 'normal', 'continue', etc. | ||
| 110 | */ | 111 | */ |
| 111 | 112 | ||
| 112 | /** | 113 | /** |
| @@ -145,6 +146,36 @@ const KNOWN_DECORATORS = ['@@activate', '@@dont_activate']; | |||
| 145 | * @typedef TimedEffectType Type of timed effect | 146 | * @typedef TimedEffectType Type of timed effect |
| 146 | * @type {'sticky'|'cooldown'|'delay'} | 147 | * @type {'sticky'|'cooldown'|'delay'} |
| 147 | */ | 148 | */ |
| 149 | |||
| 150 | /** | ||
| 151 | * @typedef {object} WIPromptResult | ||
| 152 | * @property {string} worldInfoString - Complete world info string | ||
| 153 | * @property {string} worldInfoBefore - World info that goes before the prompt | ||
| 154 | * @property {string} worldInfoAfter - World info that goes after the prompt | ||
| 155 | * @property {Array} worldInfoExamples - Array of example entries | ||
| 156 | * @property {Array} worldInfoDepth - Array of depth entries | ||
| 157 | * @property {Array} anBefore - Array of entries before Author's Note | ||
| 158 | * @property {Array} anAfter - Array of entries after Author's Note | ||
| 159 | */ | ||
| 160 | |||
| 161 | /** | ||
| 162 | * @typedef {object} WIActivated | ||
| 163 | * @property {string} worldInfoBefore The world info before the chat. | ||
| 164 | * @property {string} worldInfoAfter The world info after the chat. | ||
| 165 | * @property {any[]} EMEntries The entries for examples. | ||
| 166 | * @property {any[]} WIDepthEntries The depth entries. | ||
| 167 | * @property {any[]} ANBeforeEntries The entries before Author's Note. | ||
| 168 | * @property {any[]} ANAfterEntries The entries after Author's Note. | ||
| 169 | * @property {Set<any>} allActivatedEntries All entries. | ||
| 170 | */ | ||
| 171 | |||
| 172 | /** | ||
| 173 | * @typedef {object} WIEntryFieldDefinition | ||
| 174 | * @property {any} default - Default value for the field | ||
| 175 | * @property {string} type - Type of the field, can be 'string', 'number', 'boolean', 'array', 'enum' | ||
| 176 | * @property {boolean} [excludeFromTemplate=false] - Whether to exclude this field from the template | ||
| 177 | * @property {(value: any) => boolean} [arrayFilter] - Optional filter function for array fields to filter out unwanted values | ||
| 178 | */ | ||
| 148 | // End typedef area | 179 | // End typedef area |
| 149 | 180 | ||
| 150 | /** | 181 | /** |
| @@ -801,14 +832,6 @@ export const worldInfoCache = new StructuredCloneMap({ cloneOnGet: true, cloneOn | |||
| 801 | * @param {number} maxContext - The maximum context size of the generation. | 832 | * @param {number} maxContext - The maximum context size of the generation. |
| 802 | * @param {boolean} isDryRun - If true, the function will not emit any events. | 833 | * @param {boolean} isDryRun - If true, the function will not emit any events. |
| 803 | * @param {WIGlobalScanData} globalScanData Chat independent context to be scanned | 834 | * @param {WIGlobalScanData} globalScanData Chat independent context to be scanned |
| 804 | * @typedef {object} WIPromptResult | ||
| 805 | * @property {string} worldInfoString - Complete world info string | ||
| 806 | * @property {string} worldInfoBefore - World info that goes before the prompt | ||
| 807 | * @property {string} worldInfoAfter - World info that goes after the prompt | ||
| 808 | * @property {Array} worldInfoExamples - Array of example entries | ||
| 809 | * @property {Array} worldInfoDepth - Array of depth entries | ||
| 810 | * @property {Array} anBefore - Array of entries before Author's Note | ||
| 811 | * @property {Array} anAfter - Array of entries after Author's Note | ||
| 812 | * @returns {Promise<WIPromptResult>} The world info string and depth. | 835 | * @returns {Promise<WIPromptResult>} The world info string and depth. |
| 813 | */ | 836 | */ |
| 814 | export async function getWorldInfoPrompt(chat, maxContext, isDryRun, globalScanData) { | 837 | export async function getWorldInfoPrompt(chat, maxContext, isDryRun, globalScanData) { |
| @@ -1139,7 +1162,7 @@ function registerWorldInfoSlashCommands() { | |||
| 1139 | return ''; | 1162 | return ''; |
| 1140 | } | 1163 | } |
| 1141 | 1164 | ||
| 1142 | if (newWorldInfoEntryTemplate[field] === undefined) { | 1165 | if (!Object.hasOwn(newWorldInfoEntryDefinition, field)) { |
| 1143 | toastr.warning('Valid field name is required'); | 1166 | toastr.warning('Valid field name is required'); |
| 1144 | return ''; | 1167 | return ''; |
| 1145 | } | 1168 | } |
| @@ -1167,7 +1190,7 @@ function registerWorldInfoSlashCommands() { | |||
| 1167 | } | 1190 | } |
| 1168 | break; | 1191 | break; |
| 1169 | default: | 1192 | default: |
| 1170 | fieldValue = entry[field]; | 1193 | fieldValue = entry[field] ?? newWorldInfoEntryDefinition[field]?.default; |
| 1171 | } | 1194 | } |
| 1172 | 1195 | ||
| 1173 | if (fieldValue === undefined) { | 1196 | if (fieldValue === undefined) { |
| @@ -1253,11 +1276,19 @@ function registerWorldInfoSlashCommands() { | |||
| 1253 | return ''; | 1276 | return ''; |
| 1254 | } | 1277 | } |
| 1255 | 1278 | ||
| 1256 | if (newWorldInfoEntryTemplate[field] === undefined) { | 1279 | if (!Object.hasOwn(newWorldInfoEntryDefinition, field)) { |
| 1257 | toastr.warning('Valid field name is required'); | 1280 | toastr.warning('Valid field name is required'); |
| 1258 | return ''; | 1281 | return ''; |
| 1259 | } | 1282 | } |
| 1260 | 1283 | ||
| 1284 | // Init a default value for the field if it does not exist | ||
| 1285 | if (!Object.hasOwn(entry, field)) { | ||
| 1286 | entry[field] = newWorldInfoEntryDefinition[field].default; | ||
| 1287 | } | ||
| 1288 | |||
| 1289 | // Use an array filter if it exists for the field | ||
| 1290 | const arrayFilter = newWorldInfoEntryDefinition[field]?.arrayFilter || (() => true); | ||
| 1291 | |||
| 1261 | // handle special cases, otherwise execute default logic | 1292 | // handle special cases, otherwise execute default logic |
| 1262 | let tagNames; | 1293 | let tagNames; |
| 1263 | let charNames; | 1294 | let charNames; |
| @@ -1285,7 +1316,7 @@ function registerWorldInfoSlashCommands() { | |||
| 1285 | break; | 1316 | break; |
| 1286 | default: | 1317 | default: |
| 1287 | if (Array.isArray(entry[field])) { | 1318 | if (Array.isArray(entry[field])) { |
| 1288 | entry[field] = parseStringArray(value); | 1319 | entry[field] = parseStringArray(value).filter(arrayFilter); |
| 1289 | } else if (typeof entry[field] === 'boolean') { | 1320 | } else if (typeof entry[field] === 'boolean') { |
| 1290 | entry[field] = isTrueBoolean(value); | 1321 | entry[field] = isTrueBoolean(value); |
| 1291 | } else if (typeof entry[field] === 'number') { | 1322 | } else if (typeof entry[field] === 'number') { |
| @@ -2438,6 +2469,7 @@ export const originalWIDataKeyMap = { | |||
| 2438 | 'sticky': 'extensions.sticky', | 2469 | 'sticky': 'extensions.sticky', |
| 2439 | 'cooldown': 'extensions.cooldown', | 2470 | 'cooldown': 'extensions.cooldown', |
| 2440 | 'delay': 'extensions.delay', | 2471 | 'delay': 'extensions.delay', |
| 2472 | 'triggers': 'extensions.triggers', | ||
| 2441 | }; | 2473 | }; |
| 2442 | 2474 | ||
| 2443 | /** Checks the state of the current search, and adds/removes the search sorting option accordingly */ | 2475 | /** Checks the state of the current search, and adds/removes the search sorting option accordingly */ |
| @@ -3496,6 +3528,29 @@ export async function getWorldEntry(name, data, entry) { | |||
| 3496 | automationIdInput.val(entry.automationId ?? '').trigger('input', { noSave: true }); | 3528 | automationIdInput.val(entry.automationId ?? '').trigger('input', { noSave: true }); |
| 3497 | setTimeout(() => createEntryInputAutocomplete(automationIdInput, getAutomationIdCallback(data)), 1); | 3529 | setTimeout(() => createEntryInputAutocomplete(automationIdInput, getAutomationIdCallback(data)), 1); |
| 3498 | 3530 | ||
| 3531 | // Generation Type Triggers | ||
| 3532 | const generationTypeTriggers = editTemplate.find('select[name="triggers"]'); | ||
| 3533 | generationTypeTriggers.data('uid', entry.uid); | ||
| 3534 | generationTypeTriggers.on('input', async function (_, { noSave = false } = {}) { | ||
| 3535 | const uid = $(this).data('uid'); | ||
| 3536 | const value = $(this).val(); | ||
| 3537 | data.entries[uid].triggers = Array.isArray(value) ? value : []; | ||
| 3538 | setWIOriginalDataValue(data, uid, 'extensions.triggers', data.entries[uid].triggers); | ||
| 3539 | !noSave && await saveWorldInfo(name, data); | ||
| 3540 | }); | ||
| 3541 | if (!isMobile()) { | ||
| 3542 | generationTypeTriggers.select2({ | ||
| 3543 | placeholder: t`All types (default)`, | ||
| 3544 | width: '100%', | ||
| 3545 | closeOnSelect: false, | ||
| 3546 | allowClear: true, | ||
| 3547 | }); | ||
| 3548 | } | ||
| 3549 | generationTypeTriggers | ||
| 3550 | .val(Array.isArray(entry.triggers) ? entry.triggers : []) | ||
| 3551 | .trigger('input', { noSave: true }) | ||
| 3552 | .trigger('change'); | ||
| 3553 | |||
| 3499 | countTokensDebounced(counter, contentInput.val()); | 3554 | countTokensDebounced(counter, contentInput.val()); |
| 3500 | 3555 | ||
| 3501 | editTemplate.find('.inline-drawer-content').css('display', 'none'); | 3556 | editTemplate.find('.inline-drawer-content').css('display', 'none'); |
| @@ -3652,7 +3707,7 @@ export async function deleteWorldInfoEntry(data, uid, { silent = false } = {}) { | |||
| 3652 | * | 3707 | * |
| 3653 | * Use `newEntryTemplate` if you just need the template that contains default values | 3708 | * Use `newEntryTemplate` if you just need the template that contains default values |
| 3654 | * | 3709 | * |
| 3655 | * @type {{[key: string]: { default: any, type: string, excludeFromTemplate?: boolean }}} | 3710 | * @type {{[key: string]: WIEntryFieldDefinition}} |
| 3656 | */ | 3711 | */ |
| 3657 | export const newWorldInfoEntryDefinition = { | 3712 | export const newWorldInfoEntryDefinition = { |
| 3658 | key: { default: [], type: 'array' }, | 3713 | key: { default: [], type: 'array' }, |
| @@ -3694,6 +3749,7 @@ export const newWorldInfoEntryDefinition = { | |||
| 3694 | characterFilterNames: { default: [], type: 'array', excludeFromTemplate: true }, | 3749 | characterFilterNames: { default: [], type: 'array', excludeFromTemplate: true }, |
| 3695 | characterFilterTags: { default: [], type: 'array', excludeFromTemplate: true }, | 3750 | characterFilterTags: { default: [], type: 'array', excludeFromTemplate: true }, |
| 3696 | characterFilterExclude: { default: false, type: 'boolean', excludeFromTemplate: true }, | 3751 | characterFilterExclude: { default: false, type: 'boolean', excludeFromTemplate: true }, |
| 3752 | triggers: { default: [], type: 'array', arrayFilter: (value) => GENERATION_TYPE_TRIGGERS.includes(value) }, | ||
| 3697 | }; | 3753 | }; |
| 3698 | 3754 | ||
| 3699 | export const newWorldInfoEntryTemplate = Object.fromEntries( | 3755 | export const newWorldInfoEntryTemplate = Object.fromEntries( |
| @@ -4143,23 +4199,14 @@ function parseDecorators(content) { | |||
| 4143 | * @param {number} maxContext The maximum context size of the generation. | 4199 | * @param {number} maxContext The maximum context size of the generation. |
| 4144 | * @param {boolean} isDryRun Whether to perform a dry run. | 4200 | * @param {boolean} isDryRun Whether to perform a dry run. |
| 4145 | * @param {WIGlobalScanData} globalScanData Chat independent context to be scanned | 4201 | * @param {WIGlobalScanData} globalScanData Chat independent context to be scanned |
| 4146 | * @typedef {object} WIActivated | ||
| 4147 | * @property {string} worldInfoBefore The world info before the chat. | ||
| 4148 | * @property {string} worldInfoAfter The world info after the chat. | ||
| 4149 | * @property {any[]} EMEntries The entries for examples. | ||
| 4150 | * @property {any[]} WIDepthEntries The depth entries. | ||
| 4151 | * @property {any[]} ANBeforeEntries The entries before Author's Note. | ||
| 4152 | * @property {any[]} ANAfterEntries The entries after Author's Note. | ||
| 4153 | * @property {Set<any>} allActivatedEntries All entries. | ||
| 4154 | * @returns {Promise<WIActivated>} The world info activated. | 4202 | * @returns {Promise<WIActivated>} The world info activated. |
| 4155 | */ | 4203 | */ |
| 4156 | |||
| 4157 | //MARK: checkWorldInfo | 4204 | //MARK: checkWorldInfo |
| 4158 | export async function checkWorldInfo(chat, maxContext, isDryRun, globalScanData) { | 4205 | export async function checkWorldInfo(chat, maxContext, isDryRun, globalScanData) { |
| 4159 | const context = getContext(); | 4206 | const context = getContext(); |
| 4160 | const buffer = new WorldInfoBuffer(chat, globalScanData); | 4207 | const buffer = new WorldInfoBuffer(chat, globalScanData); |
| 4161 | 4208 | ||
| 4162 | console.debug(`[WI] --- START WI SCAN (on ${chat.length} messages)${isDryRun ? ' (DRY RUN)' : ''} ---`); | 4209 | console.debug(`[WI] --- START WI SCAN (on ${chat.length} messages, trigger = ${globalScanData.trigger})${isDryRun ? ' (DRY RUN)' : ''} ---`); |
| 4163 | 4210 | ||
| 4164 | // Combine the chat | 4211 | // Combine the chat |
| 4165 | 4212 | ||
| @@ -4231,7 +4278,7 @@ export async function checkWorldInfo(chat, maxContext, isDryRun, globalScanData) | |||
| 4231 | // Loop and find all entries that can activate here | 4278 | // Loop and find all entries that can activate here |
| 4232 | let activatedNow = new Set(); | 4279 | let activatedNow = new Set(); |
| 4233 | 4280 | ||
| 4234 | for (let entry of sortedEntries) { | 4281 | for (const entry of sortedEntries) { |
| 4235 | // Logging preparation | 4282 | // Logging preparation |
| 4236 | let headerLogged = false; | 4283 | let headerLogged = false; |
| 4237 | function log(...args) { | 4284 | function log(...args) { |
| @@ -4252,6 +4299,15 @@ export async function checkWorldInfo(chat, maxContext, isDryRun, globalScanData) | |||
| 4252 | continue; | 4299 | continue; |
| 4253 | } | 4300 | } |
| 4254 | 4301 | ||
| 4302 | // Check for generation type trigger filter | ||
| 4303 | if (Array.isArray(entry.triggers) && entry.triggers.length > 0) { | ||
| 4304 | const isTriggered = entry.triggers.includes(globalScanData.trigger); | ||
| 4305 | if (!isTriggered) { | ||
| 4306 | log(`skipped by generation type trigger filter (${globalScanData.trigger} ∉ ${entry.triggers})`); | ||
| 4307 | continue; | ||
| 4308 | } | ||
| 4309 | } | ||
| 4310 | |||
| 4255 | // Check if this entry applies to the character or if it's excluded | 4311 | // Check if this entry applies to the character or if it's excluded |
| 4256 | if (entry.characterFilter && entry.characterFilter?.names?.length > 0) { | 4312 | if (entry.characterFilter && entry.characterFilter?.names?.length > 0) { |
| 4257 | const nameIncluded = entry.characterFilter.names.includes(getCharaFilename()); | 4313 | const nameIncluded = entry.characterFilter.names.includes(getCharaFilename()); |
| @@ -4877,6 +4933,7 @@ function convertAgnaiMemoryBook(inputObj) { | |||
| 4877 | sticky: null, | 4933 | sticky: null, |
| 4878 | cooldown: null, | 4934 | cooldown: null, |
| 4879 | delay: null, | 4935 | delay: null, |
| 4936 | triggers: [], | ||
| 4880 | }; | 4937 | }; |
| 4881 | }); | 4938 | }); |
| 4882 | 4939 | ||
| @@ -4919,6 +4976,7 @@ function convertRisuLorebook(inputObj) { | |||
| 4919 | sticky: null, | 4976 | sticky: null, |
| 4920 | cooldown: null, | 4977 | cooldown: null, |
| 4921 | delay: null, | 4978 | delay: null, |
| 4979 | triggers: [], | ||
| 4922 | }; | 4980 | }; |
| 4923 | }); | 4981 | }); |
| 4924 | 4982 | ||
| @@ -4966,6 +5024,7 @@ function convertNovelLorebook(inputObj) { | |||
| 4966 | sticky: null, | 5024 | sticky: null, |
| 4967 | cooldown: null, | 5025 | cooldown: null, |
| 4968 | delay: null, | 5026 | delay: null, |
| 5027 | triggers: [], | ||
| 4969 | }; | 5028 | }; |
| 4970 | }); | 5029 | }); |
| 4971 | 5030 | ||
| @@ -5022,6 +5081,7 @@ export function convertCharacterBook(characterBook) { | |||
| 5022 | matchScenario: entry.extensions?.match_scenario ?? false, | 5081 | matchScenario: entry.extensions?.match_scenario ?? false, |
| 5023 | matchCreatorNotes: entry.extensions?.match_creator_notes ?? false, | 5082 | matchCreatorNotes: entry.extensions?.match_creator_notes ?? false, |
| 5024 | extensions: entry.extensions ?? {}, | 5083 | extensions: entry.extensions ?? {}, |
| 5084 | triggers: entry.extensions?.triggers || [], | ||
| 5025 | }; | 5085 | }; |
| 5026 | }); | 5086 | }); |
| 5027 | 5087 | ||
| @@ -707,6 +707,7 @@ function convertWorldInfoToCharacterBook(name, entries) { | |||
| 707 | match_character_depth_prompt: entry.matchCharacterDepthPrompt ?? false, | 707 | match_character_depth_prompt: entry.matchCharacterDepthPrompt ?? false, |
| 708 | match_scenario: entry.matchScenario ?? false, | 708 | match_scenario: entry.matchScenario ?? false, |
| 709 | match_creator_notes: entry.matchCreatorNotes ?? false, | 709 | match_creator_notes: entry.matchCreatorNotes ?? false, |
| 710 | triggers: entry.triggers ?? [], | ||
| 710 | }, | 711 | }, |
| 711 | }; | 712 | }; |
| 712 | 713 | ||