@@ -6,6 +6,7 @@ use super::{
66 settings_modal:: render_settings_modal,
77} ;
88use agentic_core:: {
9+ cloud,
910 models:: { ModelValidator , OllamaModel , OpenRouterModel } ,
1011 orchestrator,
1112 settings:: { Settings , ValidationError } ,
@@ -49,6 +50,8 @@ pub enum AgentStatus {
4950 LocalEndpointError ,
5051 CloudEndpointError ,
5152 Orchestrating ,
53+ Searching ,
54+ Complete ,
5255}
5356
5457#[ derive( Debug ) ]
@@ -63,6 +66,7 @@ pub enum ValidationMessage {
6366pub enum AgentMessage {
6467 ProposalsGenerated ( Result < Vec < String > , anyhow:: Error > ) ,
6568 RevisedProposalGenerated ( Result < String , anyhow:: Error > ) ,
69+ CloudSynthesisComplete ( Result < String , anyhow:: Error > ) ,
6670}
6771
6872#[ derive( Debug , Clone , Copy , PartialEq , Eq , Default ) ]
@@ -119,6 +123,8 @@ pub struct App {
119123 proposals : Vec < String > ,
120124 current_proposal_index : usize ,
121125 final_prompt : String ,
126+ cloud_response : String ,
127+ synthesis_scroll : u16 ,
122128}
123129
124130impl App {
@@ -144,6 +150,8 @@ impl App {
144150 proposals : Vec :: new ( ) ,
145151 current_proposal_index : 0 ,
146152 final_prompt : String :: new ( ) ,
153+ cloud_response : String :: new ( ) ,
154+ synthesis_scroll : 0 ,
147155 }
148156 }
149157
@@ -202,7 +210,7 @@ impl App {
202210 // Clean up the proposal text - remove template artifacts
203211 let proposal_text = proposal
204212 . replace ( "Context statement: " , "" )
205- . replace ( "Another context: " , "" )
213+ . replace ( "Another context: " , "" )
206214 . replace ( "Third context: " , "" )
207215 . replace ( "Context statement - " , "" )
208216 . replace ( "Another context - " , "" )
@@ -226,8 +234,7 @@ impl App {
226234
227235 let proposals_paragraph = Paragraph :: new ( proposal_lines)
228236 . style ( self . theme . ratatui_style ( Element :: Text ) )
229- . wrap ( Wrap { trim : true } )
230- . scroll ( ( self . current_proposal_index as u16 * 3 , 0 ) ) ; // Scroll to selected proposal
237+ . wrap ( Wrap { trim : true } ) ;
231238
232239 frame. render_widget ( proposals_paragraph, chunks[ 1 ] ) ;
233240
@@ -241,11 +248,7 @@ impl App {
241248 }
242249
243250 fn render_coaching_tip_modal ( & self , frame : & mut ratatui:: Frame , area : Rect ) {
244- use ratatui:: {
245- prelude:: Alignment ,
246- text:: { Line , Span } ,
247- widgets:: Paragraph ,
248- } ;
251+ use ratatui:: { prelude:: Alignment , text:: Line , widgets:: Paragraph } ;
249252
250253 let block = Block :: default ( )
251254 . title ( " Coaching Tip " )
@@ -267,8 +270,9 @@ impl App {
267270 // Main coaching message with tips
268271 let message_text = vec ! [
269272 Line :: from( "" ) ,
270- Line :: from( "Ruixen is having a tough time with this abstract query. Smaller" ) ,
271- Line :: from( "local models work best with clear and concrete questions." ) ,
273+ Line :: from( "Ruixen is having a tough time with this abstract query." ) ,
274+ Line :: from( "" ) ,
275+ Line :: from( ":: Smaller local models work best with clear and concrete questions." ) ,
272276 Line :: from( "" ) ,
273277 Line :: from( ":: Try a more direct question, add specific context, or break" ) ,
274278 Line :: from( " the query down into smaller steps." ) ,
@@ -463,10 +467,13 @@ impl App {
463467 frame. render_widget ( Clear , modal_area) ;
464468 self . render_coaching_tip_modal ( frame, modal_area) ;
465469 } else if self . mode == AppMode :: Complete {
466- let block = Block :: default ( ) . title ( "Final Prompt" ) . borders ( Borders :: ALL ) ;
467- let paragraph = Paragraph :: new ( self . final_prompt . as_str ( ) )
470+ let block = Block :: default ( )
471+ . title ( "Synthesis Complete" )
472+ . borders ( Borders :: ALL ) ;
473+ let paragraph = Paragraph :: new ( self . cloud_response . as_str ( ) )
468474 . block ( block)
469- . wrap ( Wrap { trim : true } ) ;
475+ . wrap ( Wrap { trim : true } )
476+ . scroll ( ( self . synthesis_scroll , 0 ) ) ;
470477 frame. render_widget ( paragraph, app_chunks[ 1 ] ) ;
471478 } else {
472479 render_chat (
@@ -600,6 +607,16 @@ impl App {
600607 // TODO: Set error state and display to user
601608 self . agent_status = AgentStatus :: Ready ;
602609 }
610+ AgentMessage :: CloudSynthesisComplete ( Ok ( response) ) => {
611+ self . cloud_response = response;
612+ self . mode = AppMode :: Complete ;
613+ self . agent_status = AgentStatus :: Complete ;
614+ }
615+ AgentMessage :: CloudSynthesisComplete ( Err ( _e) ) => {
616+ // Show coaching tip for cloud API failures
617+ self . mode = AppMode :: CoachingTip ;
618+ self . agent_status = AgentStatus :: Ready ;
619+ }
603620 }
604621 }
605622
@@ -841,12 +858,12 @@ impl App {
841858 }
842859 }
843860 KeyCode :: Enter => {
844- // Synthesize - use selected proposal
861+ // Synthesize - send proposal to cloud for synthesis
845862 if let Some ( proposal) =
846863 self . proposals . get ( self . current_proposal_index )
847864 {
848865 self . final_prompt = proposal. clone ( ) ;
849- self . mode = AppMode :: Complete ;
866+ self . handle_cloud_synthesis ( ) ;
850867 }
851868 }
852869 KeyCode :: Char ( 'e' ) => {
@@ -879,11 +896,20 @@ impl App {
879896 _ => { }
880897 } ,
881898 AppMode :: Complete => match key. code {
899+ KeyCode :: Up => {
900+ self . synthesis_scroll = self . synthesis_scroll . saturating_sub ( 1 ) ;
901+ }
902+ KeyCode :: Down => {
903+ self . synthesis_scroll = self . synthesis_scroll . saturating_add ( 1 ) ;
904+ }
882905 KeyCode :: Enter | KeyCode :: Esc => {
883906 self . mode = AppMode :: Normal ;
884907 self . final_prompt . clear ( ) ;
885908 self . proposals . clear ( ) ;
886909 self . current_proposal_index = 0 ;
910+ self . cloud_response . clear ( ) ;
911+ self . synthesis_scroll = 0 ;
912+ self . agent_status = AgentStatus :: Ready ;
887913 }
888914 _ => { }
889915 } ,
@@ -947,6 +973,21 @@ impl App {
947973 self . edit_buffer . clear ( ) ;
948974 }
949975
976+ fn handle_cloud_synthesis ( & mut self ) {
977+ // Set status to searching and trigger cloud API call
978+ self . agent_status = AgentStatus :: Searching ;
979+
980+ let prompt = self . final_prompt . clone ( ) ;
981+ let api_key = self . settings . api_key . clone ( ) ;
982+ let model = self . settings . cloud_model . clone ( ) ;
983+ let tx = self . agent_tx . clone ( ) ;
984+
985+ tokio:: spawn ( async move {
986+ let result = cloud:: call_cloud_model ( & api_key, & model, & prompt) . await ;
987+ let _ = tx. send ( AgentMessage :: CloudSynthesisComplete ( result) ) ;
988+ } ) ;
989+ }
990+
950991 fn handle_slash_command ( & mut self , command : & str ) {
951992 match command {
952993 "/setting" | "/settings" => {
0 commit comments