diff --git a/index.js b/index.js index ea14c9e..b90b7c0 100644 --- a/index.js +++ b/index.js @@ -114,7 +114,8 @@ hide_animated_bar: false, surprise_depth_min: 2, // minimum messages away (used for random range or fixed min) surprise_depth_max: 6, // maximum messages away (used for random range or fixed max) - surprise_randomize: true // randomize depth between min and max + surprise_randomize: true, // randomize depth between min and max + surprise_endless: false // auto-rearm a new surprise after each one fires }); @@ -1466,6 +1467,9 @@ GUIDELINES: Surprise Me ? + ${settings.surprise_endless ? `
+ Endless Surprises active +
` : ''} ${surpriseCount > 0 ? `
@@ -2509,6 +2513,15 @@ GUIDELINES: Surprise Me ? +
+ Endless Surprises + ? + +
+
+

+ A new surprise is silently queued the moment the previous one fires. +

Randomize depth
@@ -3681,6 +3694,7 @@ GUIDELINES: fetchAndPopulateOllamaModels('#pw_ollama_model'); } renderSurpriseQueue(); + jQuery('#pw_surprise_endless').prop('checked', settings.surprise_endless); } function updateProviderVisibility(source) { @@ -3765,6 +3779,7 @@ GUIDELINES: jQuery('#pw_stream_suggestions').prop('checked', settings.stream_suggestions); // Surprise Me jQuery('#pw_surprise_randomize').prop('checked', settings.surprise_randomize); + jQuery('#pw_surprise_endless').prop('checked', settings.surprise_endless); jQuery('#pw_surprise_depth_min').val(settings.surprise_depth_min); jQuery('#pw_surprise_depth_max').val(settings.surprise_depth_max); if (settings.surprise_randomize) { @@ -3810,6 +3825,7 @@ GUIDELINES: // Surprise Me jQuery('.pw_toggle[data-setting="surprise_randomize"]').toggleClass('active', settings.surprise_randomize); + jQuery('.pw_toggle[data-setting="surprise_endless"]').toggleClass('active', settings.surprise_endless); jQuery('#pw_sm_surprise_depth_min').val(settings.surprise_depth_min); jQuery('#pw_sm_surprise_depth_max').val(settings.surprise_depth_max); if (settings.surprise_randomize) { @@ -4051,9 +4067,18 @@ GUIDELINES: openStyleEditor(); }); + // Surprise Me: endless toggle + jQuery('#pw_surprise_endless').on('change', function () { + settings.surprise_endless = this.checked; + saveSettings(); + syncSettingsToModal(); + if (this.checked) { + showToast('Endless Surprises enabled — surprises will keep arming themselves!'); + } + }); + // Surprise Me: randomize toggle - jQuery('#pw_surprise_randomize').on('change', function () { - settings.surprise_randomize = this.checked; + jQuery('#pw_surprise_randomize').on('change', function () { settings.surprise_randomize = this.checked; if (settings.surprise_randomize) { jQuery('#pw_surprise_range_rows').show(); jQuery('#pw_surprise_fixed_hint').hide(); @@ -4159,9 +4184,15 @@ GUIDELINES: if (s.injected) { clearSurprisePrompt(s.key); + const firedCategory = s.category; // capture before splice activeSurprises.splice(i, 1); changed = true; log('Surprise', s.key, 'cleared after firing'); + + // Endless Surprises: silently queue a fresh one with the same style + if (settings.surprise_endless) { + scheduleEndlessSurprise(firedCategory); + } } else if (newMessages >= s.triggerAfter) { const ok = injectSurprisePrompt(s.text, 1, s.key); if (ok) { @@ -4179,6 +4210,39 @@ GUIDELINES: } } + /** + * Silently generate and arm a new surprise for the given category. + * Used by Endless Surprises to keep the queue perpetually loaded + * without interrupting the user. + */ + async function scheduleEndlessSurprise(category) { + log('Endless Surprises: scheduling background surprise for category', category); + try { + const endlessAbort = new AbortController(); + const text = await generateSurpriseText(category, endlessAbort.signal); + + const dMin = Math.max(1, Math.min(12, settings.surprise_depth_min || 2)); + const dMax = Math.max(dMin, Math.min(12, settings.surprise_depth_max || 6)); + const triggerAfter = settings.surprise_randomize + ? Math.floor(Math.random() * (dMax - dMin + 1)) + dMin + : dMin; + + const stContext = SillyTavern.getContext(); + const baseMessageCount = stContext?.chat?.length ?? 0; + const key = `pathweaver_surprise_${surpriseKeyCounter++}`; + + activeSurprises.push({ key, category, triggerAfter, baseMessageCount, text, injected: false }); + saveSurpriseQueue(); + renderSurpriseQueue(); + createActionBar(); + + log('Endless Surprises: new surprise armed for category', category, '— fires in', triggerAfter, 'messages'); + } catch (err) { + if (err.name === 'AbortError') return; + warn('Endless Surprises: background generation failed:', err.message); + } + } + const handleProfileMousedown = () => { populateConnectionProfiles(); }; diff --git a/manifest.json b/manifest.json index 159a923..202dbe0 100644 --- a/manifest.json +++ b/manifest.json @@ -6,7 +6,7 @@ "js": "index.js", "css": "style.css", "author": "mattjaybe", - "version": "1.3.0", + "version": "1.4", "homePage": "https://github.com/mattjaybe/SillyTavern-Pathweaver", "auto_update": true } diff --git a/settings.html b/settings.html index be103fb..c28f732 100644 --- a/settings.html +++ b/settings.html @@ -228,6 +228,14 @@ ? + +

+ When enabled, a new surprise is silently generated and armed as soon as the previous one fires — keeping the story perpetually on the edge. +

+