Skip to main content

EpisodicStore

Struct EpisodicStore 

Source
pub struct EpisodicStore { /* private fields */ }
Expand description

Stores episodic (event-based) memories for agents, ordered by insertion time.

§Guarantees

  • Thread-safe via Arc<Mutex<_>>
  • Ordered: recall returns items in descending importance order
  • Bounded by optional per-agent capacity
  • O(1) agent lookup via per-agent HashMap index
  • Automatic expiry via optional max_age_hours

Implementations§

Source§

impl EpisodicStore

Source

pub fn new() -> Self

Create a new unbounded episodic store without decay.

Source

pub fn builder() -> EpisodicStoreBuilder

Return a fluent builder to construct an EpisodicStore with any combination of options.

Source

pub fn with_decay(policy: DecayPolicy) -> Self

Create a new episodic store with the given decay policy.

Source

pub fn with_decay_and_recall_policy( decay: DecayPolicy, recall: RecallPolicy, ) -> Self

Create a new episodic store with both a decay policy and a recall policy.

§Warning

When recall is RecallPolicy::Hybrid, decay is applied before scoring, producing a double time penalty. See RecallPolicy docs for details. Consider using the builder to configure only one of these time-based mechanisms.

Source

pub fn with_recall_policy(policy: RecallPolicy) -> Self

Create a new episodic store with the given recall policy.

Source

pub fn with_per_agent_capacity(capacity: usize) -> Self

Create a new episodic store with the given per-agent capacity limit.

When an agent exceeds this capacity, the lowest-importance item for that agent is evicted.

§Soft-limit semantics

The capacity is a soft limit. During each add_episode call the new item is inserted first, and only then is the lowest-importance item evicted if the count exceeds capacity. This means the store momentarily holds capacity + 1 items per agent while eviction is in progress. The newly added item is never the one evicted regardless of its importance score.

Concurrent calls to add_episode may briefly exceed the cap by more than one item before each call performs its own eviction sweep.

Source

pub fn try_with_per_agent_capacity( capacity: usize, ) -> Result<Self, AgentRuntimeError>

Create a new episodic store with a per-agent capacity limit, without panicking.

Returns Err if capacity == 0. Prefer this over with_per_agent_capacity in user-facing code where a zero capacity should be a recoverable error rather than a panic.

Source

pub fn with_max_age(max_age_hours: f64) -> Result<Self, AgentRuntimeError>

Create a new episodic store with an absolute age limit.

Items older than max_age_hours are automatically purged on the next recall or add_episode call for the owning agent.

§Arguments
  • max_age_hours — maximum memory age in hours; must be > 0
Source

pub fn with_eviction_policy(policy: EvictionPolicy) -> Self

Create a new episodic store with the given eviction policy.

Source

pub fn add_episode( &self, agent_id: AgentId, content: impl Into<String> + Debug, importance: f32, ) -> Result<MemoryId, AgentRuntimeError>

Record a new episode for the given agent.

§Returns

The MemoryId of the newly created memory item.

§Errors

Returns Err(AgentRuntimeError::Memory) only if the internal mutex is poisoned (extremely unlikely in normal operation; see recover_lock).

§Capacity enforcement

If the store was created with with_per_agent_capacity, the item is always inserted first. If the agent’s item count then exceeds the cap, the single lowest-importance item for that agent is evicted. See with_per_agent_capacity for the full soft-limit semantics.

Source

pub fn add_episode_with_tags( &self, agent_id: AgentId, content: impl Into<String> + Debug, importance: f32, tags: Vec<String>, ) -> Result<MemoryId, AgentRuntimeError>

Add an episode with associated tags.

Convenience wrapper around add_episode that accepts a tag list in the same call. Episode capacity eviction follows the same rules as add_episode.

Source

pub fn remove_by_id( &self, agent_id: &AgentId, id: &MemoryId, ) -> Result<bool, AgentRuntimeError>

Remove a specific episode by its MemoryId.

Returns Ok(true) if the episode was found and removed, Ok(false) if no episode with that id exists for agent_id.

Source

pub fn update_tags_by_id( &self, agent_id: &AgentId, id: &MemoryId, new_tags: Vec<String>, ) -> Result<bool, AgentRuntimeError>

Update the tags of an episode identified by its MemoryId.

Returns Ok(true) if found and updated, Ok(false) otherwise.

Source

pub fn max_importance_for( &self, agent_id: &AgentId, ) -> Result<Option<f32>, AgentRuntimeError>

