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_registry = match bamboo_infrastructure::ProviderRegistry::from_config(
55 &config,
56 bamboo_home_dir.clone(),
57 )
58 .await
59 {
60 Ok(registry) => Arc::new(registry),
61 Err(e) => {
62 tracing::error!("Failed to create provider registry: {}", e);
63 Arc::new(
64 bamboo_infrastructure::ProviderRegistry::from_config(
65 &Config::default(),
66 bamboo_home_dir.clone(),
67 )
68 .await
69 .expect("Cannot create even an empty provider registry"),
70 )
71 }
72 };
73
74 let provider = provider_registry.get_default().unwrap_or_else(|| {
75 let default_provider_name = provider_registry.default_provider_name();
76 let message = if config.has_provider_instances() {
77 format!(
78 "Default provider instance '{}' is not available or failed to initialize",
79 default_provider_name
80 )
81 } else {
82 format!(
83 "Provider '{}' is not available or failed to initialize",
84 config.provider
85 )
86 };
87 Arc::new(UnconfiguredProvider { message }) as Arc<dyn LLMProvider>
88 });
89
90 Self::new_with_provider(bamboo_home_dir, config, provider).await
91 }
92
93 pub async fn new_with_provider(
108 bamboo_home_dir: PathBuf,
109 config: Config,
110 provider: Arc<dyn LLMProvider>,
111 ) -> Result<Self, AppError> {
112 let data_dir = bamboo_home_dir.clone();
113 let (session_store, storage) = init_storage(&data_dir).await?;
114 let persistence = Arc::new(LockedSessionStore::new(storage.clone()));
115
116 let sessions: Arc<RwLock<HashMap<String, bamboo_agent_core::Session>>> =
118 Arc::new(RwLock::new(HashMap::new()));
119
120 let config = Arc::new(RwLock::new(config));
121
122 let permission_checker = load_permission_checker(&bamboo_home_dir).await;
123 let mcp_manager = init_mcp_manager(config.clone());
124 let skill_manager = init_skill_manager(&data_dir).await;
125 let metrics_service = init_metrics_service(&data_dir).await?;
126
127 let startup_sessions = {
128 let entries = session_store.list_index_entries().await;
129 let mut sessions = Vec::new();
130 for entry in entries {
131 if let Some(session) = session_store
132 .load_session(&entry.id)
133 .await
134 .map_err(AppError::StorageError)?
135 {
136 sessions.push(session);
137 }
138 }
139 sessions
140 };
141 metrics_service
142 .reconcile_startup_sessions(startup_sessions, &[])
143 .await
144 .map_err(|error| {
145 AppError::InternalError(anyhow::anyhow!(
146 "Failed to reconcile stale metrics state on startup: {error}"
147 ))
148 })?;
149
150 let agent_runners: Arc<RwLock<HashMap<String, AgentRunner>>> =
151 Arc::new(RwLock::new(HashMap::new()));
152 spawn_runner_cleanup_task(agent_runners.clone(), None);
153
154 let process_registry = Arc::new(ProcessRegistry::new());
155 let (provider_lock, provider_handle) = build_provider_handles(provider);
156
157 let config_snapshot = config.read().await;
159 let provider_registry = match bamboo_infrastructure::ProviderRegistry::from_config(
160 &config_snapshot,
161 bamboo_home_dir.clone(),
162 )
163 .await
164 {
165 Ok(registry) => Arc::new(registry),
166 Err(e) => {
167 tracing::error!("Failed to create provider registry: {}", e);
168 Arc::new(
169 bamboo_infrastructure::ProviderRegistry::from_config(
170 &Config::default(),
171 bamboo_home_dir.clone(),
172 )
173 .await
174 .expect("Cannot create even an empty provider registry"),
175 )
176 }
177 };
178 drop(config_snapshot);
179
180 let provider_router = Arc::new(bamboo_infrastructure::ProviderModelRouter::new(
181 provider_registry.clone(),
182 ));
183 let model_catalog = Arc::new(bamboo_infrastructure::ModelCatalogService::new(
184 provider_registry.clone(),
185 ));
186
187 let base_tools = build_base_tools(
188 config.clone(),
189 permission_checker,
190 mcp_manager.clone(),
191 skill_manager.clone(),
192 storage.clone(),
193 persistence.clone(),
194 sessions.clone(),
195 bamboo_home_dir.clone(),
196 );
197
198 let session_event_senders: Arc<RwLock<HashMap<String, broadcast::Sender<AgentEvent>>>> =
200 Arc::new(RwLock::new(HashMap::new()));
201
202 let subagent_profiles = crate::subagent_profiles::load_registry(&bamboo_home_dir, None)
210 .map_err(|e| {
211 crate::error::AppError::InternalError(anyhow::anyhow!(
212 "failed to load subagent profile registry: {e}"
213 ))
214 })?;
215
216 let child_tools: Arc<dyn bamboo_agent_core::tools::ToolExecutor> =
221 Arc::new(crate::tools::PolicyAwareToolExecutor::new(
222 base_tools.clone(),
223 subagent_profiles.clone(),
224 sessions.clone(),
225 ));
226
227 let agent = Arc::new(
232 bamboo_engine::Agent::builder()
233 .storage(storage.clone())
234 .persistence(persistence.clone())
235 .attachment_reader(session_store.clone())
236 .skill_manager(skill_manager.clone())
237 .metrics_collector(metrics_service.collector())
238 .config(config.clone())
239 .provider(provider_handle.clone())
240 .default_tools(base_tools.clone())
241 .build()
242 .expect("agent runtime should be fully configured"),
243 );
244
245 let child_completion_coordinator = Arc::new(
246 super::child_completion_coordinator::ChildCompletionCoordinator::new(
247 storage.clone(),
248 persistence.clone(),
249 sessions.clone(),
250 agent_runners.clone(),
251 session_event_senders.clone(),
252 agent.clone(),
253 config.clone(),
254 provider_registry.clone(),
255 provider_router.clone(),
256 data_dir.clone(),
257 ),
258 );
259
260 let config_snapshot = config.read().await.clone();
262 let external_runner =
263 crate::external_agents::runtime::build_external_child_runner(&config_snapshot);
264 let spawn_scheduler = build_spawn_scheduler(
265 agent.clone(),
266 child_tools,
267 sessions.clone(),
268 agent_runners.clone(),
269 session_event_senders.clone(),
270 external_runner,
271 Some(provider_router.clone()),
272 Some(child_completion_coordinator.clone()),
273 Some(data_dir.clone()),
274 );
275
276 let tools_with_task = base_tools.clone();
277
278 let schedule_store = init_schedule_store(&data_dir).await?;
279 let schedule_manager = build_schedule_manager(
280 schedule_store.clone(),
281 agent.clone(),
282 tools_with_task.clone(),
283 sessions.clone(),
284 agent_runners.clone(),
285 session_event_senders.clone(),
286 persistence.clone(),
287 config.clone(),
288 provider_registry.clone(),
289 Some(data_dir.clone()),
290 );
291
292 crate::services::auto_dream::spawn_auto_dream_task(
293 crate::services::auto_dream::AutoDreamContext {
294 session_store: session_store.clone(),
295 storage: storage.clone(),
296 provider: provider_handle.clone(),
297 config: config.clone(),
298 provider_registry: provider_registry.clone(),
299 },
300 );
301
302 let config_for_resolver = config.clone();
303 let subagent_model_resolver: OptionalSubagentModelResolver = {
304 let registry = provider_registry.clone();
305 Some(Arc::new(
306 move |subagent_type: String| -> futures::future::BoxFuture<
307 'static,
308 Option<bamboo_domain::ProviderModelRef>,
309 > {
310 let config_for_resolver = config_for_resolver.clone();
311 let registry = registry.clone();
312 Box::pin(async move {
313 let config_snap = config_for_resolver.read().await.clone();
314 crate::model_config_helper::resolve_subagent_model_ref(
315 &config_snap,
316 &config_snap.provider,
317 ®istry,
318 &subagent_type,
319 )
320 })
321 },
322 ))
323 };
324
325 let tools = build_root_tools(
326 tools_with_task.clone(),
327 schedule_store.clone(),
328 schedule_manager.clone(),
329 session_store.clone(),
330 storage.clone(),
331 persistence.clone(),
332 spawn_scheduler.clone(),
333 sessions.clone(),
334 agent_runners.clone(),
335 session_event_senders.clone(),
336 subagent_model_resolver,
337 config.clone(),
338 subagent_profiles.clone(),
339 );
340
341 child_completion_coordinator
342 .set_root_tools(tools.clone())
343 .await;
344
345 let tool_factory =
346 crate::tools::ToolSurfaceFactory::new(base_tools, tools_with_task, tools);
347
348 Ok(Self {
349 app_data_dir: bamboo_home_dir,
350 config,
351 provider: provider_lock,
352 provider_handle,
353 sessions,
354 storage,
355 session_store,
356 persistence,
357 spawn_scheduler,
358 child_completion_coordinator,
359 schedule_store,
360 schedule_manager,
361 tool_factory,
362 subagent_profiles,
363 cancel_tokens: Arc::new(RwLock::new(HashMap::new())),
364 skill_manager,
365 mcp_manager,
366 metrics_service,
367 agent_runners,
368 session_event_senders,
369 process_registry,
370 metrics_bus: None, agent,
372 provider_registry,
373 provider_router,
374 model_catalog,
375 title_gen_in_flight: Arc::new(dashmap::DashSet::new()),
376 })
377 }
378}