harn-vm 0.10.34

Async bytecode virtual machine for the Harn programming language
Documentation
use crate::value::{VmError, VmValue};

tokio::task_local! {
    static COST_ROUTE_STACK: Vec<crate::value::DictMap>;
}

fn normalize_config(config: crate::value::DictMap) -> Result<crate::value::DictMap, VmError> {
    crate::llm::helpers::validate_llm_option_keys(&config)?;
    Ok(config)
}

fn merge_budget(inherited: Option<&VmValue>, explicit: Option<&VmValue>) -> Option<VmValue> {
    let mut merged = match inherited {
        Some(VmValue::Dict(dict)) => dict.as_ref().clone(),
        Some(value) => {
            let mut dict = crate::value::DictMap::new();
            dict.insert(crate::value::intern_key("max_cost_usd"), value.clone());
            dict
        }
        None => crate::value::DictMap::new(),
    };
    if let Some(VmValue::Dict(dict)) = explicit {
        for (key, value) in dict.iter() {
            merged.insert(key.clone(), value.clone());
        }
    } else if let Some(value) = explicit {
        merged.insert(crate::value::intern_key("max_cost_usd"), value.clone());
    }
    (!merged.is_empty()).then(|| VmValue::dict(merged))
}

pub(crate) fn merge_context_options(
    explicit: Option<crate::value::DictMap>,
) -> Option<crate::value::DictMap> {
    let inherited = COST_ROUTE_STACK
        .try_with(|stack| {
            let mut merged = crate::value::DictMap::new();
            for frame in stack.iter() {
                for (key, value) in frame {
                    merged.insert(key.clone(), value.clone());
                }
            }
            merged
        })
        .unwrap_or_default();

    if inherited.is_empty() {
        return explicit;
    }

    let mut merged = inherited;
    if let Some(explicit) = explicit {
        let budget = merge_budget(merged.get("budget"), explicit.get("budget"));
        for (key, value) in explicit {
            merged.insert(key, value);
        }
        if let Some(budget) = budget {
            merged.insert(crate::value::intern_key("budget"), budget);
        }
    }
    Some(merged)
}

pub(crate) async fn cost_route_impl(
    ctx: &crate::vm::AsyncBuiltinCtx,
    args: Vec<VmValue>,
) -> Result<VmValue, VmError> {
    let config = match args.first().and_then(VmValue::as_dict) {
        Some(config) => normalize_config(config.clone())?,
        None => {
            return Err(VmError::Runtime(
                "cost_route: first argument must be a config dict".to_string(),
            ))
        }
    };
    let closure = match args.get(1) {
        Some(VmValue::Closure(closure)) => closure.clone(),
        _ => {
            return Err(VmError::Runtime(
                "cost_route: second argument must be a closure".to_string(),
            ))
        }
    };

    let mut child_vm = ctx.child_vm();
    let mut stack = COST_ROUTE_STACK
        .try_with(|current| current.clone())
        .unwrap_or_default();
    stack.push(config);
    let result = COST_ROUTE_STACK
        .scope(stack, child_vm.call_closure_pub(&closure, &[]))
        .await;
    ctx.forward_output(&child_vm.take_output());
    result
}