Return the highest importance score across all episodes for agent_id.

Returns None if the agent has no stored episodes.

Source

pub fn count_for(&self, agent_id: &AgentId) -> Result<usize, AgentRuntimeError>

Return the number of episodes stored for agent_id.

Cheaper than recall(agent, usize::MAX)?.len() because it does not sort, clone, or increment recall counts.

Source

pub fn has_agent(&self, agent_id: &AgentId) -> Result<bool, AgentRuntimeError>

Return true if the store contains at least one episode for agent_id.

Cheaper than count_for(agent_id)? > 0 because no heap allocation occurs.

Source

pub fn agents_with_min_episodes( &self, min: usize, ) -> Result<Vec<AgentId>, AgentRuntimeError>

Return the IDs of agents that have at least min episodes.

Source

pub fn total_episode_count(&self) -> Result<usize, AgentRuntimeError>

Return the total number of episodes stored across all agents.

Source

pub fn episode_count_for( &self, agent_id: &AgentId, ) -> Result<usize, AgentRuntimeError>

Return the number of episodes stored for the given agent.

Returns 0 if the agent has no recorded episodes.

Source

pub fn agent_with_most_episodes( &self, ) -> Result<Option<AgentId>, AgentRuntimeError>

Return the AgentId of the agent with the most stored episodes, or None if the store is empty.

Source

pub fn agents(&self) -> Result<Vec<AgentId>, AgentRuntimeError>

Return all agent IDs that have at least one stored episode, sorted.

Source

pub fn max_importance_overall(&self) -> Result<Option<f32>, AgentRuntimeError>

Return the highest importance value across all stored episodes, or None if the store is empty.

Source

pub fn importance_variance_for( &self, agent_id: &AgentId, ) -> Result<f64, AgentRuntimeError>

Return the variance of importance scores for the given agent’s episodes.

Returns 0.0 when the agent has fewer than two episodes.

Source

pub fn recall_top_n( &self, agent_id: &AgentId, n: usize, ) -> Result<Vec<MemoryItem>, AgentRuntimeError>

Return up to n episodes for agent_id sorted by descending importance without incrementing recall counts or applying decay.

Use this for read-only importance-ranked snapshots.

Source

pub fn filter_by_importance( &self, agent_id: &AgentId, min: f32, max: f32, ) -> Result<Vec<MemoryItem>, AgentRuntimeError>

Return all episodes for agent_id whose importance is within [min_inclusive, max_inclusive], sorted by descending importance.

Source

pub fn retain_top_n( &self, agent_id: &AgentId, n: usize, ) -> Result<usize, AgentRuntimeError>

Keep only the n most-important episodes for agent_id, removing the rest. Returns the number of episodes that were removed.

If the agent has n or fewer episodes already, nothing is removed.

Source

pub fn most_recent( &self, agent_id: &AgentId, ) -> Result<Option<MemoryItem>, AgentRuntimeError>

Return the most recently stored episode for agent_id, or None if the agent has no episodes.

“Most recent” is defined as the last element in the stored list, which matches insertion order.

Source

pub fn max_importance( &self, agent_id: &AgentId, ) -> Result<Option<f32>, AgentRuntimeError>

Return the highest importance score for agent_id, or None if the agent has no episodes.

Source

pub fn min_importance( &self, agent_id: &AgentId, ) -> Result<Option<f32>, AgentRuntimeError>

Return the lowest importance score for agent_id, or None if the agent has no episodes.

Source

pub fn count_above_importance( &self, agent_id: &AgentId, threshold: f32, ) -> Result<usize, AgentRuntimeError>

Count episodes for agent_id whose importance is strictly greater than threshold.

Returns 0 if the agent has no episodes.

Source

pub fn most_recalled( &self, agent_id: &AgentId, ) -> Result<Option<MemoryItem>, AgentRuntimeError>

Return the episode with the highest recall_count for agent_id.

Returns None if the agent has no stored episodes. When multiple episodes tie for the maximum recall count, any one of them may be returned.

Source

pub fn importance_avg( &self, agent_id: &AgentId, ) -> Result<f32, AgentRuntimeError>

Return the arithmetic mean importance for agent_id, or 0.0 if the agent has no stored episodes.

Source

pub fn deduplicate_content( &self, agent_id: &AgentId, ) -> Result<usize, AgentRuntimeError>

Remove duplicate episodes (same content) for agent_id, keeping only the episode with the highest importance for each distinct content string.

