/** Sqlite persistence for chats + UI state. */ const LS_CHATS = 'swarm_assistent_chats_v1'; const SAVE_DEBOUNCE_MS = 700; const timers = { chats: new Map(), ui: null }; function normalizeChat(raw) { if (!raw || !raw.id) { return null; } return { id: String(raw.id), title: String(raw.title || 'Новый чат'), createdAt: Number(raw.createdAt) || Date.now(), updatedAt: Number(raw.updatedAt) || Date.now(), messages: Array.isArray(raw.messages) ? raw.messages : [], messages_count: Number(raw.messages_count) || (Array.isArray(raw.messages) ? raw.messages.length : 0), params: raw.params && typeof raw.params === 'object' ? raw.params : null, }; } export function attachPersist(SA, request = SA.request) { async function loadChats() { let chats = []; try { const data = await request('AssistentListChats', { with_messages: true }); chats = (data?.chats || []).map(normalizeChat).filter(Boolean); } catch (e) { console.warn('Assistent: disk chats unavailable', e); return null; } return chats.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0)); } async function getChat(id) { if (!id) { return null; } const data = await request('AssistentGetChat', { id }); return normalizeChat(data?.chat); } async function searchChats(q) { const query = String(q || '').trim(); if (query.length < 2) { return []; } const data = await request('AssistentListChats', { q: query, with_messages: false, limit: 40 }); return (data?.chats || []).map(normalizeChat).filter(Boolean); } function saveChat(chat, { immediate = false } = {}) { const clean = normalizeChat(chat); if (!clean) { return Promise.resolve(null); } const send = () => { timers.chats.delete(clean.id); return request('AssistentSaveChat', { id: clean.id, title: clean.title, messages: clean.messages, params: clean.params, createdAt: clean.createdAt, updatedAt: clean.updatedAt, }); }; if (immediate) { const pending = timers.chats.get(clean.id); if (pending) { clearTimeout(pending); } return send(); } const pending = timers.chats.get(clean.id); if (pending) { clearTimeout(pending); } timers.chats.set(clean.id, setTimeout(() => { send().catch((e) => console.warn('Assistent: chat save failed', clean.id, e)); }, SAVE_DEBOUNCE_MS)); return Promise.resolve(null); } function deleteChat(id) { if (!id) { return Promise.resolve(null); } const pending = timers.chats.get(id); if (pending) { clearTimeout(pending); timers.chats.delete(id); } return request('AssistentDeleteChat', { id }); } async function loadUiState() { try { const data = await request('AssistentGetUiState', {}); const ui = data?.ui_state; return ui && typeof ui === 'object' ? ui : null; } catch (e) { return null; } } function saveUiState(uiState, { immediate = false } = {}) { if (!uiState || typeof uiState !== 'object') { return Promise.resolve(null); } const send = () => { timers.ui = null; return request('AssistentSaveUiState', { ui_state: uiState }); }; if (timers.ui) { clearTimeout(timers.ui); timers.ui = null; } if (immediate) { return send(); } timers.ui = setTimeout(() => { send().catch((e) => console.warn('Assistent: ui-state save failed', e)); }, SAVE_DEBOUNCE_MS); return Promise.resolve(null); } SA.persist = { LS_CHATS, loadChats, getChat, searchChats, saveChat, deleteChat, loadUiState, saveUiState, }; }