@@ -67,6 +67,43 @@ pub enum AgentMessage {
6767 CloudSynthesisComplete ( Result < AtomicNote , CloudError > ) ,
6868}
6969
70+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
71+ pub enum RuixenState {
72+ Resting , // 😴💤🌙 - Waiting for input, peaceful state
73+ Curious , // 🤨🧠💭 - Analyzing user query, thinking
74+ Working , // 😤💦📝 - Processing complex query, working hard
75+ Searching , // 🔍☁️⚡ - Cloud processing, searching for answers
76+ Celebrating , // 💎🚀🎯 - Successful synthesis, celebration
77+ Confused , // 😅🤦♂️📝 - Error state, but learning from it
78+ }
79+
80+ impl RuixenState {
81+ pub fn emoji_expression ( & self ) -> & ' static str {
82+ match self {
83+ RuixenState :: Resting => "😴 💤 🌙" ,
84+ RuixenState :: Curious => "🤨 🧠 💭" ,
85+ RuixenState :: Working => "😤 💦 📝" ,
86+ RuixenState :: Searching => "🔍 ☁️ ⚡" ,
87+ RuixenState :: Celebrating => "💎 🚀 🎯" ,
88+ RuixenState :: Confused => "😅 🤦♂️ 📝" ,
89+ }
90+ }
91+
92+ pub fn from_agent_status ( status : AgentStatus ) -> Self {
93+ match status {
94+ AgentStatus :: Ready => RuixenState :: Resting ,
95+ AgentStatus :: Orchestrating => RuixenState :: Curious ,
96+ AgentStatus :: Searching => RuixenState :: Searching ,
97+ AgentStatus :: Complete => RuixenState :: Celebrating ,
98+ AgentStatus :: LocalEndpointError | AgentStatus :: CloudEndpointError => {
99+ RuixenState :: Confused
100+ }
101+ AgentStatus :: ValidatingLocal | AgentStatus :: ValidatingCloud => RuixenState :: Working ,
102+ _ => RuixenState :: Resting ,
103+ }
104+ }
105+ }
106+
70107#[ derive( Debug , Clone , Copy , PartialEq , Eq , Default ) ]
71108pub enum SettingsSelection {
72109 #[ default]
@@ -129,6 +166,8 @@ pub struct App {
129166 cloud_tokens_used : u32 , // Token count for current cloud request
130167 show_autocomplete : bool ,
131168 autocomplete_index : usize ,
169+ ruixen_reaction_state : Option < RuixenState > , // Temporary reaction state
170+ reaction_timer : Option < std:: time:: Instant > , // When reaction started,
132171}
133172
134173impl App {
@@ -162,6 +201,76 @@ impl App {
162201 cloud_tokens_used : 0 ,
163202 show_autocomplete : false ,
164203 autocomplete_index : 0 ,
204+ ruixen_reaction_state : None ,
205+ reaction_timer : None ,
206+ }
207+ }
208+
209+ fn get_current_ruixen_emoji ( & self ) -> & ' static str {
210+ // Check if we have a temporary reaction that should expire
211+ if let ( Some ( reaction) , Some ( timer) ) = ( & self . ruixen_reaction_state , & self . reaction_timer ) {
212+ if timer. elapsed ( ) <= std:: time:: Duration :: from_millis ( 2000 ) {
213+ // 2 second reactions
214+ return reaction. emoji_expression ( ) ;
215+ }
216+ }
217+
218+ // Default to agent status-based emoji
219+ RuixenState :: from_agent_status ( self . agent_status ) . emoji_expression ( )
220+ }
221+
222+ fn set_ruixen_reaction ( & mut self , reaction : RuixenState ) {
223+ self . ruixen_reaction_state = Some ( reaction) ;
224+ self . reaction_timer = Some ( std:: time:: Instant :: now ( ) ) ;
225+ }
226+
227+ fn cleanup_expired_reactions ( & mut self ) {
228+ if let ( Some ( _) , Some ( timer) ) = ( & self . ruixen_reaction_state , & self . reaction_timer ) {
229+ if timer. elapsed ( ) > std:: time:: Duration :: from_millis ( 2000 ) {
230+ self . ruixen_reaction_state = None ;
231+ self . reaction_timer = None ;
232+ }
233+ }
234+ }
235+
236+ fn analyze_query_complexity ( & self , query : & str ) -> RuixenState {
237+ let word_count = query. split_whitespace ( ) . count ( ) ;
238+ let has_questions = query. contains ( '?' ) ;
239+ let has_complex_words = query. split_whitespace ( ) . any ( |word| word. len ( ) > 10 ) ;
240+ let is_philosophical = query. to_lowercase ( ) . contains ( "why" )
241+ || query. to_lowercase ( ) . contains ( "how" )
242+ || query. to_lowercase ( ) . contains ( "what if" ) ;
243+
244+ // Determine Ruixen's initial reaction based on query complexity
245+ if word_count < 5 && !has_questions {
246+ RuixenState :: Curious // 🤨🧠💭 - Simple query, just curious
247+ } else if ( word_count > 15 ) || has_complex_words || is_philosophical {
248+ RuixenState :: Working // 😤💦📝 - Complex query, need to work hard
249+ } else {
250+ RuixenState :: Curious // 🤨🧠💭 - Standard query, thinking
251+ }
252+ }
253+
254+ fn analyze_synthesis_quality ( & self , response : & AtomicNote ) -> RuixenState {
255+ let body_length = response. body_text . len ( ) ;
256+ let has_insights = response. body_text . to_lowercase ( ) . contains ( "insight" )
257+ || response. body_text . to_lowercase ( ) . contains ( "reveals" )
258+ || response. body_text . to_lowercase ( ) . contains ( "understanding" ) ;
259+ let has_technical_terms = response
260+ . body_text
261+ . split_whitespace ( )
262+ . any ( |word| word. len ( ) > 12 || word. contains ( "ology" ) || word. contains ( "tion" ) ) ;
263+ let tag_count = response. header_tags . len ( ) ;
264+
265+ // Determine Ruixen's reaction to the synthesis quality
266+ if body_length > 800 && has_insights && tag_count > 3 {
267+ RuixenState :: Celebrating // 💎🚀🎯 - Excellent synthesis, celebration!
268+ } else if body_length > 400 && ( has_insights || has_technical_terms) {
269+ RuixenState :: Celebrating // 💎🚀🎯 - Good synthesis, satisfied
270+ } else if body_length < 200 {
271+ RuixenState :: Confused // 😅🤦♂️📝 - Short response, maybe didn't work well
272+ } else {
273+ RuixenState :: Curious // 🤨🧠💭 - Decent response, still thinking
165274 }
166275 }
167276
@@ -173,7 +282,7 @@ impl App {
173282 } ;
174283
175284 let block = Block :: default ( )
176- . title ( " Synthesize Knowledge " )
285+ . title ( format ! ( " {} " , self . get_current_ruixen_emoji ( ) ) )
177286 . borders ( Borders :: ALL )
178287 . style ( self . theme . ratatui_style ( Element :: Active ) ) ;
179288
@@ -299,6 +408,9 @@ impl App {
299408
300409 pub async fn run ( & mut self , terminal : & mut Terminal < CrosstermBackend < Stdout > > ) -> Result < ( ) > {
301410 while !self . should_quit {
411+ // Clean up expired reactions
412+ self . cleanup_expired_reactions ( ) ;
413+
302414 self . draw ( terminal) ?;
303415
304416 // Handle validation messages from background tasks
@@ -496,7 +608,7 @@ impl App {
496608 ) ;
497609
498610 let block = Block :: default ( )
499- . title ( " Synthesis Complete " )
611+ . title ( format ! ( " {} " , self . get_current_ruixen_emoji ( ) ) )
500612 . borders ( Borders :: ALL )
501613 . style ( self . theme . ratatui_style ( Element :: Active ) ) ;
502614
@@ -519,6 +631,7 @@ impl App {
519631 commands : & self . get_filtered_slash_commands ( ) ,
520632 selected_index : self . autocomplete_index ,
521633 } ,
634+ self . get_current_ruixen_emoji ( ) ,
522635 ) ;
523636 }
524637 } ) ?;
@@ -638,6 +751,10 @@ impl App {
638751 self . agent_status = AgentStatus :: Ready ;
639752 }
640753 AgentMessage :: CloudSynthesisComplete ( Ok ( response) ) => {
754+ // Analyze the synthesis quality and show reaction
755+ let reaction = self . analyze_synthesis_quality ( & response) ;
756+ self . set_ruixen_reaction ( reaction) ;
757+
641758 self . cloud_response = Some ( response) ;
642759 self . mode = AppMode :: Complete ;
643760 self . agent_status = AgentStatus :: Complete ;
@@ -1079,6 +1196,10 @@ impl App {
10791196 // Store the original user query for metadata
10801197 self . original_user_query = message. clone ( ) ;
10811198
1199+ // Analyze query complexity and show brief reaction
1200+ let reaction = self . analyze_query_complexity ( & message) ;
1201+ self . set_ruixen_reaction ( reaction) ;
1202+
10821203 // Estimate tokens for local request (rough: chars/4 + prompt overhead)
10831204 self . local_tokens_used = ( message. len ( ) / 4 ) as u32 + 500 ; // ~500 tokens for prompt template
10841205 self . cloud_tokens_used = 0 ; // Reset cloud tokens for new session
0 commit comments