memoir_core/lib.rs
1// Raised from the default 128 so the compiler can finish proving the worker's
2// spawned future is `Send`: that proof recurses through the falkordb -> redis ->
3// mio TcpStream type tree, which is deep but valid. The future is genuinely
4// `Send`; only the proof depth exceeds the default.
5#![recursion_limit = "256"]
6//! Memoir memory substrate as an embeddable Rust library.
7//!
8//! Memoir stores what an agent is told and derives durable facts from it. A
9//! write is an *episodic* memory (the raw utterance); a background worker runs
10//! LLM extraction over it to produce *semantic* memories (the facts). See
11//! [`memory::MemoryKind`]. Recall reads the semantic layer; the episodic layer
12//! is the audit trail and the source the facts are re-derived from.
13//!
14//! Two contracts govern how that derived knowledge is ranked and corrected.
15//!
16//! # Selection
17//!
18//! Retrieval is not just cosine similarity. Each semantic memory carries a
19//! [`memory::Confidence`] (how sure the extractor was) and, once the categorize
20//! worker runs, a category label. [`client::Client::query`] blends these signals
21//! — cosine, confidence, recency, and a category bonus — via a
22//! [`client::RankingStrategy`] with tunable [`client::BlendWeights`]. Use
23//! [`client::Client::search`] for raw nearest-neighbor hits, `query` when you
24//! want ranked, prompt-shaped context. Hard filters (`min_confidence`,
25//! `category`) exclude rows; the blend *weights* them — distinct mechanisms.
26//!
27//! # Correction
28//!
29//! Semantic memory is **always derived, never hand-written** — there is no API
30//! to edit a semantic row's content. A consumer corrects a wrong fact by
31//! *teaching*: [`client::Client::feedback`] supplies the correction, and memoir
32//! re-derives from the episodic source. Editing the episodic source itself
33//! ([`client::Client::edit`]) cascades the same way. Both retire the stale
34//! derived rows and re-extract — see [`memory::RetirementReason`] for why a
35//! retirement is `Rejected` (a wrong extraction, counts against extraction
36//! accuracy) versus `Stale` (the source changed, does not). Retired rows are
37//! kept (not deleted) so accuracy is measurable via
38//! [`client::Client::extraction_stats`].
39//!
40//! # Categorization
41//!
42//! The category label is populated by a zero-shot NLI classifier
43//! ([`nli::NliClassifier`]), opt-in via [`nli::NliConfig`] on the client builder.
44//! Without it, categorization is skipped and the category-bonus blend term is
45//! inert.
46
47pub mod client;
48pub mod embedding;
49pub mod graph;
50pub mod jobs;
51pub mod llm;
52pub mod memory;
53pub mod migration;
54pub mod nli;
55pub mod store;
56pub mod vector;
57
58#[doc(inline)]
59pub use client::{Client, DEFAULT_SYSTEM_PROMPT};
60
61#[doc(inline)]
62pub use nli::{ExecutionProvider, NliClassifier, NliConfig, NliError, ScoredLabel};
63
64#[doc(inline)]
65pub use llm::DEFAULT_EXTRACTION_PROMPT;
66
67/// Default Postgres schema for memoir-core's tables.
68///
69/// Consumers configuring a custom schema via `Client::builder().schema(...)`
70/// can fall back to this when no override is supplied.
71pub use migration::DEFAULT_SCHEMA;