@@ -24,20 +24,20 @@ use crate::API;
2424pub struct ForgeAPI < S , F > {
2525 services : Arc < S > ,
2626 infra : Arc < F > ,
27- config : forge_config:: ForgeConfig ,
2827}
2928
3029impl < A , F > ForgeAPI < A , F > {
31- pub fn new ( services : Arc < A > , infra : Arc < F > , config : forge_config :: ForgeConfig ) -> Self {
32- Self { services, infra, config }
30+ pub fn new ( services : Arc < A > , infra : Arc < F > ) -> Self {
31+ Self { services, infra }
3332 }
3433
35- /// Creates a ForgeApp instance with the current services
34+ /// Creates a ForgeApp instance with the current services and latest config.
3635 fn app ( & self ) -> ForgeApp < A >
3736 where
38- A : Services ,
37+ A : Services + EnvironmentInfra < Config = forge_config:: ForgeConfig > ,
38+ F : EnvironmentInfra < Config = forge_config:: ForgeConfig > ,
3939 {
40- ForgeApp :: new ( self . services . clone ( ) , self . config . clone ( ) )
40+ ForgeApp :: new ( self . services . clone ( ) )
4141 }
4242}
4343
@@ -49,10 +49,10 @@ impl ForgeAPI<ForgeServices<ForgeRepo<ForgeInfra>>, ForgeRepo<ForgeInfra>> {
4949 /// * `config` - Pre-read application configuration (from startup)
5050 /// * `services_url` - Pre-validated URL for the gRPC workspace server
5151 pub fn init ( cwd : PathBuf , config : ForgeConfig , services_url : Url ) -> Self {
52- let infra = Arc :: new ( ForgeInfra :: new ( cwd, config. clone ( ) , services_url) ) ;
53- let repo = Arc :: new ( ForgeRepo :: new ( infra. clone ( ) , config . clone ( ) ) ) ;
54- let app = Arc :: new ( ForgeServices :: new ( repo. clone ( ) , config . clone ( ) ) ) ;
55- ForgeAPI :: new ( app, repo, config )
52+ let infra = Arc :: new ( ForgeInfra :: new ( cwd, config, services_url) ) ;
53+ let repo = Arc :: new ( ForgeRepo :: new ( infra. clone ( ) ) ) ;
54+ let app = Arc :: new ( ForgeServices :: new ( repo. clone ( ) ) ) ;
55+ ForgeAPI :: new ( app, repo)
5656 }
5757
5858 pub async fn get_skills_internal ( & self ) -> Result < Vec < Skill > > {
@@ -62,8 +62,13 @@ impl ForgeAPI<ForgeServices<ForgeRepo<ForgeInfra>>, ForgeRepo<ForgeInfra>> {
6262}
6363
6464#[ async_trait:: async_trait]
65- impl < A : Services , F : CommandInfra + EnvironmentInfra + SkillRepository + GrpcInfra > API
66- for ForgeAPI < A , F >
65+ impl <
66+ A : Services + EnvironmentInfra < Config = forge_config:: ForgeConfig > ,
67+ F : CommandInfra
68+ + EnvironmentInfra < Config = forge_config:: ForgeConfig >
69+ + SkillRepository
70+ + GrpcInfra ,
71+ > API for ForgeAPI < A , F >
6772{
6873 async fn discover ( & self ) -> Result < Vec < File > > {
6974 let environment = self . services . get_environment ( ) ;
@@ -98,7 +103,7 @@ impl<A: Services, F: CommandInfra + EnvironmentInfra + SkillRepository + GrpcInf
98103 diff : Option < String > ,
99104 additional_context : Option < String > ,
100105 ) -> Result < forge_app:: CommitResult > {
101- let git_app = GitApp :: new ( self . services . clone ( ) , self . config . clone ( ) ) ;
106+ let git_app = GitApp :: new ( self . services . clone ( ) ) ;
102107 let result = git_app
103108 . commit_message ( max_diff_size, diff, additional_context)
104109 . await ?;
@@ -225,13 +230,31 @@ impl<A: Services, F: CommandInfra + EnvironmentInfra + SkillRepository + GrpcInf
225230 agent_provider_resolver. get_provider ( Some ( agent_id) ) . await
226231 }
227232
228- async fn set_default_provider ( & self , provider_id : ProviderId ) -> anyhow:: Result < ( ) > {
229- let result = self . services . set_default_provider ( provider_id) . await ;
230- // Invalidate cache for agents
231- let _ = self . services . reload_agents ( ) . await ;
233+ async fn update_config ( & self , ops : Vec < forge_domain:: ConfigOperation > ) -> anyhow:: Result < ( ) > {
234+ // Determine whether any op affects provider/model resolution before writing,
235+ // so we can invalidate the agent cache afterwards.
236+ let needs_agent_reload = ops
237+ . iter ( )
238+ . any ( |op| matches ! ( op, forge_domain:: ConfigOperation :: SetSessionConfig ( _) ) ) ;
239+ let result = self . services . update_config ( ops) . await ;
240+ if needs_agent_reload {
241+ let _ = self . services . reload_agents ( ) . await ;
242+ }
232243 result
233244 }
234245
246+ async fn get_commit_config ( & self ) -> anyhow:: Result < Option < ModelConfig > > {
247+ self . services . get_commit_config ( ) . await
248+ }
249+
250+ async fn get_suggest_config ( & self ) -> anyhow:: Result < Option < ModelConfig > > {
251+ self . services . get_suggest_config ( ) . await
252+ }
253+
254+ async fn get_reasoning_effort ( & self ) -> anyhow:: Result < Option < Effort > > {
255+ self . services . get_reasoning_effort ( ) . await
256+ }
257+
235258 async fn user_info ( & self ) -> Result < Option < User > > {
236259 let provider = self . get_default_provider ( ) . await ?;
237260 if let Some ( api_key) = provider. api_key ( ) {
@@ -273,50 +296,6 @@ impl<A: Services, F: CommandInfra + EnvironmentInfra + SkillRepository + GrpcInf
273296 async fn get_default_model ( & self ) -> Option < ModelId > {
274297 self . services . get_provider_model ( None ) . await . ok ( )
275298 }
276- async fn set_default_model ( & self , model_id : ModelId ) -> anyhow:: Result < ( ) > {
277- let result = self . services . set_default_model ( model_id) . await ;
278- // Invalidate cache for agents
279- let _ = self . services . reload_agents ( ) . await ;
280-
281- result
282- }
283-
284- async fn set_default_provider_and_model (
285- & self ,
286- provider_id : ProviderId ,
287- model : ModelId ,
288- ) -> anyhow:: Result < ( ) > {
289- let result = self
290- . services
291- . set_default_provider_and_model ( provider_id, model)
292- . await ;
293- let _ = self . services . reload_agents ( ) . await ;
294- result
295- }
296-
297- async fn get_commit_config ( & self ) -> anyhow:: Result < Option < CommitConfig > > {
298- self . services . get_commit_config ( ) . await
299- }
300-
301- async fn set_commit_config ( & self , config : CommitConfig ) -> anyhow:: Result < ( ) > {
302- self . services . set_commit_config ( config) . await
303- }
304-
305- async fn get_suggest_config ( & self ) -> anyhow:: Result < Option < SuggestConfig > > {
306- self . services . get_suggest_config ( ) . await
307- }
308-
309- async fn set_suggest_config ( & self , config : SuggestConfig ) -> anyhow:: Result < ( ) > {
310- self . services . set_suggest_config ( config) . await
311- }
312-
313- async fn get_reasoning_effort ( & self ) -> anyhow:: Result < Option < Effort > > {
314- self . services . get_reasoning_effort ( ) . await
315- }
316-
317- async fn set_reasoning_effort ( & self , effort : Effort ) -> anyhow:: Result < ( ) > {
318- self . services . set_reasoning_effort ( effort) . await
319- }
320299
321300 async fn reload_mcp ( & self ) -> Result < ( ) > {
322301 self . services . mcp_service ( ) . reload_mcp ( ) . await
0 commit comments