diff --git a/docs/agents/custom-agents.md b/docs/agents/custom-agents.md index c54c066186..faa58fed44 100644 --- a/docs/agents/custom-agents.md +++ b/docs/agents/custom-agents.md @@ -111,7 +111,7 @@ This method orchestrates the sub-agents using standard Python async/await and co These are standard `LlmAgent` definitions, responsible for specific tasks. Their `output_key` parameter is crucial for placing results into the `session.state` where other agents or the custom orchestrator can access them. ```python -GEMINI_FLASH = "gemini-2.0-flash-exp" # Define model constant +GEMINI_FLASH = "gemini-2.0-flash" # Define model constant --8<-- "examples/python/snippets/agents/custom-agent/storyflow_agent.py:llmagents" ``` diff --git a/docs/agents/llm-agents.md b/docs/agents/llm-agents.md index 2830c8532e..63c53d021a 100644 --- a/docs/agents/llm-agents.md +++ b/docs/agents/llm-agents.md @@ -14,12 +14,12 @@ First, you need to establish what the agent *is* and what it's *for*. * **`description` (Optional, Recommended for Multi-Agent):** Provide a concise summary of the agent's capabilities. This description is primarily used by *other* LLM agents to determine if they should route a task to this agent. Make it specific enough to differentiate it from peers (e.g., "Handles inquiries about current billing statements," not just "Billing agent"). -* **`model` (Required):** Specify the underlying LLM that will power this agent's reasoning. This is a string identifier like `"gemini-2.0-flash-exp"`. The choice of model impacts the agent's capabilities, cost, and performance. See the [Models](models.md) page for available options and considerations. +* **`model` (Required):** Specify the underlying LLM that will power this agent's reasoning. This is a string identifier like `"gemini-2.0-flash"`. The choice of model impacts the agent's capabilities, cost, and performance. See the [Models](models.md) page for available options and considerations. ```python # Example: Defining the basic identity capital_agent = LlmAgent( - model="gemini-2.0-flash-exp", + model="gemini-2.0-flash", name="capital_agent", description="Answers user questions about the capital city of a given country." # instruction and tools will be added next @@ -46,7 +46,7 @@ The `instruction` parameter is arguably the most critical for shaping an `LlmAge ```python # Example: Adding instructions capital_agent = LlmAgent( - model="gemini-2.0-flash-exp", + model="gemini-2.0-flash", name="capital_agent", description="Answers user questions about the capital city of a given country.", instruction="""You are an agent that provides the capital city of a country. @@ -84,7 +84,7 @@ def get_capital_city(country: str) -> str: # Add the tool to the agent capital_agent = LlmAgent( - model="gemini-2.0-flash-exp", + model="gemini-2.0-flash", name="capital_agent", description="Answers user questions about the capital city of a given country.", instruction="""You are an agent that provides the capital city of a country... (previous instruction text)""", diff --git a/docs/agents/models.md b/docs/agents/models.md index 826b1f2fe7..8fbb10b197 100644 --- a/docs/agents/models.md +++ b/docs/agents/models.md @@ -13,46 +13,55 @@ The following sections guide you through using these methods based on your needs This is the most direct way to use Google's flagship models within ADK. -**Integration Method:** Pass the model's identifier string directly to the `model` parameter of `LlmAgent`. +**Integration Method:** Pass the model's identifier string directly to the `model` parameter of `LlmAgent` (or its alias, `Agent`). **Backend Options & Setup:** -The `google-genai` library, used internally by ADK for Gemini, can connect through two backends: +The `google-genai` library, used internally by ADK for Gemini, can connect through either Google AI Studio or Vertex AI. -1. **Google AI Studio:** - * **Use Case:** Best for rapid prototyping and development. - * **Setup:** Typically requires an API key set as an environment variable: +!!!note "Model support for voice/video streaming" - ```shell - export GOOGLE_API_KEY="YOUR_GOOGLE_API_KEY" - export GOOGLE_GENAI_USE_VERTEXAI=FALSE - ``` + In order to use voice/video streaming in ADK, you will need to use Gemini models that support the Live API. You can find the **model ID(s)** that supports the Gemini Live API in the documentation: + + - [Google AI Studio: Gemini Live API](https://ai.google.dev/gemini-api/docs/models#live-api) + - [Vertex AI: Gemini Live API](https://cloud.google.com/vertex-ai/generative-ai/docs/live-api) + +### Google AI Studio + +* **Use Case:** Google AI Studio is the easiest way to started with Gemini. All you need is the [API key](https://aistudio.google.com/app/apikey). Best for rapid prototyping and development. +* **Setup:** Typically requires an API key set as an environment variable: + +```shell +export GOOGLE_API_KEY="YOUR_GOOGLE_API_KEY" +export GOOGLE_GENAI_USE_VERTEXAI=FALSE +``` - * **Models:** Find available models on the [Google AI for Developers site](https://ai.google.dev/gemini-api/docs/models). +* **Models:** Find all available models on the [Google AI for Developers site](https://ai.google.dev/gemini-api/docs/models). -2. **Vertex AI:** - * **Use Case:** Recommended for production applications, leveraging Google Cloud infrastructure. - * **Setup:** - * Authenticate using Application Default Credentials (ADC): +### Vertex AI - ```shell - gcloud auth application-default login - ``` +* **Use Case:** Recommended for production applications, leveraging Google Cloud infrastructure. Gemini on Vertex AI supports enterprise-grade features, security, and compliance controls. +* **Setup:** + * Authenticate using Application Default Credentials (ADC): - * Set your Google Cloud project and location: + ```shell + gcloud auth application-default login + ``` - ```shell - export GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID" - export GOOGLE_CLOUD_LOCATION="YOUR_VERTEX_AI_LOCATION" # e.g., us-central1 - ``` + * Set your Google Cloud project and location: - * Explicitly tell the library to use Vertex AI: + ```shell + export GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID" + export GOOGLE_CLOUD_LOCATION="YOUR_VERTEX_AI_LOCATION" # e.g., us-central1 + ``` - ```shell - export GOOGLE_GENAI_USE_VERTEXAI=TRUE - ``` + * Explicitly tell the library to use Vertex AI: + + ```shell + export GOOGLE_GENAI_USE_VERTEXAI=TRUE + ``` - * **Models:** Find available model IDs in the [Vertex AI documentation](https://cloud.google.com/vertex-ai/generative-ai/docs/learn/models). +* **Models:** Find available model IDs in the [Vertex AI documentation](https://cloud.google.com/vertex-ai/generative-ai/docs/learn/models). **Example:** @@ -62,7 +71,7 @@ from google.adk.agents import LlmAgent # --- Example using a stable Gemini Flash model --- agent_gemini_flash = LlmAgent( # Use the latest stable Flash model identifier - model="gemini-2.0-flash-exp", + model="gemini-2.0-flash", name="gemini_flash_agent", instruction="You are a fast and helpful Gemini assistant.", # ... other agent parameters diff --git a/docs/agents/multi-agents.md b/docs/agents/multi-agents.md index a0d78d98e1..69a18b2bd1 100644 --- a/docs/agents/multi-agents.md +++ b/docs/agents/multi-agents.md @@ -29,13 +29,13 @@ The foundation for structuring multi-agent systems is the parent-child relations from google.adk.agents import LlmAgent, BaseAgent # Define individual agents -greeter = LlmAgent(name="Greeter", model="gemini-2.0-flash-exp") +greeter = LlmAgent(name="Greeter", model="gemini-2.0-flash") task_doer = BaseAgent(name="TaskExecutor") # Custom non-LLM agent # Create parent agent and assign children via sub_agents coordinator = LlmAgent( name="Coordinator", - model="gemini-2.0-flash-exp", + model="gemini-2.0-flash", description="I coordinate greetings and tasks.", sub_agents=[ # Assign sub_agents here greeter, @@ -196,7 +196,7 @@ image_tool = AgentTool(agent=image_agent) # Wrap the agent # Parent agent uses the AgentTool artist_agent = LlmAgent( name="Artist", - model="gemini-2.0-flash-exp", + model="gemini-2.0-flash", instruction="Create a prompt and use the ImageGen tool to generate the image.", tools=[image_tool] # Include the AgentTool ) @@ -229,7 +229,7 @@ support_agent = LlmAgent(name="Support", description="Handles technical support coordinator = LlmAgent( name="HelpDeskCoordinator", - model="gemini-2.0-flash-exp", + model="gemini-2.0-flash", instruction="Route user requests: Use Billing agent for payment issues, Support agent for technical problems.", description="Main help desk router.", # allow_transfer=True is often implicit with sub_agents in AutoFlow @@ -317,7 +317,7 @@ summarizer = LlmAgent(name="Summarizer", description="Summarizes text.") # Mid-level agent combining tools research_assistant = LlmAgent( name="ResearchAssistant", - model="gemini-2.0-flash-exp", + model="gemini-2.0-flash", description="Finds and summarizes information on a topic.", tools=[AgentTool(agent=web_searcher), AgentTool(agent=summarizer)] ) @@ -325,7 +325,7 @@ research_assistant = LlmAgent( # High-level agent delegating research report_writer = LlmAgent( name="ReportWriter", - model="gemini-2.0-flash-exp", + model="gemini-2.0-flash", instruction="Write a report on topic X. Use the ResearchAssistant to gather information.", tools=[AgentTool(agent=research_assistant)] # Alternatively, could use LLM Transfer if research_assistant is a sub_agent diff --git a/docs/get-started/quickstart-streaming.md b/docs/get-started/quickstart-streaming.md index 1bf8a2f674..0ee4a527ba 100644 --- a/docs/get-started/quickstart-streaming.md +++ b/docs/get-started/quickstart-streaming.md @@ -1,9 +1,16 @@ # ADK Streaming Quickstart {#adk-streaming-quickstart} -With this quickstart, you'll learn to create a simple agent and use ADK Streaming to enable audio and video communication with it. We will install ADK, set up a basic "Google Search" agent, try running the agent with Streaming with `adk web` tool, and then explain how to build a simple asynchronous web app by yourself using ADK Streaming and [FastAPI](https://fastapi.tiangolo.com/). +With this quickstart, you'll learn to create a simple agent and use ADK Streaming to enable voice and video communication with it that is low-latency and bidirectional. We will install ADK, set up a basic "Google Search" agent, try running the agent with Streaming with `adk web` tool, and then explain how to build a simple asynchronous web app by yourself using ADK Streaming and [FastAPI](https://fastapi.tiangolo.com/). **Note:** This guide assumes you have experience using a terminal in Windows, Mac, and Linux environments. +## Supported models for voice/video streaming {#supported-models} + +In order to use voice/video streaming in ADK, you will need to use Gemini models that support the Live API. You can find the **model ID(s)** that supports the Gemini Live API in the documentation: + +- [Google AI Studio: Gemini Live API](https://ai.google.dev/gemini-api/docs/models#live-api) +- [Vertex AI: Gemini Live API](https://cloud.google.com/vertex-ai/generative-ai/docs/live-api) + ## 1. Setup Environment & Install ADK {#1.-setup-installation} Create & Activate Virtual Environment (Recommended): @@ -38,7 +45,9 @@ adk-streaming/ # Project folder ### agent.py -Copy-paste the following code block to the [`agent.py`](http://agent.py). Please note that ADK Streaming works with `gemini-2.0-flash-exp` model only. +Copy-paste the following code block to the [`agent.py`](http://agent.py). + +For `model`, please double check the model ID as described earlier in the [Models section](#supported-models). ```py from google.adk.agents import Agent @@ -48,7 +57,8 @@ root_agent = Agent( # A unique name for the agent. name="basic_search_agent", # The Large Language Model (LLM) that agent will use. - model="gemini-2.0-flash-exp", + model="gemini-2.0-flash-live-001", # Google AI Studio + #model="gemini-2.0-flash-live-preview-04-09" # Vertex AI Studio # A short description of the agent's purpose. description="Agent to answer questions using Google Search.", # Instructions to set the agent's behavior. diff --git a/docs/get-started/quickstart.md b/docs/get-started/quickstart.md index bf99787dc2..5391cbd987 100644 --- a/docs/get-started/quickstart.md +++ b/docs/get-started/quickstart.md @@ -182,16 +182,25 @@ There are multiple ways to interact with your agent: ![adk-web-dev-ui-function-call.png](../assets/adk-web-dev-ui-function-call.png) **Step 5.** You can also enable your microphone and talk to your agent: + + !!!note "Model support for voice/video streaming" + + In order to use voice/video streaming in ADK, you will need to use Gemini models that support the Live API. You can find the **model ID(s)** that supports the Gemini Live API in the documentation: + + - [Google AI Studio: Gemini Live API](https://ai.google.dev/gemini-api/docs/models#live-api) + - [Vertex AI: Gemini Live API](https://cloud.google.com/vertex-ai/generative-ai/docs/live-api) + + You can then replace the `model` string in `root_agent` in the `agent.py` file you created earlier ([jump to section](#agentpy)). Your code should look something like: + + ```py + root_agent = Agent( + name="weather_time_agent", + model="replace-me-with-model-id", #e.g. gemini-2.0-flash-live-001 + ... + ``` ![adk-web-dev-ui-audio.png](../assets/adk-web-dev-ui-audio.png) - !!!note "Model support" - - Currently only `gemini-2.0-flash-exp` supports talking to your agent via - audio/video, and can be used either with your API key from Google AI - Studio or via - [Vertex AI](https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal-live-api). - === "Terminal (adk run)" Run the following command, to chat with your Google Search agent. diff --git a/docs/get-started/tutorial.md b/docs/get-started/tutorial.md index 0087ce5c34..1ca7eb1168 100644 --- a/docs/get-started/tutorial.md +++ b/docs/get-started/tutorial.md @@ -142,10 +142,9 @@ os.environ["GOOGLE_GENAI_USE_VERTEXAI"] = "False" ### Define Model Constants for easier use ``` +MODEL_GEMINI_2_0_FLASH = "gemini-2.0-flash" -MODEL_GEMINI_2_0_FLASH = "gemini-2.0-flash-exp" - -# Note: Specific model names might change. Refer to LiteLLM/Provider documentation. +# Note: Specific model names might change. Refer to LiteLLM or the model provider's documentation. MODEL_GPT_4O = "openai/gpt-4o" MODEL_CLAUDE_SONNET = "anthropic/claude-3-sonnet-20240229" diff --git a/docs/guides/responsible-agents.md b/docs/guides/responsible-agents.md index 40f15ea755..047b50d146 100644 --- a/docs/guides/responsible-agents.md +++ b/docs/guides/responsible-agents.md @@ -156,7 +156,7 @@ def validate_tool_params( # Hypothetical Agent setup root_agent = LlmAgent( # Use specific agent type - model='gemini-2.0-flash-exp', + model='gemini-2.0-flash', name='root_agent', instruction="...", before_tool_callback=validate_tool_params, # Assign the callback diff --git a/docs/sessions/memory.md b/docs/sessions/memory.md index 432e1a887f..90b04ff3d1 100644 --- a/docs/sessions/memory.md +++ b/docs/sessions/memory.md @@ -85,7 +85,7 @@ This example demonstrates the basic flow using the `InMemory` services for simpl # --- Constants --- APP_NAME = "memory_example_app" USER_ID = "mem_user" - MODEL = "gemini-2.0-flash-exp" # Use a valid model + MODEL = "gemini-2.0-flash" # Use a valid model # --- Agent Definitions --- # Agent 1: Simple agent to capture information diff --git a/docs/sessions/state.md b/docs/sessions/state.md index 6012def6a0..1af1eb8458 100644 --- a/docs/sessions/state.md +++ b/docs/sessions/state.md @@ -81,7 +81,7 @@ from google.genai.types import Content, Part # Define agent with output_key greeting_agent = LlmAgent( name="Greeter", - model="gemini-2.0-flash-exp", # Use a valid model + model="gemini-2.0-flash", # Use a valid model instruction="Generate a short, friendly greeting.", output_key="last_greeting" # Save response to state['last_greeting'] ) diff --git a/docs/tools/google-cloud-tools.md b/docs/tools/google-cloud-tools.md index fba718f943..a1976ab673 100644 --- a/docs/tools/google-cloud-tools.md +++ b/docs/tools/google-cloud-tools.md @@ -83,7 +83,7 @@ Note: this tutorial includes an agent creation. If you already have an agent, yo from .tools import sample_toolset root_agent = LlmAgent( - model='gemini-2.0-flash-exp', + model='gemini-2.0-flash', name='enterprise_assistant', instruction='Help user, leverage the tools you have access to', tools=sample_toolset.get_tools(),) @@ -169,7 +169,7 @@ When running the agent, make sure to run adk web in project\_root\_folder from .tools import connector_tool root_agent = LlmAgent( - model='gemini-2.0-flash-exp', + model='gemini-2.0-flash', name='connector_agent', instruction="Help user, leverage the tools you have access to", tools=connector_tool.get_tools(), @@ -217,7 +217,7 @@ When running the agent, make sure to run adk web in project\_root\_folder from .tools import integration_tool, connector_tool root_agent = LlmAgent( - model='gemini-2.0-flash-exp', + model='gemini-2.0-flash', name='integration_agent', instruction="Help user, leverage the tools you have access to", tools=integration_tool.get_tools(), diff --git a/docs/tools/mcp-tools.md b/docs/tools/mcp-tools.md index 9c7626a424..01c3af9cdc 100644 --- a/docs/tools/mcp-tools.md +++ b/docs/tools/mcp-tools.md @@ -234,7 +234,7 @@ async def get_agent_async(): tools, exit_stack = await get_tools_async() print(f"Fetched {len(tools)} tools from MCP server.") root_agent = LlmAgent( - model='gemini-2.0-flash-exp', # Adjust if needed + model='gemini-2.0-flash', # Adjust if needed name='maps_assistant', instruction='Help user with mapping and directions using available tools.', tools=tools, diff --git a/docs/tools/openapi-tools.md b/docs/tools/openapi-tools.md index f7de5ee564..8f12163814 100644 --- a/docs/tools/openapi-tools.md +++ b/docs/tools/openapi-tools.md @@ -70,7 +70,7 @@ Follow these steps to integrate an OpenAPI spec into your agent: my_agent = LlmAgent( name="api_interacting_agent", - model="gemini-2.0-flash-exp", # Or your preferred model + model="gemini-2.0-flash", # Or your preferred model tools=api_tools, # Pass the list of generated tools # ... other agent config ... ) diff --git a/docs/tools/third-party-tools.md b/docs/tools/third-party-tools.md index 8333ed82ab..e841acca3c 100644 --- a/docs/tools/third-party-tools.md +++ b/docs/tools/third-party-tools.md @@ -55,7 +55,7 @@ ADK provides the `LangchainTool` wrapper to integrate tools from the LangChain e # Define the ADK agent, including the wrapped tool my_agent = Agent( name="langchain_tool_agent", - model="gemini-2.0-flash-exp", + model="gemini-2.0-flash", description="Agent to answer questions using TavilySearch.", instruction="I can answer your questions by searching the internet. Just ask me anything!", tools=[adk_tavily_tool] # Add the wrapped tool here @@ -125,7 +125,7 @@ ADK provides the `CrewaiTool` wrapper to integrate tools from the CrewAI library # Define the ADK agent my_agent = Agent( name="crewai_search_agent", - model="gemini-2.0-flash-exp", + model="gemini-2.0-flash", description="Agent to find recent news using the Serper search tool.", instruction="I can find the latest news for you. What topic are you interested in?", tools=[adk_serper_tool] # Add the wrapped tool here diff --git a/examples/python/notebooks/adk_tutorial.ipynb b/examples/python/notebooks/adk_tutorial.ipynb index b107339818..cb3750dcf3 100644 --- a/examples/python/notebooks/adk_tutorial.ipynb +++ b/examples/python/notebooks/adk_tutorial.ipynb @@ -1,22 +1,10 @@ { - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "provenance": [], - "toc_visible": true - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "language_info": { - "name": "python" - } - }, "cells": [ { "cell_type": "markdown", + "metadata": { + "id": "Np0plMPXRvoq" + }, "source": [ "# Build Your First Intelligent Agent Team: A Progressive Weather Bot with ADK\n", "\n", @@ -58,10 +46,7 @@ "* ✅ **API Keys** for the LLMs you intend to use (e.g., Google AI Studio for Gemini, OpenAI Platform, Anthropic Console).\n", "\n", "**Ready to build your agent team? Let's dive in!**" - ], - "metadata": { - "id": "Np0plMPXRvoq" - } + ] }, { "cell_type": "code", @@ -82,6 +67,11 @@ }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "sbwxKypOSBkN" + }, + "outputs": [], "source": [ "# @title Import necessary libraries\n", "import os\n", @@ -100,15 +90,15 @@ "logging.basicConfig(level=logging.ERROR)\n", "\n", "print(\"Libraries imported.\")" - ], - "metadata": { - "id": "sbwxKypOSBkN" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "3mNsVI5eSDOi" + }, + "outputs": [], "source": [ "# @title Configure API Keys (Replace with your actual keys!)\n", "\n", @@ -135,19 +125,19 @@ "\n", "\n", "# @markdown **Security Note:** It's best practice to manage API keys securely (e.g., using Colab Secrets or environment variables) rather than hardcoding them directly in the notebook. Replace the placeholder strings above." - ], - "metadata": { - "id": "3mNsVI5eSDOi" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "MI_qvZJrSJuR" + }, + "outputs": [], "source": [ "# --- Define Model Constants for easier use ---\n", "\n", - "MODEL_GEMINI_2_0_FLASH = \"gemini-2.0-flash-exp\"\n", + "MODEL_GEMINI_2_0_FLASH = \"gemini-2.0-flash\"\n", "\n", "# Note: Specific model names might change. Refer to LiteLLM/Provider documentation.\n", "MODEL_GPT_4O = \"openai/gpt-4o\"\n", @@ -155,15 +145,13 @@ "\n", "\n", "print(\"\\nEnvironment configured.\")" - ], - "metadata": { - "id": "MI_qvZJrSJuR" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "F7LZM3ysSOMu" + }, "source": [ "---\n", "\n", @@ -190,13 +178,15 @@ "* *What information* it returns.\n", "\n", "**Best Practice:** Write clear, descriptive, and accurate docstrings for your tools. This is essential for the LLM to use the tool correctly." - ], - "metadata": { - "id": "F7LZM3ysSOMu" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ILy7YTCbSRAT" + }, + "outputs": [], "source": [ "# @title Define the get_weather Tool\n", "def get_weather(city: str) -> dict:\n", @@ -229,15 +219,13 @@ "# Example tool usage (optional test)\n", "print(get_weather(\"New York\"))\n", "print(get_weather(\"Paris\"))" - ], - "metadata": { - "id": "ILy7YTCbSRAT" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "hAM0BqGWSTo5" + }, "source": [ "---\n", "\n", @@ -256,13 +244,15 @@ "**Best Practice:** Provide clear and specific `instruction` prompts. The more detailed the instructions, the better the LLM can understand its role and how to use its tools effectively. Be explicit about error handling if needed.\n", "\n", "**Best Practice:** Choose descriptive `name` and `description` values. These are used internally by ADK and are vital for features like automatic delegation (covered later)." - ], - "metadata": { - "id": "hAM0BqGWSTo5" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "6Ho1COmKSUeV" + }, + "outputs": [], "source": [ "# @title Define the Weather Agent\n", "# Use one of the model constants defined earlier\n", @@ -281,15 +271,13 @@ ")\n", "\n", "print(f\"Agent '{weather_agent.name}' created using model '{AGENT_MODEL}'.\")" - ], - "metadata": { - "id": "6Ho1COmKSUeV" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "Dvz7LDhbSZxL" + }, "source": [ "---\n", "\n", @@ -299,13 +287,15 @@ "\n", "* `SessionService`: Responsible for managing conversation history and state for different users and sessions. The `InMemorySessionService` is a simple implementation that stores everything in memory, suitable for testing and simple applications. It keeps track of the messages exchanged. We'll explore state persistence more in Step 4\\. \n", "* `Runner`: The engine that orchestrates the interaction flow. It takes user input, routes it to the appropriate agent, manages calls to the LLM and tools based on the agent's logic, handles session updates via the `SessionService`, and yields events representing the progress of the interaction." - ], - "metadata": { - "id": "Dvz7LDhbSZxL" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "h30dNtqMSah5" + }, + "outputs": [], "source": [ "# @title Setup Session Service and Runner\n", "\n", @@ -335,15 +325,13 @@ " session_service=session_service # Uses our session manager\n", ")\n", "print(f\"Runner created for agent '{runner.agent.name}'.\")" - ], - "metadata": { - "id": "h30dNtqMSah5" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "5zKGVwRkSduA" + }, "source": [ "---\n", "\n", @@ -360,13 +348,15 @@ "5. Identifies and prints the **final response** event using `event.is_final_response()`.\n", "\n", "**Why `async`?** Interactions with LLMs and potentially tools (like external APIs) are I/O-bound operations. Using `asyncio` allows the program to handle these operations efficiently without blocking execution." - ], - "metadata": { - "id": "5zKGVwRkSduA" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "yZJr8lbkSebH" + }, + "outputs": [], "source": [ "# @title Define Agent Interaction Function\n", "\n", @@ -398,15 +388,13 @@ " break # Stop processing events once the final response is found\n", "\n", " print(f\"<<< Agent Response: {final_response_text}\")" - ], - "metadata": { - "id": "yZJr8lbkSebH" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "Z6DQSqrqk5ic" + }, "source": [ "---\n", "\n", @@ -419,13 +407,15 @@ "* See the user queries. \n", "* Notice the `--- Tool: get_weather called... ---` logs when the agent uses the tool. \n", "* Observe the agent's final responses, including how it handles the case where weather data isn't available (for Paris)." - ], - "metadata": { - "id": "Z6DQSqrqk5ic" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "mEd2QhHyUKY8" + }, + "outputs": [], "source": [ "# @title Run the Initial Conversation\n", "\n", @@ -448,28 +438,26 @@ "\n", "# Execute the conversation using await in an async context (like Colab/Jupyter)\n", "await run_conversation()" - ], - "metadata": { - "id": "mEd2QhHyUKY8" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "xbUzAGvsmB2a" + }, "source": [ "---\n", "\n", "Congratulations\\! You've successfully built and interacted with your first ADK agent. It understands the user's request, uses a tool to find information, and responds appropriately based on the tool's result.\n", "\n", "In the next step, we'll explore how to easily switch the underlying Language Model powering this agent." - ], - "metadata": { - "id": "xbUzAGvsmB2a" - } + ] }, { "cell_type": "markdown", + "metadata": { + "id": "HEPaI-beSh8P" + }, "source": [ "## Step 2: Going Multi-Model with LiteLLM\n", "\n", @@ -487,38 +475,38 @@ "1. Learn how to configure an ADK `Agent` to use models from providers like OpenAI (GPT) and Anthropic (Claude) using the `LiteLlm` wrapper.\n", "2. Define, configure (with their own sessions and runners), and immediately test instances of our Weather Agent, each backed by a different LLM.\n", "3. Interact with these different agents to observe potential variations in their responses, even when using the same underlying tool." - ], - "metadata": { - "id": "HEPaI-beSh8P" - } + ] }, { "cell_type": "markdown", + "metadata": { + "id": "OvfhdrCDnPMn" + }, "source": [ "---\n", "\n", "**1\\. Import `LiteLlm`**\n", "\n", "We imported this during the initial setup (Step 0), but it's the key component for multi-model support:" - ], - "metadata": { - "id": "OvfhdrCDnPMn" - } + ] }, { "cell_type": "code", - "source": [ - "# @title 1. Import LiteLlm\n", - "from google.adk.models.lite_llm import LiteLlm" - ], + "execution_count": null, "metadata": { "id": "mPBr56NSnMje" }, - "execution_count": null, - "outputs": [] + "outputs": [], + "source": [ + "# @title 1. Import LiteLlm\n", + "from google.adk.models.lite_llm import LiteLlm" + ] }, { "cell_type": "markdown", + "metadata": { + "id": "NoUbe1mZnXd9" + }, "source": [ "**2\\. Define and Test Multi-Model Agents**\n", "\n", @@ -539,13 +527,15 @@ "**Error Handling:** We wrap the agent definitions in `try...except` blocks. This prevents the entire code cell from failing if an API key for a specific provider is missing or invalid, allowing the tutorial to proceed with the models that *are* configured.\n", "\n", "First, let's create and test the agent using OpenAI's GPT-4o." - ], - "metadata": { - "id": "NoUbe1mZnXd9" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "C2WvKj4_Sp2J" + }, + "outputs": [], "source": [ "# @title Define and Test GPT Agent\n", "\n", @@ -603,24 +593,24 @@ "\n", "except Exception as e:\n", " print(f\"❌ Could not create or run GPT agent '{MODEL_GPT_4O}'. Check API Key and model name. Error: {e}\")\n" - ], - "metadata": { - "id": "C2WvKj4_Sp2J" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", - "source": [ - "Next, we'll do the same for Anthropic's Claude Sonnet." - ], "metadata": { "id": "Gu_OHirKWFXN" - } + }, + "source": [ + "Next, we'll do the same for Anthropic's Claude Sonnet." + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "7zqJIS4_nhoh" + }, + "outputs": [], "source": [ "# @title Define and Test Claude Agent\n", "\n", @@ -679,15 +669,13 @@ "\n", "except Exception as e:\n", " print(f\"❌ Could not create or run Claude agent '{MODEL_CLAUDE_SONNET}'. Check API Key and model name. Error: {e}\")" - ], - "metadata": { - "id": "7zqJIS4_nhoh" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "xsroj8NzWMU9" + }, "source": [ "Observe the output carefully from both code blocks. You should see:\n", "\n", @@ -702,13 +690,13 @@ "In the next step, we'll move beyond a single agent and build a small team where agents can delegate tasks to each other!\n", "\n", "---" - ], - "metadata": { - "id": "xsroj8NzWMU9" - } + ] }, { "cell_type": "markdown", + "metadata": { + "id": "tL5estZ_VKki" + }, "source": [ "## Step 3: Building an Agent Team \\- Delegation for Greetings & Farewells\n", "\n", @@ -734,26 +722,28 @@ "3. Update our main weather agent (`weather_agent_v2`) to act as the **root agent**. \n", "4. Configure the root agent with its sub-agents, enabling **automatic delegation**. \n", "5. Test the delegation flow by sending different types of requests to the root agent." - ], - "metadata": { - "id": "tL5estZ_VKki" - } + ] }, { "cell_type": "markdown", + "metadata": { + "id": "tLpXYXxppB4S" + }, "source": [ "---\n", "\n", "**1\\. Define Tools for Sub-Agents**\n", "\n", "First, let's create the simple Python functions that will serve as tools for our new specialist agents. Remember, clear docstrings are vital for the agents that will use them." - ], - "metadata": { - "id": "tLpXYXxppB4S" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Qc7dHr4ZVM6X" + }, + "outputs": [], "source": [ "# @title Define Tools for Greeting and Farewell Agents\n", "\n", @@ -782,15 +772,13 @@ "# Optional self-test\n", "print(say_hello(\"Alice\"))\n", "print(say_goodbye())" - ], - "metadata": { - "id": "Qc7dHr4ZVM6X" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "lkv34_tMVPG3" + }, "source": [ "---\n", "\n", @@ -803,13 +791,15 @@ "**Best Practice:** Sub-agent `description` fields should accurately and concisely summarize their specific capability. This is crucial for effective automatic delegation.\n", "\n", "**Best Practice:** Sub-agent `instruction` fields should be tailored to their limited scope, telling them exactly what to do and *what not* to do (e.g., \"Your *only* task is...\")." - ], - "metadata": { - "id": "lkv34_tMVPG3" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "tgT7P1doVRA0" + }, + "outputs": [], "source": [ "# @title Define Greeting and Farewell Sub-Agents\n", "\n", @@ -852,15 +842,13 @@ " print(f\"✅ Agent '{farewell_agent.name}' created using model '{MODEL_GPT_4O}'.\")\n", "except Exception as e:\n", " print(f\"❌ Could not create Farewell agent. Check API Key ({MODEL_GPT_4O}). Error: {e}\")" - ], - "metadata": { - "id": "tgT7P1doVRA0" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "IFL_TLFPVS5P" + }, "source": [ "---\n", "\n", @@ -874,13 +862,15 @@ "**Key Concept: Automatic Delegation (Auto Flow)** By providing the `sub_agents` list, ADK enables automatic delegation. When the root agent receives a user query, its LLM considers not only its own instructions and tools but also the `description` of each sub-agent. If the LLM determines that a query aligns better with a sub-agent's described capability (e.g., \"Handles simple greetings\"), it will automatically generate a special internal action to *transfer control* to that sub-agent for that turn. The sub-agent then processes the query using its own model, instructions, and tools.\n", "\n", "**Best Practice:** Ensure the root agent's instructions clearly guide its delegation decisions. Mention the sub-agents by name and describe the conditions under which delegation should occur." - ], - "metadata": { - "id": "IFL_TLFPVS5P" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "nniWunchVV8_" + }, + "outputs": [], "source": [ "# @title Define the Root Agent with Sub-Agents\n", "\n", @@ -917,15 +907,13 @@ " if not farewell_agent: print(\" - Farewell Agent is missing.\")\n", " if 'get_weather' not in globals(): print(\" - get_weather function is missing.\")\n", "\n" - ], - "metadata": { - "id": "nniWunchVV8_" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "Yg-IjZYVVYXe" + }, "source": [ "---\n", "\n", @@ -949,13 +937,15 @@ "4. The \"What is the weather in New York?\" query is *not* delegated and is handled directly by the root agent using its `get_weather` tool.\n", "5. The \"Thanks, bye!\" query is delegated to the `farewell_agent`, which uses its `say_goodbye` tool.\n", "\n" - ], - "metadata": { - "id": "Yg-IjZYVVYXe" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "t9Wy4ai8VZ7H" + }, + "outputs": [], "source": [ "# @title Interact with the Agent Team\n", "\n", @@ -1022,15 +1012,13 @@ " await run_team_conversation()\n", "else:\n", " print(\"\\n⚠️ Skipping agent team conversation as the root agent was not successfully defined in the previous step.\")\n" - ], - "metadata": { - "id": "t9Wy4ai8VZ7H" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "Zgw3Cn2NVcI7" + }, "source": [ "---\n", "\n", @@ -1043,13 +1031,13 @@ "This confirms successful **automatic delegation**! The root agent, guided by its instructions and the `description`s of its `sub_agents`, correctly routed user requests to the appropriate specialist agent within the team.\n", "\n", "You've now structured your application with multiple collaborating agents. This modular design is fundamental for building more complex and capable agent systems. In the next step, we'll give our agents the ability to remember information across turns using session state." - ], - "metadata": { - "id": "Zgw3Cn2NVcI7" - } + ] }, { "cell_type": "markdown", + "metadata": { + "id": "s7gD2sCy1qWz" + }, "source": [ "## Step 4: Adding Memory and Personalization with Session State\n", "\n", @@ -1073,26 +1061,28 @@ "3. Creating a state-aware version of the weather tool (`get_weather_stateful`) that reads this preference via `ToolContext` and adjusts its output format (Celsius/Fahrenheit). \n", "4. Updating the root agent to use this stateful tool and configuring it with an `output_key` to automatically save its final weather report to the session state. \n", "5. Running a conversation to observe how the initial state affects the tool, how manual state changes alter subsequent behavior, and how `output_key` persists the agent's response." - ], - "metadata": { - "id": "s7gD2sCy1qWz" - } + ] }, { "cell_type": "markdown", + "metadata": { + "id": "HsIjxunW1xeO" + }, "source": [ "---\n", "\n", "**1\\. Initialize New Session Service and State**\n", "\n", "To clearly demonstrate state management without interference from prior steps, we'll instantiate a new `InMemorySessionService`. We'll also create a session with an initial state defining the user's preferred temperature unit." - ], - "metadata": { - "id": "HsIjxunW1xeO" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "wt21ea6ctFT5" + }, + "outputs": [], "source": [ "# @title 1. Initialize New Session Service and State\n", "\n", @@ -1130,15 +1120,13 @@ " print(retrieved_session.state)\n", "else:\n", " print(\"Error: Could not retrieve session.\")" - ], - "metadata": { - "id": "wt21ea6ctFT5" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "652bNx3H16lJ" + }, "source": [ "---\n", "\n", @@ -1151,13 +1139,15 @@ "\n", "\n", "* **Best Practice:** When reading from state, use `dictionary.get('key', default_value)` to handle cases where the key might not exist yet, ensuring your tool doesn't crash." - ], - "metadata": { - "id": "652bNx3H16lJ" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "zK11GeWftFRC" + }, + "outputs": [], "source": [ "from google.adk.tools.tool_context import ToolContext\n", "\n", @@ -1207,15 +1197,13 @@ " return {\"status\": \"error\", \"error_message\": error_msg}\n", "\n", "print(\"✅ State-aware 'get_weather_stateful' tool defined.\")\n" - ], - "metadata": { - "id": "zK11GeWftFRC" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "UuQMolpG2Qkg" + }, "source": [ "---\n", "\n", @@ -1226,13 +1214,15 @@ "* It uses the new `get_weather_stateful` tool. \n", "* It includes the greeting and farewell sub-agents for delegation. \n", "* **Crucially**, it sets `output_key=\"last_weather_report\"` which automatically saves its final weather response to the session state." - ], - "metadata": { - "id": "UuQMolpG2Qkg" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ox3-2hwTtFOK" + }, + "outputs": [], "source": [ "# @title 3. Redefine Sub-Agents and Update Root Agent with output_key\n", "\n", @@ -1307,15 +1297,13 @@ " if not greeting_agent: print(\" - greeting_agent definition missing.\")\n", " if not farewell_agent: print(\" - farewell_agent definition missing.\")\n", " if 'get_weather_stateful' not in globals(): print(\" - get_weather_stateful tool missing.\")\n" - ], - "metadata": { - "id": "ox3-2hwTtFOK" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "P394DfSb2aOw" + }, "source": [ "---\n", "\n", @@ -1331,13 +1319,15 @@ "3. **Check weather again (New York):** The `get_weather_stateful` tool should now read the updated \"Fahrenheit\" preference from the state and convert the temperature accordingly. The root agent's *new* response (weather in Fahrenheit) will overwrite the previous value in `state['last_weather_report']` due to the `output_key`.\n", "4. **Greet the agent:** Verify that delegation to the `greeting_agent` still works correctly alongside the stateful operations. This interaction will become the *last* response saved by `output_key` in this specific sequence.\n", "5. **Inspect final state:** After the conversation, we retrieve the session one last time (getting a copy) and print its state to confirm the `user_preference_temperature_unit` is indeed \"Fahrenheit\", observe the final value saved by `output_key` (which will be the greeting in this run), and see the `last_city_checked_stateful` value written by the tool.\n" - ], - "metadata": { - "id": "P394DfSb2aOw" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "WYZfRCp0tFLT" + }, + "outputs": [], "source": [ "# @title 4. Interact to Test State Flow and output_key\n", "\n", @@ -1408,15 +1398,13 @@ "\n", "else:\n", " print(\"\\n⚠️ Skipping state test conversation. Stateful root agent runner ('runner_root_stateful') is not available.\")" - ], - "metadata": { - "id": "WYZfRCp0tFLT" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "mqiG4SAX2l8C" + }, "source": [ "---\n", "\n", @@ -1433,13 +1421,13 @@ "You've now successfully integrated session state to personalize agent behavior using `ToolContext`, manually manipulated state for testing `InMemorySessionService`, and observed how `output_key` provides a simple mechanism for saving the agent's last response to state. This foundational understanding of state management is key as we proceed to implement safety guardrails using callbacks in the next steps.\n", "\n", "---" - ], - "metadata": { - "id": "mqiG4SAX2l8C" - } + ] }, { "cell_type": "markdown", + "metadata": { + "id": "JwTcmu0oaEiI" + }, "source": [ "## Step 5: Adding Safety \\- Input Guardrail with `before_model_callback`\n", "\n", @@ -1475,26 +1463,28 @@ "2. Update our stateful root agent (`weather_agent_v4_stateful` from Step 4\\) to use this callback. \n", "3. Create a new runner associated with this updated agent but using the *same stateful session service* to maintain state continuity. \n", "4. Test the guardrail by sending both normal and keyword-containing requests." - ], - "metadata": { - "id": "JwTcmu0oaEiI" - } + ] }, { "cell_type": "markdown", + "metadata": { + "id": "G7m6zhMv4Zss" + }, "source": [ "---\n", "\n", "**1\\. Define the Guardrail Callback Function**\n", "\n", "This function will inspect the last user message within the `llm_request` content. If it finds \"BLOCK\" (case-insensitive), it constructs and returns an `LlmResponse` to block the flow; otherwise, it returns `None`. " - ], - "metadata": { - "id": "G7m6zhMv4Zss" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "JZay2mbHaHSk" + }, + "outputs": [], "source": [ "# @title 1. Define the before_model_callback Guardrail\n", "\n", @@ -1550,15 +1540,13 @@ " return None # Returning None signals ADK to continue normally\n", "\n", "print(\"✅ block_keyword_guardrail function defined.\")\n" - ], - "metadata": { - "id": "JZay2mbHaHSk" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "giawLd9VaI7G" + }, "source": [ "---\n", "\n", @@ -1567,13 +1555,15 @@ "We redefine the root agent, adding the `before_model_callback` parameter and pointing it to our new guardrail function. We'll give it a new version name for clarity.\n", "\n", "*Important:* We need to redefine the sub-agents (`greeting_agent`, `farewell_agent`) and the stateful tool (`get_weather_stateful`) within this context if they are not already available from previous steps, ensuring the root agent definition has access to all its components." - ], - "metadata": { - "id": "giawLd9VaI7G" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "IRoMmJ9V_cuH" + }, + "outputs": [], "source": [ "# @title 2. Update Root Agent with before_model_callback\n", "\n", @@ -1650,15 +1640,13 @@ " if not farewell_agent: print(\" - Farewell Agent\")\n", " if 'get_weather_stateful' not in globals(): print(\" - 'get_weather_stateful' tool\")\n", " if 'block_keyword_guardrail' not in globals(): print(\" - 'block_keyword_guardrail' callback\")" - ], - "metadata": { - "id": "IRoMmJ9V_cuH" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "R2EW2LSS4wnz" + }, "source": [ "---\n", "\n", @@ -1669,13 +1657,15 @@ "1. Send a normal weather request (should pass the guardrail and execute). \n", "2. Send a request containing \"BLOCK\" (should be intercepted by the callback). \n", "3. Send a greeting (should pass the root agent's guardrail, be delegated, and execute normally)." - ], - "metadata": { - "id": "R2EW2LSS4wnz" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "4EnMiXX8aO9n" + }, + "outputs": [], "source": [ "# @title 3. Interact to Test the Model Input Guardrail\n", "\n", @@ -1716,15 +1706,13 @@ "else:\n", " print(\"\\n⚠️ Skipping model guardrail test. Runner ('runner_root_model_guardrail') is not available.\")\n", "\n" - ], - "metadata": { - "id": "4EnMiXX8aO9n" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "e5D0KaW-aQ8z" + }, "source": [ "---\n", "\n", @@ -1735,13 +1723,13 @@ "3. **Hello Again:** The callback runs for `weather_agent_v5_model_guardrail`, allows the request. The root agent then delegates to `greeting_agent`. *Note: The `before_model_callback` defined on the root agent does NOT automatically apply to sub-agents.* The `greeting_agent` proceeds normally, calls its `say_hello` tool, and returns the greeting.\n", "\n", "You have successfully implemented an input safety layer\\! The `before_model_callback` provides a powerful mechanism to enforce rules and control agent behavior *before* expensive or potentially risky LLM calls are made. Next, we'll apply a similar concept to add guardrails around tool usage itself." - ], - "metadata": { - "id": "e5D0KaW-aQ8z" - } + ] }, { "cell_type": "markdown", + "metadata": { + "id": "ZnH5C0IRaqet" + }, "source": [ "## Step 6: Adding Safety \\- Tool Argument Guardrail (`before_tool_callback`)\n", "\n", @@ -1779,26 +1767,28 @@ "3. Update our root agent (`weather_agent_v6_tool_guardrail`) to include *both* the `before_model_callback` and this new `before_tool_callback`. \n", "4. Create a new runner for this agent, using the same stateful session service. \n", "5. Test the flow by requesting weather for allowed cities and the blocked city (\"Paris\")." - ], - "metadata": { - "id": "ZnH5C0IRaqet" - } + ] }, { "cell_type": "markdown", + "metadata": { + "id": "H5myniS17Q5q" + }, "source": [ "---\n", "\n", "**1\\. Define the Tool Guardrail Callback Function**\n", "\n", "This function targets the `get_weather_stateful` tool. It checks the `city` argument. If it's \"Paris\", it returns an error dictionary that looks like the tool's own error response. Otherwise, it allows the tool to run by returning `None`." - ], - "metadata": { - "id": "H5myniS17Q5q" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "g4wOLl6aastz" + }, + "outputs": [], "source": [ "# @title 1. Define the before_tool_callback Guardrail\n", "\n", @@ -1851,15 +1841,13 @@ "\n", "print(\"✅ block_paris_tool_guardrail function defined.\")\n", "\n" - ], - "metadata": { - "id": "g4wOLl6aastz" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "4d01OYJlauSI" + }, "source": [ "---\n", "\n", @@ -1868,13 +1856,15 @@ "We redefine the root agent again (`weather_agent_v6_tool_guardrail`), this time adding the `before_tool_callback` parameter alongside the `before_model_callback` from Step 5\\.\n", "\n", "*Self-Contained Execution Note:* Similar to Step 5, ensure all prerequisites (sub-agents, tools, `before_model_callback`) are defined or available in the execution context before defining this agent." - ], - "metadata": { - "id": "4d01OYJlauSI" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "8BVIl_3uLTZT" + }, + "outputs": [], "source": [ "# @title 2. Update Root Agent with BOTH Callbacks (Self-Contained)\n", "\n", @@ -1953,15 +1943,13 @@ "else:\n", " print(\"❌ Cannot create root agent with tool guardrail. Prerequisites missing.\")\n", "\n" - ], - "metadata": { - "id": "8BVIl_3uLTZT" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "aUo-nu657kc8" + }, "source": [ "---\n", "\n", @@ -1972,13 +1960,15 @@ "1. Request weather for \"New York\": Passes both callbacks, tool executes (using Fahrenheit preference from state). \n", "2. Request weather for \"Paris\": Passes `before_model_callback`. LLM decides to call `get_weather_stateful(city='Paris')`. `before_tool_callback` intercepts, blocks the tool, and returns the error dictionary. Agent relays this error. \n", "3. Request weather for \"London\": Passes both callbacks, tool executes normally." - ], - "metadata": { - "id": "aUo-nu657kc8" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "wpg4fzkLav1-" + }, + "outputs": [], "source": [ "# @title 3. Interact to Test the Tool Argument Guardrail\n", "\n", @@ -2017,15 +2007,13 @@ "\n", "else:\n", " print(\"\\n⚠️ Skipping tool guardrail test. Runner ('runner_root_tool_guardrail') is not available.\")" - ], - "metadata": { - "id": "wpg4fzkLav1-" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "6gCcBgMfa1VS" + }, "source": [ "---\n", "\n", @@ -2036,13 +2024,13 @@ "3. **London:** Behaves like New York, passing both callbacks and executing the tool successfully. The new London weather report overwrites the `last_weather_report` in the state.\n", "\n", "You've now added a crucial safety layer controlling not just *what* reaches the LLM, but also *how* the agent's tools can be used based on the specific arguments generated by the LLM. Callbacks like `before_model_callback` and `before_tool_callback` are essential for building robust, safe, and policy-compliant agent applications." - ], - "metadata": { - "id": "6gCcBgMfa1VS" - } + ] }, { "cell_type": "markdown", + "metadata": { + "id": "xYWtGbdI8DZw" + }, "source": [ "\n", "\n", @@ -2090,10 +2078,22 @@ "The Agent Development Kit provides a robust foundation for building sophisticated LLM-powered applications. By mastering the concepts covered in this tutorial – tools, state, delegation, and callbacks – you are well-equipped to tackle increasingly complex agentic systems.\n", "\n", "Happy building!" - ], - "metadata": { - "id": "xYWtGbdI8DZw" - } + ] } - ] -} \ No newline at end of file + ], + "metadata": { + "colab": { + "provenance": [], + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/examples/python/snippets/agents/custom-agent/storyflow_agent.py b/examples/python/snippets/agents/custom-agent/storyflow_agent.py index 321a7d74ec..2beed0eba2 100644 --- a/examples/python/snippets/agents/custom-agent/storyflow_agent.py +++ b/examples/python/snippets/agents/custom-agent/storyflow_agent.py @@ -14,7 +14,7 @@ APP_NAME = "story_app" USER_ID = "12345" SESSION_ID = "123344" -GEMINI_2_FLASH = "gemini-2.0-flash-exp" +GEMINI_2_FLASH = "gemini-2.0-flash" # --- Configure Logging --- logging.basicConfig(level=logging.INFO) diff --git a/examples/python/snippets/agents/llm-agent/capital_agent.py b/examples/python/snippets/agents/llm-agent/capital_agent.py index 9bd393c171..9a9b9ec6fc 100644 --- a/examples/python/snippets/agents/llm-agent/capital_agent.py +++ b/examples/python/snippets/agents/llm-agent/capital_agent.py @@ -12,7 +12,7 @@ USER_ID = "test_user_456" SESSION_ID_TOOL_AGENT = "session_tool_agent_xyz" SESSION_ID_SCHEMA_AGENT = "session_schema_agent_xyz" -MODEL_NAME = "gemini-2.0-flash-exp" +MODEL_NAME = "gemini-2.0-flash" # --- 2. Define Schemas --- diff --git a/examples/python/snippets/agents/workflow-agents/loop_agent_doc_improv_agent.py b/examples/python/snippets/agents/workflow-agents/loop_agent_doc_improv_agent.py index c88bc4948c..28c83831b1 100644 --- a/examples/python/snippets/agents/workflow-agents/loop_agent_doc_improv_agent.py +++ b/examples/python/snippets/agents/workflow-agents/loop_agent_doc_improv_agent.py @@ -8,7 +8,7 @@ APP_NAME = "doc_writing_app" USER_ID = "dev_user_01" SESSION_ID = "session_01" -GEMINI_MODEL = "gemini-2.0-flash-exp" +GEMINI_MODEL = "gemini-2.0-flash" # --- State Keys --- STATE_INITIAL_TOPIC = "quantum physics" diff --git a/examples/python/snippets/agents/workflow-agents/parallel_agent_web_research.py b/examples/python/snippets/agents/workflow-agents/parallel_agent_web_research.py index f63651db76..56ffcdb850 100644 --- a/examples/python/snippets/agents/workflow-agents/parallel_agent_web_research.py +++ b/examples/python/snippets/agents/workflow-agents/parallel_agent_web_research.py @@ -8,7 +8,7 @@ APP_NAME = "parallel_research_app" USER_ID = "research_user_01" SESSION_ID = "parallel_research_session" -GEMINI_MODEL = "gemini-2.0-flash-exp" +GEMINI_MODEL = "gemini-2.0-flash" # --- Define Researcher Sub-Agents --- diff --git a/examples/python/snippets/agents/workflow-agents/sequential_agent_code_development_agent.py b/examples/python/snippets/agents/workflow-agents/sequential_agent_code_development_agent.py index b881cc03b8..057f6f04d6 100644 --- a/examples/python/snippets/agents/workflow-agents/sequential_agent_code_development_agent.py +++ b/examples/python/snippets/agents/workflow-agents/sequential_agent_code_development_agent.py @@ -8,7 +8,7 @@ APP_NAME = "code_pipeline_app" USER_ID = "dev_user_01" SESSION_ID = "pipeline_session_01" -GEMINI_MODEL = "gemini-2.0-flash-exp" +GEMINI_MODEL = "gemini-2.0-flash" # --- 1. Define Sub-Agents for Each Pipeline Stage --- diff --git a/examples/python/snippets/callbacks/after_agent_callback.py b/examples/python/snippets/callbacks/after_agent_callback.py index 943978652e..22f2f1509a 100644 --- a/examples/python/snippets/callbacks/after_agent_callback.py +++ b/examples/python/snippets/callbacks/after_agent_callback.py @@ -5,7 +5,7 @@ from google.genai import types from google.adk.sessions import InMemorySessionService -GEMINI_2_FLASH="gemini-2.0-flash-exp" +GEMINI_2_FLASH="gemini-2.0-flash" # --- Define the Callback Function --- def simple_after_agent_logger(callback_context: CallbackContext) -> Optional[types.Content]: diff --git a/examples/python/snippets/callbacks/after_model_callback.py b/examples/python/snippets/callbacks/after_model_callback.py index 693aa0e685..09a05c3e53 100644 --- a/examples/python/snippets/callbacks/after_model_callback.py +++ b/examples/python/snippets/callbacks/after_model_callback.py @@ -6,7 +6,7 @@ from google.adk.sessions import InMemorySessionService from google.adk.models import LlmResponse -GEMINI_2_FLASH="gemini-2.0-flash-exp" +GEMINI_2_FLASH="gemini-2.0-flash" # --- Define the Callback Function --- def simple_after_model_modifier( diff --git a/examples/python/snippets/callbacks/after_tool_callback.py b/examples/python/snippets/callbacks/after_tool_callback.py index 4e185bb542..24447b4ffa 100644 --- a/examples/python/snippets/callbacks/after_tool_callback.py +++ b/examples/python/snippets/callbacks/after_tool_callback.py @@ -9,7 +9,7 @@ from typing import Dict, Any from copy import copy -GEMINI_2_FLASH="gemini-2.0-flash-exp" +GEMINI_2_FLASH="gemini-2.0-flash" # --- Define a Simple Tool Function (Same as before) --- def get_capital_city(country: str) -> str: diff --git a/examples/python/snippets/callbacks/before_agent_callback.py b/examples/python/snippets/callbacks/before_agent_callback.py index a7e47570ce..8dcf1bf3f1 100644 --- a/examples/python/snippets/callbacks/before_agent_callback.py +++ b/examples/python/snippets/callbacks/before_agent_callback.py @@ -5,7 +5,7 @@ from google.genai import types from google.adk.sessions import InMemorySessionService -GEMINI_2_FLASH="gemini-2.0-flash-exp" +GEMINI_2_FLASH="gemini-2.0-flash" # --- Define the Callback Function --- def simple_before_agent_logger(callback_context: CallbackContext) -> Optional[types.Content]: diff --git a/examples/python/snippets/callbacks/before_model_callback.py b/examples/python/snippets/callbacks/before_model_callback.py index c033329792..69ea552656 100644 --- a/examples/python/snippets/callbacks/before_model_callback.py +++ b/examples/python/snippets/callbacks/before_model_callback.py @@ -6,7 +6,7 @@ from google.genai import types from google.adk.sessions import InMemorySessionService -GEMINI_2_FLASH="gemini-2.0-flash-exp" +GEMINI_2_FLASH="gemini-2.0-flash" # --- Define the Callback Function --- def simple_before_model_modifier( diff --git a/examples/python/snippets/callbacks/before_tool_callback.py b/examples/python/snippets/callbacks/before_tool_callback.py index 0be21f8fd8..cb1b65de94 100644 --- a/examples/python/snippets/callbacks/before_tool_callback.py +++ b/examples/python/snippets/callbacks/before_tool_callback.py @@ -9,7 +9,7 @@ from typing import Dict, Any -GEMINI_2_FLASH="gemini-2.0-flash-exp" +GEMINI_2_FLASH="gemini-2.0-flash" def get_capital_city(country: str) -> str: """Retrieves the capital city of a given country.""" diff --git a/examples/python/snippets/callbacks/callback_basic.py b/examples/python/snippets/callbacks/callback_basic.py index 99e4c6686e..c80e90bc3b 100644 --- a/examples/python/snippets/callbacks/callback_basic.py +++ b/examples/python/snippets/callbacks/callback_basic.py @@ -15,7 +15,7 @@ def my_before_model_logic( # --- Register it during Agent creation --- my_agent = LlmAgent( name="MyCallbackAgent", - model="gemini-2.0-flash-exp", # Or your desired model + model="gemini-2.0-flash", # Or your desired model instruction="Be helpful.", # Other agent parameters... before_model_callback=my_before_model_logic # Pass the function here diff --git a/examples/python/snippets/get-started/google_search_agent/agent.py b/examples/python/snippets/get-started/google_search_agent/agent.py index 171d2b7d1b..f5922cdb39 100644 --- a/examples/python/snippets/get-started/google_search_agent/agent.py +++ b/examples/python/snippets/get-started/google_search_agent/agent.py @@ -5,7 +5,7 @@ # A unique name for the agent. name="google_search_agent", # The Large Language Model (LLM) that agent will use. - model="gemini-2.0-flash-exp", + model="gemini-2.0-flash", # A short description of the agent's purpose. description="Agent to answer questions using Google Search.", # Instructions to set the agent's behavior. diff --git a/examples/python/snippets/get-started/multi_tool_agent/agent.py b/examples/python/snippets/get-started/multi_tool_agent/agent.py index ccd44c592e..30884be683 100644 --- a/examples/python/snippets/get-started/multi_tool_agent/agent.py +++ b/examples/python/snippets/get-started/multi_tool_agent/agent.py @@ -56,7 +56,7 @@ def get_current_time(city: str) -> dict: root_agent = Agent( name="weather_time_agent", - model="gemini-2.0-flash-exp", + model="gemini-2.0-flash", description=( "Agent to answer questions about the time and weather in a city." ), diff --git a/examples/python/snippets/tools/built-in-tools/code_execution.py b/examples/python/snippets/tools/built-in-tools/code_execution.py index d14393d1c1..8ce1e959f8 100644 --- a/examples/python/snippets/tools/built-in-tools/code_execution.py +++ b/examples/python/snippets/tools/built-in-tools/code_execution.py @@ -9,7 +9,7 @@ APP_NAME="calculator" USER_ID="user1234" SESSION_ID="session_code_exec_async" -GEMINI_MODEL = "gemini-2.0-flash-exp" +GEMINI_MODEL = "gemini-2.0-flash" # Agent Definition code_agent = LlmAgent( diff --git a/examples/python/snippets/tools/built-in-tools/google_search.py b/examples/python/snippets/tools/built-in-tools/google_search.py index 5a491ebec9..e1bf515539 100644 --- a/examples/python/snippets/tools/built-in-tools/google_search.py +++ b/examples/python/snippets/tools/built-in-tools/google_search.py @@ -11,7 +11,7 @@ root_agent = Agent( name="basic_search_agent", - model="gemini-2.0-flash-exp", + model="gemini-2.0-flash", description="Agent to answer questions using Google Search.", instruction="I can answer your questions by searching the internet. Just ask me anything!", # google_search is a pre-built tool which allows the agent to perform Google searches. diff --git a/examples/python/snippets/tools/built-in-tools/vertexai_search.py b/examples/python/snippets/tools/built-in-tools/vertexai_search.py index fee6ffccd2..b48bcfbe60 100644 --- a/examples/python/snippets/tools/built-in-tools/vertexai_search.py +++ b/examples/python/snippets/tools/built-in-tools/vertexai_search.py @@ -16,7 +16,7 @@ USER_ID_VSEARCH = "user_vsearch_1" SESSION_ID_VSEARCH = "session_vsearch_1" AGENT_NAME_VSEARCH = "doc_qa_agent" -GEMINI_2_FLASH = "gemini-2.0-flash-exp" +GEMINI_2_FLASH = "gemini-2.0-flash" # Tool Instantiation # You MUST provide your datastore ID here. diff --git a/examples/python/snippets/tools/function-tools/file_processor.py b/examples/python/snippets/tools/function-tools/file_processor.py index 8827219b1f..8d9f78d1cd 100644 --- a/examples/python/snippets/tools/function-tools/file_processor.py +++ b/examples/python/snippets/tools/function-tools/file_processor.py @@ -40,7 +40,7 @@ def process_large_file(file_path: str) -> dict: # 3. Use the tool in an Agent file_processor_agent = Agent( # Use a model compatible with function calling - model="gemini-2.0-flash-exp", + model="gemini-2.0-flash", name='file_processor_agent', instruction="""You are an agent that processes large files. When the user provides a file path, use the 'process_large_file' tool. Keep the user informed about the progress based on the tool's updates (which arrive as function responses). Only provide the final result when the tool indicates completion in its final function response.""", tools=[long_running_tool] diff --git a/examples/python/snippets/tools/function-tools/func_tool.py b/examples/python/snippets/tools/function-tools/func_tool.py index abf5edae13..7cf87e7333 100644 --- a/examples/python/snippets/tools/function-tools/func_tool.py +++ b/examples/python/snippets/tools/function-tools/func_tool.py @@ -34,7 +34,7 @@ def get_stock_price(symbol: str): stock_price_agent = Agent( - model='gemini-2.0-flash-exp', + model='gemini-2.0-flash', name='stock_agent', instruction= 'You are an agent to retrieve stock prices. If a ticker symbol is provided, fetch the current price. If only a company name is given, first perform a Google search to find the correct ticker symbol before retrieving the stock price.If the provided ticker symbol is invalid or data cannot be retrieved, inform the user that the stock price could not be found.', description='You specialize in retrieving real-time stock prices. Given a stock ticker symbol (e.g., AAPL, GOOG, MSFT) or the stock name, use the tools and reliable data sources to provide the most up-to-date price.', diff --git a/examples/python/snippets/tools/function-tools/summarizer.py b/examples/python/snippets/tools/function-tools/summarizer.py index 81d82c5b6f..50a61d89cc 100644 --- a/examples/python/snippets/tools/function-tools/summarizer.py +++ b/examples/python/snippets/tools/function-tools/summarizer.py @@ -9,14 +9,14 @@ SESSION_ID="1234" summary_agent = Agent( - model="gemini-2.0-flash-exp", + model="gemini-2.0-flash", name="summary_agent", instruction="""You are an expert summarizer. Please read the following text and provide a concise summary.""", description="Agent to summarize text", ) root_agent = Agent( - model='gemini-2.0-flash-exp', + model='gemini-2.0-flash', name='root_agent', instruction="""You are a helpful assistant. When the user provides a long text, use the 'summarize' tool to get a summary and then present it to the user.""", tools=[AgentTool(agent=summary_agent)] diff --git a/examples/python/snippets/tools/openapi_tool.py b/examples/python/snippets/tools/openapi_tool.py index c0b2347198..13ef91fe74 100644 --- a/examples/python/snippets/tools/openapi_tool.py +++ b/examples/python/snippets/tools/openapi_tool.py @@ -13,7 +13,7 @@ USER_ID_OPENAPI = "user_openapi_1" SESSION_ID_OPENAPI = f"session_openapi_{uuid.uuid4()}" # Unique session ID AGENT_NAME_OPENAPI = "petstore_manager_agent" -GEMINI_MODEL = "gemini-2.0-flash-exp" +GEMINI_MODEL = "gemini-2.0-flash" # --- Sample OpenAPI Specification (JSON String) --- # A basic Pet Store API example using httpbin.org as a mock server diff --git a/examples/python/snippets/tools/overview/customer_support_agent.py b/examples/python/snippets/tools/overview/customer_support_agent.py index a4670c02b0..e2ab5f7bd3 100644 --- a/examples/python/snippets/tools/overview/customer_support_agent.py +++ b/examples/python/snippets/tools/overview/customer_support_agent.py @@ -22,14 +22,14 @@ def check_and_transfer(query: str, tool_context: ToolContext) -> str: escalation_tool = FunctionTool(func=check_and_transfer) main_agent = Agent( - model='gemini-2.0-flash-exp', + model='gemini-2.0-flash', name='main_agent', instruction="""You are the first point of contact for customer support of an analytics tool. Answer general queries. If the user indicates urgency, use the 'check_and_transfer' tool.""", tools=[check_and_transfer] ) support_agent = Agent( - model='gemini-2.0-flash-exp', + model='gemini-2.0-flash', name='support_agent', instruction="""You are the dedicated support agent. Mentioned you are a support handler and please help the user with their urgent issue.""" ) diff --git a/examples/python/snippets/tools/overview/weather_sentiment.py b/examples/python/snippets/tools/overview/weather_sentiment.py index db84109336..eb400e0a6c 100644 --- a/examples/python/snippets/tools/overview/weather_sentiment.py +++ b/examples/python/snippets/tools/overview/weather_sentiment.py @@ -7,7 +7,7 @@ APP_NAME="weather_sentiment_agent" USER_ID="user1234" SESSION_ID="1234" -MODEL_ID="gemini-2.0-flash-exp" +MODEL_ID="gemini-2.0-flash" # Tool 1 def get_weather_report(city: str) -> dict: diff --git a/examples/python/snippets/tools/third-party/crewai_serper_search.py b/examples/python/snippets/tools/third-party/crewai_serper_search.py index 98114268dc..93e3f16fdd 100644 --- a/examples/python/snippets/tools/third-party/crewai_serper_search.py +++ b/examples/python/snippets/tools/third-party/crewai_serper_search.py @@ -29,7 +29,7 @@ serper_agent = Agent( name="basic_search_agent", - model="gemini-2.0-flash-exp", + model="gemini-2.0-flash", description="Agent to answer questions using Google Search.", instruction="I can answer your questions by searching the internet. Just ask me anything!", # Add the Serper tool diff --git a/examples/python/snippets/tools/third-party/langchain_tavily_search.py b/examples/python/snippets/tools/third-party/langchain_tavily_search.py index 81c20ebcf7..bea9937e69 100644 --- a/examples/python/snippets/tools/third-party/langchain_tavily_search.py +++ b/examples/python/snippets/tools/third-party/langchain_tavily_search.py @@ -28,7 +28,7 @@ # Define Agent with the wrapped tool my_agent = Agent( name="langchain_tool_agent", - model="gemini-2.0-flash-exp", + model="gemini-2.0-flash", description="Agent to answer questions using TavilySearch.", instruction="I can answer your questions by searching the internet. Just ask me anything!", tools=[adk_tavily_tool] # Add the wrapped tool here