systemprompt-models 0.1.21

Shared data models and types for systemprompt.io OS
Documentation
use serde::{Deserialize, Serialize};
use serde_json::Value;

use super::execution_plan::{TemplateRef, ToolCallResult};

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct TemplateResolver;

impl TemplateResolver {
    pub fn resolve_arguments(arguments: &Value, results: &[ToolCallResult]) -> Value {
        Self::resolve_value(arguments, results)
    }

    fn resolve_value(value: &Value, results: &[ToolCallResult]) -> Value {
        match value {
            Value::String(s) if s.starts_with('$') && s.contains(".output.") => {
                Self::resolve_template(s, results)
            },
            Value::Array(arr) => Value::Array(
                arr.iter()
                    .map(|v| Self::resolve_value(v, results))
                    .collect(),
            ),
            Value::Object(obj) => Value::Object(
                obj.iter()
                    .map(|(k, v)| (k.clone(), Self::resolve_value(v, results)))
                    .collect(),
            ),
            Value::Null | Value::Bool(_) | Value::Number(_) | Value::String(_) => value.clone(),
        }
    }

    fn resolve_template(template: &str, results: &[ToolCallResult]) -> Value {
        let Some(template_ref) = TemplateRef::parse(template) else {
            return Value::String(template.to_string());
        };

        let Some(result) = results.get(template_ref.tool_index) else {
            return Value::Null;
        };

        Self::get_nested_value(&result.output, &template_ref.field_path)
    }

    fn get_nested_value(value: &Value, path: &[String]) -> Value {
        let mut current = value;
        for segment in path {
            match current.get(segment) {
                Some(v) => current = v,
                None => return Value::Null,
            }
        }
        current.clone()
    }
}