hive-agent: emit harness-only per-turn otel metrics
This commit is contained in:
parent
ed95e692e1
commit
eb981e7f5d
4 changed files with 196 additions and 18 deletions
|
|
@ -17,6 +17,7 @@ mod identity;
|
|||
mod login;
|
||||
mod login_session;
|
||||
mod mcp_config;
|
||||
mod otel_turn_metrics;
|
||||
mod paths;
|
||||
mod plugins;
|
||||
mod prompt;
|
||||
|
|
@ -1006,30 +1007,42 @@ async fn handle_turn<S: Surface>(
|
|||
let tool_calls = bus.take_tool_calls();
|
||||
let todo_wake_checked =
|
||||
(from == "todo").then(|| tool_calls.contains_key("mcp__hyperhive__get_loose_ends"));
|
||||
// Read-and-clear once per turn unconditionally (same rationale as
|
||||
// `take_tool_calls` above — the harness gets exactly one chance to
|
||||
// observe this flag) rather than only when the sqlite sink happens to be
|
||||
// configured: the OTEL turn-metrics exporter's session-boundary counter
|
||||
// needs it too, independent of `stats`.
|
||||
let fresh_session = bus.take_fresh_session();
|
||||
if let Some(stats) = stats {
|
||||
// Fresh session this turn → mint a `sessions` row and set its id on
|
||||
// the bus so this turn (and subsequent ones until the next fresh
|
||||
// start) stamp `turn_stats.session_id`. Takes the one-shot flag
|
||||
// `run_claude` set when it suppressed `--continue`.
|
||||
if bus.take_fresh_session() {
|
||||
// start) stamp `turn_stats.session_id`.
|
||||
if fresh_session {
|
||||
let sid = stats.start_session(started_at, &model_at_start);
|
||||
bus.set_session_id(sid);
|
||||
}
|
||||
let ended_at = chrono::Utc::now().timestamp();
|
||||
let duration_ms = i64::try_from(started_instant.elapsed().as_millis()).unwrap_or(i64::MAX);
|
||||
let (open_threads, open_reminders) = S::post_turn_counts(socket).await;
|
||||
let row = serve_common::build_row(serve_common::TurnRowArgs {
|
||||
started_at,
|
||||
ended_at,
|
||||
duration_ms,
|
||||
model: model_at_start,
|
||||
wake_from: from.clone(),
|
||||
outcome: &outcome,
|
||||
bus,
|
||||
tool_calls,
|
||||
open_threads_count: open_threads,
|
||||
open_reminders_count: open_reminders,
|
||||
});
|
||||
}
|
||||
let ended_at = chrono::Utc::now().timestamp();
|
||||
let duration_ms = i64::try_from(started_instant.elapsed().as_millis()).unwrap_or(i64::MAX);
|
||||
let (open_threads, open_reminders) = S::post_turn_counts(socket).await;
|
||||
let row = serve_common::build_row(serve_common::TurnRowArgs {
|
||||
started_at,
|
||||
ended_at,
|
||||
duration_ms,
|
||||
model: model_at_start,
|
||||
wake_from: from.clone(),
|
||||
outcome: &outcome,
|
||||
bus,
|
||||
tool_calls,
|
||||
open_threads_count: open_threads,
|
||||
open_reminders_count: open_reminders,
|
||||
});
|
||||
// Harness-only OTEL metrics (duration/wake_from/result_kind/loose-ends/
|
||||
// session boundaries) — independent of the sqlite sink below, and a
|
||||
// cheap no-op when OTEL isn't configured. See `otel_turn_metrics`'s
|
||||
// module doc for why token/cost/tool-count are deliberately not here.
|
||||
otel_turn_metrics::record(&row, fresh_session);
|
||||
if let Some(stats) = stats {
|
||||
stats.record(&row);
|
||||
}
|
||||
let pending = S::inbox_unread(socket).await;
|
||||
|
|
|
|||
Loading…
Reference in a new issue