1use crate::agent::core::Agent;
2use crate::apis::api_client::SessionManager;
3use crate::app::commands::SpecialCommand;
4use crate::app::history::ConversationSummary;
5use crate::app::models::ToolPermissionStatus;
6use crate::app::permissions::PendingToolExecution;
7use crate::app::utils::ScrollState;
8use crate::models::ModelConfig;
9use std::sync::mpsc;
10use std::time::{Duration, Instant};
11use tokio::runtime::Runtime;
12use uuid::Uuid;
13
14#[derive(Debug, PartialEq)]
15pub enum AppState {
16 Setup,
17 ApiKeyInput,
18 Error(String),
19 Chat,
20}
21
22#[derive(Debug, Clone, PartialEq)]
24pub enum TaskStatus {
25 InProgress,
27 Completed {
29 duration: Duration,
30 tool_uses: u32,
31 input_tokens: u32,
32 output_tokens: u32,
33 },
34 Failed(String),
36}
37
38#[derive(Debug, Clone)]
40pub struct Task {
41 pub id: String,
42 pub description: String,
43 pub status: TaskStatus,
44 pub created_at: Instant,
45 pub updated_at: Instant,
46 pub tool_count: u32,
47 pub input_tokens: u32,
48 pub output_tokens: u32,
49}
50
51impl Task {
52 pub fn new(description: &str) -> Self {
54 let now = Instant::now();
55 Self {
56 id: format!("{}", Uuid::new_v4().simple()),
57 description: description.to_string(),
58 status: TaskStatus::InProgress,
59 created_at: now,
60 updated_at: now,
61 tool_count: 0,
62 input_tokens: 0,
63 output_tokens: 0,
64 }
65 }
66
67 pub fn complete(&mut self, _tool_uses: u32, output_tokens: u32) {
69 let now = Instant::now();
71 let duration = now.duration_since(self.created_at);
72
73 self.output_tokens = output_tokens;
75
76 self.status = TaskStatus::Completed {
77 duration,
78 tool_uses: self.tool_count, input_tokens: self.input_tokens,
80 output_tokens: self.output_tokens,
81 };
82 self.updated_at = now;
83 }
84
85 pub fn fail(&mut self, error: &str) {
87 self.status = TaskStatus::Failed(error.to_string());
88 self.updated_at = Instant::now();
89 }
90
91 pub fn add_tool_use(&mut self) {
93 self.tool_count += 1;
94 self.updated_at = Instant::now();
95 }
96
97 pub fn add_input_tokens(&mut self, tokens: u32) {
99 self.input_tokens += tokens;
100 self.updated_at = Instant::now();
101 }
102
103 pub fn is_in_progress(&self) -> bool {
105 matches!(self.status, TaskStatus::InProgress)
106 }
107}
108
109use tui_textarea::TextArea;
110
111pub struct App {
112 pub state: AppState,
113 pub textarea: TextArea<'static>, pub input: String, pub messages: Vec<String>,
116 pub logs: Vec<String>, pub show_logs: bool, pub selected_model: usize,
119 pub available_models: Vec<ModelConfig>,
120 pub error_message: Option<String>,
121 pub debug_messages: bool,
122 pub message_scroll: ScrollState, pub log_scroll: ScrollState, pub scroll_position: usize, pub last_query_time: Instant,
126 pub last_message_time: Instant, pub use_agent: bool,
128 pub agent: Option<Agent>,
129 pub tokio_runtime: Option<Runtime>,
130 pub agent_progress_rx: Option<mpsc::Receiver<String>>,
131 pub api_key: Option<String>,
132 pub current_working_dir: Option<String>,
133 pub command_mode: bool,
135 pub available_commands: Vec<SpecialCommand>,
136 pub selected_command: usize,
137 pub show_command_menu: bool,
138 pub permission_required: bool, pub pending_tool: Option<PendingToolExecution>, pub tool_permission_status: ToolPermissionStatus, pub tool_execution_in_progress: bool, pub show_intermediate_steps: bool, pub show_shortcuts_hint: bool, pub show_detailed_shortcuts: bool, pub cursor_position: usize, pub tasks: Vec<Task>,
150 pub current_task_id: Option<String>,
151 pub task_scroll: ScrollState, pub task_scroll_position: usize, pub conversation_summaries: Vec<ConversationSummary>, pub session_manager: Option<SessionManager>, pub session_id: String, }