From 9d680532a3dd3e4a67d18c81f5795225e432f1dd Mon Sep 17 00:00:00 2001 From: quifox <289420841+quifox@users.noreply.github.com> Date: Thu, 1 Oct 2026 19:40:41 +0800 Subject: [PATCH] fix(skills): remove unregistered script tool from default instructions --- .../google/adk/tools/skills/SkillToolset.java | 10 ++---- .../adk/tools/skills/SkillToolsetTest.java | 32 +++++++++++++++++++ 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/com/google/adk/tools/skills/SkillToolset.java b/core/src/main/java/com/google/adk/tools/skills/SkillToolset.java index d159bd39b..d34364c1c 100644 --- a/core/src/main/java/com/google/adk/tools/skills/SkillToolset.java +++ b/core/src/main/java/com/google/adk/tools/skills/SkillToolset.java @@ -35,10 +35,7 @@ import java.util.Map; import java.util.StringJoiner; -/** - * A toolset for managing and interacting with agent skills. Provides tools to list, load, and run - * skills. - */ +/** A toolset for listing skills and loading their instructions and resources. */ public class SkillToolset implements BaseToolset { private static final String DEFAULT_SKILL_SYSTEM_INSTRUCTION = @@ -49,21 +46,20 @@ public class SkillToolset implements BaseToolset { - **SKILL.md** (required): The main instruction file with skill metadata and detailed markdown instructions. - **references/** (Optional): Additional documentation or examples for skill usage. - **assets/** (Optional): Templates, scripts or other resources used by the skill. - - **scripts/** (Optional): Executable scripts that can be run via bash. + - **scripts/** (Optional): Scripts bundled with the skill. You cannot run them; use `load_skill_resource` to read one and follow it yourself. This is very important: 1. If a skill seems relevant to the current user query, you MUST use the `load_skill` tool with `skill_name=""` to read its full instructions before proceeding. 2. Once you have read the instructions, follow them exactly as documented before replying to the user. For example, If the instruction lists multiple steps, please make sure you complete all of them in order. 3. The `load_skill_resource` tool is for viewing files within a skill's directory (e.g., `references/*`, `assets/*`, `scripts/*`). Do NOT use other tools to access these files. - 4. Use `run_skill_script` to run scripts from a skill's `scripts/` directory. Use `load_skill_resource` to view script content first if needed. """; private final SkillSource skillSource; private final ImmutableList coreTools; private final String systemInstruction; - /** Initializes the SkillToolset with a SkillSource and default execution settings. */ + /** Initializes the SkillToolset with a SkillSource and default system instructions. */ public SkillToolset(SkillSource skillSource) { this(skillSource, DEFAULT_SKILL_SYSTEM_INSTRUCTION); } diff --git a/core/src/test/java/com/google/adk/tools/skills/SkillToolsetTest.java b/core/src/test/java/com/google/adk/tools/skills/SkillToolsetTest.java index 4be781469..334d95b7d 100644 --- a/core/src/test/java/com/google/adk/tools/skills/SkillToolsetTest.java +++ b/core/src/test/java/com/google/adk/tools/skills/SkillToolsetTest.java @@ -31,6 +31,7 @@ import com.google.common.truth.Correspondence; import io.reactivex.rxjava3.core.Flowable; import java.util.List; +import java.util.regex.Pattern; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -140,4 +141,35 @@ public void close() {} baseToolset.processLlmRequest(LlmRequest.builder(), mock(ToolContext.class)).blockingAwait(); } } + + @Test + public void processLlmRequest_defaultInstructionOnlyMentionsRegisteredTools() throws Exception { + SkillSource skillSource = + InMemorySkillSource.builder() + .skill("test-skill") + .frontmatter(Frontmatter.builder().name("test-skill").description("test skill").build()) + .instructions("Test instructions") + .build(); + try (SkillToolset toolSet = new SkillToolset(skillSource)) { + LlmRequest.Builder requestBuilder = LlmRequest.builder(); + toolSet.processLlmRequest(requestBuilder, mock(ToolContext.class)).blockingAwait(); + String instruction = requestBuilder.build().getSystemInstructions().get(0); + assertThat(instruction) + .contains( + "Scripts bundled with the skill. You cannot run them; use `load_skill_resource` to" + + " read one and follow it yourself."); + assertThat(instruction).doesNotContain("can be run via bash"); + List availableTools = + toolSet.getTools(null).toList().blockingGet().stream().map(BaseTool::name).toList(); + List mentionedTools = + Pattern.compile("`([a-z_]+)`") + .matcher(instruction) + .results() + .map(match -> match.group(1)) + .distinct() + .toList(); + assertThat(mentionedTools).isNotEmpty(); + assertThat(availableTools).containsAtLeastElementsIn(mentionedTools); + } + } }