* Add Kotlin to hero / front page * Add quickstart page for Kotlin * Complete Kotlin quickstart guide and fix hero code sample (#2) * Replace GitHub repo links with language icons in header (#3) * Fix header icon FOUC and homepage font weight regression (#4) * Testing staging pipeline * Revert test edit (for staging pipeline) * Update language icon tooltips to indicate GitHub destination (#5) * Add link to ADK Kotlin release notes (#7) * Initial commit of ADK Kotlin API reference docs (#6) * Add script to generate ADK Kotlin API reference docs (#8) * Update links and link checker ignore list (temporarily) (#9) * Add ADK Kotlin for Android getting started guide to Advanced setup page (#10) * Add advanced setup page with steps to "Use ADK Kotlin in Android projects" * Update temp link checker rules * Add placeholder folder for adk-samples (#13) * adding linter/compilation checks for kotlin snippets (#12) * adding linter/compilation checks for kotlin snippets * Add Kotlin validation scripts * Initial commit of Kotlin sample agents for adk-samples (#15) * Adding kotlin snippet for llm agents (#16) * Adding kotlin snippets to Events (#17) * Pull changes to docs/events/index.md from glaforge-kotlin-snippets * fixing kotlin event timestamp and longRunningToolIds * Fix language tags (#19) * Fix language tags * Update * Fix wrapping * Fix wrapping (again) * Fix wrapping/format * Fix language tag on integration page * Enable check_paths in PyMdown Snippets Extension to make the build fail if a snippet can't be found (#20) * Update mkdocs config (#21) * Fix broken links, update URLs to adk.dev, and improve (temp) lychee config (#22) * Add Kotlin/maven badge to README (#23) * Adding Kotlin snippets for artifacts (#18) * Pull Kotlin snippets for artifacts from glaforge-kotlin-snippets * Add comprehensive Kotlin snippets for artifacts * Refactor artifacts documentation to use external Kotlin snippets * Update Kotlin model to gemini-flash-latest * Fix GCS initialization in Kotlin artifact snippet * afixi failing test with capital-agent added to files_to_check * Fix snippet label syntax for MkDocs build * Configure proper Gradle project for Kotlin snippets and fix dependencies * Add KSP support and generated sources to Kotlin snippets build * fixing capital_agent turnComplete * Fix syntax error in build.gradle.kts by removing invalid placeholders (#25) * Adding Kotlin snippets to google-gemini.md (#27) Pulling kotlin changes to google-gemini.md from glaforge-kotlin-snippets * Add a warning about not adding an api key to production code. (#28) * Add a warning about not adding an api key to production code. * Update note --------- Co-authored-by: Kristopher Overholt <koverholt@google.com> * Add ADK Demo App sample showcasing Gemini-powered agents (#29) This sample demonstrates how to use the Google ADK (Agent Development Kit) in an Android application to create a chat interface powered by a Gemini-based "Fun Facts" agent. The implementation features: * Integration with the Kotlin ADK core and processor libraries. * A `FunFactsAgent` defined using `LlmAgent` and the Gemini model. * A `ChatViewModel` utilizing `InMemoryRunner` for asynchronous message streaming. * A modern UI built with Jetpack Compose and Material 3. * Build configuration logic for secure API key management via environment variables or `local.properties`. * Update Kotlin docs and samples to align with adk-kotlin API changes (#30) Rename GeminiModel to Gemini, @AdkTool/@AdkParam to @Tool/@Param, adkTools() to generatedTools(), replace DebugRunner with InMemoryRunner, fix AgentLoader import path, use SingleAgentLoader, bump Kotlin to 2.3.21 and KSP to 2.3.7, and update Android minSdk from 24 to 26. * adding kotlin info to READMEs (#14) * Reorganize Android sample agent and add READMEs (#31) * Move Android sample agent * Update repo README, add Android README, update sample agent README * Minor edit to language support tags (#32) * Remove blog post link (#33) Will re-add after it's published * Remove examples link (#34) * Adding Kotlin snippets for Sessions docs (#26) * initial kotlins snippets additions to sessions docs * Updating memory docs with kotlin snippets * Adding kotlin snippets to session state docs. * update model to gemini-flash-latest * sessions examples clean-up * fixing sessions snippet markers * adding kotlin session snippets to files to test * adding callback to memory_example * Fixing capital agent snippet (#35) Fixing file name Updating adkTool > Tool Updating GeminiModel > Gemini * Adding kotlin snippets for tools docs (#36) * adding function tool kotlin snippets * adding function_tools snippets to files to test * Adding kotlin snippets to observability docs (#37) * initial kotlin observability updates * adding observability snippets to file check (#38) * Adding Kotlin snippets to Callbacks docs (#39) * kotlin callbacks snippets * adding callbacks snippets to file check * Align Kotlin and KSP versions with published 0.1.0 artifacts (#40) * switch CLI entry points from InMemoryRunner to ReplRunner (#41) * Switch CLI entry points from InMemoryRunner to ReplRunner * Fix wording * Update API reference docs for Kotlin, 2026-05-18 (#42) * Remove ADK on Android note until published (#43) * Update Kotlin code samples (#44) * Rename GeminiModel to Gemini in Kotlin snippets and docs * Remove broken SessionKey call and use sessionId directly in AgentTool snippet * Rewrite Go hero snippet to use llmagent API * Use isFinalResponse with safe access in CapitalAgent snippet * Use Role.USER constant instead of raw string in SetupExample * Use full semver v0.1.0 in Kotlin language support tags * Remove Android setup steps, moving to new property (#45) * Tutorial Kotlin agent (#46) * Adding multi-tool-agent snippet and updating tutorial * Fixing Go language order on tutorial page * adding multi tool agent example to files to test * Inline Kotlin get-started code sample * Kotlin Multi agents snippets (#47) * Multi-agent kotlin snippets * Fixing docs tags in multiagent example * Fix Kotlin language support tags, code samples, and google-gemini.md cleanup (#48) * Add Kotlin v0.1.0 to language support tags across docs * Fix MultiToolAgent.kt model string and argument style * Update MultiAgentExample.kt to use gemini-flash-latest model string * Fix google-gemini.md: add Kotlin sample, remove unsupported Java tabs * Remove explicit apiKey from CallbackBasic.kt for consistency * Standardize Gemini() constructor to use named args in all snippets * Remove adk-samples directory (moved to google/adk-samples#1969) * Remove adk-samples directory (moved to google/adk-samples#1969) (#49) * Update API reference docs for ADK Kotlin 0.1.0 (#50) * Remove adk-samples directory (moved to google/adk-samples#1969) * Update API reference docs for ADK Kotlin 0.1.0 * Remove kotlin lycheeignore config (#51) * Remove adk-samples directory (moved to google/adk-samples#1969) * Remove Kotlin .lycheeignore config links --------- Co-authored-by: Toni Klopfenstein <2359976+ToniCorinne@users.noreply.github.com> Co-authored-by: Jolanda Verhoef <JolandaVerhoef@users.noreply.github.com>
28 KiB
Function tools
When pre-built ADK tools don't meet your requirements, you can create custom function tools. Building function tools allows you to create tailored functionality, such as connecting to proprietary databases or implementing unique algorithms.
For example, a function tool, myfinancetool, might be a function that calculates a specific financial metric. ADK also supports long-running functions, so if that calculation takes a while, the agent can continue working on other tasks.
ADK offers several ways to create functions tools, each suited to different levels of complexity and control:
Function Tools
Transforming a Python function into a tool is a straightforward way to integrate custom logic into your agents. When you assign a function to an agent’s tools list, the framework automatically wraps it as a FunctionTool.
How it Works
The ADK framework automatically inspects your Python function's signature—including its name, docstring, parameters, type hints, and default values—to generate a schema. This schema is what the LLM uses to understand the tool's purpose, when to use it, and what arguments it requires.
Defining Function Signatures
A well-defined function signature is crucial for the LLM to use your tool correctly.
Parameters
Required Parameters
=== "Python" A parameter is considered required if it has a type hint but no default value. The LLM must provide a value for this argument when it calls the tool. The parameter's description is taken from the function's docstring.
???+ "Example: Required Parameters"
```python
def get_weather(city: str, unit: str):
"""
Retrieves the weather for a city in the specified unit.
Args:
city (str): The city name.
unit (str): The temperature unit, either 'Celsius' or 'Fahrenheit'.
"""
# ... function logic ...
return {"status": "success", "report": f"Weather for {city} is sunny."}
```
In this example, both `city` and `unit` are mandatory. If the LLM tries to call `get_weather` without one of them, the ADK will return an error to the LLM, prompting it to correct the call.
=== "Go"
In Go, you use struct tags to control the JSON schema. The two primary tags are json and jsonschema.
A parameter is considered **required** if its struct field does **not** have the `omitempty` or `omitzero` option in its `json` tag.
The `jsonschema` tag is used to provide the argument's description. This is crucial for the LLM to understand what the argument is for.
???+ "Example: Required Parameters"
```go
// GetWeatherParams defines the arguments for the getWeather tool.
type GetWeatherParams struct {
// This field is REQUIRED (no "omitempty").
// The jsonschema tag provides the description.
Location string `json:"location" jsonschema:"The city and state, e.g., San Francisco, CA"`
// This field is also REQUIRED.
Unit string `json:"unit" jsonschema:"The temperature unit, either 'celsius' or 'fahrenheit'"`
}
```
In this example, both `location` and `unit` are mandatory.
=== "Java"
In Java, primitive types (e.g., int, double, boolean) are inherently required because they cannot be null. For object types (like String or Integer), they are typically considered required unless explicitly marked as optional.
The `@Schema` annotation is used to provide the argument's description and can explicitly define parameter properties. This is crucial for the LLM to understand what the argument is for.
???+ "Example: Required Parameters"
```java
// The @Schema annotation on the parameter provides the description.
public static Map<String, Object> getWeather(
@Schema(description = "The city and state, e.g., San Francisco, CA", name = "location")
String location,
@Schema(description = "The temperature unit, either 'Celsius' or 'Fahrenheit'", name = "unit")
String unit) {
// ... function logic ...
return Map.of("status", "success", "report", "Weather for " + location + " is sunny.");
}
```
In this example, both `location` and `unit` are mandatory.
=== "Kotlin" In Kotlin, parameters are considered required by default if they are of a non-nullable type and have no default value. The LLM must provide a value for these arguments.
The `@Param` annotation is used to provide the argument's description. This is crucial for the LLM to understand what the argument is for.
???+ "Example: Required Parameters"
```kotlin
--8<-- "examples/kotlin/snippets/tools/function-tools/RequiredParams.kt:required_params"
```
In this example, both `location` and `unit` are mandatory.
Optional Parameters
=== "Python"
A parameter is considered optional if you provide a default value. This is the standard Python way to define optional arguments. You can also mark a parameter as optional using typing.Optional[SomeType] or the | None syntax (Python 3.10+).
Use defaults only for values that are truly optional. Do not add defaults for information the model should derive from the user request or ask the user to provide.
???+ "Example: Optional Parameters"
```python
def search_flights(destination: str, departure_date: str, flexible_days: int = 0):
"""
Searches for flights.
Args:
destination (str): The destination city.
departure_date (str): The desired departure date.
flexible_days (int, optional): Number of flexible days for the search. Defaults to 0.
"""
# ... function logic ...
if flexible_days > 0:
return {"status": "success", "report": f"Found flexible flights to {destination}."}
return {"status": "success", "report": f"Found flights to {destination} on {departure_date}."}
```
Here, `flexible_days` is optional. The LLM can choose to provide it, but it's not required.
=== "Go"
A parameter is considered optional if its struct field has the omitempty or omitzero option in its json tag.
???+ "Example: Optional Parameters"
```go
// GetWeatherParams defines the arguments for the getWeather tool.
type GetWeatherParams struct {
// Location is required.
Location string `json:"location" jsonschema:"The city and state, e.g., San Francisco, CA"`
// Unit is optional.
Unit string `json:"unit,omitempty" jsonschema:"The temperature unit, either 'celsius' or 'fahrenheit'"`
// Days is optional.
Days int `json:"days,omitzero" jsonschema:"The number of forecast days to return (defaults to 1)"`
}
```
Here, `unit` and `days` are optional. The LLM can choose to provide them, but they are not required.
=== "Java"
A parameter can be considered optional in Java by using object types that allow null values (such as Integer instead of int), or by explicitly defining it as optional using java.util.Optional.
???+ "Example: Optional Parameters"
```java
import java.util.Map;
import java.util.Optional;
public static Map<String, Object> searchFlights(
@Schema(description = "The destination city.", name = "destination")
String destination,
@Schema(description = "The desired departure date.", name = "departureDate")
String departureDate,
@Schema(description = "Number of flexible days for the search. Defaults to 0.", name = "flexibleDays")
Optional<Integer> flexibleDays) {
// ... function logic ...
int days = flexibleDays.orElse(0);
if (days > 0) {
return Map.of("status", "success", "report", "Found flexible flights to " + destination + ".");
}
return Map.of("status", "success", "report", "Found flights to " + destination + " on " + departureDate + ".");
}
```
Here, `flexibleDays` is optional. The LLM can choose to provide it, but it's not required.
=== "Kotlin" In Kotlin, a parameter is considered optional if it is of a nullable type or if it has a default value.
???+ "Example: Optional Parameters"
```kotlin
--8<-- "examples/kotlin/snippets/tools/function-tools/OptionalParams.kt:optional_params"
```
Here, `flexibleDays` is optional. The LLM can choose to provide it, but it's not required.
Optional Parameters with typing.Optional
You can also mark a parameter as optional using typing.Optional[SomeType] or the | None syntax (Python 3.10+). This signals that the parameter can be None. When combined with a default value of None, it behaves as a standard optional parameter.
???+ "Example: typing.Optional"
=== "Python"
```python
from typing import Optional
def create_user_profile(username: str, bio: Optional[str] = None):
"""
Creates a new user profile.
Args:
username (str): The user's unique username.
bio (str, optional): A short biography for the user. Defaults to None.
"""
# ... function logic ...
if bio:
return {"status": "success", "message": f"Profile for {username} created with a bio."}
return {"status": "success", "message": f"Profile for {username} created."}
```
Variadic Parameters (*args and **kwargs)
While you can include *args (variable positional arguments) and **kwargs (variable keyword arguments) in your function signature for other purposes, they are ignored by the ADK framework when generating the tool schema for the LLM. The LLM will not be aware of them and cannot pass arguments to them. It's best to rely on explicitly defined parameters for all data you expect from the LLM.
Return Type
The preferred return type for a Function Tool is a dictionary in Python, a Map or custom Record or POJO in Java, an object in TypeScript, or a Map or Data Class in Kotlin. This allows you to structure the response with key-value pairs, providing context and clarity to the LLM. If your function returns a type other than a dictionary or map, the framework automatically wraps it into a dictionary with a single key named "result".
Strive to make your return values as descriptive as possible. For example, instead of returning a numeric error code, return a dictionary with an "error_message" key containing a human-readable explanation. Remember that the LLM, not a piece of code, needs to understand the result. As a best practice, include a "status" key in your return dictionary to indicate the overall outcome (e.g., "success", "error", "pending"), providing the LLM with a clear signal about the operation's state.
Docstrings
The docstring of your function serves as the tool's description and is sent to the LLM. Therefore, a well-written and comprehensive docstring is crucial for the LLM to understand how to use the tool effectively. Clearly explain the purpose of the function, the meaning of its parameters, and the expected return values. In Java, you can use Javadoc comments or the @Schema(description="...") annotation on your method to serve as this description. In Kotlin, you can use KDoc comments or the @Tool(description="...") and @Param(description="...") annotations to provide these descriptions.
Passing Data Between Tools
When an agent calls multiple tools in a sequence, you might need to pass data from one tool to another. The recommended way to do this is by using the temp: prefix in the session state.
A tool can write data to a temp: variable, and a subsequent tool can read it. This data is only available for the current invocation and is discarded afterwards.
!!! note "Shared Invocation Context"
All tool calls within a single agent turn share the same InvocationContext. This means they also share the same temporary (temp:) state, which is how data can be passed between them.
Example
??? "Example"
=== "Python"
This tool is a python function which obtains the Stock price of a given Stock ticker/ symbol.
<u>Note</u>: You need to `pip install yfinance` library before using this tool.
```python
--8<-- "examples/python/snippets/tools/function-tools/func_tool.py"
```
The return value from this tool will be wrapped into a dictionary.
```json
{"result": "$123"}
```
=== "Typescript"
This tool retrieves the mocked value of a stock price.
```typescript
--8<-- "examples/typescript/snippets/tools/function-tools/function-tools-example.ts"
```
The return value from this tool will be an object.
```json
For input `GOOG`: {"price": 2800.0, "currency": "USD"}
```
=== "Go"
This tool retrieves the mocked value of a stock price.
```go
import (
"google.golang.org/adk/agent"
"google.golang.org/adk/agent/llmagent"
"google.golang.org/adk/model/gemini"
"google.golang.org/adk/runner"
"google.golang.org/adk/session"
"google.golang.org/adk/tool"
"google.golang.org/adk/tool/functiontool"
"google.golang.org/genai"
)
--8<-- "examples/go/snippets/tools/function-tools/func_tool.go"
```
The return value from this tool will be a `getStockPriceResults` instance.
```json
For input `{"symbol": "GOOG"}`: {"price":300.6,"symbol":"GOOG"}
```
=== "Java"
This tool retrieves the mocked value of a stock price.
```java
--8<-- "examples/java/snippets/src/main/java/tools/StockPriceAgent.java:full_code"
```
The return value from this tool will be wrapped into a Map<String, Object>.
```json
For input `GOOG`: {"symbol": "GOOG", "price": "1.0"}
```
=== "Kotlin"
This tool retrieves the mocked value of a stock price.
```kotlin
--8<-- "examples/kotlin/snippets/tools/function-tools/FuncTool.kt:full_example"
```
The return value from this tool will be a Map.
```json
For input `GOOG`: {"symbol": "GOOG", "price": 123.45}
```
Best Practices
While you have considerable flexibility in defining your function, remember that simplicity enhances usability for the LLM. Consider these guidelines:
- Fewer Parameters are Better: Minimize the number of parameters to reduce complexity.
- Simple Data Types: Favor primitive data types like
strandintover custom classes whenever possible. - Meaningful Names: The function's name and parameter names significantly influence how the LLM interprets and utilizes the tool. Choose names that clearly reflect the function's purpose and the meaning of its inputs. Avoid generic names like
do_stuff()orbeAgent(). - Build for Parallel Execution: Improve function calling performance when multiple tools are run by building for asynchronous operation. For information on enabling parallel execution for tools, see Increase tool performance with parallel execution.
Long Running Function Tools
This tool is designed to help you start and manage tasks that are handled outside the operation of your agent workflow, and require a significant amount of processing time, without blocking the agent's execution. This tool is a subclass of FunctionTool.
When using a LongRunningFunctionTool, your function can initiate the long-running operation and optionally return an initial result, such as a long-running operation id. Once a long running function tool is invoked the agent runner pauses the agent run and lets the agent client to decide whether to continue or wait until the long-running operation finishes. The agent client can query the progress of the long-running operation and send back an intermediate or final response. The agent can then continue with other tasks. An example is the human-in-the-loop scenario where the agent needs human approval before proceeding with a task.
!!! warning "Warning: Execution handling" Long Running Function Tools are designed to help you start and manage long running tasks as part of your agent workflow, but not perform the actual, long task. For tasks that require significant time to complete, you should implement a separate server to do the task.
!!! tip "Tip: Parallel execution" Depending on the type of tool you are building, designing for asynchronous operation may be a better solution than creating a long running tool. For more information, see Increase tool performance with parallel execution.
How it Works
In Python, you wrap a function with LongRunningFunctionTool. In Java, you pass a Method name to LongRunningFunctionTool.create(). In TypeScript, you instantiate the LongRunningFunctionTool class.
-
Initiation: When the LLM calls the tool, your function starts the long-running operation.
-
Initial Updates: Your function should optionally return an initial result (e.g. the long-running operation id). The ADK framework takes the result and sends it back to the LLM packaged within a
FunctionResponse. This allows the LLM to inform the user (e.g., status, percentage complete, messages). And then the agent run is ended / paused. -
Continue or Wait: After each agent run is completed. Agent client can query the progress of the long-running operation and decide whether to continue the agent run with an intermediate response (to update the progress) or wait until a final response is retrieved. Agent client should send the intermediate or final response back to the agent for the next run.
-
Framework Handling: The ADK framework manages the execution. It sends the intermediate or final
FunctionResponsesent by agent client to the LLM to generate a user friendly message.
Creating the Tool
Define your tool function and wrap it using the LongRunningFunctionTool class:
=== "Python"
```python
--8<-- "examples/python/snippets/tools/function-tools/human_in_the_loop.py:define_long_running_function"
```
=== "TypeScript"
```typescript
--8<-- "examples/typescript/snippets/tools/function-tools/long-running-function-tool-example.ts:define_long_running_function"
```
=== "Go"
```go
import (
"google.golang.org/adk/agent"
"google.golang.org/adk/agent/llmagent"
"google.golang.org/adk/model/gemini"
"google.golang.org/adk/tool"
"google.golang.org/adk/tool/functiontool"
"google.golang.org/genai"
)
--8<-- "examples/go/snippets/tools/function-tools/long-running-tool/long_running_tool.go:create_long_running_tool"
```
=== "Java"
```java
import com.google.adk.agents.LlmAgent;
import com.google.adk.tools.LongRunningFunctionTool;
import java.util.HashMap;
import java.util.Map;
public class ExampleLongRunningFunction {
// Define your Long Running function.
// Ask for approval for the reimbursement.
public static Map<String, Object> askForApproval(String purpose, double amount) {
// Simulate creating a ticket and sending a notification
System.out.println(
"Simulating ticket creation for purpose: " + purpose + ", amount: " + amount);
// Send a notification to the approver with the link of the ticket
Map<String, Object> result = new HashMap<>();
result.put("status", "pending");
result.put("approver", "Sean Zhou");
result.put("purpose", purpose);
result.put("amount", amount);
result.put("ticket-id", "approval-ticket-1");
return result;
}
public static void main(String[] args) throws NoSuchMethodException {
// Pass the method to LongRunningFunctionTool.create
LongRunningFunctionTool approveTool =
LongRunningFunctionTool.create(ExampleLongRunningFunction.class, "askForApproval");
// Include the tool in the agent
LlmAgent approverAgent =
LlmAgent.builder()
// ...
.tools(approveTool)
.build();
}
}
```
=== "Kotlin"
In Kotlin, you can create a long-running function tool by setting the `isLongRunning` property to `true` in the `@Tool` annotation.
```kotlin
--8<-- "examples/kotlin/snippets/tools/function-tools/LongRunningTool.kt:long_running_tool"
```
Intermediate / Final result Updates
Agent client received an event with long running function calls and check the status of the ticket. Then Agent client can send the intermediate or final response back to update the progress. The framework packages this value (even if it's None) into the content of the FunctionResponse sent back to the LLM.
!!! note "Note: Long running function response with Resume feature"
If your ADK agent workflow is configured with the
[Resume](/runtime/resume/) feature, you also must include
the Invocation ID (`invocation_id`) parameter with the long running
function response. The Invocation ID you provide must be the same
invocation that generated the long running function request, otherwise
the system starts a new invocation with the response. If your
agent uses the Resume feature, consider including the Invocation ID
as a parameter with your long running function request, so it can be
included with the response. For more details on using the Resume
feature, see
[Resume stopped agents](/runtime/resume/).
??? Tip "Applies to only Java ADK"
When passing `ToolContext` with Function Tools, ensure that one of the following is true:
* The Schema is passed with the ToolContext parameter in the function signature, like:
```
@com.google.adk.tools.Annotations.Schema(name = "toolContext") ToolContext toolContext
```
OR
* The following `-parameters` flag is set to the mvn compiler plugin
```
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.0</version> <!-- or newer -->
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
```
This constraint is temporary and will be removed.
=== "Python"
```python
--8<-- "examples/python/snippets/tools/function-tools/human_in_the_loop.py:call_reimbursement_tool"
```
=== "TypeScript"
```typescript
--8<-- "examples/typescript/snippets/tools/function-tools/long-running-function-tool-example.ts"
```
=== "Go"
The following example demonstrates a multi-turn workflow. First, the user asks the agent to create a ticket. The agent calls the long-running tool and the client captures the `FunctionCall` ID. The client then simulates the asynchronous work completing by sending subsequent `FunctionResponse` messages back to the agent to provide the ticket ID and final status.
```go
--8<-- "examples/go/snippets/tools/function-tools/long-running-tool/long_running_tool.go:run_long_running_tool"
```
=== "Java"
```java
--8<-- "examples/java/snippets/src/main/java/tools/LongRunningFunctionExample.java:full_code"
```
??? "Python complete example: File Processing Simulation"
```python
--8<-- "examples/python/snippets/tools/function-tools/human_in_the_loop.py"
```
Key aspects of this example
-
LongRunningFunctionTool: Wraps the supplied method/function; the framework handles sending yielded updates and the final return value as sequential FunctionResponses. -
Agent instruction: Directs the LLM to use the tool and understand the incoming FunctionResponse stream (progress vs. completion) for user updates.
-
Final return: The function returns the final result dictionary, which is sent in the concluding FunctionResponse to indicate completion.
Agent-as-a-Tool
This powerful feature allows you to leverage the capabilities of other agents within your system by calling them as tools. The Agent-as-a-Tool enables you to invoke another agent to perform a specific task, effectively delegating responsibility. This is conceptually similar to creating a Python function that calls another agent and uses the agent's response as the function's return value.
Key difference from sub-agents
It's important to distinguish an Agent-as-a-Tool from a Sub-Agent.
-
Agent-as-a-Tool: When Agent A calls Agent B as a tool (using Agent-as-a-Tool), Agent B's answer is passed back to Agent A, which then summarizes the answer and generates a response to the user. Agent A retains control and continues to handle future user input.
-
Sub-agent: When Agent A calls Agent B as a sub-agent, the responsibility of answering the user is completely transferred to Agent B. Agent A is effectively out of the loop. All subsequent user input will be answered by Agent B.
Usage
To use an agent as a tool, wrap the agent with the AgentTool class.
=== "Python"
```python
tools=[AgentTool(agent=agent_b)]
```
=== "TypeScript"
```typescript
tools: [new AgentTool({agent: agentB})]
```
=== "Go"
```go
agenttool.New(agent, &agenttool.Config{...})
```
=== "Java"
```java
AgentTool.create(agent)
```
=== "Kotlin"
```kotlin
AgentTool(agent = agentB)
```
Customization
The AgentTool class provides the following attributes for customizing its behavior:
- skip_summarization (Python/TypeScript) / skipSummarization (Kotlin/Java): (boolean) If set to True, the framework will bypass the LLM-based summarization of the tool agent's response. This can be useful when the tool's response is already well-formatted and requires no further processing.
??? "Example"
=== "Python"
```python
--8<-- "examples/python/snippets/tools/function-tools/summarizer.py"
```
=== "TypeScript"
```typescript
--8<-- "examples/typescript/snippets/tools/function-tools/agent-as-a-tool-example.ts"
```
=== "Go"
```go
import (
"google.golang.org/adk/agent"
"google.golang.org/adk/agent/llmagent"
"google.golang.org/adk/model/gemini"
"google.golang.org/adk/tool"
"google.golang.org/adk/tool/agenttool"
"google.golang.org/genai"
)
--8<-- "examples/go/snippets/tools/function-tools/func_tool.go:agent_tool_example"
```
=== "Java"
```java
--8<-- "examples/java/snippets/src/main/java/tools/AgentToolCustomization.java:full_code"
```
=== "Kotlin"
```kotlin
--8<-- "examples/kotlin/snippets/tools/function-tools/AgentTool.kt:agent_tool"
```
How it works
- When the
root_agentreceives the long text, its instruction tells it to use the 'summarize' tool for long texts. - The framework recognizes 'summarize' as an
AgentToolthat wraps thesummary_agent. - Behind the scenes, the
root_agentwill call thesummary_agentwith the long text as input. - The
summary_agentwill process the text according to its instruction and generate a summary. - The response from the
summary_agentis then passed back to theroot_agent. - The
root_agentcan then take the summary and formulate its final response to the user (e.g., "Here's a summary of the text: ...")