use std::time::Duration;
use memoir_core::client::{Client, DEFAULT_SYSTEM_PROMPT};
use memoir_core::memory::{ForgetTarget, Scope};
type BoxError = Box<dyn std::error::Error + Send + Sync>;
#[tokio::main(flavor = "multi_thread", worker_threads = 2)]
async fn main() -> Result<(), BoxError> {
tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("memoir_core=info,info")),
)
.init();
let database_url = std::env::var("DATABASE_URL")
.map_err(|_| "DATABASE_URL must be set (e.g. postgres://postgres:postgres@localhost:54321/memoir_service_test)")?;
let qdrant_url = std::env::var("QDRANT_URL")
.map_err(|_| "QDRANT_URL must be set (e.g. http://localhost:6334)")?;
let example_schema = format!("memoir_example_{}", std::process::id());
println!("→ Building memoir Client (schema = {example_schema})...");
let client = Client::builder()
.database_url(database_url)
.qdrant(qdrant_url)
.schema(example_schema.clone())
.system_prompt(DEFAULT_SYSTEM_PROMPT)
.build()
.await?;
println!("→ Applying memoir migrations...");
client.migrate().await?;
println!("→ Spawning background worker...");
let worker = client.spawn_worker().start().await?;
let scope = Scope {
agent_id: "example-agent".to_string(),
org_id: "example-org".to_string(),
user_id: "example-user".to_string(),
};
println!("→ Writing three episodic memories...");
let _ = client.remember("the user is learning Rust", scope.clone()).await?;
let _ = client
.remember("the user prefers the bon crate for builders", scope.clone())
.await?;
let _ = client
.remember("the user is building a memory substrate called Memoir", scope.clone())
.await?;
println!("→ Waiting briefly for the background indexer...");
tokio::time::sleep(Duration::from_secs(2)).await;
let memories = client
.search("what is the user working on?", scope.clone())
.limit(5)
.await?;
println!();
println!("=== Memories (Display rendering) ===");
println!("{memories}");
if let Some(first) = memories.list().first() {
let row = client.recall(&first.pid).await?;
println!("=== Recalled pid={} ===", row.pid);
println!("content: {}", row.content);
println!("kind: {}", row.kind);
println!("created_at: {}", row.created_at);
println!();
}
println!("→ Cleaning up — forgetting the entire example scope...");
let deleted = client.forget(ForgetTarget::Scope(scope)).await?;
println!("Deleted {} memories.", deleted.len());
println!("→ Shutting down worker...");
worker.shutdown().await;
println!();
println!("Done. To run again, just re-invoke the example — each run uses");
println!("a unique schema name derived from the process id.");
Ok(())
}