ralph_workflow/pipeline/
mod.rs1#![deny(unsafe_code)]
16
17mod clipboard;
18mod fallback;
19mod model_flag;
20mod prompt;
21mod runner;
22mod types;
23
24pub use fallback::OutputValidator;
25pub use prompt::{run_with_prompt, PipelineRuntime, PromptCommand};
26pub use runner::{run_with_fallback, run_with_fallback_and_validator, FallbackConfig};
27pub use types::{AgentPhaseGuard, Stats};
28
29use std::time::{Duration, Instant};
32
33#[derive(Clone)]
35pub struct Timer {
36 start_time: Instant,
37 phase_start: Instant,
38}
39
40impl Timer {
41 pub fn new() -> Self {
43 let now = Instant::now();
44 Self {
45 start_time: now,
46 phase_start: now,
47 }
48 }
49
50 pub fn start_phase(&mut self) {
52 self.phase_start = Instant::now();
53 }
54
55 pub fn elapsed(&self) -> Duration {
57 self.start_time.elapsed()
58 }
59
60 pub fn phase_elapsed(&self) -> Duration {
62 self.phase_start.elapsed()
63 }
64
65 pub fn format_duration(duration: Duration) -> String {
67 let total_secs = duration.as_secs();
68 let mins = total_secs / 60;
69 let secs = total_secs % 60;
70 format!("{mins}m {secs:02}s")
71 }
72
73 pub fn elapsed_formatted(&self) -> String {
75 Self::format_duration(self.elapsed())
76 }
77
78 pub fn phase_elapsed_formatted(&self) -> String {
80 Self::format_duration(self.phase_elapsed())
81 }
82}
83
84impl Default for Timer {
85 fn default() -> Self {
86 Self::new()
87 }
88}
89
90#[cfg(test)]
91mod timer_tests {
92 use super::*;
93 use std::thread;
94
95 #[test]
96 fn test_format_duration_zero() {
97 let d = Duration::from_secs(0);
98 assert_eq!(Timer::format_duration(d), "0m 00s");
99 }
100
101 #[test]
102 fn test_format_duration_seconds() {
103 let d = Duration::from_secs(30);
104 assert_eq!(Timer::format_duration(d), "0m 30s");
105 }
106
107 #[test]
108 fn test_format_duration_minutes() {
109 let d = Duration::from_secs(65);
110 assert_eq!(Timer::format_duration(d), "1m 05s");
111 }
112
113 #[test]
114 fn test_format_duration_large() {
115 let d = Duration::from_secs(3661);
116 assert_eq!(Timer::format_duration(d), "61m 01s");
117 }
118
119 #[test]
120 fn test_timer_elapsed() {
121 let timer = Timer::new();
122 thread::sleep(Duration::from_millis(10));
123 assert!(timer.elapsed() >= Duration::from_millis(10));
124 }
125
126 #[test]
127 fn test_timer_phase() {
128 let mut timer = Timer::new();
129 thread::sleep(Duration::from_millis(10));
130 timer.start_phase();
131 thread::sleep(Duration::from_millis(10));
132 assert!(timer.phase_elapsed() < timer.elapsed());
134 }
135}
136
137#[cfg(test)]
138mod tests;