From e0ebe07a5532b671f2487a4fd83a4ad4c717b040 Mon Sep 17 00:00:00 2001
From: Youzini-afk <13153778771cx@gmail.com>
Date: Tue, 7 Apr 2026 01:12:28 +0800
Subject: [PATCH] Fix prompt preview semantics for display regex rules
---
panel.js | 16 +++++++-----
task-regex.js | 61 +++++++++++++++++++++++++++++++++++++++-----
tests/task-regex.mjs | 11 +++++---
3 files changed, 71 insertions(+), 17 deletions(-)
diff --git a/panel.js b/panel.js
index bfa418c..4afff13 100644
--- a/panel.js
+++ b/panel.js
@@ -3890,7 +3890,11 @@ function _renderRegexReuseRuleList(rules = [], emptyText = "无") {
const flags = [
rule.promptOnly ? "promptOnly" : "",
rule.markdownOnly ? "markdownOnly" : "",
- rule.promptReplaceAsEmpty ? "请求阶段按空字符串替换" : "",
+ rule.promptStageMode === "clear"
+ ? "请求阶段: 美化/展示 -> 清空"
+ : rule.promptStageMode === "replace"
+ ? "请求阶段: 正常替换"
+ : "请求阶段: 不参与",
rule.reason ? `原因: ${rule.reason}` : "",
].filter(Boolean);
const replaceText = rule.promptReplaceAsEmpty
@@ -3983,10 +3987,10 @@ function _buildRegexReusePopupContent(snapshot = {}) {
raw=${Number(source.rawRuleCount || 0)} / active=${Number(source.activeRuleCount || 0)}
${source.reason ? `
${_escHtml(source.reason)}` : ""}
-
本来源当前生效规则
- ${_renderRegexReuseRuleList(source.rules, "该来源当前没有进入任务链的复用规则")}
- 被跳过的规则
- ${_renderRegexReuseRuleList(source.ignoredRules, "没有被额外跳过的规则")}
+ 本来源规则总览
+ ${_renderRegexReuseRuleList(source.previewRules || source.rules, "该来源当前没有可展示的规则")}
+ 未纳入最终任务链
+ ${_renderRegexReuseRuleList(source.ignoredRules, "没有额外被排除的规则")}
`).join("")
: `当前没有可展示的酒馆正则来源。
`
@@ -3996,7 +4000,7 @@ function _buildRegexReusePopupContent(snapshot = {}) {
汇总后的复用规则
- 这是经过来源开关、allowlist 和去重后,准备进入当前任务链的 Tavern 规则集合。
+ 这是经过来源开关、allowlist 和去重后,进入 ST-BME 任务链的 Tavern 规则集合。展示/美化类规则在请求阶段会按空字符串替换。
${_renderRegexReuseRuleList(activeRules, "当前没有复用到任何酒馆正则")}
diff --git a/task-regex.js b/task-regex.js
index 9906bf5..15800b3 100644
--- a/task-regex.js
+++ b/task-regex.js
@@ -169,7 +169,7 @@ function normalizeRule(raw = {}, fallbackSource = "local", index = 0) {
sourceFlags,
destinationFlags: {
prompt: destination
- ? isTavernRule && beautificationReplace
+ ? isTavernRule && (raw.markdownOnly === true || beautificationReplace)
? true
: Boolean(destination.prompt)
: isTavernRule && raw.markdownOnly === true
@@ -397,7 +397,8 @@ function getPlacementLabels(placement = []) {
function summarizeRule(rule, reason = "") {
const normalized = rule && typeof rule === "object" ? rule : {};
- const promptReplaceAsEmpty = Boolean(normalized.beautificationReplace);
+ const promptReplaceAsEmpty =
+ Boolean(normalized.markdownOnly) || Boolean(normalized.beautificationReplace);
const sourceFlags =
normalized.sourceFlags && typeof normalized.sourceFlags === "object"
? normalized.sourceFlags
@@ -434,6 +435,24 @@ function summarizeRule(rule, reason = "") {
};
}
+function summarizeRuleForPromptPreview(rule, stageConfig = {}, reason = "") {
+ const summary = summarizeRule(rule, reason);
+ const promptStageApplies = shouldApplyRuleForStage(
+ rule,
+ "input.finalPrompt",
+ stageConfig,
+ );
+ return {
+ ...summary,
+ promptStageApplies,
+ promptStageMode: promptStageApplies
+ ? summary.promptReplaceAsEmpty
+ ? "clear"
+ : "replace"
+ : "skip",
+ };
+}
+
function collectViaApi(sourceType, regexHost = null) {
const getter = regexHost?.getTavernRegexes;
if (typeof getter !== "function") {
@@ -505,6 +524,8 @@ function collectTavernRulesDetailed(regexConfig = {}) {
enabled && allowed ? (Array.isArray(rawItems) ? rawItems : []) : [];
const activeRules = [];
const ignoredRules = [];
+ const ignoredPreviewRules = [];
+ const previewRules = [];
if (!enabled) {
sources.push({
@@ -518,6 +539,10 @@ function collectTavernRulesDetailed(regexConfig = {}) {
reason || (shouldReuse ? "当前任务已关闭该来源" : "当前任务未启用复用酒馆正则"),
rawRuleCount: Array.isArray(rawItems) ? rawItems.length : 0,
activeRuleCount: 0,
+ previewRules: Array.isArray(rawItems)
+ ? rawItems.map((item, index) => normalizeRule(item, type, index))
+ : [],
+ ignoredPreviewRules: [],
rules: [],
ignoredRules: [],
});
@@ -526,24 +551,31 @@ function collectTavernRulesDetailed(regexConfig = {}) {
if (!allowed && Array.isArray(rawItems)) {
for (let index = 0; index < rawItems.length; index++) {
+ const normalized = normalizeRule(rawItems[index], type, index);
+ previewRules.push(normalized);
+ ignoredPreviewRules.push({ ...normalized, reason: "not-allowed" });
ignoredRules.push(
- summarizeRule(normalizeRule(rawItems[index], type, index), "not-allowed"),
+ summarizeRule(normalized, "not-allowed"),
);
}
}
for (let index = 0; index < effectiveItems.length; index++) {
const normalized = normalizeRule(effectiveItems[index], type, index);
+ previewRules.push(normalized);
if (!normalized.enabled) {
+ ignoredPreviewRules.push({ ...normalized, reason: "disabled" });
ignoredRules.push(summarizeRule(normalized, "disabled"));
continue;
}
if (!normalized.findRegex) {
+ ignoredPreviewRules.push({ ...normalized, reason: "missing-find-regex" });
ignoredRules.push(summarizeRule(normalized, "missing-find-regex"));
continue;
}
const key = `${type}:${normalized.id}:${normalized.findRegex}`;
if (seen.has(key)) {
+ ignoredPreviewRules.push({ ...normalized, reason: "duplicate" });
ignoredRules.push(summarizeRule(normalized, "duplicate"));
continue;
}
@@ -562,6 +594,8 @@ function collectTavernRulesDetailed(regexConfig = {}) {
reason,
rawRuleCount: Array.isArray(rawItems) ? rawItems.length : 0,
activeRuleCount: activeRules.length,
+ previewRules,
+ ignoredPreviewRules,
rules: activeRules,
ignoredRules,
});
@@ -676,7 +710,7 @@ function shouldApplyRuleForTaskContext(rule, stage = "") {
const isOutputStage = OUTPUT_STAGES.has(normalizedStage);
if (rule.markdownOnly) {
- return isPromptStage && rule.beautificationReplace === true;
+ return isPromptStage;
}
if (isFinalPromptStage) {
@@ -726,7 +760,7 @@ function applyOneRule(input, rule, stage = "") {
let replacement = rule.replaceString || "";
if (
PROMPT_STAGES.has(stage) &&
- rule.beautificationReplace
+ (rule.markdownOnly || rule.beautificationReplace)
) {
replacement = "";
}
@@ -820,6 +854,12 @@ export function inspectTaskRegexReuse(settings = {}, taskType = "") {
const profile = getActiveTaskProfile(settings, taskType);
const regexConfig = profile?.regex || {};
const detailed = collectTavernRulesDetailed(regexConfig);
+ const stageConfig = normalizeTaskRegexStages(regexConfig.stages || {});
+
+ const mapPreviewRules = (rules = []) =>
+ (Array.isArray(rules) ? rules : []).map((rule) =>
+ summarizeRuleForPromptPreview(rule, stageConfig, rule?.reason || ""),
+ );
return {
taskType: String(taskType || ""),
@@ -836,9 +876,16 @@ export function inspectTaskRegexReuse(settings = {}, taskType = "") {
localRuleCount: Array.isArray(regexConfig.localRules)
? regexConfig.localRules.length
: 0,
- sources: detailed.sources,
+ sources: detailed.sources.map((source) => ({
+ ...source,
+ previewRules: mapPreviewRules(source.previewRules),
+ rules: mapPreviewRules(source.previewRules),
+ ignoredRules: mapPreviewRules(source.ignoredPreviewRules),
+ })),
host: detailed.host,
activeRuleCount: detailed.rules.length,
- activeRules: detailed.rules.map((rule) => summarizeRule(rule)),
+ activeRules: detailed.rules.map((rule) =>
+ summarizeRuleForPromptPreview(rule, stageConfig),
+ ),
};
}
diff --git a/tests/task-regex.mjs b/tests/task-regex.mjs
index 1636f6f..b6320ee 100644
--- a/tests/task-regex.mjs
+++ b/tests/task-regex.mjs
@@ -506,6 +506,7 @@ try {
assert.equal(markdownRule?.promptReplaceAsEmpty, true);
assert.equal(markdownRule?.effectivePromptReplaceString, "");
assert.deepEqual(markdownRule?.placementLabels, ["用户输入"]);
+ assert.equal(markdownRule?.promptStageMode, "clear");
const markdownOnlyFinalPromptSettings = buildSettings({
sources: {
global: true,
@@ -588,15 +589,15 @@ try {
destinationBeautifySettings,
"extract",
"input.finalPrompt",
- "Decor Plain",
+ "DecorPlain",
destinationDebug,
"user",
),
- " Plain",
+ "",
);
assert.deepEqual(
destinationDebug.entries[0].appliedRules.map((item) => item.id),
- ["destination-display-only-beautify"],
+ ["destination-display-only-beautify", "destination-display-only-text"],
);
const destinationInspect = inspectTaskRegexReuse(
destinationBeautifySettings,
@@ -610,7 +611,9 @@ try {
);
assert.deepEqual(destinationBeautifyRule?.placementLabels, ["用户输入"]);
assert.equal(destinationBeautifyRule?.promptReplaceAsEmpty, true);
- assert.equal(destinationTextRule?.promptReplaceAsEmpty, false);
+ assert.equal(destinationBeautifyRule?.promptStageMode, "clear");
+ assert.equal(destinationTextRule?.promptReplaceAsEmpty, true);
+ assert.equal(destinationTextRule?.promptStageMode, "clear");
setTestContext({
extensionSettings: {
regex: [