Skip to main content

relay_knowledge/bootstrap/
service.rs

1//! Outermost service assembly for concrete runtime adapters.
2
3use std::sync::Arc;
4
5use crate::{
6    adapters::{NetworkEmbeddingProvider, NetworkWorkerOutbound, SqliteKnowledgeStoreFactory},
7    application::{
8        ProcessRuntimeConfig, RelayKnowledgeService, RuntimeConfiguration,
9        RuntimeConfigurationError,
10    },
11    env::{EnvironmentConfig, windows_system_root_from_process},
12    ports::{embedding::EmbeddingProvider, worker_outbound::WorkerOutboundPort},
13    project::PROJECT_NAME,
14    storage::{KnowledgeStore, KnowledgeStoreFactory},
15};
16
17impl RelayKnowledgeService {
18    /// Creates a service from validated configuration and outer storage adapters.
19    pub fn new(runtime: RuntimeConfiguration) -> Self {
20        let storage: Arc<dyn KnowledgeStoreFactory> = Arc::new(SqliteKnowledgeStoreFactory::new(
21            runtime.paths.clone(),
22            runtime.storage.topology,
23        ));
24        let adapters = network_adapters(&runtime);
25        Self::with_runtime_adapters(runtime, storage, adapters.embedding, adapters.worker)
26    }
27
28    /// Creates a service backed by an explicit store for deterministic tests.
29    pub fn with_store(runtime: RuntimeConfiguration, store: Arc<dyn KnowledgeStore>) -> Self {
30        let adapters = network_adapters(&runtime);
31        Self::with_store_and_runtime_adapters(runtime, store, adapters.embedding, adapters.worker)
32    }
33
34    /// Creates a service by reading the current process environment once.
35    pub async fn from_process_environment() -> Result<Self, RuntimeConfigurationError> {
36        runtime_configuration_from_process_environment()
37            .await
38            .map(Self::new)
39    }
40
41    /// Creates a service from a deterministic environment snapshot.
42    pub async fn from_environment(
43        environment: &EnvironmentConfig,
44    ) -> Result<Self, RuntimeConfigurationError> {
45        RuntimeConfiguration::from_environment(environment)
46            .await
47            .map(Self::new)
48    }
49
50    /// Creates a service from deterministic environment and process snapshots.
51    pub async fn from_environment_with_process(
52        environment: &EnvironmentConfig,
53        process: ProcessRuntimeConfig,
54    ) -> Result<Self, RuntimeConfigurationError> {
55        RuntimeConfiguration::from_environment_with_process(environment, process)
56            .await
57            .map(Self::new)
58    }
59}
60
61/// Captures live process inputs at the composition root before application
62/// configuration is resolved from typed snapshots.
63pub(crate) async fn runtime_configuration_from_process_environment()
64-> Result<RuntimeConfiguration, RuntimeConfigurationError> {
65    let environment =
66        EnvironmentConfig::from_process().map_err(RuntimeConfigurationError::Environment)?;
67    let current_executable =
68        std::env::current_exe().unwrap_or_else(|_| std::path::PathBuf::from(PROJECT_NAME));
69    let process = ProcessRuntimeConfig::from_bootstrap_inputs(
70        current_executable,
71        windows_system_root_from_process(),
72    );
73
74    RuntimeConfiguration::from_environment_with_process(&environment, process).await
75}
76
77struct RuntimeNetworkAdapters {
78    embedding: Option<Arc<dyn EmbeddingProvider>>,
79    worker: Option<Arc<dyn WorkerOutboundPort>>,
80}
81
82fn network_adapters(runtime: &RuntimeConfiguration) -> RuntimeNetworkAdapters {
83    let embedding = runtime.retrieval.remote_embedding.clone().map(|config| {
84        Arc::new(NetworkEmbeddingProvider::new(
85            config,
86            runtime.network.clone(),
87        )) as Arc<dyn EmbeddingProvider>
88    });
89    let worker = Some(
90        Arc::new(NetworkWorkerOutbound::new(runtime.network.clone()))
91            as Arc<dyn WorkerOutboundPort>,
92    );
93    RuntimeNetworkAdapters { embedding, worker }
94}
95
96#[cfg(test)]
97#[path = "service_tests.rs"]
98mod tests;