remem-ai 0.5.211

Local-first coding agent memory for Claude Code and OpenAI Codex
Documentation
use rusqlite::params;

use super::*;
use crate::retrieval::embedding::EmbeddingBackfillTarget;

#[test]
fn local_model_unavailable_defers_memory_embedding_write() -> Result<()> {
    let conn = setup_vector_conn_with_provider("local")?;
    let model_dir = std::env::temp_dir().join(format!(
        "remem-empty-vector-models-{}-{}",
        std::process::id(),
        chrono::Utc::now().timestamp_nanos_opt().unwrap_or_default()
    ));
    unsafe { std::env::set_var("REMEM_EMBEDDINGS_MODEL_DIR", &model_dir) };
    insert_test_memory(&conn, 1)?;
    ensure_vec_table(&conn)?;

    upsert_memory_embedding(
        &conn,
        1,
        "Credential store",
        "SQLCipher encrypts secrets at rest.",
        "architecture",
        None,
    )?;

    assert_eq!(embedding_count(&conn)?, 0);
    Ok(())
}

#[test]
fn prune_inactive_profiles_requires_complete_active_coverage() -> Result<()> {
    let conn = setup_vector_conn()?;
    for id in 1..=2 {
        insert_test_memory(&conn, id)?;
    }
    ensure_vec_table(&conn)?;
    let old_blob = vec![0u8; 3 * std::mem::size_of::<f32>()];
    for id in 1..=2 {
        conn.execute(
            "INSERT INTO memory_embeddings
             (memory_id, embedding, dimensions, model, content_hash, updated_at_epoch)
             VALUES (?1, ?2, 3, 'old-model', 'old-hash', 1)",
            params![id, &old_blob],
        )?;
    }
    let target = EmbeddingBackfillTarget {
        model: DEFAULT_EMBEDDING_MODEL.to_string(),
        dimensions: EMBEDDING_DIMENSIONS,
    };

    upsert_memory_embedding(
        &conn,
        1,
        "Credential store",
        "SQLCipher encrypts secrets at rest.",
        "architecture",
        None,
    )?;
    let error = prune_inactive_memory_embeddings(&conn, &target).unwrap_err();
    assert!(
        error
            .to_string()
            .contains("before active coverage reaches 100%"),
        "{error:#}"
    );

    upsert_memory_embedding(
        &conn,
        2,
        "Credential store",
        "SQLCipher encrypts secrets at rest.",
        "architecture",
        None,
    )?;
    let report = prune_inactive_memory_embeddings(&conn, &target)?;

    assert_eq!(report.pruned, 2);
    assert_eq!(report.coverage.embedded, 2);
    assert_eq!(report.coverage.total, 2);
    let old_rows: i64 = conn.query_row(
        "SELECT COUNT(*) FROM memory_embeddings WHERE model = 'old-model'",
        [],
        |row| row.get(0),
    )?;
    let active_rows: i64 = conn.query_row(
        "SELECT COUNT(*) FROM memory_embeddings WHERE model = ?1 AND dimensions = ?2",
        params![DEFAULT_EMBEDDING_MODEL, EMBEDDING_DIMENSIONS as i64],
        |row| row.get(0),
    )?;
    assert_eq!(old_rows, 0);
    assert_eq!(active_rows, 2);
    Ok(())
}

#[test]
fn prune_inactive_profiles_requires_fresh_active_rows() -> Result<()> {
    let conn = setup_vector_conn()?;
    for id in 1..=2 {
        insert_test_memory(&conn, id)?;
    }
    ensure_vec_table(&conn)?;
    let active_blob = vec![0u8; EMBEDDING_DIMENSIONS * std::mem::size_of::<f32>()];
    let old_blob = vec![0u8; 3 * std::mem::size_of::<f32>()];
    for id in 1..=2 {
        conn.execute(
            "INSERT INTO memory_embeddings
             (memory_id, embedding, dimensions, model, content_hash, updated_at_epoch)
             VALUES (?1, ?2, ?3, ?4, 'active-old-hash', 1)",
            params![
                id,
                &active_blob,
                EMBEDDING_DIMENSIONS as i64,
                DEFAULT_EMBEDDING_MODEL
            ],
        )?;
        conn.execute(
            "INSERT INTO memory_embeddings
             (memory_id, embedding, dimensions, model, content_hash, updated_at_epoch)
             VALUES (?1, ?2, 3, 'old-model', 'old-hash', 1)",
            params![id, &old_blob],
        )?;
    }
    conn.execute("UPDATE memories SET updated_at_epoch = 10 WHERE id = 1", [])?;
    let target = EmbeddingBackfillTarget {
        model: DEFAULT_EMBEDDING_MODEL.to_string(),
        dimensions: EMBEDDING_DIMENSIONS,
    };

    let error = prune_inactive_memory_embeddings(&conn, &target).unwrap_err();

    assert!(
        error.to_string().contains("missing or stale rows"),
        "{error:#}"
    );
    let old_rows: i64 = conn.query_row(
        "SELECT COUNT(*) FROM memory_embeddings WHERE model = 'old-model'",
        [],
        |row| row.get(0),
    )?;
    assert_eq!(old_rows, 2);
    Ok(())
}