@@ -13,6 +13,7 @@ use std::io::{
1313} ;
1414use std:: process:: ExitCode ;
1515use std:: sync:: Arc ;
16+ use std:: sync:: atomic:: AtomicBool ;
1617
1718use color_eyre:: owo_colors:: OwoColorize ;
1819use conversation_state:: ConversationState ;
@@ -53,6 +54,7 @@ use spinners::{
5354 Spinners ,
5455} ;
5556use tools:: {
57+ InvokeOutput ,
5658 Tool ,
5759 ToolSpec ,
5860} ;
@@ -204,6 +206,18 @@ where
204206 }
205207
206208 async fn try_chat ( & mut self ) -> Result < ( ) > {
209+ let should_terminate = Arc :: new ( AtomicBool :: new ( true ) ) ;
210+ let should_terminate_ref = should_terminate. clone ( ) ;
211+ let ( tx, mut rx) = tokio:: sync:: mpsc:: channel ( 1 ) ;
212+ ctrlc:: set_handler ( move || {
213+ if should_terminate_ref. load ( std:: sync:: atomic:: Ordering :: SeqCst ) {
214+ execute ! ( std:: io:: stdout( ) , cursor:: Show ) . unwrap ( ) ;
215+ #[ allow( clippy:: exit) ]
216+ std:: process:: exit ( 0 ) ;
217+ } else {
218+ let _ = tx. blocking_send ( ( ) ) ;
219+ }
220+ } ) ?;
207221 // todo: what should we set this to?
208222 if self . is_interactive {
209223 execute ! (
@@ -222,7 +236,7 @@ Hi, I'm <g>Amazon Q</g>. Ask me anything.
222236
223237 loop {
224238 let mut response = loop {
225- match self . prompt_and_send_request ( ) . await {
239+ match self . prompt_and_send_request ( & mut rx , & should_terminate ) . await {
226240 Ok ( resp) => {
227241 break resp;
228242 } ,
@@ -401,7 +415,11 @@ Hi, I'm <g>Amazon Q</g>. Ask me anything.
401415 Ok ( ( ) )
402416 }
403417
404- async fn prompt_and_send_request ( & mut self ) -> Result < Option < SendMessageOutput > > {
418+ async fn prompt_and_send_request (
419+ & mut self ,
420+ sigint_recver : & mut tokio:: sync:: mpsc:: Receiver < ( ) > ,
421+ should_terminate : & Arc < AtomicBool > ,
422+ ) -> Result < Option < SendMessageOutput > > {
405423 // Tool uses that need to be executed.
406424 let mut queued_tools: Vec < ( String , Tool ) > = Vec :: new ( ) ;
407425
@@ -582,8 +600,28 @@ Hi, I'm <g>Amazon Q</g>. Ask me anything.
582600 style:: Print ( format!( "{}...\n \n " , tool. 1 . display_name( ) ) ) ,
583601 style:: SetForegroundColor ( Color :: Reset ) ,
584602 ) ?;
585- let invoke_result = tool. 1 . invoke ( & self . ctx , self . output ) . await ;
603+ self . spinner = Some ( Spinner :: new (
604+ Spinners :: Dots ,
605+ "Running tool... press ctrl + c to terminate early" . to_owned ( ) ,
606+ ) ) ;
607+ should_terminate. store ( false , std:: sync:: atomic:: Ordering :: SeqCst ) ;
608+ let invoke_result = tokio:: select! {
609+ output = tool. 1 . invoke( & self . ctx, self . output) => Some ( output) ,
610+ _ = sigint_recver. recv( ) => None
611+ }
612+ . map_or ( Ok ( InvokeOutput :: default ( ) ) , |v| v) ;
613+ if self . is_interactive && self . spinner . is_some ( ) {
614+ drop ( self . spinner . take ( ) ) ;
615+ queue ! (
616+ self . output,
617+ terminal:: Clear ( terminal:: ClearType :: CurrentLine ) ,
618+ cursor:: MoveToColumn ( 0 ) ,
619+ cursor:: Show
620+ ) ?;
621+ }
622+ should_terminate. store ( true , std:: sync:: atomic:: Ordering :: SeqCst ) ;
586623 execute ! ( self . output, style:: Print ( "\n " ) ) ?;
624+
587625 let tool_time = std:: time:: Instant :: now ( ) . duration_since ( tool_start) ;
588626 let tool_time = format ! ( "{}.{}" , tool_time. as_secs( ) , tool_time. subsec_millis( ) ) ;
589627
@@ -662,12 +700,6 @@ Hi, I'm <g>Amazon Q</g>. Ask me anything.
662700 }
663701 queue ! ( self . output, style:: SetForegroundColor ( Color :: Reset ) ) ?;
664702 queue ! ( self . output, cursor:: Hide ) ?;
665- tokio:: spawn ( async {
666- tokio:: signal:: ctrl_c ( ) . await . unwrap ( ) ;
667- execute ! ( std:: io:: stdout( ) , cursor:: Show ) . unwrap ( ) ;
668- #[ allow( clippy:: exit) ]
669- std:: process:: exit ( 0 ) ;
670- } ) ;
671703 execute ! ( self . output, style:: Print ( "\n " ) ) ?;
672704 self . spinner = Some ( Spinner :: new ( Spinners :: Dots , "Thinking..." . to_owned ( ) ) ) ;
673705 }
0 commit comments