mod handler;
mod recorder;
pub use handler::EventHandler;
pub use recorder::{EventRecorder, RecordedEvent, load_recorded_events};
use crossterm::event::{Event as CrosstermEvent, KeyEvent};
use opendev_models::message::ChatMessage;
use opendev_runtime::InterruptToken;
#[derive(Debug)]
#[allow(clippy::large_enum_variant)]
pub enum AppEvent {
Terminal(CrosstermEvent),
Key(KeyEvent),
Resize(u16, u16),
ScrollUp,
ScrollDown,
MouseDown { col: u16, row: u16 },
MouseDrag { col: u16, row: u16 },
MouseUp { col: u16, row: u16 },
FocusGained,
Tick,
AgentStarted,
AgentChunk(String),
AgentMessage(ChatMessage),
AgentFinished,
AgentError(String),
ToolStarted {
tool_id: String,
tool_name: String,
args: std::collections::HashMap<String, serde_json::Value>,
},
ToolOutput { tool_id: String, output: String },
ToolResult {
tool_id: String,
tool_name: String,
output: String,
success: bool,
args: std::collections::HashMap<String, serde_json::Value>,
},
ToolFinished { tool_id: String, success: bool },
ToolApprovalRequired {
tool_id: String,
tool_name: String,
description: String,
},
ToolApprovalRequested {
command: String,
working_dir: String,
response_tx: tokio::sync::oneshot::Sender<opendev_runtime::ToolApprovalDecision>,
},
AskUserRequested {
question: String,
options: Vec<String>,
default: Option<String>,
response_tx: tokio::sync::oneshot::Sender<String>,
},
SubagentStarted {
subagent_id: String,
subagent_name: String,
task: String,
cancel_token: Option<tokio_util::sync::CancellationToken>,
},
SubagentToolCall {
subagent_id: String,
subagent_name: String,
tool_name: String,
tool_id: String,
args: std::collections::HashMap<String, serde_json::Value>,
},
SubagentToolComplete {
subagent_id: String,
subagent_name: String,
tool_name: String,
tool_id: String,
success: bool,
},
SubagentFinished {
subagent_id: String,
subagent_name: String,
success: bool,
result_summary: String,
tool_call_count: usize,
shallow_warning: Option<String>,
},
SubagentTokenUpdate {
subagent_id: String,
subagent_name: String,
input_tokens: u64,
output_tokens: u64,
},
ReasoningContent(String),
ReasoningBlockStart,
TaskProgressStarted { description: String },
TaskProgressFinished,
BudgetExhausted { cost_usd: f64, budget_usd: f64 },
FileChangeSummary {
files: usize,
additions: u64,
deletions: u64,
},
ContextUsage(f64),
CompactionStarted,
CompactionFinished { success: bool, message: String },
PlanApprovalRequested {
plan_content: String,
response_tx: tokio::sync::oneshot::Sender<opendev_runtime::PlanDecision>,
},
UserSubmit(String),
Interrupt,
SetInterruptToken(InterruptToken),
AgentInterrupted,
ModeChanged(String),
KillTask(String),
AgentBackgrounded {
task_id: String,
query_summary: String,
},
BackgroundAgentCompleted {
task_id: String,
success: bool,
result_summary: String,
full_result: String,
cost_usd: f64,
tool_call_count: usize,
},
BackgroundAgentProgress {
task_id: String,
tool_name: String,
tool_count: usize,
},
BackgroundAgentKilled { task_id: String },
BackgroundNudge { content: String },
BackgroundAgentActivity { task_id: String, line: String },
SetBackgroundAgentToken {
task_id: String,
query: String,
session_id: String,
interrupt_token: InterruptToken,
},
SnapshotTaken { hash: String },
UndoResult { success: bool, message: String },
RedoResult { success: bool, message: String },
ShareResult { path: String },
FileChanged { paths: Vec<String> },
SessionTitleUpdated(String),
Quit,
}
#[cfg(test)]
mod tests;