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
24 changes: 24 additions & 0 deletions contributing/samples/local_environment_skill/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Local Environment Skill Sample

This sample demonstrates how to use the `LocalEnvironment` with the `EnvironmentToolset` to allow an agent to manually discover and load skills from the environment, rather than using the pre-configured `SkillToolset`.

## Description

The agent is configured with the `EnvironmentToolset` and is initialized with a `LocalEnvironment` pointing to the agent's directory.
Instead of having skills pre-loaded, the agent uses system instructions that guide it to search for skills in the `skills/` folder and load them by reading their `SKILL.md` files using the `ReadFile` tool.

This demonstrates a "manual skill loading" pattern where the agent can acquire new capabilities dynamically by reading instructions from the environment.

## Sample Usage

You can interact with the agent by providing prompts that require a specific skill (like weather).

### Example Prompt

> "Can you check the weather in Sunnyvale?"

### Expected Behavior

1. **Find Skill**: The agent uses the `Execute` tool to search for all available skills by running `find skills -name SKILL.md`.
2. **Load Skill**: The agent identifies the relevant skill and uses the `ReadFile` tool to read its `SKILL.md` file.
3. **Execute Skill**: The agent follows the instructions in the skill file (e.g., reading references or running scripts) to answer the user's request.
15 changes: 15 additions & 0 deletions contributing/samples/local_environment_skill/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from . import agent
95 changes: 95 additions & 0 deletions contributing/samples/local_environment_skill/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import pathlib

from google.adk import Agent
from google.adk.environment import LocalEnvironment
from google.adk.tools.base_tool import BaseTool
from google.adk.tools.environment import EnvironmentToolset
from google.genai import types


class GetTimezoneTool(BaseTool):
"""A tool to get the timezone for a given location."""

def __init__(self):
super().__init__(
name="get_timezone",
description="Returns the timezone for a given location.",
)

def _get_declaration(self) -> types.FunctionDeclaration | None:
return types.FunctionDeclaration(
name=self.name,
description=self.description,
parameters_json_schema={
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The location to get the timezone for.",
},
},
"required": ["location"],
},
)

async def run_async(self, *, args: dict, tool_context) -> str:
return f"The timezone for {args['location']} is UTC+00:00."


def get_wind_speed(location: str) -> str:
"""Returns the current wind speed for a given location."""
return f"The wind speed in {location} is 10 mph."


BASE_INSTRUCTION = (
"You are a helpful AI assistant that can use the local environment to"
" execute commands and file I/O."
)

SKILL_USAGE_INSTRUCTION = """\
[SKILLS ACCESS]
You have access to specialized skills stored in the environment's `skills/` folder.
Each skill is a folder containing a `SKILL.md` file with instructions.

[MANDATORY PROCEDURE]
Before declaring that you cannot perform a task or answer a question (especially for domain-specific queries like weather), you MUST:
1. Use the `Execute` tool to search for all available skills by running: `find skills -name SKILL.md`
2. Review the list of found skills to see if any are relevant to the user's request.
3. If a relevant skill is found, use the `ReadFile` tool to read its `SKILL.md` file.
4. Follow the instructions in that file to complete the request.
*CRITICAL NOTE ON PATHS:* All file and script paths mentioned inside a `SKILL.md` file (e.g., `references/...` or `scripts/...`) are RELATIVE to that specific skill's folder. You MUST resolve them by prepending the skill's folder path (e.g., if the skill is at `skills/weather-skill/`, you must read `skills/weather-skill/references/weather_info.md`).

Failure to check the `skills/` directory before stating you cannot help is unacceptable.\
"""


root_agent = Agent(
model="gemini-2.5-pro",
name="local_environment_skill_agent",
description=(
"An agent that uses local environment tools to load and use skills."
),
instruction=f"{BASE_INSTRUCTION}\n\n{SKILL_USAGE_INSTRUCTION}",
tools=[
EnvironmentToolset(
environment=LocalEnvironment(
working_dir=pathlib.Path(__file__).parent
),
),
GetTimezoneTool(),
get_wind_speed,
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
name: weather-skill
description: A skill that provides weather information based on reference data.
metadata:
adk_additional_tools:
- get_wind_speed
---

Step 1: Check 'references/weather_info.md' for the current weather.
Step 2: If humidity is requested, use run 'scripts/get_humidity.py' with the `location` argument.
Step 3: If wind speed is requested, use the `get_wind_speed` tool.
Step 4: Provide the update to the user.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Weather Information

- **Location:** San Francisco, CA
- **Condition:** Sunny ☀️
- **Temperature:** 72°F (22°C)
- **Forecast:** Clear skies all day.

- **Location:** Sunnyvale, CA
- **Condition:** Sunny ☀️
- **Temperature:** 75°F (24°C)
- **Forecast:** Warm and sunny.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import argparse


def get_humidity(location: str) -> str:
"""Fetch live humidity for a given location. (Simulated)"""
print(f"Fetching live humidity for {location}...")
return "45% (Simulated)"


if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--location", type=str, default="Mountain View")
args = parser.parse_args()

print(get_humidity(args.location))
Loading