agentkit-reporting 0.2.0

Reporting observers and event consumers for agentkit loops.
Documentation

agentkit-reporting

Observers for turning loop events into logs, summaries, and transcript views.

This crate provides [LoopObserver] implementations for [agentkit-loop]. Instead of baking reporting into the driver, you attach one or more reporters to the loop and they react to every AgentEvent that flows through it.

Included reporters

Reporter Purpose
StdoutReporter Human-readable bracketed log lines ([turn] started ...)
JsonlReporter Machine-readable newline-delimited JSON envelopes
UsageReporter Aggregated token counts and cost totals
TranscriptReporter Growing snapshot of conversation items
CompositeReporter Fan-out wrapper that forwards events to multiple reporters

Quick start

Compose several reporters with CompositeReporter and hand it to the loop:

use agentkit_reporting::{
    CompositeReporter, JsonlReporter, StdoutReporter,
    TranscriptReporter, UsageReporter,
};

// Build a composite reporter that fans out to all four reporters.
let reporter = CompositeReporter::new()
    .with_observer(StdoutReporter::new(std::io::stderr()).with_usage(false))
    .with_observer(JsonlReporter::new(Vec::new()).with_flush_each_event(false))
    .with_observer(UsageReporter::new())
    .with_observer(TranscriptReporter::new());

// Pass `reporter` as the observer when constructing the agent loop.

Accessing outputs after the loop

Reporters that accumulate state (UsageReporter, TranscriptReporter, JsonlReporter) expose accessors for reading back data once the loop finishes:

use agentkit_reporting::{UsageReporter, TranscriptReporter, JsonlReporter};

// Usage totals
let reporter = UsageReporter::new();
// ...run the loop...
let summary = reporter.summary();
println!(
    "tokens: {} in / {} out, turns: {}",
    summary.totals.input_tokens,
    summary.totals.output_tokens,
    summary.turn_results_seen,
);

// Transcript items
let reporter = TranscriptReporter::new();
// ...run the loop...
for item in &reporter.transcript().items {
    println!("{:?}: {} parts", item.kind, item.parts.len());
}

// JSONL buffer
let mut reporter = JsonlReporter::new(Vec::new());
// ...run the loop...
let jsonl = String::from_utf8(reporter.writer().clone()).unwrap();
let errors = reporter.take_errors();
assert!(errors.is_empty(), "reporting errors: {:?}", errors);

Writing to a file

JsonlReporter and StdoutReporter accept any std::io::Write implementation, so you can point them at files, network sockets, or in-memory buffers:

use agentkit_reporting::JsonlReporter;
use std::io::BufWriter;
use std::fs::File;

let file = File::create("events.jsonl").expect("open file");
let reporter = JsonlReporter::new(BufWriter::new(file));

Error handling

JsonlReporter and StdoutReporter never panic on write failures. Errors are collected internally and can be drained after the loop with take_errors(). This keeps the LoopObserver::handle_event signature infallible while still giving you full visibility into any I/O issues.