Skip to content

Commit 7c7d779

Browse files
Jacksunweicopybara-github
authored andcommitted
feat(maven): Supports using custom/subclass of ComponentRegistry to provide tools for agents
Usage example: ``` mvn clean compile google-adk:web \ -Dagents=config_agents \ -Dregistry=com.example.CustomComponentRegistry ``` See more details in the maven_plugin/examples/custom_tools/README.md. PiperOrigin-RevId: 796003653
1 parent 48cfb3d commit 7c7d779

File tree

7 files changed

+491
-92
lines changed

7 files changed

+491
-92
lines changed
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# Custom Tools Example
2+
3+
This example demonstrates how to create and use custom tools with a ComponentRegistry in the Google ADK Maven plugin. The custom registry allows you to inject your own tools and components into the ADK environment.
4+
5+
## Overview
6+
7+
The example includes:
8+
- **CustomComponentRegistry**: A custom registry that extends ComponentRegistry
9+
- **GetWeatherTool**: A custom tool for retrieving weather information using @Schema annotation
10+
- **weather_agent**: A configuration-based agent that uses the custom tool
11+
12+
## Project Structure
13+
14+
```
15+
├── src/main/java/com/example/
16+
│ ├── CustomComponentRegistry.java # Custom registry implementation
17+
│ └── GetWeatherTool.java # Custom weather tool
18+
├── config_agents/
19+
│ └── weather_agent/
20+
│ └── root_agent.yaml # YAML agent configuration
21+
├── pom.xml # Maven configuration
22+
└── README.md # This file
23+
```
24+
25+
## How to Use
26+
27+
### 1. Build and Run
28+
29+
Compile and start the ADK web server with the custom registry:
30+
31+
```bash
32+
# Navigate to the example directory
33+
cd maven_plugin/examples/custom_tools
34+
35+
# Clean, compile, and start the server
36+
mvn clean compile google-adk:web \
37+
-Dagents=config_agents \
38+
-Dregistry=com.example.CustomComponentRegistry
39+
```
40+
41+
### 2. Access the Web UI
42+
43+
Open your browser and navigate to:
44+
```
45+
http://localhost:8000
46+
```
47+
48+
You should see the weather_agent available in the UI, and it will have access to the custom get_weather tool.
49+
50+
## Key Components
51+
52+
### CustomComponentRegistry
53+
54+
The `CustomComponentRegistry` extends the base `ComponentRegistry` and registers custom tools:
55+
56+
```java
57+
public class CustomComponentRegistry extends ComponentRegistry {
58+
public static final CustomComponentRegistry INSTANCE = new CustomComponentRegistry();
59+
60+
private CustomComponentRegistry() {
61+
super(); // Initialize base ADK components
62+
63+
// Register custom tools
64+
register("tools.get_weather", GetWeatherTool.INSTANCE);
65+
}
66+
}
67+
```
68+
69+
### GetWeatherTool
70+
71+
A simple tool implementation using the `@Schema` annotation approach:
72+
73+
```java
74+
public class GetWeatherTool {
75+
public static final FunctionTool INSTANCE =
76+
FunctionTool.create(GetWeatherTool.class, "getWeather");
77+
78+
@Schema(name = "get_weather", description = "Get current weather information for a city")
79+
public static Map<String, Object> getWeather(
80+
@Schema(name = "city", description = "The city to fetch weather for.") String city) {
81+
if (isNullOrEmpty(city)) {
82+
return Map.of("error", "City parameter is required");
83+
}
84+
85+
return Map.of(
86+
"city", city,
87+
"temperature", getSimulatedTemperature(city),
88+
"condition", getSimulatedCondition(city)
89+
);
90+
}
91+
}
92+
```
93+
94+
### Configuration-Based Agent
95+
96+
The weather agent is defined in `config_agents/weather_agent/root_agent.yaml`:
97+
98+
```yaml
99+
model: "gemini-2.5-flash"
100+
name: "weather_agent"
101+
description: "A weather assistant that can fetch weather information for cities"
102+
instruction: |
103+
You are a helpful weather assistant.
104+
105+
- Use the get_weather tool to fetch current weather information for any city.
106+
- Always provide clear and informative responses about weather conditions.
107+
- If a user doesn't ask about weather, steer the topic back to weather.
108+
tools:
109+
- name: "tools.get_weather"
110+
```
111+
112+
## Sample Queries
113+
114+
Once the server is running, try these sample queries with the weather_agent:
115+
116+
### Basic Weather Queries
117+
118+
- "What's the weather like in New York?"
119+
- "Tell me the current weather in Tokyo"
120+
- "How's the weather in London today?"
121+
122+
### Follow-up Questions
123+
124+
- "What about Paris?"
125+
- "And San Francisco?"
126+
- "How about the weather in my hometown of Chicago?"
127+
128+
### Non-weather Topics (Agent will redirect)
129+
130+
- "What's the capital of France?" → Agent will steer back to weather
131+
- "Tell me a joke" → Agent will suggest asking about weather instead
132+
133+
## Best Practices
134+
135+
- Use `@Schema` annotation for simple tool implementations
136+
- Return structured data (Maps) from tools for better integration
137+
- Register tools with descriptive, namespaced names (e.g., "tools.get_weather")
138+
- Test tool functionality through the web UI
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
2+
model: "gemini-2.5-flash"
3+
name: "weather_agent"
4+
description: "A weather assistant that can fetch weather information for cities"
5+
instruction: |
6+
You are a helpful weather assistant.
7+
8+
- Use the get_weather tool to fetch current weather information for any city.
9+
- Always provide clear and informative responses about weather conditions.
10+
- If a user doesn't ask about weather, steer the topic back to weather.
11+
tools:
12+
- name: "tools.get_weather"
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>com.example</groupId>
8+
<artifactId>custom-tools-example</artifactId>
9+
<version>1.0-SNAPSHOT</version>
10+
<packaging>jar</packaging>
11+
12+
<name>ADK Custom Tools Example</name>
13+
<description>Example project demonstrating how to use custom tools with ComponentRegistry in Google ADK</description>
14+
15+
<properties>
16+
<maven.compiler.source>11</maven.compiler.source>
17+
<maven.compiler.target>11</maven.compiler.target>
18+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
19+
<google-adk.version>0.2.1-SNAPSHOT</google-adk.version>
20+
</properties>
21+
22+
<dependencies>
23+
<dependency>
24+
<groupId>com.google.adk</groupId>
25+
<artifactId>google-adk</artifactId>
26+
<version>${google-adk.version}</version>
27+
</dependency>
28+
29+
<!-- Maven plugin dependency for AgentLoader interface -->
30+
<dependency>
31+
<groupId>com.google.adk</groupId>
32+
<artifactId>google-adk-maven-plugin</artifactId>
33+
<version>${google-adk.version}</version>
34+
<scope>compile</scope>
35+
</dependency>
36+
</dependencies>
37+
38+
<build>
39+
<plugins>
40+
<plugin>
41+
<groupId>org.apache.maven.plugins</groupId>
42+
<artifactId>maven-compiler-plugin</artifactId>
43+
<version>3.11.0</version>
44+
<configuration>
45+
<source>11</source>
46+
<target>11</target>
47+
</configuration>
48+
</plugin>
49+
50+
<!-- ADK Maven Plugin -->
51+
<plugin>
52+
<groupId>com.google.adk</groupId>
53+
<artifactId>google-adk-maven-plugin</artifactId>
54+
<version>${google-adk.version}</version>
55+
</plugin>
56+
</plugins>
57+
</build>
58+
</project>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example;
18+
19+
import com.google.adk.utils.ComponentRegistry;
20+
21+
/**
22+
* Example of a custom ComponentRegistry that pre-registers custom tools.
23+
*
24+
* <p>This registry extends the base ComponentRegistry and adds custom components:
25+
*
26+
* <ul>
27+
* <li>GetWeatherTool - A custom tool for retrieving weather information
28+
* </ul>
29+
*
30+
* <p>Usage with the maven plugin:
31+
*
32+
* <pre>{@code
33+
* mvn google-adk:web ... -Dregistry=com.example.CustomComponentRegistry
34+
* }</pre>
35+
*/
36+
public class CustomComponentRegistry extends ComponentRegistry {
37+
38+
/** Singleton instance for easy access */
39+
public static final CustomComponentRegistry INSTANCE = new CustomComponentRegistry();
40+
41+
/** Private constructor to initialize custom components */
42+
public CustomComponentRegistry() {
43+
super(); // Initialize base ADK components
44+
register("tools.get_weather", GetWeatherTool.INSTANCE);
45+
}
46+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example;
18+
19+
import static com.google.common.base.Strings.isNullOrEmpty;
20+
21+
import com.google.adk.tools.Annotations.Schema;
22+
import com.google.adk.tools.FunctionTool;
23+
import java.util.Map;
24+
25+
/**
26+
* Example custom tool that simulates weather information retrieval.
27+
*
28+
* <p>This is a demonstration tool showing how to create custom tools using the @Schema annotation
29+
* approach.
30+
*/
31+
public class GetWeatherTool {
32+
33+
public static final FunctionTool INSTANCE =
34+
FunctionTool.create(GetWeatherTool.class, "getWeather");
35+
36+
@Schema(name = "get_weather", description = "Get current weather information for a city")
37+
public static Map<String, Object> getWeather(
38+
@Schema(name = "city", description = "The city to fetch weather for.") String city) {
39+
if (isNullOrEmpty(city)) {
40+
return Map.of("error", "City parameter is required");
41+
}
42+
43+
// Simulate weather data retrieval
44+
int temperature = getSimulatedTemperature(city);
45+
String condition = getSimulatedCondition(city);
46+
47+
return Map.of(
48+
"city", city,
49+
"temperature", temperature,
50+
"condition", condition);
51+
}
52+
53+
private static int getSimulatedTemperature(String city) {
54+
// Simple hash-based simulation for consistent results
55+
int hash = city.toLowerCase().hashCode();
56+
return 15 + Math.abs(hash % 25); // Temperature between 15-40°C
57+
}
58+
59+
private static String getSimulatedCondition(String city) {
60+
String[] conditions = {"sunny", "cloudy", "partly cloudy", "rainy", "overcast"};
61+
int hash = city.toLowerCase().hashCode();
62+
return conditions[Math.abs(hash % conditions.length)];
63+
}
64+
}

0 commit comments

Comments
 (0)