Returns the number of episodes removed.

Source

pub fn agent_ids(&self) -> Result<Vec<AgentId>, AgentRuntimeError>

Return all AgentIds that have at least one stored episode.

Source

pub fn find_by_content( &self, agent_id: &AgentId, pattern: &str, ) -> Result<Vec<MemoryItem>, AgentRuntimeError>

Return all episodes for agent_id whose content contains pattern (case-sensitive substring match), sorted by descending importance.

Source

pub fn clear_for(&self, agent_id: &AgentId) -> Result<usize, AgentRuntimeError>

Remove all episodes stored for agent_id.

Returns the number of episodes that were removed.

Source

pub fn count_episodes_with_tag( &self, agent_id: &AgentId, tag: &str, ) -> Result<usize, AgentRuntimeError>

Return the number of episodes for agent_id that carry the given tag.

Source

pub fn episodes_with_content( &self, agent_id: &AgentId, substring: &str, ) -> Result<Vec<String>, AgentRuntimeError>

Return the content strings of all episodes for agent_id whose content contains substring.

Source

pub fn max_content_length( &self, agent_id: &AgentId, ) -> Result<usize, AgentRuntimeError>

Return the byte length of the longest episode content for agent_id.

Returns 0 if the agent has no episodes.

Source

pub fn min_content_length( &self, agent_id: &AgentId, ) -> Result<usize, AgentRuntimeError>

Return the byte length of the shortest episode content for agent_id.

Returns 0 if the agent has no episodes.

Source

pub fn episodes_by_importance( &self, agent_id: &AgentId, ) -> Result<Vec<String>, AgentRuntimeError>

Return the content strings of all episodes for agent_id, sorted by descending importance (most important first).

Source

pub fn content_contains_count( &self, agent_id: &AgentId, substring: &str, ) -> Result<usize, AgentRuntimeError>

Return the count of episodes for agent_id whose content contains substring.

The match is case-sensitive. Returns 0 if the agent has no episodes.

Source

pub fn agents_with_episodes(&self) -> Result<Vec<AgentId>, AgentRuntimeError>

Return a sorted list of all AgentIds that have at least one episode.

Source

pub fn high_importance_count( &self, agent_id: &AgentId, threshold: f32, ) -> Result<usize, AgentRuntimeError>

Return the count of episodes whose importance is strictly greater than threshold.

Source

pub fn content_lengths( &self, agent_id: &AgentId, ) -> Result<Vec<usize>, AgentRuntimeError>

Return a list of content byte lengths for all episodes belonging to agent_id, in storage order.

Source

pub fn total_content_bytes( &self, agent_id: &AgentId, ) -> Result<usize, AgentRuntimeError>

Return the total byte length of all episode content strings for agent_id.

Returns 0 if the agent has no stored episodes.

Source

pub fn avg_content_length( &self, agent_id: &AgentId, ) -> Result<f64, AgentRuntimeError>

Return the average byte length of episode content strings for agent_id.

Returns 0.0 if the agent has no stored episodes.

Source

pub fn importance_sum( &self, agent_id: &AgentId, ) -> Result<f32, AgentRuntimeError>

Return the sum of all importance scores for agent_id.

Returns 0.0 if the agent has no stored episodes.

Source

pub fn recall_by_tag( &self, agent_id: &AgentId, tag: &str, limit: usize, ) -> Result<Vec<MemoryItem>, AgentRuntimeError>

Recall up to limit episodes for agent_id that carry tag, sorted by descending importance. limit = 0 returns all matches.

Source

pub fn add_episode_at( &self, agent_id: AgentId, content: impl Into<String> + Debug, importance: f32, timestamp: DateTime<Utc>, ) -> Result<MemoryId, AgentRuntimeError>

Add an episode with an explicit timestamp.

Source

pub fn add_episodes_batch( &self, agent_id: AgentId, episodes: impl IntoIterator<Item = (impl Into<String>, f32)>, ) -> Result<Vec<MemoryId>, AgentRuntimeError>

Add multiple episodes for the same agent in a single lock acquisition.

More efficient than calling add_episode in a loop when inserting many items at once. Returns the generated MemoryIds in the same order as episodes.

Source

pub fn recall( &self, agent_id: &AgentId, limit: usize, ) -> Result<Vec<MemoryItem>, AgentRuntimeError>

Recall up to limit memories for the given agent.

Applies decay if configured, purges stale items if max_age is set, increments recall_count for each recalled item, then returns items sorted according to the configured RecallPolicy.

