@@ -402,6 +402,10 @@ pub enum ChatError {
402402 Interrupted { tool_uses : Option < Vec < QueuedTool > > } ,
403403 #[ error( transparent) ]
404404 GetPromptError ( #[ from] GetPromptError ) ,
405+ #[ error(
406+ "Tool approval required but --no-interactive was specified. Use --trust-all-tools to automatically approve tools."
407+ ) ]
408+ NonInteractiveToolApproval ,
405409}
406410
407411impl ChatError {
@@ -415,6 +419,7 @@ impl ChatError {
415419 ChatError :: Custom ( _) => None ,
416420 ChatError :: Interrupted { .. } => None ,
417421 ChatError :: GetPromptError ( _) => None ,
422+ ChatError :: NonInteractiveToolApproval => None ,
418423 }
419424 }
420425}
@@ -430,6 +435,7 @@ impl ReasonCode for ChatError {
430435 ChatError :: Interrupted { .. } => "Interrupted" . to_string ( ) ,
431436 ChatError :: GetPromptError ( _) => "GetPromptError" . to_string ( ) ,
432437 ChatError :: Auth ( _) => "AuthError" . to_string ( ) ,
438+ ChatError :: NonInteractiveToolApproval => "NonInteractiveToolApproval" . to_string ( ) ,
433439 }
434440 }
435441}
@@ -573,10 +579,16 @@ impl ChatSession {
573579 let ctrl_c_stream = ctrl_c ( ) ;
574580 let result = match self . inner . take ( ) . expect ( "state must always be Some" ) {
575581 ChatState :: PromptUser { skip_printing_tools } => {
576- if !self . interactive {
577- self . inner = Some ( ChatState :: Exit ) ;
578- return Ok ( ( ) ) ;
579- }
582+ match ( self . interactive , self . tool_uses . is_empty ( ) ) {
583+ ( false , true ) => {
584+ self . inner = Some ( ChatState :: Exit ) ;
585+ return Ok ( ( ) ) ;
586+ } ,
587+ ( false , false ) => {
588+ return Err ( ChatError :: NonInteractiveToolApproval ) ;
589+ } ,
590+ _ => ( ) ,
591+ } ;
580592
581593 self . prompt_user ( os, skip_printing_tools) . await
582594 } ,
@@ -862,6 +874,7 @@ impl Default for ChatState {
862874impl ChatSession {
863875 async fn spawn ( & mut self , os : & mut Os ) -> Result < ( ) > {
864876 let is_small_screen = self . terminal_width ( ) < GREETING_BREAK_POINT ;
877+ let mut interactive_text: Vec < u8 > = Vec :: new ( ) ;
865878 if os
866879 . database
867880 . settings
@@ -876,20 +889,20 @@ impl ChatSession {
876889 } ,
877890 } ;
878891
879- execute ! ( self . stderr , style:: Print ( welcome_text) , style:: Print ( "\n \n " ) , ) ?;
892+ execute ! ( interactive_text , style:: Print ( welcome_text) , style:: Print ( "\n \n " ) , ) ?;
880893
881894 let tip = ROTATING_TIPS [ usize:: try_from ( rand:: random :: < u32 > ( ) ) . unwrap_or ( 0 ) % ROTATING_TIPS . len ( ) ] ;
882895 if is_small_screen {
883896 // If the screen is small, print the tip in a single line
884897 execute ! (
885- self . stderr ,
898+ interactive_text ,
886899 style:: Print ( "💡 " . to_string( ) ) ,
887900 style:: Print ( tip) ,
888901 style:: Print ( "\n " )
889902 ) ?;
890903 } else {
891904 draw_box (
892- & mut self . stderr ,
905+ & mut interactive_text ,
893906 "Did you know?" ,
894907 tip,
895908 GREETING_BREAK_POINT ,
@@ -898,7 +911,7 @@ impl ChatSession {
898911 }
899912
900913 execute ! (
901- self . stderr ,
914+ interactive_text ,
902915 style:: Print ( "\n " ) ,
903916 style:: Print ( match is_small_screen {
904917 true => SMALL_SCREEN_POPULAR_SHORTCUTS ,
@@ -911,24 +924,27 @@ impl ChatSession {
911924 . dark_grey( )
912925 )
913926 ) ?;
914- execute ! ( self . stderr, style:: Print ( "\n " ) , style:: SetForegroundColor ( Color :: Reset ) ) ?;
927+ execute ! (
928+ interactive_text,
929+ style:: Print ( "\n " ) ,
930+ style:: SetForegroundColor ( Color :: Reset )
931+ ) ?;
915932 }
916933
917934 if self . all_tools_trusted ( ) {
918935 queue ! (
919- self . stderr ,
936+ interactive_text ,
920937 style:: Print ( format!(
921938 "{}{TRUST_ALL_TEXT}\n \n " ,
922939 if !is_small_screen { "\n " } else { "" }
923940 ) )
924941 ) ?;
925942 }
926- self . stderr . flush ( ) ?;
927943
928944 if let Some ( ref id) = self . conversation . model {
929945 if let Some ( model_option) = MODEL_OPTIONS . iter ( ) . find ( |option| option. model_id == * id) {
930946 execute ! (
931- self . stderr ,
947+ interactive_text ,
932948 style:: SetForegroundColor ( Color :: Cyan ) ,
933949 style:: Print ( format!( "🤖 You are chatting with {}\n " , model_option. name) ) ,
934950 style:: SetForegroundColor ( Color :: Reset ) ,
@@ -937,6 +953,11 @@ impl ChatSession {
937953 }
938954 }
939955
956+ if self . interactive {
957+ self . stderr . write_all ( & interactive_text) ?;
958+ self . stderr . flush ( ) ?;
959+ }
960+
940961 if let Some ( user_input) = self . initial_input . take ( ) {
941962 self . inner = Some ( ChatState :: HandleInput { input : user_input } ) ;
942963 }
@@ -1397,7 +1418,10 @@ impl ChatSession {
13971418 queue ! ( self . stderr, style:: SetForegroundColor ( Color :: Reset ) ) ?;
13981419 queue ! ( self . stderr, cursor:: Hide ) ?;
13991420 execute ! ( self . stderr, style:: Print ( "\n " ) ) ?;
1400- self . spinner = Some ( Spinner :: new ( Spinners :: Dots , "Thinking..." . to_owned ( ) ) ) ;
1421+
1422+ if self . interactive {
1423+ self . spinner = Some ( Spinner :: new ( Spinners :: Dots , "Thinking..." . to_owned ( ) ) ) ;
1424+ }
14011425
14021426 Ok ( ChatState :: HandleResponseStream (
14031427 os. client . send_message ( conv_state) . await ?,
0 commit comments