@@ -92,6 +92,15 @@ pub trait AgentScheduler {
9292 agent_id : AgentId ,
9393 request : crate :: api:: types:: UpdateAgentRequest ,
9494 ) -> Result < ( ) , SchedulerError > ;
95+
96+ /// Check whether an agent is registered (regardless of run state)
97+ fn has_agent ( & self , agent_id : AgentId ) -> bool ;
98+
99+ /// Retrieve the stored config for a registered agent
100+ fn get_agent_config ( & self , agent_id : AgentId ) -> Option < AgentConfig > ;
101+
102+ /// Remove an agent from the registry entirely
103+ async fn delete_agent ( & self , agent_id : AgentId ) -> Result < ( ) , SchedulerError > ;
95104}
96105
97106/// Scheduler configuration
@@ -251,6 +260,10 @@ pub struct DefaultAgentScheduler {
251260 task_manager : Arc < TaskManager > ,
252261 running_agents : Arc < DashMap < AgentId , ScheduledTask > > ,
253262 suspended_agents : Arc < DashMap < AgentId , AgentSuspensionInfo > > ,
263+ /// Persistent registry of all agents that have been scheduled. Agents
264+ /// remain here after being dequeued so that status/execute/list continue
265+ /// to work even after completion.
266+ registered_agents : Arc < DashMap < AgentId , AgentConfig > > ,
254267 system_metrics : Arc < RwLock < SystemMetrics > > ,
255268 shutdown_notify : Arc < Notify > ,
256269 is_running : Arc < RwLock < bool > > ,
@@ -274,6 +287,7 @@ impl DefaultAgentScheduler {
274287 let task_manager = Arc :: new ( TaskManager :: new ( config. task_timeout ) ) ;
275288 let running_agents = Arc :: new ( DashMap :: new ( ) ) ;
276289 let suspended_agents = Arc :: new ( DashMap :: new ( ) ) ;
290+ let registered_agents = Arc :: new ( DashMap :: new ( ) ) ;
277291 let system_metrics = Arc :: new ( RwLock :: new ( SystemMetrics :: new ( ) ) ) ;
278292 let shutdown_notify = Arc :: new ( Notify :: new ( ) ) ;
279293 let is_running = Arc :: new ( RwLock :: new ( true ) ) ;
@@ -305,6 +319,7 @@ impl DefaultAgentScheduler {
305319 task_manager,
306320 running_agents,
307321 suspended_agents,
322+ registered_agents,
308323 system_metrics,
309324 shutdown_notify,
310325 is_running,
@@ -456,9 +471,12 @@ impl AgentScheduler for DefaultAgentScheduler {
456471 return Err ( SchedulerError :: ShuttingDown ) ;
457472 }
458473
459- let task = ScheduledTask :: new ( config) ;
474+ let task = ScheduledTask :: new ( config. clone ( ) ) ;
460475 let agent_id = task. agent_id ;
461476
477+ // Persist in the registry so the agent survives dequeue
478+ self . registered_agents . insert ( agent_id, config) ;
479+
462480 // Add to priority queue
463481 self . priority_queue . write ( ) . push ( task) ;
464482
@@ -503,13 +521,16 @@ impl AgentScheduler for DefaultAgentScheduler {
503521 reason : format ! ( "Failed to terminate task: {}" , e) ,
504522 } ) ?;
505523
524+ self . registered_agents . remove ( & agent_id) ;
506525 tracing:: info!( "Terminated agent {}" , agent_id) ;
507526 return Ok ( ( ) ) ;
508527 }
509528
510529 // Remove from queue
511530 let mut queue = self . priority_queue . write ( ) ;
512531 if queue. remove ( & agent_id) . is_some ( ) {
532+ drop ( queue) ;
533+ self . registered_agents . remove ( & agent_id) ;
513534 tracing:: info!( "Removed agent {} from queue" , agent_id) ;
514535 return Ok ( ( ) ) ;
515536 }
@@ -623,6 +644,17 @@ impl AgentScheduler for DefaultAgentScheduler {
623644 active_tasks : 0 ,
624645 scheduled_at : task. scheduled_at ,
625646 } )
647+ } else if self . registered_agents . contains_key ( & agent_id) {
648+ // Agent was registered but already ran and was dequeued
649+ Ok ( AgentStatus {
650+ agent_id,
651+ state : AgentState :: Completed ,
652+ last_activity : SystemTime :: now ( ) ,
653+ memory_usage : 0 ,
654+ cpu_usage : 0.0 ,
655+ active_tasks : 0 ,
656+ scheduled_at : SystemTime :: now ( ) ,
657+ } )
626658 } else {
627659 // Agent not found anywhere
628660 Err ( SchedulerError :: AgentNotFound { agent_id } )
@@ -776,21 +808,11 @@ impl AgentScheduler for DefaultAgentScheduler {
776808 }
777809
778810 async fn list_agents ( & self ) -> Vec < AgentId > {
779- let mut agent_ids = Vec :: new ( ) ;
780-
781- // Collect running agents
782- for entry in self . running_agents . iter ( ) {
783- agent_ids. push ( * entry. key ( ) ) ;
784- }
785-
786- // Collect queued agents
787- let queue = self . priority_queue . read ( ) ;
788- let queued_tasks = queue. to_vec ( ) ;
789- for task in queued_tasks {
790- agent_ids. push ( task. agent_id ) ;
791- }
792-
793- agent_ids
811+ // Return all registered agents (running, queued, and completed)
812+ self . registered_agents
813+ . iter ( )
814+ . map ( |entry| * entry. key ( ) )
815+ . collect ( )
794816 }
795817
796818 #[ cfg( feature = "http-api" ) ]
@@ -840,6 +862,35 @@ impl AgentScheduler for DefaultAgentScheduler {
840862
841863 Err ( SchedulerError :: AgentNotFound { agent_id } )
842864 }
865+
866+ fn has_agent ( & self , agent_id : AgentId ) -> bool {
867+ self . registered_agents . contains_key ( & agent_id)
868+ }
869+
870+ fn get_agent_config ( & self , agent_id : AgentId ) -> Option < AgentConfig > {
871+ self . registered_agents . get ( & agent_id) . map ( |r| r. clone ( ) )
872+ }
873+
874+ async fn delete_agent ( & self , agent_id : AgentId ) -> Result < ( ) , SchedulerError > {
875+ // Remove from running agents if present
876+ if let Some ( ( _, _) ) = self . running_agents . remove ( & agent_id) {
877+ let _ = self . task_manager . terminate_task ( agent_id) . await ;
878+ }
879+
880+ // Remove from queue if present
881+ {
882+ let mut queue = self . priority_queue . write ( ) ;
883+ queue. remove ( & agent_id) ;
884+ }
885+
886+ // Remove from registry
887+ if self . registered_agents . remove ( & agent_id) . is_some ( ) {
888+ tracing:: info!( "Deleted agent {} from registry" , agent_id) ;
889+ Ok ( ( ) )
890+ } else {
891+ Err ( SchedulerError :: AgentNotFound { agent_id } )
892+ }
893+ }
843894}
844895
845896impl DefaultAgentScheduler {
0 commit comments