systemprompt-runtime 0.1.22

Application runtime context and module registry for systemprompt.io
Documentation
use indicatif::{ProgressBar, ProgressStyle};
use std::path::Path;
use std::time::Duration;
use systemprompt_logging::CliService;
use systemprompt_models::validators::{ValidationConfigProvider, WebConfigRaw, WebMetadataRaw};
use systemprompt_models::{Config, ContentConfigRaw};
use systemprompt_traits::ConfigProvider;

pub fn load_content_config(
    config: &Config,
    mut provider: ValidationConfigProvider,
    verbose: bool,
) -> ValidationConfigProvider {
    if let Some(content_config_path) = ConfigProvider::get(config, "content_config_path") {
        let spinner = if verbose {
            Some(create_spinner("Loading content config"))
        } else {
            None
        };
        match load_yaml_config::<ContentConfigRaw>(Path::new(&content_config_path)) {
            Ok(cfg) => {
                if let Some(s) = spinner {
                    s.finish_and_clear();
                }
                if verbose {
                    CliService::phase_success("Content config", None);
                }
                provider = provider.with_content_config(cfg);
            },
            Err(e) => {
                if let Some(s) = spinner {
                    s.finish_and_clear();
                }
                if verbose {
                    CliService::phase_warning("Content config", Some(&e));
                }
            },
        }
    }
    provider
}

pub fn load_web_config(
    config: &Config,
    mut provider: ValidationConfigProvider,
    verbose: bool,
) -> ValidationConfigProvider {
    if let Some(web_config_path) = ConfigProvider::get(config, "web_config_path") {
        let spinner = if verbose {
            Some(create_spinner("Loading web config"))
        } else {
            None
        };
        match load_yaml_config::<WebConfigRaw>(Path::new(&web_config_path)) {
            Ok(cfg) => {
                if let Some(s) = spinner {
                    s.finish_and_clear();
                }
                if verbose {
                    CliService::phase_success("Web config", None);
                }
                provider = provider.with_web_config(cfg);
            },
            Err(e) => {
                if let Some(s) = spinner {
                    s.finish_and_clear();
                }
                if verbose {
                    CliService::phase_warning("Web config", Some(&e));
                }
            },
        }
    }
    provider
}

pub fn load_web_metadata(
    config: &Config,
    mut provider: ValidationConfigProvider,
    verbose: bool,
) -> ValidationConfigProvider {
    if let Some(web_metadata_path) = ConfigProvider::get(config, "web_metadata_path") {
        let spinner = if verbose {
            Some(create_spinner("Loading web metadata"))
        } else {
            None
        };
        match load_yaml_config::<WebMetadataRaw>(Path::new(&web_metadata_path)) {
            Ok(cfg) => {
                if let Some(s) = spinner {
                    s.finish_and_clear();
                }
                if verbose {
                    CliService::phase_success("Web metadata", None);
                }
                provider = provider.with_web_metadata(cfg);
            },
            Err(e) => {
                if let Some(s) = spinner {
                    s.finish_and_clear();
                }
                if verbose {
                    CliService::phase_warning("Web metadata", Some(&e));
                }
            },
        }
    }
    provider
}

pub fn create_spinner(message: &str) -> ProgressBar {
    let spinner = ProgressBar::new_spinner();
    spinner.set_style(
        ProgressStyle::default_spinner()
            .template("  {spinner:.208} {msg}")
            .unwrap_or_else(|_| ProgressStyle::default_spinner())
            .tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"),
    );
    spinner.set_message(format!("{}...", message));
    spinner.enable_steady_tick(Duration::from_millis(80));
    spinner
}

pub fn load_yaml_config<T: serde::de::DeserializeOwned>(path: &Path) -> Result<T, String> {
    let content = std::fs::read_to_string(path)
        .map_err(|e| format!("Cannot read {}: {}", path.display(), e))?;
    serde_yaml::from_str(&content).map_err(|e| format!("Cannot parse {}: {}", path.display(), e))
}

pub fn load_extension_config(path: &Path) -> Result<serde_json::Value, String> {
    let content = std::fs::read_to_string(path)
        .map_err(|e| format!("Cannot read {}: {}", path.display(), e))?;
    let yaml: serde_yaml::Value = serde_yaml::from_str(&content)
        .map_err(|e| format!("Cannot parse {}: {}", path.display(), e))?;
    serde_json::to_value(yaml).map_err(|e| format!("Cannot convert to JSON: {}", e))
}