@@ -402,6 +402,10 @@ pub enum ChatError {
402
402
Interrupted { tool_uses : Option < Vec < QueuedTool > > } ,
403
403
#[ error( transparent) ]
404
404
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 ,
405
409
}
406
410
407
411
impl ChatError {
@@ -415,6 +419,7 @@ impl ChatError {
415
419
ChatError :: Custom ( _) => None ,
416
420
ChatError :: Interrupted { .. } => None ,
417
421
ChatError :: GetPromptError ( _) => None ,
422
+ ChatError :: NonInteractiveToolApproval => None ,
418
423
}
419
424
}
420
425
}
@@ -430,6 +435,7 @@ impl ReasonCode for ChatError {
430
435
ChatError :: Interrupted { .. } => "Interrupted" . to_string ( ) ,
431
436
ChatError :: GetPromptError ( _) => "GetPromptError" . to_string ( ) ,
432
437
ChatError :: Auth ( _) => "AuthError" . to_string ( ) ,
438
+ ChatError :: NonInteractiveToolApproval => "NonInteractiveToolApproval" . to_string ( ) ,
433
439
}
434
440
}
435
441
}
@@ -573,10 +579,16 @@ impl ChatSession {
573
579
let ctrl_c_stream = ctrl_c ( ) ;
574
580
let result = match self . inner . take ( ) . expect ( "state must always be Some" ) {
575
581
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
+ } ;
580
592
581
593
self . prompt_user ( os, skip_printing_tools) . await
582
594
} ,
@@ -862,6 +874,7 @@ impl Default for ChatState {
862
874
impl ChatSession {
863
875
async fn spawn ( & mut self , os : & mut Os ) -> Result < ( ) > {
864
876
let is_small_screen = self . terminal_width ( ) < GREETING_BREAK_POINT ;
877
+ let mut interactive_text: Vec < u8 > = Vec :: new ( ) ;
865
878
if os
866
879
. database
867
880
. settings
@@ -876,20 +889,20 @@ impl ChatSession {
876
889
} ,
877
890
} ;
878
891
879
- execute ! ( self . stderr , style:: Print ( welcome_text) , style:: Print ( "\n \n " ) , ) ?;
892
+ execute ! ( interactive_text , style:: Print ( welcome_text) , style:: Print ( "\n \n " ) , ) ?;
880
893
881
894
let tip = ROTATING_TIPS [ usize:: try_from ( rand:: random :: < u32 > ( ) ) . unwrap_or ( 0 ) % ROTATING_TIPS . len ( ) ] ;
882
895
if is_small_screen {
883
896
// If the screen is small, print the tip in a single line
884
897
execute ! (
885
- self . stderr ,
898
+ interactive_text ,
886
899
style:: Print ( "💡 " . to_string( ) ) ,
887
900
style:: Print ( tip) ,
888
901
style:: Print ( "\n " )
889
902
) ?;
890
903
} else {
891
904
draw_box (
892
- & mut self . stderr ,
905
+ & mut interactive_text ,
893
906
"Did you know?" ,
894
907
tip,
895
908
GREETING_BREAK_POINT ,
@@ -898,7 +911,7 @@ impl ChatSession {
898
911
}
899
912
900
913
execute ! (
901
- self . stderr ,
914
+ interactive_text ,
902
915
style:: Print ( "\n " ) ,
903
916
style:: Print ( match is_small_screen {
904
917
true => SMALL_SCREEN_POPULAR_SHORTCUTS ,
@@ -911,24 +924,27 @@ impl ChatSession {
911
924
. dark_grey( )
912
925
)
913
926
) ?;
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
+ ) ?;
915
932
}
916
933
917
934
if self . all_tools_trusted ( ) {
918
935
queue ! (
919
- self . stderr ,
936
+ interactive_text ,
920
937
style:: Print ( format!(
921
938
"{}{TRUST_ALL_TEXT}\n \n " ,
922
939
if !is_small_screen { "\n " } else { "" }
923
940
) )
924
941
) ?;
925
942
}
926
- self . stderr . flush ( ) ?;
927
943
928
944
if let Some ( ref id) = self . conversation . model {
929
945
if let Some ( model_option) = MODEL_OPTIONS . iter ( ) . find ( |option| option. model_id == * id) {
930
946
execute ! (
931
- self . stderr ,
947
+ interactive_text ,
932
948
style:: SetForegroundColor ( Color :: Cyan ) ,
933
949
style:: Print ( format!( "🤖 You are chatting with {}\n " , model_option. name) ) ,
934
950
style:: SetForegroundColor ( Color :: Reset ) ,
@@ -937,6 +953,11 @@ impl ChatSession {
937
953
}
938
954
}
939
955
956
+ if self . interactive {
957
+ self . stderr . write_all ( & interactive_text) ?;
958
+ self . stderr . flush ( ) ?;
959
+ }
960
+
940
961
if let Some ( user_input) = self . initial_input . take ( ) {
941
962
self . inner = Some ( ChatState :: HandleInput { input : user_input } ) ;
942
963
}
@@ -1397,7 +1418,10 @@ impl ChatSession {
1397
1418
queue ! ( self . stderr, style:: SetForegroundColor ( Color :: Reset ) ) ?;
1398
1419
queue ! ( self . stderr, cursor:: Hide ) ?;
1399
1420
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
+ }
1401
1425
1402
1426
Ok ( ChatState :: HandleResponseStream (
1403
1427
os. client . send_message ( conv_state) . await ?,
0 commit comments