Skip to main content

ralph_workflow/app/initialization/
mod.rs

1//! Initialization boundary module.
2//!
3//! This module provides boundary functions for pipeline initialization that involve
4//! imperative setup and configuration restoration. As a boundary module, it is
5//! exempt from functional programming lints.
6
7use crate::agents::AgentRegistry;
8use crate::config::UnifiedConfig;
9use std::path::Path;
10
11/// Restore configuration from a checkpoint by applying checkpoint overrides.
12///
13/// This function performs imperative config restoration which requires mutable access.
14/// It is placed in a boundary module for functional code compliance.
15pub fn restore_config_from_checkpoint(
16    mut config: crate::config::Config,
17    checkpoint: &crate::checkpoint::PipelineCheckpoint,
18) -> crate::config::Config {
19    crate::checkpoint::apply_checkpoint_to_config(&mut config, checkpoint);
20    config
21}
22
23/// Load agent registry with optional unified config.
24///
25/// This boundary function handles the I/O and mutation involved in registry loading.
26pub fn load_agent_registry_boundary<L: crate::agents::opencode_api::CatalogLoader>(
27    unified: Option<&UnifiedConfig>,
28    config_path: &Path,
29    catalog_loader: &L,
30) -> anyhow::Result<(AgentRegistry, Vec<crate::agents::ConfigSource>)> {
31    let registry = if let Some(unified_config) = unified {
32        AgentRegistry::new()?.apply_unified_config(unified_config)?
33    } else {
34        AgentRegistry::new()?
35    };
36
37    let config_sources: Vec<_> = if let Some(unified_config) = unified {
38        let agents_loaded = unified_config.ccs_aliases.len() + unified_config.agents.len();
39        vec![crate::agents::ConfigSource {
40            path: config_path.to_path_buf(),
41            agents_loaded,
42        }]
43    } else {
44        vec![]
45    };
46
47    let opencode_refs =
48        crate::agents::validation::get_opencode_refs_in_resolved_drains(registry.resolved_drains());
49    let registry = if !opencode_refs.is_empty() {
50        let catalog = catalog_loader.load().map_err(|e| {
51            anyhow::anyhow!(
52                "Failed to load OpenCode API catalog. \
53                 This is required for the following agent references: {opencode_refs:?}. \
54                 Error: {e}"
55            )
56        })?;
57        let registry = registry.with_opencode_catalog(catalog.clone());
58
59        crate::agents::validation::validate_opencode_agents_in_resolved_drains(
60            registry.resolved_drains(),
61            &catalog,
62        )
63        .map_err(|e| anyhow::anyhow!("{e}"))?;
64        registry
65    } else {
66        registry
67    };
68
69    Ok((registry, config_sources))
70}