diff --git a/panel.js b/panel.js index 4a68d58..bfa418c 100644 --- a/panel.js +++ b/panel.js @@ -3890,8 +3890,14 @@ function _renderRegexReuseRuleList(rules = [], emptyText = "无") { const flags = [ rule.promptOnly ? "promptOnly" : "", rule.markdownOnly ? "markdownOnly" : "", + rule.promptReplaceAsEmpty ? "请求阶段按空字符串替换" : "", rule.reason ? `原因: ${rule.reason}` : "", ].filter(Boolean); + const replaceText = rule.promptReplaceAsEmpty + ? `${rule.replaceString ? `${_escHtml(rule.replaceString)} -> ` : ""}(prompt 时为空)` + : rule.replaceString + ? `${_escHtml(rule.replaceString)}` + : ""; return `
${_escHtml(rule.name || rule.id || "未命名规则")} @@ -3899,7 +3905,7 @@ function _renderRegexReuseRuleList(rules = [], emptyText = "无") {
${_escHtml(rule.findRegex || "(空 findRegex)")} - ${rule.replaceString ? ` -> ${_escHtml(rule.replaceString)}` : ""} + ${replaceText ? ` -> ${replaceText}` : ""} ${flags.length ? `
${_escHtml(flags.join(" · "))}` : ""}
`; diff --git a/task-regex.js b/task-regex.js index 361c7ae..fcbe057 100644 --- a/task-regex.js +++ b/task-regex.js @@ -154,7 +154,9 @@ function normalizeRule(raw = {}, fallbackSource = "local", index = 0) { destinationFlags: { prompt: destination ? Boolean(destination.prompt) - : raw.markdownOnly !== true, + : isTavernRule && raw.markdownOnly === true + ? true + : raw.markdownOnly !== true, display: destination ? Boolean(destination.display) : Boolean(raw.markdownOnly), @@ -376,11 +378,18 @@ function getPlacementLabels(placement = []) { function summarizeRule(rule, reason = "") { const normalized = rule && typeof rule === "object" ? rule : {}; + const promptReplaceAsEmpty = + Boolean(normalized.markdownOnly) || + isBeautificationReplace(normalized.replaceString); return { id: String(normalized.id || ""), name: String(normalized.scriptName || normalized.id || ""), findRegex: String(normalized.findRegex || ""), replaceString: String(normalized.replaceString || ""), + effectivePromptReplaceString: promptReplaceAsEmpty + ? "" + : String(normalized.replaceString || ""), + promptReplaceAsEmpty, sourceType: String(normalized.sourceType || ""), promptOnly: Boolean(normalized.promptOnly), markdownOnly: Boolean(normalized.markdownOnly), @@ -629,15 +638,16 @@ function shouldApplyRuleForTaskContext(rule, stage = "") { return true; } - if (rule.markdownOnly) { - return false; - } - const normalizedStage = String(stage || "").trim(); + const isPromptStage = PROMPT_STAGES.has(normalizedStage); const isFinalPromptStage = normalizedStage === "finalPrompt" || normalizedStage === "input.finalPrompt"; const isOutputStage = OUTPUT_STAGES.has(normalizedStage); + if (rule.markdownOnly) { + return isPromptStage; + } + if (isFinalPromptStage) { return rule.promptOnly === true; } @@ -683,7 +693,10 @@ function applyOneRule(input, rule, stage = "") { if (!regex) return { output: input, changed: false, error: "invalid_regex" }; let replacement = rule.replaceString || ""; - if (PROMPT_STAGES.has(stage) && isBeautificationReplace(replacement)) { + if ( + PROMPT_STAGES.has(stage) && + (rule.markdownOnly || isBeautificationReplace(replacement)) + ) { replacement = ""; } diff --git a/tests/task-regex.mjs b/tests/task-regex.mjs index 8bad23c..2a1f010 100644 --- a/tests/task-regex.mjs +++ b/tests/task-regex.mjs @@ -443,7 +443,7 @@ try { placement: [PLACEMENT.USER_INPUT], promptOnly: true, }), - createTavernRule("markdown-only", "/Alpha/g", "M", { + createTavernRule("markdown-only", "/Alpha/g", "M", { placement: [PLACEMENT.USER_INPUT], markdownOnly: true, }), @@ -475,7 +475,7 @@ try { { entries: [] }, "user", ), - "Alpha", + "", ); assert.equal( applyTaskRegex( @@ -499,6 +499,77 @@ try { ), "AI Lore", ); + const markdownInspect = inspectTaskRegexReuse(tavernSemanticsSettings, "extract"); + const markdownRule = markdownInspect.activeRules.find( + (rule) => rule.id === "markdown-only", + ); + assert.equal(markdownRule?.promptReplaceAsEmpty, true); + assert.equal(markdownRule?.effectivePromptReplaceString, ""); + const markdownOnlyFinalPromptSettings = buildSettings({ + sources: { + global: true, + preset: false, + character: false, + }, + }); + setTestContext({ + extensionSettings: { + regex: [ + createTavernRule("markdown-final-strip", "/Decor/g", "Decor", { + placement: [PLACEMENT.USER_INPUT], + markdownOnly: true, + }), + ], + preset_allowed_regex: {}, + character_allowed_regex: [], + }, + }); + initializeHostAdapter({}); + const markdownFinalDebug = { entries: [] }; + assert.equal( + applyTaskRegex( + markdownOnlyFinalPromptSettings, + "extract", + "input.finalPrompt", + "Decor", + markdownFinalDebug, + "user", + ), + "", + ); + assert.deepEqual( + markdownFinalDebug.entries[0].appliedRules.map((item) => item.id), + ["markdown-final-strip"], + ); + setTestContext({ + extensionSettings: { + regex: [ + createTavernRule("user-prompt-only", "/Alpha/g", "A", { + placement: [PLACEMENT.USER_INPUT], + promptOnly: true, + }), + createTavernRule("markdown-only", "/Alpha/g", "M", { + placement: [PLACEMENT.USER_INPUT], + markdownOnly: true, + }), + createTavernRule("output-only", "/Answer/g", "AI", { + placement: [PLACEMENT.AI_OUTPUT], + }), + createTavernRule("world-info-only", "/Lore/g", "SYS", { + placement: [PLACEMENT.WORLD_INFO], + }), + createTavernRule("recent-user", "/User/g", "U", { + placement: [PLACEMENT.USER_INPUT], + }), + createTavernRule("recent-ai", "/Reply/g", "R", { + placement: [PLACEMENT.AI_OUTPUT], + }), + ], + preset_allowed_regex: {}, + character_allowed_regex: [], + }, + }); + initializeHostAdapter({}); assert.equal( applyTaskRegex( tavernSemanticsSettings,