Merge pull request #2601 from SillyTavern/wi-blackbox-be-gone WI blackbox begone (Export, document and refactor a bit of the WI API)
Signed| @@ -18,33 +18,13 @@ import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js'; | |||
| 18 | import { callGenericPopup, Popup, POPUP_TYPE } from './popup.js'; | 18 | import { callGenericPopup, Popup, POPUP_TYPE } from './popup.js'; |
| 19 | import { StructuredCloneMap } from './util/StructuredCloneMap.js'; | 19 | import { StructuredCloneMap } from './util/StructuredCloneMap.js'; |
| 20 | 20 | ||
| 21 | export { | 21 | export const world_info_insertion_strategy = { |
| 22 | world_info, | ||
| 23 | world_info_budget, | ||
| 24 | world_info_depth, | ||
| 25 | world_info_min_activations, | ||
| 26 | world_info_min_activations_depth_max, | ||
| 27 | world_info_include_names, | ||
| 28 | world_info_recursive, | ||
| 29 | world_info_overflow_alert, | ||
| 30 | world_info_case_sensitive, | ||
| 31 | world_info_match_whole_words, | ||
| 32 | world_info_character_strategy, | ||
| 33 | world_info_budget_cap, | ||
| 34 | world_names, | ||
| 35 | checkWorldInfo, | ||
| 36 | deleteWorldInfo, | ||
| 37 | setWorldInfoSettings, | ||
| 38 | getWorldInfoPrompt, | ||
| 39 | }; | ||
| 40 | |||
| 41 | const world_info_insertion_strategy = { | ||
| 42 | evenly: 0, | 22 | evenly: 0, |
| 43 | character_first: 1, | 23 | character_first: 1, |
| 44 | global_first: 2, | 24 | global_first: 2, |
| 45 | }; | 25 | }; |
| 46 | 26 | ||
| 47 | const world_info_logic = { | 27 | export const world_info_logic = { |
| 48 | AND_ANY: 0, | 28 | AND_ANY: 0, |
| 49 | NOT_ALL: 1, | 29 | NOT_ALL: 1, |
| 50 | NOT_ANY: 2, | 30 | NOT_ANY: 2, |
| @@ -54,7 +34,7 @@ const world_info_logic = { | |||
| 54 | /** | 34 | /** |
| 55 | * @enum {number} Possible states of the WI evaluation | 35 | * @enum {number} Possible states of the WI evaluation |
| 56 | */ | 36 | */ |
| 57 | const scan_state = { | 37 | export const scan_state = { |
| 58 | /** | 38 | /** |
| 59 | * The scan will be stopped. | 39 | * The scan will be stopped. |
| 60 | */ | 40 | */ |
| @@ -75,23 +55,23 @@ const scan_state = { | |||
| 75 | 55 | ||
| 76 | const WI_ENTRY_EDIT_TEMPLATE = $('#entry_edit_template .world_entry'); | 56 | const WI_ENTRY_EDIT_TEMPLATE = $('#entry_edit_template .world_entry'); |
| 77 | 57 | ||
| 78 | let world_info = {}; | 58 | export let world_info = {}; |
| 79 | let selected_world_info = []; | 59 | export let selected_world_info = []; |
| 80 | /** @type {string[]} */ | 60 | /** @type {string[]} */ |
| 81 | let world_names; | 61 | export let world_names; |
| 82 | let world_info_depth = 2; | 62 | export let world_info_depth = 2; |
| 83 | let world_info_min_activations = 0; // if > 0, will continue seeking chat until minimum world infos are activated | 63 | export let world_info_min_activations = 0; // if > 0, will continue seeking chat until minimum world infos are activated |
| 84 | let world_info_min_activations_depth_max = 0; // used when (world_info_min_activations > 0) | 64 | export let world_info_min_activations_depth_max = 0; // used when (world_info_min_activations > 0) |
| 85 | 65 | ||
| 86 | let world_info_budget = 25; | 66 | export let world_info_budget = 25; |
| 87 | let world_info_include_names = true; | 67 | export let world_info_include_names = true; |
| 88 | let world_info_recursive = false; | 68 | export let world_info_recursive = false; |
| 89 | let world_info_overflow_alert = false; | 69 | export let world_info_overflow_alert = false; |
| 90 | let world_info_case_sensitive = false; | 70 | export let world_info_case_sensitive = false; |
| 91 | let world_info_match_whole_words = false; | 71 | export let world_info_match_whole_words = false; |
| 92 | let world_info_use_group_scoring = false; | 72 | export let world_info_use_group_scoring = false; |
| 93 | let world_info_character_strategy = world_info_insertion_strategy.character_first; | 73 | export let world_info_character_strategy = world_info_insertion_strategy.character_first; |
| 94 | let world_info_budget_cap = 0; | 74 | export let world_info_budget_cap = 0; |
| 95 | const saveWorldDebounced = debounce(async (name, data) => await _save(name, data), debounce_timeout.relaxed); | 75 | const saveWorldDebounced = debounce(async (name, data) => await _save(name, data), debounce_timeout.relaxed); |
| 96 | const saveSettingsDebounced = debounce(() => { | 76 | const saveSettingsDebounced = debounce(() => { |
| 97 | Object.assign(world_info, { globalSelect: selected_world_info }); | 77 | Object.assign(world_info, { globalSelect: selected_world_info }); |
| @@ -101,13 +81,13 @@ const sortFn = (a, b) => b.order - a.order; | |||
| 101 | let updateEditor = (navigation, flashOnNav = true) => { console.debug('Triggered WI navigation', navigation, flashOnNav); }; | 81 | let updateEditor = (navigation, flashOnNav = true) => { console.debug('Triggered WI navigation', navigation, flashOnNav); }; |
| 102 | 82 | ||
| 103 | // Do not optimize. updateEditor is a function that is updated by the displayWorldEntries with new data. | 83 | // Do not optimize. updateEditor is a function that is updated by the displayWorldEntries with new data. |
| 104 | const worldInfoFilter = new FilterHelper(() => updateEditor()); | 84 | export const worldInfoFilter = new FilterHelper(() => updateEditor()); |
| 105 | const SORT_ORDER_KEY = 'world_info_sort_order'; | 85 | export const SORT_ORDER_KEY = 'world_info_sort_order'; |
| 106 | const METADATA_KEY = 'world_info'; | 86 | export const METADATA_KEY = 'world_info'; |
| 107 | 87 | ||
| 108 | const DEFAULT_DEPTH = 4; | 88 | export const DEFAULT_DEPTH = 4; |
| 109 | const DEFAULT_WEIGHT = 100; | 89 | export const DEFAULT_WEIGHT = 100; |
| 110 | const MAX_SCAN_DEPTH = 1000; | 90 | export const MAX_SCAN_DEPTH = 1000; |
| 111 | const KNOWN_DECORATORS = ['@@activate', '@@dont_activate']; | 91 | const KNOWN_DECORATORS = ['@@activate', '@@dont_activate']; |
| 112 | 92 | ||
| 113 | // Typedef area | 93 | // Typedef area |
| @@ -732,7 +712,7 @@ export function getWorldInfoSettings() { | |||
| 732 | }; | 712 | }; |
| 733 | } | 713 | } |
| 734 | 714 | ||
| 735 | const world_info_position = { | 715 | export const world_info_position = { |
| 736 | before: 0, | 716 | before: 0, |
| 737 | after: 1, | 717 | after: 1, |
| 738 | ANTop: 2, | 718 | ANTop: 2, |
| @@ -747,8 +727,18 @@ export const wi_anchor_position = { | |||
| 747 | after: 1, | 727 | after: 1, |
| 748 | }; | 728 | }; |
| 749 | 729 | ||
| 750 | /** @type {StructuredCloneMap<string,object>} */ | 730 | /** |
| 751 | const worldInfoCache = new StructuredCloneMap({ cloneOnGet: true, cloneOnSet: false }); | 731 | * The cache of all world info data that was loaded from the backend. |
| 732 | * | ||
| 733 | * Calling `loadWorldInfo` will fill this cache and utilize this cache, so should be the preferred way to load any world info data. | ||
| 734 | * Only use the cache directly if you need synchronous access. | ||
| 735 | * | ||
| 736 | * This will return a deep clone of the data, so no way to modify the data without actually saving it. | ||
| 737 | * Should generally be only used for readonly access. | ||
| 738 | * | ||
| 739 | * @type {StructuredCloneMap<string,object>} | ||
| 740 | * */ | ||
| 741 | export const worldInfoCache = new StructuredCloneMap({ cloneOnGet: true, cloneOnSet: false }); | ||
| 752 | 742 | ||
| 753 | /** | 743 | /** |
| 754 | * Gets the world info based on chat messages. | 744 | * Gets the world info based on chat messages. |
| @@ -758,7 +748,7 @@ const worldInfoCache = new StructuredCloneMap({ cloneOnGet: true, cloneOnSet: fa | |||
| 758 | * @typedef {{worldInfoString: string, worldInfoBefore: string, worldInfoAfter: string, worldInfoExamples: any[], worldInfoDepth: any[]}} WIPromptResult | 748 | * @typedef {{worldInfoString: string, worldInfoBefore: string, worldInfoAfter: string, worldInfoExamples: any[], worldInfoDepth: any[]}} WIPromptResult |
| 759 | * @returns {Promise<WIPromptResult>} The world info string and depth. | 749 | * @returns {Promise<WIPromptResult>} The world info string and depth. |
| 760 | */ | 750 | */ |
| 761 | async function getWorldInfoPrompt(chat, maxContext, isDryRun) { | 751 | export async function getWorldInfoPrompt(chat, maxContext, isDryRun) { |
| 762 | let worldInfoString = '', worldInfoBefore = '', worldInfoAfter = ''; | 752 | let worldInfoString = '', worldInfoBefore = '', worldInfoAfter = ''; |
| 763 | 753 | ||
| 764 | const activatedWorldInfo = await checkWorldInfo(chat, maxContext, isDryRun); | 754 | const activatedWorldInfo = await checkWorldInfo(chat, maxContext, isDryRun); |
| @@ -780,7 +770,7 @@ async function getWorldInfoPrompt(chat, maxContext, isDryRun) { | |||
| 780 | }; | 770 | }; |
| 781 | } | 771 | } |
| 782 | 772 | ||
| 783 | function setWorldInfoSettings(settings, data) { | 773 | export function setWorldInfoSettings(settings, data) { |
| 784 | if (settings.world_info_depth !== undefined) | 774 | if (settings.world_info_depth !== undefined) |
| 785 | world_info_depth = Number(settings.world_info_depth); | 775 | world_info_depth = Number(settings.world_info_depth); |
| 786 | if (settings.world_info_min_activations !== undefined) | 776 | if (settings.world_info_min_activations !== undefined) |
| @@ -916,7 +906,7 @@ function registerWorldInfoSlashCommands() { | |||
| 916 | return ''; | 906 | return ''; |
| 917 | } | 907 | } |
| 918 | 908 | ||
| 919 | const data = await loadWorldInfoData(file); | 909 | const data = await loadWorldInfo(file); |
| 920 | 910 | ||
| 921 | if (!data || !('entries' in data)) { | 911 | if (!data || !('entries' in data)) { |
| 922 | toastr.warning('World Info file has an invalid format'); | 912 | toastr.warning('World Info file has an invalid format'); |
| @@ -965,7 +955,7 @@ function registerWorldInfoSlashCommands() { | |||
| 965 | return ''; | 955 | return ''; |
| 966 | } | 956 | } |
| 967 | 957 | ||
| 968 | if (typeof newEntryTemplate[field] === 'boolean') { | 958 | if (typeof newWorldInfoEntryTemplate[field] === 'boolean') { |
| 969 | const isTrue = isTrueBoolean(value); | 959 | const isTrue = isTrueBoolean(value); |
| 970 | const isFalse = isFalseBoolean(value); | 960 | const isFalse = isFalseBoolean(value); |
| 971 | 961 | ||
| @@ -1016,7 +1006,7 @@ function registerWorldInfoSlashCommands() { | |||
| 1016 | return ''; | 1006 | return ''; |
| 1017 | } | 1007 | } |
| 1018 | 1008 | ||
| 1019 | if (newEntryTemplate[field] === undefined) { | 1009 | if (newWorldInfoEntryTemplate[field] === undefined) { |
| 1020 | toastr.warning('Valid field name is required'); | 1010 | toastr.warning('Valid field name is required'); |
| 1021 | return ''; | 1011 | return ''; |
| 1022 | } | 1012 | } |
| @@ -1038,7 +1028,7 @@ function registerWorldInfoSlashCommands() { | |||
| 1038 | const file = args.file; | 1028 | const file = args.file; |
| 1039 | const key = args.key; | 1029 | const key = args.key; |
| 1040 | 1030 | ||
| 1041 | const data = await loadWorldInfoData(file); | 1031 | const data = await loadWorldInfo(file); |
| 1042 | 1032 | ||
| 1043 | if (!data || !('entries' in data)) { | 1033 | if (!data || !('entries' in data)) { |
| 1044 | toastr.warning('Valid World Info file name is required'); | 1034 | toastr.warning('Valid World Info file name is required'); |
| @@ -1075,7 +1065,7 @@ function registerWorldInfoSlashCommands() { | |||
| 1075 | 1065 | ||
| 1076 | value = value.replace(/\\([{}|])/g, '$1'); | 1066 | value = value.replace(/\\([{}|])/g, '$1'); |
| 1077 | 1067 | ||
| 1078 | const data = await loadWorldInfoData(file); | 1068 | const data = await loadWorldInfo(file); |
| 1079 | 1069 | ||
| 1080 | if (!data || !('entries' in data)) { | 1070 | if (!data || !('entries' in data)) { |
| 1081 | toastr.warning('Valid World Info file name is required'); | 1071 | toastr.warning('Valid World Info file name is required'); |
| @@ -1089,7 +1079,7 @@ function registerWorldInfoSlashCommands() { | |||
| 1089 | return ''; | 1079 | return ''; |
| 1090 | } | 1080 | } |
| 1091 | 1081 | ||
| 1092 | if (newEntryTemplate[field] === undefined) { | 1082 | if (newWorldInfoEntryTemplate[field] === undefined) { |
| 1093 | toastr.warning('Valid field name is required'); | 1083 | toastr.warning('Valid field name is required'); |
| 1094 | return ''; | 1084 | return ''; |
| 1095 | } | 1085 | } |
| @@ -1104,8 +1094,8 @@ function registerWorldInfoSlashCommands() { | |||
| 1104 | entry[field] = value; | 1094 | entry[field] = value; |
| 1105 | } | 1095 | } |
| 1106 | 1096 | ||
| 1107 | if (originalDataKeyMap[field]) { | 1097 | if (originalWIDataKeyMap[field]) { |
| 1108 | setOriginalDataValue(data, uid, originalDataKeyMap[field], entry[field]); | 1098 | setWIOriginalDataValue(data, uid, originalWIDataKeyMap[field], entry[field]); |
| 1109 | } | 1099 | } |
| 1110 | 1100 | ||
| 1111 | await saveWorldInfo(file, data); | 1101 | await saveWorldInfo(file, data); |
| @@ -1226,7 +1216,7 @@ function registerWorldInfoSlashCommands() { | |||
| 1226 | /** A collection of local enum providers for this context of world info */ | 1216 | /** A collection of local enum providers for this context of world info */ |
| 1227 | const localEnumProviders = { | 1217 | const localEnumProviders = { |
| 1228 | /** All possible fields that can be set in a WI entry */ | 1218 | /** All possible fields that can be set in a WI entry */ |
| 1229 | wiEntryFields: () => Object.entries(newEntryDefinition).map(([key, value]) => | 1219 | wiEntryFields: () => Object.entries(newWorldInfoEntryDefinition).map(([key, value]) => |
| 1230 | new SlashCommandEnumValue(key, `[${value.type}] default: ${(typeof value.default === 'string' ? `'${value.default}'` : value.default)}`, | 1220 | new SlashCommandEnumValue(key, `[${value.type}] default: ${(typeof value.default === 'string' ? `'${value.default}'` : value.default)}`, |
| 1231 | enumTypes.enum, enumIcons.getDataTypeIcon(value.type))), | 1221 | enumTypes.enum, enumIcons.getDataTypeIcon(value.type))), |
| 1232 | 1222 | ||
| @@ -1566,18 +1556,32 @@ function registerWorldInfoSlashCommands() { | |||
| 1566 | })); | 1556 | })); |
| 1567 | } | 1557 | } |
| 1568 | 1558 | ||
| 1569 | // World Info Editor | 1559 | |
| 1570 | async function showWorldEditor(name) { | 1560 | /** |
| 1561 | * Loads the given world into the World Editor. | ||
| 1562 | * | ||
| 1563 | * @param {string} name - The name of the world | ||
| 1564 | * @return {Promise<void>} A promise that resolves when the world editor is loaded | ||
| 1565 | */ | ||
| 1566 | export async function showWorldEditor(name) { | ||
| 1571 | if (!name) { | 1567 | if (!name) { |
| 1572 | hideWorldEditor(); | 1568 | hideWorldEditor(); |
| 1573 | return; | 1569 | return; |
| 1574 | } | 1570 | } |
| 1575 | 1571 | ||
| 1576 | const wiData = await loadWorldInfoData(name); | 1572 | const wiData = await loadWorldInfo(name); |
| 1577 | displayWorldEntries(name, wiData); | 1573 | displayWorldEntries(name, wiData); |
| 1578 | } | 1574 | } |
| 1579 | 1575 | ||
| 1580 | async function loadWorldInfoData(name) { | 1576 | /** |
| 1577 | * Loads world info from the backend. | ||
| 1578 | * | ||
| 1579 | * This function will return from `worldInfoCache` if it has already been loaded before. | ||
| 1580 | * | ||
| 1581 | * @param {string} name - The name of the world to load | ||
| 1582 | * @return {Promise<Object|null>} A promise that resolves to the loaded world information, or null if the request fails. | ||
| 1583 | */ | ||
| 1584 | export async function loadWorldInfo(name) { | ||
| 1581 | if (!name) { | 1585 | if (!name) { |
| 1582 | return; | 1586 | return; |
| 1583 | } | 1587 | } |
| @@ -1635,14 +1639,18 @@ function getWIElement(name) { | |||
| 1635 | } | 1639 | } |
| 1636 | 1640 | ||
| 1637 | /** | 1641 | /** |
| 1642 | * Sorts the given data based on the selected sort option | ||
| 1643 | * | ||
| 1638 | * @param {any[]} data WI entries | 1644 | * @param {any[]} data WI entries |
| 1645 | * @param {object} [options={}] - Optional arguments | ||
| 1646 | * @param {{sortField?: string, sortOrder?: string, sortRule?: string}} [options.customSort={}] - Custom sort options, instead of the chosen UI sort | ||
| 1639 | * @returns {any[]} Sorted data | 1647 | * @returns {any[]} Sorted data |
| 1640 | */ | 1648 | */ |
| 1641 | function sortEntries(data) { | 1649 | export function sortWorldInfoEntries(data, { customSort = null } = {}) { |
| 1642 | const option = $('#world_info_sort_order').find(':selected'); | 1650 | const option = $('#world_info_sort_order').find(':selected'); |
| 1643 | const sortField = option.data('field'); | 1651 | const sortField = customSort?.sortField ?? option.data('field'); |
| 1644 | const sortOrder = option.data('order'); | 1652 | const sortOrder = customSort?.sortOrder ?? option.data('order'); |
| 1645 | const sortRule = option.data('rule'); | 1653 | const sortRule = customSort?.sortRule ?? option.data('rule'); |
| 1646 | const orderSign = sortOrder === 'asc' ? 1 : -1; | 1654 | const orderSign = sortOrder === 'asc' ? 1 : -1; |
| 1647 | 1655 | ||
| 1648 | if (!data.length) return data; | 1656 | if (!data.length) return data; |
| @@ -1801,7 +1809,7 @@ function displayWorldEntries(name, data, navigation = navigation_option.none, fl | |||
| 1801 | 1809 | ||
| 1802 | // Apply the filter and do the chosen sorting | 1810 | // Apply the filter and do the chosen sorting |
| 1803 | entriesArray = worldInfoFilter.applyFilters(entriesArray); | 1811 | entriesArray = worldInfoFilter.applyFilters(entriesArray); |
| 1804 | entriesArray = sortEntries(entriesArray); | 1812 | entriesArray = sortWorldInfoEntries(entriesArray); |
| 1805 | 1813 | ||
| 1806 | // Cache keys | 1814 | // Cache keys |
| 1807 | const keys = entriesArray.flatMap(entry => [...entry.key, ...entry.keysecondary]); | 1815 | const keys = entriesArray.flatMap(entry => [...entry.key, ...entry.keysecondary]); |
| @@ -1919,7 +1927,7 @@ function displayWorldEntries(name, data, navigation = navigation_option.none, fl | |||
| 1919 | for (const entry of Object.values(data.entries)) { | 1927 | for (const entry of Object.values(data.entries)) { |
| 1920 | if (!entry.comment && Array.isArray(entry.key) && entry.key.length > 0) { | 1928 | if (!entry.comment && Array.isArray(entry.key) && entry.key.length > 0) { |
| 1921 | entry.comment = entry.key[0]; | 1929 | entry.comment = entry.key[0]; |
| 1922 | setOriginalDataValue(data, entry.uid, 'comment', entry.comment); | 1930 | setWIOriginalDataValue(data, entry.uid, 'comment', entry.comment); |
| 1923 | counter++; | 1931 | counter++; |
| 1924 | } | 1932 | } |
| 1925 | } | 1933 | } |
| @@ -1954,7 +1962,7 @@ function displayWorldEntries(name, data, navigation = navigation_option.none, fl | |||
| 1954 | 1962 | ||
| 1955 | // We need to sort the entries here, as the data source isn't sorted | 1963 | // We need to sort the entries here, as the data source isn't sorted |
| 1956 | const entries = Object.values(data.entries); | 1964 | const entries = Object.values(data.entries); |
| 1957 | sortEntries(entries); | 1965 | sortWorldInfoEntries(entries); |
| 1958 | 1966 | ||
| 1959 | let updated = 0, current = start; | 1967 | let updated = 0, current = start; |
| 1960 | for (const entry of entries) { | 1968 | for (const entry of entries) { |
| @@ -1962,7 +1970,7 @@ function displayWorldEntries(name, data, navigation = navigation_option.none, fl | |||
| 1962 | if (entry.order === newOrder) continue; | 1970 | if (entry.order === newOrder) continue; |
| 1963 | 1971 | ||
| 1964 | entry.order = newOrder; | 1972 | entry.order = newOrder; |
| 1965 | setOriginalDataValue(data, entry.order, 'order', entry.order); | 1973 | setWIOriginalDataValue(data, entry.order, 'order', entry.order); |
| 1966 | updated++; | 1974 | updated++; |
| 1967 | } | 1975 | } |
| 1968 | 1976 | ||
| @@ -2025,7 +2033,7 @@ function displayWorldEntries(name, data, navigation = navigation_option.none, fl | |||
| 2025 | } | 2033 | } |
| 2026 | 2034 | ||
| 2027 | item.displayIndex = minDisplayIndex + index; | 2035 | item.displayIndex = minDisplayIndex + index; |
| 2028 | setOriginalDataValue(data, uid, 'extensions.display_index', item.displayIndex); | 2036 | setWIOriginalDataValue(data, uid, 'extensions.display_index', item.displayIndex); |
| 2029 | }); | 2037 | }); |
| 2030 | 2038 | ||
| 2031 | console.table(Object.keys(data.entries).map(uid => data.entries[uid]).map(x => ({ uid: x.uid, key: x.key.join(','), displayIndex: x.displayIndex }))); | 2039 | console.table(Object.keys(data.entries).map(uid => data.entries[uid]).map(x => ({ uid: x.uid, key: x.key.join(','), displayIndex: x.displayIndex }))); |
| @@ -2036,7 +2044,7 @@ function displayWorldEntries(name, data, navigation = navigation_option.none, fl | |||
| 2036 | //$("#world_popup_entries_list").disableSelection(); | 2044 | //$("#world_popup_entries_list").disableSelection(); |
| 2037 | } | 2045 | } |
| 2038 | 2046 | ||
| 2039 | const originalDataKeyMap = { | 2047 | export const originalWIDataKeyMap = { |
| 2040 | 'displayIndex': 'extensions.display_index', | 2048 | 'displayIndex': 'extensions.display_index', |
| 2041 | 'excludeRecursion': 'extensions.exclude_recursion', | 2049 | 'excludeRecursion': 'extensions.exclude_recursion', |
| 2042 | 'preventRecursion': 'extensions.prevent_recursion', | 2050 | 'preventRecursion': 'extensions.prevent_recursion', |
| @@ -2087,7 +2095,17 @@ function verifyWorldInfoSearchSortRule() { | |||
| 2087 | } | 2095 | } |
| 2088 | } | 2096 | } |
| 2089 | 2097 | ||
| 2090 | function setOriginalDataValue(data, uid, key, value) { | 2098 | /** |
| 2099 | * Sets the value of a specific key in the original data entry corresponding to the given uid | ||
| 2100 | * This needs to be called whenever you update JSON data fields. | ||
| 2101 | * Use `originalWIDataKeyMap` to find the correct value to be set. | ||
| 2102 | * | ||
| 2103 | * @param {object} data - The data object containing the original data entries. | ||
| 2104 | * @param {string} uid - The unique identifier of the data entry. | ||
| 2105 | * @param {string} key - The key of the value to be set. | ||
| 2106 | * @param {any} value - The value to be set. | ||
| 2107 | */ | ||
| 2108 | export function setWIOriginalDataValue(data, uid, key, value) { | ||
| 2091 | if (data.originalData && Array.isArray(data.originalData.entries)) { | 2109 | if (data.originalData && Array.isArray(data.originalData.entries)) { |
| 2092 | let originalEntry = data.originalData.entries.find(x => x.uid === uid); | 2110 | let originalEntry = data.originalData.entries.find(x => x.uid === uid); |
| 2093 | 2111 | ||
| @@ -2099,7 +2117,13 @@ function setOriginalDataValue(data, uid, key, value) { | |||
| 2099 | } | 2117 | } |
| 2100 | } | 2118 | } |
| 2101 | 2119 | ||
| 2102 | function deleteOriginalDataValue(data, uid) { | 2120 | /** |
| 2121 | * Deletes the original data entry corresponding to the given uid from the provided data object | ||
| 2122 | * | ||
| 2123 | * @param {object} data - The data object containing the original data entries | ||
| 2124 | * @param {string} uid - The unique identifier of the data entry to be deleted | ||
| 2125 | */ | ||
| 2126 | export function deleteWIOriginalDataValue(data, uid) { | ||
| 2103 | if (data.originalData && Array.isArray(data.originalData.entries)) { | 2127 | if (data.originalData && Array.isArray(data.originalData.entries)) { |
| 2104 | const originalIndex = data.originalData.entries.findIndex(x => x.uid === uid); | 2128 | const originalIndex = data.originalData.entries.findIndex(x => x.uid === uid); |
| 2105 | 2129 | ||
| @@ -2120,7 +2144,7 @@ function deleteOriginalDataValue(data, uid) { | |||
| 2120 | * @param {string} input - One or multiple keywords or regexes, separated by commas | 2144 | * @param {string} input - One or multiple keywords or regexes, separated by commas |
| 2121 | * @returns {string[]} An array of keywords and regexes | 2145 | * @returns {string[]} An array of keywords and regexes |
| 2122 | */ | 2146 | */ |
| 2123 | function splitKeywordsAndRegexes(input) { | 2147 | export function splitKeywordsAndRegexes(input) { |
| 2124 | /** @type {string[]} */ | 2148 | /** @type {string[]} */ |
| 2125 | let keywordsAndRegexes = []; | 2149 | let keywordsAndRegexes = []; |
| 2126 | 2150 | ||
| @@ -2224,7 +2248,7 @@ function isValidRegex(input) { | |||
| 2224 | * @param {string} input - A delimited regex string | 2248 | * @param {string} input - A delimited regex string |
| 2225 | * @returns {RegExp|null} The regex object, or null if not a valid regex | 2249 | * @returns {RegExp|null} The regex object, or null if not a valid regex |
| 2226 | */ | 2250 | */ |
| 2227 | function parseRegexFromString(input) { | 2251 | export function parseRegexFromString(input) { |
| 2228 | // Extracting the regex pattern and flags | 2252 | // Extracting the regex pattern and flags |
| 2229 | let match = input.match(/^\/([\w\W]+?)\/([gimsuy]*)$/); | 2253 | let match = input.match(/^\/([\w\W]+?)\/([gimsuy]*)$/); |
| 2230 | if (!match) { | 2254 | if (!match) { |
| @@ -2310,7 +2334,7 @@ function getWorldEntry(name, data, entry) { | |||
| 2310 | !skipReset && resetScrollHeight(this); | 2334 | !skipReset && resetScrollHeight(this); |
| 2311 | if (!noSave) { | 2335 | if (!noSave) { |
| 2312 | data.entries[uid][entryPropName] = keys; | 2336 | data.entries[uid][entryPropName] = keys; |
| 2313 | setOriginalDataValue(data, uid, originalDataValueName, data.entries[uid][entryPropName]); | 2337 | setWIOriginalDataValue(data, uid, originalDataValueName, data.entries[uid][entryPropName]); |
| 2314 | await saveWorldInfo(name, data); | 2338 | await saveWorldInfo(name, data); |
| 2315 | } | 2339 | } |
| 2316 | }); | 2340 | }); |
| @@ -2348,7 +2372,7 @@ function getWorldEntry(name, data, entry) { | |||
| 2348 | !skipReset && resetScrollHeight(this); | 2372 | !skipReset && resetScrollHeight(this); |
| 2349 | if (!noSave) { | 2373 | if (!noSave) { |
| 2350 | data.entries[uid][entryPropName] = splitKeywordsAndRegexes(value); | 2374 | data.entries[uid][entryPropName] = splitKeywordsAndRegexes(value); |
| 2351 | setOriginalDataValue(data, uid, originalDataValueName, data.entries[uid][entryPropName]); | 2375 | setWIOriginalDataValue(data, uid, originalDataValueName, data.entries[uid][entryPropName]); |
| 2352 | await saveWorldInfo(name, data); | 2376 | await saveWorldInfo(name, data); |
| 2353 | } | 2377 | } |
| 2354 | }); | 2378 | }); |
| @@ -2392,7 +2416,7 @@ function getWorldEntry(name, data, entry) { | |||
| 2392 | const uid = $(this).data('uid'); | 2416 | const uid = $(this).data('uid'); |
| 2393 | const value = Number($(this).val()); | 2417 | const value = Number($(this).val()); |
| 2394 | data.entries[uid].selectiveLogic = !isNaN(value) ? value : world_info_logic.AND_ANY; | 2418 | data.entries[uid].selectiveLogic = !isNaN(value) ? value : world_info_logic.AND_ANY; |
| 2395 | setOriginalDataValue(data, uid, 'selectiveLogic', data.entries[uid].selectiveLogic); | 2419 | setWIOriginalDataValue(data, uid, 'selectiveLogic', data.entries[uid].selectiveLogic); |
| 2396 | await saveWorldInfo(name, data); | 2420 | await saveWorldInfo(name, data); |
| 2397 | }); | 2421 | }); |
| 2398 | 2422 | ||
| @@ -2441,7 +2465,7 @@ function getWorldEntry(name, data, entry) { | |||
| 2441 | } | 2465 | } |
| 2442 | } | 2466 | } |
| 2443 | 2467 | ||
| 2444 | setOriginalDataValue(data, uid, 'character_filter', data.entries[uid].characterFilter); | 2468 | setWIOriginalDataValue(data, uid, 'character_filter', data.entries[uid].characterFilter); |
| 2445 | await saveWorldInfo(name, data); | 2469 | await saveWorldInfo(name, data); |
| 2446 | }); | 2470 | }); |
| 2447 | characterExclusionInput.prop('checked', entry.characterFilter?.isExclude ?? false).trigger('input'); | 2471 | characterExclusionInput.prop('checked', entry.characterFilter?.isExclude ?? false).trigger('input'); |
| @@ -2503,7 +2527,7 @@ function getWorldEntry(name, data, entry) { | |||
| 2503 | }, | 2527 | }, |
| 2504 | ); | 2528 | ); |
| 2505 | } | 2529 | } |
| 2506 | setOriginalDataValue(data, uid, 'character_filter', data.entries[uid].characterFilter); | 2530 | setWIOriginalDataValue(data, uid, 'character_filter', data.entries[uid].characterFilter); |
| 2507 | await saveWorldInfo(name, data); | 2531 | await saveWorldInfo(name, data); |
| 2508 | }); | 2532 | }); |
| 2509 | 2533 | ||
| @@ -2517,7 +2541,7 @@ function getWorldEntry(name, data, entry) { | |||
| 2517 | !skipReset && resetScrollHeight(this); | 2541 | !skipReset && resetScrollHeight(this); |
| 2518 | data.entries[uid].comment = value; | 2542 | data.entries[uid].comment = value; |
| 2519 | 2543 | ||
| 2520 | setOriginalDataValue(data, uid, 'comment', data.entries[uid].comment); | 2544 | setWIOriginalDataValue(data, uid, 'comment', data.entries[uid].comment); |
| 2521 | await saveWorldInfo(name, data); | 2545 | await saveWorldInfo(name, data); |
| 2522 | }); | 2546 | }); |
| 2523 | commentToggle.data('uid', entry.uid); | 2547 | commentToggle.data('uid', entry.uid); |
| @@ -2552,7 +2576,7 @@ function getWorldEntry(name, data, entry) { | |||
| 2552 | const value = $(this).val(); | 2576 | const value = $(this).val(); |
| 2553 | data.entries[uid].content = value; | 2577 | data.entries[uid].content = value; |
| 2554 | 2578 | ||
| 2555 | setOriginalDataValue(data, uid, 'content', data.entries[uid].content); | 2579 | setWIOriginalDataValue(data, uid, 'content', data.entries[uid].content); |
| 2556 | await saveWorldInfo(name, data); | 2580 | await saveWorldInfo(name, data); |
| 2557 | 2581 | ||
| 2558 | if (skipCount) { | 2582 | if (skipCount) { |
| @@ -2582,7 +2606,7 @@ function getWorldEntry(name, data, entry) { | |||
| 2582 | const value = $(this).prop('checked'); | 2606 | const value = $(this).prop('checked'); |
| 2583 | data.entries[uid].selective = value; | 2607 | data.entries[uid].selective = value; |
| 2584 | 2608 | ||
| 2585 | setOriginalDataValue(data, uid, 'selective', data.entries[uid].selective); | 2609 | setWIOriginalDataValue(data, uid, 'selective', data.entries[uid].selective); |
| 2586 | await saveWorldInfo(name, data); | 2610 | await saveWorldInfo(name, data); |
| 2587 | 2611 | ||
| 2588 | const keysecondary = $(this) | 2612 | const keysecondary = $(this) |
| @@ -2631,7 +2655,7 @@ function getWorldEntry(name, data, entry) { | |||
| 2631 | 2655 | ||
| 2632 | data.entries[uid].order = !isNaN(value) ? value : 0; | 2656 | data.entries[uid].order = !isNaN(value) ? value : 0; |
| 2633 | updatePosOrdDisplay(uid); | 2657 | updatePosOrdDisplay(uid); |
| 2634 | setOriginalDataValue(data, uid, 'insertion_order', data.entries[uid].order); | 2658 | setWIOriginalDataValue(data, uid, 'insertion_order', data.entries[uid].order); |
| 2635 | await saveWorldInfo(name, data); | 2659 | await saveWorldInfo(name, data); |
| 2636 | }); | 2660 | }); |
| 2637 | orderInput.val(entry.order).trigger('input'); | 2661 | orderInput.val(entry.order).trigger('input'); |
| @@ -2645,7 +2669,7 @@ function getWorldEntry(name, data, entry) { | |||
| 2645 | const value = String($(this).val()).trim(); | 2669 | const value = String($(this).val()).trim(); |
| 2646 | 2670 | ||
| 2647 | data.entries[uid].group = value; | 2671 | data.entries[uid].group = value; |
| 2648 | setOriginalDataValue(data, uid, 'extensions.group', data.entries[uid].group); | 2672 | setWIOriginalDataValue(data, uid, 'extensions.group', data.entries[uid].group); |
| 2649 | await saveWorldInfo(name, data); | 2673 | await saveWorldInfo(name, data); |
| 2650 | }); | 2674 | }); |
| 2651 | groupInput.val(entry.group ?? '').trigger('input'); | 2675 | groupInput.val(entry.group ?? '').trigger('input'); |
| @@ -2658,7 +2682,7 @@ function getWorldEntry(name, data, entry) { | |||
| 2658 | const uid = $(this).data('uid'); | 2682 | const uid = $(this).data('uid'); |
| 2659 | const value = $(this).prop('checked'); | 2683 | const value = $(this).prop('checked'); |
| 2660 | data.entries[uid].groupOverride = value; | 2684 | data.entries[uid].groupOverride = value; |
| 2661 | setOriginalDataValue(data, uid, 'extensions.group_override', data.entries[uid].groupOverride); | 2685 | setWIOriginalDataValue(data, uid, 'extensions.group_override', data.entries[uid].groupOverride); |
| 2662 | await saveWorldInfo(name, data); | 2686 | await saveWorldInfo(name, data); |
| 2663 | }); | 2687 | }); |
| 2664 | groupOverrideInput.prop('checked', entry.groupOverride).trigger('input'); | 2688 | groupOverrideInput.prop('checked', entry.groupOverride).trigger('input'); |
| @@ -2682,7 +2706,7 @@ function getWorldEntry(name, data, entry) { | |||
| 2682 | } | 2706 | } |
| 2683 | 2707 | ||
| 2684 | data.entries[uid].groupWeight = !isNaN(value) ? Math.abs(value) : 1; | 2708 | data.entries[uid].groupWeight = !isNaN(value) ? Math.abs(value) : 1; |
| 2685 | setOriginalDataValue(data, uid, 'extensions.group_weight', data.entries[uid].groupWeight); | 2709 | setWIOriginalDataValue(data, uid, 'extensions.group_weight', data.entries[uid].groupWeight); |
| 2686 | await saveWorldInfo(name, data); | 2710 | await saveWorldInfo(name, data); |
| 2687 | }); | 2711 | }); |
| 2688 | groupWeightInput.val(entry.groupWeight ?? DEFAULT_WEIGHT).trigger('input'); | 2712 | groupWeightInput.val(entry.groupWeight ?? DEFAULT_WEIGHT).trigger('input'); |
| @@ -2695,7 +2719,7 @@ function getWorldEntry(name, data, entry) { | |||
| 2695 | const value = Number($(this).val()); | 2719 | const value = Number($(this).val()); |
| 2696 | data.entries[uid].sticky = !isNaN(value) ? value : null; | 2720 | data.entries[uid].sticky = !isNaN(value) ? value : null; |
| 2697 | 2721 | ||
| 2698 | setOriginalDataValue(data, uid, 'extensions.sticky', data.entries[uid].sticky); | 2722 | setWIOriginalDataValue(data, uid, 'extensions.sticky', data.entries[uid].sticky); |
| 2699 | await saveWorldInfo(name, data); | 2723 | await saveWorldInfo(name, data); |
| 2700 | }); | 2724 | }); |
| 2701 | sticky.val(entry.sticky > 0 ? entry.sticky : '').trigger('input'); | 2725 | sticky.val(entry.sticky > 0 ? entry.sticky : '').trigger('input'); |
| @@ -2708,7 +2732,7 @@ function getWorldEntry(name, data, entry) { | |||
| 2708 | const value = Number($(this).val()); | 2732 | const value = Number($(this).val()); |
| 2709 | data.entries[uid].cooldown = !isNaN(value) ? value : null; | 2733 | data.entries[uid].cooldown = !isNaN(value) ? value : null; |
| 2710 | 2734 | ||
| 2711 | setOriginalDataValue(data, uid, 'extensions.cooldown', data.entries[uid].cooldown); | 2735 | setWIOriginalDataValue(data, uid, 'extensions.cooldown', data.entries[uid].cooldown); |
| 2712 | await saveWorldInfo(name, data); | 2736 | await saveWorldInfo(name, data); |
| 2713 | }); | 2737 | }); |
| 2714 | cooldown.val(entry.cooldown > 0 ? entry.cooldown : '').trigger('input'); | 2738 | cooldown.val(entry.cooldown > 0 ? entry.cooldown : '').trigger('input'); |
| @@ -2721,7 +2745,7 @@ function getWorldEntry(name, data, entry) { | |||
| 2721 | const value = Number($(this).val()); | 2745 | const value = Number($(this).val()); |
| 2722 | data.entries[uid].delay = !isNaN(value) ? value : null; | 2746 | data.entries[uid].delay = !isNaN(value) ? value : null; |
| 2723 | 2747 | ||
| 2724 | setOriginalDataValue(data, uid, 'extensions.delay', data.entries[uid].delay); | 2748 | setWIOriginalDataValue(data, uid, 'extensions.delay', data.entries[uid].delay); |
| 2725 | await saveWorldInfo(name, data); | 2749 | await saveWorldInfo(name, data); |
| 2726 | }); | 2750 | }); |
| 2727 | delay.val(entry.delay > 0 ? entry.delay : '').trigger('input'); | 2751 | delay.val(entry.delay > 0 ? entry.delay : '').trigger('input'); |
| @@ -2741,7 +2765,7 @@ function getWorldEntry(name, data, entry) { | |||
| 2741 | 2765 | ||
| 2742 | data.entries[uid].depth = !isNaN(value) ? value : 0; | 2766 | data.entries[uid].depth = !isNaN(value) ? value : 0; |
| 2743 | updatePosOrdDisplay(uid); | 2767 | updatePosOrdDisplay(uid); |
| 2744 | setOriginalDataValue(data, uid, 'extensions.depth', data.entries[uid].depth); | 2768 | setWIOriginalDataValue(data, uid, 'extensions.depth', data.entries[uid].depth); |
| 2745 | await saveWorldInfo(name, data); | 2769 | await saveWorldInfo(name, data); |
| 2746 | }); | 2770 | }); |
| 2747 | depthInput.val(entry.depth ?? DEFAULT_DEPTH).trigger('input'); | 2771 | depthInput.val(entry.depth ?? DEFAULT_DEPTH).trigger('input'); |
| @@ -2769,7 +2793,7 @@ function getWorldEntry(name, data, entry) { | |||
| 2769 | } | 2793 | } |
| 2770 | } | 2794 | } |
| 2771 | 2795 | ||
| 2772 | setOriginalDataValue(data, uid, 'extensions.probability', data.entries[uid].probability); | 2796 | setWIOriginalDataValue(data, uid, 'extensions.probability', data.entries[uid].probability); |
| 2773 | await saveWorldInfo(name, data); | 2797 | await saveWorldInfo(name, data); |
| 2774 | }); | 2798 | }); |
| 2775 | probabilityInput.val(entry.probability).trigger('input'); | 2799 | probabilityInput.val(entry.probability).trigger('input'); |
| @@ -2836,10 +2860,10 @@ function getWorldEntry(name, data, entry) { | |||
| 2836 | } | 2860 | } |
| 2837 | updatePosOrdDisplay(uid); | 2861 | updatePosOrdDisplay(uid); |
| 2838 | // Spec v2 only supports before_char and after_char | 2862 | // Spec v2 only supports before_char and after_char |
| 2839 | setOriginalDataValue(data, uid, 'position', data.entries[uid].position == 0 ? 'before_char' : 'after_char'); | 2863 | setWIOriginalDataValue(data, uid, 'position', data.entries[uid].position == 0 ? 'before_char' : 'after_char'); |
| 2840 | // Write the original value as extensions field | 2864 | // Write the original value as extensions field |
| 2841 | setOriginalDataValue(data, uid, 'extensions.position', data.entries[uid].position); | 2865 | setWIOriginalDataValue(data, uid, 'extensions.position', data.entries[uid].position); |
| 2842 | setOriginalDataValue(data, uid, 'extensions.role', data.entries[uid].role); | 2866 | setWIOriginalDataValue(data, uid, 'extensions.role', data.entries[uid].role); |
| 2843 | await saveWorldInfo(name, data); | 2867 | await saveWorldInfo(name, data); |
| 2844 | }); | 2868 | }); |
| 2845 | 2869 | ||
| @@ -2881,36 +2905,36 @@ function getWorldEntry(name, data, entry) { | |||
| 2881 | data.entries[uid].constant = true; | 2905 | data.entries[uid].constant = true; |
| 2882 | data.entries[uid].disable = false; | 2906 | data.entries[uid].disable = false; |
| 2883 | data.entries[uid].vectorized = false; | 2907 | data.entries[uid].vectorized = false; |
| 2884 | setOriginalDataValue(data, uid, 'enabled', true); | 2908 | setWIOriginalDataValue(data, uid, 'enabled', true); |
| 2885 | setOriginalDataValue(data, uid, 'constant', true); | 2909 | setWIOriginalDataValue(data, uid, 'constant', true); |
| 2886 | setOriginalDataValue(data, uid, 'extensions.vectorized', false); | 2910 | setWIOriginalDataValue(data, uid, 'extensions.vectorized', false); |
| 2887 | template.removeClass('disabledWIEntry'); | 2911 | template.removeClass('disabledWIEntry'); |
| 2888 | break; | 2912 | break; |
| 2889 | case 'normal': | 2913 | case 'normal': |
| 2890 | data.entries[uid].constant = false; | 2914 | data.entries[uid].constant = false; |
| 2891 | data.entries[uid].disable = false; | 2915 | data.entries[uid].disable = false; |
| 2892 | data.entries[uid].vectorized = false; | 2916 | data.entries[uid].vectorized = false; |
| 2893 | setOriginalDataValue(data, uid, 'enabled', true); | 2917 | setWIOriginalDataValue(data, uid, 'enabled', true); |
| 2894 | setOriginalDataValue(data, uid, 'constant', false); | 2918 | setWIOriginalDataValue(data, uid, 'constant', false); |
| 2895 | setOriginalDataValue(data, uid, 'extensions.vectorized', false); | 2919 | setWIOriginalDataValue(data, uid, 'extensions.vectorized', false); |
| 2896 | template.removeClass('disabledWIEntry'); | 2920 | template.removeClass('disabledWIEntry'); |
| 2897 | break; | 2921 | break; |
| 2898 | case 'vectorized': | 2922 | case 'vectorized': |
| 2899 | data.entries[uid].constant = false; | 2923 | data.entries[uid].constant = false; |
| 2900 | data.entries[uid].disable = false; | 2924 | data.entries[uid].disable = false; |
| 2901 | data.entries[uid].vectorized = true; | 2925 | data.entries[uid].vectorized = true; |
| 2902 | setOriginalDataValue(data, uid, 'enabled', true); | 2926 | setWIOriginalDataValue(data, uid, 'enabled', true); |
| 2903 | setOriginalDataValue(data, uid, 'constant', false); | 2927 | setWIOriginalDataValue(data, uid, 'constant', false); |
| 2904 | setOriginalDataValue(data, uid, 'extensions.vectorized', true); | 2928 | setWIOriginalDataValue(data, uid, 'extensions.vectorized', true); |
| 2905 | template.removeClass('disabledWIEntry'); | 2929 | template.removeClass('disabledWIEntry'); |
| 2906 | break; | 2930 | break; |
| 2907 | case 'disabled': | 2931 | case 'disabled': |
| 2908 | data.entries[uid].constant = false; | 2932 | data.entries[uid].constant = false; |
| 2909 | data.entries[uid].disable = true; | 2933 | data.entries[uid].disable = true; |
| 2910 | data.entries[uid].vectorized = false; | 2934 | data.entries[uid].vectorized = false; |
| 2911 | setOriginalDataValue(data, uid, 'enabled', false); | 2935 | setWIOriginalDataValue(data, uid, 'enabled', false); |
| 2912 | setOriginalDataValue(data, uid, 'constant', false); | 2936 | setWIOriginalDataValue(data, uid, 'constant', false); |
| 2913 | setOriginalDataValue(data, uid, 'extensions.vectorized', false); | 2937 | setWIOriginalDataValue(data, uid, 'extensions.vectorized', false); |
| 2914 | template.addClass('disabledWIEntry'); | 2938 | template.addClass('disabledWIEntry'); |
| 2915 | break; | 2939 | break; |
| 2916 | } | 2940 | } |
| @@ -2941,7 +2965,7 @@ function getWorldEntry(name, data, entry) { | |||
| 2941 | const uid = $(this).data('uid'); | 2965 | const uid = $(this).data('uid'); |
| 2942 | const value = $(this).prop('checked'); | 2966 | const value = $(this).prop('checked'); |
| 2943 | data.entries[uid].excludeRecursion = value; | 2967 | data.entries[uid].excludeRecursion = value; |
| 2944 | setOriginalDataValue(data, uid, 'extensions.exclude_recursion', data.entries[uid].excludeRecursion); | 2968 | setWIOriginalDataValue(data, uid, 'extensions.exclude_recursion', data.entries[uid].excludeRecursion); |
| 2945 | await saveWorldInfo(name, data); | 2969 | await saveWorldInfo(name, data); |
| 2946 | }); | 2970 | }); |
| 2947 | excludeRecursionInput.prop('checked', entry.excludeRecursion).trigger('input'); | 2971 | excludeRecursionInput.prop('checked', entry.excludeRecursion).trigger('input'); |
| @@ -2953,7 +2977,7 @@ function getWorldEntry(name, data, entry) { | |||
| 2953 | const uid = $(this).data('uid'); | 2977 | const uid = $(this).data('uid'); |
| 2954 | const value = $(this).prop('checked'); | 2978 | const value = $(this).prop('checked'); |
| 2955 | data.entries[uid].preventRecursion = value; | 2979 | data.entries[uid].preventRecursion = value; |
| 2956 | setOriginalDataValue(data, uid, 'extensions.prevent_recursion', data.entries[uid].preventRecursion); | 2980 | setWIOriginalDataValue(data, uid, 'extensions.prevent_recursion', data.entries[uid].preventRecursion); |
| 2957 | await saveWorldInfo(name, data); | 2981 | await saveWorldInfo(name, data); |
| 2958 | }); | 2982 | }); |
| 2959 | preventRecursionInput.prop('checked', entry.preventRecursion).trigger('input'); | 2983 | preventRecursionInput.prop('checked', entry.preventRecursion).trigger('input'); |
| @@ -2965,7 +2989,7 @@ function getWorldEntry(name, data, entry) { | |||
| 2965 | const uid = $(this).data('uid'); | 2989 | const uid = $(this).data('uid'); |
| 2966 | const value = $(this).prop('checked'); | 2990 | const value = $(this).prop('checked'); |
| 2967 | data.entries[uid].delayUntilRecursion = value; | 2991 | data.entries[uid].delayUntilRecursion = value; |
| 2968 | setOriginalDataValue(data, uid, 'extensions.delay_until_recursion', data.entries[uid].delayUntilRecursion); | 2992 | setWIOriginalDataValue(data, uid, 'extensions.delay_until_recursion', data.entries[uid].delayUntilRecursion); |
| 2969 | await saveWorldInfo(name, data); | 2993 | await saveWorldInfo(name, data); |
| 2970 | }); | 2994 | }); |
| 2971 | delayUntilRecursionInput.prop('checked', entry.delayUntilRecursion).trigger('input'); | 2995 | delayUntilRecursionInput.prop('checked', entry.delayUntilRecursion).trigger('input'); |
| @@ -2985,10 +3009,12 @@ function getWorldEntry(name, data, entry) { | |||
| 2985 | // delete button | 3009 | // delete button |
| 2986 | const deleteButton = template.find('.delete_entry_button'); | 3010 | const deleteButton = template.find('.delete_entry_button'); |
| 2987 | deleteButton.data('uid', entry.uid); | 3011 | deleteButton.data('uid', entry.uid); |
| 2988 | deleteButton.on('click', async function () { | 3012 | deleteButton.on('click', async function (e) { |
| 3013 | e.stopPropagation(); | ||
| 2989 | const uid = $(this).data('uid'); | 3014 | const uid = $(this).data('uid'); |
| 2990 | deleteWorldInfoEntry(data, uid); | 3015 | const deleted = await deleteWorldInfoEntry(data, uid); |
| 2991 | deleteOriginalDataValue(data, uid); | 3016 | if (!deleted) return; |
| 3017 | deleteWIOriginalDataValue(data, uid); | ||
| 2992 | await saveWorldInfo(name, data); | 3018 | await saveWorldInfo(name, data); |
| 2993 | updateEditor(navigation_option.previous); | 3019 | updateEditor(navigation_option.previous); |
| 2994 | }); | 3020 | }); |
| @@ -3015,7 +3041,7 @@ function getWorldEntry(name, data, entry) { | |||
| 3015 | } | 3041 | } |
| 3016 | 3042 | ||
| 3017 | data.entries[uid].scanDepth = !isEmpty && !isNaN(value) && value >= 0 && value <= MAX_SCAN_DEPTH ? Math.floor(value) : null; | 3043 | data.entries[uid].scanDepth = !isEmpty && !isNaN(value) && value >= 0 && value <= MAX_SCAN_DEPTH ? Math.floor(value) : null; |
| 3018 | setOriginalDataValue(data, uid, 'extensions.scan_depth', data.entries[uid].scanDepth); | 3044 | setWIOriginalDataValue(data, uid, 'extensions.scan_depth', data.entries[uid].scanDepth); |
| 3019 | await saveWorldInfo(name, data); | 3045 | await saveWorldInfo(name, data); |
| 3020 | }); | 3046 | }); |
| 3021 | scanDepthInput.val(entry.scanDepth ?? null).trigger('input'); | 3047 | scanDepthInput.val(entry.scanDepth ?? null).trigger('input'); |
| @@ -3028,7 +3054,7 @@ function getWorldEntry(name, data, entry) { | |||
| 3028 | const value = $(this).val(); | 3054 | const value = $(this).val(); |
| 3029 | 3055 | ||
| 3030 | data.entries[uid].caseSensitive = value === 'null' ? null : value === 'true'; | 3056 | data.entries[uid].caseSensitive = value === 'null' ? null : value === 'true'; |
| 3031 | setOriginalDataValue(data, uid, 'extensions.case_sensitive', data.entries[uid].caseSensitive); | 3057 | setWIOriginalDataValue(data, uid, 'extensions.case_sensitive', data.entries[uid].caseSensitive); |
| 3032 | await saveWorldInfo(name, data); | 3058 | await saveWorldInfo(name, data); |
| 3033 | }); | 3059 | }); |
| 3034 | caseSensitiveSelect.val((entry.caseSensitive === null || entry.caseSensitive === undefined) ? 'null' : entry.caseSensitive ? 'true' : 'false').trigger('input'); | 3060 | caseSensitiveSelect.val((entry.caseSensitive === null || entry.caseSensitive === undefined) ? 'null' : entry.caseSensitive ? 'true' : 'false').trigger('input'); |
| @@ -3041,7 +3067,7 @@ function getWorldEntry(name, data, entry) { | |||
| 3041 | const value = $(this).val(); | 3067 | const value = $(this).val(); |
| 3042 | 3068 | ||
| 3043 | data.entries[uid].matchWholeWords = value === 'null' ? null : value === 'true'; | 3069 | data.entries[uid].matchWholeWords = value === 'null' ? null : value === 'true'; |
| 3044 | setOriginalDataValue(data, uid, 'extensions.match_whole_words', data.entries[uid].matchWholeWords); | 3070 | setWIOriginalDataValue(data, uid, 'extensions.match_whole_words', data.entries[uid].matchWholeWords); |
| 3045 | await saveWorldInfo(name, data); | 3071 | await saveWorldInfo(name, data); |
| 3046 | }); | 3072 | }); |
| 3047 | matchWholeWordsSelect.val((entry.matchWholeWords === null || entry.matchWholeWords === undefined) ? 'null' : entry.matchWholeWords ? 'true' : 'false').trigger('input'); | 3073 | matchWholeWordsSelect.val((entry.matchWholeWords === null || entry.matchWholeWords === undefined) ? 'null' : entry.matchWholeWords ? 'true' : 'false').trigger('input'); |
| @@ -3054,7 +3080,7 @@ function getWorldEntry(name, data, entry) { | |||
| 3054 | const value = $(this).val(); | 3080 | const value = $(this).val(); |
| 3055 | 3081 | ||
| 3056 | data.entries[uid].useGroupScoring = value === 'null' ? null : value === 'true'; | 3082 | data.entries[uid].useGroupScoring = value === 'null' ? null : value === 'true'; |
| 3057 | setOriginalDataValue(data, uid, 'extensions.use_group_scoring', data.entries[uid].useGroupScoring); | 3083 | setWIOriginalDataValue(data, uid, 'extensions.use_group_scoring', data.entries[uid].useGroupScoring); |
| 3058 | await saveWorldInfo(name, data); | 3084 | await saveWorldInfo(name, data); |
| 3059 | }); | 3085 | }); |
| 3060 | useGroupScoringSelect.val((entry.useGroupScoring === null || entry.useGroupScoring === undefined) ? 'null' : entry.useGroupScoring ? 'true' : 'false').trigger('input'); | 3086 | useGroupScoringSelect.val((entry.useGroupScoring === null || entry.useGroupScoring === undefined) ? 'null' : entry.useGroupScoring ? 'true' : 'false').trigger('input'); |
| @@ -3067,7 +3093,7 @@ function getWorldEntry(name, data, entry) { | |||
| 3067 | const value = $(this).val(); | 3093 | const value = $(this).val(); |
| 3068 | 3094 | ||
| 3069 | data.entries[uid].automationId = value; | 3095 | data.entries[uid].automationId = value; |
| 3070 | setOriginalDataValue(data, uid, 'extensions.automation_id', data.entries[uid].automationId); | 3096 | setWIOriginalDataValue(data, uid, 'extensions.automation_id', data.entries[uid].automationId); |
| 3071 | await saveWorldInfo(name, data); | 3097 | await saveWorldInfo(name, data); |
| 3072 | }); | 3098 | }); |
| 3073 | automationIdInput.val(entry.automationId ?? '').trigger('input'); | 3099 | automationIdInput.val(entry.automationId ?? '').trigger('input'); |
| @@ -3200,12 +3226,12 @@ function createEntryInputAutocomplete(input, callback, { allowMultiple = false } | |||
| 3200 | 3226 | ||
| 3201 | 3227 | ||
| 3202 | /** | 3228 | /** |
| 3203 | * Duplicated a WI entry by copying all of its properties and assigning a new uid | 3229 | * Duplicate a WI entry by copying all of its properties and assigning a new uid |
| 3204 | * @param {*} data - The data of the book | 3230 | * @param {*} data - The data of the book |
| 3205 | * @param {number} uid - The uid of the entry to copy in this book | 3231 | * @param {number} uid - The uid of the entry to copy in this book |
| 3206 | * @returns {*} The new WI duplicated entry | 3232 | * @returns {*} The new WI duplicated entry |
| 3207 | */ | 3233 | */ |
| 3208 | function duplicateWorldInfoEntry(data, uid) { | 3234 | export function duplicateWorldInfoEntry(data, uid) { |
| 3209 | if (!data || !('entries' in data) || !data.entries[uid]) { | 3235 | if (!data || !('entries' in data) || !data.entries[uid]) { |
| 3210 | return; | 3236 | return; |
| 3211 | } | 3237 | } |
| @@ -3225,17 +3251,22 @@ function duplicateWorldInfoEntry(data, uid) { | |||
| 3225 | * Deletes a WI entry, with a user confirmation dialog | 3251 | * Deletes a WI entry, with a user confirmation dialog |
| 3226 | * @param {*[]} data - The data of the book | 3252 | * @param {*[]} data - The data of the book |
| 3227 | * @param {number} uid - The uid of the entry to copy in this book | 3253 | * @param {number} uid - The uid of the entry to copy in this book |
| 3254 | * @param {object} [options={}] - Optional arguments | ||
| 3255 | * @param {boolean} [options.silent=false] - Whether to prompt the user for deletion or just do it | ||
| 3256 | * @returns {Promise<boolean>} Whether the entry deletion was successful | ||
| 3228 | */ | 3257 | */ |
| 3229 | function deleteWorldInfoEntry(data, uid) { | 3258 | export async function deleteWorldInfoEntry(data, uid, { silent = false } = {}) { |
| 3230 | if (!data || !('entries' in data)) { | 3259 | if (!data || !('entries' in data)) { |
| 3231 | return; | 3260 | return; |
| 3232 | } | 3261 | } |
| 3233 | 3262 | ||
| 3234 | if (!confirm(`Delete the entry with UID: ${uid}? This action is irreversible!`)) { | 3263 | const confirmation = silent || await Popup.show.confirm(`Delete the entry with UID: ${uid}?`, 'This action is irreversible!'); |
| 3235 | throw new Error('User cancelled deletion'); | 3264 | if (!confirmation) { |
| 3265 | return false; | ||
| 3236 | } | 3266 | } |
| 3237 | 3267 | ||
| 3238 | delete data.entries[uid]; | 3268 | delete data.entries[uid]; |
| 3269 | return true; | ||
| 3239 | } | 3270 | } |
| 3240 | 3271 | ||
| 3241 | /** | 3272 | /** |
| @@ -3245,7 +3276,7 @@ function deleteWorldInfoEntry(data, uid) { | |||
| 3245 | * | 3276 | * |
| 3246 | * @type {{[key: string]: { default: any, type: string }}} | 3277 | * @type {{[key: string]: { default: any, type: string }}} |
| 3247 | */ | 3278 | */ |
| 3248 | const newEntryDefinition = { | 3279 | export const newWorldInfoEntryDefinition = { |
| 3249 | key: { default: [], type: 'array' }, | 3280 | key: { default: [], type: 'array' }, |
| 3250 | keysecondary: { default: [], type: 'array' }, | 3281 | keysecondary: { default: [], type: 'array' }, |
| 3251 | comment: { default: '', type: 'string' }, | 3282 | comment: { default: '', type: 'string' }, |
| @@ -3278,8 +3309,8 @@ const newEntryDefinition = { | |||
| 3278 | delay: { default: null, type: 'number?' }, | 3309 | delay: { default: null, type: 'number?' }, |
| 3279 | }; | 3310 | }; |
| 3280 | 3311 | ||
| 3281 | const newEntryTemplate = Object.fromEntries( | 3312 | export const newWorldInfoEntryTemplate = Object.fromEntries( |
| 3282 | Object.entries(newEntryDefinition).map(([key, value]) => [key, value.default]), | 3313 | Object.entries(newWorldInfoEntryDefinition).map(([key, value]) => [key, value.default]), |
| 3283 | ); | 3314 | ); |
| 3284 | 3315 | ||
| 3285 | /** | 3316 | /** |
| @@ -3288,7 +3319,7 @@ const newEntryTemplate = Object.fromEntries( | |||
| 3288 | * @param {any} data WI data | 3319 | * @param {any} data WI data |
| 3289 | * @returns {object | undefined} New entry object or undefined if failed | 3320 | * @returns {object | undefined} New entry object or undefined if failed |
| 3290 | */ | 3321 | */ |
| 3291 | function createWorldInfoEntry(_name, data) { | 3322 | export function createWorldInfoEntry(_name, data) { |
| 3292 | const newUid = getFreeWorldEntryUid(data); | 3323 | const newUid = getFreeWorldEntryUid(data); |
| 3293 | 3324 | ||
| 3294 | if (!Number.isInteger(newUid)) { | 3325 | if (!Number.isInteger(newUid)) { |
| @@ -3296,7 +3327,7 @@ function createWorldInfoEntry(_name, data) { | |||
| 3296 | return; | 3327 | return; |
| 3297 | } | 3328 | } |
| 3298 | 3329 | ||
| 3299 | const newEntry = { uid: newUid, ...structuredClone(newEntryTemplate) }; | 3330 | const newEntry = { uid: newUid, ...structuredClone(newWorldInfoEntryTemplate) }; |
| 3300 | data.entries[newUid] = newEntry; | 3331 | data.entries[newUid] = newEntry; |
| 3301 | 3332 | ||
| 3302 | return newEntry; | 3333 | return newEntry; |
| @@ -3314,7 +3345,21 @@ async function _save(name, data) { | |||
| 3314 | eventSource.emit(event_types.WORLDINFO_UPDATED, name, data); | 3345 | eventSource.emit(event_types.WORLDINFO_UPDATED, name, data); |
| 3315 | } | 3346 | } |
| 3316 | 3347 | ||
| 3317 | async function saveWorldInfo(name, data, immediately = false) { | 3348 | |
| 3349 | /** | ||
| 3350 | * Saves the world info | ||
| 3351 | * | ||
| 3352 | * This will also refresh the `worldInfoCache`. | ||
| 3353 | * Note, for performance reasons the saved cache will not make a deep clone of the data. | ||
| 3354 | * It is your responsibility to not modify the saved data object after calling this function, or there will be data inconsistencies. | ||
| 3355 | * Call `loadWorldInfoData` or query directly from cache if you need the object again. | ||
| 3356 | * | ||
| 3357 | * @param {string} name - The name of the world info | ||
| 3358 | * @param {any} data - The data to be saved | ||
| 3359 | * @param {boolean} [immediately=false] - Whether to save immediately or use debouncing | ||
| 3360 | * @return {Promise<void>} A promise that resolves when the world info is saved | ||
| 3361 | */ | ||
| 3362 | export async function saveWorldInfo(name, data, immediately = false) { | ||
| 3318 | if (!name || !data) { | 3363 | if (!name || !data) { |
| 3319 | return; | 3364 | return; |
| 3320 | } | 3365 | } |
| @@ -3371,7 +3416,7 @@ async function renameWorldInfo(name, data) { | |||
| 3371 | * @param {string} worldInfoName - The name of the world info to delete | 3416 | * @param {string} worldInfoName - The name of the world info to delete |
| 3372 | * @returns {Promise<boolean>} A promise that resolves to true if the world info was successfully deleted, false otherwise | 3417 | * @returns {Promise<boolean>} A promise that resolves to true if the world info was successfully deleted, false otherwise |
| 3373 | */ | 3418 | */ |
| 3374 | async function deleteWorldInfo(worldInfoName) { | 3419 | export async function deleteWorldInfo(worldInfoName) { |
| 3375 | if (!world_names.includes(worldInfoName)) { | 3420 | if (!world_names.includes(worldInfoName)) { |
| 3376 | return false; | 3421 | return false; |
| 3377 | } | 3422 | } |
| @@ -3406,7 +3451,7 @@ async function deleteWorldInfo(worldInfoName) { | |||
| 3406 | return true; | 3451 | return true; |
| 3407 | } | 3452 | } |
| 3408 | 3453 | ||
| 3409 | function getFreeWorldEntryUid(data) { | 3454 | export function getFreeWorldEntryUid(data) { |
| 3410 | if (!data || !('entries' in data)) { | 3455 | if (!data || !('entries' in data)) { |
| 3411 | return null; | 3456 | return null; |
| 3412 | } | 3457 | } |
| @@ -3422,7 +3467,7 @@ function getFreeWorldEntryUid(data) { | |||
| 3422 | return null; | 3467 | return null; |
| 3423 | } | 3468 | } |
| 3424 | 3469 | ||
| 3425 | function getFreeWorldName() { | 3470 | export function getFreeWorldName() { |
| 3426 | const MAX_FREE_NAME = 100_000; | 3471 | const MAX_FREE_NAME = 100_000; |
| 3427 | for (let index = 1; index < MAX_FREE_NAME; index++) { | 3472 | for (let index = 1; index < MAX_FREE_NAME; index++) { |
| 3428 | const newName = `New World (${index})`; | 3473 | const newName = `New World (${index})`; |
| @@ -3444,7 +3489,7 @@ function getFreeWorldName() { | |||
| 3444 | * @param {boolean} [options.interactive=false] - Whether to show a confirmation dialog when overwriting an existing world | 3489 | * @param {boolean} [options.interactive=false] - Whether to show a confirmation dialog when overwriting an existing world |
| 3445 | * @returns {Promise<boolean>} - True if the world info was successfully created, false otherwise | 3490 | * @returns {Promise<boolean>} - True if the world info was successfully created, false otherwise |
| 3446 | */ | 3491 | */ |
| 3447 | async function createNewWorldInfo(worldName, { interactive = false } = {}) { | 3492 | export async function createNewWorldInfo(worldName, { interactive = false } = {}) { |
| 3448 | const worldInfoTemplate = { entries: {} }; | 3493 | const worldInfoTemplate = { entries: {} }; |
| 3449 | 3494 | ||
| 3450 | if (!worldName) { | 3495 | if (!worldName) { |
| @@ -3505,7 +3550,7 @@ async function getCharacterLore() { | |||
| 3505 | continue; | 3550 | continue; |
| 3506 | } | 3551 | } |
| 3507 | 3552 | ||
| 3508 | const data = await loadWorldInfoData(worldName); | 3553 | const data = await loadWorldInfo(worldName); |
| 3509 | const newEntries = data ? Object.keys(data.entries).map((x) => data.entries[x]).map(({ uid, ...rest }) => ({ uid, world: worldName, ...rest })) : []; | 3554 | const newEntries = data ? Object.keys(data.entries).map((x) => data.entries[x]).map(({ uid, ...rest }) => ({ uid, world: worldName, ...rest })) : []; |
| 3510 | entries = entries.concat(newEntries); | 3555 | entries = entries.concat(newEntries); |
| 3511 | 3556 | ||
| @@ -3525,7 +3570,7 @@ async function getGlobalLore() { | |||
| 3525 | 3570 | ||
| 3526 | let entries = []; | 3571 | let entries = []; |
| 3527 | for (const worldName of selected_world_info) { | 3572 | for (const worldName of selected_world_info) { |
| 3528 | const data = await loadWorldInfoData(worldName); | 3573 | const data = await loadWorldInfo(worldName); |
| 3529 | const newEntries = data ? Object.keys(data.entries).map((x) => data.entries[x]).map(({ uid, ...rest }) => ({ uid, world: worldName, ...rest })) : []; | 3574 | const newEntries = data ? Object.keys(data.entries).map((x) => data.entries[x]).map(({ uid, ...rest }) => ({ uid, world: worldName, ...rest })) : []; |
| 3530 | entries = entries.concat(newEntries); | 3575 | entries = entries.concat(newEntries); |
| 3531 | } | 3576 | } |
| @@ -3547,7 +3592,7 @@ async function getChatLore() { | |||
| 3547 | return []; | 3592 | return []; |
| 3548 | } | 3593 | } |
| 3549 | 3594 | ||
| 3550 | const data = await loadWorldInfoData(chatWorld); | 3595 | const data = await loadWorldInfo(chatWorld); |
| 3551 | const entries = data ? Object.keys(data.entries).map((x) => data.entries[x]).map(({ uid, ...rest }) => ({ uid, world: chatWorld, ...rest })) : []; | 3596 | const entries = data ? Object.keys(data.entries).map((x) => data.entries[x]).map(({ uid, ...rest }) => ({ uid, world: chatWorld, ...rest })) : []; |
| 3552 | 3597 | ||
| 3553 | console.debug(`[WI] Chat lore has ${entries.length} entries`, [chatWorld]); | 3598 | console.debug(`[WI] Chat lore has ${entries.length} entries`, [chatWorld]); |
| @@ -3663,7 +3708,7 @@ function parseDecorators(content) { | |||
| 3663 | * @typedef {{ worldInfoBefore: string, worldInfoAfter: string, EMEntries: any[], WIDepthEntries: any[], allActivatedEntries: Set<any> }} WIActivated | 3708 | * @typedef {{ worldInfoBefore: string, worldInfoAfter: string, EMEntries: any[], WIDepthEntries: any[], allActivatedEntries: Set<any> }} WIActivated |
| 3664 | * @returns {Promise<WIActivated>} The world info activated. | 3709 | * @returns {Promise<WIActivated>} The world info activated. |
| 3665 | */ | 3710 | */ |
| 3666 | async function checkWorldInfo(chat, maxContext, isDryRun) { | 3711 | export async function checkWorldInfo(chat, maxContext, isDryRun) { |
| 3667 | const context = getContext(); | 3712 | const context = getContext(); |
| 3668 | const buffer = new WorldInfoBuffer(chat); | 3713 | const buffer = new WorldInfoBuffer(chat); |
| 3669 | 3714 | ||
| @@ -4233,7 +4278,7 @@ function convertAgnaiMemoryBook(inputObj) { | |||
| 4233 | 4278 | ||
| 4234 | inputObj.entries.forEach((entry, index) => { | 4279 | inputObj.entries.forEach((entry, index) => { |
| 4235 | outputObj.entries[index] = { | 4280 | outputObj.entries[index] = { |
| 4236 | ...newEntryTemplate, | 4281 | ...newWorldInfoEntryTemplate, |
| 4237 | uid: index, | 4282 | uid: index, |
| 4238 | key: entry.keywords, | 4283 | key: entry.keywords, |
| 4239 | keysecondary: [], | 4284 | keysecondary: [], |
| @@ -4275,7 +4320,7 @@ function convertRisuLorebook(inputObj) { | |||
| 4275 | 4320 | ||
| 4276 | inputObj.data.forEach((entry, index) => { | 4321 | inputObj.data.forEach((entry, index) => { |
| 4277 | outputObj.entries[index] = { | 4322 | outputObj.entries[index] = { |
| 4278 | ...newEntryTemplate, | 4323 | ...newWorldInfoEntryTemplate, |
| 4279 | uid: index, | 4324 | uid: index, |
| 4280 | key: entry.key.split(',').map(x => x.trim()), | 4325 | key: entry.key.split(',').map(x => x.trim()), |
| 4281 | keysecondary: entry.secondkey ? entry.secondkey.split(',').map(x => x.trim()) : [], | 4326 | keysecondary: entry.secondkey ? entry.secondkey.split(',').map(x => x.trim()) : [], |
| @@ -4322,7 +4367,7 @@ function convertNovelLorebook(inputObj) { | |||
| 4322 | const addMemo = displayName !== undefined && displayName.trim() !== ''; | 4367 | const addMemo = displayName !== undefined && displayName.trim() !== ''; |
| 4323 | 4368 | ||
| 4324 | outputObj.entries[index] = { | 4369 | outputObj.entries[index] = { |
| 4325 | ...newEntryTemplate, | 4370 | ...newWorldInfoEntryTemplate, |
| 4326 | uid: index, | 4371 | uid: index, |
| 4327 | key: entry.keys, | 4372 | key: entry.keys, |
| 4328 | keysecondary: [], | 4373 | keysecondary: [], |
| @@ -4369,7 +4414,7 @@ function convertCharacterBook(characterBook) { | |||
| 4369 | } | 4414 | } |
| 4370 | 4415 | ||
| 4371 | result.entries[entry.id] = { | 4416 | result.entries[entry.id] = { |
| 4372 | ...newEntryTemplate, | 4417 | ...newWorldInfoEntryTemplate, |
| 4373 | uid: entry.id, | 4418 | uid: entry.id, |
| 4374 | key: entry.keys, | 4419 | key: entry.keys, |
| 4375 | keysecondary: entry.secondary_keys || [], | 4420 | keysecondary: entry.secondary_keys || [], |
| @@ -4499,7 +4544,7 @@ export async function importEmbeddedWorldInfo(skipPopup = false) { | |||
| 4499 | setWorldInfoButtonClass(chid, true); | 4544 | setWorldInfoButtonClass(chid, true); |
| 4500 | } | 4545 | } |
| 4501 | 4546 | ||
| 4502 | function onWorldInfoChange(args, text) { | 4547 | export function onWorldInfoChange(args, text) { |
| 4503 | if (args !== '__notSlashCommand__') { // if it's a slash command | 4548 | if (args !== '__notSlashCommand__') { // if it's a slash command |
| 4504 | const silent = isTrueBoolean(args.silent); | 4549 | const silent = isTrueBoolean(args.silent); |
| 4505 | if (text.trim() !== '') { // and args are provided | 4550 | if (text.trim() !== '') { // and args are provided |
| @@ -4650,7 +4695,7 @@ export async function importWorldInfo(file) { | |||
| 4650 | }); | 4695 | }); |
| 4651 | } | 4696 | } |
| 4652 | 4697 | ||
| 4653 | function assignLorebookToChat() { | 4698 | export function assignLorebookToChat() { |
| 4654 | const selectedName = chat_metadata[METADATA_KEY]; | 4699 | const selectedName = chat_metadata[METADATA_KEY]; |
| 4655 | const template = $('#chat_world_template .chat_world').clone(); | 4700 | const template = $('#chat_world_template .chat_world').clone(); |
| 4656 | 4701 | ||