forked from enderofwings/NexusOS
fix(runtime): improve local service reliability
Close SQLite handles safely on Windows, clean orphaned vectors, normalize Ollama endpoints, and surface model errors without leaking reasoning tags. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -220,6 +220,8 @@ class PersistentMemoryStore:
|
||||
"DELETE FROM settings WHERE key IN ('anthropic_api_key', 'escalation_model')"
|
||||
)
|
||||
|
||||
self._sweep_orphan_msg_vectors(conn)
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
@@ -483,6 +485,10 @@ class PersistentMemoryStore:
|
||||
conn = self._connect()
|
||||
try:
|
||||
cur = conn.cursor()
|
||||
ids = [r["id"] for r in cur.execute(
|
||||
"SELECT id FROM messages WHERE conversation_id = ?", (conversation_id,)
|
||||
).fetchall()]
|
||||
self._delete_message_vectors(conn, ids)
|
||||
cur.execute("DELETE FROM messages WHERE conversation_id = ?", (conversation_id,))
|
||||
cur.execute("DELETE FROM conversations WHERE id = ?", (conversation_id,))
|
||||
conn.commit()
|
||||
@@ -671,6 +677,41 @@ class PersistentMemoryStore:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _delete_message_vectors(self, conn, message_ids) -> None:
|
||||
"""Drop the cached embeddings of messages that are about to be deleted,
|
||||
mirroring the removal into the ANN index — the delete-side counterpart of
|
||||
`_vec_upsert_msg`. Retrieval already ignores orphans (it inner-joins
|
||||
messages), but `messages.id` is AUTOINCREMENT so a stale vector is never
|
||||
overwritten either: without this the table and index only ever grow."""
|
||||
ids = list(message_ids)
|
||||
if not ids:
|
||||
return
|
||||
for i in range(0, len(ids), 500): # stay under SQLite's variable limit
|
||||
batch = ids[i:i + 500]
|
||||
conn.execute(
|
||||
f"DELETE FROM message_vectors WHERE message_id IN ({','.join('?' * len(batch))})",
|
||||
batch,
|
||||
)
|
||||
if self.vec_enabled:
|
||||
try:
|
||||
for mid in ids:
|
||||
conn.execute("DELETE FROM vec_messages WHERE rowid = ?", (mid,))
|
||||
except Exception:
|
||||
pass # index absent / extension unavailable — it's only a mirror
|
||||
|
||||
def _sweep_orphan_msg_vectors(self, conn) -> None:
|
||||
"""One-time repair for databases written before delete_conversation
|
||||
cleaned up after itself: drop vectors whose message is already gone."""
|
||||
try:
|
||||
ids = [r["message_id"] for r in conn.execute(
|
||||
"SELECT v.message_id FROM message_vectors v "
|
||||
"LEFT JOIN messages m ON m.id = v.message_id WHERE m.id IS NULL"
|
||||
).fetchall()]
|
||||
if ids:
|
||||
self._delete_message_vectors(conn, ids)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _backfill_vec_msgs(self, conn, dim: int) -> None:
|
||||
"""Index any message_vectors rows missing from vec_messages."""
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user