1use super::init::{
2 build_provider_handles, build_schedule_manager, build_spawn_scheduler, init_mcp_manager,
3 init_metrics_service, init_schedule_store, init_skill_manager, init_storage,
4 load_permission_checker, spawn_runner_cleanup_task,
5};
6use super::tools::{build_base_tools, build_root_tools};
7use super::*;
8use crate::tools::OptionalSubagentModelResolver;
9use bamboo_agent_core::storage::Storage;
10
11impl AppState {
12 pub async fn new(bamboo_home_dir: PathBuf) -> Result<Self, AppError> {
47 bamboo_infrastructure::paths::init_bamboo_dir(bamboo_home_dir.clone());
50
51 let config = Config::from_data_dir(Some(bamboo_home_dir.clone()));
53
54 let provider =
56 match bamboo_infrastructure::create_provider_with_dir(&config, bamboo_home_dir.clone())
57 .await
58 {
59 Ok(p) => p,
60 Err(e) => {
61 tracing::error!("Failed to create provider: {}.", e);
64 Arc::new(UnconfiguredProvider {
65 message: e.to_string(),
66 })
67 }
68 };
69
70 Self::new_with_provider(bamboo_home_dir, config, provider).await
71 }
72
73 pub async fn new_with_provider(
88 bamboo_home_dir: PathBuf,
89 config: Config,
90 provider: Arc<dyn LLMProvider>,
91 ) -> Result<Self, AppError> {
92 let data_dir = bamboo_home_dir.clone();
93 let (session_store, storage) = init_storage(&data_dir).await?;
94 let persistence = Arc::new(LockedSessionStore::new(storage.clone()));
95
96 let sessions: Arc<RwLock<HashMap<String, bamboo_agent_core::Session>>> =
98 Arc::new(RwLock::new(HashMap::new()));
99
100 let config = Arc::new(RwLock::new(config));
101
102 let permission_checker = load_permission_checker(&bamboo_home_dir).await;
103 let mcp_manager = init_mcp_manager(config.clone());
104 let skill_manager = init_skill_manager(&data_dir).await;
105 let metrics_service = init_metrics_service(&data_dir).await?;
106
107 let startup_sessions = {
108 let entries = session_store.list_index_entries().await;
109 let mut sessions = Vec::new();
110 for entry in entries {
111 if let Some(session) = session_store.load_session(&entry.id).await.map_err(AppError::StorageError)? {
112 sessions.push(session);
113 }
114 }
115 sessions
116 };
117 metrics_service
118 .reconcile_startup_sessions(startup_sessions, &[])
119 .await
120 .map_err(|error| {
121 AppError::InternalError(anyhow::anyhow!(
122 "Failed to reconcile stale metrics state on startup: {error}"
123 ))
124 })?;
125
126 let agent_runners: Arc<RwLock<HashMap<String, AgentRunner>>> =
127 Arc::new(RwLock::new(HashMap::new()));
128 spawn_runner_cleanup_task(agent_runners.clone(), None);
129
130 let process_registry = Arc::new(ProcessRegistry::new());
131 let (provider_lock, provider_handle) = build_provider_handles(provider);
132
133 let config_snapshot = config.read().await;
135 let provider_registry = match bamboo_infrastructure::ProviderRegistry::from_config(
136 &config_snapshot,
137 bamboo_home_dir.clone(),
138 )
139 .await
140 {
141 Ok(registry) => Arc::new(registry),
142 Err(e) => {
143 tracing::error!("Failed to create provider registry: {}", e);
144 Arc::new(
145 bamboo_infrastructure::ProviderRegistry::from_config(
146 &Config::default(),
147 bamboo_home_dir.clone(),
148 )
149 .await
150 .expect("Cannot create even an empty provider registry"),
151 )
152 }
153 };
154 drop(config_snapshot);
155
156 let provider_router = Arc::new(bamboo_infrastructure::ProviderModelRouter::new(
157 provider_registry.clone(),
158 ));
159 let model_catalog = Arc::new(bamboo_infrastructure::ModelCatalogService::new(
160 provider_registry.clone(),
161 ));
162
163 let base_tools = build_base_tools(
164 config.clone(),
165 permission_checker,
166 mcp_manager.clone(),
167 skill_manager.clone(),
168 storage.clone(),
169 persistence.clone(),
170 sessions.clone(),
171 bamboo_home_dir.clone(),
172 );
173
174 let session_event_senders: Arc<RwLock<HashMap<String, broadcast::Sender<AgentEvent>>>> =
176 Arc::new(RwLock::new(HashMap::new()));
177
178 let subagent_profiles = crate::subagent_profiles::load_registry(&bamboo_home_dir, None)
186 .map_err(|e| {
187 crate::error::AppError::InternalError(anyhow::anyhow!(
188 "failed to load subagent profile registry: {e}"
189 ))
190 })?;
191
192 let child_tools: Arc<dyn bamboo_agent_core::tools::ToolExecutor> =
197 Arc::new(crate::tools::PolicyAwareToolExecutor::new(
198 base_tools.clone(),
199 subagent_profiles.clone(),
200 sessions.clone(),
201 ));
202
203 let agent = Arc::new(
208 bamboo_engine::Agent::builder()
209 .storage(storage.clone())
210 .persistence(persistence.clone())
211 .attachment_reader(session_store.clone())
212 .skill_manager(skill_manager.clone())
213 .metrics_collector(metrics_service.collector())
214 .config(config.clone())
215 .provider(provider_handle.clone())
216 .default_tools(base_tools.clone())
217 .build()
218 .expect("agent runtime should be fully configured"),
219 );
220
221 let child_completion_coordinator = Arc::new(
222 super::child_completion_coordinator::ChildCompletionCoordinator::new(
223 storage.clone(),
224 persistence.clone(),
225 sessions.clone(),
226 agent_runners.clone(),
227 session_event_senders.clone(),
228 agent.clone(),
229 config.clone(),
230 provider_registry.clone(),
231 provider_router.clone(),
232 data_dir.clone(),
233 ),
234 );
235
236 let config_snapshot = config.read().await.clone();
238 let external_runner =
239 crate::external_agents::runtime::build_external_child_runner(&config_snapshot);
240 let spawn_scheduler = build_spawn_scheduler(
241 agent.clone(),
242 child_tools,
243 sessions.clone(),
244 agent_runners.clone(),
245 session_event_senders.clone(),
246 external_runner,
247 Some(provider_router.clone()),
248 Some(child_completion_coordinator.clone()),
249 Some(data_dir.clone()),
250 );
251
252 let tools_with_task = base_tools.clone();
253
254 let schedule_store = init_schedule_store(&data_dir).await?;
255 let schedule_manager = build_schedule_manager(
256 schedule_store.clone(),
257 agent.clone(),
258 tools_with_task.clone(),
259 sessions.clone(),
260 agent_runners.clone(),
261 session_event_senders.clone(),
262 persistence.clone(),
263 config.clone(),
264 Some(data_dir.clone()),
265 );
266
267 crate::services::auto_dream::spawn_auto_dream_task(
268 crate::services::auto_dream::AutoDreamContext {
269 session_store: session_store.clone(),
270 storage: storage.clone(),
271 provider: provider_handle.clone(),
272 config: config.clone(),
273 provider_registry: provider_registry.clone(),
274 },
275 );
276
277 let config_for_resolver = config.clone();
278 let subagent_model_resolver: OptionalSubagentModelResolver = {
279 let registry = provider_registry.clone();
280 Some(Arc::new(
281 move |subagent_type: String| -> futures::future::BoxFuture<
282 'static,
283 Option<bamboo_domain::ProviderModelRef>,
284 > {
285 let config_for_resolver = config_for_resolver.clone();
286 let registry = registry.clone();
287 Box::pin(async move {
288 let config_snap = config_for_resolver.read().await.clone();
289 crate::model_config_helper::resolve_subagent_model_ref(
290 &config_snap,
291 &config_snap.provider,
292 ®istry,
293 &subagent_type,
294 )
295 })
296 },
297 ))
298 };
299
300 let tools = build_root_tools(
301 tools_with_task.clone(),
302 schedule_store.clone(),
303 schedule_manager.clone(),
304 session_store.clone(),
305 storage.clone(),
306 persistence.clone(),
307 spawn_scheduler.clone(),
308 sessions.clone(),
309 agent_runners.clone(),
310 session_event_senders.clone(),
311 subagent_model_resolver,
312 config.clone(),
313 subagent_profiles.clone(),
314 );
315
316 child_completion_coordinator
317 .set_root_tools(tools.clone())
318 .await;
319
320 let tool_factory =
321 crate::tools::ToolSurfaceFactory::new(base_tools, tools_with_task, tools);
322
323 Ok(Self {
324 app_data_dir: bamboo_home_dir,
325 config,
326 provider: provider_lock,
327 provider_handle,
328 sessions,
329 storage,
330 session_store,
331 persistence,
332 spawn_scheduler,
333 child_completion_coordinator,
334 schedule_store,
335 schedule_manager,
336 tool_factory,
337 subagent_profiles,
338 cancel_tokens: Arc::new(RwLock::new(HashMap::new())),
339 skill_manager,
340 mcp_manager,
341 metrics_service,
342 agent_runners,
343 session_event_senders,
344 process_registry,
345 metrics_bus: None, agent,
347 provider_registry,
348 provider_router,
349 model_catalog,
350 title_gen_in_flight: Arc::new(dashmap::DashSet::new()),
351 })
352 }
353}