// ═══════════════════════════════════════════════════════════════════════════ // Story Summary - State Store (L0) // StateAtom 存 chat_metadata(持久化) // StateVector 存 IndexedDB(可重建) // ═══════════════════════════════════════════════════════════════════════════ import { saveMetadataDebounced } from '../../../../../../extensions.js'; import { chat_metadata } from '../../../../../../../script.js'; import { stateVectorsTable } from '../data/db.js'; import { EXT_ID } from '../../../core/constants.js'; import { xbLog } from '../../../core/debug-core.js'; const MODULE_ID = 'state-store'; // ═══════════════════════════════════════════════════════════════════════════ // 工具函数 // ═══════════════════════════════════════════════════════════════════════════ export function float32ToBuffer(arr) { return arr.buffer.slice(arr.byteOffset, arr.byteOffset + arr.byteLength); } export function bufferToFloat32(buffer) { return new Float32Array(buffer); } // ═══════════════════════════════════════════════════════════════════════════ // StateAtom 操作(chat_metadata) // ═══════════════════════════════════════════════════════════════════════════ function ensureStateAtomsArray() { chat_metadata.extensions ||= {}; chat_metadata.extensions[EXT_ID] ||= {}; chat_metadata.extensions[EXT_ID].stateAtoms ||= []; return chat_metadata.extensions[EXT_ID].stateAtoms; } /** * 获取当前聊天的所有 StateAtoms */ export function getStateAtoms() { return ensureStateAtomsArray(); } /** * 保存新的 StateAtoms(追加,去重) */ export function saveStateAtoms(atoms) { if (!atoms?.length) return; const arr = ensureStateAtomsArray(); const existing = new Set(arr.map(a => a.atomId)); let added = 0; for (const atom of atoms) { // 有效性检查 if (!atom?.atomId || typeof atom.floor !== 'number' || atom.floor < 0 || !atom.semantic) { xbLog.warn(MODULE_ID, `跳过无效 atom: ${atom?.atomId}`); continue; } if (!existing.has(atom.atomId)) { arr.push(atom); existing.add(atom.atomId); added++; } } if (added > 0) { saveMetadataDebounced(); xbLog.info(MODULE_ID, `存储 ${added} 个 StateAtom`); } } /** * 删除指定楼层及之后的 StateAtoms */ export function deleteStateAtomsFromFloor(floor) { const arr = ensureStateAtomsArray(); const before = arr.length; const filtered = arr.filter(a => a.floor < floor); chat_metadata.extensions[EXT_ID].stateAtoms = filtered; const deleted = before - filtered.length; if (deleted > 0) { saveMetadataDebounced(); xbLog.info(MODULE_ID, `删除 ${deleted} 个 StateAtom (floor >= ${floor})`); } return deleted; } /** * 清空所有 StateAtoms */ export function clearStateAtoms() { const arr = ensureStateAtomsArray(); const count = arr.length; chat_metadata.extensions[EXT_ID].stateAtoms = []; if (count > 0) { saveMetadataDebounced(); xbLog.info(MODULE_ID, `清空 ${count} 个 StateAtom`); } } /** * 获取 StateAtoms 数量 */ export function getStateAtomsCount() { return ensureStateAtomsArray().length; } // ═══════════════════════════════════════════════════════════════════════════ // StateVector 操作(IndexedDB) // ═══════════════════════════════════════════════════════════════════════════ /** * 保存 StateVectors */ export async function saveStateVectors(chatId, items, fingerprint) { if (!chatId || !items?.length) return; const records = items.map(item => ({ chatId, atomId: item.atomId, floor: item.floor, vector: float32ToBuffer(new Float32Array(item.vector)), dims: item.vector.length, fingerprint, })); await stateVectorsTable.bulkPut(records); xbLog.info(MODULE_ID, `存储 ${records.length} 个 StateVector`); } /** * 获取所有 StateVectors */ export async function getAllStateVectors(chatId) { if (!chatId) return []; const records = await stateVectorsTable.where('chatId').equals(chatId).toArray(); return records.map(r => ({ ...r, vector: bufferToFloat32(r.vector), })); } /** * 删除指定楼层及之后的 StateVectors */ export async function deleteStateVectorsFromFloor(chatId, floor) { if (!chatId) return; const deleted = await stateVectorsTable .where('chatId') .equals(chatId) .filter(v => v.floor >= floor) .delete(); if (deleted > 0) { xbLog.info(MODULE_ID, `删除 ${deleted} 个 StateVector (floor >= ${floor})`); } } /** * 清空所有 StateVectors */ export async function clearStateVectors(chatId) { if (!chatId) return; const deleted = await stateVectorsTable.where('chatId').equals(chatId).delete(); if (deleted > 0) { xbLog.info(MODULE_ID, `清空 ${deleted} 个 StateVector`); } } /** * 获取 StateVectors 数量 */ export async function getStateVectorsCount(chatId) { if (!chatId) return 0; return await stateVectorsTable.where('chatId').equals(chatId).count(); }