vv-agent 0.8.0

VectorVein agent runtime, SDK, CLI, tools, and workspace backends
Documentation
use std::collections::BTreeMap;

use serde::de::DeserializeOwned;
use serde_json::Value;

use crate::events::{MemoryCompactMode, MemoryCompactTrigger, ReservedOutputSource, RunEvent};

use super::{with_selected_payload_metadata, RuntimeEventContext};

const PROVIDER_METADATA_FIELDS: &[&str] = &["memory_provider_results", "memory_provider_errors"];

pub(super) fn map_memory_compact_started(
    payload: &BTreeMap<String, Value>,
    context: &RuntimeEventContext,
) -> Option<RunEvent> {
    let event = RunEvent::memory_compact_started(
        &context.run_id,
        &context.trace_id,
        &context.agent_name,
        payload_u32(payload, "cycle")?,
        payload_usize(payload, "message_count")?,
        payload_optional_u64(payload, "estimated_tokens")?,
        payload_enum::<MemoryCompactTrigger>(payload, "trigger")?,
        payload_u64(payload, "configured_threshold")?,
        payload_u64(payload, "effective_threshold")?,
        payload_u64(payload, "microcompact_threshold")?,
        payload_u64(payload, "model_context_window")?,
        payload_nullable_u64(payload, "model_max_output_tokens")?,
        payload_u64(payload, "reserved_output_tokens")?,
        payload_enum::<ReservedOutputSource>(payload, "reserved_output_source")?,
        payload_u64(payload, "autocompact_buffer_tokens")?,
    );
    with_observed_identity(
        with_selected_payload_metadata(event, payload, PROVIDER_METADATA_FIELDS),
        payload,
    )
}

pub(super) fn map_memory_compact_completed(
    payload: &BTreeMap<String, Value>,
    context: &RuntimeEventContext,
) -> Option<RunEvent> {
    let event = RunEvent::memory_compact_completed(
        &context.run_id,
        &context.trace_id,
        &context.agent_name,
        payload_u32(payload, "cycle")?,
        payload_usize(payload, "before_count")?,
        payload_usize(payload, "after_count")?,
        payload_optional_u64(payload, "summary_tokens")?,
        payload_enum::<MemoryCompactMode>(payload, "mode")?,
        payload.get("changed").and_then(Value::as_bool)?,
    );
    with_observed_identity(
        with_selected_payload_metadata(event, payload, PROVIDER_METADATA_FIELDS),
        payload,
    )
}

fn with_observed_identity(event: RunEvent, payload: &BTreeMap<String, Value>) -> Option<RunEvent> {
    event
        .with_observed_identity(
            payload.get("event_id")?.as_str()?,
            payload.get("created_at")?.as_f64()?,
        )
        .ok()
}

fn payload_u64(payload: &BTreeMap<String, Value>, field: &str) -> Option<u64> {
    payload.get(field).and_then(Value::as_u64)
}

fn payload_u32(payload: &BTreeMap<String, Value>, field: &str) -> Option<u32> {
    u32::try_from(payload_u64(payload, field)?).ok()
}

fn payload_usize(payload: &BTreeMap<String, Value>, field: &str) -> Option<usize> {
    usize::try_from(payload_u64(payload, field)?).ok()
}

fn payload_optional_u64(payload: &BTreeMap<String, Value>, field: &str) -> Option<Option<u64>> {
    match payload.get(field) {
        None | Some(Value::Null) => Some(None),
        Some(value) => value.as_u64().map(Some),
    }
}

fn payload_nullable_u64(payload: &BTreeMap<String, Value>, field: &str) -> Option<Option<u64>> {
    match payload.get(field)? {
        Value::Null => Some(None),
        value => value.as_u64().map(Some),
    }
}

fn payload_enum<T: DeserializeOwned>(payload: &BTreeMap<String, Value>, field: &str) -> Option<T> {
    serde_json::from_value(payload.get(field)?.clone()).ok()
}