diff --git a/agentscope-core/src/main/java/io/agentscope/core/skill/SkillBox.java b/agentscope-core/src/main/java/io/agentscope/core/skill/SkillBox.java index 9eaabbb16..9d4ab4d53 100644 --- a/agentscope-core/src/main/java/io/agentscope/core/skill/SkillBox.java +++ b/agentscope-core/src/main/java/io/agentscope/core/skill/SkillBox.java @@ -290,6 +290,29 @@ public boolean exists(String skillId) { return skillRegistry.exists(skillId); } + /** + * Sets the logical activation state of a specific skill. + * + *

When a skill is set to inactive, it is marked for deactivation. However, + * its associated tool group will not be immediately disabled in the underlying + * toolkit. + * + *

Important: You must explicitly call {@link #syncToolGroupStates()} after + * modifying skill states to synchronize these changes with the bound toolkit. Only then + * will the agent be prevented from accessing the tools of inactive skills. + * + * @param skillId The ID of the skill to modify + * @param active true to mark the skill as active, false to mark as inactive + * @throws IllegalArgumentException if skillId is null + */ + public void setSkillActive(String skillId, boolean active) { + if (skillId == null) { + throw new IllegalArgumentException("Skill ID cannot be null"); + } + skillRegistry.setSkillActive(skillId, active); + logger.debug("Skill '{}' active state set to {}", skillId, active); + } + /** * Deactivates all skills. * diff --git a/agentscope-core/src/test/java/io/agentscope/core/skill/SkillBoxTest.java b/agentscope-core/src/test/java/io/agentscope/core/skill/SkillBoxTest.java index e3f5a13db..8286d882c 100644 --- a/agentscope-core/src/test/java/io/agentscope/core/skill/SkillBoxTest.java +++ b/agentscope-core/src/test/java/io/agentscope/core/skill/SkillBoxTest.java @@ -258,6 +258,52 @@ void testGetAllSkillIdsWithMultipleSkills() { assertTrue(skillIds.contains(skill2.getSkillId()), "Should contain second skill ID"); assertTrue(skillIds.contains(skill3.getSkillId()), "Should contain third skill ID"); } + + @Test + @DisplayName("Should update skill active state and require explicit sync") + void testSetSkillActiveRequiresExplicitSync() { + AgentSkill skill = + new AgentSkill("test_active_skill", "Test Active Skill", "# Content", null); + AgentTool testTool = createTestTool("active_test_tool"); + + skillBox.registration().skill(skill).agentTool(testTool).apply(); + + String toolsGroupName = skill.getSkillId() + "_skill_tools"; + + assertFalse( + skillBox.isSkillActive(skill.getSkillId()), + "Skill should be inactive initially"); + assertNotNull(toolkit.getToolGroup(toolsGroupName), "ToolGroup should be created"); + assertFalse( + toolkit.getToolGroup(toolsGroupName).isActive(), + "ToolGroup should be inactive initially"); + + skillBox.setSkillActive(skill.getSkillId(), true); + skillBox.syncToolGroupStates(); + assertTrue( + skillBox.isSkillActive(skill.getSkillId()), + "Skill logical state should be active now"); + assertTrue( + toolkit.getToolGroup(toolsGroupName).isActive(), + "ToolGroup should be active after sync"); + + skillBox.setSkillActive(skill.getSkillId(), false); + + // The physical state (Toolkit) has not changed yet (the framework will not + // automatically synchronize for you) + assertFalse( + skillBox.isSkillActive(skill.getSkillId()), + "Skill logical state should be inactive"); + assertTrue( + toolkit.getToolGroup(toolsGroupName).isActive(), + "ToolGroup should STILL be active before explicit sync"); + + skillBox.syncToolGroupStates(); + + assertFalse( + toolkit.getToolGroup(toolsGroupName).isActive(), + "ToolGroup should be inactive after sync"); + } } @Nested