@@ -76,6 +76,10 @@ pub struct SessionOptions {
7676 pub goal_tracking : bool ,
7777 /// Optional skill registry for instruction injection
7878 pub skill_registry : Option < Arc < crate :: skills:: SkillRegistry > > ,
79+ /// Optional memory store for long-term memory persistence
80+ pub memory_store : Option < Arc < dyn crate :: memory:: MemoryStore > > ,
81+ /// Deferred file memory directory — constructed async in `build_session()`
82+ pub ( crate ) file_memory_dir : Option < PathBuf > ,
7983}
8084
8185impl std:: fmt:: Debug for SessionOptions {
@@ -97,6 +101,7 @@ impl std::fmt::Debug for SessionOptions {
97101 . as_ref ( )
98102 . map ( |r| format ! ( "{} skills" , r. len( ) ) ) ,
99103 )
104+ . field ( "memory_store" , & self . memory_store . is_some ( ) )
100105 . finish ( )
101106 }
102107}
@@ -206,6 +211,24 @@ impl SessionOptions {
206211 self . skill_registry = Some ( registry) ;
207212 self
208213 }
214+
215+ /// Set a custom memory store
216+ pub fn with_memory ( mut self , store : Arc < dyn crate :: memory:: MemoryStore > ) -> Self {
217+ self . memory_store = Some ( store) ;
218+ self
219+ }
220+
221+ /// Use a file-based memory store at the given directory.
222+ ///
223+ /// The store is created lazily when the session is built (requires async).
224+ /// This stores the directory path; `FileMemoryStore::new()` is called during
225+ /// session construction.
226+ pub fn with_file_memory ( mut self , dir : impl Into < PathBuf > ) -> Self {
227+ // Store as a deferred path — we'll construct the FileMemoryStore in build_session
228+ // since FileMemoryStore::new() is async. Use a marker via the _file_memory_dir field.
229+ self . file_memory_dir = Some ( dir. into ( ) ) ;
230+ self
231+ }
209232}
210233
211234// ============================================================================
@@ -393,6 +416,39 @@ impl Agent {
393416 tool_context = tool_context. with_search_config ( search_config. clone ( ) ) ;
394417 }
395418
419+ // Resolve memory store: explicit store takes priority, then file_memory_dir
420+ let memory = {
421+ let store = if let Some ( ref store) = opts. memory_store {
422+ Some ( Arc :: clone ( store) )
423+ } else if let Some ( ref dir) = opts. file_memory_dir {
424+ match tokio:: runtime:: Handle :: try_current ( ) {
425+ Ok ( handle) => {
426+ let dir = dir. clone ( ) ;
427+ match tokio:: task:: block_in_place ( || {
428+ handle. block_on ( crate :: memory:: FileMemoryStore :: new ( dir) )
429+ } ) {
430+ Ok ( store) => {
431+ Some ( Arc :: new ( store) as Arc < dyn crate :: memory:: MemoryStore > )
432+ }
433+ Err ( e) => {
434+ tracing:: warn!( "Failed to create file memory store: {}" , e) ;
435+ None
436+ }
437+ }
438+ }
439+ Err ( _) => {
440+ tracing:: warn!(
441+ "No async runtime available for file memory store — memory disabled"
442+ ) ;
443+ None
444+ }
445+ }
446+ } else {
447+ None
448+ } ;
449+ store. map ( crate :: memory:: AgentMemory :: new)
450+ } ;
451+
396452 Ok ( AgentSession {
397453 llm_client,
398454 tool_executor,
@@ -401,6 +457,7 @@ impl Agent {
401457 workspace : canonical,
402458 history : RwLock :: new ( Vec :: new ( ) ) ,
403459 command_queue,
460+ memory,
404461 } )
405462 }
406463}
@@ -423,6 +480,8 @@ pub struct AgentSession {
423480 history : RwLock < Vec < Message > > ,
424481 /// Optional lane queue for priority-based tool execution.
425482 command_queue : Option < Arc < SessionLaneQueue > > ,
483+ /// Optional long-term memory.
484+ memory : Option < crate :: memory:: AgentMemory > ,
426485}
427486
428487impl std:: fmt:: Debug for AgentSession {
@@ -508,6 +567,11 @@ impl AgentSession {
508567 self . history . read ( ) . unwrap ( ) . clone ( )
509568 }
510569
570+ /// Return a reference to the session's memory, if configured.
571+ pub fn memory ( & self ) -> Option < & crate :: memory:: AgentMemory > {
572+ self . memory . as_ref ( )
573+ }
574+
511575 /// Read a file from the workspace.
512576 pub async fn read_file ( & self , path : & str ) -> Result < String > {
513577 let args = serde_json:: json!( { "file_path" : path } ) ;
0 commit comments