mirror of
https://github.com/Wx-2025/ST-Amily2-Chat-Optimisation.git
synced 2026-06-19 08:45:51 +00:00
release: v2.2.8 [2026-06-16 15:53:20]
### 新功能 - **填表记录 · 版本恢复**(填表设置面板「回退重填」旁新增「填表记录」按钮):针对"模型填表前把整张表删空 / 误删大量内容"的反馈,提供一键找回。 - **零新存储**:直接复用各楼层 `extra.amily2_tables_data` 里逐轮继承的表格快照——历史本就在聊天中,无需另建存储或元数据 - 点开列出所有带快照的楼层(最新在上),可**展开预览**每一版的表格内容(CSV)后再决定 - **恢复某版本**:把该楼层快照设为当前状态,并清除其**之后**所有楼层的快照与填表标记 hash——使该版本成为最新有效状态,后续楼层下轮自动重填会从恢复点往前重建(赌模型不再抽风) - 「回退重填」按钮保留,但版本恢复是更安全的找回路径 ### 重构 - 抽出 `_normalizeTableState` 共用旧存档字段归一逻辑,`loadTables` 与"恢复快照"复用,消除重复 ---
This commit is contained in:
@@ -141,6 +141,11 @@ export function getMemoryState() {
|
||||
return getState();
|
||||
}
|
||||
|
||||
// 【死代码·保留标注】loadMemoryState / saveMemoryState 原为 super-memory 的 metadata
|
||||
// 状态恢复链路服务(saveStateToMetadata / tryRestoreStateFromMetadata)。该链路在
|
||||
// v2.2.7(commit 62b37f2)确认为死代码后停用——msg.metadata 非 ST 持久化字段,
|
||||
// 写入即蒸发。这两个函数随之无调用方(唯一引用在 super-memory/manager.js 已注释段内)。
|
||||
// 属原作者代码体系,功能本身正确无副作用,按惯例保留并标注,待确认无后续用途再清。
|
||||
export function loadMemoryState(state) {
|
||||
if (!state) return;
|
||||
setState(state);
|
||||
@@ -264,6 +269,37 @@ function getDefaultTables() {
|
||||
|
||||
// ── 加载 ──────────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* 表格状态字段兼容性归一(loadTables 与 恢复快照 共用)。
|
||||
* 旧存档可能缺 note / rule_* / charLimitRules / rowStatuses 等字段,统一补齐。
|
||||
* @param {Array} state TableState(会被原地修改并返回)
|
||||
*/
|
||||
function _normalizeTableState(state) {
|
||||
state.forEach(table => {
|
||||
if (table.note === undefined) table.note = '无';
|
||||
if (table.rule_add === undefined) table.rule_add = '允许';
|
||||
if (table.rule_delete === undefined) table.rule_delete = '允许';
|
||||
if (table.rule_update === undefined) table.rule_update = '允许';
|
||||
|
||||
// 多列规则兼容
|
||||
if (table.charLimitRule && !table.charLimitRules) {
|
||||
table.charLimitRules = {};
|
||||
if (table.charLimitRule.columnIndex !== -1 && table.charLimitRule.limit > 0) {
|
||||
table.charLimitRules[table.charLimitRule.columnIndex] = table.charLimitRule.limit;
|
||||
}
|
||||
}
|
||||
delete table.charLimitRule;
|
||||
|
||||
if (table.rowLimitRule === undefined) table.rowLimitRule = 0;
|
||||
if (table.columnWidths === undefined) table.columnWidths = [];
|
||||
|
||||
if (!table.rowStatuses) {
|
||||
table.rowStatuses = Array(table.rows.length).fill('normal');
|
||||
}
|
||||
});
|
||||
return state;
|
||||
}
|
||||
|
||||
export function loadTables(stopIndex = -1) {
|
||||
const context = getContext();
|
||||
|
||||
@@ -274,30 +310,7 @@ export function loadTables(stopIndex = -1) {
|
||||
const message = context.chat[i];
|
||||
if (message.extra && message.extra[TABLE_DATA_KEY]) {
|
||||
log(`在第 ${i} 条消息中找到基准表格数据。`, 'info');
|
||||
let loadedState = JSON.parse(JSON.stringify(message.extra[TABLE_DATA_KEY]));
|
||||
|
||||
loadedState.forEach(table => {
|
||||
if (table.note === undefined) table.note = '无';
|
||||
if (table.rule_add === undefined) table.rule_add = '允许';
|
||||
if (table.rule_delete === undefined) table.rule_delete = '允许';
|
||||
if (table.rule_update === undefined) table.rule_update = '允许';
|
||||
|
||||
// 多列规则兼容
|
||||
if (table.charLimitRule && !table.charLimitRules) {
|
||||
table.charLimitRules = {};
|
||||
if (table.charLimitRule.columnIndex !== -1 && table.charLimitRule.limit > 0) {
|
||||
table.charLimitRules[table.charLimitRule.columnIndex] = table.charLimitRule.limit;
|
||||
}
|
||||
}
|
||||
delete table.charLimitRule;
|
||||
|
||||
if (table.rowLimitRule === undefined) table.rowLimitRule = 0;
|
||||
if (table.columnWidths === undefined) table.columnWidths = [];
|
||||
|
||||
if (!table.rowStatuses) {
|
||||
table.rowStatuses = Array(table.rows.length).fill('normal');
|
||||
}
|
||||
});
|
||||
const loadedState = _normalizeTableState(JSON.parse(JSON.stringify(message.extra[TABLE_DATA_KEY])));
|
||||
|
||||
setState(loadedState);
|
||||
dispatchAllTablesUpdate();
|
||||
@@ -597,6 +610,79 @@ export async function rollbackAndRefill() {
|
||||
}
|
||||
}
|
||||
|
||||
// ── 填表记录(版本恢复) ────────────────────────────────────────────────────
|
||||
// 复用各楼层 extra 里逐轮继承的 amily2_tables_data 快照,无需新建存储。
|
||||
|
||||
const PROCESS_HASH_KEY = 'amily2_process_hash';
|
||||
|
||||
/**
|
||||
* 列出当前聊天里所有带表格快照的楼层(升序,最旧→最新)。
|
||||
* @returns {Array<{index:number, isUser:boolean, preview:string, tableCount:number, rowCount:number}>}
|
||||
*/
|
||||
export function listFillSnapshots() {
|
||||
const context = getContext();
|
||||
if (!context || !context.chat) return [];
|
||||
const result = [];
|
||||
context.chat.forEach((msg, index) => {
|
||||
const snap = msg.extra?.[TABLE_DATA_KEY];
|
||||
if (snap && Array.isArray(snap)) {
|
||||
const rowCount = snap.reduce((acc, t) => acc + (t.rows?.length || 0), 0);
|
||||
result.push({
|
||||
index,
|
||||
isUser: !!msg.is_user,
|
||||
preview: (msg.mes || '').replace(/\s+/g, ' ').slice(0, 30),
|
||||
tableCount: snap.length,
|
||||
rowCount,
|
||||
});
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/** 把指定楼层的快照渲染成 CSV 文本(供预览)。 */
|
||||
export function getSnapshotCsv(floorIndex) {
|
||||
const context = getContext();
|
||||
const snap = context?.chat?.[floorIndex]?.extra?.[TABLE_DATA_KEY];
|
||||
if (!snap) return '';
|
||||
return tablesToCsv(_normalizeTableState(JSON.parse(JSON.stringify(snap))));
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复到指定楼层的表格快照:把该快照设为当前状态,并清除其**之后**所有楼层的
|
||||
* 快照与填表标记 hash——让该楼层成为最新有效状态,其后楼层无 hash → 下轮自动
|
||||
* 重填会从恢复点往前重建。用于救回"模型把表删空"等场景。
|
||||
* @param {number} floorIndex
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
export async function restoreToSnapshot(floorIndex) {
|
||||
const context = getContext();
|
||||
if (!context || !context.chat) return false;
|
||||
const snap = context.chat[floorIndex]?.extra?.[TABLE_DATA_KEY];
|
||||
if (!snap) {
|
||||
toastr.error('该楼层没有可恢复的表格快照。');
|
||||
return false;
|
||||
}
|
||||
|
||||
const restored = _normalizeTableState(JSON.parse(JSON.stringify(snap)));
|
||||
setState(restored);
|
||||
|
||||
// 从 floorIndex+1 起,清掉所有更新楼层的快照与 hash
|
||||
let clearedSnap = 0;
|
||||
for (let i = floorIndex + 1; i < context.chat.length; i++) {
|
||||
const e = context.chat[i].extra;
|
||||
if (!e) continue;
|
||||
if (e[TABLE_DATA_KEY] !== undefined) { delete e[TABLE_DATA_KEY]; clearedSnap++; }
|
||||
if (e[PROCESS_HASH_KEY] !== undefined) delete e[PROCESS_HASH_KEY];
|
||||
}
|
||||
|
||||
await saveChat();
|
||||
dispatchAllTablesUpdate();
|
||||
renderTables();
|
||||
updateOrInsertTableInChat();
|
||||
log(`已恢复到第 ${floorIndex + 1} 楼的表格快照,清理其后 ${clearedSnap} 条快照与填表标记。`, 'success');
|
||||
return true;
|
||||
}
|
||||
|
||||
// ── 杂项 ──────────────────────────────────────────────────────────────────
|
||||
|
||||
export function isCurrentTablesEmpty() {
|
||||
|
||||
Reference in New Issue
Block a user