diff --git a/lib/crates/fabro-workflows/src/cli/logs.rs b/lib/crates/fabro-workflows/src/cli/logs.rs index 640ed5cc3..d0c67dbd8 100644 --- a/lib/crates/fabro-workflows/src/cli/logs.rs +++ b/lib/crates/fabro-workflows/src/cli/logs.rs @@ -214,7 +214,10 @@ pub fn format_event_pretty(line: &str, styles: &fabro_util::terminal::Styles) -> "WorkflowRunCompleted" => { let duration = format_duration_ms(envelope.get("duration_ms")); - let status_str = str_field(&envelope, "status").unwrap_or("success"); + let status_str = match str_field(&envelope, "status") { + Some(s) if !s.is_empty() => s, + _ => "success", + }; let status_upper = status_str.to_uppercase(); let status_style = match status_str { "success" | "partial_success" => &styles.bold_green, diff --git a/lib/crates/fabro-workflows/src/engine.rs b/lib/crates/fabro-workflows/src/engine.rs index 1c1b40dcd..d4d6415ed 100644 --- a/lib/crates/fabro-workflows/src/engine.rs +++ b/lib/crates/fabro-workflows/src/engine.rs @@ -2144,28 +2144,10 @@ impl WorkflowRunEngine { .cloned() .unwrap_or_else(Outcome::success); - let run_usage: Option = { - let usages: Vec = node_outcomes - .values() - .filter_map(|o| { - let u = o.usage.as_ref()?; - Some(fabro_llm::types::Usage { - input_tokens: u.input_tokens, - output_tokens: u.output_tokens, - total_tokens: u.input_tokens + u.output_tokens, - cache_read_tokens: u.cache_read_tokens, - cache_write_tokens: u.cache_write_tokens, - reasoning_tokens: u.reasoning_tokens, - raw: None, - }) - }) - .collect(); - if usages.is_empty() { - None - } else { - Some(usages.into_iter().reduce(|a, b| a + b).unwrap()) - } - }; + let run_usage: Option = node_outcomes + .values() + .filter_map(|o| o.usage.as_ref().map(fabro_llm::types::Usage::from)) + .reduce(|a, b| a + b); self.services .emitter diff --git a/lib/crates/fabro-workflows/src/outcome.rs b/lib/crates/fabro-workflows/src/outcome.rs index 3756c2721..7677fe888 100644 --- a/lib/crates/fabro-workflows/src/outcome.rs +++ b/lib/crates/fabro-workflows/src/outcome.rs @@ -61,6 +61,20 @@ pub struct StageUsage { pub cost: Option, } +impl From<&StageUsage> for fabro_llm::types::Usage { + fn from(u: &StageUsage) -> Self { + Self { + input_tokens: u.input_tokens, + output_tokens: u.output_tokens, + total_tokens: u.input_tokens + u.output_tokens, + cache_read_tokens: u.cache_read_tokens, + cache_write_tokens: u.cache_write_tokens, + reasoning_tokens: u.reasoning_tokens, + raw: None, + } + } +} + /// Structured failure information carried through the pipeline. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct FailureDetail {