use crate::events::Event;
use crate::events::LlmGenerationMetadata;
use crate::events::correlation::provider_correlation;
#[cfg(feature = "otel")]
const ATTRIBUTE_PREFIX: &str = "everruns.";
#[cfg(feature = "otel")]
pub(crate) const USAGE_COST_UNKNOWN_COMPONENTS: &str = "everruns.usage.cost_unknown_components";
fn unpriced_components(meta: &LlmGenerationMetadata) -> Vec<String> {
meta.unpriced_cost_components()
.map(|component| format!("{}:{}", component.kind, component.name))
.collect()
}
#[cfg(feature = "otel")]
pub(crate) fn otel_provider_attributes(event: &Event) -> Vec<opentelemetry::KeyValue> {
provider_correlation(event.metadata.as_ref())
.into_iter()
.map(|(key, value)| opentelemetry::KeyValue::new(format!("{ATTRIBUTE_PREFIX}{key}"), value))
.collect()
}
#[cfg(feature = "otel")]
pub(crate) fn otel_unknown_cost_attributes(
meta: &LlmGenerationMetadata,
) -> Vec<opentelemetry::KeyValue> {
let unpriced: Vec<opentelemetry::StringValue> = unpriced_components(meta)
.into_iter()
.map(Into::into)
.collect();
if unpriced.is_empty() {
return Vec::new();
}
vec![opentelemetry::KeyValue::new(
USAGE_COST_UNKNOWN_COMPONENTS,
opentelemetry::Value::Array(unpriced.into()),
)]
}
#[cfg(feature = "braintrust")]
pub(crate) fn annotate_braintrust(event: &Event, metadata: &mut serde_json::Value) {
for (key, value) in provider_correlation(event.metadata.as_ref()) {
metadata[key] = serde_json::json!(value);
}
super::generation_attrs::annotate_braintrust(event, metadata);
if let crate::events::EventData::LlmGeneration(data) = &event.data
&& !data.metadata.cost_components.is_empty()
{
metadata["cost_components"] = serde_json::json!(data.metadata.cost_components);
metadata["cost_unknown_components"] =
serde_json::json!(unpriced_components(&data.metadata));
}
}