ai_lib_rust/telemetry/mod.rs
1//! Telemetry and feedback (optional, application-controlled).
2//!
3//! The runtime MUST NOT force telemetry collection. Instead it provides:
4//! - a stable `client_request_id` for linkage
5//! - typed feedback events
6//! - an injectable `FeedbackSink` hook (default: no-op)
7
8use crate::Result;
9use async_trait::async_trait;
10use std::sync::Arc;
11
12/// Minimal user feedback for multi-candidate selection.
13#[derive(Debug, Clone)]
14pub struct ChoiceSelectionFeedback {
15 /// Request identifier emitted by the runtime (`client_request_id`).
16 pub request_id: String,
17 /// The chosen candidate index (0-based).
18 pub chosen_index: u32,
19 /// Optional rejected indices (0-based).
20 pub rejected_indices: Option<Vec<u32>>,
21 /// Time from render to selection (ms), if the UI can measure it.
22 pub latency_to_select_ms: Option<u64>,
23 /// Optional UI context (component name / experiment id / etc.)
24 pub ui_context: Option<serde_json::Value>,
25 /// Optional content hashes to link choice to rendered candidates without uploading text.
26 pub candidate_hashes: Option<Vec<String>>,
27}
28
29/// Typed feedback events (extensible).
30#[derive(Debug, Clone)]
31pub enum FeedbackEvent {
32 ChoiceSelection(ChoiceSelectionFeedback),
33}
34
35/// Feedback sink hook. Applications decide whether and where to store/report feedback.
36#[async_trait]
37pub trait FeedbackSink: Send + Sync {
38 async fn report(&self, event: FeedbackEvent) -> Result<()>;
39}
40
41/// Default sink: do nothing.
42pub struct NoopFeedbackSink;
43
44#[async_trait]
45impl FeedbackSink for NoopFeedbackSink {
46 async fn report(&self, _event: FeedbackEvent) -> Result<()> {
47 Ok(())
48 }
49}
50
51pub fn noop_sink() -> Arc<dyn FeedbackSink> {
52 Arc::new(NoopFeedbackSink)
53}