From 93f19bf780c15c7c5341f09645be33804f92417d Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Thu, 5 Feb 2026 23:11:45 -0800 Subject: [PATCH] feat: log session config on create --- server/packages/sandbox-agent/src/router.rs | 14 +++ .../packages/sandbox-agent/src/telemetry.rs | 96 +++++++++++++++++-- 2 files changed, 102 insertions(+), 8 deletions(-) diff --git a/server/packages/sandbox-agent/src/router.rs b/server/packages/sandbox-agent/src/router.rs index 92460d5..06434a9 100644 --- a/server/packages/sandbox-agent/src/router.rs +++ b/server/packages/sandbox-agent/src/router.rs @@ -40,6 +40,7 @@ use utoipa::{Modify, OpenApi, ToSchema}; use crate::agent_server_logs::AgentServerLogs; use crate::opencode_compat::{build_opencode_router, OpenCodeAppState}; +use crate::telemetry; use crate::ui; use sandbox_agent_agent_management::agents::{ AgentError as ManagerError, AgentId, AgentManager, InstallOptions, SpawnOptions, StreamingSpawn, @@ -1622,6 +1623,9 @@ impl SessionManager { session.native_session_id = Some(format!("mock-{session_id}")); } + let telemetry_agent = request.agent.clone(); + let telemetry_model = request.model.clone(); + let telemetry_variant = request.variant.clone(); let metadata = json!({ "agent": request.agent, "agentMode": session.agent_mode, @@ -1651,6 +1655,8 @@ impl SessionManager { } let native_session_id = session.native_session_id.clone(); + let telemetry_agent_mode = session.agent_mode.clone(); + let telemetry_permission_mode = session.permission_mode.clone(); let mut sessions = self.sessions.lock().await; sessions.push(session); drop(sessions); @@ -1664,6 +1670,14 @@ impl SessionManager { self.ensure_opencode_stream(session_id).await?; } + telemetry::log_session_created(telemetry::SessionConfig { + agent: telemetry_agent, + agent_mode: Some(telemetry_agent_mode), + permission_mode: Some(telemetry_permission_mode), + model: telemetry_model, + variant: telemetry_variant, + }); + Ok(CreateSessionResponse { healthy: true, error: None, diff --git a/server/packages/sandbox-agent/src/telemetry.rs b/server/packages/sandbox-agent/src/telemetry.rs index 6ff221b..deaae77 100644 --- a/server/packages/sandbox-agent/src/telemetry.rs +++ b/server/packages/sandbox-agent/src/telemetry.rs @@ -3,6 +3,7 @@ use std::env; use std::fs; use std::io::{Read, Write}; use std::path::{Path, PathBuf}; +use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use reqwest::Client; @@ -10,6 +11,8 @@ use serde::Serialize; use time::OffsetDateTime; use tokio::time::Instant; +static TELEMETRY_ENABLED: AtomicBool = AtomicBool::new(false); + const TELEMETRY_URL: &str = "https://tc.rivet.dev"; const TELEMETRY_ENV_DEBUG: &str = "SANDBOX_AGENT_TELEMETRY_DEBUG"; const TELEMETRY_ID_FILE: &str = "telemetry_id"; @@ -60,15 +63,17 @@ struct ProviderInfo { } pub fn telemetry_enabled(no_telemetry: bool) -> bool { - if no_telemetry { - return false; - } - if cfg!(debug_assertions) { - return env::var(TELEMETRY_ENV_DEBUG) + let enabled = if no_telemetry { + false + } else if cfg!(debug_assertions) { + env::var(TELEMETRY_ENV_DEBUG) .map(|value| matches!(value.as_str(), "1" | "true" | "TRUE")) - .unwrap_or(false); - } - true + .unwrap_or(false) + } else { + true + }; + TELEMETRY_ENABLED.store(enabled, Ordering::Relaxed); + enabled } pub fn log_enabled_message() { @@ -431,3 +436,78 @@ fn metadata_or_none( Some(map) } } + +#[derive(Debug, Serialize)] +struct SessionCreatedEvent { + p: String, + dt: i64, + et: String, + eid: String, + ev: String, + d: SessionCreatedTelemetryData, + v: u8, +} + +#[derive(Debug, Serialize)] +struct SessionCreatedTelemetryData { + version: String, + agent: String, + #[serde(skip_serializing_if = "Option::is_none")] + agent_mode: Option, + #[serde(skip_serializing_if = "Option::is_none")] + permission_mode: Option, + #[serde(skip_serializing_if = "Option::is_none")] + model: Option, + #[serde(skip_serializing_if = "Option::is_none")] + variant: Option, +} + +pub struct SessionConfig { + pub agent: String, + pub agent_mode: Option, + pub permission_mode: Option, + pub model: Option, + pub variant: Option, +} + +pub fn log_session_created(config: SessionConfig) { + if !TELEMETRY_ENABLED.load(Ordering::Relaxed) { + return; + } + + tokio::spawn(async move { + let client = match Client::builder() + .timeout(Duration::from_millis(TELEMETRY_TIMEOUT_MS)) + .build() + { + Ok(client) => client, + Err(err) => { + tracing::debug!(error = %err, "failed to build telemetry client"); + return; + } + }; + + let dt = OffsetDateTime::now_utc().unix_timestamp(); + let eid = load_or_create_id(); + let event = SessionCreatedEvent { + p: "sandbox-agent".to_string(), + dt, + et: "session".to_string(), + eid, + ev: "session_created".to_string(), + d: SessionCreatedTelemetryData { + version: env!("CARGO_PKG_VERSION").to_string(), + agent: config.agent, + agent_mode: config.agent_mode, + permission_mode: config.permission_mode, + model: config.model, + variant: config.variant, + }, + v: 1, + }; + + if let Err(err) = client.post(TELEMETRY_URL).json(&event).send().await { + tracing::debug!(error = %err, "session telemetry request failed"); + } + }); +}