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