agent_core/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::{layout::Rect, Frame};
7use std::any::Any;
8
9use super::ToolStatus;
10use crate::tui::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(&mut self, frame: &mut Frame, area: Rect, theme: &Theme, pending_status: Option<&str>);
90
91 // --- Animation ---
92
93 /// Advance the spinner animation (called periodically during activity)
94 fn step_spinner(&mut self);
95
96 // --- Session State ---
97
98 /// Save the current state for session switching
99 ///
100 /// Returns an opaque state object that can be restored later.
101 fn save_state(&self) -> Box<dyn Any + Send>;
102
103 /// Restore state from a previously saved state
104 ///
105 /// If the state cannot be downcast to the expected type, this is a no-op.
106 fn restore_state(&mut self, state: Box<dyn Any + Send>);
107
108 /// Clear conversation content while preserving configuration
109 ///
110 /// This resets messages, streaming state, and scroll position,
111 /// but keeps settings like title, theme configuration, and renderers.
112 fn clear(&mut self);
113}
114
115/// Type alias for conversation view factory functions.
116///
117/// A factory is called to create a new ConversationView instance,
118/// typically when creating a new session or clearing the current one.
119///
120/// # Example
121///
122/// ```ignore
123/// let factory: ConversationViewFactory = Box::new(|| {
124/// Box::new(ChatView::new()
125/// .with_title("My Agent")
126/// .with_initial_content(welcome_renderer))
127/// });
128/// ```
129pub type ConversationViewFactory = Box<dyn Fn() -> Box<dyn ConversationView> + Send + Sync>;