vv-agent 0.1.3

VectorVein agent runtime, SDK, CLI, tools, and workspace backends
Documentation
use serde_json::{json, Value};

mod blocks;
mod breakpoints;
mod estimate;
mod model;
mod sections;

pub const SYSTEM_PROMPT_SECTIONS_KEY: &str = "system_prompt_sections";
pub const PROMPT_CACHE_ENABLED_KEY: &str = "anthropic_prompt_cache_enabled";

pub fn cache_control_ephemeral() -> Value {
    json!({"type": "ephemeral"})
}

#[allow(non_snake_case)]
pub fn CACHE_CONTROL_EPHEMERAL() -> Value {
    cache_control_ephemeral()
}

pub fn apply_claude_prompt_cache(
    endpoint_type: &str,
    model: &str,
    messages: &[Value],
    tools: &[Value],
    extra_body: Option<&Value>,
    metadata: Option<&Value>,
) -> (Vec<Value>, Vec<Value>, Option<Value>) {
    let normalized_endpoint = endpoint_type.trim().to_ascii_lowercase();
    let normalized_model = model.trim().to_ascii_lowercase();
    let request_metadata = metadata.and_then(Value::as_object);

    if !matches!(
        normalized_endpoint.as_str(),
        "anthropic" | "anthropic_vertex"
    ) {
        return (messages.to_vec(), tools.to_vec(), extra_body.cloned());
    }
    if !normalized_model.starts_with("claude") {
        return (messages.to_vec(), tools.to_vec(), extra_body.cloned());
    }
    if request_metadata
        .and_then(|metadata| metadata.get(PROMPT_CACHE_ENABLED_KEY))
        .and_then(Value::as_bool)
        == Some(false)
    {
        return (messages.to_vec(), tools.to_vec(), extra_body.cloned());
    }

    let mut planned_messages = messages.to_vec();
    let mut planned_tools = tools.to_vec();
    let planned_extra_body = extra_body.filter(|value| value.is_object()).cloned();

    breakpoints::apply_cache_breakpoints(
        &mut planned_messages,
        &mut planned_tools,
        request_metadata,
        model::minimum_cacheable_tokens(&normalized_model),
    );

    (planned_messages, planned_tools, planned_extra_body)
}