Skip to content

Add optional Stream QA pre-processor#17

Open
Trahloc wants to merge 1 commit into
p-e-w:masterfrom
Trahloc:feature/stream-qa
Open

Add optional Stream QA pre-processor#17
Trahloc wants to merge 1 commit into
p-e-w:masterfrom
Trahloc:feature/stream-qa

Conversation

@Trahloc
Copy link
Copy Markdown

@Trahloc Trahloc commented May 23, 2026

Summary

Adds an opt-in stream quality pre-processor inspired by DavidAU-style auto-correction, without changing Sorcery's marker/script model.

  • rules.json — profiles (temp/top_k bounds, regex strictness) and slop/loop patterns (community-tunable, no JS edits)
  • qa_validator.js — standalone engine: pre-compiled regex, strip on hit, sampler scramble for textgen/openai/kobold APIs, stop/continue via GENERATION_STOPPED trampoline + queueMicrotask
  • main.js / settings.js / settings.html — ~25 lines: import, one hook line before marker logic, profile dropdown (default disabled)

Design constraints

  • Zero-config default: qaProfile: "disabled" → stock Sorcery
  • QA runs before marker matchAll / runScript; marker pipeline untouched
  • No SillyTavern core patches
  • Delete test: remove 2 new files + small touchpoints → native Sorcery

Test plan

  • qaProfile: disabled — identical to stock Sorcery (with/without scripts)
  • Active profile strips obvious slop/loop text; generation continues after correction
  • Markers still fire and strip below QA line
  • QA on with empty script list — stream hook still installs
  • User Stop mid-generation restores original samplers (no stuck temp/top_k)
  • Text Completion + llama.cpp backend scrambles via textgenerationwebui_settings

Made with Cursor

Introduces rules.json and qa_validator.js for slop/loop detection, sampler
scramble on supported APIs, and continue-via-generation-stopped trampoline.
Default qaProfile is disabled so stock Sorcery behavior is unchanged.

Co-authored-by: Cursor <cursoragent@cursor.com>
Copilot AI review requested due to automatic review settings May 23, 2026 08:24
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an opt-in “Stream QA” pre-processor that can clean streamed text via regex rules and optionally scramble sampling parameters when slop/loop patterns are detected, while keeping Sorcery’s existing marker/script pipeline intact.

Changes:

  • Add qaProfile setting (default disabled) and a new settings UI dropdown.
  • Introduce rules.json (profiles + regex rules) and qa_validator.js (rule loading, regex cleaning, sampler scrambling, stop/continue trampoline).
  • Hook Stream QA into the streaming pipeline ahead of marker processing.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
settings.js Adds qaProfile to default extension settings.
settings.html Adds Stream QA Profile dropdown to the extension settings UI.
rules.json Defines QA profiles and regex patterns for slop/loop detection.
qa_validator.js Implements rule loading/caching, regex compilation, cleaning logic, and sampler scrambling/restore.
main.js Installs Stream QA into onProgressStreaming and wires the new dropdown to settings.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread main.js
Comment on lines 125 to 127
function installStreamHook() {
if (hookToBeInstalled) {
if (hookToBeInstalled || settings.qaProfile !== "disabled") {
const markerRegex = new RegExp(settings.markerRegex, "g");
Comment thread qa_validator.js
for (const [level, categories] of Object.entries(regexRules)) {
compiled[level] = {};
for (const [category, patterns] of Object.entries(categories)) {
compiled[level][category] = patterns.map((pattern) => new RegExp(pattern, "gi"));
Comment thread qa_validator.js
Comment on lines +54 to +69
function scrambleSamplers(profile) {
if (profile.temp_min == null || profile.top_k_min == null) return;
const target = getSamplerTarget();
if (!target) return;
const { settings, tempKey, topKKey } = target;
if (!originalParams) {
originalParams = {
target,
temp: settings[tempKey],
top_k: settings[topKKey],
};
}
const randomTemp = Math.random() * (profile.temp_max - profile.temp_min) + profile.temp_min;
const randomTopK = Math.floor(Math.random() * (profile.top_k_max - profile.top_k_min + 1)) + profile.top_k_min;
settings[tempKey] = parseFloat(randomTemp.toFixed(2));
settings[topKKey] = randomTopK;
Comment thread qa_validator.js
async function loadRules() {
if (rulesCache) return rulesCache;
try {
const response = await fetch("/scripts/extensions/third-party/sorcery/rules.json");
Comment thread rules.json
Comment on lines +13 to +21
"looping": ["(.{15,})\\1+"]
},
"medium": {
"slop": ["(?:testament to|tapestry of|delve into).+?", "\\b(delve|tapestry|testament)\\b"],
"looping": ["(.{30,})\\1+"]
},
"low": {
"slop": ["(?:testament to|tapestry of).+?"],
"looping": ["(.{50,})\\1+"]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants