Skip to main content

bitrouter_core/
observe.rs

1//! Handler-level observation callback for request lifecycle events.
2//!
3//! [`ObserveCallback`] fires from the API handler layer with full request
4//! context (route, provider, model, account, latency, usage/error).
5//! This is complementary to [`GenerationHook`](crate::hooks::GenerationHook)
6//! which fires at the model layer with no request context.
7
8use std::future::Future;
9use std::pin::Pin;
10
11use crate::errors::BitrouterError;
12use crate::models::language::usage::LanguageModelUsage;
13
14/// Context about the request available to observation callbacks.
15#[derive(Debug, Clone)]
16pub struct RequestContext {
17    /// The incoming model name (route key).
18    pub route: String,
19    /// The resolved provider name.
20    pub provider: String,
21    /// The resolved model ID sent to the provider.
22    pub model: String,
23    /// The account that made the request, if authentication is enabled.
24    pub account_id: Option<String>,
25    /// End-to-end request latency in milliseconds.
26    pub latency_ms: u64,
27}
28
29/// Event emitted when a request completes successfully.
30#[derive(Debug, Clone)]
31pub struct RequestSuccessEvent {
32    /// Request context.
33    pub ctx: RequestContext,
34    /// Token usage reported by the model.
35    pub usage: LanguageModelUsage,
36}
37
38/// Event emitted when a request fails.
39#[derive(Debug, Clone)]
40pub struct RequestFailureEvent {
41    /// Request context.
42    pub ctx: RequestContext,
43    /// The error that caused the failure.
44    pub error: BitrouterError,
45}
46
47/// Callback trait for observing completed API requests.
48///
49/// Implementations receive rich, typed events with full request context
50/// and can perform side effects such as spend logging, metrics aggregation,
51/// or alerting. Errors in callbacks are expected to be handled internally
52/// (e.g. logged and swallowed) — they must never break request serving.
53///
54/// Methods return boxed futures for dyn-compatibility, allowing multiple
55/// observers to be composed via [`CompositeObserver`](see bitrouter-observe).
56pub trait ObserveCallback: Send + Sync {
57    /// Called after a request completes successfully.
58    fn on_request_success(
59        &self,
60        event: RequestSuccessEvent,
61    ) -> Pin<Box<dyn Future<Output = ()> + Send + '_>>;
62
63    /// Called after a request fails.
64    fn on_request_failure(
65        &self,
66        event: RequestFailureEvent,
67    ) -> Pin<Box<dyn Future<Output = ()> + Send + '_>>;
68}