§Errors

Returns Err(AgentRuntimeError::Memory) only if the internal mutex is poisoned (extremely unlikely in normal operation).

Source

pub fn recall_tagged( &self, agent_id: &AgentId, tags: &[&str], limit: usize, ) -> Result<Vec<MemoryItem>, AgentRuntimeError>

Recall episodes for agent_id that contain all of the specified tags.

Returns at most limit items ordered by descending importance, consistent with recall. Pass an empty tags slice to match all episodes.

Source

pub fn recall_by_id( &self, agent_id: &AgentId, id: &MemoryId, ) -> Result<Option<MemoryItem>, AgentRuntimeError>

Retrieve a single episode by its MemoryId.

Returns Ok(Some(item)) if found, Ok(None) if no episode with that ID exists for agent_id.

Source

pub fn merge_from( &self, other: &EpisodicStore, agent_id: &AgentId, ) -> Result<usize, AgentRuntimeError>

Import all episodes from other for agent_id into this store.

Episodes are appended without deduplication. Capacity eviction is applied per-episode exactly as in add_episode.

Source

pub fn update_importance( &self, agent_id: &AgentId, id: &MemoryId, new_importance: f32, ) -> Result<bool, AgentRuntimeError>

Update the importance score of a specific episode in-place.

Returns Ok(true) if the episode was found and updated, Ok(false) if no episode with that id exists for agent_id.

new_importance is clamped to [0.0, 1.0].

Source

pub fn recall_since( &self, agent_id: &AgentId, cutoff: DateTime<Utc>, limit: usize, ) -> Result<Vec<MemoryItem>, AgentRuntimeError>

Recall episodes for agent_id inserted at or after cutoff.

Returns items ordered by descending importance (same as recall). Pass limit = 0 to return all matching items.

Source

pub fn update_content( &self, agent_id: &AgentId, id: &MemoryId, new_content: impl Into<String>, ) -> Result<bool, AgentRuntimeError>

Update the content of an episode identified by its MemoryId.

Returns Ok(true) if found and updated, Ok(false) if no episode with that id exists for agent_id.

Source

pub fn recall_recent( &self, agent_id: &AgentId, limit: usize, ) -> Result<Vec<MemoryItem>, AgentRuntimeError>

Recall the most recently added episodes for agent_id in reverse insertion order.

Unlike recall (which ranks by importance), this returns the limit most recently inserted items with no re-ordering. Useful when recency matters more than importance, e.g. retrieving the latest context window entries.

Source

pub fn recall_all( &self, agent_id: &AgentId, ) -> Result<Vec<MemoryItem>, AgentRuntimeError>

Retrieve all stored episodes for agent_id without any limit.

Returns items in descending importance order, consistent with recall. For large stores, prefer recall with an explicit limit.

Source

pub fn top_n( &self, agent_id: &AgentId, n: usize, ) -> Result<Vec<MemoryItem>, AgentRuntimeError>

Return the top n episodes for agent_id ordered by descending importance.

When n == 0 all episodes are returned. Does not increment recall_count.

Source

pub fn search_by_importance_range( &self, agent_id: &AgentId, min: f32, max: f32, limit: usize, ) -> Result<Vec<MemoryItem>, AgentRuntimeError>

Return episodes for agent_id whose importance is in [min, max], most important first. Passing limit == 0 returns all matching episodes.

Source

pub fn total_recall_count( &self, agent_id: &AgentId, ) -> Result<u64, AgentRuntimeError>

Return the sum of recall_count across all episodes for agent_id.

Useful for tracking aggregate access frequency per agent.

Source

pub fn importance_stats( &self, agent_id: &AgentId, ) -> Result<(usize, f32, f32, f32), AgentRuntimeError>

Return summary statistics (count, min, max, mean importance) for agent_id.

Returns (0, 0.0, 0.0, 0.0) if the agent has no stored episodes.

Source

pub fn oldest( &self, agent_id: &AgentId, ) -> Result<Option<MemoryItem>, AgentRuntimeError>

Return the oldest (first-inserted) episode for agent_id, or None if the agent has no stored episodes.

Source

pub fn clear_agent( &self, agent_id: &AgentId, ) -> Result<usize, AgentRuntimeError>

Remove all stored episodes for agent_id.

Returns the number of episodes that were removed.

Source

pub fn oldest_episode( &self, agent_id: &AgentId, ) -> Result<Option<MemoryItem>, AgentRuntimeError>

