直聊的种子历史改成逐条真多轮,不再靠块头文本猜轮次。

一条一个角色下拉加一整句正文,换行原样保留;旧盘里的纯文本在读盘时迁移,切得出轮次的转成条目,切不出的挪进史前设定免得悄悄丢掉。历史编辑器做成共用控件,预设工作台的用例与假历史也用同一套。
This commit is contained in:
2026-10-26 01:09:34 +08:00
parent 860eff59b2
commit 98e51f9c6c
11 changed files with 686 additions and 17 deletions
+33 -4
View File
@@ -1,4 +1,5 @@
import { renderMarkdownToHtml } from "./markdown.js";
import { createHistoryEditor, normalizeHistoryTurns } from "./history-editor.js";
import { planWheelScroll } from "./chat-scroll.js";
import {
bumpKeepStats,
@@ -26,6 +27,7 @@ const EMPTY_SLOTS = {
systemPrompt: "",
loreBefore: "",
seedHistory: "",
seedMessages: [],
loreAfter: "",
postTurn: "",
charName: "",
@@ -118,6 +120,12 @@ let editingTurnId = null;
let editingDraft = "";
/** 复制模式:开=回复可选中、显示复制按钮;关=整张卡片都能拖动(禁用复制) */
let copyMode = loadCopyMode();
/** 种子历史(假历史):编辑器和 slots 共用这一份数组,点「应用」才写盘 */
const seedTurns = [];
/** 旧版种子历史文本:只为了不把老数据的纯文本丢掉(新数据为空) */
let seedLegacyText = "";
/** @type {ReturnType<typeof createHistoryEditor> | null} */
let seedEditor = null;
/** 侧栏收起状态:left = 对话列表,right = 上下文面板 */
let railLeftHidden = false;
let railRightHidden = false;
@@ -389,7 +397,8 @@ function slotsFromEditor() {
return {
systemPrompt: els.shellSystem.value,
loreBefore: els.shellLoreBefore.value,
seedHistory: els.shellSeedHistory.value,
seedHistory: seedLegacyText,
seedMessages: seedTurns.map((turn) => ({ role: turn.role, content: turn.content })),
loreAfter: els.shellLoreAfter.value,
postTurn: els.shellPostTurn.value,
charName: els.shellCharName.value,
@@ -400,12 +409,30 @@ function slotsFromEditor() {
};
}
function mountSeedEditor() {
if (!els.shellSeedHistory || seedEditor) return;
seedEditor = createHistoryEditor({
items: seedTurns,
disabled: true,
addLabel: "+ 加一句",
emptyHint: "空则不占历史;点「+ 加一句」开始写。",
});
els.shellSeedHistory.replaceChildren(seedEditor.el);
}
function fillSeedTurns(value, legacyText) {
seedLegacyText = typeof legacyText === "string" ? legacyText : "";
const turns = normalizeHistoryTurns(value);
seedTurns.splice(0, seedTurns.length, ...turns);
if (seedEditor) seedEditor.redraw();
}
function fillEditor(shellLike) {
const s = shellLike || { name: "", ...EMPTY_SLOTS };
els.shellName.value = s.name || "";
els.shellSystem.value = s.systemPrompt || "";
els.shellLoreBefore.value = s.loreBefore || "";
els.shellSeedHistory.value = s.seedHistory || "";
fillSeedTurns(s.seedMessages, s.seedHistory);
els.shellLoreAfter.value = s.loreAfter || "";
els.shellPostTurn.value = s.postTurn || "";
els.shellCharName.value = s.charName || "";
@@ -420,7 +447,6 @@ function setContextEditorEnabled(enabled, subtitle) {
els.shellName,
els.shellSystem,
els.shellLoreBefore,
els.shellSeedHistory,
els.shellLoreAfter,
els.shellPostTurn,
els.shellCharName,
@@ -432,6 +458,7 @@ function setContextEditorEnabled(enabled, subtitle) {
els.btnClearShell,
];
for (const el of fields) el.disabled = !enabled;
if (seedEditor) seedEditor.setDisabled(!enabled);
if (els.contextSub) {
els.contextSub.textContent =
subtitle || (enabled ? "改完点应用" : "选择或新建后编辑");
@@ -1866,7 +1893,7 @@ function contextFieldsEmpty() {
return (
!els.shellSystem.value.trim() &&
!els.shellLoreBefore.value.trim() &&
!els.shellSeedHistory.value.trim() &&
seedTurns.length === 0 &&
!els.shellLoreAfter.value.trim() &&
!els.shellPostTurn.value.trim()
);
@@ -3223,6 +3250,8 @@ let relayoutTimer = 0;window.addEventListener(
{ passive: true },
);
mountSeedEditor();
loadProfiles()
.then(() => loadChatPrefs())
.then(() => {