Skip to main content

session_stats

Function session_stats 

Source
pub fn session_stats(messages: &[AgentMessage]) -> SessionStats
Expand description

Fold a conversation into a SessionStats.

Contract:

  • turns/token sums iterate every AgentMessage::Assistant { usage: Some(u), .. }; a missing cache_read_tokens/cache_write_tokens counts as 0.
  • (+) cache_turns counts those same messages when EITHER cache field is Some — the rate’s denominator, so an unreported cache is omitted, never 0%.
  • tools tallies every ContentBlock::ToolCall { name, .. } across Assistant messages (independently of whether a matching ToolResult exists), then sorts by calls desc, name asc.
  • (+) a first pass maps ContentBlock::ToolCall { id, name, .. } → (name, tally index); a second walk over AgentMessage::ToolResult { tool_call_id, is_error, output, .. } bumps errors (when is_error) and adds output.len() to result_bytes on THAT call’s row. The result’s own name is never used for attribution — the id is the pairing (message.rs:59 tool_call_id: String,).
  • (+) a ToolCall with NO matching ToolResult is calls += 1, errors += 0: a mid-run snapshot can legitimately catch a call in flight, and a lost result is not a failure. Counting it as an error would invent one.
  • (+) a ToolResult whose tool_call_id matches no ToolCall bumps nothing: there is no name to attribute it to (this is what a compacted prefix looks like). The old doc’s “does not depend on the pairing invariant” claim is thereby AMENDED, not weakened — it still holds for calls, and no longer for errors/result_bytes.
  • (+) tool_errors = Σ errors over the tallies.
  • (+) cost is left None: pricing needs the provider’s base_url/model, which no AgentMessage carries. The caller that knows it (the actor’s Request::Usage arm) sets cost with pricing::cost_of(..) on the SAME slice, so turns == priced + unpriced there.
  • last_input_tokens is the input_tokens of the last Assistant with Some(usage).
  • (+) is_error includes the loop’s synthesized aborts (loop_.rs:650/loop_.rs:798), so errors means “the call did not succeed”, not “the tool failed” — say it in the doc, and in D028.
  • Empty input ⇒ SessionStats::default().