microclaw-engine 0.10.1

Channel-independent Agent Engine and default services for MicroClaw
Documentation
use base64::prelude::*;
use serde_yaml::{Mapping, Value};
use tracing::warn;

use super::TraceTargetConfig;

fn get_trimmed<'a>(map: &'a Mapping, key: &str) -> Option<&'a str> {
    map.get(Value::String(key.to_string()))
        .and_then(Value::as_str)
        .map(str::trim)
        .filter(|v| !v.is_empty())
}

pub fn apply(map: &Mapping, target: &mut TraceTargetConfig) {
    let Some(pk) = get_trimmed(map, "langfuse_public_key") else {
        return;
    };
    let Some(sk) = get_trimmed(map, "langfuse_secret_key") else {
        return;
    };
    let host = normalize_langfuse_host(
        get_trimmed(map, "langfuse_host").unwrap_or("https://cloud.langfuse.com"),
    );

    if target.endpoint.is_none() {
        target.endpoint = Some(format!(
            "{}/api/public/otel/v1/traces",
            host.trim_end_matches('/')
        ));
    }

    let auth = BASE64_STANDARD.encode(format!("{pk}:{sk}"));
    if !target
        .headers
        .iter()
        .any(|(k, _)| k.eq_ignore_ascii_case("authorization"))
    {
        target
            .headers
            .push(("Authorization".to_string(), format!("Basic {auth}")));
    }
}

fn normalize_langfuse_host(raw: &str) -> String {
    let mut host = raw.trim().trim_end_matches('/').to_string();
    if let Some((prefix, _)) = host.split_once("/project/") {
        warn!(
            langfuse_host = %raw,
            "langfuse_host appears to be a UI project URL; using host root instead"
        );
        host = prefix.to_string();
    }
    if host.ends_with("/api/public/otel/v1/traces") {
        host = host
            .trim_end_matches("/api/public/otel/v1/traces")
            .to_string();
    } else if host.ends_with("/api/public/otel") {
        host = host.trim_end_matches("/api/public/otel").to_string();
    }
    host
}