codex_memory/application/
dependency_container.rs

1use crate::{
2    backup::BackupManager,
3    manager::ServerManager,
4    mcp_server::{MCPServer, MCPServerConfig},
5    memory::{
6        connection::create_pool, silent_harvester::SilentHarvesterService,
7        tier_manager::TierManager,
8    },
9    monitoring::HealthChecker,
10    Config, DatabaseSetup, MemoryRepository, SetupManager, SimpleEmbedder,
11};
12use anyhow::Result;
13use sqlx::PgPool;
14use std::sync::Arc;
15use tracing::info;
16
17/// Dependency injection container for the application
18pub struct DependencyContainer {
19    // Core configuration
20    pub config: Config,
21
22    // Database layer
23    pub db_pool: Arc<PgPool>,
24
25    // Repository layer
26    pub memory_repository: Arc<MemoryRepository>,
27
28    // Service layer
29    pub embedder: Arc<SimpleEmbedder>,
30    pub setup_manager: Arc<SetupManager>,
31    pub database_setup: Arc<DatabaseSetup>,
32    pub backup_manager: Option<Arc<BackupManager>>,
33    pub tier_manager: Option<Arc<TierManager>>,
34    pub harvester_service: Option<Arc<SilentHarvesterService>>,
35
36    // Infrastructure layer
37    pub health_checker: Arc<HealthChecker>,
38    pub mcp_server: Option<Arc<MCPServer>>,
39    pub server_manager: Arc<ServerManager>,
40}
41
42impl DependencyContainer {
43    pub async fn new() -> Result<Self> {
44        info!("🔧 Initializing dependency container...");
45
46        // Load configuration
47        let config = Config::from_env().unwrap_or_else(|_| {
48            info!("⚠️  No configuration found, using defaults");
49            Config::default()
50        });
51
52        // Create database connection pool
53        let db_pool = Arc::new(
54            create_pool(&config.database_url, config.operational.max_db_connections).await?,
55        );
56
57        // Repository layer
58        let memory_repository = Arc::new(MemoryRepository::with_config(
59            (*db_pool).clone(),
60            config.clone(),
61        ));
62
63        // Service layer
64        let embedder = Arc::new(Self::create_embedder(&config)?);
65        let setup_manager = Arc::new(SetupManager::new(config.clone()));
66        let database_setup = Arc::new(DatabaseSetup::new(config.database_url.clone()));
67
68        // Infrastructure layer
69        let health_checker = Arc::new(HealthChecker::new(db_pool.clone()));
70        let server_manager = Arc::new(ServerManager::new());
71
72        // Optional services
73        let backup_manager = if config.backup.enabled {
74            let backup_config = crate::backup::BackupConfig::default(); // Use default config for now
75            Some(Arc::new(BackupManager::new(backup_config, db_pool.clone())))
76        } else {
77            None
78        };
79
80        let tier_manager = if config.tier_manager.enabled {
81            Some(Arc::new(TierManager::new(
82                memory_repository.clone(),
83                config.tier_manager.clone(),
84            )?))
85        } else {
86            None
87        };
88
89        // TODO: Harvest service requires additional dependencies that need to be properly configured
90        // For now, disable until we can implement proper dependency injection
91        let harvester_service = None;
92        // let harvester_service = Some(Arc::new(SilentHarvesterService::new(
93        //     memory_repository.clone(),
94        //     importance_pipeline,
95        //     embedder.clone(),
96        //     Some(config.harvester.clone()),
97        //     &prometheus_registry,
98        // )?));
99
100        info!("✅ Dependency container initialized successfully");
101
102        Ok(Self {
103            config,
104            db_pool,
105            memory_repository,
106            embedder,
107            setup_manager,
108            database_setup,
109            backup_manager,
110            tier_manager,
111            harvester_service,
112            health_checker,
113            mcp_server: None, // Created on demand
114            server_manager,
115        })
116    }
117
118    fn create_embedder(config: &Config) -> Result<SimpleEmbedder> {
119        match config.embedding.provider.as_str() {
120            "openai" => Ok(SimpleEmbedder::new(config.embedding.api_key.clone())
121                .with_model(config.embedding.model.clone())
122                .with_base_url(config.embedding.base_url.clone())),
123            "ollama" => Ok(SimpleEmbedder::new_ollama(
124                config.embedding.base_url.clone(),
125                config.embedding.model.clone(),
126            )),
127            "mock" => Ok(SimpleEmbedder::new_mock()),
128            _ => Err(anyhow::anyhow!(
129                "Unsupported embedding provider: {}",
130                config.embedding.provider
131            )),
132        }
133    }
134
135    pub async fn create_mcp_server(&self) -> Result<MCPServer> {
136        let mcp_config = MCPServerConfig::default();
137
138        let server = MCPServer::new(
139            self.memory_repository.clone(),
140            self.embedder.clone(),
141            mcp_config,
142        )?;
143
144        Ok(server)
145    }
146
147    pub async fn health_check(&self) -> Result<bool> {
148        // Quick health check using our services
149        match self.database_setup.health_check().await {
150            Ok(health) => Ok(health.is_healthy()),
151            Err(_) => Ok(false),
152        }
153    }
154}