chore: import upstream snapshot with attribution
Continuous Integration / Pre-commit Linter (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.10) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.11) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.12) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.13) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.10) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.11) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.12) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.13) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.14) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.10) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.11) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.12) (push) Has been cancelled
Copybara PR Handler / close-imported-pr (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.13) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.14) (push) Has been cancelled
Continuous Integration / Pre-commit Linter (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.10) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.11) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.12) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.13) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.10) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.11) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.12) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.13) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.14) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.10) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.11) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.12) (push) Has been cancelled
Copybara PR Handler / close-imported-pr (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.13) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.14) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
# Daytona Environment Sample
|
||||
|
||||
## Overview
|
||||
|
||||
A small data analysis agent that uses the `DaytonaEnvironment` with the
|
||||
`EnvironmentToolset` to download public datasets and analyze them inside a
|
||||
[Daytona](https://daytona.io) remote sandbox.
|
||||
|
||||
Instead of running on the local machine, all commands and file operations
|
||||
execute in an isolated remote sandbox with internet access. Asked a question,
|
||||
the agent downloads a public dataset (a GCS-hosted world population /
|
||||
demographics dataset by default), installs `pandas` on demand, writes a short
|
||||
analysis script, runs it, and reports the result — all without touching the
|
||||
user's machine. This makes the sandbox a natural fit for running
|
||||
model-generated code safely and keeping the host clean.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. Install the `daytona` extra:
|
||||
|
||||
```bash
|
||||
pip install google-adk[daytona]
|
||||
```
|
||||
|
||||
1. Set your Daytona configuration. Get a server and API key by following the
|
||||
Daytona installation guide (e.g. self-hosted or via Daytona Cloud).
|
||||
|
||||
If you are using Daytona Cloud, you only need to set:
|
||||
|
||||
```bash
|
||||
export DAYTONA_API_KEY="your-api-key"
|
||||
```
|
||||
|
||||
If you are using a self-hosted Daytona server, also set:
|
||||
|
||||
```bash
|
||||
export DAYTONA_API_URL="your-api-url"
|
||||
```
|
||||
|
||||
## Sample Inputs
|
||||
|
||||
- `Download the world demographics dataset and tell me which country has the largest population.`
|
||||
|
||||
The agent downloads the dataset, installs `pandas`, filters to country-level
|
||||
rows, and finds the maximum. Expected: China (`CN`), ≈ 1.44 billion, just
|
||||
ahead of India (`IN`) at ≈ 1.38 billion.
|
||||
|
||||
- `For the United States, what is the urban vs rural population split?`
|
||||
|
||||
A follow-up to the previous turn. Because the sandbox persists across the
|
||||
session, the agent reuses the already-downloaded CSV and the installed
|
||||
`pandas` — it only writes and runs a new script. Expected for `US`: urban
|
||||
≈ 270.7 million vs rural ≈ 57.6 million (out of ≈ 331 million total).
|
||||
|
||||
- `Using https://storage.googleapis.com/cloud-samples-data/bigquery/us-states/us-states.csv, how many US states are listed?`
|
||||
|
||||
Demonstrates pointing the agent at your own dataset URL instead of the
|
||||
default.
|
||||
|
||||
## Graph
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
User -->|question| Agent[data_analysis_agent]
|
||||
Agent -->|EnvironmentToolset| Sandbox[DaytonaEnvironment sandbox]
|
||||
Sandbox -->|download / install / run| Agent
|
||||
Agent -->|answer| User
|
||||
```
|
||||
|
||||
## How To
|
||||
|
||||
The agent is a standalone `Agent` (no workflow graph) wired to a single
|
||||
`EnvironmentToolset` whose `environment` is a `DaytonaEnvironment`:
|
||||
|
||||
```python
|
||||
from google.adk.integrations.daytona import DaytonaEnvironment
|
||||
from google.adk.tools.environment import EnvironmentToolset
|
||||
|
||||
EnvironmentToolset(
|
||||
environment=DaytonaEnvironment(timeout=300),
|
||||
)
|
||||
```
|
||||
|
||||
- `timeout` bounds the sandbox lifetime in seconds.
|
||||
- By default, it will spin up a sandbox from the built-in default Python snapshot.
|
||||
If you want to use a custom Docker image instead, you can pass it to the
|
||||
`image` parameter (e.g. `image="python:3.12"`).
|
||||
@@ -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
|
||||
@@ -0,0 +1,43 @@
|
||||
# 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.
|
||||
|
||||
"""A data analysis agent that runs Python in a Daytona remote sandbox."""
|
||||
|
||||
from google.adk import Agent
|
||||
from google.adk.integrations.daytona import DaytonaEnvironment
|
||||
from google.adk.tools.environment import EnvironmentToolset
|
||||
|
||||
root_agent = Agent(
|
||||
name="data_analysis_agent",
|
||||
description=(
|
||||
"A data analysis agent that downloads public datasets and analyzes"
|
||||
" them inside a Daytona remote sandbox."
|
||||
),
|
||||
instruction="""\
|
||||
You are a data analysis assistant. You work inside an isolated Daytona remote
|
||||
sandbox that has internet access, where you can safely download data and run
|
||||
Python, so you never touch the user's machine.
|
||||
|
||||
To analyze a dataset:
|
||||
1. Download it from the internet into the working directory, e.g. with
|
||||
`curl -O <url>` or `wget <url>`.
|
||||
2. Install whatever you need on demand, e.g. `pip install pandas`.
|
||||
3. Write a short Python script that loads the data and computes the answer.
|
||||
4. Run the script and report the result, showing the numbers you found.
|
||||
|
||||
Prefer writing a script and executing it over guessing. If a command fails,
|
||||
read the error, fix the script, and try again.
|
||||
""",
|
||||
tools=[EnvironmentToolset(environment=DaytonaEnvironment())],
|
||||
)
|
||||
@@ -0,0 +1,90 @@
|
||||
# E2B Environment Sample
|
||||
|
||||
## Overview
|
||||
|
||||
A small data analysis agent that uses the `E2BEnvironment` with the
|
||||
`EnvironmentToolset` to download public datasets and analyze them inside an
|
||||
[E2B](https://e2b.dev) remote sandbox.
|
||||
|
||||
Instead of running on the local machine, all commands and file operations
|
||||
execute in an isolated remote sandbox with internet access. Asked a question,
|
||||
the agent downloads a public dataset (a GCS-hosted world population /
|
||||
demographics dataset by default), installs `pandas` on demand, writes a short
|
||||
analysis script, runs it, and reports the result — all without touching the
|
||||
user's machine. This makes the sandbox a natural fit for running
|
||||
model-generated code safely and keeping the host clean.
|
||||
|
||||
The sandbox has a bounded time-to-live (`timeout`, in seconds) to cap credit
|
||||
usage. The TTL is reset on every operation, so an actively used workspace never
|
||||
expires mid-task; after genuine idle it expires and is transparently recreated
|
||||
on the next operation (note: workspace state such as installed packages and
|
||||
files is lost on recreation).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. Install the `e2b` extra:
|
||||
|
||||
```bash
|
||||
pip install google-adk[e2b]
|
||||
```
|
||||
|
||||
1. Set your E2B API key (get one at https://e2b.dev):
|
||||
|
||||
```bash
|
||||
export E2B_API_KEY="your-api-key"
|
||||
```
|
||||
|
||||
## Sample Inputs
|
||||
|
||||
- `Download the world demographics dataset and tell me which country has the largest population.`
|
||||
|
||||
The agent downloads the dataset, installs `pandas`, filters to country-level
|
||||
rows, and finds the maximum. Expected: China (`CN`), ≈ 1.44 billion, just
|
||||
ahead of India (`IN`) at ≈ 1.38 billion.
|
||||
|
||||
- `For the United States, what is the urban vs rural population split?`
|
||||
|
||||
A follow-up to the previous turn. Because the sandbox persists across the
|
||||
session, the agent reuses the already-downloaded CSV and the installed
|
||||
`pandas` — it only writes and runs a new script. Expected for `US`: urban
|
||||
≈ 270.7 million vs rural ≈ 57.6 million (out of ≈ 331 million total).
|
||||
|
||||
- `Using https://storage.googleapis.com/cloud-samples-data/bigquery/us-states/us-states.csv, how many US states are listed?`
|
||||
|
||||
Demonstrates pointing the agent at your own dataset URL instead of the
|
||||
default.
|
||||
|
||||
## Graph
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
User -->|question| Agent[data_analysis_agent]
|
||||
Agent -->|EnvironmentToolset| Sandbox[E2BEnvironment sandbox]
|
||||
Sandbox -->|download / install / run| Agent
|
||||
Agent -->|answer| User
|
||||
```
|
||||
|
||||
## How To
|
||||
|
||||
The agent is a standalone `Agent` (no workflow graph) wired to a single
|
||||
`EnvironmentToolset` whose `environment` is an `E2BEnvironment`:
|
||||
|
||||
```python
|
||||
from google.adk.integrations.e2b import E2BEnvironment
|
||||
from google.adk.tools.environment import EnvironmentToolset
|
||||
|
||||
EnvironmentToolset(
|
||||
environment=E2BEnvironment(image="base", timeout=300),
|
||||
)
|
||||
```
|
||||
|
||||
- `image` selects the E2B template (defaults to the public `base` template).
|
||||
- `timeout` bounds the sandbox lifetime in seconds to cap credit usage; it is
|
||||
reset on every operation.
|
||||
|
||||
The default GCS-hosted demographics CSV is a standard CSV with a header row.
|
||||
Each row is one location identified by `location_key`: country-level rows use a
|
||||
two-letter ISO code (e.g. `US`, `CN`), while subregions use keys containing an
|
||||
underscore (e.g. `US_CA`). The agent's instruction documents this schema — in
|
||||
particular, to filter out underscore keys when a question is about countries —
|
||||
so the generated analysis script parses and aggregates the file correctly.
|
||||
@@ -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
|
||||
@@ -0,0 +1,52 @@
|
||||
# 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.
|
||||
|
||||
"""A data analysis agent that runs Python in an E2B remote sandbox."""
|
||||
|
||||
from google.adk import Agent
|
||||
from google.adk.integrations.e2b import E2BEnvironment
|
||||
from google.adk.tools.environment import EnvironmentToolset
|
||||
|
||||
root_agent = Agent(
|
||||
name="data_analysis_agent",
|
||||
description=(
|
||||
"A data analysis agent that downloads public datasets and analyzes"
|
||||
" them inside an E2B remote sandbox."
|
||||
),
|
||||
instruction="""\
|
||||
You are a data analysis assistant. You work inside an isolated E2B remote
|
||||
sandbox that has internet access, where you can safely download data and run
|
||||
Python, so you never touch the user's machine.
|
||||
|
||||
To analyze a dataset:
|
||||
1. Download it from the internet into the working directory, e.g. with
|
||||
`curl -O <url>` or `wget <url>`. If the user does not give a URL, use the
|
||||
public world demographics dataset hosted on Google Cloud Storage at
|
||||
https://storage.googleapis.com/covid19-open-data/v3/demographics.csv
|
||||
2. Install whatever you need on demand, e.g. `pip install pandas`.
|
||||
3. Write a short Python script that loads the data and computes the answer.
|
||||
4. Run the script and report the result, showing the numbers you found.
|
||||
|
||||
Notes on the demographics CSV above: it is a proper CSV with a header row.
|
||||
Each row is one location, identified by `location_key`. Country-level rows use
|
||||
a two-letter ISO code (e.g. `US`, `CN`, `IN`); subregions use keys containing
|
||||
an underscore (e.g. `US_CA`), so filter those out when you want countries only.
|
||||
Useful columns include `population`, `population_male`, `population_female`,
|
||||
`population_urban`, `population_rural`, and `population_density`.
|
||||
|
||||
Prefer writing a script and executing it over guessing. If a command fails,
|
||||
read the error, fix the script, and try again.
|
||||
""",
|
||||
tools=[EnvironmentToolset(environment=E2BEnvironment())],
|
||||
)
|
||||
@@ -0,0 +1,21 @@
|
||||
# Local Environment Sample
|
||||
|
||||
This sample demonstrates how to use the `LocalEnvironment` with the `EnvironmentToolset` to allow an agent to interact with the local filesystem and execute commands.
|
||||
|
||||
## Description
|
||||
|
||||
The agent is configured with the `EnvironmentToolset`, which provides tools for file I/O (reading, writing) and command execution within a local environment. This allows the agent to perform tasks that involve creating files, modifying them, and running local scripts or commands.
|
||||
|
||||
## Sample Usage
|
||||
|
||||
You can interact with the agent by providing prompts that require file operations and command execution.
|
||||
|
||||
### Example Prompt
|
||||
|
||||
> "Write a Python file named `hello.py` to the working directory that prints 'Hello from ADK!'. Then read the file to verify its contents, and finally execute it using a command."
|
||||
|
||||
### Expected Behavior
|
||||
|
||||
1. **Write File**: The agent uses a tool to write `hello.py` with the content `print("Hello from ADK!")`.
|
||||
1. **Read File**: The agent uses a tool to read `hello.py` and verify the content.
|
||||
1. **Execute Command**: The agent uses a tool to run `python3 hello.py` and returns the output.
|
||||
@@ -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
|
||||
@@ -0,0 +1,34 @@
|
||||
# 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 google.adk import Agent
|
||||
from google.adk.environment import LocalEnvironment
|
||||
from google.adk.tools.environment import EnvironmentToolset
|
||||
|
||||
root_agent = Agent(
|
||||
model="gemini-2.5-pro",
|
||||
name="local_environment_agent",
|
||||
description="A simple agent that demonstrates local environment usage.",
|
||||
instruction="""
|
||||
You are a helpful AI assistant that can use the local environment to
|
||||
execute commands and file I/O. Follow the rules of the environment and the
|
||||
user's instructions.
|
||||
""",
|
||||
tools=[
|
||||
EnvironmentToolset(
|
||||
environment=LocalEnvironment(),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -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`.
|
||||
1. **Load Skill**: The agent identifies the relevant skill and uses the `ReadFile` tool to read its `SKILL.md` file.
|
||||
1. **Execute Skill**: The agent follows the instructions in the skill file (e.g., reading references or running scripts) to answer the user's request.
|
||||
@@ -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
|
||||
@@ -0,0 +1,63 @@
|
||||
# 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.environment import EnvironmentToolset
|
||||
|
||||
|
||||
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
|
||||
),
|
||||
),
|
||||
get_wind_speed,
|
||||
],
|
||||
)
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
______________________________________________________________________
|
||||
|
||||
## name: weather-skill description: A skill that provides weather information based on reference data.
|
||||
|
||||
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.
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
# 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.
|
||||
+29
@@ -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))
|
||||
@@ -0,0 +1,115 @@
|
||||
# ADK Skills Agent Sample
|
||||
|
||||
## Overview
|
||||
|
||||
This sample demonstrates how to use **Skills** and the **SkillToolset** in ADK.
|
||||
|
||||
Skills are specialized folders of instructions, reference materials, assets, and scripts that extend an agent's capabilities. The agent can dynamically search for, load, and run resources/scripts from these skills depending on the user's query.
|
||||
|
||||
This sample showcases:
|
||||
|
||||
1. **Programmatic Skills**: Creating a skill directly within Python (`support-hours-skill`).
|
||||
1. **Directory-based Skills**: Loading a skill from a directory structure (`weather-skill`).
|
||||
1. **Skill Metadata & Additional Tools**: Declaring that a skill requires specific tools, making them dynamically active only when that skill is loaded.
|
||||
1. **Script Execution**: Executing a Python script inside a skill using a code executor.
|
||||
|
||||
## Sample Inputs
|
||||
|
||||
- `What are the support hours for Tokyo?`
|
||||
|
||||
*Triggers the support-hours-skill which checks get_timezone and reads support_policy.txt*
|
||||
|
||||
- `What is the current weather in SF?`
|
||||
|
||||
*Loads weather-skill and reads weather_info.md reference file*
|
||||
|
||||
- `Can you fetch the current humidity for Mountain View?`
|
||||
|
||||
*Executes scripts/get_humidity.py via run_skill_script*
|
||||
|
||||
- `What is the wind speed in Seattle?`
|
||||
|
||||
*Loads weather-skill which dynamically activates and calls get_wind_speed*
|
||||
|
||||
## Graph
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
Agent[Agent: skills_agent] --> Toolset[SkillToolset]
|
||||
Toolset --> Skill1[support-hours-skill]
|
||||
Toolset --> Skill2[weather-skill]
|
||||
|
||||
Skill1 --> Resource1["Resource: support_policy.txt"]
|
||||
Skill1 --> Tool1["Dynamic Tool: get_timezone"]
|
||||
|
||||
Skill2 --> Resource2["Resource: weather_info.md"]
|
||||
Skill2 --> Script1["Script: get_humidity.py"]
|
||||
Skill2 --> Tool2["Dynamic Tool: get_wind_speed"]
|
||||
```
|
||||
|
||||
## How To
|
||||
|
||||
### 1. Declaring a Skill Programmatically
|
||||
|
||||
You can declare a skill in Python code using `models.Skill`:
|
||||
|
||||
```python
|
||||
from google.adk.skills import models
|
||||
|
||||
support_hours_skill = models.Skill(
|
||||
frontmatter=models.Frontmatter(
|
||||
name="support-hours-skill",
|
||||
description="A skill to check customer support hours...",
|
||||
metadata={"adk_additional_tools": ["get_timezone"]},
|
||||
),
|
||||
instructions="Step 1: Look up the timezone... Step 2: Read 'references/support_policy.txt'...",
|
||||
resources=models.Resources(
|
||||
references={
|
||||
"support_policy.txt": "Customer support is available Monday through Friday...",
|
||||
},
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
### 2. Loading a Skill from a Directory
|
||||
|
||||
Skills can be organized as folders. Each folder must contain a `SKILL.md` file. The folder structure typically looks like:
|
||||
|
||||
```
|
||||
weather-skill/
|
||||
├── SKILL.md
|
||||
├── references/
|
||||
│ └── weather_info.md
|
||||
└── scripts/
|
||||
└── get_humidity.py
|
||||
```
|
||||
|
||||
To load a skill from a directory:
|
||||
|
||||
```python
|
||||
from google.adk.skills import load_skill_from_dir
|
||||
|
||||
weather_skill = load_skill_from_dir(
|
||||
pathlib.Path(__file__).parent / "skills" / "weather-skill"
|
||||
)
|
||||
```
|
||||
|
||||
### 3. Registering a SkillToolset
|
||||
|
||||
Use `SkillToolset` to bundle all your skills and any dynamic tools. Then pass this toolset to your agent's `tools` list:
|
||||
|
||||
```python
|
||||
from google.adk.tools.skill_toolset import SkillToolset
|
||||
from google.adk.code_executors.unsafe_local_code_executor import UnsafeLocalCodeExecutor
|
||||
|
||||
my_skill_toolset = SkillToolset(
|
||||
skills=[support_hours_skill, weather_skill],
|
||||
additional_tools=[GetTimezoneTool(), get_wind_speed],
|
||||
code_executor=UnsafeLocalCodeExecutor(),
|
||||
)
|
||||
|
||||
root_agent = Agent(
|
||||
name="skills_agent",
|
||||
tools=[my_skill_toolset],
|
||||
)
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# 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 __future__ import annotations
|
||||
|
||||
from . import agent
|
||||
@@ -0,0 +1,108 @@
|
||||
# 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 __future__ import annotations
|
||||
|
||||
import pathlib
|
||||
|
||||
from google.adk.agents import Agent
|
||||
from google.adk.code_executors.unsafe_local_code_executor import UnsafeLocalCodeExecutor
|
||||
from google.adk.skills import load_skill_from_dir
|
||||
from google.adk.skills import models
|
||||
from google.adk.tools.base_tool import BaseTool
|
||||
from google.adk.tools.skill_toolset import SkillToolset
|
||||
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-08: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."
|
||||
|
||||
|
||||
# 1. Define a skill programmatically
|
||||
support_hours_skill = models.Skill(
|
||||
frontmatter=models.Frontmatter(
|
||||
name="support-hours-skill",
|
||||
description=(
|
||||
"A skill to check customer support hours for a given location."
|
||||
),
|
||||
metadata={"adk_additional_tools": ["get_timezone"]},
|
||||
),
|
||||
instructions=(
|
||||
"Step 1: Look up the timezone for the user's location using"
|
||||
" 'get_timezone'. Step 2: Read 'references/support_policy.txt' to"
|
||||
" understand support hours policy. Step 3: Explain the support hours"
|
||||
" relative to the location's timezone."
|
||||
),
|
||||
resources=models.Resources(
|
||||
references={
|
||||
"support_policy.txt": (
|
||||
"Customer support is available Monday through Friday, "
|
||||
"from 9:00 AM to 5:00 PM local time."
|
||||
),
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
# 2. Load a skill from a directory
|
||||
weather_skill = load_skill_from_dir(
|
||||
pathlib.Path(__file__).parent / "skills" / "weather-skill"
|
||||
)
|
||||
|
||||
# 3. Combine them into a SkillToolset
|
||||
# NOTE: UnsafeLocalCodeExecutor has security concerns and should NOT
|
||||
# be used in production environments.
|
||||
my_skill_toolset = SkillToolset(
|
||||
skills=[support_hours_skill, weather_skill],
|
||||
additional_tools=[GetTimezoneTool(), get_wind_speed],
|
||||
code_executor=UnsafeLocalCodeExecutor(),
|
||||
)
|
||||
|
||||
# 4. Set up the agent with the toolset
|
||||
root_agent = Agent(
|
||||
name="skills_agent",
|
||||
description="An agent that can use specialized skills.",
|
||||
tools=[
|
||||
my_skill_toolset,
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
name: weather-skill
|
||||
description: A skill that provides weather information based on reference data and scripts.
|
||||
metadata:
|
||||
adk_additional_tools:
|
||||
- get_wind_speed
|
||||
---
|
||||
|
||||
Step 1: Check 'references/weather_info.md' for the current weather.
|
||||
Step 2: If humidity is requested, 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 complete weather update to the user.
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
# Weather Information
|
||||
|
||||
- **Location:** San Francisco, CA
|
||||
- **Condition:** Sunny ☀️
|
||||
- **Temperature:** 72°F (22°C)
|
||||
- **Forecast:** Clear skies all day.
|
||||
+29
@@ -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))
|
||||
@@ -0,0 +1,201 @@
|
||||
{
|
||||
"events": [
|
||||
{
|
||||
"author": "user",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"text": "Can you fetch the current humidity for Mountain View?"
|
||||
}
|
||||
],
|
||||
"role": "user"
|
||||
},
|
||||
"id": "e-1",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionCall": {
|
||||
"args": {},
|
||||
"id": "fc-1",
|
||||
"name": "list_skills"
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "model"
|
||||
},
|
||||
"finishReason": "STOP",
|
||||
"id": "e-2",
|
||||
"invocationId": "i-1",
|
||||
"longRunningToolIds": [],
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionResponse": {
|
||||
"id": "fc-1",
|
||||
"name": "list_skills",
|
||||
"response": {
|
||||
"result": "<available_skills>\n<skill>\n<name>\nsupport-hours-skill\n</name>\n<description>\nA skill to check customer support hours for a given location.\n</description>\n</skill>\n<skill>\n<name>\nweather-skill\n</name>\n<description>\nA skill that provides weather information based on reference data and scripts.\n</description>\n</skill>\n</available_skills>"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "user"
|
||||
},
|
||||
"id": "e-3",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionCall": {
|
||||
"args": {
|
||||
"skill_name": "weather-skill"
|
||||
},
|
||||
"id": "fc-2",
|
||||
"name": "load_skill"
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "model"
|
||||
},
|
||||
"finishReason": "STOP",
|
||||
"id": "e-4",
|
||||
"invocationId": "i-1",
|
||||
"longRunningToolIds": [],
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"actions": {
|
||||
"stateDelta": {
|
||||
"_adk_activated_skill_skills_agent": [
|
||||
"weather-skill"
|
||||
]
|
||||
}
|
||||
},
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionResponse": {
|
||||
"id": "fc-2",
|
||||
"name": "load_skill",
|
||||
"response": {
|
||||
"frontmatter": {
|
||||
"allowed_tools": null,
|
||||
"compatibility": null,
|
||||
"description": "A skill that provides weather information based on reference data and scripts.",
|
||||
"license": null,
|
||||
"metadata": {
|
||||
"adk_additional_tools": [
|
||||
"get_wind_speed"
|
||||
]
|
||||
},
|
||||
"name": "weather-skill"
|
||||
},
|
||||
"instructions": "Step 1: Check 'references/weather_info.md' for the current weather.\nStep 2: If humidity is requested, run 'scripts/get_humidity.py' with the `location` argument.\nStep 3: If wind speed is requested, use the `get_wind_speed` tool.\nStep 4: Provide the complete weather update to the user.",
|
||||
"skill_name": "weather-skill"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "user"
|
||||
},
|
||||
"id": "e-5",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionCall": {
|
||||
"args": {
|
||||
"args": {
|
||||
"location": "Mountain View"
|
||||
},
|
||||
"file_path": "scripts/get_humidity.py",
|
||||
"skill_name": "weather-skill"
|
||||
},
|
||||
"id": "fc-3",
|
||||
"name": "run_skill_script"
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "model"
|
||||
},
|
||||
"finishReason": "STOP",
|
||||
"id": "e-6",
|
||||
"invocationId": "i-1",
|
||||
"longRunningToolIds": [],
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionResponse": {
|
||||
"id": "fc-3",
|
||||
"name": "run_skill_script",
|
||||
"response": {
|
||||
"file_path": "scripts/get_humidity.py",
|
||||
"skill_name": "weather-skill",
|
||||
"status": "success",
|
||||
"stderr": "",
|
||||
"stdout": "Fetching live humidity for Mountain View...\n45% (Simulated)\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "user"
|
||||
},
|
||||
"id": "e-7",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"text": "The current humidity in Mountain View is 45% (Simulated)."
|
||||
}
|
||||
],
|
||||
"role": "model"
|
||||
},
|
||||
"finishReason": "STOP",
|
||||
"id": "e-8",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
{
|
||||
"events": [
|
||||
{
|
||||
"author": "user",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"text": "What is the current weather in SF?"
|
||||
}
|
||||
],
|
||||
"role": "user"
|
||||
},
|
||||
"id": "e-1",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionCall": {
|
||||
"args": {},
|
||||
"id": "fc-1",
|
||||
"name": "list_skills"
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "model"
|
||||
},
|
||||
"finishReason": "STOP",
|
||||
"id": "e-2",
|
||||
"invocationId": "i-1",
|
||||
"longRunningToolIds": [],
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionResponse": {
|
||||
"id": "fc-1",
|
||||
"name": "list_skills",
|
||||
"response": {
|
||||
"result": "<available_skills>\n<skill>\n<name>\nsupport-hours-skill\n</name>\n<description>\nA skill to check customer support hours for a given location.\n</description>\n</skill>\n<skill>\n<name>\nweather-skill\n</name>\n<description>\nA skill that provides weather information based on reference data and scripts.\n</description>\n</skill>\n</available_skills>"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "user"
|
||||
},
|
||||
"id": "e-3",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionCall": {
|
||||
"args": {
|
||||
"skill_name": "weather-skill"
|
||||
},
|
||||
"id": "fc-2",
|
||||
"name": "load_skill"
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "model"
|
||||
},
|
||||
"finishReason": "STOP",
|
||||
"id": "e-4",
|
||||
"invocationId": "i-1",
|
||||
"longRunningToolIds": [],
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"actions": {
|
||||
"stateDelta": {
|
||||
"_adk_activated_skill_skills_agent": [
|
||||
"weather-skill"
|
||||
]
|
||||
}
|
||||
},
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionResponse": {
|
||||
"id": "fc-2",
|
||||
"name": "load_skill",
|
||||
"response": {
|
||||
"frontmatter": {
|
||||
"allowed_tools": null,
|
||||
"compatibility": null,
|
||||
"description": "A skill that provides weather information based on reference data and scripts.",
|
||||
"license": null,
|
||||
"metadata": {
|
||||
"adk_additional_tools": [
|
||||
"get_wind_speed"
|
||||
]
|
||||
},
|
||||
"name": "weather-skill"
|
||||
},
|
||||
"instructions": "Step 1: Check 'references/weather_info.md' for the current weather.\nStep 2: If humidity is requested, run 'scripts/get_humidity.py' with the `location` argument.\nStep 3: If wind speed is requested, use the `get_wind_speed` tool.\nStep 4: Provide the complete weather update to the user.",
|
||||
"skill_name": "weather-skill"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "user"
|
||||
},
|
||||
"id": "e-5",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionCall": {
|
||||
"args": {
|
||||
"file_path": "references/weather_info.md",
|
||||
"skill_name": "weather-skill"
|
||||
},
|
||||
"id": "fc-3",
|
||||
"name": "load_skill_resource"
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "model"
|
||||
},
|
||||
"finishReason": "STOP",
|
||||
"id": "e-6",
|
||||
"invocationId": "i-1",
|
||||
"longRunningToolIds": [],
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionResponse": {
|
||||
"id": "fc-3",
|
||||
"name": "load_skill_resource",
|
||||
"response": {
|
||||
"content": "# Weather Information\n\n- **Location:** San Francisco, CA\n- **Condition:** Sunny \u2600\ufe0f\n- **Temperature:** 72\u00b0F (22\u00b0C)\n- **Forecast:** Clear skies all day.\n",
|
||||
"file_path": "references/weather_info.md",
|
||||
"skill_name": "weather-skill"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "user"
|
||||
},
|
||||
"id": "e-7",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"text": "The current weather in San Francisco, CA is Sunny with a temperature of 72\u00b0F (22\u00b0C). The forecast is clear skies all day."
|
||||
}
|
||||
],
|
||||
"role": "model"
|
||||
},
|
||||
"finishReason": "STOP",
|
||||
"id": "e-8",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
{
|
||||
"events": [
|
||||
{
|
||||
"author": "user",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"text": "What are the support hours for Tokyo?"
|
||||
}
|
||||
],
|
||||
"role": "user"
|
||||
},
|
||||
"id": "e-1",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionCall": {
|
||||
"args": {},
|
||||
"id": "fc-1",
|
||||
"name": "list_skills"
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "model"
|
||||
},
|
||||
"finishReason": "STOP",
|
||||
"id": "e-2",
|
||||
"invocationId": "i-1",
|
||||
"longRunningToolIds": [],
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionResponse": {
|
||||
"id": "fc-1",
|
||||
"name": "list_skills",
|
||||
"response": {
|
||||
"result": "<available_skills>\n<skill>\n<name>\nsupport-hours-skill\n</name>\n<description>\nA skill to check customer support hours for a given location.\n</description>\n</skill>\n<skill>\n<name>\nweather-skill\n</name>\n<description>\nA skill that provides weather information based on reference data and scripts.\n</description>\n</skill>\n</available_skills>"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "user"
|
||||
},
|
||||
"id": "e-3",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionCall": {
|
||||
"args": {
|
||||
"skill_name": "support-hours-skill"
|
||||
},
|
||||
"id": "fc-2",
|
||||
"name": "load_skill"
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "model"
|
||||
},
|
||||
"finishReason": "STOP",
|
||||
"id": "e-4",
|
||||
"invocationId": "i-1",
|
||||
"longRunningToolIds": [],
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"actions": {
|
||||
"stateDelta": {
|
||||
"_adk_activated_skill_skills_agent": [
|
||||
"support-hours-skill"
|
||||
]
|
||||
}
|
||||
},
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionResponse": {
|
||||
"id": "fc-2",
|
||||
"name": "load_skill",
|
||||
"response": {
|
||||
"frontmatter": {
|
||||
"allowed_tools": null,
|
||||
"compatibility": null,
|
||||
"description": "A skill to check customer support hours for a given location.",
|
||||
"license": null,
|
||||
"metadata": {
|
||||
"adk_additional_tools": [
|
||||
"get_timezone"
|
||||
]
|
||||
},
|
||||
"name": "support-hours-skill"
|
||||
},
|
||||
"instructions": "Step 1: Look up the timezone for the user's location using 'get_timezone'. Step 2: Read 'references/support_policy.txt' to understand support hours policy. Step 3: Explain the support hours relative to the location's timezone.",
|
||||
"skill_name": "support-hours-skill"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "user"
|
||||
},
|
||||
"id": "e-5",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionCall": {
|
||||
"args": {
|
||||
"location": "Tokyo"
|
||||
},
|
||||
"id": "fc-3",
|
||||
"name": "get_timezone"
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "model"
|
||||
},
|
||||
"finishReason": "STOP",
|
||||
"id": "e-6",
|
||||
"invocationId": "i-1",
|
||||
"longRunningToolIds": [],
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionResponse": {
|
||||
"id": "fc-3",
|
||||
"name": "get_timezone",
|
||||
"response": {
|
||||
"result": "The timezone for Tokyo is UTC-08:00."
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "user"
|
||||
},
|
||||
"id": "e-7",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionCall": {
|
||||
"args": {
|
||||
"file_path": "references/support_policy.txt",
|
||||
"skill_name": "support-hours-skill"
|
||||
},
|
||||
"id": "fc-4",
|
||||
"name": "load_skill_resource"
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "model"
|
||||
},
|
||||
"finishReason": "STOP",
|
||||
"id": "e-8",
|
||||
"invocationId": "i-1",
|
||||
"longRunningToolIds": [],
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionResponse": {
|
||||
"id": "fc-4",
|
||||
"name": "load_skill_resource",
|
||||
"response": {
|
||||
"content": "Customer support is available Monday through Friday, from 9:00 AM to 5:00 PM local time.",
|
||||
"file_path": "references/support_policy.txt",
|
||||
"skill_name": "support-hours-skill"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "user"
|
||||
},
|
||||
"id": "e-9",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"text": "Customer support in Tokyo is available Monday through Friday, from 9:00 AM to 5:00 PM local time (UTC-08:00)."
|
||||
}
|
||||
],
|
||||
"role": "model"
|
||||
},
|
||||
"finishReason": "STOP",
|
||||
"id": "e-10",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
{
|
||||
"events": [
|
||||
{
|
||||
"author": "user",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"text": "What is the wind speed in Seattle?"
|
||||
}
|
||||
],
|
||||
"role": "user"
|
||||
},
|
||||
"id": "e-1",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionCall": {
|
||||
"args": {},
|
||||
"id": "fc-1",
|
||||
"name": "list_skills"
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "model"
|
||||
},
|
||||
"finishReason": "STOP",
|
||||
"id": "e-2",
|
||||
"invocationId": "i-1",
|
||||
"longRunningToolIds": [],
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionResponse": {
|
||||
"id": "fc-1",
|
||||
"name": "list_skills",
|
||||
"response": {
|
||||
"result": "<available_skills>\n<skill>\n<name>\nsupport-hours-skill\n</name>\n<description>\nA skill to check customer support hours for a given location.\n</description>\n</skill>\n<skill>\n<name>\nweather-skill\n</name>\n<description>\nA skill that provides weather information based on reference data and scripts.\n</description>\n</skill>\n</available_skills>"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "user"
|
||||
},
|
||||
"id": "e-3",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionCall": {
|
||||
"args": {
|
||||
"skill_name": "weather-skill"
|
||||
},
|
||||
"id": "fc-2",
|
||||
"name": "load_skill"
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "model"
|
||||
},
|
||||
"finishReason": "STOP",
|
||||
"id": "e-4",
|
||||
"invocationId": "i-1",
|
||||
"longRunningToolIds": [],
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"actions": {
|
||||
"stateDelta": {
|
||||
"_adk_activated_skill_skills_agent": [
|
||||
"weather-skill"
|
||||
]
|
||||
}
|
||||
},
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionResponse": {
|
||||
"id": "fc-2",
|
||||
"name": "load_skill",
|
||||
"response": {
|
||||
"frontmatter": {
|
||||
"allowed_tools": null,
|
||||
"compatibility": null,
|
||||
"description": "A skill that provides weather information based on reference data and scripts.",
|
||||
"license": null,
|
||||
"metadata": {
|
||||
"adk_additional_tools": [
|
||||
"get_wind_speed"
|
||||
]
|
||||
},
|
||||
"name": "weather-skill"
|
||||
},
|
||||
"instructions": "Step 1: Check 'references/weather_info.md' for the current weather.\nStep 2: If humidity is requested, run 'scripts/get_humidity.py' with the `location` argument.\nStep 3: If wind speed is requested, use the `get_wind_speed` tool.\nStep 4: Provide the complete weather update to the user.",
|
||||
"skill_name": "weather-skill"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "user"
|
||||
},
|
||||
"id": "e-5",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionCall": {
|
||||
"args": {
|
||||
"location": "Seattle"
|
||||
},
|
||||
"id": "fc-3",
|
||||
"name": "get_wind_speed"
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "model"
|
||||
},
|
||||
"finishReason": "STOP",
|
||||
"id": "e-6",
|
||||
"invocationId": "i-1",
|
||||
"longRunningToolIds": [],
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionResponse": {
|
||||
"id": "fc-3",
|
||||
"name": "get_wind_speed",
|
||||
"response": {
|
||||
"result": "The wind speed in Seattle is 10 mph."
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "user"
|
||||
},
|
||||
"id": "e-7",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "skills_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"text": "The wind speed in Seattle is 10 mph."
|
||||
}
|
||||
],
|
||||
"role": "model"
|
||||
},
|
||||
"finishReason": "STOP",
|
||||
"id": "e-8",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": "skills_agent@1"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,100 @@
|
||||
# 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.
|
||||
|
||||
"""Example agent demonstrating the use of SkillToolset."""
|
||||
|
||||
import pathlib
|
||||
|
||||
from google.adk import Agent
|
||||
from google.adk.code_executors.unsafe_local_code_executor import UnsafeLocalCodeExecutor
|
||||
from google.adk.skills import load_skill_from_dir
|
||||
from google.adk.skills import models
|
||||
from google.adk.tools.base_tool import BaseTool
|
||||
from google.adk.tools.skill_toolset import SkillToolset
|
||||
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."
|
||||
|
||||
|
||||
greeting_skill = models.Skill(
|
||||
frontmatter=models.Frontmatter(
|
||||
name="greeting-skill",
|
||||
description=(
|
||||
"A friendly greeting skill that can say hello to a specific person."
|
||||
),
|
||||
metadata={"adk_additional_tools": ["get_timezone"]},
|
||||
),
|
||||
instructions=(
|
||||
"Step 1: Read the 'references/hello_world.txt' file to understand how"
|
||||
" to greet the user. Step 2: Return a greeting based on the reference."
|
||||
),
|
||||
resources=models.Resources(
|
||||
references={
|
||||
"hello_world.txt": "Hello! 👋👋👋 So glad to have you here! ✨✨✨",
|
||||
"example.md": "This is an example reference.",
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
weather_skill = load_skill_from_dir(
|
||||
pathlib.Path(__file__).parent / "skills" / "weather-skill"
|
||||
)
|
||||
|
||||
# WARNING: UnsafeLocalCodeExecutor has security concerns and should NOT
|
||||
# be used in production environments.
|
||||
my_skill_toolset = SkillToolset(
|
||||
skills=[greeting_skill, weather_skill],
|
||||
additional_tools=[GetTimezoneTool(), get_wind_speed],
|
||||
code_executor=UnsafeLocalCodeExecutor(),
|
||||
)
|
||||
|
||||
root_agent = Agent(
|
||||
name="skill_user_agent",
|
||||
description="An agent that can use specialized skills.",
|
||||
tools=[
|
||||
my_skill_toolset,
|
||||
],
|
||||
)
|
||||
+12
@@ -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.
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
# Weather Information
|
||||
|
||||
- **Location:** San Francisco, CA
|
||||
- **Condition:** Sunny ☀️
|
||||
- **Temperature:** 72°F (22°C)
|
||||
- **Forecast:** Clear skies all day.
|
||||
+29
@@ -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))
|
||||
@@ -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
|
||||
@@ -0,0 +1,102 @@
|
||||
# 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.
|
||||
|
||||
"""Example agent demonstrating the use of SkillToolset with GCS.
|
||||
|
||||
Set the following environment variables before running:
|
||||
SAMPLE_SKILLS_SANDBOX_RESOURCE_NAME="projects/{PROJECT_NUMBER}/locations/{LOCATION}/reasoningEngines/{ENGINE_ID}/sandboxEnvironments/{SANDBOX_ID}"
|
||||
SAMPLE_SKILLS_AGENT_ENGINE_RESOURCE_NAME="projects/{PROJECT_NUMBER}/locations/{LOCATION}/reasoningEngines/{ENGINE_ID}"
|
||||
|
||||
Go to parent directory and run with `adk web --host=0.0.0.0`.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import os
|
||||
|
||||
from google.adk import Agent
|
||||
from google.adk import Runner
|
||||
from google.adk.code_executors.agent_engine_sandbox_code_executor import AgentEngineSandboxCodeExecutor
|
||||
from google.adk.plugins import LoggingPlugin
|
||||
from google.adk.skills import list_skills_in_gcs_dir
|
||||
from google.adk.skills import load_skill_from_gcs_dir
|
||||
from google.adk.tools.skill_toolset import SkillToolset
|
||||
|
||||
# Define the GCS bucket and skills prefix
|
||||
BUCKET_NAME = "sample-skills"
|
||||
SKILLS_PREFIX = "static-skills"
|
||||
|
||||
logging.info("Loading skills from gs://%s/%s...", BUCKET_NAME, SKILLS_PREFIX)
|
||||
|
||||
# List and load skills from GCS
|
||||
skills = []
|
||||
try:
|
||||
available_skills = list_skills_in_gcs_dir(
|
||||
bucket_name=BUCKET_NAME, skills_base_path=SKILLS_PREFIX
|
||||
)
|
||||
for skill_id in available_skills.keys():
|
||||
skills.append(
|
||||
load_skill_from_gcs_dir(
|
||||
bucket_name=BUCKET_NAME,
|
||||
skills_base_path=SKILLS_PREFIX,
|
||||
skill_id=skill_id,
|
||||
)
|
||||
)
|
||||
logging.info("Loaded %d skills successfully.", len(skills))
|
||||
except Exception as e: # pylint: disable=broad-exception-caught
|
||||
logging.error("Failed to load skills from GCS: %s", e)
|
||||
|
||||
# Create the SkillToolset
|
||||
my_skill_toolset = SkillToolset(skills=skills)
|
||||
|
||||
# Create the Agent
|
||||
root_agent = Agent(
|
||||
model="gemini-3-flash-preview",
|
||||
name="skill_user_agent",
|
||||
description="An agent that can use specialized skills loaded from GCS.",
|
||||
tools=[
|
||||
my_skill_toolset,
|
||||
],
|
||||
code_executor=AgentEngineSandboxCodeExecutor(
|
||||
sandbox_resource_name=os.getenv("SAMPLE_SKILLS_SANDBOX_RESOURCE_NAME"),
|
||||
agent_engine_resource_name=os.getenv(
|
||||
"SAMPLE_SKILLS_AGENT_ENGINE_RESOURCE_NAME"
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def main():
|
||||
# Initialize the plugins
|
||||
logging_plugin = LoggingPlugin()
|
||||
|
||||
# Create a Runner
|
||||
runner = Runner(
|
||||
agents=[root_agent],
|
||||
plugins=[logging_plugin],
|
||||
)
|
||||
|
||||
# Example run
|
||||
print("Agent initialized with GCS skills. Sending a test prompt...")
|
||||
# You can replace this with an interactive loop if needed.
|
||||
responses = await runner.run(
|
||||
user_input="Hello! What skills do you have access to?"
|
||||
)
|
||||
|
||||
if responses and responses[-1].content and responses[-1].content.parts:
|
||||
print(f"\nResponse: {responses[-1].content.parts[0].text}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user