From 4f569544221197c5007febc2a76efb8c2f42e915 Mon Sep 17 00:00:00 2001 From: damocles Date: Sun, 17 May 2026 02:40:34 +0200 Subject: [PATCH] extract TokenUsage::from_stream_event helper to keep run_claude under clippy line limit --- hive-ag3nt/src/events.rs | 18 ++++++++++++++++++ hive-ag3nt/src/turn.rs | 26 ++------------------------ 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/hive-ag3nt/src/events.rs b/hive-ag3nt/src/events.rs index 09a724d..0588c82 100644 --- a/hive-ag3nt/src/events.rs +++ b/hive-ag3nt/src/events.rs @@ -171,6 +171,24 @@ impl TokenUsage { pub fn context_tokens(&self) -> u64 { self.input_tokens + self.cache_read_input_tokens + self.cache_creation_input_tokens } + + /// Parse usage from a stream-json event. Returns `Some` only for the + /// terminal `result` event (which is the only one that carries `usage`); + /// every other event maps to `None`. Missing numeric fields default to 0 + /// so partial server payloads don't drop the whole snapshot. + pub fn from_stream_event(v: &serde_json::Value) -> Option { + if v.get("type").and_then(|t| t.as_str()) != Some("result") { + return None; + } + let u = v.get("usage")?; + let field = |k: &str| u.get(k).and_then(serde_json::Value::as_u64).unwrap_or(0); + Some(Self { + input_tokens: field("input_tokens"), + output_tokens: field("output_tokens"), + cache_read_input_tokens: field("cache_read_input_tokens"), + cache_creation_input_tokens: field("cache_creation_input_tokens"), + }) + } } /// Authoritative turn-loop state. The harness owns it; the web UI diff --git a/hive-ag3nt/src/turn.rs b/hive-ag3nt/src/turn.rs index c660b08..1992317 100644 --- a/hive-ag3nt/src/turn.rs +++ b/hive-ag3nt/src/turn.rs @@ -277,30 +277,8 @@ async fn run_claude(prompt: &str, files: &TurnFiles, bus: &Bus) -> Result } match serde_json::from_str::(&line) { Ok(v) => { - // Extract token usage from the final `result` event and - // store it in the bus for the web UI to surface. - if v.get("type").and_then(|t| t.as_str()) == Some("result") { - if let Some(u) = v.get("usage") { - let usage = crate::events::TokenUsage { - input_tokens: u - .get("input_tokens") - .and_then(|v| v.as_u64()) - .unwrap_or(0), - output_tokens: u - .get("output_tokens") - .and_then(|v| v.as_u64()) - .unwrap_or(0), - cache_read_input_tokens: u - .get("cache_read_input_tokens") - .and_then(|v| v.as_u64()) - .unwrap_or(0), - cache_creation_input_tokens: u - .get("cache_creation_input_tokens") - .and_then(|v| v.as_u64()) - .unwrap_or(0), - }; - bus_out.record_usage(usage); - } + if let Some(usage) = crate::events::TokenUsage::from_stream_event(&v) { + bus_out.record_usage(usage); } bus_out.emit(LiveEvent::Stream(v)); }