agentkit_reporting/buffered.rs
1//! Batch-buffered reporter adapter.
2//!
3//! [`BufferedReporter`] enqueues events and forwards them to an inner
4//! [`LoopObserver`] in batches — either when the buffer reaches a configured
5//! capacity or on an explicit [`flush`](BufferedReporter::flush) call.
6//! Remaining events are flushed automatically on drop.
7
8use agentkit_loop::{AgentEvent, LoopObserver};
9
10/// Reporter adapter that enqueues events for batch flushing.
11///
12/// Wraps any [`LoopObserver`] and delivers events in batches rather than
13/// one-at-a-time. This is useful when the inner reporter benefits from
14/// amortised work (e.g. a network sink that batches writes).
15///
16/// # Example
17///
18/// ```rust
19/// use agentkit_reporting::{BufferedReporter, UsageReporter};
20///
21/// // Buffer up to 64 events before forwarding to the inner reporter.
22/// let reporter = BufferedReporter::new(UsageReporter::new(), 64);
23/// ```
24pub struct BufferedReporter<T: LoopObserver> {
25 inner: T,
26 buffer: Vec<AgentEvent>,
27 capacity: usize,
28}
29
30impl<T: LoopObserver> BufferedReporter<T> {
31 /// Creates a new `BufferedReporter` that buffers up to `capacity` events
32 /// before flushing them to `inner`.
33 ///
34 /// A capacity of `0` disables automatic flushing — events are only
35 /// delivered when [`flush`](BufferedReporter::flush) is called explicitly
36 /// (or on drop).
37 pub fn new(inner: T, capacity: usize) -> Self {
38 Self {
39 inner,
40 buffer: Vec::with_capacity(capacity),
41 capacity,
42 }
43 }
44
45 /// Delivers all buffered events to the inner observer and clears the
46 /// buffer.
47 pub fn flush(&mut self) {
48 for event in self.buffer.drain(..) {
49 self.inner.handle_event(event);
50 }
51 }
52
53 /// Returns the number of events currently buffered.
54 pub fn pending(&self) -> usize {
55 self.buffer.len()
56 }
57
58 /// Returns a reference to the inner observer.
59 pub fn inner(&self) -> &T {
60 &self.inner
61 }
62
63 /// Returns a mutable reference to the inner observer.
64 pub fn inner_mut(&mut self) -> &mut T {
65 &mut self.inner
66 }
67}
68
69impl<T: LoopObserver> LoopObserver for BufferedReporter<T> {
70 fn handle_event(&mut self, event: AgentEvent) {
71 self.buffer.push(event);
72 if self.capacity > 0 && self.buffer.len() >= self.capacity {
73 self.flush();
74 }
75 }
76}
77
78impl<T: LoopObserver> Drop for BufferedReporter<T> {
79 fn drop(&mut self) {
80 self.flush();
81 }
82}