Store Assistent chats, UI state, and taste in sqlite.
Runtime session data belongs in one DB so History can FTS-search and follow the volume; persona overlays and sidecar cards stay files. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -427,6 +427,23 @@
|
||||
letter-spacing: 0.03em;
|
||||
}
|
||||
|
||||
.sa-chats-search {
|
||||
appearance: none;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid color-mix(in srgb, currentColor 22%, transparent);
|
||||
background: color-mix(in srgb, #000 28%, transparent);
|
||||
color: inherit;
|
||||
border-radius: 0.35rem;
|
||||
padding: 0.35rem 0.5rem;
|
||||
font: inherit;
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
|
||||
.sa-chats-search:focus {
|
||||
outline: 1px solid color-mix(in srgb, #6cf 55%, currentColor);
|
||||
}
|
||||
|
||||
.sa-chats-panel-hint {
|
||||
font-size: 0.72rem;
|
||||
opacity: 0.65;
|
||||
|
||||
+2
-2
@@ -4047,7 +4047,7 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills fields the browser has never seen from Assistent/ui-state.json, so a fresh
|
||||
* Fills fields the browser has never seen from sqlite ui_state, so a fresh
|
||||
* browser on the same volume inherits the previous session. Existing localStorage wins.
|
||||
* auto_download is only ever restored when it is off — the danger flag stays opt-in.
|
||||
*/
|
||||
@@ -5361,7 +5361,7 @@
|
||||
}
|
||||
const remoteUpdated = remote.updated || 0;
|
||||
const localUpdated = state.taste?.updated || 0;
|
||||
// Disk taste.json is the source of truth; localStorage only wins when it is strictly newer.
|
||||
// sqlite taste is the source of truth; localStorage only wins when it is strictly newer.
|
||||
const localEmpty = !localUpdated
|
||||
&& !(state.taste?.styles?.length || state.taste?.likes?.length || state.taste?.avoid?.length);
|
||||
if (localEmpty || remoteUpdated >= localUpdated) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Swarm Assistent — disk persistence for chats + UI state (Assistent/chats/, Assistent/ui-state.json).
|
||||
* Swarm Assistent — sqlite persistence for chats + UI state (Assistent/memory/assistent.sqlite).
|
||||
* Loaded after assistent.api.js and before assistent.js.
|
||||
*/
|
||||
window.SA = window.SA || {};
|
||||
@@ -40,6 +40,7 @@ window.SA = window.SA || {};
|
||||
createdAt: Number(raw.createdAt) || Date.now(),
|
||||
updatedAt: Number(raw.updatedAt) || Number(raw.createdAt) || 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,
|
||||
};
|
||||
}
|
||||
@@ -74,7 +75,7 @@ window.SA = window.SA || {};
|
||||
return local;
|
||||
}
|
||||
|
||||
/** Disk chats, newest first. Falls back to a localStorage migration when the volume is empty. */
|
||||
/** Sqlite chats, newest first. Falls back to a localStorage migration when the store is empty. */
|
||||
async function loadChats() {
|
||||
let chats = [];
|
||||
try {
|
||||
@@ -103,6 +104,15 @@ window.SA = window.SA || {};
|
||||
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) {
|
||||
@@ -183,6 +193,7 @@ window.SA = window.SA || {};
|
||||
LS_CHATS,
|
||||
loadChats,
|
||||
getChat,
|
||||
searchChats,
|
||||
saveChat,
|
||||
deleteChat,
|
||||
loadUiState,
|
||||
|
||||
Reference in New Issue
Block a user