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: [