klieo-memory-sqlite 3.4.0

SQLite-backed implementations of klieo-core's memory traits.
Documentation
//! Persistence integration test: data written via one MemorySqlite
//! handle is visible to a second handle opened on the same file.

use klieo_core::ids::{RunId, ThreadId};
use klieo_core::llm::{Message, Role};
use klieo_core::memory::{Episode, Fact, Scope};
use klieo_memory_sqlite::{DummyEmbedder, MemorySqlite};
use std::sync::Arc;

#[tokio::test]
async fn data_survives_handle_drop_and_reopen() {
    let dir = tempfile::tempdir().unwrap();
    let path = dir.path().join("persist.db");

    let run = RunId::new();
    let thread = ThreadId::new("persist-thread");

    {
        let mem = MemorySqlite::new(&path, Arc::new(DummyEmbedder))
            .await
            .unwrap();
        mem.short_term
            .append(
                thread.clone(),
                Message {
                    role: Role::User,
                    content: "hello from handle 1".into(),
                    tool_calls: vec![],
                    tool_call_id: None,
                },
            )
            .await
            .unwrap();
        mem.long_term
            .remember(
                Scope::Workspace("w1".into()),
                Fact::new("fact from handle 1"),
            )
            .await
            .unwrap();
        mem.episodic
            .record(run, Episode::Started { agent: "h1".into() })
            .await
            .unwrap();
    }

    // Drop handle 1, reopen on same path.
    let mem2 = MemorySqlite::new(&path, Arc::new(DummyEmbedder))
        .await
        .unwrap();

    let loaded = mem2.short_term.load(thread, 10_000).await.unwrap();
    assert_eq!(loaded.len(), 1);
    assert_eq!(loaded[0].content, "hello from handle 1");

    let hits = mem2
        .long_term
        .recall(Scope::Workspace("w1".into()), "anything", 10)
        .await
        .unwrap();
    assert_eq!(hits.len(), 1);
    assert_eq!(hits[0].text, "fact from handle 1");

    let replay = mem2.episodic.replay(run).await.unwrap();
    assert_eq!(replay.len(), 1);
    assert!(matches!(replay[0], Episode::Started { .. }));
}