feat: add verbose logging and complete observability (#251)
This commit is contained in:
parent
6d56a040ce
commit
50f508766f
8 changed files with 316 additions and 5 deletions
96
src/observability/verbose.rs
Normal file
96
src/observability/verbose.rs
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
use super::traits::{Observer, ObserverEvent, ObserverMetric};
|
||||
|
||||
/// Human-readable progress observer for interactive CLI sessions.
|
||||
///
|
||||
/// This observer prints compact `>` / `<` progress lines without exposing
|
||||
/// prompt contents. It is intended to be opt-in (e.g. `--verbose`).
|
||||
pub struct VerboseObserver;
|
||||
|
||||
impl VerboseObserver {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl Observer for VerboseObserver {
|
||||
fn record_event(&self, event: &ObserverEvent) {
|
||||
match event {
|
||||
ObserverEvent::LlmRequest {
|
||||
provider,
|
||||
model,
|
||||
messages_count,
|
||||
} => {
|
||||
eprintln!("> Thinking");
|
||||
eprintln!(
|
||||
"> Send (provider={}, model={}, messages={})",
|
||||
provider, model, messages_count
|
||||
);
|
||||
}
|
||||
ObserverEvent::LlmResponse {
|
||||
duration, success, ..
|
||||
} => {
|
||||
let ms = u64::try_from(duration.as_millis()).unwrap_or(u64::MAX);
|
||||
eprintln!("< Receive (success={success}, duration_ms={ms})");
|
||||
}
|
||||
ObserverEvent::ToolCallStart { tool } => {
|
||||
eprintln!("> Tool {tool}");
|
||||
}
|
||||
ObserverEvent::ToolCall {
|
||||
tool,
|
||||
duration,
|
||||
success,
|
||||
} => {
|
||||
let ms = u64::try_from(duration.as_millis()).unwrap_or(u64::MAX);
|
||||
eprintln!("< Tool {tool} (success={success}, duration_ms={ms})");
|
||||
}
|
||||
ObserverEvent::TurnComplete => {
|
||||
eprintln!("< Complete");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn record_metric(&self, _metric: &ObserverMetric) {}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
"verbose"
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::time::Duration;
|
||||
|
||||
#[test]
|
||||
fn verbose_name() {
|
||||
assert_eq!(VerboseObserver::new().name(), "verbose");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verbose_events_do_not_panic() {
|
||||
let obs = VerboseObserver::new();
|
||||
obs.record_event(&ObserverEvent::LlmRequest {
|
||||
provider: "openrouter".into(),
|
||||
model: "claude".into(),
|
||||
messages_count: 3,
|
||||
});
|
||||
obs.record_event(&ObserverEvent::LlmResponse {
|
||||
provider: "openrouter".into(),
|
||||
model: "claude".into(),
|
||||
duration: Duration::from_millis(12),
|
||||
success: true,
|
||||
error_message: None,
|
||||
});
|
||||
obs.record_event(&ObserverEvent::ToolCallStart {
|
||||
tool: "shell".into(),
|
||||
});
|
||||
obs.record_event(&ObserverEvent::ToolCall {
|
||||
tool: "shell".into(),
|
||||
duration: Duration::from_millis(2),
|
||||
success: true,
|
||||
});
|
||||
obs.record_event(&ObserverEvent::TurnComplete);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue