Skip to main content

ralph_workflow/pipeline/
mod.rs

1//! Pipeline Execution Module
2//!
3//! This module contains the core pipeline execution infrastructure:
4//! - Types for tracking pipeline statistics and RAII cleanup
5//! - Model flag resolution utilities
6//! - Command execution helpers with fault-tolerant fallback chains
7//! - Timer utilities for tracking execution duration
8//! - Session management for agent continuation
9//! - Log file path management
10//!
11//! # Module Structure
12//!
13//! - [`model_flag`] - Model flag resolution and provider detection
14//! - [`runner`] - Pipeline runtime and command execution with fallback
15//! - [`types`] - Pipeline statistics tracking and RAII guards
16//! - [`session`] - Session extraction and continuation for XSD retries
17//! - [`logfile`] - Unified log file path creation, parsing, and discovery
18
19#![deny(unsafe_code)]
20
21mod clipboard;
22mod fallback;
23pub mod idle_timeout;
24pub mod logfile;
25mod model_flag;
26mod prompt;
27mod runner;
28pub mod session;
29mod types;
30
31pub use fallback::OutputValidator;
32pub use prompt::{run_with_prompt, PipelineRuntime, PromptCommand};
33pub use runner::{
34    run_with_fallback_and_validator, run_xsd_retry_with_session, FallbackConfig, XsdRetryConfig,
35};
36pub use types::{AgentPhaseGuard, Stats};
37
38// ===== Timer Utilities =====
39
40use std::time::{Duration, Instant};
41
42/// Timer for tracking execution duration
43#[derive(Clone)]
44pub struct Timer {
45    start_time: Instant,
46    phase_start: Instant,
47}
48
49impl Timer {
50    /// Create a new timer, starting now
51    pub fn new() -> Self {
52        let now = Instant::now();
53        Self {
54            start_time: now,
55            phase_start: now,
56        }
57    }
58
59    /// Start a new phase timer
60    pub fn start_phase(&mut self) {
61        self.phase_start = Instant::now();
62    }
63
64    /// Get elapsed time since timer start
65    pub fn elapsed(&self) -> Duration {
66        self.start_time.elapsed()
67    }
68
69    /// Get elapsed time since phase start
70    pub fn phase_elapsed(&self) -> Duration {
71        self.phase_start.elapsed()
72    }
73
74    /// Format a duration as "Xm YYs"
75    pub fn format_duration(duration: Duration) -> String {
76        let total_secs = duration.as_secs();
77        let mins = total_secs / 60;
78        let secs = total_secs % 60;
79        format!("{mins}m {secs:02}s")
80    }
81
82    /// Get formatted elapsed time since start
83    pub fn elapsed_formatted(&self) -> String {
84        Self::format_duration(self.elapsed())
85    }
86
87    /// Get formatted elapsed time since phase start
88    pub fn phase_elapsed_formatted(&self) -> String {
89        Self::format_duration(self.phase_elapsed())
90    }
91}
92
93impl Default for Timer {
94    fn default() -> Self {
95        Self::new()
96    }
97}
98
99#[cfg(test)]
100mod timer_tests {
101    use super::*;
102    use std::thread;
103
104    #[test]
105    fn test_format_duration_zero() {
106        let d = Duration::from_secs(0);
107        assert_eq!(Timer::format_duration(d), "0m 00s");
108    }
109
110    #[test]
111    fn test_format_duration_seconds() {
112        let d = Duration::from_secs(30);
113        assert_eq!(Timer::format_duration(d), "0m 30s");
114    }
115
116    #[test]
117    fn test_format_duration_minutes() {
118        let d = Duration::from_secs(65);
119        assert_eq!(Timer::format_duration(d), "1m 05s");
120    }
121
122    #[test]
123    fn test_format_duration_large() {
124        let d = Duration::from_secs(3661);
125        assert_eq!(Timer::format_duration(d), "61m 01s");
126    }
127
128    #[test]
129    fn test_timer_elapsed() {
130        let timer = Timer::new();
131        thread::sleep(Duration::from_millis(10));
132        assert!(timer.elapsed() >= Duration::from_millis(10));
133    }
134
135    #[test]
136    fn test_timer_phase() {
137        let mut timer = Timer::new();
138        thread::sleep(Duration::from_millis(10));
139        timer.start_phase();
140        thread::sleep(Duration::from_millis(10));
141        // Phase elapsed should be less than total elapsed
142        assert!(timer.phase_elapsed() < timer.elapsed());
143    }
144}
145
146#[cfg(test)]
147mod tests;