use std::sync::Arc; use async_trait::async_trait; use time::OffsetDateTime; use crate::{AgentId, InvocationSource, InvocationStatus, OperationId, WorkspaceId}; #[derive(Clone, Debug, PartialEq, Eq)] pub struct MeteringEvent { pub workspace_id: WorkspaceId, pub agent_id: Option, pub operation_id: OperationId, pub source: InvocationSource, pub status: InvocationStatus, pub duration_ms: u64, pub created_at: OffsetDateTime, } #[async_trait] pub trait MeteringSink: Send + Sync { async fn record(&self, event: MeteringEvent); } pub type SharedMeteringSink = Arc; #[derive(Clone, Copy, Debug, Default)] pub struct NoopMeteringSink; #[async_trait] impl MeteringSink for NoopMeteringSink { async fn record(&self, _event: MeteringEvent) {} } #[cfg(test)] mod tests { use time::OffsetDateTime; use super::{MeteringEvent, MeteringSink, NoopMeteringSink}; use crate::{InvocationSource, InvocationStatus, OperationId, WorkspaceId}; #[tokio::test] async fn noop_metering_sink_accepts_event() { NoopMeteringSink .record(MeteringEvent { workspace_id: WorkspaceId::new("ws_01"), agent_id: None, operation_id: OperationId::new("op_01"), source: InvocationSource::AgentToolCall, status: InvocationStatus::Ok, duration_ms: 42, created_at: OffsetDateTime::now_utc(), }) .await; } }