From d4dbda1e891b9ec82086e2d94af2dcdc82ee736f Mon Sep 17 00:00:00 2001 From: Alex Clarke Date: Thu, 18 Jun 2026 13:01:38 -0600 Subject: [PATCH] fix: rebuild the tool scope after dynamically updating the skills_enabled value in the REPL --- src/config/request_context.rs | 39 +++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/config/request_context.rs b/src/config/request_context.rs index b85d569..93ab13a 100644 --- a/src/config/request_context.rs +++ b/src/config/request_context.rs @@ -1984,6 +1984,7 @@ impl RequestContext { } else { self.update_app_config(|app| app.skills_enabled = value.unwrap_or(true)); } + self.refresh_tool_scope(abort_signal.clone()).await?; } "enabled_mcp_servers" => { let raw: Option = super::parse_value(value)?; @@ -3794,6 +3795,44 @@ mod tests { ); } + #[test] + #[serial] + fn update_skills_enabled_false_removes_skill_meta_tools_from_scope() { + let _guard = TestConfigDirGuard::new(); + let app_state = app_state_with_mcp_config(false, &[]); + let mut ctx = RequestContext::new(app_state, WorkingMode::Repl); + let app = ctx.app.config.clone(); + let abort = utils::create_abort_signal(); + + run_async(ctx.rebuild_tool_scope(&app, None, abort.clone())).unwrap(); + + let names_before: Vec = ctx + .tool_scope + .functions + .declarations() + .iter() + .map(|f| f.name.clone()) + .collect(); + assert!( + names_before.iter().any(|n| n.starts_with("skill__")), + "expected skill__* functions before toggle, got: {names_before:?}" + ); + + run_async(ctx.update("skills_enabled false", abort)).unwrap(); + + let names_after: Vec = ctx + .tool_scope + .functions + .declarations() + .iter() + .map(|f| f.name.clone()) + .collect(); + assert!( + !names_after.iter().any(|n| n.starts_with("skill__")), + "expected skill__* functions to be removed after `.set skills_enabled false`, got: {names_after:?}" + ); + } + #[test] fn select_functions_returns_none_when_no_tools_enabled() { let ctx = create_test_ctx();