mirror of
https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git
synced 2026-05-15 22:30:38 +08:00
Fix prompt preview semantics for display regex rules
This commit is contained in:
16
panel.js
16
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 ? `<br>${_escHtml(source.reason)}` : ""}
|
||||
</div>
|
||||
<div class="bme-task-section-label">本来源当前生效规则</div>
|
||||
${_renderRegexReuseRuleList(source.rules, "该来源当前没有进入任务链的复用规则")}
|
||||
<div class="bme-task-section-label">被跳过的规则</div>
|
||||
${_renderRegexReuseRuleList(source.ignoredRules, "没有被额外跳过的规则")}
|
||||
<div class="bme-task-section-label">本来源规则总览</div>
|
||||
${_renderRegexReuseRuleList(source.previewRules || source.rules, "该来源当前没有可展示的规则")}
|
||||
<div class="bme-task-section-label">未纳入最终任务链</div>
|
||||
${_renderRegexReuseRuleList(source.ignoredRules, "没有额外被排除的规则")}
|
||||
</details>
|
||||
`).join("")
|
||||
: `<div class="bme-task-empty">当前没有可展示的酒馆正则来源。</div>`
|
||||
@@ -3996,7 +4000,7 @@ function _buildRegexReusePopupContent(snapshot = {}) {
|
||||
<div class="bme-config-card">
|
||||
<div class="bme-config-card-title">汇总后的复用规则</div>
|
||||
<div class="bme-config-card-subtitle">
|
||||
这是经过来源开关、allowlist 和去重后,准备进入当前任务链的 Tavern 规则集合。
|
||||
这是经过来源开关、allowlist 和去重后,进入 ST-BME 任务链的 Tavern 规则集合。展示/美化类规则在请求阶段会按空字符串替换。
|
||||
</div>
|
||||
${_renderRegexReuseRuleList(activeRules, "当前没有复用到任何酒馆正则")}
|
||||
</div>
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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: [
|
||||
|
||||
Reference in New Issue
Block a user