@@ -1590,8 +1590,15 @@ pub fn spawn_cortex_loop(deps: AgentDeps, logger: CortexLogger) -> tokio::task::
15901590 let cortex = Cortex :: new ( deps. clone ( ) , system_prompt) ;
15911591 let mut event_rx = deps. event_tx . subscribe ( ) ;
15921592 let mut memory_event_rx = deps. memory_event_tx . subscribe ( ) ;
1593- if let Err ( error) =
1594- run_cortex_loop ( & cortex, & logger, & mut event_rx, & mut memory_event_rx) . await
1593+ let mut tool_output_rx = deps. tool_output_tx . subscribe ( ) ;
1594+ if let Err ( error) = run_cortex_loop (
1595+ & cortex,
1596+ & logger,
1597+ & mut event_rx,
1598+ & mut memory_event_rx,
1599+ & mut tool_output_rx,
1600+ )
1601+ . await
15951602 {
15961603 tracing:: error!( %error, "cortex loop exited with error" ) ;
15971604 }
@@ -1795,6 +1802,7 @@ async fn run_cortex_loop(
17951802 logger : & CortexLogger ,
17961803 event_rx : & mut broadcast:: Receiver < ProcessEvent > ,
17971804 memory_event_rx : & mut broadcast:: Receiver < ProcessEvent > ,
1805+ tool_output_rx : & mut broadcast:: Receiver < ProcessEvent > ,
17981806) -> anyhow:: Result < ( ) > {
17991807 tracing:: info!( "cortex loop started" ) ;
18001808
@@ -1853,7 +1861,10 @@ async fn run_cortex_loop(
18531861 let mut last_lag_warning_control: Option < Instant > = None ;
18541862 let mut lagged_since_last_warning_memory: u64 = 0 ;
18551863 let mut last_lag_warning_memory: Option < Instant > = None ;
1864+ let mut lagged_since_last_warning_tool_output: u64 = 0 ;
1865+ let mut last_lag_warning_tool_output: Option < Instant > = None ;
18561866 let mut memory_event_stream_open = true ;
1867+ let mut tool_output_stream_open = true ;
18571868 let mut refresh_task: Option < tokio:: task:: JoinHandle < BulletinRefreshOutcome > > = None ;
18581869 let mut maintenance_task: Option <
18591870 tokio:: task:: JoinHandle < crate :: error:: Result < memory_maintenance:: MaintenanceReport > > ,
@@ -1937,6 +1948,31 @@ async fn run_cortex_loop(
19371948 }
19381949 }
19391950 } ,
1951+ event = tool_output_rx. recv( ) , if tool_output_stream_open => {
1952+ match handle_cortex_receiver_result(
1953+ event,
1954+ "tool_output" ,
1955+ ReceiverClosedBehavior :: DisableStream ,
1956+ & mut lagged_since_last_warning_tool_output,
1957+ & mut last_lag_warning_tool_output,
1958+ LAG_WARNING_INTERVAL_SECS ,
1959+ ) {
1960+ CortexReceiverOutcome :: Observe ( event) => cortex. observe( event) . await ,
1961+ CortexReceiverOutcome :: Lagged { dropped } => {
1962+ #[ cfg( feature = "metrics" ) ]
1963+ crate :: telemetry:: Metrics :: global( )
1964+ . event_receiver_lagged_events_total
1965+ . with_label_values( & [ & * cortex. deps. agent_id, "cortex_tool_output" ] )
1966+ . inc_by( dropped) ;
1967+ #[ cfg( not( feature = "metrics" ) ) ]
1968+ let _ = dropped;
1969+ }
1970+ CortexReceiverOutcome :: StopLoop => unreachable!( "tool output stream cannot stop cortex loop" ) ,
1971+ CortexReceiverOutcome :: DisableStream => {
1972+ tool_output_stream_open = false ;
1973+ }
1974+ }
1975+ } ,
19401976 _ = tick_timer. tick( ) => {
19411977 if let Err ( error) = cortex. run_health_tick( logger) . await {
19421978 tracing:: warn!( %error, "cortex health tick failed" ) ;
0 commit comments