//! Domain types for agent lifecycle: turn events, session runtime, progress //! reporting, prompts, and the agent-turn parameter bundle. use serde::{Deserialize, Serialize}; use std::path::PathBuf; use crate::core::{ChatMessage, ToolCallResult, UsageStats}; pub mod defaults; pub mod progress; pub mod prompt; /// Which kind of caller (main agent vs. subagent vs. reviewer) is /// invoking a tool, used to scope permissions and tag log/output paths. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)] pub enum Origin { /// The main agent turn loop. Main, /// A spawned subagent (test-gen, arch-review, security-review, etc.). SubAgent, /// The auto-inline review step after an edit. Reviewer, } impl Origin { /// Short string tag for this origin, used in filenames and logs. pub fn tag(self) -> String { match self { Origin::Main => "main", Origin::SubAgent => "subagent", Origin::Reviewer => "reviewer", } .to_string() } } /// Severity/category of a toast notification, used to pick its color. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum ToastKind { Info, Success, Warning, Error, Lesson, } /// A transient status message shown in the TUI, auto-dismissed after `lifetime_ms`. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Toast { pub kind: ToastKind, pub message: String, pub created_at: i64, pub lifetime_ms: u64, } impl Toast { /// Create a toast with a default 5-second lifetime, stamped with now. pub fn new(kind: ToastKind, message: String) -> Self { Toast { kind, message, created_at: chrono::Utc::now().timestamp_millis(), lifetime_ms: 5000, } } /// Whether this toast's lifetime has elapsed as of `now_ms`. pub fn expired(&self, now_ms: i64) -> bool { let lifetime = self.lifetime_ms as i64; now_ms - self.created_at > lifetime } } /// Agent status for workflow engine progress tracking. #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub enum AgentStatus { Pending, Running, Completed, Failed(String), Cancelled, } impl std::fmt::Display for AgentStatus { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { AgentStatus::Pending => write!(f, "pending"), AgentStatus::Running => write!(f, "running"), AgentStatus::Completed => write!(f, "completed"), AgentStatus::Failed(msg) => write!(f, "failed: {msg}"), AgentStatus::Cancelled => write!(f, "cancelled"), } } } /// Events emitted onto the turn-event queue while an agent turn runs, /// consumed by the event loop to update state and drive re-renders. #[derive(Debug, Clone)] pub enum TurnEvent { AssistantMessage(ChatMessage), ToolResult { tool_call_id: String, tool_name: String, output: String, is_error: bool, path: Option, }, SystemNote { kind: String, message: String, }, StreamStart, StreamToken(String), StreamReasoning(String), StreamDone(ChatMessage), Usage { tokens_in: u64, tokens_out: u64, }, ReviewUsage { tokens_in: u64, tokens_out: u64, }, Compacted(Vec), Error(String), Done, WorkflowAgentUpdate { agent_id: String, agent_name: String, status: AgentStatus, }, TodoUpdate(String), PlanUpdate(String), /// Structured progress report from a subagent or workflow node, /// carrying the current tool name and optional step counters. AgentProgress(crate::agent::progress::AgentProgress), } /// How a pending tool call should be executed when the turn resumes. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum ExecutionModel { Inline, Deferred, AsyncTokio, } /// A tool call awaiting execution, along with which execution model /// (inline, deferred, async) it should run under. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PendingTool { pub tool_name: String, pub args: serde_json::Value, pub execution_model: ExecutionModel, } /// Reference to a background bash job tracked in session state. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct BashJobRef { pub id: String, pub command: String, pub started_at: i64, pub running: bool, } /// Tracks counts of learned patterns by outcome and lifecycle stage. #[derive(Debug, Clone, Default)] pub struct LessonStats { /// Total number of lessons tracked. pub total: u32, /// User-initiated lessons. pub user: u32, /// Feedback-driven lessons. pub feedback: u32, /// Project-scoped lessons. pub project: u32, /// Reference-scoped lessons. pub reference: u32, /// Currently active lessons. pub active: u32, /// Stale (outdated) lessons. pub stale: u32, /// Contradicted lessons. pub contradicted: u32, /// Human-authored lessons. pub human: u32, /// Verified lessons. pub verified: u32, /// Unverified lessons. pub unverified: u32, } /// Per-session runtime state: message history, pending tool queue, /// background bash jobs, lesson/review counters. #[derive(Debug, Clone)] pub struct SessionRuntime { pub messages: Vec, pub tool_call_results: Vec, pub pending_tool_queue: Vec, pub bash_jobs: Vec, pub subagent_queue: usize, pub edit_count: u32, pub consecutive_empty_reviews: u32, pub session_start: i64, /// Aggregated lesson statistics. pub lessons: LessonStats, pub review_count: u32, pub session_dir: PathBuf, pub usage: UsageStats, pub hive_mind_converged: bool, } impl SessionRuntime { pub fn new(session_dir: PathBuf) -> Self { SessionRuntime { messages: Vec::new(), tool_call_results: Vec::new(), pending_tool_queue: Vec::new(), bash_jobs: Vec::new(), subagent_queue: 0, edit_count: 0, consecutive_empty_reviews: 0, session_start: chrono::Utc::now().timestamp_millis(), lessons: LessonStats::default(), review_count: 0, session_dir, usage: UsageStats::default(), hive_mind_converged: false, } } pub fn push_message(&mut self, msg: ChatMessage) { self.messages.push(msg); } } /// Simple ASCII progress display for a long-running operation. #[derive(Debug, Clone)] pub struct ProgressState { pub current: u64, pub total: u64, pub message: String, pub start_time: i64, } use std::collections::VecDeque; use std::sync::atomic::AtomicBool; use std::sync::{Arc, Mutex}; /// Owned parameters required to spawn and execute an agent turn. pub struct AgentTurnParams { pub messages: Vec, pub session_dir: PathBuf, pub workspace_roots: Vec, pub turn_events: Arc>>, pub in_flight: Arc, pub abort: Arc, pub api_key: String, pub model: String, pub api_base: Option, }