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 let configured_model = match config.provider.as_str() {
39 "copilot" => config
40 .providers
41 .copilot
42 .as_ref()
43 .and_then(|p| p.model.as_ref()),
44 "openai" => config
45 .providers
46 .openai
47 .as_ref()
48 .and_then(|p| p.model.as_ref()),
49 "anthropic" => config
50 .providers
51 .anthropic
52 .as_ref()
53 .and_then(|p| p.model.as_ref()),
54 "gemini" => config
55 .providers
56 .gemini
57 .as_ref()
58 .and_then(|p| p.model.as_ref()),
59 _ => None,
60 };
61
62 tracing::info!(
63 "Reloading provider: type={}, model={:?}",
64 config.provider,
65 configured_model
66 );
67
68 let new_provider =
69 bamboo_infrastructure::create_provider_with_dir(&config, self.app_data_dir.clone())
70 .await?;
71
72 let mut provider = self.provider.write().await;
73 *provider = new_provider;
74
75 tracing::info!("Provider reloaded successfully to: {}", config.provider);
76 Ok(())
77 }
78
79 pub async fn reload_config(&self) -> Config {
109 let new_config = Config::from_data_dir(Some(self.app_data_dir.clone()));
110 let mut config = self.config.write().await;
111 *config = new_config.clone();
112 new_config
113 }
114
115 pub async fn persist_config(&self) -> anyhow::Result<()> {
119 let config = self.config.read().await.clone();
120 let data_dir = self.app_data_dir.clone();
121 tokio::task::spawn_blocking(move || config.save_to_dir(data_dir))
122 .await
123 .map_err(|e| anyhow::anyhow!("Config save task failed: {e}"))??;
124 Ok(())
125 }
126
127 async fn persist_config_snapshot(&self, config: Config) -> anyhow::Result<()> {
128 let data_dir = self.app_data_dir.clone();
129 tokio::task::spawn_blocking(move || config.save_to_dir(data_dir))
130 .await
131 .map_err(|e| anyhow::anyhow!("Config save task failed: {e}"))??;
132 Ok(())
133 }
134
135 pub async fn update_config<F>(
142 &self,
143 update: F,
144 effects: ConfigUpdateEffects,
145 ) -> Result<Config, AppError>
146 where
147 F: FnOnce(&mut Config) -> Result<(), AppError>,
148 {
149 let snapshot = {
150 let mut cfg = self.config.write().await;
151 update(&mut cfg)?;
152 cfg.publish_env_vars();
153 cfg.clone()
154 };
155
156 self.persist_config_snapshot(snapshot.clone())
157 .await
158 .map_err(|e| AppError::InternalError(anyhow::anyhow!("Failed to save config: {e}")))?;
159
160 self.apply_config_effects(snapshot.clone(), effects).await?;
161 Ok(snapshot)
162 }
163
164 pub async fn replace_config(
166 &self,
167 new_config: Config,
168 effects: ConfigUpdateEffects,
169 ) -> Result<Config, AppError> {
170 {
171 let mut cfg = self.config.write().await;
172 *cfg = new_config.clone();
173 cfg.publish_env_vars();
174 }
175
176 self.persist_config_snapshot(new_config.clone())
177 .await
178 .map_err(|e| AppError::InternalError(anyhow::anyhow!("Failed to save config: {e}")))?;
179
180 self.apply_config_effects(new_config.clone(), effects)
181 .await?;
182 Ok(new_config)
183 }
184
185 async fn apply_config_effects(
186 &self,
187 new_config: Config,
188 effects: ConfigUpdateEffects,
189 ) -> Result<(), AppError> {
190 if effects.reload_provider {
191 self.reload_provider().await.map_err(|e| {
192 AppError::InternalError(anyhow::anyhow!(
193 "Failed to reload provider after updating config: {e}"
194 ))
195 })?;
196 }
197
198 if effects.reconcile_mcp {
199 self.mcp_manager
200 .reconcile_from_config(&new_config.mcp)
201 .await;
202 }
203
204 Ok(())
205 }
206}