# Copyright 2025 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. ## --8<-- [start:init] import asyncio from typing import Optional, List, Dict, Any from google.adk.agents import LlmAgent from google.adk.agents.readonly_context import ReadonlyContext from google.adk.tools import BaseTool, FunctionTool from google.adk.tools.base_toolset import BaseToolset from google.adk.tools.tool_context import ToolContext from google.adk.runners import InMemoryRunner # 1. Define the individual tool functions def add_numbers(a: int, b: int, tool_context: ToolContext) -> Dict[str, Any]: """Adds two integer numbers. Args: a: The first number. b: The second number. Returns: A dictionary with the sum, e.g., {'status': 'success', 'result': 5} """ print(f"Tool: add_numbers called with a={a}, b={b}") result = a + b # Example: Storing something in tool_context state tool_context.state["last_math_operation"] = "addition" return {"status": "success", "result": result} def subtract_numbers(a: int, b: int) -> Dict[str, Any]: """Subtracts the second number from the first. Args: a: The first number. b: The second number. Returns: A dictionary with the difference, e.g., {'status': 'success', 'result': 1} """ print(f"Tool: subtract_numbers called with a={a}, b={b}") return {"status": "success", "result": a - b} # 2. Create the Toolset by implementing BaseToolset class SimpleMathToolset(BaseToolset): def __init__(self, prefix: str = "math"): self.prefix = prefix super().__init__(tool_name_prefix=self.prefix) # Toolset can customize names by passing a prefix # Create FunctionTool instances once self._add_tool = FunctionTool( func=add_numbers, ) self._subtract_tool = FunctionTool( func=subtract_numbers, ) print(f"SimpleMathToolset initialized with prefix '{self.prefix}'") async def get_tools( self, readonly_context: Optional[ReadonlyContext] = None ) -> List[BaseTool]: print("SimpleMathToolset.get_tools() called.") # Example of dynamic behavior: # Could use readonly_context.state to decide which tools to return # For instance, if readonly_context.state.get("enable_advanced_math"): # return [self._add_tool, self._subtract_tool, self._multiply_tool] # For this simple example, always return both tools tools_to_return = [self._add_tool, self._subtract_tool] print(f"SimpleMathToolset providing tools: {[t.name for t in tools_to_return]}") return tools_to_return async def close(self) -> None: # No resources to clean up in this simple example print(f"SimpleMathToolset.close() called for prefix '{self.prefix}'.") await asyncio.sleep(0) # Placeholder for async cleanup if needed # 3. Define an individual tool (not part of the toolset) def greet_user(name: str = "User") -> Dict[str, str]: """Greets the user.""" print(f"Tool: greet_user called with name={name}") return {"greeting": f"Hello, {name}!"} greet_tool = FunctionTool(func=greet_user) # 4. Instantiate the toolset math_toolset_instance = SimpleMathToolset(prefix="calculator") # 5. Define an agent that uses both the individual tool and the toolset calculator_agent = LlmAgent( name="CalculatorAgent", model="gemini-flash-latest", # Replace with your desired model instruction="You are a helpful calculator and greeter. " "Use 'greet_user' for greetings. " "Use 'calculator_add_numbers' to add and 'calculator_subtract_numbers' to subtract. " "Announce the state of 'last_math_operation' if it's set.", tools=[greet_tool, math_toolset_instance], # Individual tool # Toolset instance ) # 6. Run the agent runner = InMemoryRunner(agent=calculator_agent, app_name="toolset_example_app") async def main(): print("\n--- Query 1: Greeting ---") await runner.run_debug("Hi there!") print("\n--- Query 2: Addition ---") await runner.run_debug("What is 5 plus 3?") await math_toolset_instance.close() if __name__ == "__main__": asyncio.run(main()) ## --8<-- [end:init]