Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions core/src/main/java/com/google/adk/tools/skills/SkillToolset.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand All @@ -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="<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<BaseTool> 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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<String> availableTools =
toolSet.getTools(null).toList().blockingGet().stream().map(BaseTool::name).toList();
List<String> mentionedTools =
Pattern.compile("`([a-z_]+)`")
.matcher(instruction)
.results()
.map(match -> match.group(1))
.distinct()
.toList();
assertThat(mentionedTools).isNotEmpty();
assertThat(availableTools).containsAtLeastElementsIn(mentionedTools);
}
}
}
Loading