Spaces:
Runtime error
Runtime error
| /** | |
| * db/memoryVec.ts β CRUD for memory vector metadata and reindex state. | |
| * | |
| * Plan 21 β Memory Engine Redesign. | |
| * Raw SQL is allowed here (Hard Rule #5 β src/lib/db/ domain module). | |
| * | |
| * This module manages: | |
| * - `memory_vec_meta`: singleton row tracking the active embedding dim/signature/reset | |
| * - `memories.needs_reindex`: flag for lazy backfill of missing/stale vectors | |
| */ | |
| import { getDbInstance } from "./core"; | |
| // ββββββββββββββββ Types ββββββββββββββββ | |
| export interface MemoryVecMeta { | |
| activeDim: number | null; | |
| embeddingSignature: string | null; | |
| lastResetAt: string | null; | |
| vecLoaded: boolean; | |
| } | |
| // ββββββββββββββββ memory_vec_meta ββββββββββββββββ | |
| /** | |
| * Get the singleton memory_vec_meta row. | |
| * Returns defaults if the row is absent (e.g. migration not yet applied on | |
| * an in-memory test DB that ran without the migration file). | |
| */ | |
| export function getMemoryVecMeta(): MemoryVecMeta { | |
| const db = getDbInstance(); | |
| const row = db | |
| .prepare( | |
| "SELECT active_dim, embedding_signature, last_reset_at, vec_loaded FROM memory_vec_meta WHERE id = 1" | |
| ) | |
| .get() as | |
| | { | |
| active_dim: number | null; | |
| embedding_signature: string | null; | |
| last_reset_at: string | null; | |
| vec_loaded: number; | |
| } | |
| | undefined; | |
| if (!row) { | |
| return { | |
| activeDim: null, | |
| embeddingSignature: null, | |
| lastResetAt: null, | |
| vecLoaded: false, | |
| }; | |
| } | |
| return { | |
| activeDim: row.active_dim, | |
| embeddingSignature: row.embedding_signature, | |
| lastResetAt: row.last_reset_at, | |
| vecLoaded: row.vec_loaded === 1, | |
| }; | |
| } | |
| /** | |
| * Update one or more fields in the singleton memory_vec_meta row. | |
| * Uses INSERT OR REPLACE to handle the case where the row is missing | |
| * (e.g. called before or during migration on a test DB). | |
| */ | |
| export function setMemoryVecMeta(meta: Partial<MemoryVecMeta>): void { | |
| const db = getDbInstance(); | |
| // Read current values first so we can merge (partial update pattern). | |
| const current = getMemoryVecMeta(); | |
| const activeDim = "activeDim" in meta ? meta.activeDim ?? null : current.activeDim; | |
| const embeddingSignature = | |
| "embeddingSignature" in meta | |
| ? meta.embeddingSignature ?? null | |
| : current.embeddingSignature; | |
| const lastResetAt = | |
| "lastResetAt" in meta ? meta.lastResetAt ?? null : current.lastResetAt; | |
| const vecLoaded = | |
| "vecLoaded" in meta ? (meta.vecLoaded ? 1 : 0) : current.vecLoaded ? 1 : 0; | |
| db.prepare( | |
| `INSERT OR REPLACE INTO memory_vec_meta | |
| (id, active_dim, embedding_signature, last_reset_at, vec_loaded) | |
| VALUES (1, ?, ?, ?, ?)` | |
| ).run(activeDim, embeddingSignature, lastResetAt, vecLoaded); | |
| } | |
| // ββββββββββββββββ memories.needs_reindex ββββββββββββββββ | |
| /** | |
| * Mark a single memory as needing reindex (or clear the flag). | |
| */ | |
| export function markMemoryNeedsReindex(id: string, needs: boolean): void { | |
| const db = getDbInstance(); | |
| db.prepare("UPDATE memories SET needs_reindex = ? WHERE id = ?").run(needs ? 1 : 0, id); | |
| } | |
| /** | |
| * Mark ALL memories as needing reindex. | |
| * Returns the number of rows affected. | |
| */ | |
| export function markAllMemoriesNeedReindex(): number { | |
| const db = getDbInstance(); | |
| const result = db.prepare("UPDATE memories SET needs_reindex = 1").run(); | |
| return result.changes; | |
| } | |
| /** | |
| * Get a batch of memories that need reindex, ordered by creation date ascending. | |
| * Returns id, content, and key for each memory so the vector can be regenerated. | |
| */ | |
| export function getMemoryReindexQueue( | |
| limit: number | |
| ): Array<{ id: string; content: string; key: string }> { | |
| const db = getDbInstance(); | |
| return db | |
| .prepare( | |
| `SELECT id, content, COALESCE(key, '') AS key | |
| FROM memories | |
| WHERE needs_reindex = 1 | |
| ORDER BY created_at ASC | |
| LIMIT ?` | |
| ) | |
| .all(limit) as Array<{ id: string; content: string; key: string }>; | |
| } | |
| /** | |
| * Count how many memories currently have needs_reindex = 1. | |
| */ | |
| export function countMemoryReindexPending(): number { | |
| const db = getDbInstance(); | |
| const row = db | |
| .prepare("SELECT COUNT(*) AS cnt FROM memories WHERE needs_reindex = 1") | |
| .get() as { cnt: number }; | |
| return row.cnt; | |
| } | |