ralph_workflow/pipeline/
mod.rs1#![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
31#[cfg(any(test, feature = "test-utils"))]
32pub mod test_trait;
33
34pub use fallback::OutputValidator;
35pub use prompt::{run_with_prompt, PipelineRuntime, PromptCommand};
36pub use runner::{
37 run_with_fallback_and_validator, run_xsd_retry_with_session, FallbackConfig, XsdRetryConfig,
38};
39pub use types::{AgentPhaseGuard, Stats};
40
41use std::time::{Duration, Instant};
44
45#[derive(Clone)]
47pub struct Timer {
48 start_time: Instant,
49 phase_start: Instant,
50}
51
52impl Timer {
53 pub fn new() -> Self {
55 let now = Instant::now();
56 Self {
57 start_time: now,
58 phase_start: now,
59 }
60 }
61
62 pub fn start_phase(&mut self) {
64 self.phase_start = Instant::now();
65 }
66
67 pub fn elapsed(&self) -> Duration {
69 self.start_time.elapsed()
70 }
71
72 pub fn phase_elapsed(&self) -> Duration {
74 self.phase_start.elapsed()
75 }
76
77 pub fn format_duration(duration: Duration) -> String {
79 let total_secs = duration.as_secs();
80 let mins = total_secs / 60;
81 let secs = total_secs % 60;
82 format!("{mins}m {secs:02}s")
83 }
84
85 pub fn elapsed_formatted(&self) -> String {
87 Self::format_duration(self.elapsed())
88 }
89
90 pub fn phase_elapsed_formatted(&self) -> String {
92 Self::format_duration(self.phase_elapsed())
93 }
94}
95
96impl Default for Timer {
97 fn default() -> Self {
98 Self::new()
99 }
100}
101
102#[cfg(test)]
103mod timer_tests {
104 use super::*;
105 use std::thread;
106
107 #[test]
108 fn test_format_duration_zero() {
109 let d = Duration::from_secs(0);
110 assert_eq!(Timer::format_duration(d), "0m 00s");
111 }
112
113 #[test]
114 fn test_format_duration_seconds() {
115 let d = Duration::from_secs(30);
116 assert_eq!(Timer::format_duration(d), "0m 30s");
117 }
118
119 #[test]
120 fn test_format_duration_minutes() {
121 let d = Duration::from_secs(65);
122 assert_eq!(Timer::format_duration(d), "1m 05s");
123 }
124
125 #[test]
126 fn test_format_duration_large() {
127 let d = Duration::from_secs(3661);
128 assert_eq!(Timer::format_duration(d), "61m 01s");
129 }
130
131 #[test]
132 fn test_timer_elapsed() {
133 let timer = Timer::new();
134 thread::sleep(Duration::from_millis(10));
135 assert!(timer.elapsed() >= Duration::from_millis(10));
136 }
137
138 #[test]
139 fn test_timer_phase() {
140 let mut timer = Timer::new();
141 thread::sleep(Duration::from_millis(10));
142 timer.start_phase();
143 thread::sleep(Duration::from_millis(10));
144 assert!(timer.phase_elapsed() < timer.elapsed());
146 }
147}
148
149#[cfg(test)]
150mod tests;