bamboo_server/app_state/
config_runtime.rs1use super::*;
2
3impl AppState {
4 pub async fn reload_provider(&self) -> Result<(), bamboo_infrastructure::LLMError> {
36 let config = self.config.read().await.clone();
37
38 self.provider_registry
39 .reload_from_config(&config, self.app_data_dir.clone())
40 .await?;
41
42 let default_provider_name = self.provider_registry.default_provider_name();
43 tracing::info!(
44 default_provider = %default_provider_name,
45 legacy_provider = %config.provider,
46 has_provider_instances = config.has_provider_instances(),
47 "Reloading provider runtime from current config"
48 );
49
50 let new_provider = self.provider_registry.get_default().unwrap_or_else(|| {
51 let message = if config.has_provider_instances() {
52 format!(
53 "Default provider instance '{}' is not available or failed to initialize",
54 default_provider_name
55 )
56 } else {
57 format!(
58 "Provider '{}' is not available or failed to initialize",
59 config.provider
60 )
61 };
62 Arc::new(UnconfiguredProvider { message }) as Arc<dyn LLMProvider>
63 });
64
65 let mut provider = self.provider.write().await;
66 *provider = new_provider;
67
68 tracing::info!(
69 default_provider = %default_provider_name,
70 "Provider reloaded successfully"
71 );
72 Ok(())
73 }
74
75 pub async fn reload_config(&self) -> Config {
105 let new_config = Config::from_data_dir(Some(self.app_data_dir.clone()));
106 let mut config = self.config.write().await;
107 *config = new_config.clone();
108 new_config
109 }
110
111 pub async fn persist_config(&self) -> anyhow::Result<()> {
115 let config = self.config.read().await.clone();
116 let data_dir = self.app_data_dir.clone();
117 tokio::task::spawn_blocking(move || config.save_to_dir(data_dir))
118 .await
119 .map_err(|e| anyhow::anyhow!("Config save task failed: {e}"))??;
120 Ok(())
121 }
122
123 async fn persist_config_snapshot(&self, config: Config) -> anyhow::Result<()> {
124 let data_dir = self.app_data_dir.clone();
125 tokio::task::spawn_blocking(move || config.save_to_dir(data_dir))
126 .await
127 .map_err(|e| anyhow::anyhow!("Config save task failed: {e}"))??;
128 Ok(())
129 }
130
131 pub async fn update_config<F>(
138 &self,
139 update: F,
140 effects: ConfigUpdateEffects,
141 ) -> Result<Config, AppError>
142 where
143 F: FnOnce(&mut Config) -> Result<(), AppError>,
144 {
145 let snapshot = {
146 let mut cfg = self.config.write().await;
147 update(&mut cfg)?;
148 cfg.publish_env_vars();
149 cfg.clone()
150 };
151
152 self.persist_config_snapshot(snapshot.clone())
153 .await
154 .map_err(|e| AppError::InternalError(anyhow::anyhow!("Failed to save config: {e}")))?;
155
156 self.apply_config_effects(snapshot.clone(), effects).await?;
157 Ok(snapshot)
158 }
159
160 pub async fn replace_config(
162 &self,
163 new_config: Config,
164 effects: ConfigUpdateEffects,
165 ) -> Result<Config, AppError> {
166 {
167 let mut cfg = self.config.write().await;
168 *cfg = new_config.clone();
169 cfg.publish_env_vars();
170 }
171
172 self.persist_config_snapshot(new_config.clone())
173 .await
174 .map_err(|e| AppError::InternalError(anyhow::anyhow!("Failed to save config: {e}")))?;
175
176 self.apply_config_effects(new_config.clone(), effects)
177 .await?;
178 Ok(new_config)
179 }
180
181 async fn apply_config_effects(
182 &self,
183 new_config: Config,
184 effects: ConfigUpdateEffects,
185 ) -> Result<(), AppError> {
186 if effects.reload_provider {
187 self.reload_provider().await.map_err(|e| {
188 AppError::InternalError(anyhow::anyhow!(
189 "Failed to reload provider after updating config: {e}"
190 ))
191 })?;
192 }
193
194 if effects.reconcile_mcp {
195 self.mcp_manager
196 .reconcile_from_config(&new_config.mcp)
197 .await;
198 }
199
200 Ok(())
201 }
202}