Return the episode with the earliest timestamp for agent_id, or None if the agent has no stored episodes.

Source

pub fn max_importance_episode( &self, agent_id: &AgentId, ) -> Result<Option<MemoryItem>, AgentRuntimeError>

Return the episode with the highest importance score for agent_id, or None if the agent has no stored episodes. Ties are broken in favour of the later-inserted episode.

Source

pub fn newest( &self, agent_id: &AgentId, ) -> Result<Option<MemoryItem>, AgentRuntimeError>

Return the most recently inserted episode for agent_id, or None if the agent has no stored episodes.

Source

pub fn len(&self) -> Result<usize, AgentRuntimeError>

Return the total number of stored episodes across all agents.

Source

pub fn is_empty(&self) -> Result<bool, AgentRuntimeError>

Return true if no episodes have been stored.

Source

pub fn agent_count(&self) -> Result<usize, AgentRuntimeError>

Return the number of distinct agents that have at least one stored episode.

Source

pub fn agent_memory_count( &self, agent_id: &AgentId, ) -> Result<usize, AgentRuntimeError>

Return the number of stored episodes for a specific agent.

Returns 0 if the agent has no episodes or has not been seen before.

Source

pub fn has_episodes( &self, agent_id: &AgentId, ) -> Result<bool, AgentRuntimeError>

Return true if agent_id has at least one stored episode.

Source

pub fn latest_episode( &self, agent_id: &AgentId, ) -> Result<Option<MemoryItem>, AgentRuntimeError>

Return the most recently inserted episode for agent_id, or None if the agent has no stored episodes.

“Most recent” is determined by timestamp.

Source

pub fn max_recall_count_for( &self, agent_id: &AgentId, ) -> Result<Option<u64>, AgentRuntimeError>

Return the maximum single recall_count value across all episodes for agent_id, or None if the agent has no stored episodes.

Source

pub fn avg_importance( &self, agent_id: &AgentId, ) -> Result<f64, AgentRuntimeError>

Return the mean importance score across all episodes for agent_id.

Returns 0.0 when the agent has no stored episodes.

Source

pub fn importance_range( &self, agent_id: &AgentId, ) -> Result<Option<(f32, f32)>, AgentRuntimeError>

Return the (min, max) importance pair across all episodes for agent_id, or None when the agent has no stored episodes.

Source

pub fn sum_recall_counts( &self, agent_id: &AgentId, ) -> Result<u64, AgentRuntimeError>

Return the total recall_count across all episodes for agent_id.

Returns 0 if the agent has no stored episodes.

Source

pub fn list_agents(&self) -> Result<Vec<AgentId>, AgentRuntimeError>

Return all agent IDs that have at least one stored episode.

The order of agents in the returned vector is not guaranteed.

Source

pub fn purge_agent_memories( &self, agent_id: &AgentId, ) -> Result<usize, AgentRuntimeError>

Remove all stored episodes for agent_id and return the number removed.

Returns 0 if the agent had no episodes. Does not affect other agents.

Source

pub fn clear_agent_memory( &self, agent_id: &AgentId, ) -> Result<(), AgentRuntimeError>

Remove all memories for the given agent.

After this call, recall for this agent returns an empty list.

Source

pub fn clear_all(&self) -> Result<(), AgentRuntimeError>

Remove all episodes for all agents.

After this call len() returns 0 and list_agents() returns an empty slice.

Source

pub fn export_agent_memory( &self, agent_id: &AgentId, ) -> Result<Vec<MemoryItem>, AgentRuntimeError>

Export all memories for the given agent as a serializable Vec.

Useful for migrating agent state across runtime instances.

Source

pub fn import_agent_memory( &self, agent_id: &AgentId, items: Vec<MemoryItem>, ) -> Result<(), AgentRuntimeError>

Import a Vec of MemoryItems for the given agent, replacing any existing memories.

The agent’s existing memories are completely replaced by the imported items.

Source

pub fn search_by_content( &self, agent_id: &AgentId, query: &str, limit: usize, ) -> Result<Vec<MemoryItem>, AgentRuntimeError>

Search episodes for a given agent_id whose content contains query as a substring.

The comparison is case-sensitive. Returns at most limit matching items, ordered by descending importance (same as recall).

Trait Implementations§

Source§

impl Clone for EpisodicStore

Source§

fn clone(&self) -> EpisodicStore

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for EpisodicStore

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for EpisodicStore

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more