@@ -35,6 +35,8 @@ pub struct SessionManager {
3535 Arc < RwLock < HashMap < String , tokio_util:: sync:: CancellationToken > > > ,
3636 /// Skill registry for runtime skill management
3737 pub ( crate ) skill_registry : Arc < RwLock < Option < Arc < SkillRegistry > > > > ,
38+ /// Per-session skill registries layered on top of the shared registry.
39+ pub ( crate ) session_skill_registries : Arc < RwLock < HashMap < String , Arc < SkillRegistry > > > > ,
3840 /// Shared memory store for agent long-term memory.
3941 /// When set, each `generate`/`generate_streaming` call wraps this in
4042 /// `AgentMemory` and injects it into `AgentConfig.memory`.
@@ -56,6 +58,7 @@ impl SessionManager {
5658 llm_configs : Arc :: new ( RwLock :: new ( HashMap :: new ( ) ) ) ,
5759 ongoing_operations : Arc :: new ( RwLock :: new ( HashMap :: new ( ) ) ) ,
5860 skill_registry : Arc :: new ( RwLock :: new ( None ) ) ,
61+ session_skill_registries : Arc :: new ( RwLock :: new ( HashMap :: new ( ) ) ) ,
5962 memory_store : Arc :: new ( RwLock :: new ( None ) ) ,
6063 mcp_manager : Arc :: new ( RwLock :: new ( None ) ) ,
6164 }
@@ -85,6 +88,7 @@ impl SessionManager {
8588 llm_configs : Arc :: new ( RwLock :: new ( HashMap :: new ( ) ) ) ,
8689 ongoing_operations : Arc :: new ( RwLock :: new ( HashMap :: new ( ) ) ) ,
8790 skill_registry : Arc :: new ( RwLock :: new ( None ) ) ,
91+ session_skill_registries : Arc :: new ( RwLock :: new ( HashMap :: new ( ) ) ) ,
8892 memory_store : Arc :: new ( RwLock :: new ( None ) ) ,
8993 mcp_manager : Arc :: new ( RwLock :: new ( None ) ) ,
9094 } ;
@@ -114,6 +118,7 @@ impl SessionManager {
114118 llm_configs : Arc :: new ( RwLock :: new ( HashMap :: new ( ) ) ) ,
115119 ongoing_operations : Arc :: new ( RwLock :: new ( HashMap :: new ( ) ) ) ,
116120 skill_registry : Arc :: new ( RwLock :: new ( None ) ) ,
121+ session_skill_registries : Arc :: new ( RwLock :: new ( HashMap :: new ( ) ) ) ,
117122 memory_store : Arc :: new ( RwLock :: new ( None ) ) ,
118123 mcp_manager : Arc :: new ( RwLock :: new ( None ) ) ,
119124 }
@@ -151,6 +156,27 @@ impl SessionManager {
151156 self . skill_registry . read ( ) . await . clone ( )
152157 }
153158
159+ /// Override the active skill registry for a single session.
160+ pub async fn set_session_skill_registry (
161+ & self ,
162+ session_id : impl Into < String > ,
163+ registry : Arc < SkillRegistry > ,
164+ ) {
165+ self . session_skill_registries
166+ . write ( )
167+ . await
168+ . insert ( session_id. into ( ) , registry) ;
169+ }
170+
171+ /// Get the active skill registry for a single session, if one was set.
172+ pub async fn session_skill_registry ( & self , session_id : & str ) -> Option < Arc < SkillRegistry > > {
173+ self . session_skill_registries
174+ . read ( )
175+ . await
176+ . get ( session_id)
177+ . cloned ( )
178+ }
179+
154180 /// Set the shared memory store for agent long-term memory.
155181 ///
156182 /// When set, every `generate`/`generate_streaming` call wraps this store
@@ -480,6 +506,11 @@ impl SessionManager {
480506 configs. remove ( id) ;
481507 }
482508
509+ {
510+ let mut registries = self . session_skill_registries . write ( ) . await ;
511+ registries. remove ( id) ;
512+ }
513+
483514 // Remove storage type tracking
484515 {
485516 let mut storage_types = self . session_storage_types . write ( ) . await ;
@@ -663,7 +694,10 @@ impl SessionManager {
663694 } ;
664695
665696 // Inject skill registry into system prompt and agent config
666- let skill_registry = self . skill_registry . read ( ) . await . clone ( ) ;
697+ let skill_registry = match self . session_skill_registry ( session_id) . await {
698+ Some ( registry) => Some ( registry) ,
699+ None => self . skill_registry . read ( ) . await . clone ( ) ,
700+ } ;
667701 let system = if let Some ( ref registry) = skill_registry {
668702 let skill_prompt = registry. to_system_prompt ( ) ;
669703 if skill_prompt. is_empty ( ) {
@@ -820,7 +854,10 @@ impl SessionManager {
820854 } ;
821855
822856 // Inject skill registry into system prompt and agent config
823- let skill_registry = self . skill_registry . read ( ) . await . clone ( ) ;
857+ let skill_registry = match self . session_skill_registry ( session_id) . await {
858+ Some ( registry) => Some ( registry) ,
859+ None => self . skill_registry . read ( ) . await . clone ( ) ,
860+ } ;
824861 let system = if let Some ( ref registry) = skill_registry {
825862 let skill_prompt = registry. to_system_prompt ( ) ;
826863 if skill_prompt. is_empty ( ) {
@@ -1162,6 +1199,22 @@ impl SessionManager {
11621199 Ok ( ( ) )
11631200 }
11641201
1202+ /// Update a session's system prompt in place.
1203+ pub async fn set_system_prompt (
1204+ & self ,
1205+ session_id : & str ,
1206+ system_prompt : Option < String > ,
1207+ ) -> Result < ( ) > {
1208+ {
1209+ let session_lock = self . get_session ( session_id) . await ?;
1210+ let mut session = session_lock. write ( ) . await ;
1211+ session. config . system_prompt = system_prompt;
1212+ }
1213+
1214+ self . persist_in_background ( session_id, "set_system_prompt" ) ;
1215+ Ok ( ( ) )
1216+ }
1217+
11651218 /// Get session count
11661219 pub async fn session_count ( & self ) -> usize {
11671220 let sessions = self . sessions . read ( ) . await ;
0 commit comments