use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
pub enum ApiFormat {
#[default]
ChatCompletions,
Responses,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
pub enum OtelProtocol {
#[default]
Grpc,
HttpProtobuf,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TelemetryConfig {
pub enabled: bool,
pub endpoint: String,
pub protocol: OtelProtocol,
pub headers: Vec<(String, String)>,
pub service_name: String,
}
impl Default for TelemetryConfig {
fn default() -> Self {
Self {
enabled: false,
endpoint: "http://localhost:4317".into(),
protocol: OtelProtocol::Grpc,
headers: vec![],
service_name: "simple-agents".into(),
}
}
}
impl TelemetryConfig {
pub fn from_env() -> Self {
let enabled = std::env::var("SIMPLE_AGENTS_TRACING_ENABLED")
.map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
.unwrap_or(false);
let endpoint = std::env::var("OTEL_EXPORTER_OTLP_ENDPOINT")
.unwrap_or_else(|_| "http://localhost:4317".into());
let protocol = match std::env::var("OTEL_EXPORTER_OTLP_PROTOCOL").as_deref() {
Ok("http/protobuf") => OtelProtocol::HttpProtobuf,
_ => OtelProtocol::Grpc,
};
let headers = std::env::var("OTEL_EXPORTER_OTLP_HEADERS")
.map(|h| {
h.split(',')
.filter_map(|pair| {
let (k, v) = pair.split_once('=')?;
Some((k.trim().to_string(), v.trim().to_string()))
})
.collect()
})
.unwrap_or_default();
let service_name =
std::env::var("OTEL_SERVICE_NAME").unwrap_or_else(|_| "simple-agents".into());
Self {
enabled,
endpoint,
protocol,
headers,
service_name,
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct TraceContext {
pub trace_id: Option<String>,
pub span_id: Option<String>,
pub session_id: Option<String>,
pub user_id: Option<String>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_api_format_default() {
assert_eq!(ApiFormat::default(), ApiFormat::ChatCompletions);
}
#[test]
fn test_telemetry_config_default() {
let cfg = TelemetryConfig::default();
assert!(!cfg.enabled);
assert_eq!(cfg.endpoint, "http://localhost:4317");
}
#[test]
fn test_telemetry_config_serialization() {
let cfg = TelemetryConfig::default();
let json = serde_json::to_string(&cfg).unwrap();
let parsed: TelemetryConfig = serde_json::from_str(&json).unwrap();
assert_eq!(parsed.endpoint, cfg.endpoint);
}
}