pub mod chunker;
pub mod durable;
pub mod embedding;
pub mod manager;
pub mod recall;
pub mod session;
pub mod snapshot;
pub mod store;
pub mod structured;
pub mod vector;
pub use chunker::{chunk_markdown, Chunk};
pub use durable::{
DurableMemory, DurableMemoryKind, DurableMemoryManager, DurableMemoryManifestEntry,
DurableMemoryPolicy,
};
#[cfg(feature = "sqlite")]
pub use embedding::OpenAiEmbedding;
pub use embedding::{EmbeddingProvider, NoopEmbedding};
pub use manager::MemoryManager;
pub use recall::{RecallPacket, RecallQuery};
pub use session::{
truncate_session_memory_summary, SessionMemoryBudgetingResult, SessionMemoryManager,
SessionMemoryPolicy, SessionMemorySummary, SessionSummarySource,
};
pub use snapshot::{ContentBlock, ConversationMessage, MemoryRole, MemorySnapshot};
#[cfg(feature = "sqlite")]
pub use store::SqliteDurableMemoryStore;
pub use store::{
DurableMemoryStore, FilesystemDurableMemoryStore, FilesystemMemoryStore,
FilesystemSessionMemoryStore, MemoryIndexEntry, MemoryStore, ScoredMemory, SemanticMemoryStore,
SemanticSearchQuery, SessionMemoryStore,
};
pub use structured::{
FactMemory, InstructionMemory, PromptHistoryEntry, TaskMemory, TokenUsageBaseline,
};
pub use vector::{cosine_similarity, hybrid_merge};
use agent_types::LlmError;
use std::{
ffi::OsStr,
path::{Component, Path},
};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum MemoryError {
#[error("invalid configuration: {message}")]
InvalidConfiguration { message: String },
#[error("session memory budget exhausted: {message}")]
SessionMemoryBudgetExhausted { message: String },
#[error("session memory summary parse failed: {message}")]
SessionMemorySummaryParse { message: String },
#[error("invalid session id")]
InvalidSessionId,
#[error("invalid durable memory id")]
InvalidDurableMemoryId,
#[error("current task must not be empty")]
EmptyTask,
#[error("fact key must not be empty")]
EmptyFactKey,
#[error("instruction source must not be empty")]
EmptyInstructionSource,
#[error("durable memory limit exceeded: configured={configured}, actual={actual}")]
DurableMemoryLimitExceeded { configured: usize, actual: usize },
#[error("embedding error: {message}")]
Embedding { message: String },
#[error("io error: {0}")]
Io(#[from] std::io::Error),
#[error("llm error: {0}")]
Llm(#[from] LlmError),
}
pub type MemoryResult<T> = Result<T, MemoryError>;
pub(crate) fn ensure_valid_session_id(session_id: &str) -> MemoryResult<()> {
if is_safe_storage_key(session_id) {
Ok(())
} else {
Err(MemoryError::InvalidSessionId)
}
}
pub(crate) fn ensure_valid_durable_memory_id(memory_id: &str) -> MemoryResult<()> {
if is_safe_storage_key(memory_id) {
Ok(())
} else {
Err(MemoryError::InvalidDurableMemoryId)
}
}
pub(crate) fn invalid_session_id_io_error() -> std::io::Error {
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"session_id must be a safe file name",
)
}
pub(crate) fn invalid_durable_memory_id_io_error() -> std::io::Error {
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"memory_id must be a safe file name",
)
}
fn is_safe_storage_key(value: &str) -> bool {
let trimmed = value.trim();
if trimmed.is_empty() {
return false;
}
let mut components = Path::new(trimmed).components();
matches!(
(components.next(), components.next()),
(Some(Component::Normal(component)), None) if component == OsStr::new(trimmed)
)
}