Skip to main content

do_memory_core/context/
mod.rs

1//! Bounded context assembly for retrieval results.
2//!
3//! This module provides `BundleAccumulator`, a sliding window accumulator that
4//! bounds retrieval context size by recency and salience instead of flat accumulation.
5//!
6//! ## Purpose
7//!
8//! When retrieving episodes and patterns for downstream prompts (e.g., LLM context),
9//! flat accumulation can result in:
10//! - Excessive token usage (too many items)
11//! - Irrelevant items (low-quality matches included)
12//! - Stale context (old items dominating recent ones)
13//!
14//! `BundleAccumulator` addresses these by:
15//! - Capping the number of items via a sliding window
16//! - Prioritizing by combined recency + salience scoring
17//! - Evicting lowest-priority items when capacity exceeded
18//!
19//! ## DAG-Based State Management (WG-134)
20//!
21//! The `dag` submodule provides DAG-based state management achieving ~86% token
22//! reduction by deduplicating shared context between episodes:
23//! - `StateDag`: Manages shared context nodes
24//! - `DagContextAssembler`: Assembles minimal deduplicated context
25//!
26//! ## Architecture
27//!
28//! ```text
29//! Retrieval Results
30//!        |
31//!        v
32//!   ContextItem (Episode/Pattern + Salience)
33//!        |
34//!        v
35//!   BundleAccumulator (Sliding Window)
36//!        |  - Check salience threshold
37//!        |  - Compute priority = recency_weight * recency + salience_weight * salience
38//!        |  - Evict lowest priority if full
39//!        v
40//!   Bounded Bundle (sorted by priority)
41//!        |
42//!        v
43//!   DagContextAssembler (WG-134)
44//!        |  - Deduplicate shared context
45//!        |  - ~86% token reduction
46//!        v
47//!   Downstream Prompt
48//! ```
49//!
50//! ## Quick Start
51//!
52//! ```
53//! use do_memory_core::context::{BundleAccumulator, BundleConfig, ContextItem};
54//! use do_memory_core::episode::Episode;
55//! use do_memory_core::TaskContext;
56//! use do_memory_core::types::TaskType;
57//! use std::sync::Arc;
58//!
59//! // Create accumulator with default config (20 items max)
60//! let mut accumulator = BundleAccumulator::default_config();
61//!
62//! // Add retrieved episodes with their salience scores
63//! let episode = Episode::new(
64//!     "Fix authentication bug".to_string(),
65//!     TaskContext::default(),
66//!     TaskType::Debugging,
67//! );
68//! let item = ContextItem::from_episode(Arc::new(episode), 0.85);
69//! accumulator.add(item);
70//!
71//! // Finalize bundle for prompt
72//! let bundle = accumulator.to_bundle();
73//! println!("Bundle contains {} items for prompt", bundle.len());
74//! ```
75//!
76//! ## Configuration Options
77//!
78//! ```
79//! use do_memory_core::context::BundleConfig;
80//!
81//! // Token-efficient: smaller bundle, higher quality threshold
82//! let token_config = BundleConfig::token_efficient();
83//!
84//! // Comprehensive: larger bundle, lower threshold
85//! let full_config = BundleConfig::comprehensive();
86//!
87//! // Custom: tune for specific needs
88//! let custom = BundleConfig {
89//!     max_items: 15,            // Allow 15 items
90//!     recency_weight: 0.6,      // Favor recent items
91//!     salience_weight: 0.3,     // Still consider retrieval score
92//!     min_salience_threshold: 0.3, // Reject very low salience
93//!     recency_half_life_days: 14.0, // Recent = last 2 weeks
94//! };
95//! ```
96//!
97//! ## Integration with Retrieval
98//!
99//! The accumulator is designed to sit between retrieval results and prompt construction:
100//!
101//! ```no_run
102//! use do_memory_core::memory::SelfLearningMemory;
103//! use do_memory_core::context::{BundleAccumulator, BundleConfig};
104//! use do_memory_core::TaskContext;
105//!
106//! # async fn example(memory: SelfLearningMemory) {
107//! // Retrieve episodes (unbounded)
108//! let episodes = memory.retrieve_relevant_context(
109//!     "Implement OAuth2".to_string(),
110//!     TaskContext::default(),
111//!     50,  // May retrieve up to 50
112//! ).await;
113//!
114//! // Create bounded bundle
115//! let bundle = BundleAccumulator::from_episodes_with_config(
116//!     episodes,
117//!     BundleConfig::token_efficient(),
118//!     |ep| ep.reward.as_ref().map_or(0.5, |r| r.total),
119//! );
120//!
121//! // bundle.len() <= 10 (bounded for token efficiency)
122//! # }
123//! ```
124//!
125//! ## Modules
126//!
127//! - [`types`]: Core types (`ContextItem`, `BundleConfig`, `BundleStats`)
128//! - [`accumulator`]: `BundleAccumulator` implementation
129//! - [`scoring`]: Priority and recency scoring functions
130//! - [`dag`]: DAG-based state management (WG-134, ~86% token reduction)
131
132pub mod accumulator;
133pub mod dag;
134pub mod scoring;
135pub mod types;
136
137#[cfg(test)]
138mod tests;
139
140#[cfg(test)]
141mod tests_edge;
142
143// Re-export public types
144pub use accumulator::BundleAccumulator;
145pub use scoring::{
146    calculate_priority_score, calculate_recency_score, compare_by_priority, compare_by_recency,
147    compare_by_salience,
148};
149pub use types::{AddResult, BundleConfig, BundleStats, ContextItem, ContextItemType};
150
151// Re-export DAG types (WG-134)
152pub use dag::{
153    AssembledContext, DagAssemblyConfig, DagContextAssembler, DagStats, EdgeMetadata, EdgeType,
154    NodeId, StateDag, StateEdge, StateNode, StateNodeType,
155};