Merge branch 'staging' into parser-v2

This commit is contained in:
LenAnderson
2024-04-05 10:43:25 -04:00
49 changed files with 820 additions and 233 deletions

View File

@@ -5,6 +5,7 @@ import {
addCopyToCodeBlocks,
appendMediaToMessage,
callPopup,
characters,
chat,
eventSource,
event_types,
@@ -12,9 +13,14 @@ import {
getRequestHeaders,
hideSwipeButtons,
name2,
reloadCurrentChat,
saveChatDebounced,
saveSettingsDebounced,
showSwipeButtons,
this_chid,
} from '../script.js';
import { selected_group } from './group-chats.js';
import { power_user } from './power-user.js';
import {
extractTextFromHTML,
extractTextFromMarkdown,
@@ -416,6 +422,56 @@ export function decodeStyleTags(text) {
});
}
async function openExternalMediaOverridesDialog() {
const entityId = getCurrentEntityId();
if (!entityId) {
toastr.info('No character or group selected');
return;
}
const template = $('#forbid_media_override_template > .forbid_media_override').clone();
template.find('.forbid_media_global_state_forbidden').toggle(power_user.forbid_external_images);
template.find('.forbid_media_global_state_allowed').toggle(!power_user.forbid_external_images);
if (power_user.external_media_allowed_overrides.includes(entityId)) {
template.find('#forbid_media_override_allowed').prop('checked', true);
}
else if (power_user.external_media_forbidden_overrides.includes(entityId)) {
template.find('#forbid_media_override_forbidden').prop('checked', true);
}
else {
template.find('#forbid_media_override_global').prop('checked', true);
}
callPopup(template, 'text', '', { wide: false, large: false });
}
export function getCurrentEntityId() {
if (selected_group) {
return String(selected_group);
}
return characters[this_chid]?.avatar ?? null;
}
export function isExternalMediaAllowed() {
const entityId = getCurrentEntityId();
if (!entityId) {
return !power_user.forbid_external_images;
}
if (power_user.external_media_allowed_overrides.includes(entityId)) {
return true;
}
if (power_user.external_media_forbidden_overrides.includes(entityId)) {
return false;
}
return !power_user.forbid_external_images;
}
jQuery(function () {
$(document).on('click', '.mes_hide', async function () {
const messageBlock = $(this).closest('.mes');
@@ -511,6 +567,32 @@ jQuery(function () {
$(this).closest('.mes').find('.mes_edit').trigger('click');
});
$(document).on('click', '.open_media_overrides', openExternalMediaOverridesDialog);
$(document).on('input', '#forbid_media_override_allowed', function () {
const entityId = getCurrentEntityId();
if (!entityId) return;
power_user.external_media_allowed_overrides.push(entityId);
power_user.external_media_forbidden_overrides = power_user.external_media_forbidden_overrides.filter((v) => v !== entityId);
saveSettingsDebounced();
reloadCurrentChat();
});
$(document).on('input', '#forbid_media_override_forbidden', function () {
const entityId = getCurrentEntityId();
if (!entityId) return;
power_user.external_media_forbidden_overrides.push(entityId);
power_user.external_media_allowed_overrides = power_user.external_media_allowed_overrides.filter((v) => v !== entityId);
saveSettingsDebounced();
reloadCurrentChat();
});
$(document).on('input', '#forbid_media_override_global', function () {
const entityId = getCurrentEntityId();
if (!entityId) return;
power_user.external_media_allowed_overrides = power_user.external_media_allowed_overrides.filter((v) => v !== entityId);
power_user.external_media_forbidden_overrides = power_user.external_media_forbidden_overrides.filter((v) => v !== entityId);
saveSettingsDebounced();
reloadCurrentChat();
});
$('#file_form_input').on('change', onFileAttach);
$('#file_form').on('reset', function () {
$('#file_form').addClass('displayNone');

View File

@@ -354,15 +354,15 @@ jQuery(function () {
<div class="flex1 flex-container flexFlowColumn flexNoGap">
<label for="caption_multimodal_api">API</label>
<select id="caption_multimodal_api" class="flex1 text_pole">
<option value="llamacpp">llama.cpp</option>
<option value="ooba">Text Generation WebUI (oobabooga)</option>
<option value="anthropic">Anthropic</option>
<option value="custom">Custom (OpenAI-compatible)</option>
<option value="google">Google MakerSuite</option>
<option value="koboldcpp">KoboldCpp</option>
<option value="llamacpp">llama.cpp</option>
<option value="ollama">Ollama</option>
<option value="openai">OpenAI</option>
<option value="anthropic">Anthropic</option>
<option value="openrouter">OpenRouter</option>
<option value="google">Google MakerSuite</option>
<option value="custom">Custom (OpenAI-compatible)</option>
<option value="ooba">Text Generation WebUI (oobabooga)</option>
</select>
</div>
<div class="flex1 flex-container flexFlowColumn flexNoGap">
@@ -375,6 +375,14 @@ jQuery(function () {
<option data-type="google" value="gemini-pro-vision">gemini-pro-vision</option>
<option data-type="openrouter" value="openai/gpt-4-vision-preview">openai/gpt-4-vision-preview</option>
<option data-type="openrouter" value="haotian-liu/llava-13b">haotian-liu/llava-13b</option>
<option data-type="openrouter" value="anthropic/claude-3-haiku">anthropic/claude-3-haiku</option>
<option data-type="openrouter" value="anthropic/claude-3-sonnet">anthropic/claude-3-sonnet</option>
<option data-type="openrouter" value="anthropic/claude-3-opus">anthropic/claude-3-opus</option>
<option data-type="openrouter" value="anthropic/claude-3-haiku:beta">anthropic/claude-3-haiku:beta</option>
<option data-type="openrouter" value="anthropic/claude-3-sonnet:beta">anthropic/claude-3-sonnet:beta</option>
<option data-type="openrouter" value="anthropic/claude-3-opus:beta">anthropic/claude-3-opus:beta</option>
<option data-type="openrouter" value="nousresearch/nous-hermes-2-vision-7b">nousresearch/nous-hermes-2-vision-7b</option>
<option data-type="openrouter" value="google/gemini-pro-vision">google/gemini-pro-vision</option>
<option data-type="ollama" value="ollama_current">[Currently selected]</option>
<option data-type="ollama" value="bakllava:latest">bakllava:latest</option>
<option data-type="ollama" value="llava:latest">llava:latest</option>

View File

@@ -91,7 +91,7 @@ const defaultSettings = {
maxMessagesPerRequestMin: 0,
maxMessagesPerRequestMax: 250,
maxMessagesPerRequestStep: 1,
prompt_builder: prompt_builders.RAW_BLOCKING,
prompt_builder: prompt_builders.DEFAULT,
};
function loadSettings() {

View File

@@ -78,7 +78,7 @@
<input type="checkbox" id="qr--executeOnGroupMemberDraft">
<span><i class="fa-solid fa-fw fa-people-group"></i> Execute before group member message</span>
</label>
<div class="flex-container alignItemsBaseline" title="Activate this quick reply when a World Info entry with the same Automation ID is triggered.">
<div class="flex-container alignItemsBaseline flexFlowColumn flexNoGap" title="Activate this quick reply when a World Info entry with the same Automation ID is triggered.">
<small>Automation ID</small>
<input type="text" id="qr--automationId" class="text_pole flex1" placeholder="( None )">
</div>

View File

@@ -104,7 +104,7 @@ const loadSets = async () => {
qr.executeOnAi = slot.autoExecute_botMessage ?? false;
qr.executeOnChatChange = slot.autoExecute_chatLoad ?? false;
qr.executeOnGroupMemberDraft = slot.autoExecute_groupMemberDraft ?? false;
qr.automationId = slot.automationId ?? false;
qr.automationId = slot.automationId ?? '';
qr.contextList = (slot.contextMenu ?? []).map(it=>({
set: it.preset,
isChained: it.chain,

View File

@@ -1808,7 +1808,7 @@ function processReply(str) {
str = str.replaceAll('“', '');
str = str.replaceAll('.', ',');
str = str.replaceAll('\n', ', ');
str = str.replace(/[^a-zA-Z0-9,:()']+/g, ' '); // Replace everything except alphanumeric characters and commas with spaces
str = str.replace(/[^a-zA-Z0-9,:()\-']+/g, ' '); // Replace everything except alphanumeric characters and commas with spaces
str = str.replace(/\s+/g, ' '); // Collapse multiple whitespaces into one
str = str.trim();

View File

@@ -69,9 +69,11 @@ import {
loadItemizedPrompts,
animation_duration,
depth_prompt_role_default,
shouldAutoContinue,
} from '../script.js';
import { printTagList, createTagMapFromList, applyTagsOnCharacterSelect, tag_map } from './tags.js';
import { FILTER_TYPES, FilterHelper } from './filters.js';
import { isExternalMediaAllowed } from './chats.js';
export {
selected_group,
@@ -175,7 +177,7 @@ async function loadGroupChat(chatId) {
return [];
}
export async function getGroupChat(groupId) {
export async function getGroupChat(groupId, reload = false) {
const group = groups.find((x) => x.id === groupId);
const chat_id = group.chat_id;
const data = await loadGroupChat(chat_id);
@@ -215,6 +217,10 @@ export async function getGroupChat(groupId) {
updateChatMetadata(metadata, true);
}
if (reload) {
select_group_chats(groupId, true);
}
await eventSource.emit(event_types.CHAT_CHANGED, getCurrentChatId());
}
@@ -678,9 +684,10 @@ async function generateGroupWrapper(by_auto_mode, type = null, params = {}) {
await delay(1);
}
const group = groups.find((x) => x.id === selected_group);
let typingIndicator = $('#chat .typing_indicator');
/** @type {any} Caution: JS war crimes ahead */
let textResult = '';
let typingIndicator = $('#chat .typing_indicator');
const group = groups.find((x) => x.id === selected_group);
if (!group || !Array.isArray(group.members) || !group.members.length) {
sendSystemMessage(system_message_types.EMPTY, '', { isSmallSys: true });
@@ -778,8 +785,15 @@ async function generateGroupWrapper(by_auto_mode, type = null, params = {}) {
}
// Wait for generation to finish
const generateFinished = await Generate(generateType, { automatic_trigger: by_auto_mode, ...(params || {}) });
textResult = await generateFinished;
textResult = await Generate(generateType, { automatic_trigger: by_auto_mode, ...(params || {}) });
let messageChunk = textResult?.messageChunk;
if (messageChunk) {
while (shouldAutoContinue(messageChunk, type === 'impersonate')) {
textResult = await Generate('continue', { automatic_trigger: by_auto_mode, ...(params || {}) });
messageChunk = textResult?.messageChunk;
}
}
}
} finally {
typingIndicator.hide();
@@ -1297,6 +1311,10 @@ function select_group_chats(groupId, skipAnimation) {
$('#rm_group_delete').show();
$('#rm_group_scenario').show();
$('#group-metadata-controls .chat_lorebook_button').removeClass('disabled').prop('disabled', false);
$('#group_open_media_overrides').show();
const isMediaAllowed = isExternalMediaAllowed();
$('#group_media_allowed_icon').toggle(isMediaAllowed);
$('#group_media_forbidden_icon').toggle(!isMediaAllowed);
} else {
$('#rm_group_submit').show();
if ($('#groupAddMemberListToggle .inline-drawer-content').css('display') !== 'block') {
@@ -1305,6 +1323,7 @@ function select_group_chats(groupId, skipAnimation) {
$('#rm_group_delete').hide();
$('#rm_group_scenario').hide();
$('#group-metadata-controls .chat_lorebook_button').addClass('disabled').prop('disabled', true);
$('#group_open_media_overrides').hide();
}
updateFavButtonState(group?.fav ?? false);

View File

@@ -26,6 +26,7 @@ const controls = [
{ id: 'instruct_output_suffix', property: 'output_suffix', isCheckbox: false },
{ id: 'instruct_system_sequence', property: 'system_sequence', isCheckbox: false },
{ id: 'instruct_system_suffix', property: 'system_suffix', isCheckbox: false },
{ id: 'instruct_last_system_sequence', property: 'last_system_sequence', isCheckbox: false },
{ id: 'instruct_user_alignment_message', property: 'user_alignment_message', isCheckbox: false },
{ id: 'instruct_stop_sequence', property: 'stop_sequence', isCheckbox: false },
{ id: 'instruct_names', property: 'names', isCheckbox: true },
@@ -56,6 +57,7 @@ function migrateInstructModeSettings(settings) {
system_sequence: '',
system_suffix: '',
user_alignment_message: '',
last_system_sequence: '',
names_force_groups: true,
skip_examples: false,
system_same_as_user: false,
@@ -243,14 +245,15 @@ export function getInstructStoppingSequences() {
const result = [];
if (power_user.instruct.enabled) {
const stop_sequence = power_user.instruct.stop_sequence;
const input_sequence = power_user.instruct.input_sequence.replace(/{{name}}/gi, name1);
const output_sequence = power_user.instruct.output_sequence.replace(/{{name}}/gi, name2);
const first_output_sequence = power_user.instruct.first_output_sequence.replace(/{{name}}/gi, name2);
const last_output_sequence = power_user.instruct.last_output_sequence.replace(/{{name}}/gi, name2);
const system_sequence = power_user.instruct.system_sequence.replace(/{{name}}/gi, 'System');
const stop_sequence = power_user.instruct.stop_sequence || '';
const input_sequence = power_user.instruct.input_sequence?.replace(/{{name}}/gi, name1) || '';
const output_sequence = power_user.instruct.output_sequence?.replace(/{{name}}/gi, name2) || '';
const first_output_sequence = power_user.instruct.first_output_sequence?.replace(/{{name}}/gi, name2) || '';
const last_output_sequence = power_user.instruct.last_output_sequence?.replace(/{{name}}/gi, name2) || '';
const system_sequence = power_user.instruct.system_sequence?.replace(/{{name}}/gi, 'System') || '';
const last_system_sequence = power_user.instruct.last_system_sequence?.replace(/{{name}}/gi, 'System') || '';
const combined_sequence = `${stop_sequence}\n${input_sequence}\n${output_sequence}\n${first_output_sequence}\n${last_output_sequence}\n${system_sequence}`;
const combined_sequence = `${stop_sequence}\n${input_sequence}\n${output_sequence}\n${first_output_sequence}\n${last_output_sequence}\n${system_sequence}\n${last_system_sequence}`;
combined_sequence.split('\n').filter((line, index, self) => self.indexOf(line) === index).forEach(addInstructSequence);
}
@@ -452,9 +455,10 @@ export function formatInstructModePrompt(name, isImpersonate, promptBias, name1,
return power_user.instruct.input_sequence;
}
// Neutral / system prompt
// Neutral / system / quiet prompt
// Use a special quiet instruct sequence if defined, or assistant's output sequence otherwise
if (isQuiet && !isQuietToLoud) {
return power_user.instruct.output_sequence;
return power_user.instruct.last_system_sequence || power_user.instruct.output_sequence;
}
// Quiet in-character prompt
@@ -517,20 +521,28 @@ export function replaceInstructMacros(input) {
if (!input) {
return '';
}
const instructMacros = {
'instructSystem|instructSystemPrompt': power_user.instruct.system_prompt,
'instructSystemPromptPrefix': power_user.instruct.system_sequence_prefix,
'instructSystemPromptSuffix': power_user.instruct.system_sequence_suffix,
'instructInput|instructUserPrefix': power_user.instruct.input_sequence,
'instructUserSuffix': power_user.instruct.input_suffix,
'instructOutput|instructAssistantPrefix': power_user.instruct.output_sequence,
'instructSeparator|instructAssistantSuffix': power_user.instruct.output_suffix,
'instructSystemPrefix': power_user.instruct.system_sequence,
'instructSystemSuffix': power_user.instruct.system_suffix,
'instructFirstOutput|instructFirstAssistantPrefix': power_user.instruct.first_output_sequence || power_user.instruct.output_sequence,
'instructLastOutput|instructLastAssistantPrefix': power_user.instruct.last_output_sequence || power_user.instruct.output_sequence,
'instructStop': power_user.instruct.stop_sequence,
'instructUserFiller': power_user.instruct.user_alignment_message,
'instructSystemInstructionPrefix': power_user.instruct.last_system_sequence,
};
for (const [placeholder, value] of Object.entries(instructMacros)) {
const regex = new RegExp(`{{(${placeholder})}}`, 'gi');
input = input.replace(regex, power_user.instruct.enabled ? value : '');
}
input = input.replace(/{{(instructSystem|instructSystemPrompt)}}/gi, power_user.instruct.enabled ? power_user.instruct.system_prompt : '');
input = input.replace(/{{instructSystemPromptPrefix}}/gi, power_user.instruct.enabled ? power_user.instruct.system_sequence_prefix : '');
input = input.replace(/{{instructSystemPromptSuffix}}/gi, power_user.instruct.enabled ? power_user.instruct.system_sequence_suffix : '');
input = input.replace(/{{(instructInput|instructUserPrefix)}}/gi, power_user.instruct.enabled ? power_user.instruct.input_sequence : '');
input = input.replace(/{{instructUserSuffix}}/gi, power_user.instruct.enabled ? power_user.instruct.input_suffix : '');
input = input.replace(/{{(instructOutput|instructAssistantPrefix)}}/gi, power_user.instruct.enabled ? power_user.instruct.output_sequence : '');
input = input.replace(/{{(instructSeparator|instructAssistantSuffix)}}/gi, power_user.instruct.enabled ? power_user.instruct.output_suffix : '');
input = input.replace(/{{instructSystemPrefix}}/gi, power_user.instruct.enabled ? power_user.instruct.system_sequence : '');
input = input.replace(/{{instructSystemSuffix}}/gi, power_user.instruct.enabled ? power_user.instruct.system_suffix : '');
input = input.replace(/{{(instructFirstOutput|instructFirstAssistantPrefix)}}/gi, power_user.instruct.enabled ? (power_user.instruct.first_output_sequence || power_user.instruct.output_sequence) : '');
input = input.replace(/{{(instructLastOutput|instructLastAssistantPrefix)}}/gi, power_user.instruct.enabled ? (power_user.instruct.last_output_sequence || power_user.instruct.output_sequence) : '');
input = input.replace(/{{instructStop}}/gi, power_user.instruct.enabled ? power_user.instruct.stop_sequence : '');
input = input.replace(/{{instructUserFiller}}/gi, power_user.instruct.enabled ? power_user.instruct.user_alignment_message : '');
input = input.replace(/{{exampleSeparator}}/gi, power_user.context.example_separator);
input = input.replace(/{{chatStart}}/gi, power_user.context.chat_start);

View File

@@ -9,7 +9,7 @@ import {
import {
power_user,
} from './power-user.js';
import EventSourceStream from './sse-stream.js';
import { getEventSourceStream } from './sse-stream.js';
import { getSortableDelay } from './utils.js';
export const kai_settings = {
@@ -174,7 +174,7 @@ export async function generateKoboldWithStreaming(generate_data, signal) {
tryParseStreamingError(response, await response.text());
throw new Error(`Got response status ${response.status}`);
}
const eventStream = new EventSourceStream();
const eventStream = getEventSourceStream();
response.body.pipeThrough(eventStream);
const reader = eventStream.readable.getReader();

View File

@@ -8,6 +8,7 @@ import {
Generate,
getGeneratingApi,
is_send_press,
isStreamingEnabled,
} from '../script.js';
import { debounce, delay, getStringHash } from './utils.js';
import { decodeTextTokens, getTokenizerBestMatch } from './tokenizers.js';
@@ -64,11 +65,15 @@ function renderAlternativeTokensView() {
renderTopLogprobs();
const { messageLogprobs, continueFrom } = getActiveMessageLogprobData() || {};
if (!messageLogprobs?.length) {
const usingSmoothStreaming = isStreamingEnabled() && power_user.smooth_streaming;
if (!messageLogprobs?.length || usingSmoothStreaming) {
const emptyState = $('<div></div>');
const noTokensMsg = usingSmoothStreaming
? 'Token probabilities are not available when using Smooth Streaming.'
: 'No token probabilities available for the current message.';
const msg = power_user.request_token_probabilities
? 'No token probabilities available for the current message.'
: `<span>Enable <b>Request token probabilities</b> in the User Settings menu to use this feature.</span>`;
? noTokensMsg
: '<span>Enable <b>Request token probabilities</b> in the User Settings menu to use this feature.</span>';
emptyState.html(msg);
emptyState.addClass('logprobs_empty_state');
view.append(emptyState);

View File

@@ -10,7 +10,7 @@ import {
import { getCfgPrompt } from './cfg-scale.js';
import { MAX_CONTEXT_DEFAULT, MAX_RESPONSE_DEFAULT, power_user } from './power-user.js';
import { getTextTokens, tokenizers } from './tokenizers.js';
import EventSourceStream from './sse-stream.js';
import { getEventSourceStream } from './sse-stream.js';
import {
getSortableDelay,
getStringHash,
@@ -614,7 +614,7 @@ export async function generateNovelWithStreaming(generate_data, signal) {
tryParseStreamingError(response, await response.text());
throw new Error(`Got response status ${response.status}`);
}
const eventStream = new EventSourceStream();
const eventStream = getEventSourceStream();
response.body.pipeThrough(eventStream);
const reader = eventStream.readable.getReader();

View File

@@ -45,7 +45,7 @@ import {
import { getCustomStoppingStrings, persona_description_positions, power_user } from './power-user.js';
import { SECRET_KEYS, secret_state, writeSecret } from './secrets.js';
import EventSourceStream from './sse-stream.js';
import { getEventSourceStream } from './sse-stream.js';
import {
delay,
download,
@@ -1772,7 +1772,7 @@ async function sendOpenAIRequest(type, messages, signal) {
throw new Error(`Got response status ${response.status}`);
}
if (stream) {
const eventStream = new EventSourceStream();
const eventStream = getEventSourceStream();
response.body.pipeThrough(eventStream);
const reader = eventStream.readable.getReader();
return async function* streamData() {
@@ -3661,7 +3661,7 @@ async function onModelChange() {
else if (['command-light-nightly', 'command-nightly'].includes(oai_settings.cohere_model)) {
$('#openai_max_context').attr('max', max_8k);
}
else if (['command-r'].includes(oai_settings.cohere_model)) {
else if (['command-r', 'command-r-plus'].includes(oai_settings.cohere_model)) {
$('#openai_max_context').attr('max', max_128k);
}
else {

View File

@@ -118,6 +118,8 @@ let power_user = {
markdown_escape_strings: '',
chat_truncation: 100,
streaming_fps: 30,
smooth_streaming: false,
smooth_streaming_speed: 50,
ui_mode: ui_mode.POWER,
fast_ui_mode: true,
@@ -202,6 +204,7 @@ let power_user = {
output_suffix: '',
system_sequence: '',
system_suffix: '',
last_system_sequence: '',
first_output_sequence: '',
last_output_sequence: '',
system_sequence_prefix: '',
@@ -255,6 +258,8 @@ let power_user = {
auto_connect: false,
auto_load_chat: false,
forbid_external_images: false,
external_media_allowed_overrides: [],
external_media_forbidden_overrides: [],
};
let themes = [];
@@ -1548,6 +1553,9 @@ function loadPowerUserSettings(settings, data) {
$('#streaming_fps').val(power_user.streaming_fps);
$('#streaming_fps_counter').val(power_user.streaming_fps);
$('#smooth_streaming').prop('checked', power_user.smooth_streaming);
$('#smooth_streaming_speed').val(power_user.smooth_streaming_speed);
$('#font_scale').val(power_user.font_scale);
$('#font_scale_counter').val(power_user.font_scale);
@@ -2759,22 +2767,35 @@ export function getCustomStoppingStrings(limit = undefined) {
}
$(document).ready(() => {
const adjustAutocompleteDebounced = debounce(() => {
$('.ui-autocomplete-input').each(function () {
const isOpen = $(this).autocomplete('widget')[0].style.display !== 'none';
if (isOpen) {
$(this).autocomplete('search');
}
});
});
$(window).on('resize', async () => {
if (isMobile()) {
return;
}
//console.log('Window resized!');
const reportZoomLevelDebounced = debounce(() => {
const zoomLevel = Number(window.devicePixelRatio).toFixed(2);
const winWidth = window.innerWidth;
const winHeight = window.innerHeight;
console.debug(`Zoom: ${zoomLevel}, X:${winWidth}, Y:${winHeight}`);
});
$(window).on('resize', async () => {
adjustAutocompleteDebounced();
setHotswapsDebounced();
if (isMobile()) {
return;
}
reportZoomLevelDebounced();
if (Object.keys(power_user.movingUIState).length > 0) {
resetMovablePanels('resize');
}
// Adjust layout and styling here
setHotswapsDebounced();
});
// Settings that go to settings.json
@@ -2945,6 +2966,16 @@ $(document).ready(() => {
saveSettingsDebounced();
});
$('#smooth_streaming').on('input', function () {
power_user.smooth_streaming = !!$(this).prop('checked');
saveSettingsDebounced();
});
$('#smooth_streaming_speed').on('input', function () {
power_user.smooth_streaming_speed = Number($('#smooth_streaming_speed').val());
saveSettingsDebounced();
});
$('input[name="font_scale"]').on('input', async function (e) {
power_user.font_scale = Number(e.target.value);
$('#font_scale_counter').val(power_user.font_scale);

View File

@@ -470,7 +470,7 @@ async function waitForConnection() {
export async function initPresetManager() {
eventSource.on(event_types.CHAT_CHANGED, autoSelectPreset);
registerPresetManagers();
registerSlashCommand('preset', presetCommandCallback, [], '<span class="monospace">(name)</span> sets a preset by name for the current API', true, true);
registerSlashCommand('preset', presetCommandCallback, [], '<span class="monospace">(name)</span> sets a preset by name for the current API. Gets the current preset if no name is provided', true, true);
$(document).on('click', '[data-preset-manager-update]', async function () {
const apiId = $(this).data('preset-manager-update');

View File

@@ -254,7 +254,7 @@ parser.addCommand('inject', injectCallback, [], '<span class="monospace">id=inje
parser.addCommand('listinjects', listInjectsCallback, [], ' lists all script injections for the current chat.', true, true);
parser.addCommand('flushinjects', flushInjectsCallback, [], ' removes all script injections for the current chat.', true, true);
parser.addCommand('tokens', (_, text) => getTokenCount(text), [], '<span class="monospace">(text)</span> counts the number of tokens in the text.', true, true);
parser.addCommand('model', modelCallback, [], '<span class="monospace">(model name)</span> sets the model for the current API.', true, true);
parser.addCommand('model', modelCallback, [], '<span class="monospace">(model name)</span> sets the model for the current API. Gets the current model name if no argument is provided.', true, true);
registerVariableCommands();
const NARRATOR_NAME_KEY = 'narrator_name';
@@ -1653,16 +1653,10 @@ function setBackgroundCallback(_, bg) {
/**
* Sets a model for the current API.
* @param {object} _ Unused
* @param {string} model Model name
* @returns {void}
* @param {string} model New model name
* @returns {string} New or existing model name
*/
function modelCallback(_, model) {
if (!model) {
return;
}
console.log('Set model to ' + model);
const modelSelectMap = [
{ id: 'model_togetherai_select', api: 'textgenerationwebui', type: textgen_types.TOGETHERAI },
{ id: 'openrouter_model', api: 'textgenerationwebui', type: textgen_types.OPENROUTER },
@@ -1700,23 +1694,31 @@ function modelCallback(_, model) {
if (!modelSelectItem) {
toastr.info('Setting a model for your API is not supported or not implemented yet.');
return;
return '';
}
const modelSelectControl = document.getElementById(modelSelectItem);
if (!(modelSelectControl instanceof HTMLSelectElement)) {
toastr.error(`Model select control not found: ${main_api}[${apiSubType}]`);
return;
return '';
}
const options = Array.from(modelSelectControl.options);
if (!options.length) {
toastr.warning('No model options found. Check your API settings.');
return;
return '';
}
model = String(model || '').trim();
if (!model) {
return modelSelectControl.value;
}
console.log('Set model to ' + model);
let newSelectedOption = null;
const fuse = new Fuse(options, { keys: ['text', 'value'] });
@@ -1737,8 +1739,10 @@ function modelCallback(_, model) {
modelSelectControl.value = newSelectedOption.value;
$(modelSelectControl).trigger('change');
toastr.success(`Model set to "${newSelectedOption.text}"`);
return newSelectedOption.value;
} else {
toastr.warning(`No model found with name "${model}"`);
return '';
}
}

View File

@@ -1,3 +1,7 @@
import { eventSource, event_types } from '../script.js';
import { power_user } from './power-user.js';
import { delay } from './utils.js';
/**
* A stream which handles Server-Sent Events from a binary ReadableStream like you get from the fetch API.
*/
@@ -74,4 +78,215 @@ class EventSourceStream {
}
}
/**
* Gets a delay based on the character.
* @param {string} s The character.
* @returns {number} The delay in milliseconds.
*/
function getDelay(s) {
if (!s) {
return 0;
}
const speedFactor = Math.max(100 - power_user.smooth_streaming_speed, 1);
const defaultDelayMs = speedFactor * 0.4;
const punctuationDelayMs = defaultDelayMs * 25;
if ([',', '\n'].includes(s)) {
return punctuationDelayMs / 2;
}
if (['.', '!', '?'].includes(s)) {
return punctuationDelayMs;
}
return defaultDelayMs;
}
/**
* Parses the stream data and returns the parsed data and the chunk to be sent.
* @param {object} json The JSON data.
* @returns {AsyncGenerator<{data: object, chunk: string}>} The parsed data and the chunk to be sent.
*/
async function* parseStreamData(json) {
// Claude
if (typeof json.delta === 'object') {
if (typeof json.delta.text === 'string' && json.delta.text.length > 0) {
for (let i = 0; i < json.delta.text.length; i++) {
const str = json.delta.text[i];
yield {
data: { ...json, delta: { text: str } },
chunk: str,
};
}
}
return;
}
// MakerSuite
else if (Array.isArray(json.candidates)) {
for (let i = 0; i < json.candidates.length; i++) {
const isNotPrimary = json.candidates?.[0]?.index > 0;
if (isNotPrimary || json.candidates.length === 0) {
return null;
}
if (typeof json.candidates[0].content === 'object' && Array.isArray(json.candidates[i].content.parts)) {
for (let j = 0; j < json.candidates[i].content.parts.length; j++) {
if (typeof json.candidates[i].content.parts[j].text === 'string') {
for (let k = 0; k < json.candidates[i].content.parts[j].text.length; k++) {
const str = json.candidates[i].content.parts[j].text[k];
const candidateClone = structuredClone(json.candidates[0]);
candidateClone.content.parts[j].text = str;
const candidates = [candidateClone];
yield {
data: { ...json, candidates },
chunk: str,
};
}
}
}
}
}
return;
}
// NovelAI / KoboldCpp Classic
else if (typeof json.token === 'string' && json.token.length > 0) {
for (let i = 0; i < json.token.length; i++) {
const str = json.token[i];
yield {
data: { ...json, token: str },
chunk: str,
};
}
return;
}
// llama.cpp?
else if (typeof json.content === 'string' && json.content.length > 0) {
for (let i = 0; i < json.content.length; i++) {
const str = json.content[i];
yield {
data: { ...json, content: str },
chunk: str,
};
}
return;
}
// OpenAI-likes
else if (Array.isArray(json.choices)) {
const isNotPrimary = json?.choices?.[0]?.index > 0;
if (isNotPrimary || json.choices.length === 0) {
return null;
}
if (typeof json.choices[0].text === 'string' && json.choices[0].text.length > 0) {
for (let j = 0; j < json.choices[0].text.length; j++) {
const str = json.choices[0].text[j];
const choiceClone = structuredClone(json.choices[0]);
choiceClone.text = str;
const choices = [choiceClone];
yield {
data: { ...json, choices },
chunk: str,
};
}
return;
}
else if (typeof json.choices[0].delta === 'object') {
if (typeof json.choices[0].delta.text === 'string' && json.choices[0].delta.text.length > 0) {
for (let j = 0; j < json.choices[0].delta.text.length; j++) {
const str = json.choices[0].delta.text[j];
const choiceClone = structuredClone(json.choices[0]);
choiceClone.delta.text = str;
const choices = [choiceClone];
yield {
data: { ...json, choices },
chunk: str,
};
}
return;
}
else if (typeof json.choices[0].delta.content === 'string' && json.choices[0].delta.content.length > 0) {
for (let j = 0; j < json.choices[0].delta.content.length; j++) {
const str = json.choices[0].delta.content[j];
const choiceClone = structuredClone(json.choices[0]);
choiceClone.delta.content = str;
const choices = [choiceClone];
yield {
data: { ...json, choices },
chunk: str,
};
}
return;
}
}
else if (typeof json.choices[0].message === 'object') {
if (typeof json.choices[0].message.content === 'string' && json.choices[0].message.content.length > 0) {
for (let j = 0; j < json.choices[0].message.content.length; j++) {
const str = json.choices[0].message.content[j];
const choiceClone = structuredClone(json.choices[0]);
choiceClone.message.content = str;
const choices = [choiceClone];
yield {
data: { ...json, choices },
chunk: str,
};
}
return;
}
}
}
throw new Error('Unknown event data format');
}
/**
* Like the default one, but multiplies the events by the number of letters in the event data.
*/
export class SmoothEventSourceStream extends EventSourceStream {
constructor() {
super();
let lastStr = '';
const transformStream = new TransformStream({
async transform(chunk, controller) {
const event = chunk;
const data = event.data;
try {
const hasFocus = document.hasFocus();
if (data === '[DONE]') {
lastStr = '';
return controller.enqueue(event);
}
const json = JSON.parse(data);
if (!json) {
lastStr = '';
return controller.enqueue(event);
}
for await (const parsed of parseStreamData(json)) {
hasFocus && await delay(getDelay(lastStr));
controller.enqueue(new MessageEvent(event.type, { data: JSON.stringify(parsed.data) }));
lastStr = parsed.chunk;
hasFocus && await eventSource.emit(event_types.SMOOTH_STREAM_TOKEN_RECEIVED, parsed.chunk);
}
} catch (error) {
console.error('Smooth Streaming parsing error', error);
controller.enqueue(event);
}
},
});
this.readable = this.readable.pipeThrough(transformStream);
}
}
export function getEventSourceStream() {
if (power_user.smooth_streaming) {
return new SmoothEventSourceStream();
}
return new EventSourceStream();
}
export default EventSourceStream;

View File

@@ -43,6 +43,9 @@ export {
const CHARACTER_FILTER_SELECTOR = '#rm_characters_block .rm_tag_filter';
const GROUP_FILTER_SELECTOR = '#rm_group_chats_block .rm_tag_filter';
const TAG_TEMPLATE = $('#tag_template .tag');
const FOLDER_TEMPLATE = $('#bogus_folder_template .bogus_folder_select');
const VIEW_TAG_TEMPLATE = $('#tag_view_template .tag_view_item');
function getFilterHelper(listSelector) {
return $(listSelector).is(GROUP_FILTER_SELECTOR) ? groupCandidatesFilter : entitiesFilter;
@@ -271,7 +274,7 @@ function getTagBlock(tag, entities, hidden = 0) {
const tagFolder = TAG_FOLDER_TYPES[tag.folder_type];
const template = $('#bogus_folder_template .bogus_folder_select').clone();
const template = FOLDER_TEMPLATE.clone();
template.addClass(tagFolder.class);
template.attr({ 'tagid': tag.id, 'id': `BogusFolder${tag.id}` });
template.find('.avatar').css({ 'background-color': tag.color, 'color': tag.color2 }).attr('title', `[Folder] ${tag.name}`);
@@ -665,7 +668,7 @@ function appendTagToList(listElement, tag, { removable = false, selectable = fal
return;
}
let tagElement = $('#tag_template .tag').clone();
let tagElement = TAG_TEMPLATE.clone();
tagElement.attr('id', tag.id);
//tagElement.css('color', 'var(--SmartThemeBodyColor)');
@@ -765,7 +768,9 @@ function toggleTagThreeState(element, { stateOverride = undefined, simulateClick
element.toggleClass(FILTER_STATES[state].class, state === states[targetStateIndex]);
});
console.debug('toggle three-way filter from', states[currentStateIndex], 'to', states[targetStateIndex], 'on', element);
if (states[currentStateIndex] !== states[targetStateIndex]) {
console.debug('toggle three-way filter from', states[currentStateIndex], 'to', states[targetStateIndex], 'on', element);
}
}
@@ -1129,7 +1134,7 @@ function onTagCreateClick() {
function appendViewTagToList(list, tag, everything) {
const count = everything.filter(x => x == tag.id).length;
const template = $('#tag_view_template .tag_view_item').clone();
const template = VIEW_TAG_TEMPLATE.clone();
template.attr('id', tag.id);
template.find('.tag_view_counter_value').text(count);
template.find('.tag_view_name').text(tag.name);
@@ -1146,16 +1151,18 @@ function appendViewTagToList(list, tag, everything) {
template.find('.tag_as_folder').hide();
}
template.find('.tagColorPickerHolder').html(
`<toolcool-color-picker id="${colorPickerId}" color="${tag.color}" class="tag-color"></toolcool-color-picker>`,
);
template.find('.tagColorPicker2Holder').html(
`<toolcool-color-picker id="${colorPicker2Id}" color="${tag.color2}" class="tag-color2"></toolcool-color-picker>`,
);
const primaryColorPicker = $('<toolcool-color-picker></toolcool-color-picker>')
.addClass('tag-color')
.attr({ id: colorPickerId, color: tag.color });
const secondaryColorPicker = $('<toolcool-color-picker></toolcool-color-picker>')
.addClass('tag-color2')
.attr({ id: colorPicker2Id, color: tag.color2 });
template.find('.tagColorPickerHolder').append(primaryColorPicker);
template.find('.tagColorPicker2Holder').append(secondaryColorPicker);
template.find('.tag_as_folder').attr('id', tagAsFolderId);
template.find('.tag-color').attr('id', colorPickerId);
template.find('.tag-color2').attr('id', colorPicker2Id);
list.append(template);

View File

@@ -60,6 +60,7 @@
<li><tt>&lcub;&lcub;instructLastAssistantPrefix&rcub;&rcub;</tt> instruct assistant last output sequence</li>
<li><tt>&lcub;&lcub;instructSystemPrefix&rcub;&rcub;</tt> instruct system message prefix sequence</li>
<li><tt>&lcub;&lcub;instructSystemSuffix&rcub;&rcub;</tt> instruct system message suffix sequence</li>
<li><tt>&lcub;&lcub;instructSystemInstructionPrefix&rcub;&rcub;</tt> instruct system instruction prefix</li>
<li><tt>&lcub;&lcub;instructUserFiller&rcub;&rcub;</tt> instruct first user message filler</li>
<li><tt>&lcub;&lcub;instructStop&rcub;&rcub;</tt> instruct stop sequence</li>
</ul>

View File

@@ -12,7 +12,7 @@ import {
import { BIAS_CACHE, createNewLogitBiasEntry, displayLogitBias, getLogitBiasListResult } from './logit-bias.js';
import { power_user, registerDebugFunction } from './power-user.js';
import EventSourceStream from './sse-stream.js';
import { getEventSourceStream } from './sse-stream.js';
import { getCurrentDreamGenModelTokenizer, getCurrentOpenRouterModelTokenizer } from './textgen-models.js';
import { SENTENCEPIECE_TOKENIZERS, TEXTGEN_TOKENIZERS, getTextTokens, tokenizers } from './tokenizers.js';
import { getSortableDelay, onlyUnique } from './utils.js';
@@ -821,7 +821,7 @@ async function generateTextGenWithStreaming(generate_data, signal) {
throw new Error(`Got response status ${response.status}`);
}
const eventStream = new EventSourceStream();
const eventStream = getEventSourceStream();
response.body.pipeThrough(eventStream);
const reader = eventStream.readable.getReader();

View File

@@ -42,6 +42,8 @@ const world_info_logic = {
AND_ALL: 3,
};
const WI_ENTRY_EDIT_TEMPLATE = $('#entry_edit_template .world_entry');
let world_info = {};
let selected_world_info = [];
let world_names;
@@ -95,6 +97,11 @@ class WorldInfoBuffer {
*/
#skew = 0;
/**
* @type {number} The starting depth of the global scan depth. Incremented by "min activations" feature to not repeat scans. When > 0 it means a complete scan was done up to #startDepth already, and `advanceScanPosition` was called.
*/
#startDepth = 0;
/**
* Initialize the buffer with the given messages.
* @param {string[]} messages Array of messages to add to the buffer
@@ -137,7 +144,10 @@ class WorldInfoBuffer {
* @returns {string} A slice of buffer until the given depth (inclusive)
*/
get(entry) {
let depth = entry.scanDepth ?? (world_info_depth + this.#skew);
let depth = entry.scanDepth ?? this.getDepth();
if (depth <= this.#startDepth) {
return '';
}
if (depth < 0) {
console.error(`Invalid WI scan depth ${depth}. Must be >= 0`);
@@ -149,7 +159,7 @@ class WorldInfoBuffer {
depth = MAX_SCAN_DEPTH;
}
let result = this.#depthBuffer.slice(0, depth).join('\n');
let result = this.#depthBuffer.slice(this.#startDepth, depth).join('\n');
if (this.#recurseBuffer.length > 0) {
result += '\n' + this.#recurseBuffer.join('\n');
@@ -197,11 +207,19 @@ class WorldInfoBuffer {
}
/**
* Adds an increment to depth skew.
* Increments skew and sets startDepth to previous depth.
*/
addSkew() {
advanceScanPosition() {
this.#startDepth = this.getDepth();
this.#skew++;
}
/**
* @returns {number} Settings' depth + current skew.
*/
getDepth() {
return world_info_depth + this.#skew;
}
}
export function getWorldInfoSettings() {
@@ -783,6 +801,11 @@ function displayWorldEntries(name, data, navigation = navigation_option.none) {
afterSizeSelectorChange: function (e) {
localStorage.setItem(storageKey, e.target.value);
},
afterPaging: function () {
$('#world_popup_entries_list textarea[name="comment"]').each(function () {
initScrollHeight($(this));
});
},
});
if (typeof navigation === 'number' && Number(navigation) >= 0) {
@@ -970,7 +993,7 @@ function getWorldEntry(name, data, entry) {
return;
}
const template = $('#entry_edit_template .world_entry').clone();
const template = WI_ENTRY_EDIT_TEMPLATE.clone();
template.data('uid', entry.uid);
template.attr('uid', entry.uid);
@@ -982,10 +1005,10 @@ function getWorldEntry(name, data, entry) {
event.stopPropagation();
});
keyInput.on('input', function () {
keyInput.on('input', function (_, { skipReset } = {}) {
const uid = $(this).data('uid');
const value = String($(this).val());
resetScrollHeight(this);
!skipReset && resetScrollHeight(this);
data.entries[uid].key = value
.split(',')
.map((x) => x.trim())
@@ -994,7 +1017,7 @@ function getWorldEntry(name, data, entry) {
setOriginalDataValue(data, uid, 'keys', data.entries[uid].key);
saveWorldInfo(name, data);
});
keyInput.val(entry.key.join(', ')).trigger('input');
keyInput.val(entry.key.join(', ')).trigger('input', { skipReset: true });
//initScrollHeight(keyInput);
// logic AND/NOT
@@ -1008,7 +1031,6 @@ function getWorldEntry(name, data, entry) {
selectiveLogicDropdown.on('input', function () {
const uid = $(this).data('uid');
const value = Number($(this).val());
console.debug(`logic for ${entry.uid} set to ${value}`);
data.entries[uid].selectiveLogic = !isNaN(value) ? value : world_info_logic.AND_ANY;
setOriginalDataValue(data, uid, 'selectiveLogic', data.entries[uid].selectiveLogic);
saveWorldInfo(name, data);
@@ -1118,10 +1140,10 @@ function getWorldEntry(name, data, entry) {
// keysecondary
const keySecondaryInput = template.find('textarea[name="keysecondary"]');
keySecondaryInput.data('uid', entry.uid);
keySecondaryInput.on('input', function () {
keySecondaryInput.on('input', function (_, { skipReset } = {}) {
const uid = $(this).data('uid');
const value = String($(this).val());
resetScrollHeight(this);
!skipReset && resetScrollHeight(this);
data.entries[uid].keysecondary = value
.split(',')
.map((x) => x.trim())
@@ -1131,17 +1153,17 @@ function getWorldEntry(name, data, entry) {
saveWorldInfo(name, data);
});
keySecondaryInput.val(entry.keysecondary.join(', ')).trigger('input');
initScrollHeight(keySecondaryInput);
keySecondaryInput.val(entry.keysecondary.join(', ')).trigger('input', { skipReset: true });
//initScrollHeight(keySecondaryInput);
// comment
const commentInput = template.find('textarea[name="comment"]');
const commentToggle = template.find('input[name="addMemo"]');
commentInput.data('uid', entry.uid);
commentInput.on('input', function () {
commentInput.on('input', function (_, { skipReset } = {}) {
const uid = $(this).data('uid');
const value = $(this).val();
resetScrollHeight(this);
!skipReset && resetScrollHeight(this);
data.entries[uid].comment = value;
setOriginalDataValue(data, uid, 'comment', data.entries[uid].comment);
@@ -1160,8 +1182,8 @@ function getWorldEntry(name, data, entry) {
value ? commentContainer.show() : commentContainer.hide();
});
commentInput.val(entry.comment).trigger('input');
initScrollHeight(commentInput);
commentInput.val(entry.comment).trigger('input', { skipReset: true });
//initScrollHeight(commentInput);
commentToggle.prop('checked', true /* entry.addMemo */).trigger('input');
commentToggle.parent().hide();
@@ -1196,6 +1218,8 @@ function getWorldEntry(name, data, entry) {
if (counter.data('first-run')) {
counter.data('first-run', false);
countTokensDebounced(counter, contentInput.val());
initScrollHeight(keyInput);
initScrollHeight(keySecondaryInput);
}
});
@@ -1362,7 +1386,7 @@ function getWorldEntry(name, data, entry) {
}
const positionInput = template.find('select[name="position"]');
initScrollHeight(positionInput);
//initScrollHeight(positionInput);
positionInput.data('uid', entry.uid);
positionInput.on('click', function (event) {
// Prevent closing the drawer on clicking the input
@@ -1419,7 +1443,6 @@ function getWorldEntry(name, data, entry) {
//new tri-state selector for constant/normal/disabled
const entryStateSelector = template.find('select[name="entryStateSelector"]');
entryStateSelector.data('uid', entry.uid);
console.log(entry.uid);
entryStateSelector.on('click', function (event) {
// Prevent closing the drawer on clicking the input
event.stopPropagation();
@@ -1434,7 +1457,6 @@ function getWorldEntry(name, data, entry) {
setOriginalDataValue(data, uid, 'enabled', true);
setOriginalDataValue(data, uid, 'constant', true);
template.removeClass('disabledWIEntry');
console.debug('set to constant');
break;
case 'normal':
data.entries[uid].constant = false;
@@ -1442,7 +1464,6 @@ function getWorldEntry(name, data, entry) {
setOriginalDataValue(data, uid, 'enabled', true);
setOriginalDataValue(data, uid, 'constant', false);
template.removeClass('disabledWIEntry');
console.debug('set to normal');
break;
case 'disabled':
data.entries[uid].constant = false;
@@ -1450,7 +1471,6 @@ function getWorldEntry(name, data, entry) {
setOriginalDataValue(data, uid, 'enabled', false);
setOriginalDataValue(data, uid, 'constant', false);
template.addClass('disabledWIEntry');
console.debug('set to disabled');
break;
}
saveWorldInfo(name, data);
@@ -1458,19 +1478,13 @@ function getWorldEntry(name, data, entry) {
});
const entryState = function () {
console.log(`constant: ${entry.constant}, disabled: ${entry.disable}`);
if (entry.constant === true) {
console.debug('found constant');
return 'constant';
} else if (entry.disable === true) {
console.debug('found disabled');
return 'disabled';
} else {
console.debug('found normal');
return 'normal';
}
};
template
.find(`select[name="entryStateSelector"] option[value=${entryState()}]`)
@@ -1966,15 +1980,12 @@ async function getSortedEntries() {
switch (Number(world_info_character_strategy)) {
case world_info_insertion_strategy.evenly:
console.debug('WI using evenly');
entries = [...globalLore, ...characterLore].sort(sortFn);
break;
case world_info_insertion_strategy.character_first:
console.debug('WI using char first');
entries = [...characterLore.sort(sortFn), ...globalLore.sort(sortFn)];
break;
case world_info_insertion_strategy.global_first:
console.debug('WI using global first');
entries = [...globalLore.sort(sortFn), ...characterLore.sort(sortFn)];
break;
default:
@@ -2009,7 +2020,6 @@ async function checkWorldInfo(chat, maxContext) {
const buffer = new WorldInfoBuffer(chat);
// Combine the chat
let minActivationMsgIndex = world_info_depth; // tracks chat index to satisfy `world_info_min_activations`
// Add the depth or AN if enabled
// Put this code here since otherwise, the chat reference is modified
@@ -2102,8 +2112,6 @@ async function checkWorldInfo(chat, maxContext) {
const substituted = substituteParams(key);
const textToScan = buffer.get(entry);
console.debug(`${entry.uid}: ${substituted}`);
if (substituted && buffer.matchKeys(textToScan, substituted.trim(), entry)) {
console.debug(`WI UID ${entry.uid} found by primary match: ${substituted}.`);
@@ -2160,7 +2168,7 @@ async function checkWorldInfo(chat, maxContext) {
activatedNow.add(entry);
break primary;
}
} else { console.debug(`No active entries for logic checks for word: ${substituted}.`); }
}
}
}
}
@@ -2225,15 +2233,14 @@ async function checkWorldInfo(chat, maxContext) {
// world_info_min_activations
if (!needsToScan && !token_budget_overflowed) {
if (world_info_min_activations > 0 && (allActivatedEntries.size < world_info_min_activations)) {
let over_max = false;
over_max = (
let over_max = (
world_info_min_activations_depth_max > 0 &&
minActivationMsgIndex > world_info_min_activations_depth_max
) || (minActivationMsgIndex >= chat.length);
buffer.getDepth() > world_info_min_activations_depth_max
) || (buffer.getDepth() > chat.length);
if (!over_max) {
needsToScan = true;
minActivationMsgIndex += 1;
buffer.addSkew();
needsToScan = true; // loop
buffer.advanceScanPosition();
}
}
}