聊天与历史
+
x.trim()).filter(Boolean);
}
+ function normalizeKeepTagsInput(text) {
+ const src = csvToArr(text);
+ const out = [];
+ src.forEach(item => {
+ const tag = String(item || '').replace(/^<+|>+$/g, '').toLowerCase();
+ if (!/^[a-z][a-z0-9_-]*$/.test(tag)) return;
+ if (!out.includes(tag)) out.push(tag);
+ });
+ return out;
+ }
function escapeHtml(str) {
return String(str || '').replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"');
@@ -669,6 +684,7 @@
$('ep_wb_pos4').value = String(toBool(cfg.excludeWorldbookPosition4, true));
$('ep_wb_exclude_names').value = arrToCsv(cfg.worldbookExcludeNames);
$('ep_plot_n').value = String(toNum(cfg.plotCount, 2));
+ $('ep_keep_tags').value = arrToCsv(cfg.responseKeepTags || ['plot', 'note']);
$('ep_exclude_tags').value = arrToCsv(cfg.chatExcludeTags);
$('ep_logs_persist').value = String(toBool(cfg.logsPersist, true));
@@ -708,6 +724,7 @@
p.excludeWorldbookPosition4 = toBool($('ep_wb_pos4').value, true);
p.worldbookExcludeNames = csvToArr($('ep_wb_exclude_names').value);
p.plotCount = Math.max(0, Math.floor(toNum($('ep_plot_n').value, 2)));
+ p.responseKeepTags = normalizeKeepTagsInput($('ep_keep_tags').value);
p.chatExcludeTags = csvToArr($('ep_exclude_tags').value);
p.logsPersist = toBool($('ep_logs_persist').value, true);
@@ -761,6 +778,10 @@
const val = $('ep_model_select').value;
if (val) { $('ep_model').value = val; scheduleSave(); }
});
+ $('ep_keep_tags').addEventListener('change', () => {
+ const normalized = normalizeKeepTagsInput($('ep_keep_tags').value);
+ $('ep_keep_tags').value = normalized.join(', ');
+ });
$('ep_add_prompt').addEventListener('click', () => {
cfg.promptBlocks = cfg.promptBlocks || [];
diff --git a/modules/ena-planner/ena-planner.js b/modules/ena-planner/ena-planner.js
index 6d8562d..2b2886c 100644
--- a/modules/ena-planner/ena-planner.js
+++ b/modules/ena-planner/ena-planner.js
@@ -32,6 +32,8 @@ function getDefaultSettings() {
// Plot extraction
plotCount: 2,
+ // Planner response tags to keep, in source order (empty = keep full response)
+ responseKeepTags: ['plot', 'note'],
// Planner prompts (designer)
promptBlocks: structuredClone(DEFAULT_PROMPT_BLOCKS),
@@ -100,6 +102,8 @@ function ensureSettings() {
}
}
deepMerge(s, d);
+ if (!Array.isArray(s.responseKeepTags)) s.responseKeepTags = structuredClone(d.responseKeepTags);
+ else s.responseKeepTags = normalizeResponseKeepTags(s.responseKeepTags);
// Migration: remove old keys that are no longer needed
delete s.includeCharacterLorebooks;
@@ -114,6 +118,20 @@ function ensureSettings() {
return s;
}
+function normalizeResponseKeepTags(tags) {
+ const src = Array.isArray(tags) ? tags : [];
+ const cleaned = [];
+ for (const raw of src) {
+ const t = String(raw || '')
+ .trim()
+ .replace(/^<+|>+$/g, '')
+ .toLowerCase();
+ if (!/^[a-z][a-z0-9_-]*$/.test(t)) continue;
+ if (!cleaned.includes(t)) cleaned.push(t);
+ }
+ return cleaned;
+}
+
async function loadConfig() {
const loaded = await EnaPlannerStorage.get('config', null);
config = (loaded && typeof loaded === 'object') ? loaded : getDefaultSettings();
@@ -878,10 +896,13 @@ function stripThinkBlocks(text) {
return out.trim();
}
-function extractPlotAndNoteInOrder(text) {
+function extractSelectedBlocksInOrder(text, tagNames) {
+ const names = normalizeResponseKeepTags(tagNames);
+ if (!Array.isArray(names) || names.length === 0) return '';
const src = String(text ?? '');
const blocks = [];
- const re = /<(plot|note)\b[^>]*>[\s\S]*?<\/\1>/gi;
+ const escapedNames = names.map(n => n.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
+ const re = new RegExp(`<(${escapedNames.join('|')})\\b[^>]*>[\\s\\S]*?<\\/\\1>`, 'gi');
let m;
while ((m = re.exec(src)) !== null) {
blocks.push(m[0]);
@@ -891,8 +912,9 @@ function extractPlotAndNoteInOrder(text) {
function filterPlannerForInput(rawFull) {
const noThink = stripThinkBlocks(rawFull);
- const onlyPN = extractPlotAndNoteInOrder(noThink);
- if (onlyPN) return onlyPN;
+ const tags = ensureSettings().responseKeepTags;
+ const selected = extractSelectedBlocksInOrder(noThink, tags);
+ if (selected) return selected;
return noThink;
}