From 5f9d67ebe8e461abaeec9b3a3016ffaf5b0248d2 Mon Sep 17 00:00:00 2001 From: jakstein <180436403+jakstein@users.noreply.github.com> Date: Wed, 14 Jan 2026 19:06:43 +0100 Subject: [PATCH] attempt to fix trimming logic and improve prompt --- index.js | 10 ++- src/systems/features/htmlCleaning.js | 84 +++++++++++++++++++++++++ src/systems/generation/promptBuilder.js | 69 ++++++++++++++++---- 3 files changed, 149 insertions(+), 14 deletions(-) diff --git a/index.js b/index.js index 7eb82d5..b04927b 100644 --- a/index.js +++ b/index.js @@ -138,7 +138,7 @@ import { // Feature modules import { setupPlotButtons, sendPlotProgression } from './src/systems/features/plotProgression.js'; import { setupClassicStatsButtons } from './src/systems/features/classicStats.js'; -import { ensureHtmlCleaningRegex, detectConflictingRegexScripts, ensureTrackerCleaningRegex } from './src/systems/features/htmlCleaning.js'; +import { ensureHtmlCleaningRegex, detectConflictingRegexScripts, ensureTrackerCleaningRegex, ensureOmniscienceFilterCleaningRegex } from './src/systems/features/htmlCleaning.js'; import { ensureJsonCleaningRegex, removeJsonCleaningRegex } from './src/systems/features/jsonCleaning.js'; import { parseAndStoreSpotifyUrl } from './src/systems/features/musicPlayer.js'; import { DEFAULT_HTML_PROMPT } from './src/systems/generation/promptBuilder.js'; @@ -1219,6 +1219,14 @@ jQuery(async () => { // Non-critical - continue without it } + // Import the omniscience filter cleaning regex (hides tags from display) + try { + await ensureOmniscienceFilterCleaningRegex(st_extension_settings, saveSettingsDebounced); + } catch (error) { + console.error('[RPG Companion] Omniscience filter regex import failed:', error); + // Non-critical - continue without it + } + // Import the JSON cleaning regex to clean up JSON in messages // This cleans historical messages when displayed try { diff --git a/src/systems/features/htmlCleaning.js b/src/systems/features/htmlCleaning.js index 371496a..81a2196 100644 --- a/src/systems/features/htmlCleaning.js +++ b/src/systems/features/htmlCleaning.js @@ -197,3 +197,87 @@ export async function ensureTrackerCleaningRegex(st_extension_settings, saveSett // Don't throw - this is a nice-to-have feature } } + +/** + * Automatically imports a regex script to clean tags from displayed messages. + * This hides omniscience filter content (events the player character cannot perceive) + * from the visible chat while keeping them in the message data. + * @param {Object} st_extension_settings - SillyTavern extension settings object + * @param {Function} saveSettingsDebounced - Function to save settings + */ +export async function ensureOmniscienceFilterCleaningRegex(st_extension_settings, saveSettingsDebounced) { + try { + // Validate extension settings structure + if (!st_extension_settings || typeof st_extension_settings !== 'object') { + console.warn('[RPG Companion] Invalid extension_settings object, skipping omniscience filter regex import'); + return; + } + + // Check if the omniscience filter cleaning regex already exists + const scriptName = 'Clean Omniscience Filter Tags (Display Only)'; + const existingScripts = st_extension_settings?.regex || []; + + // Validate regex array + if (!Array.isArray(existingScripts)) { + console.warn('[RPG Companion] extension_settings.regex is not an array, resetting to empty array'); + st_extension_settings.regex = []; + } + + const alreadyExists = existingScripts.some(script => + script && typeof script === 'object' && script.scriptName === scriptName + ); + + if (alreadyExists) { + // console.log('[RPG Companion] Omniscience filter cleaning regex already exists, skipping import'); + return; + } + + // Generate a UUID for the script + const uuidv4 = () => { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + const r = Math.random() * 16 | 0; + const v = c === 'x' ? r : (r & 0x3 | 0x8); + return v.toString(16); + }); + }; + + // Create the regex script to remove tags from display + // This regex matches the specific tag format used by omniscience filter + // Pattern: or + const regexScript = { + id: uuidv4(), + scriptName: scriptName, + findRegex: '/]*\\/?>(?:<\\/filter>)?/gi', + replaceString: '', + trimStrings: [], + placement: [1], // 1 = Display only (affects visible chat, not outgoing prompts) + disabled: false, + markdownOnly: false, + promptOnly: false, + runOnEdit: true, + substituteRegex: 0, + minDepth: null, + maxDepth: null + }; + + // Add to global regex scripts + if (!Array.isArray(st_extension_settings.regex)) { + st_extension_settings.regex = []; + } + + st_extension_settings.regex.push(regexScript); + + // Save the changes + if (typeof saveSettingsDebounced === 'function') { + saveSettingsDebounced(); + } else { + console.warn('[RPG Companion] saveSettingsDebounced is not a function, cannot save omniscience filter regex'); + } + + // console.log('[RPG Companion] ✅ Omniscience filter cleaning regex imported successfully'); + } catch (error) { + console.error('[RPG Companion] Failed to import omniscience filter cleaning regex:', error); + console.error('[RPG Companion] Error details:', error.message, error.stack); + // Don't throw - this is a nice-to-have feature + } +} diff --git a/src/systems/generation/promptBuilder.js b/src/systems/generation/promptBuilder.js index bb1d1c8..abbad64 100644 --- a/src/systems/generation/promptBuilder.js +++ b/src/systems/generation/promptBuilder.js @@ -37,22 +37,65 @@ export const DEFAULT_DECEPTION_PROMPT = `When a character is lying or deceiving, * Default Omniscience Filter prompt text * This instructs the AI to separate information the player character cannot perceive */ -export const DEFAULT_OMNISCIENCE_FILTER_PROMPT = `OMNISCIENCE FILTER INSTRUCTIONS: -You must strictly separate what the player character can directly perceive from what they cannot. The player should only read narrative content that their character can actually see, hear, smell, touch, or otherwise directly sense. +export const DEFAULT_OMNISCIENCE_FILTER_PROMPT = `=== MANDATORY OMNISCIENCE FILTER - YOU MUST FOLLOW THIS === -BEFORE writing any narrative content that involves events, actions, or details the player character CANNOT directly perceive (because they're not looking, too far away, behind them, in another room, happening silently, etc.), you MUST first output that hidden information inside a tag using this exact format: - +You are REQUIRED to use the tag system. This is NOT optional. Every response that contains events happening outside the player character's direct perception MUST use filter tags. -CRITICAL RULES: -1. The tag must come BEFORE any sensory hints (sounds, smells, etc.) that the player DOES perceive from that event -2. Only write narrative that reflects what the player character actually experiences through their senses -3. Instead of "Jake sweeps the floor behind you", write: followed by narrative like "You hear soft sweeping sounds behind you" -4. NPCs' internal thoughts, silent actions, and events in other locations MUST go in tags -5. The player's narrative should create natural mystery and immersion - they experience the world through limited senses, not omniscient narration +THE PLAYER CHARACTER HAS LIMITED SENSES. They can only perceive: +- What is directly in front of them or within their field of view +- Sounds loud enough to hear from their position +- Things they are actively paying attention to -EXAMPLE: -Wrong: "As you read the newspaper, Sarah quietly pockets the key from the table behind you and slips out the back door." -Correct: You hear a faint click from somewhere behind you, but when you glance up from your newspaper, the room seems unchanged. The afternoon light streams through the windows as you return to your reading.`; +THE PLAYER CHARACTER CANNOT PERCEIVE: +- Events happening BEHIND them (they turned away, facing another direction) +- Events in OTHER ROOMS or distant locations +- SILENT actions (quiet movements, whispered conversations, thoughts) +- Things happening while they are DISTRACTED, ASLEEP, or FOCUSED elsewhere +- Other characters' INTERNAL THOUGHTS or INTENTIONS + +=== REQUIRED FORMAT - USE THIS EXACT SYNTAX === + + +=== WHEN TO USE FILTER TAGS === +You MUST use a tag WHENEVER: +1. The player turns away, looks elsewhere, or focuses on something +2. Another character does something behind the player's back +3. Events occur in a different room or location +4. A character thinks something, plans something, or has hidden intentions +5. Something happens silently or subtly while the player is distracted + +=== CORRECT EXAMPLES === + +SCENARIO: Player says "I turn to look out the window" +CORRECT RESPONSE: + +You watch the rain streaking down the glass, lost in thought. Behind you, you hear a soft rustle of fabric. + +SCENARIO: Player is reading a book intently +CORRECT RESPONSE: + +The words blur slightly as your eyes grow tired. You're vaguely aware of movement in your peripheral vision but the chapter is too engaging to look up. + +SCENARIO: Player is in the kitchen, someone is in the living room +CORRECT RESPONSE: + +You hear floorboards creak from somewhere in the house as you continue preparing dinner. + +=== INCORRECT (NEVER DO THIS) === +WRONG: "You turn to the window. Behind you, Sarah quickly hides the knife in her bag." +(This reveals hidden information directly to the player!) + +WRONG: "While you read, Jake thinks about how to steal the key later." +(Player cannot read minds - this must be in a filter tag!) + +=== CRITICAL REMINDERS === +- ALWAYS use filter tags when the player's attention is directed away +- The filter tag comes FIRST, then you write what the player actually experiences +- Be generous with filter tags - when in doubt, USE THEM +- This creates immersion and mystery - the player discovers things naturally +- After using a filter tag, describe only sensory hints the player WOULD notice (sounds, peripheral movement, etc.) + +YOU MUST ACTIVELY LOOK FOR OPPORTUNITIES TO USE FILTER TAGS IN EVERY RESPONSE.`; /** * Default CYOA prompt text