agent_air_tui/widgets/conversation.rs
1//! ConversationView trait for conversation/chat display widgets.
2//!
3//! This trait defines the interface for widgets that display conversation history,
4//! supporting streaming, tool messages, and session state management.
5
6use ratatui::{Frame, layout::Rect};
7use std::any::Any;
8
9use super::ToolStatus;
10use crate::themes::Theme;
11
12/// Trait for conversation/chat display widgets.
13///
14/// This trait is separate from the Widget trait - a ConversationView may also
15/// implement Widget, but this trait focuses specifically on conversation display
16/// functionality.
17///
18/// # Session State
19///
20/// ConversationView supports saving and restoring state for session switching:
21/// - `save_state()` returns an opaque state object
22/// - `restore_state()` restores from a previously saved state
23/// - `clear()` resets the view while preserving configuration
24///
25/// # Example Implementation
26///
27/// ```ignore
28/// impl ConversationView for MyChatView {
29/// fn add_user_message(&mut self, content: String) {
30/// self.messages.push(Message::user(content));
31/// }
32/// // ... implement other methods
33/// }
34/// ```
35pub trait ConversationView: Send + 'static {
36 // --- Message Operations ---
37
38 /// Add a user message to the conversation
39 fn add_user_message(&mut self, content: String);
40
41 /// Add an assistant message to the conversation
42 fn add_assistant_message(&mut self, content: String);
43
44 /// Add a system message to the conversation
45 fn add_system_message(&mut self, content: String);
46
47 // --- Streaming ---
48
49 /// Append text to the current streaming response
50 fn append_streaming(&mut self, text: &str);
51
52 /// Complete the streaming response and finalize it as a message
53 fn complete_streaming(&mut self);
54
55 /// Discard the streaming buffer without saving (used on cancel)
56 fn discard_streaming(&mut self);
57
58 /// Check if currently streaming a response
59 fn is_streaming(&self) -> bool;
60
61 // --- Tool Messages ---
62
63 /// Add a tool execution message
64 fn add_tool_message(&mut self, tool_use_id: &str, display_name: &str, display_title: &str);
65
66 /// Update the status of a tool message
67 fn update_tool_status(&mut self, tool_use_id: &str, status: ToolStatus);
68
69 // --- Scrolling ---
70
71 /// Scroll up by the implementation's scroll step
72 fn scroll_up(&mut self);
73
74 /// Scroll down by the implementation's scroll step
75 fn scroll_down(&mut self);
76
77 /// Enable auto-scroll and scroll to bottom (called when user submits a message)
78 fn enable_auto_scroll(&mut self);
79
80 // --- Rendering ---
81
82 /// Render the conversation view
83 ///
84 /// # Arguments
85 /// * `frame` - The ratatui frame to render to
86 /// * `area` - The area to render within
87 /// * `theme` - The current theme
88 /// * `pending_status` - Optional pending status message (e.g., "running tools...")
89 fn render(
90 &mut self,
91 frame: &mut Frame,
92 area: Rect,
93 theme: &Theme,
94 pending_status: Option<&str>,
95 );
96
97 // --- Animation ---
98
99 /// Advance the spinner animation (called periodically during activity)
100 fn step_spinner(&mut self);
101
102 // --- Session State ---
103
104 /// Save the current state for session switching
105 ///
106 /// Returns an opaque state object that can be restored later.
107 fn save_state(&self) -> Box<dyn Any + Send>;
108
109 /// Restore state from a previously saved state
110 ///
111 /// If the state cannot be downcast to the expected type, this is a no-op.
112 fn restore_state(&mut self, state: Box<dyn Any + Send>);
113
114 /// Clear conversation content while preserving configuration
115 ///
116 /// This resets messages, streaming state, and scroll position,
117 /// but keeps settings like title, theme configuration, and renderers.
118 fn clear(&mut self);
119}
120
121/// Type alias for conversation view factory functions.
122///
123/// A factory is called to create a new ConversationView instance,
124/// typically when creating a new session or clearing the current one.
125///
126/// # Example
127///
128/// ```ignore
129/// let factory: ConversationViewFactory = Box::new(|| {
130/// Box::new(ChatView::new()
131/// .with_title("My Agent")
132/// .with_initial_content(welcome_renderer))
133/// });
134/// ```
135pub type ConversationViewFactory = Box<dyn Fn() -> Box<dyn ConversationView> + Send + Sync>;