#[cfg(feature = "telemetry")]
use rig_tap::{EventKind, emit_kind};
#[cfg(feature = "telemetry")]
tokio::task_local! {
pub static CURRENT_SESSION: String;
}
pub async fn with_session<F, Fut>(session_id: String, f: F) -> Fut::Output
where
F: FnOnce() -> Fut,
Fut: std::future::Future,
{
#[cfg(feature = "telemetry")]
{
CURRENT_SESSION.scope(session_id, f()).await
}
#[cfg(not(feature = "telemetry"))]
{
let _ = session_id;
f().await
}
}
pub fn current_session() -> String {
#[cfg(feature = "telemetry")]
{
CURRENT_SESSION
.try_with(|s| s.clone())
.unwrap_or_else(|_| "unknown".to_string())
}
#[cfg(not(feature = "telemetry"))]
{
"unknown".to_string()
}
}
#[cfg_attr(not(feature = "telemetry"), allow(unused_variables))]
pub fn record_prompt(
model: &str,
tokens_in: u64,
tokens_out: u64,
cached_in: u64,
reasoning: u64,
duration_ms: u64,
) {
#[cfg(feature = "telemetry")]
emit_kind(
current_session(),
EventKind::PromptCompleted {
model: model.to_string(),
tokens_in: Some(tokens_in),
tokens_out: Some(tokens_out),
cached_tokens_in: Some(cached_in),
reasoning_tokens: Some(reasoning),
cost_usd: None,
finish_reason: None,
response_id: None,
previous_response_id: None,
time_to_first_token_ms: None,
duration_ms: Some(duration_ms),
},
);
}
pub async fn record_tool_call<F, Fut, T, E>(
#[allow(unused_variables)] tool_name: &'static str,
#[allow(unused_variables)] args: &str,
f: F,
) -> Result<T, E>
where
F: FnOnce() -> Fut,
Fut: std::future::Future<Output = Result<T, E>>,
T: serde::Serialize,
E: std::fmt::Display,
{
#[cfg(feature = "telemetry")]
let start = std::time::Instant::now();
#[cfg(feature = "telemetry")]
let call_id = format!("{tool_name}-{}", uuid::Uuid::new_v4());
#[cfg(feature = "telemetry")]
let session = current_session();
#[cfg(feature = "telemetry")]
emit_kind(
&session,
EventKind::ToolInvoked {
tool_name: tool_name.to_string(),
provider_call_id: None,
call_id: call_id.clone(),
args_json: args.to_string(),
truncated: false,
},
);
let res = f().await;
#[cfg(feature = "telemetry")]
match &res {
Ok(val) => {
let result_str = serde_json::to_string(val).unwrap_or_else(|_| "{}".to_string());
emit_kind(
&session,
EventKind::ToolCompleted {
tool_name: tool_name.to_string(),
provider_call_id: None,
call_id,
result: result_str,
truncated: false,
duration_ms: Some(start.elapsed().as_millis() as u64),
},
);
}
Err(err) => {
emit_kind(
&session,
EventKind::ToolFailed {
tool_name: tool_name.to_string(),
call_id,
error_class: rig_tap::ErrorClass::Unknown,
message: err.to_string(),
},
);
}
}
res
}