Files
2026-09-13 21:55:56 +00:00

9186 lines
459 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!--
Copyright 2026 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="Build powerful multi-agent systems with Agent Development Kit (ADK)">
<link rel="canonical" href="https://adk.dev/tutorials/agent-team/">
<link rel="prev" href="../multi-tool-agent/">
<link rel="next" href="../coding-with-ai/">
<link rel="icon" href="../../assets/agent-development-kit.png">
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.7.0">
<title>Agent team - Agent Development Kit (ADK)</title>
<link rel="stylesheet" href="../../assets/stylesheets/main.618322db.min.css">
<link rel="stylesheet" href="../../assets/stylesheets/palette.ab4e12ef.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
<link rel="stylesheet" href="../../stylesheets/custom.css">
<link rel="stylesheet" href="../../stylesheets/language-tags.css">
<script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
<script id="__analytics">function __md_analytics(){function e(){dataLayer.push(arguments)}window.dataLayer=window.dataLayer||[],e("js",new Date),e("config","G-DKHZS27PHP"),document.addEventListener("DOMContentLoaded",(function(){document.forms.search&&document.forms.search.query.addEventListener("blur",(function(){this.value&&e("event","search",{search_term:this.value})}));document$.subscribe((function(){var t=document.forms.feedback;if(void 0!==t)for(var a of t.querySelectorAll("[type=submit]"))a.addEventListener("click",(function(a){a.preventDefault();var n=document.location.pathname,d=this.getAttribute("data-md-value");e("event","feedback",{page:n,data:d}),t.firstElementChild.disabled=!0;var r=t.querySelector(".md-feedback__note [data-md-value='"+d+"']");r&&(r.hidden=!1)})),t.hidden=!1})),location$.subscribe((function(t){e("config","G-DKHZS27PHP",{page_path:t.pathname})}))}));var t=document.createElement("script");t.async=!0,t.src="https://www.googletagmanager.com/gtag/js?id=G-DKHZS27PHP",document.getElementById("__analytics").insertAdjacentElement("afterEnd",t)}</script>
<script>if("undefined"!=typeof __md_analytics){var consent=__md_get("__consent");consent&&consent.analytics&&__md_analytics()}</script>
<!-- HTML Meta Tags -->
<title>Agent Development Kit (ADK)</title>
<meta name="description" content="Build powerful multi-agent systems with Agent Development Kit (ADK)">
<!-- Facebook Meta Tags -->
<meta property="og:url" content="https://adk.dev">
<meta property="og:type" content="website">
<meta property="og:title" content="Agent Development Kit (ADK)">
<meta property="og:description" content="Build powerful multi-agent systems with Agent Development Kit (ADK)">
<meta property="og:image" content="https://adk.dev/assets/adk-social-card.png">
<!-- Twitter Meta Tags -->
<meta name="twitter:card" content="summary_large_image">
<meta property="twitter:domain" content="adk.dev">
<meta property="twitter:url" content="https://adk.dev">
<meta name="twitter:title" content="Agent Development Kit (ADK)">
<meta name="twitter:description" content="Build powerful multi-agent systems with Agent Development Kit (ADK)">
<meta name="twitter:image" content="https://adk.dev/assets/adk-social-card.png">
<!-- Pagefind search UI. hooks/pagefind.py builds the index and guards both
filenames, so a third asset added here needs adding there too. -->
<link rel="stylesheet" href="../../pagefind/pagefind-component-ui.css">
<script type="module" src="../../pagefind/pagefind-component-ui.js"></script>
<!-- `| url` covers only the assets above. document.currentScript is null in a
module script, so the bundle always fetches its index from the origin
root: correct at a root domain, wrong under a subpath. -->
<!-- Raise termSimilarity so "LlmAgent" beats pages that merely say "agent"
often. Set on pagefindOptions, which is read lazily; configureInstance()
is ignored once the components create the instance on connect. -->
<script type="module">
window.PagefindComponents
.getInstanceManager()
.getInstance("default")
.pagefindOptions.ranking = { termSimilarity: 2.0 };
</script>
<!-- Mirror Material's data-md-color-scheme onto data-pf-theme, the only
thing that switches Pagefind's dark palette. -->
<script>
(function () {
var sync = function () {
var root = document.documentElement;
if (document.body.getAttribute("data-md-color-scheme") === "slate") {
root.setAttribute("data-pf-theme", "dark");
} else {
root.removeAttribute("data-pf-theme");
}
};
document.addEventListener("DOMContentLoaded", function () {
sync();
new MutationObserver(sync).observe(document.body, {
attributes: true,
attributeFilter: ["data-md-color-scheme"],
});
});
})();
</script>
<!-- Upstream bug: reset-on-close clears the results but never the input, so
the next keystroke appends to the old query. Writing through the native
setter keeps the component in step. Delete this once Pagefind fixes it. -->
<script>
(function () {
document.addEventListener("DOMContentLoaded", function () {
var modal = document.querySelector("pagefind-modal");
// Bind once: the modal outlives instant navigation.
if (!modal || modal.dataset.adkPfClearOnClose) return;
modal.dataset.adkPfClearOnClose = "1";
modal.addEventListener(
"close",
function () {
var input =
modal.querySelector("input") ||
(modal.shadowRoot && modal.shadowRoot.querySelector("input"));
if (!input || !input.value) return;
Object.getOwnPropertyDescriptor(
HTMLInputElement.prototype,
"value",
).set.call(input, "");
input.dispatchEvent(
new Event("input", { bubbles: true, composed: true }),
);
},
true, // `close` does not bubble, but capture still reaches it.
);
});
})();
</script>
<!-- Result links are light DOM, so navigation.instant swaps the page without
unloading the header and the modal stays open. document$ emits after every
swap; close() no-ops when the modal is already closed. -->
<script>
(function () {
document.addEventListener("DOMContentLoaded", function () {
if (!window.document$ || window.__adkPagefindCloseOnNav) return;
window.__adkPagefindCloseOnNav = true;
window.document$.subscribe(function () {
var modal = document.querySelector("pagefind-modal");
if (modal && typeof modal.close === "function") modal.close();
});
});
})();
</script>
<!-- Restore the `/` and `s` shortcuts lost with Material's search plugin;
Pagefind's trigger parses one binding only, already spent on mod+k.
Ignore them with a modifier held, while typing, or while already open. -->
<script>
(function () {
if (window.__adkPagefindSearchKeys) return;
window.__adkPagefindSearchKeys = true;
document.addEventListener("keydown", function (event) {
if (event.key !== "/" && event.key !== "s") return;
if (event.ctrlKey || event.metaKey || event.altKey) return;
var target = event.target;
if (target instanceof Element) {
if (target.isContentEditable) return;
if (target.closest("input, textarea, select")) return;
}
var modal = document.querySelector("pagefind-modal");
if (!modal || typeof modal.open !== "function") return;
var dialog = modal.querySelector("dialog");
if (dialog && dialog.open) return;
event.preventDefault();
modal.open();
});
})();
</script>
</head>
<body dir="ltr" data-md-color-scheme="default" data-md-color-primary="white" data-md-color-accent="white">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#build-your-first-intelligent-agent-team-a-progressive-weather-bot-with-adk" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
<aside class="md-banner">
<div class="md-banner__inner md-grid md-typeset">
<span class="announce-item">
<strong>Released!</strong>
<a href="/2.0/">
ADK TypeScript 2.0 GA
</a>
is now available with graph workflows support! <a href="/graphs/#typescript">Get started</a>
</span>
</div>
</aside>
</div>
<!--
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.
-->
<!-- Determine classes -->
<!-- Header -->
<header class="md-header" data-md-component="header">
<nav
class="md-header__inner md-grid"
aria-label="Header"
>
<!-- Link to home -->
<a
href="../.."
title="Agent Development Kit (ADK)"
class="md-header__button md-logo"
aria-label="Agent Development Kit (ADK)"
data-md-component="logo"
>
<img src="../../assets/agent-development-kit.png" alt="logo">
</a>
<!-- Button to open drawer -->
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
</label>
<!-- Header title -->
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
<a
href="../.."
title="Agent Development Kit (ADK)"
aria-label="Agent Development Kit (ADK)"
data-md-component="logo"
>
Agent Development Kit (ADK)
</a>
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Agent team
</a>
</span>
</div>
</div>
</div>
<!-- Language SDK repository links -->
<div class="lang-header-repos">
<div class="lang-repos">
<a href="https://github.com/google/adk-python"
title="adk-python on GitHub"
class="lang-item">
<img src="/assets/icon-python.svg"
alt="Python" class="lang-icon" width="24" height="24" />
<span class="lang-label">Python</span>
</a>
<a href="https://github.com/google/adk-js"
title="adk-js on GitHub"
class="lang-item">
<img src="/assets/icon-typescript.svg"
alt="TypeScript" class="lang-icon" width="24" height="24" />
<span class="lang-label">JS</span>
</a>
<a href="https://github.com/google/adk-go"
title="adk-go on GitHub"
class="lang-item">
<img src="/assets/icon-go.svg"
alt="Go" class="lang-icon" width="24" height="24" />
<span class="lang-label">Go</span>
</a>
<a href="https://github.com/google/adk-java"
title="adk-java on GitHub"
class="lang-item">
<img src="/assets/icon-java.svg"
alt="Java" class="lang-icon" width="24" height="24" />
<span class="lang-label">Java</span>
</a>
<a href="https://github.com/google/adk-kotlin"
title="adk-kotlin on GitHub"
class="lang-item">
<img src="/assets/icon-kotlin.svg"
alt="Kotlin" class="lang-icon" width="24" height="24" />
<span class="lang-label">Kotlin</span>
</a>
</div>
</div>
<!-- Color palette toggle -->
<form class="md-header__option" data-md-component="palette">
<input class="md-option" data-md-color-media="" data-md-color-scheme="default" data-md-color-primary="white" data-md-color-accent="white" aria-label="Switch to dark mode" type="radio" name="__palette" id="__palette_0">
<label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_1" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a4 4 0 0 0-4 4 4 4 0 0 0 4 4 4 4 0 0 0 4-4 4 4 0 0 0-4-4m0 10a6 6 0 0 1-6-6 6 6 0 0 1 6-6 6 6 0 0 1 6 6 6 6 0 0 1-6 6m8-9.31V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12z"/></svg>
</label>
<input class="md-option" data-md-color-media="" data-md-color-scheme="slate" data-md-color-primary="grey" data-md-color-accent="grey" aria-label="Switch to light mode" type="radio" name="__palette" id="__palette_1">
<label class="md-header__button md-icon" title="Switch to light mode" for="__palette_0" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 18c-.89 0-1.74-.2-2.5-.55C11.56 16.5 13 14.42 13 12s-1.44-4.5-3.5-5.45C10.26 6.2 11.11 6 12 6a6 6 0 0 1 6 6 6 6 0 0 1-6 6m8-9.31V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12z"/></svg>
</label>
</form>
<!-- User preference: color palette -->
<script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
<!-- Site language selector -->
<!-- Pagefind search. Both live in the header nav, which survives
navigation.instant DOM swaps, so the modal keeps its state. -->
<pagefind-modal-trigger placeholder="Search"></pagefind-modal-trigger>
<pagefind-modal reset-on-close></pagefind-modal>
</nav>
<!-- Navigation tabs (sticky) -->
</header>
<div class="md-container" data-md-component="container">
<nav class="md-tabs" aria-label="Tabs" data-md-component="tabs">
<div class="md-grid">
<ul class="md-tabs__list">
<li class="md-tabs__item">
<a href="../.." class="md-tabs__link">
Home
</a>
</li>
<li class="md-tabs__item md-tabs__item--active">
<a href="../../get-started/" class="md-tabs__link">
Build Agents
</a>
</li>
<li class="md-tabs__item">
<a href="../../runtime/" class="md-tabs__link">
Run Agents
</a>
</li>
<li class="md-tabs__item">
<a href="../../get-started/about/" class="md-tabs__link">
Components
</a>
</li>
<li class="md-tabs__item">
<a href="../../integrations/" class="md-tabs__link">
Integrations
</a>
</li>
<li class="md-tabs__item">
<a href="../../api-reference/" class="md-tabs__link">
Reference
</a>
</li>
<li class="md-tabs__item">
<a href="../../community/" class="md-tabs__link">
Community
</a>
</li>
<li class="md-tabs__item">
<a href="../../2.0/" class="md-tabs__link">
ADK 2.0
</a>
</li>
</ul>
</div>
</nav>
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<!--
Copyright (c) 2016-2025 Martin Donath <martin.donath@squidfunk.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
-->
<!-- Determine classes -->
<!-- Navigation -->
<nav
class="md-nav md-nav--primary md-nav--lifted"
aria-label="Navigation"
data-md-level="0"
>
<!-- Repository information -->
<div class="md-nav__source">
<div class="lang-repos">
<a href="https://github.com/google/adk-python"
title="adk-python on GitHub"
class="lang-item">
<img src="/assets/icon-python.svg"
alt="Python" class="lang-icon" width="24" height="24" />
<span class="lang-label">Python</span>
</a>
<a href="https://github.com/google/adk-js"
title="adk-js on GitHub"
class="lang-item">
<img src="/assets/icon-typescript.svg"
alt="TypeScript" class="lang-icon" width="24" height="24" />
<span class="lang-label">JS</span>
</a>
<a href="https://github.com/google/adk-go"
title="adk-go on GitHub"
class="lang-item">
<img src="/assets/icon-go.svg"
alt="Go" class="lang-icon" width="24" height="24" />
<span class="lang-label">Go</span>
</a>
<a href="https://github.com/google/adk-java"
title="adk-java on GitHub"
class="lang-item">
<img src="/assets/icon-java.svg"
alt="Java" class="lang-icon" width="24" height="24" />
<span class="lang-label">Java</span>
</a>
<a href="https://github.com/google/adk-kotlin"
title="adk-kotlin on GitHub"
class="lang-item">
<img src="/assets/icon-kotlin.svg"
alt="Kotlin" class="lang-icon" width="24" height="24" />
<span class="lang-label">Kotlin</span>
</a>
</div>
</div>
<!-- Navigation list -->
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../.." class="md-nav__link">
<span class="md-ellipsis">
Home
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2" checked>
<label class="md-nav__link" for="__nav_2" id="__nav_2_label" tabindex="">
<span class="md-ellipsis">
Build Agents
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_2_label" aria-expanded="true">
<label class="md-nav__title" for="__nav_2">
<span class="md-nav__icon md-icon"></span>
Build Agents
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_1" >
<div class="md-nav__link md-nav__container">
<a href="../../get-started/" class="md-nav__link ">
<span class="md-ellipsis">
Get Started
</span>
</a>
<label class="md-nav__link " for="__nav_2_1" id="__nav_2_1_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_1_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_1">
<span class="md-nav__icon md-icon"></span>
Get Started
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../get-started/python/" class="md-nav__link">
<span class="md-ellipsis">
Python
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../get-started/typescript/" class="md-nav__link">
<span class="md-ellipsis">
TypeScript
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../get-started/go/" class="md-nav__link">
<span class="md-ellipsis">
Go
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../get-started/java/" class="md-nav__link">
<span class="md-ellipsis">
Java
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../get-started/kotlin/" class="md-nav__link">
<span class="md-ellipsis">
Kotlin
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../get-started/agents-cli/" class="md-nav__link">
<span class="md-ellipsis">
Agents CLI
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../get-started/installation/" class="md-nav__link">
<span class="md-ellipsis">
Installation
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../get-started/google-cloud/" class="md-nav__link">
<span class="md-ellipsis">
Google Cloud
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../get-started/migrate/" class="md-nav__link">
<span class="md-ellipsis">
Migrate to ADK
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_2" checked>
<div class="md-nav__link md-nav__container">
<a href="../" class="md-nav__link ">
<span class="md-ellipsis">
Build your Agent
</span>
</a>
<label class="md-nav__link " for="__nav_2_2" id="__nav_2_2_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_2_label" aria-expanded="true">
<label class="md-nav__title" for="__nav_2_2">
<span class="md-nav__icon md-icon"></span>
Build your Agent
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../multi-tool-agent/" class="md-nav__link">
<span class="md-ellipsis">
Multi-tool agent
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
<span class="md-ellipsis">
Agent team
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
<span class="md-ellipsis">
Agent team
</span>
</a>
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#step-1-your-first-agent-basic-weather-lookup" class="md-nav__link">
<span class="md-ellipsis">
Step 1: Your First Agent - Basic Weather Lookup
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#step-2-going-multi-model-with-litellm-optional" class="md-nav__link">
<span class="md-ellipsis">
Step 2: Going Multi-Model with LiteLLM [Optional]
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#step-3-building-an-agent-team-delegation-for-greetings-farewells" class="md-nav__link">
<span class="md-ellipsis">
Step 3: Building an Agent Team - Delegation for Greetings &amp; Farewells
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#step-4-adding-memory-and-personalization-with-session-state" class="md-nav__link">
<span class="md-ellipsis">
Step 4: Adding Memory and Personalization with Session State
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#step-5-adding-safety-input-guardrail-with-before_model_callback" class="md-nav__link">
<span class="md-ellipsis">
Step 5: Adding Safety - Input Guardrail with before_model_callback
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#step-6-adding-safety-tool-argument-guardrail-before_tool_callback" class="md-nav__link">
<span class="md-ellipsis">
Step 6: Adding Safety - Tool Argument Guardrail (before_tool_callback)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#conclusion-your-agent-team-is-ready" class="md-nav__link">
<span class="md-ellipsis">
Conclusion: Your Agent Team is Ready!
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../coding-with-ai/" class="md-nav__link">
<span class="md-ellipsis">
Code with AI
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../agents/config/" class="md-nav__link">
<span class="md-ellipsis">
Agent Config
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_3" >
<div class="md-nav__link md-nav__container">
<a href="../../agents/" class="md-nav__link ">
<span class="md-ellipsis">
Agents
</span>
</a>
<label class="md-nav__link " for="__nav_2_3" id="__nav_2_3_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_3">
<span class="md-nav__icon md-icon"></span>
Agents
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../agents/llm-agents/" class="md-nav__link">
<span class="md-ellipsis">
Simple agents
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../agents/managed-agents/" class="md-nav__link">
<span class="md-ellipsis">
Managed agents
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_4" >
<div class="md-nav__link md-nav__container">
<a href="../../graphs/" class="md-nav__link ">
<span class="md-ellipsis">
Graph Workflows
</span>
</a>
<label class="md-nav__link " for="__nav_2_4" id="__nav_2_4_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_4">
<span class="md-nav__icon md-icon"></span>
Graph Workflows
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../graphs/routes/" class="md-nav__link">
<span class="md-ellipsis">
Graph routes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../graphs/data-handling/" class="md-nav__link">
<span class="md-ellipsis">
Data handling
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../graphs/human-input/" class="md-nav__link">
<span class="md-ellipsis">
Human input
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../graphs/dynamic/" class="md-nav__link">
<span class="md-ellipsis">
Dynamic workflows
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_5" >
<div class="md-nav__link md-nav__container">
<a href="../../workflows/" class="md-nav__link ">
<span class="md-ellipsis">
Multi-Agent Workflows
</span>
</a>
<label class="md-nav__link " for="__nav_2_5" id="__nav_2_5_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_5_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_5">
<span class="md-nav__icon md-icon"></span>
Multi-Agent Workflows
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../workflows/collaboration/" class="md-nav__link">
<span class="md-ellipsis">
Collaborative workflows
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_5_3" >
<div class="md-nav__link md-nav__container">
<a href="../../agents/workflow-agents/" class="md-nav__link ">
<span class="md-ellipsis">
Template workflows
</span>
</a>
<label class="md-nav__link " for="__nav_2_5_3" id="__nav_2_5_3_label" tabindex="0">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_5_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_5_3">
<span class="md-nav__icon md-icon"></span>
Template workflows
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../agents/workflow-agents/sequential-agents/" class="md-nav__link">
<span class="md-ellipsis">
Sequential workflow
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../agents/workflow-agents/loop-agents/" class="md-nav__link">
<span class="md-ellipsis">
Loop workflow
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../agents/workflow-agents/parallel-agents/" class="md-nav__link">
<span class="md-ellipsis">
Parallel workflow
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../agents/custom-agents/" class="md-nav__link">
<span class="md-ellipsis">
Custom template workflows
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../../agents/routing/" class="md-nav__link">
<span class="md-ellipsis">
Agent routing
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../workflows/patterns/" class="md-nav__link">
<span class="md-ellipsis">
Workflow patterns
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_6" >
<div class="md-nav__link md-nav__container">
<a href="../../agents/models/" class="md-nav__link ">
<span class="md-ellipsis">
Models for Agents
</span>
</a>
<label class="md-nav__link " for="__nav_2_6" id="__nav_2_6_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_6_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_6">
<span class="md-nav__icon md-icon"></span>
Models for Agents
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../agents/models/google-gemini/" class="md-nav__link">
<span class="md-ellipsis">
Gemini
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../agents/models/google-gemma/" class="md-nav__link">
<span class="md-ellipsis">
Gemma
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../agents/models/anthropic/" class="md-nav__link">
<span class="md-ellipsis">
Claude
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../agents/models/agent-platform/" class="md-nav__link">
<span class="md-ellipsis">
Agent Platform hosted
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../agents/models/apigee/" class="md-nav__link">
<span class="md-ellipsis">
Apigee AI Gateway
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../agents/models/routing/" class="md-nav__link">
<span class="md-ellipsis">
Model routing
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../agents/models/openai/" class="md-nav__link">
<span class="md-ellipsis">
OpenAI
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../agents/models/ollama/" class="md-nav__link">
<span class="md-ellipsis">
Ollama
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../agents/models/vllm/" class="md-nav__link">
<span class="md-ellipsis">
vLLM
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../agents/models/litellm/" class="md-nav__link">
<span class="md-ellipsis">
LiteLLM
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../agents/models/litert-lm/" class="md-nav__link">
<span class="md-ellipsis">
LiteRT-LM
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3" >
<label class="md-nav__link" for="__nav_3" id="__nav_3_label" tabindex="0">
<span class="md-ellipsis">
Run Agents
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_3">
<span class="md-nav__icon md-icon"></span>
Run Agents
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3_1" >
<div class="md-nav__link md-nav__container">
<a href="../../runtime/" class="md-nav__link ">
<span class="md-ellipsis">
Agent Runtime
</span>
</a>
<label class="md-nav__link " for="__nav_3_1" id="__nav_3_1_label" tabindex="0">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_3_1_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_3_1">
<span class="md-nav__icon md-icon"></span>
Agent Runtime
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3_1_2" >
<div class="md-nav__link md-nav__container">
<a href="../../runtime/web-interface/" class="md-nav__link ">
<span class="md-ellipsis">
Web Interface
</span>
</a>
<label class="md-nav__link " for="__nav_3_1_2" id="__nav_3_1_2_label" tabindex="0">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="3" aria-labelledby="__nav_3_1_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_3_1_2">
<span class="md-nav__icon md-icon"></span>
Web Interface
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../visual-builder/" class="md-nav__link">
<span class="md-ellipsis">
Visual Builder
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../../runtime/command-line/" class="md-nav__link">
<span class="md-ellipsis">
Command Line
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../runtime/api-server/" class="md-nav__link">
<span class="md-ellipsis">
API Server
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../runtime/ambient-agents/" class="md-nav__link">
<span class="md-ellipsis">
Ambient Agents
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../runtime/resume/" class="md-nav__link">
<span class="md-ellipsis">
Resume Agents
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../runtime/cancel/" class="md-nav__link">
<span class="md-ellipsis">
Cancel Agent Runs
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../runtime/runconfig/" class="md-nav__link">
<span class="md-ellipsis">
Runtime Config
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../runtime/event-loop/" class="md-nav__link">
<span class="md-ellipsis">
Event Loop
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3_2" >
<div class="md-nav__link md-nav__container">
<a href="../../deploy/" class="md-nav__link ">
<span class="md-ellipsis">
Deployment
</span>
</a>
<label class="md-nav__link " for="__nav_3_2" id="__nav_3_2_label" tabindex="0">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_3_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_3_2">
<span class="md-nav__icon md-icon"></span>
Deployment
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3_2_2" >
<div class="md-nav__link md-nav__container">
<a href="../../deploy/agent-runtime/" class="md-nav__link ">
<span class="md-ellipsis">
Agent Runtime
</span>
</a>
<label class="md-nav__link " for="__nav_3_2_2" id="__nav_3_2_2_label" tabindex="0">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="3" aria-labelledby="__nav_3_2_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_3_2_2">
<span class="md-nav__icon md-icon"></span>
Agent Runtime
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../deploy/agent-runtime/deploy/" class="md-nav__link">
<span class="md-ellipsis">
Standard deployment
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../deploy/agent-runtime/agents-cli/" class="md-nav__link">
<span class="md-ellipsis">
agents-cli
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../deploy/agent-runtime/test/" class="md-nav__link">
<span class="md-ellipsis">
Test deployed agents
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../../deploy/cloud-run/" class="md-nav__link">
<span class="md-ellipsis">
Cloud Run
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../deploy/gke/" class="md-nav__link">
<span class="md-ellipsis">
GKE
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3_3" >
<div class="md-nav__link md-nav__container">
<a href="../../observability/" class="md-nav__link ">
<span class="md-ellipsis">
Observability
</span>
</a>
<label class="md-nav__link " for="__nav_3_3" id="__nav_3_3_label" tabindex="0">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_3_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_3_3">
<span class="md-nav__icon md-icon"></span>
Observability
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../observability/logging/" class="md-nav__link">
<span class="md-ellipsis">
Logging
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../observability/metrics/" class="md-nav__link">
<span class="md-ellipsis">
Metrics
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../observability/traces/" class="md-nav__link">
<span class="md-ellipsis">
Traces
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3_4" >
<div class="md-nav__link md-nav__container">
<a href="../../evaluate/" class="md-nav__link ">
<span class="md-ellipsis">
Evaluation
</span>
</a>
<label class="md-nav__link " for="__nav_3_4" id="__nav_3_4_label" tabindex="0">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_3_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_3_4">
<span class="md-nav__icon md-icon"></span>
Evaluation
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../evaluate/criteria/" class="md-nav__link">
<span class="md-ellipsis">
Criteria
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../evaluate/user-sim/" class="md-nav__link">
<span class="md-ellipsis">
User Simulation
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../evaluate/environment_simulation/" class="md-nav__link">
<span class="md-ellipsis">
Environment Simulation
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../evaluate/custom_metrics/" class="md-nav__link">
<span class="md-ellipsis">
Custom Metrics
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../optimize/" class="md-nav__link">
<span class="md-ellipsis">
Optimization
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3_5" >
<div class="md-nav__link md-nav__container">
<a href="../../safety/" class="md-nav__link ">
<span class="md-ellipsis">
Safety and Security
</span>
</a>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_3_5_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_3_5">
<span class="md-nav__icon md-icon"></span>
Safety and Security
</label>
<ul class="md-nav__list" data-md-scrollfix>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4" >
<label class="md-nav__link" for="__nav_4" id="__nav_4_label" tabindex="0">
<span class="md-ellipsis">
Components
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4">
<span class="md-nav__icon md-icon"></span>
Components
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../get-started/about/" class="md-nav__link">
<span class="md-ellipsis">
Technical Overview
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4_2" >
<div class="md-nav__link md-nav__container">
<a href="../../tools-custom/" class="md-nav__link ">
<span class="md-ellipsis">
Custom Tools
</span>
</a>
<label class="md-nav__link " for="__nav_4_2" id="__nav_4_2_label" tabindex="0">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_4_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_2">
<span class="md-nav__icon md-icon"></span>
Custom Tools
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4_2_2" >
<label class="md-nav__link" for="__nav_4_2_2" id="__nav_4_2_2_label" tabindex="0">
<span class="md-ellipsis">
Function tools
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="3" aria-labelledby="__nav_4_2_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_2_2">
<span class="md-nav__icon md-icon"></span>
Function tools
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../tools-custom/function-tools/" class="md-nav__link">
<span class="md-ellipsis">
Overview
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../tools-custom/performance/" class="md-nav__link">
<span class="md-ellipsis">
Tool performance
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../tools-custom/confirmation/" class="md-nav__link">
<span class="md-ellipsis">
Action confirmations
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../../tools-custom/mcp-tools/" class="md-nav__link">
<span class="md-ellipsis">
MCP tools
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../tools-custom/openapi-tools/" class="md-nav__link">
<span class="md-ellipsis">
OpenAPI tools
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../tools-custom/authentication/" class="md-nav__link">
<span class="md-ellipsis">
Authentication
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../tools/limitations/" class="md-nav__link">
<span class="md-ellipsis">
Tool limitations
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4_3" >
<div class="md-nav__link md-nav__container">
<a href="../../artifacts/" class="md-nav__link ">
<span class="md-ellipsis">
Artifacts
</span>
</a>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_4_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_3">
<span class="md-nav__icon md-icon"></span>
Artifacts
</label>
<ul class="md-nav__list" data-md-scrollfix>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4_4" >
<div class="md-nav__link md-nav__container">
<a href="../../skills/" class="md-nav__link ">
<span class="md-ellipsis">
Skills for Agents
</span>
</a>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_4_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_4">
<span class="md-nav__icon md-icon"></span>
Skills for Agents
</label>
<ul class="md-nav__list" data-md-scrollfix>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4_5" >
<div class="md-nav__link md-nav__container">
<a href="../../apps/" class="md-nav__link ">
<span class="md-ellipsis">
App management
</span>
</a>
<label class="md-nav__link " for="__nav_4_5" id="__nav_4_5_label" tabindex="0">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_4_5_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_5">
<span class="md-nav__icon md-icon"></span>
App management
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4_5_2" >
<div class="md-nav__link md-nav__container">
<a href="../../callbacks/" class="md-nav__link ">
<span class="md-ellipsis">
Callbacks
</span>
</a>
<label class="md-nav__link " for="__nav_4_5_2" id="__nav_4_5_2_label" tabindex="0">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="3" aria-labelledby="__nav_4_5_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_5_2">
<span class="md-nav__icon md-icon"></span>
Callbacks
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../callbacks/types-of-callbacks/" class="md-nav__link">
<span class="md-ellipsis">
Types of callbacks
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../callbacks/design-patterns-and-best-practices/" class="md-nav__link">
<span class="md-ellipsis">
Callback patterns
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../../plugins/" class="md-nav__link">
<span class="md-ellipsis">
Plugins
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4_6" >
<div class="md-nav__link md-nav__container">
<a href="../../context/" class="md-nav__link ">
<span class="md-ellipsis">
Agent context
</span>
</a>
<label class="md-nav__link " for="__nav_4_6" id="__nav_4_6_label" tabindex="0">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_4_6_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_6">
<span class="md-nav__icon md-icon"></span>
Agent context
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../sessions/" class="md-nav__link">
<span class="md-ellipsis">
Conversational context
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4_6_3" >
<div class="md-nav__link md-nav__container">
<a href="../../sessions/session/" class="md-nav__link ">
<span class="md-ellipsis">
Sessions
</span>
</a>
<label class="md-nav__link " for="__nav_4_6_3" id="__nav_4_6_3_label" tabindex="0">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="3" aria-labelledby="__nav_4_6_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_6_3">
<span class="md-nav__icon md-icon"></span>
Sessions
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../sessions/session/rewind/" class="md-nav__link">
<span class="md-ellipsis">
Rewind sessions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../sessions/session/migrate/" class="md-nav__link">
<span class="md-ellipsis">
Migrate sessions
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../../sessions/state/" class="md-nav__link">
<span class="md-ellipsis">
State
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../events/" class="md-nav__link">
<span class="md-ellipsis">
Events
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../sessions/memory/" class="md-nav__link">
<span class="md-ellipsis">
Memory
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../context/compaction/" class="md-nav__link">
<span class="md-ellipsis">
Context compression
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../context/caching/" class="md-nav__link">
<span class="md-ellipsis">
Model context caching
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4_7" >
<div class="md-nav__link md-nav__container">
<a href="../../mcp/" class="md-nav__link ">
<span class="md-ellipsis">
MCP
</span>
</a>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_4_7_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_7">
<span class="md-nav__icon md-icon"></span>
MCP
</label>
<ul class="md-nav__list" data-md-scrollfix>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4_8" >
<div class="md-nav__link md-nav__container">
<a href="../../a2a/" class="md-nav__link ">
<span class="md-ellipsis">
A2A Protocol
</span>
</a>
<label class="md-nav__link " for="__nav_4_8" id="__nav_4_8_label" tabindex="0">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_4_8_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_8">
<span class="md-nav__icon md-icon"></span>
A2A Protocol
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../a2a/intro/" class="md-nav__link">
<span class="md-ellipsis">
Introduction to A2A
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4_8_3" >
<label class="md-nav__link" for="__nav_4_8_3" id="__nav_4_8_3_label" tabindex="0">
<span class="md-ellipsis">
A2A Quickstart (Exposing)
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="3" aria-labelledby="__nav_4_8_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_8_3">
<span class="md-nav__icon md-icon"></span>
A2A Quickstart (Exposing)
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../a2a/quickstart-exposing/" class="md-nav__link">
<span class="md-ellipsis">
Python
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../a2a/quickstart-exposing-go/" class="md-nav__link">
<span class="md-ellipsis">
Go
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../a2a/quickstart-exposing-java/" class="md-nav__link">
<span class="md-ellipsis">
Java
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4_8_4" >
<label class="md-nav__link" for="__nav_4_8_4" id="__nav_4_8_4_label" tabindex="0">
<span class="md-ellipsis">
A2A Quickstart (Consuming)
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="3" aria-labelledby="__nav_4_8_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_8_4">
<span class="md-nav__icon md-icon"></span>
A2A Quickstart (Consuming)
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../a2a/quickstart-consuming/" class="md-nav__link">
<span class="md-ellipsis">
Python
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../a2a/quickstart-consuming-go/" class="md-nav__link">
<span class="md-ellipsis">
Go
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../a2a/quickstart-consuming-java/" class="md-nav__link">
<span class="md-ellipsis">
Java
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../a2a/quickstart-consuming-kotlin/" class="md-nav__link">
<span class="md-ellipsis">
Kotlin
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../../a2a/a2a-extension/" class="md-nav__link">
<span class="md-ellipsis">
A2A Extension
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4_9" >
<div class="md-nav__link md-nav__container">
<a href="../../live/" class="md-nav__link ">
<span class="md-ellipsis">
Live and Voice Agents
</span>
</a>
<label class="md-nav__link " for="__nav_4_9" id="__nav_4_9_label" tabindex="0">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_4_9_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_9">
<span class="md-nav__icon md-icon"></span>
Live and Voice Agents
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4_9_2" >
<div class="md-nav__link md-nav__container">
<a href="../../live/get-started/" class="md-nav__link ">
<span class="md-ellipsis">
Get started
</span>
</a>
<label class="md-nav__link " for="__nav_4_9_2" id="__nav_4_9_2_label" tabindex="0">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="3" aria-labelledby="__nav_4_9_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_9_2">
<span class="md-nav__icon md-icon"></span>
Get started
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../live/get-started/streaming-python/" class="md-nav__link">
<span class="md-ellipsis">
Python
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../live/get-started/streaming-java/" class="md-nav__link">
<span class="md-ellipsis">
Java
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4_9_3" >
<label class="md-nav__link" for="__nav_4_9_3" id="__nav_4_9_3_label" tabindex="0">
<span class="md-ellipsis">
Building
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="3" aria-labelledby="__nav_4_9_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_9_3">
<span class="md-nav__icon md-icon"></span>
Building
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../live/workflows/" class="md-nav__link">
<span class="md-ellipsis">
Workflows
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../live/tools/" class="md-nav__link">
<span class="md-ellipsis">
Tools
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../live/sessions/" class="md-nav__link">
<span class="md-ellipsis">
Sessions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../live/events/" class="md-nav__link">
<span class="md-ellipsis">
Events
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../live/audio-video/" class="md-nav__link">
<span class="md-ellipsis">
Audio and video
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../live/configuration/" class="md-nav__link">
<span class="md-ellipsis">
Configuration
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4_9_4" >
<label class="md-nav__link" for="__nav_4_9_4" id="__nav_4_9_4_label" tabindex="0">
<span class="md-ellipsis">
Production
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="3" aria-labelledby="__nav_4_9_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_9_4">
<span class="md-nav__icon md-icon"></span>
Production
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../live/evaluation/" class="md-nav__link">
<span class="md-ellipsis">
Evaluation
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../live/custom-server/" class="md-nav__link">
<span class="md-ellipsis">
Build a custom server
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../../live/models/" class="md-nav__link">
<span class="md-ellipsis">
Supported models
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4_10" >
<div class="md-nav__link md-nav__container">
<a href="../../grounding/" class="md-nav__link ">
<span class="md-ellipsis">
Grounding
</span>
</a>
<label class="md-nav__link " for="__nav_4_10" id="__nav_4_10_label" tabindex="0">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_4_10_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_10">
<span class="md-nav__icon md-icon"></span>
Grounding
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../grounding/google_search_grounding/" class="md-nav__link">
<span class="md-ellipsis">
Google Search Grounding
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../grounding/grounding_with_search/" class="md-nav__link">
<span class="md-ellipsis">
Grounding with Search
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5" >
<div class="md-nav__link md-nav__container">
<a href="../../integrations/" class="md-nav__link ">
<span class="md-ellipsis">
Integrations
</span>
</a>
</div>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_5_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5">
<span class="md-nav__icon md-icon"></span>
Integrations
</label>
<ul class="md-nav__list" data-md-scrollfix>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_6" >
<label class="md-nav__link" for="__nav_6" id="__nav_6_label" tabindex="0">
<span class="md-ellipsis">
Reference
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_6_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Reference
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_6_1" >
<div class="md-nav__link md-nav__container">
<a href="../../api-reference/" class="md-nav__link ">
<span class="md-ellipsis">
API Reference
</span>
</a>
<label class="md-nav__link " for="__nav_6_1" id="__nav_6_1_label" tabindex="0">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_6_1_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_6_1">
<span class="md-nav__icon md-icon"></span>
API Reference
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../api-reference/python/" class="md-nav__link">
<span class="md-ellipsis">
Python ADK
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../api-reference/typescript/" class="md-nav__link">
<span class="md-ellipsis">
TypeScript ADK
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_6_1_4" >
<label class="md-nav__link" for="__nav_6_1_4" id="__nav_6_1_4_label" tabindex="0">
<span class="md-ellipsis">
Go ADK
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="3" aria-labelledby="__nav_6_1_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_6_1_4">
<span class="md-nav__icon md-icon"></span>
Go ADK
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="https://pkg.go.dev/google.golang.org/adk/v2" target="_blank" class="md-nav__link">
<span class="md-ellipsis">
Go v2.x
</span>
</a>
</li>
<li class="md-nav__item">
<a href="https://pkg.go.dev/google.golang.org/adk" target="_blank" class="md-nav__link">
<span class="md-ellipsis">
Go v1.x
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../../api-reference/java/" class="md-nav__link">
<span class="md-ellipsis">
Java ADK
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../api-reference/kotlin/" class="md-nav__link">
<span class="md-ellipsis">
Kotlin ADK
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../api-reference/cli/" class="md-nav__link">
<span class="md-ellipsis">
CLI Reference
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../api-reference/agentconfig/" class="md-nav__link">
<span class="md-ellipsis">
Agent Config Reference
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../api-reference/rest/" class="md-nav__link">
<span class="md-ellipsis">
REST API
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../../release-notes/" class="md-nav__link">
<span class="md-ellipsis">
Release Notes
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_7" >
<div class="md-nav__link md-nav__container">
<a href="../../community/" class="md-nav__link ">
<span class="md-ellipsis">
Community
</span>
</a>
<label class="md-nav__link " for="__nav_7" id="__nav_7_label" tabindex="0">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_7_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_7">
<span class="md-nav__icon md-icon"></span>
Community
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../community/contributing-guide/" class="md-nav__link">
<span class="md-ellipsis">
Contributing Guide
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_8" >
<div class="md-nav__link md-nav__container">
<a href="../../2.0/" class="md-nav__link ">
<span class="md-ellipsis">
ADK 2.0
</span>
</a>
</div>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_8_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_8">
<span class="md-nav__icon md-icon"></span>
ADK 2.0
</label>
<ul class="md-nav__list" data-md-scrollfix>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#step-1-your-first-agent-basic-weather-lookup" class="md-nav__link">
<span class="md-ellipsis">
Step 1: Your First Agent - Basic Weather Lookup
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#step-2-going-multi-model-with-litellm-optional" class="md-nav__link">
<span class="md-ellipsis">
Step 2: Going Multi-Model with LiteLLM [Optional]
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#step-3-building-an-agent-team-delegation-for-greetings-farewells" class="md-nav__link">
<span class="md-ellipsis">
Step 3: Building an Agent Team - Delegation for Greetings &amp; Farewells
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#step-4-adding-memory-and-personalization-with-session-state" class="md-nav__link">
<span class="md-ellipsis">
Step 4: Adding Memory and Personalization with Session State
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#step-5-adding-safety-input-guardrail-with-before_model_callback" class="md-nav__link">
<span class="md-ellipsis">
Step 5: Adding Safety - Input Guardrail with before_model_callback
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#step-6-adding-safety-tool-argument-guardrail-before_tool_callback" class="md-nav__link">
<span class="md-ellipsis">
Step 6: Adding Safety - Tool Argument Guardrail (before_tool_callback)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#conclusion-your-agent-team-is-ready" class="md-nav__link">
<span class="md-ellipsis">
Conclusion: Your Agent Team is Ready!
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<nav class="md-path" aria-label="Navigation" >
<ol class="md-path__list">
<li class="md-path__item">
<a href="../.." class="md-path__link">
<span class="md-ellipsis">
Home
</span>
</a>
</li>
<li class="md-path__item">
<a href="../../get-started/" class="md-path__link">
<span class="md-ellipsis">
Build Agents
</span>
</a>
</li>
<li class="md-path__item">
<a href="../" class="md-path__link">
<span class="md-ellipsis">
Build your Agent
</span>
</a>
</li>
</ol>
</nav>
<article class="md-content__inner md-typeset" data-pagefind-body>
<a href="https://github.com/google/adk-docs/edit/main/docs/tutorials/agent-team.md" title="Edit this page on GitHub" class="md-content__button md-icon" rel="edit">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 20H6V4h7v5h5v3.1l2-2V8l-6-6H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h4zm10.2-7c.1 0 .3.1.4.2l1.3 1.3c.2.2.2.6 0 .8l-1 1-2.1-2.1 1-1c.1-.1.2-.2.4-.2m0 3.9L14.1 23H12v-2.1l6.1-6.1z"/></svg>
</a>
<a href="./index.md" title="View this page as Markdown" class="md-content__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M17 18c.56 0 1 .44 1 1s-.44 1-1 1-1-.44-1-1 .44-1 1-1m0-3c-2.73 0-5.06 1.66-6 4 .94 2.34 3.27 4 6 4s5.06-1.66 6-4c-.94-2.34-3.27-4-6-4m0 6.5a2.5 2.5 0 0 1-2.5-2.5 2.5 2.5 0 0 1 2.5-2.5 2.5 2.5 0 0 1 2.5 2.5 2.5 2.5 0 0 1-2.5 2.5M9.27 20H6V4h7v5h5v4.07c.7.08 1.36.25 2 .49V8l-6-6H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h4.5a8.2 8.2 0 0 1-1.23-2"/></svg>
</a>
<button id="copy-page-btn" class="md-content__button md-icon" title="Copy page as Markdown" data-url="./index.md">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 21H8V7h11m0-2H8a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h11a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2m-3-4H4a2 2 0 0 0-2 2v14h2V3h12z"/></svg>
</button>
<h1 id="build-your-first-intelligent-agent-team-a-progressive-weather-bot-with-adk">Build Your First Intelligent Agent Team: A Progressive Weather Bot with ADK<a class="headerlink" href="#build-your-first-intelligent-agent-team-a-progressive-weather-bot-with-adk" title="Permanent link">&para;</a></h1>
<p><a href="https://colab.research.google.com/github/google/adk-docs/blob/main/examples/python/tutorial/agent_team/adk_tutorial.ipynb" target="_blank" style="display: inline-flex; align-items: center; gap: 5px; text-decoration: none; color: #4285F4;">
<img width="32px" src="https://www.gstatic.com/pantheon/images/bigquery/welcome_page/colab-logo.svg" alt="Google Colaboratory logo">
<span>Open in Colab</span>
</a></p>
<p>This tutorial extends from the <a href="/tutorials/multi-tool-agent/">Multi-tool agent</a> project. Now, you're ready to dive deeper and construct a more sophisticated, <strong>multi-agent system</strong>.</p>
<p>We'll embark on building a <strong>Weather Bot agent team</strong>, progressively layering advanced features onto a simple foundation. Starting with a single agent that can look up weather, we will incrementally add capabilities like:</p>
<ul>
<li>Leveraging different AI models (Gemini, GPT, Claude).</li>
<li>Designing specialized sub-agents for distinct tasks (like greetings and farewells).</li>
<li>Enabling intelligent delegation between agents.</li>
<li>Giving agents memory using persistent session state.</li>
<li>Implementing crucial safety guardrails using callbacks.</li>
</ul>
<p><strong>Why a Weather Bot Team?</strong></p>
<p>This use case, while seemingly simple, provides a practical and relatable canvas to explore core ADK concepts essential for building complex, real-world agentic applications. You'll learn how to structure interactions, manage state, ensure safety, and orchestrate multiple AI "brains" working together.</p>
<p><strong>What is ADK Again?</strong></p>
<p>As a reminder, ADK is a Python framework designed to streamline the development of applications powered by Large Language Models (LLMs). It offers robust building blocks for creating agents that can reason, plan, utilize tools, interact dynamically with users, and collaborate effectively within a team.</p>
<p><strong>In this advanced tutorial, you will master:</strong></p>
<ul>
<li>✅ <strong>Tool Definition &amp; Usage:</strong> Crafting Python functions (<code>tools</code>) that grant agents specific abilities (like fetching data) and instructing agents on how to use them effectively.</li>
<li>✅ <strong>Multi-LLM Flexibility:</strong> Configuring agents to utilize various leading LLMs (Gemini, GPT-4o, Claude Sonnet) via LiteLLM integration, allowing you to choose the best model for each task.</li>
<li>✅ <strong>Agent Delegation &amp; Collaboration:</strong> Designing specialized sub-agents and enabling automatic routing (<code>auto flow</code>) of user requests to the most appropriate agent within a team.</li>
<li>✅ <strong>Session State for Memory:</strong> Utilizing <code>Session State</code> and <code>ToolContext</code> to enable agents to remember information across conversational turns, leading to more contextual interactions.</li>
<li>✅ <strong>Safety Guardrails with Callbacks:</strong> Implementing <code>before_model_callback</code> and <code>before_tool_callback</code> to inspect, modify, or block requests/tool usage based on predefined rules, enhancing application safety and control.</li>
</ul>
<p><strong>End State Expectation:</strong></p>
<p>By completing this tutorial, you will have built a functional multi-agent Weather Bot system. This system will not only provide weather information but also handle conversational niceties, remember the last city checked, and operate within defined safety boundaries, all orchestrated using ADK.</p>
<p><strong>Prerequisites:</strong></p>
<ul>
<li>✅ <strong>Solid understanding of Python programming.</strong></li>
<li>✅ <strong>Familiarity with Large Language Models (LLMs), APIs, and the concept of agents.</strong></li>
<li>❗ <strong>Crucially: Completion of the ADK Quickstart tutorial(s) or equivalent foundational knowledge of ADK basics (Agent, Runner, SessionService, basic Tool usage).</strong> This tutorial builds directly upon those concepts.</li>
<li>✅ <strong>API Keys</strong> for the LLMs you intend to use (e.g., Google AI Studio for Gemini, OpenAI Platform, Anthropic Console).</li>
</ul>
<hr />
<p><strong>Note on Execution Environment:</strong></p>
<p>This tutorial is structured for interactive notebook environments like Google Colab, Colab Enterprise, or Jupyter notebooks. Please keep the following in mind:</p>
<ul>
<li><strong>Running Async Code:</strong> Notebook environments handle asynchronous code differently. You'll see examples using <code>await</code> (suitable when an event loop is already running, common in notebooks) or <code>asyncio.run()</code> (often needed when running as a standalone <code>.py</code> script or in specific notebook setups). The code blocks provide guidance for both scenarios.</li>
<li><strong>Manual Runner/Session Setup:</strong> The steps involve explicitly creating <code>Runner</code> and <code>SessionService</code> instances. This approach is shown because it gives you fine-grained control over the agent's execution lifecycle, session management, and state persistence.</li>
</ul>
<p><strong>Alternative: Using ADK's Built-in Tools (Web UI / CLI / API Server)</strong></p>
<p>If you prefer a setup that handles the runner and session management automatically using ADK's standard tools, you can find the equivalent code structured for that purpose <a href="https://github.com/google/adk-docs/tree/main/examples/python/tutorial/agent_team/adk_tutorial">here</a>. That version is designed to be run directly with commands like <code>adk web</code> (for a web UI), <code>adk run</code> (for CLI interaction), or <code>adk api_server</code> (to expose an API). Please follow the <code>README.md</code> instructions provided in that alternative resource.</p>
<hr />
<p><strong>Ready to build your agent team? Let's dive in!</strong></p>
<blockquote>
<p><strong>Note:</strong> This tutorial works with adk version 1.0.0 and above</p>
</blockquote>
<div class="language-python highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="c1"># @title Step 0: Setup and Installation</span>
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a><span class="c1"># Install ADK and LiteLLM for multi-model support</span>
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a>
</span><span id="__span-0-4"><a id="__codelineno-0-4" name="__codelineno-0-4" href="#__codelineno-0-4"></a><span class="err">!</span><span class="n">pip</span> <span class="n">install</span> <span class="n">google</span><span class="o">-</span><span class="n">adk</span> <span class="o">-</span><span class="n">q</span>
</span><span id="__span-0-5"><a id="__codelineno-0-5" name="__codelineno-0-5" href="#__codelineno-0-5"></a><span class="err">!</span><span class="n">pip</span> <span class="n">install</span> <span class="s2">"litellm&gt;=1.84"</span> <span class="o">-</span><span class="n">q</span>
</span><span id="__span-0-6"><a id="__codelineno-0-6" name="__codelineno-0-6" href="#__codelineno-0-6"></a>
</span><span id="__span-0-7"><a id="__codelineno-0-7" name="__codelineno-0-7" href="#__codelineno-0-7"></a><span class="nb">print</span><span class="p">(</span><span class="s2">"Installation complete."</span><span class="p">)</span>
</span></code></pre></div>
<div class="language-python highlight"><pre><span></span><code><span id="__span-1-1"><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a><span class="c1"># @title Import necessary libraries</span>
</span><span id="__span-1-2"><a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a><span class="kn">import</span><span class="w"> </span><span class="nn">os</span>
</span><span id="__span-1-3"><a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span>
</span><span id="__span-1-4"><a id="__codelineno-1-4" name="__codelineno-1-4" href="#__codelineno-1-4"></a><span class="kn">from</span><span class="w"> </span><span class="nn">google.adk.agents</span><span class="w"> </span><span class="kn">import</span> <span class="n">Agent</span>
</span><span id="__span-1-5"><a id="__codelineno-1-5" name="__codelineno-1-5" href="#__codelineno-1-5"></a><span class="kn">from</span><span class="w"> </span><span class="nn">google.adk.models.lite_llm</span><span class="w"> </span><span class="kn">import</span> <span class="n">LiteLlm</span> <span class="c1"># For multi-model support</span>
</span><span id="__span-1-6"><a id="__codelineno-1-6" name="__codelineno-1-6" href="#__codelineno-1-6"></a><span class="kn">from</span><span class="w"> </span><span class="nn">google.adk.sessions</span><span class="w"> </span><span class="kn">import</span> <span class="n">InMemorySessionService</span>
</span><span id="__span-1-7"><a id="__codelineno-1-7" name="__codelineno-1-7" href="#__codelineno-1-7"></a><span class="kn">from</span><span class="w"> </span><span class="nn">google.adk.runners</span><span class="w"> </span><span class="kn">import</span> <span class="n">Runner</span>
</span><span id="__span-1-8"><a id="__codelineno-1-8" name="__codelineno-1-8" href="#__codelineno-1-8"></a><span class="kn">from</span><span class="w"> </span><span class="nn">google.genai</span><span class="w"> </span><span class="kn">import</span> <span class="n">types</span> <span class="c1"># For creating message Content/Parts</span>
</span><span id="__span-1-9"><a id="__codelineno-1-9" name="__codelineno-1-9" href="#__codelineno-1-9"></a>
</span><span id="__span-1-10"><a id="__codelineno-1-10" name="__codelineno-1-10" href="#__codelineno-1-10"></a><span class="kn">import</span><span class="w"> </span><span class="nn">warnings</span>
</span><span id="__span-1-11"><a id="__codelineno-1-11" name="__codelineno-1-11" href="#__codelineno-1-11"></a><span class="c1"># Ignore all warnings</span>
</span><span id="__span-1-12"><a id="__codelineno-1-12" name="__codelineno-1-12" href="#__codelineno-1-12"></a><span class="n">warnings</span><span class="o">.</span><span class="n">filterwarnings</span><span class="p">(</span><span class="s2">"ignore"</span><span class="p">)</span>
</span><span id="__span-1-13"><a id="__codelineno-1-13" name="__codelineno-1-13" href="#__codelineno-1-13"></a>
</span><span id="__span-1-14"><a id="__codelineno-1-14" name="__codelineno-1-14" href="#__codelineno-1-14"></a><span class="kn">import</span><span class="w"> </span><span class="nn">logging</span>
</span><span id="__span-1-15"><a id="__codelineno-1-15" name="__codelineno-1-15" href="#__codelineno-1-15"></a><span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">ERROR</span><span class="p">)</span>
</span><span id="__span-1-16"><a id="__codelineno-1-16" name="__codelineno-1-16" href="#__codelineno-1-16"></a>
</span><span id="__span-1-17"><a id="__codelineno-1-17" name="__codelineno-1-17" href="#__codelineno-1-17"></a><span class="nb">print</span><span class="p">(</span><span class="s2">"Libraries imported."</span><span class="p">)</span>
</span></code></pre></div>
<div class="language-python highlight"><pre><span></span><code><span id="__span-2-1"><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a><span class="c1"># @title Configure API Keys (Replace with your actual keys!)</span>
</span><span id="__span-2-2"><a id="__codelineno-2-2" name="__codelineno-2-2" href="#__codelineno-2-2"></a>
</span><span id="__span-2-3"><a id="__codelineno-2-3" name="__codelineno-2-3" href="#__codelineno-2-3"></a><span class="c1"># --- IMPORTANT: Replace placeholders with your real API keys ---</span>
</span><span id="__span-2-4"><a id="__codelineno-2-4" name="__codelineno-2-4" href="#__codelineno-2-4"></a>
</span><span id="__span-2-5"><a id="__codelineno-2-5" name="__codelineno-2-5" href="#__codelineno-2-5"></a><span class="c1"># Gemini API Key (Get from Google AI Studio: https://aistudio.google.com/app/apikey)</span>
</span><span id="__span-2-6"><a id="__codelineno-2-6" name="__codelineno-2-6" href="#__codelineno-2-6"></a><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s2">"GOOGLE_API_KEY"</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"YOUR_GOOGLE_API_KEY"</span> <span class="c1"># &lt;--- REPLACE</span>
</span><span id="__span-2-7"><a id="__codelineno-2-7" name="__codelineno-2-7" href="#__codelineno-2-7"></a>
</span><span id="__span-2-8"><a id="__codelineno-2-8" name="__codelineno-2-8" href="#__codelineno-2-8"></a><span class="c1"># [Optional]</span>
</span><span id="__span-2-9"><a id="__codelineno-2-9" name="__codelineno-2-9" href="#__codelineno-2-9"></a><span class="c1"># OpenAI API Key (Get from OpenAI Platform: https://platform.openai.com/api-keys)</span>
</span><span id="__span-2-10"><a id="__codelineno-2-10" name="__codelineno-2-10" href="#__codelineno-2-10"></a><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s1">'OPENAI_API_KEY'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'YOUR_OPENAI_API_KEY'</span> <span class="c1"># &lt;--- REPLACE</span>
</span><span id="__span-2-11"><a id="__codelineno-2-11" name="__codelineno-2-11" href="#__codelineno-2-11"></a>
</span><span id="__span-2-12"><a id="__codelineno-2-12" name="__codelineno-2-12" href="#__codelineno-2-12"></a><span class="c1"># [Optional]</span>
</span><span id="__span-2-13"><a id="__codelineno-2-13" name="__codelineno-2-13" href="#__codelineno-2-13"></a><span class="c1"># Anthropic API Key (Get from Anthropic Console: https://console.anthropic.com/settings/keys)</span>
</span><span id="__span-2-14"><a id="__codelineno-2-14" name="__codelineno-2-14" href="#__codelineno-2-14"></a><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s1">'ANTHROPIC_API_KEY'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'YOUR_ANTHROPIC_API_KEY'</span> <span class="c1"># &lt;--- REPLACE</span>
</span><span id="__span-2-15"><a id="__codelineno-2-15" name="__codelineno-2-15" href="#__codelineno-2-15"></a>
</span><span id="__span-2-16"><a id="__codelineno-2-16" name="__codelineno-2-16" href="#__codelineno-2-16"></a><span class="c1"># --- Verify Keys (Optional Check) ---</span>
</span><span id="__span-2-17"><a id="__codelineno-2-17" name="__codelineno-2-17" href="#__codelineno-2-17"></a><span class="nb">print</span><span class="p">(</span><span class="s2">"API Keys Set:"</span><span class="p">)</span>
</span><span id="__span-2-18"><a id="__codelineno-2-18" name="__codelineno-2-18" href="#__codelineno-2-18"></a><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Google API Key set: </span><span class="si">{</span><span class="s1">'Yes'</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'GOOGLE_API_KEY'</span><span class="p">)</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s1">'GOOGLE_API_KEY'</span><span class="p">]</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="s1">'YOUR_GOOGLE_API_KEY'</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="s1">'No (REPLACE PLACEHOLDER!)'</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span><span id="__span-2-19"><a id="__codelineno-2-19" name="__codelineno-2-19" href="#__codelineno-2-19"></a><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"OpenAI API Key set: </span><span class="si">{</span><span class="s1">'Yes'</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'OPENAI_API_KEY'</span><span class="p">)</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s1">'OPENAI_API_KEY'</span><span class="p">]</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="s1">'YOUR_OPENAI_API_KEY'</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="s1">'No (REPLACE PLACEHOLDER!)'</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span><span id="__span-2-20"><a id="__codelineno-2-20" name="__codelineno-2-20" href="#__codelineno-2-20"></a><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Anthropic API Key set: </span><span class="si">{</span><span class="s1">'Yes'</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'ANTHROPIC_API_KEY'</span><span class="p">)</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s1">'ANTHROPIC_API_KEY'</span><span class="p">]</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="s1">'YOUR_ANTHROPIC_API_KEY'</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="s1">'No (REPLACE PLACEHOLDER!)'</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span><span id="__span-2-21"><a id="__codelineno-2-21" name="__codelineno-2-21" href="#__codelineno-2-21"></a>
</span><span id="__span-2-22"><a id="__codelineno-2-22" name="__codelineno-2-22" href="#__codelineno-2-22"></a><span class="c1"># Configure ADK to use API keys directly (not Agent Platform for this multi-model setup)</span>
</span><span id="__span-2-23"><a id="__codelineno-2-23" name="__codelineno-2-23" href="#__codelineno-2-23"></a><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s2">"GOOGLE_GENAI_USE_ENTERPRISE"</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"False"</span>
</span><span id="__span-2-24"><a id="__codelineno-2-24" name="__codelineno-2-24" href="#__codelineno-2-24"></a>
</span><span id="__span-2-25"><a id="__codelineno-2-25" name="__codelineno-2-25" href="#__codelineno-2-25"></a>
</span><span id="__span-2-26"><a id="__codelineno-2-26" name="__codelineno-2-26" href="#__codelineno-2-26"></a><span class="c1"># @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.</span>
</span></code></pre></div>
<div class="language-python highlight"><pre><span></span><code><span id="__span-3-1"><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a><span class="c1"># --- Define Model Constants for easier use ---</span>
</span><span id="__span-3-2"><a id="__codelineno-3-2" name="__codelineno-3-2" href="#__codelineno-3-2"></a>
</span><span id="__span-3-3"><a id="__codelineno-3-3" name="__codelineno-3-3" href="#__codelineno-3-3"></a><span class="c1"># More supported models can be referenced here: https://ai.google.dev/gemini-api/docs/models#model-variations</span>
</span><span id="__span-3-4"><a id="__codelineno-3-4" name="__codelineno-3-4" href="#__codelineno-3-4"></a><span class="n">MODEL_GEMINI_FLASH</span> <span class="o">=</span> <span class="s2">"gemini-flash-latest"</span>
</span><span id="__span-3-5"><a id="__codelineno-3-5" name="__codelineno-3-5" href="#__codelineno-3-5"></a>
</span><span id="__span-3-6"><a id="__codelineno-3-6" name="__codelineno-3-6" href="#__codelineno-3-6"></a><span class="c1"># More supported models can be referenced here: https://docs.litellm.ai/docs/providers/openai#openai-chat-completion-models</span>
</span><span id="__span-3-7"><a id="__codelineno-3-7" name="__codelineno-3-7" href="#__codelineno-3-7"></a><span class="n">MODEL_GPT_4O</span> <span class="o">=</span> <span class="s2">"openai/gpt-4.1"</span> <span class="c1"># You can also try: gpt-4.1-mini, gpt-4o etc.</span>
</span><span id="__span-3-8"><a id="__codelineno-3-8" name="__codelineno-3-8" href="#__codelineno-3-8"></a>
</span><span id="__span-3-9"><a id="__codelineno-3-9" name="__codelineno-3-9" href="#__codelineno-3-9"></a><span class="c1"># More supported models can be referenced here: https://docs.litellm.ai/docs/providers/anthropic</span>
</span><span id="__span-3-10"><a id="__codelineno-3-10" name="__codelineno-3-10" href="#__codelineno-3-10"></a><span class="n">MODEL_CLAUDE_SONNET</span> <span class="o">=</span> <span class="s2">"claude-sonnet-4-6"</span> <span class="c1"># You can also try: claude-opus-4-6, etc</span>
</span><span id="__span-3-11"><a id="__codelineno-3-11" name="__codelineno-3-11" href="#__codelineno-3-11"></a>
</span><span id="__span-3-12"><a id="__codelineno-3-12" name="__codelineno-3-12" href="#__codelineno-3-12"></a><span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">Environment configured."</span><span class="p">)</span>
</span></code></pre></div>
<hr />
<h2 id="step-1-your-first-agent-basic-weather-lookup">Step 1: Your First Agent - Basic Weather Lookup<a class="headerlink" href="#step-1-your-first-agent-basic-weather-lookup" title="Permanent link">&para;</a></h2>
<p>Let's begin by building the fundamental component of our Weather Bot: a single agent capable of performing a specific task – looking up weather information. This involves creating two core pieces:</p>
<ol>
<li><strong>A Tool:</strong> A Python function that equips the agent with the <em>ability</em> to fetch weather data.</li>
<li><strong>An Agent:</strong> The AI "brain" that understands the user's request, knows it has a weather tool, and decides when and how to use it.</li>
</ol>
<hr />
<p><strong>1. Define the Tool (<code>get_weather</code>)</strong></p>
<p>In ADK, <strong>Tools</strong> are the building blocks that give agents concrete capabilities beyond just text generation. They are typically regular Python functions that perform specific actions, like calling an API, querying a database, or performing calculations.</p>
<p>Our first tool will provide a <em>mock</em> weather report. This allows us to focus on the agent structure without needing external API keys yet. Later, you could easily swap this mock function with one that calls a real weather service.</p>
<p><strong>Key Concept: Docstrings are Crucial!</strong> The agent's LLM relies heavily on the function's <strong>docstring</strong> to understand:</p>
<ul>
<li><em>What</em> the tool does.</li>
<li><em>When</em> to use it.</li>
<li><em>What arguments</em> it requires (<code>city: str</code>).</li>
<li><em>What information</em> it returns.</li>
</ul>
<p><strong>Best Practice:</strong> Write clear, descriptive, and accurate docstrings for your tools. This is essential for the LLM to use the tool correctly.</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-4-1"><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><span class="c1"># @title Define the get_weather Tool</span>
</span><span id="__span-4-2"><a id="__codelineno-4-2" name="__codelineno-4-2" href="#__codelineno-4-2"></a><span class="k">def</span><span class="w"> </span><span class="nf">get_weather</span><span class="p">(</span><span class="n">city</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">:</span>
</span><span id="__span-4-3"><a id="__codelineno-4-3" name="__codelineno-4-3" href="#__codelineno-4-3"></a><span class="w"> </span><span class="sd">"""Retrieves the current weather report for a specified city.</span>
</span><span id="__span-4-4"><a id="__codelineno-4-4" name="__codelineno-4-4" href="#__codelineno-4-4"></a>
</span><span id="__span-4-5"><a id="__codelineno-4-5" name="__codelineno-4-5" href="#__codelineno-4-5"></a><span class="sd"> Args:</span>
</span><span id="__span-4-6"><a id="__codelineno-4-6" name="__codelineno-4-6" href="#__codelineno-4-6"></a><span class="sd"> city (str): The name of the city (e.g., "New York", "London", "Tokyo").</span>
</span><span id="__span-4-7"><a id="__codelineno-4-7" name="__codelineno-4-7" href="#__codelineno-4-7"></a>
</span><span id="__span-4-8"><a id="__codelineno-4-8" name="__codelineno-4-8" href="#__codelineno-4-8"></a><span class="sd"> Returns:</span>
</span><span id="__span-4-9"><a id="__codelineno-4-9" name="__codelineno-4-9" href="#__codelineno-4-9"></a><span class="sd"> dict: A dictionary containing the weather information.</span>
</span><span id="__span-4-10"><a id="__codelineno-4-10" name="__codelineno-4-10" href="#__codelineno-4-10"></a><span class="sd"> Includes a 'status' key ('success' or 'error').</span>
</span><span id="__span-4-11"><a id="__codelineno-4-11" name="__codelineno-4-11" href="#__codelineno-4-11"></a><span class="sd"> If 'success', includes a 'report' key with weather details.</span>
</span><span id="__span-4-12"><a id="__codelineno-4-12" name="__codelineno-4-12" href="#__codelineno-4-12"></a><span class="sd"> If 'error', includes an 'error_message' key.</span>
</span><span id="__span-4-13"><a id="__codelineno-4-13" name="__codelineno-4-13" href="#__codelineno-4-13"></a><span class="sd"> """</span>
</span><span id="__span-4-14"><a id="__codelineno-4-14" name="__codelineno-4-14" href="#__codelineno-4-14"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"--- Tool: get_weather called for city: </span><span class="si">{</span><span class="n">city</span><span class="si">}</span><span class="s2"> ---"</span><span class="p">)</span> <span class="c1"># Log tool execution</span>
</span><span id="__span-4-15"><a id="__codelineno-4-15" name="__codelineno-4-15" href="#__codelineno-4-15"></a> <span class="n">city_normalized</span> <span class="o">=</span> <span class="n">city</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">" "</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span> <span class="c1"># Basic normalization</span>
</span><span id="__span-4-16"><a id="__codelineno-4-16" name="__codelineno-4-16" href="#__codelineno-4-16"></a>
</span><span id="__span-4-17"><a id="__codelineno-4-17" name="__codelineno-4-17" href="#__codelineno-4-17"></a> <span class="c1"># Mock weather data</span>
</span><span id="__span-4-18"><a id="__codelineno-4-18" name="__codelineno-4-18" href="#__codelineno-4-18"></a> <span class="n">mock_weather_db</span> <span class="o">=</span> <span class="p">{</span>
</span><span id="__span-4-19"><a id="__codelineno-4-19" name="__codelineno-4-19" href="#__codelineno-4-19"></a> <span class="s2">"newyork"</span><span class="p">:</span> <span class="p">{</span><span class="s2">"status"</span><span class="p">:</span> <span class="s2">"success"</span><span class="p">,</span> <span class="s2">"report"</span><span class="p">:</span> <span class="s2">"The weather in New York is sunny with a temperature of 25°C."</span><span class="p">},</span>
</span><span id="__span-4-20"><a id="__codelineno-4-20" name="__codelineno-4-20" href="#__codelineno-4-20"></a> <span class="s2">"london"</span><span class="p">:</span> <span class="p">{</span><span class="s2">"status"</span><span class="p">:</span> <span class="s2">"success"</span><span class="p">,</span> <span class="s2">"report"</span><span class="p">:</span> <span class="s2">"It's cloudy in London with a temperature of 15°C."</span><span class="p">},</span>
</span><span id="__span-4-21"><a id="__codelineno-4-21" name="__codelineno-4-21" href="#__codelineno-4-21"></a> <span class="s2">"tokyo"</span><span class="p">:</span> <span class="p">{</span><span class="s2">"status"</span><span class="p">:</span> <span class="s2">"success"</span><span class="p">,</span> <span class="s2">"report"</span><span class="p">:</span> <span class="s2">"Tokyo is experiencing light rain and a temperature of 18°C."</span><span class="p">},</span>
</span><span id="__span-4-22"><a id="__codelineno-4-22" name="__codelineno-4-22" href="#__codelineno-4-22"></a> <span class="p">}</span>
</span><span id="__span-4-23"><a id="__codelineno-4-23" name="__codelineno-4-23" href="#__codelineno-4-23"></a>
</span><span id="__span-4-24"><a id="__codelineno-4-24" name="__codelineno-4-24" href="#__codelineno-4-24"></a> <span class="k">if</span> <span class="n">city_normalized</span> <span class="ow">in</span> <span class="n">mock_weather_db</span><span class="p">:</span>
</span><span id="__span-4-25"><a id="__codelineno-4-25" name="__codelineno-4-25" href="#__codelineno-4-25"></a> <span class="k">return</span> <span class="n">mock_weather_db</span><span class="p">[</span><span class="n">city_normalized</span><span class="p">]</span>
</span><span id="__span-4-26"><a id="__codelineno-4-26" name="__codelineno-4-26" href="#__codelineno-4-26"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-4-27"><a id="__codelineno-4-27" name="__codelineno-4-27" href="#__codelineno-4-27"></a> <span class="k">return</span> <span class="p">{</span><span class="s2">"status"</span><span class="p">:</span> <span class="s2">"error"</span><span class="p">,</span> <span class="s2">"error_message"</span><span class="p">:</span> <span class="sa">f</span><span class="s2">"Sorry, I don't have weather information for '</span><span class="si">{</span><span class="n">city</span><span class="si">}</span><span class="s2">'."</span><span class="p">}</span>
</span><span id="__span-4-28"><a id="__codelineno-4-28" name="__codelineno-4-28" href="#__codelineno-4-28"></a>
</span><span id="__span-4-29"><a id="__codelineno-4-29" name="__codelineno-4-29" href="#__codelineno-4-29"></a><span class="c1"># Example tool usage (optional test)</span>
</span><span id="__span-4-30"><a id="__codelineno-4-30" name="__codelineno-4-30" href="#__codelineno-4-30"></a><span class="nb">print</span><span class="p">(</span><span class="n">get_weather</span><span class="p">(</span><span class="s2">"New York"</span><span class="p">))</span>
</span><span id="__span-4-31"><a id="__codelineno-4-31" name="__codelineno-4-31" href="#__codelineno-4-31"></a><span class="nb">print</span><span class="p">(</span><span class="n">get_weather</span><span class="p">(</span><span class="s2">"Paris"</span><span class="p">))</span>
</span></code></pre></div>
<hr />
<p><strong>2. Define the Agent (<code>weather_agent</code>)</strong></p>
<p>Now, let's create the <strong>Agent</strong> itself. An <code>Agent</code> in ADK orchestrates the interaction between the user, the LLM, and the available tools.</p>
<p>We configure it with several key parameters:</p>
<ul>
<li><code>name</code>: A unique identifier for this agent (e.g., "weather_agent_v1").</li>
<li><code>model</code>: Specifies which LLM to use (e.g., <code>MODEL_GEMINI_FLASH</code>). We'll start with a specific Gemini model.</li>
<li><code>description</code>: A concise summary of the agent's overall purpose. This becomes crucial later when other agents need to decide whether to delegate tasks to <em>this</em> agent.</li>
<li><code>instruction</code>: Detailed guidance for the LLM on how to behave, its persona, its goals, and specifically <em>how and when</em> to utilize its assigned <code>tools</code>.</li>
<li><code>tools</code>: A list containing the actual Python tool functions the agent is allowed to use (e.g., <code>[get_weather]</code>).</li>
</ul>
<p><strong>Best Practice:</strong> Provide clear and specific <code>instruction</code> 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.</p>
<p><strong>Best Practice:</strong> Choose descriptive <code>name</code> and <code>description</code> values. These are used internally by ADK and are vital for features like automatic delegation (covered later).</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-5-1"><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a><span class="c1"># @title Define the Weather Agent</span>
</span><span id="__span-5-2"><a id="__codelineno-5-2" name="__codelineno-5-2" href="#__codelineno-5-2"></a><span class="c1"># Use one of the model constants defined earlier</span>
</span><span id="__span-5-3"><a id="__codelineno-5-3" name="__codelineno-5-3" href="#__codelineno-5-3"></a><span class="n">AGENT_MODEL</span> <span class="o">=</span> <span class="n">MODEL_GEMINI_FLASH</span> <span class="c1"># Starting with Gemini</span>
</span><span id="__span-5-4"><a id="__codelineno-5-4" name="__codelineno-5-4" href="#__codelineno-5-4"></a>
</span><span id="__span-5-5"><a id="__codelineno-5-5" name="__codelineno-5-5" href="#__codelineno-5-5"></a><span class="n">weather_agent</span> <span class="o">=</span> <span class="n">Agent</span><span class="p">(</span>
</span><span id="__span-5-6"><a id="__codelineno-5-6" name="__codelineno-5-6" href="#__codelineno-5-6"></a> <span class="n">name</span><span class="o">=</span><span class="s2">"weather_agent_v1"</span><span class="p">,</span>
</span><span id="__span-5-7"><a id="__codelineno-5-7" name="__codelineno-5-7" href="#__codelineno-5-7"></a> <span class="n">model</span><span class="o">=</span><span class="n">AGENT_MODEL</span><span class="p">,</span> <span class="c1"># Can be a string for Gemini or a LiteLlm object</span>
</span><span id="__span-5-8"><a id="__codelineno-5-8" name="__codelineno-5-8" href="#__codelineno-5-8"></a> <span class="n">description</span><span class="o">=</span><span class="s2">"Provides weather information for specific cities."</span><span class="p">,</span>
</span><span id="__span-5-9"><a id="__codelineno-5-9" name="__codelineno-5-9" href="#__codelineno-5-9"></a> <span class="n">instruction</span><span class="o">=</span><span class="s2">"You are a helpful weather assistant. "</span>
</span><span id="__span-5-10"><a id="__codelineno-5-10" name="__codelineno-5-10" href="#__codelineno-5-10"></a> <span class="s2">"When the user asks for the weather in a specific city, "</span>
</span><span id="__span-5-11"><a id="__codelineno-5-11" name="__codelineno-5-11" href="#__codelineno-5-11"></a> <span class="s2">"use the 'get_weather' tool to find the information. "</span>
</span><span id="__span-5-12"><a id="__codelineno-5-12" name="__codelineno-5-12" href="#__codelineno-5-12"></a> <span class="s2">"If the tool returns an error, inform the user politely. "</span>
</span><span id="__span-5-13"><a id="__codelineno-5-13" name="__codelineno-5-13" href="#__codelineno-5-13"></a> <span class="s2">"If the tool is successful, present the weather report clearly."</span><span class="p">,</span>
</span><span id="__span-5-14"><a id="__codelineno-5-14" name="__codelineno-5-14" href="#__codelineno-5-14"></a> <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">get_weather</span><span class="p">],</span> <span class="c1"># Pass the function directly</span>
</span><span id="__span-5-15"><a id="__codelineno-5-15" name="__codelineno-5-15" href="#__codelineno-5-15"></a><span class="p">)</span>
</span><span id="__span-5-16"><a id="__codelineno-5-16" name="__codelineno-5-16" href="#__codelineno-5-16"></a>
</span><span id="__span-5-17"><a id="__codelineno-5-17" name="__codelineno-5-17" href="#__codelineno-5-17"></a><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Agent '</span><span class="si">{</span><span class="n">weather_agent</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">' created using model '</span><span class="si">{</span><span class="n">AGENT_MODEL</span><span class="si">}</span><span class="s2">'."</span><span class="p">)</span>
</span></code></pre></div>
<hr />
<p><strong>3. Setup Runner and Session Service</strong></p>
<p>To manage conversations and execute the agent, we need two more components:</p>
<ul>
<li><code>SessionService</code>: Responsible for managing conversation history and state for different users and sessions. The <code>InMemorySessionService</code> 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.</li>
<li><code>Runner</code>: 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 <code>SessionService</code>, and yields events representing the progress of the interaction.</li>
</ul>
<div class="language-python highlight"><pre><span></span><code><span id="__span-6-1"><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a><span class="c1"># @title Setup Session Service and Runner</span>
</span><span id="__span-6-2"><a id="__codelineno-6-2" name="__codelineno-6-2" href="#__codelineno-6-2"></a>
</span><span id="__span-6-3"><a id="__codelineno-6-3" name="__codelineno-6-3" href="#__codelineno-6-3"></a><span class="c1"># --- Session Management ---</span>
</span><span id="__span-6-4"><a id="__codelineno-6-4" name="__codelineno-6-4" href="#__codelineno-6-4"></a><span class="c1"># Key Concept: SessionService stores conversation history &amp; state.</span>
</span><span id="__span-6-5"><a id="__codelineno-6-5" name="__codelineno-6-5" href="#__codelineno-6-5"></a><span class="c1"># InMemorySessionService is simple, non-persistent storage for this tutorial.</span>
</span><span id="__span-6-6"><a id="__codelineno-6-6" name="__codelineno-6-6" href="#__codelineno-6-6"></a><span class="n">session_service</span> <span class="o">=</span> <span class="n">InMemorySessionService</span><span class="p">()</span>
</span><span id="__span-6-7"><a id="__codelineno-6-7" name="__codelineno-6-7" href="#__codelineno-6-7"></a>
</span><span id="__span-6-8"><a id="__codelineno-6-8" name="__codelineno-6-8" href="#__codelineno-6-8"></a><span class="c1"># Define constants for identifying the interaction context</span>
</span><span id="__span-6-9"><a id="__codelineno-6-9" name="__codelineno-6-9" href="#__codelineno-6-9"></a><span class="n">APP_NAME</span> <span class="o">=</span> <span class="s2">"weather_tutorial_app"</span>
</span><span id="__span-6-10"><a id="__codelineno-6-10" name="__codelineno-6-10" href="#__codelineno-6-10"></a><span class="n">USER_ID</span> <span class="o">=</span> <span class="s2">"user_1"</span>
</span><span id="__span-6-11"><a id="__codelineno-6-11" name="__codelineno-6-11" href="#__codelineno-6-11"></a><span class="n">SESSION_ID</span> <span class="o">=</span> <span class="s2">"session_001"</span> <span class="c1"># Using a fixed ID for simplicity</span>
</span><span id="__span-6-12"><a id="__codelineno-6-12" name="__codelineno-6-12" href="#__codelineno-6-12"></a>
</span><span id="__span-6-13"><a id="__codelineno-6-13" name="__codelineno-6-13" href="#__codelineno-6-13"></a><span class="c1"># Create the specific session where the conversation will happen</span>
</span><span id="__span-6-14"><a id="__codelineno-6-14" name="__codelineno-6-14" href="#__codelineno-6-14"></a><span class="n">session</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session_service</span><span class="o">.</span><span class="n">create_session</span><span class="p">(</span>
</span><span id="__span-6-15"><a id="__codelineno-6-15" name="__codelineno-6-15" href="#__codelineno-6-15"></a> <span class="n">app_name</span><span class="o">=</span><span class="n">APP_NAME</span><span class="p">,</span>
</span><span id="__span-6-16"><a id="__codelineno-6-16" name="__codelineno-6-16" href="#__codelineno-6-16"></a> <span class="n">user_id</span><span class="o">=</span><span class="n">USER_ID</span><span class="p">,</span>
</span><span id="__span-6-17"><a id="__codelineno-6-17" name="__codelineno-6-17" href="#__codelineno-6-17"></a> <span class="n">session_id</span><span class="o">=</span><span class="n">SESSION_ID</span>
</span><span id="__span-6-18"><a id="__codelineno-6-18" name="__codelineno-6-18" href="#__codelineno-6-18"></a><span class="p">)</span>
</span><span id="__span-6-19"><a id="__codelineno-6-19" name="__codelineno-6-19" href="#__codelineno-6-19"></a><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Session created: App='</span><span class="si">{</span><span class="n">APP_NAME</span><span class="si">}</span><span class="s2">', User='</span><span class="si">{</span><span class="n">USER_ID</span><span class="si">}</span><span class="s2">', Session='</span><span class="si">{</span><span class="n">SESSION_ID</span><span class="si">}</span><span class="s2">'"</span><span class="p">)</span>
</span><span id="__span-6-20"><a id="__codelineno-6-20" name="__codelineno-6-20" href="#__codelineno-6-20"></a>
</span><span id="__span-6-21"><a id="__codelineno-6-21" name="__codelineno-6-21" href="#__codelineno-6-21"></a><span class="c1"># --- OR ---</span>
</span><span id="__span-6-22"><a id="__codelineno-6-22" name="__codelineno-6-22" href="#__codelineno-6-22"></a>
</span><span id="__span-6-23"><a id="__codelineno-6-23" name="__codelineno-6-23" href="#__codelineno-6-23"></a><span class="c1"># Uncomment the following lines if running as a standard Python script (.py file):</span>
</span><span id="__span-6-24"><a id="__codelineno-6-24" name="__codelineno-6-24" href="#__codelineno-6-24"></a>
</span><span id="__span-6-25"><a id="__codelineno-6-25" name="__codelineno-6-25" href="#__codelineno-6-25"></a><span class="c1"># from google.adk.sessions import Session</span>
</span><span id="__span-6-26"><a id="__codelineno-6-26" name="__codelineno-6-26" href="#__codelineno-6-26"></a><span class="c1">#</span>
</span><span id="__span-6-27"><a id="__codelineno-6-27" name="__codelineno-6-27" href="#__codelineno-6-27"></a><span class="c1"># async def init_session(app_name:str,user_id:str,session_id:str) -&gt; Session:</span>
</span><span id="__span-6-28"><a id="__codelineno-6-28" name="__codelineno-6-28" href="#__codelineno-6-28"></a><span class="c1"># session = await session_service.create_session(</span>
</span><span id="__span-6-29"><a id="__codelineno-6-29" name="__codelineno-6-29" href="#__codelineno-6-29"></a><span class="c1"># app_name=app_name,</span>
</span><span id="__span-6-30"><a id="__codelineno-6-30" name="__codelineno-6-30" href="#__codelineno-6-30"></a><span class="c1"># user_id=user_id,</span>
</span><span id="__span-6-31"><a id="__codelineno-6-31" name="__codelineno-6-31" href="#__codelineno-6-31"></a><span class="c1"># session_id=session_id</span>
</span><span id="__span-6-32"><a id="__codelineno-6-32" name="__codelineno-6-32" href="#__codelineno-6-32"></a><span class="c1"># )</span>
</span><span id="__span-6-33"><a id="__codelineno-6-33" name="__codelineno-6-33" href="#__codelineno-6-33"></a><span class="c1"># print(f"Session created: App='{app_name}', User='{user_id}', Session='{session_id}'")</span>
</span><span id="__span-6-34"><a id="__codelineno-6-34" name="__codelineno-6-34" href="#__codelineno-6-34"></a><span class="c1"># return session</span>
</span><span id="__span-6-35"><a id="__codelineno-6-35" name="__codelineno-6-35" href="#__codelineno-6-35"></a><span class="c1">#</span>
</span><span id="__span-6-36"><a id="__codelineno-6-36" name="__codelineno-6-36" href="#__codelineno-6-36"></a><span class="c1"># session = asyncio.run(init_session(APP_NAME,USER_ID,SESSION_ID))</span>
</span><span id="__span-6-37"><a id="__codelineno-6-37" name="__codelineno-6-37" href="#__codelineno-6-37"></a>
</span><span id="__span-6-38"><a id="__codelineno-6-38" name="__codelineno-6-38" href="#__codelineno-6-38"></a><span class="c1"># --- Runner ---</span>
</span><span id="__span-6-39"><a id="__codelineno-6-39" name="__codelineno-6-39" href="#__codelineno-6-39"></a><span class="c1"># Key Concept: Runner orchestrates the agent execution loop.</span>
</span><span id="__span-6-40"><a id="__codelineno-6-40" name="__codelineno-6-40" href="#__codelineno-6-40"></a><span class="n">runner</span> <span class="o">=</span> <span class="n">Runner</span><span class="p">(</span>
</span><span id="__span-6-41"><a id="__codelineno-6-41" name="__codelineno-6-41" href="#__codelineno-6-41"></a> <span class="n">agent</span><span class="o">=</span><span class="n">weather_agent</span><span class="p">,</span> <span class="c1"># The agent we want to run</span>
</span><span id="__span-6-42"><a id="__codelineno-6-42" name="__codelineno-6-42" href="#__codelineno-6-42"></a> <span class="n">app_name</span><span class="o">=</span><span class="n">APP_NAME</span><span class="p">,</span> <span class="c1"># Associates runs with our app</span>
</span><span id="__span-6-43"><a id="__codelineno-6-43" name="__codelineno-6-43" href="#__codelineno-6-43"></a> <span class="n">session_service</span><span class="o">=</span><span class="n">session_service</span> <span class="c1"># Uses our session manager</span>
</span><span id="__span-6-44"><a id="__codelineno-6-44" name="__codelineno-6-44" href="#__codelineno-6-44"></a><span class="p">)</span>
</span><span id="__span-6-45"><a id="__codelineno-6-45" name="__codelineno-6-45" href="#__codelineno-6-45"></a><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Runner created for agent '</span><span class="si">{</span><span class="n">runner</span><span class="o">.</span><span class="n">agent</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">'."</span><span class="p">)</span>
</span></code></pre></div>
<hr />
<p><strong>4. Interact with the Agent</strong></p>
<p>We need a way to send messages to our agent and receive its responses. Since LLM calls and tool executions can take time, ADK's <code>Runner</code> operates asynchronously.</p>
<p>We'll define an <code>async</code> helper function (<code>call_agent_async</code>) that:</p>
<ol>
<li>Takes a user query string.</li>
<li>Packages it into the ADK <code>Content</code> format.</li>
<li>Calls <code>runner.run_async</code>, providing the user/session context and the new message.</li>
<li>Iterates through the <strong>Events</strong> yielded by the runner. Events represent steps in the agent's execution (e.g., tool call requested, tool result received, intermediate LLM thought, final response).</li>
<li>Identifies and prints the <strong>final response</strong> event using <code>event.is_final_response()</code>.</li>
</ol>
<p><strong>Why <code>async</code>?</strong> Interactions with LLMs and potentially tools (like external APIs) are I/O-bound operations. Using <code>asyncio</code> allows the program to handle these operations efficiently without blocking execution.</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-7-1"><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a><span class="c1"># @title Define Agent Interaction Function</span>
</span><span id="__span-7-2"><a id="__codelineno-7-2" name="__codelineno-7-2" href="#__codelineno-7-2"></a>
</span><span id="__span-7-3"><a id="__codelineno-7-3" name="__codelineno-7-3" href="#__codelineno-7-3"></a><span class="kn">from</span><span class="w"> </span><span class="nn">google.genai</span><span class="w"> </span><span class="kn">import</span> <span class="n">types</span> <span class="c1"># For creating message Content/Parts</span>
</span><span id="__span-7-4"><a id="__codelineno-7-4" name="__codelineno-7-4" href="#__codelineno-7-4"></a>
</span><span id="__span-7-5"><a id="__codelineno-7-5" name="__codelineno-7-5" href="#__codelineno-7-5"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">call_agent_async</span><span class="p">(</span><span class="n">query</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">runner</span><span class="p">,</span> <span class="n">user_id</span><span class="p">,</span> <span class="n">session_id</span><span class="p">):</span>
</span><span id="__span-7-6"><a id="__codelineno-7-6" name="__codelineno-7-6" href="#__codelineno-7-6"></a><span class="w"> </span><span class="sd">"""Sends a query to the agent and prints the final response."""</span>
</span><span id="__span-7-7"><a id="__codelineno-7-7" name="__codelineno-7-7" href="#__codelineno-7-7"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="se">\n</span><span class="s2">&gt;&gt;&gt; User Query: </span><span class="si">{</span><span class="n">query</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span><span id="__span-7-8"><a id="__codelineno-7-8" name="__codelineno-7-8" href="#__codelineno-7-8"></a>
</span><span id="__span-7-9"><a id="__codelineno-7-9" name="__codelineno-7-9" href="#__codelineno-7-9"></a> <span class="c1"># Prepare the user's message in ADK format</span>
</span><span id="__span-7-10"><a id="__codelineno-7-10" name="__codelineno-7-10" href="#__codelineno-7-10"></a> <span class="n">content</span> <span class="o">=</span> <span class="n">types</span><span class="o">.</span><span class="n">Content</span><span class="p">(</span><span class="n">role</span><span class="o">=</span><span class="s1">'user'</span><span class="p">,</span> <span class="n">parts</span><span class="o">=</span><span class="p">[</span><span class="n">types</span><span class="o">.</span><span class="n">Part</span><span class="p">(</span><span class="n">text</span><span class="o">=</span><span class="n">query</span><span class="p">)])</span>
</span><span id="__span-7-11"><a id="__codelineno-7-11" name="__codelineno-7-11" href="#__codelineno-7-11"></a>
</span><span id="__span-7-12"><a id="__codelineno-7-12" name="__codelineno-7-12" href="#__codelineno-7-12"></a> <span class="n">final_response_text</span> <span class="o">=</span> <span class="s2">"Agent did not produce a final response."</span> <span class="c1"># Default</span>
</span><span id="__span-7-13"><a id="__codelineno-7-13" name="__codelineno-7-13" href="#__codelineno-7-13"></a>
</span><span id="__span-7-14"><a id="__codelineno-7-14" name="__codelineno-7-14" href="#__codelineno-7-14"></a> <span class="c1"># Key Concept: run_async executes the agent logic and yields Events.</span>
</span><span id="__span-7-15"><a id="__codelineno-7-15" name="__codelineno-7-15" href="#__codelineno-7-15"></a> <span class="c1"># We iterate through events to find the final answer.</span>
</span><span id="__span-7-16"><a id="__codelineno-7-16" name="__codelineno-7-16" href="#__codelineno-7-16"></a> <span class="k">async</span> <span class="k">for</span> <span class="n">event</span> <span class="ow">in</span> <span class="n">runner</span><span class="o">.</span><span class="n">run_async</span><span class="p">(</span><span class="n">user_id</span><span class="o">=</span><span class="n">user_id</span><span class="p">,</span> <span class="n">session_id</span><span class="o">=</span><span class="n">session_id</span><span class="p">,</span> <span class="n">new_message</span><span class="o">=</span><span class="n">content</span><span class="p">):</span>
</span><span id="__span-7-17"><a id="__codelineno-7-17" name="__codelineno-7-17" href="#__codelineno-7-17"></a> <span class="c1"># You can uncomment the line below to see *all* events during execution</span>
</span><span id="__span-7-18"><a id="__codelineno-7-18" name="__codelineno-7-18" href="#__codelineno-7-18"></a> <span class="c1"># print(f" [Event] Author: {event.author}, Type: {type(event).__name__}, Final: {event.is_final_response()}, Content: {event.content}")</span>
</span><span id="__span-7-19"><a id="__codelineno-7-19" name="__codelineno-7-19" href="#__codelineno-7-19"></a>
</span><span id="__span-7-20"><a id="__codelineno-7-20" name="__codelineno-7-20" href="#__codelineno-7-20"></a> <span class="c1"># Key Concept: is_final_response() marks the concluding message for the turn.</span>
</span><span id="__span-7-21"><a id="__codelineno-7-21" name="__codelineno-7-21" href="#__codelineno-7-21"></a> <span class="k">if</span> <span class="n">event</span><span class="o">.</span><span class="n">is_final_response</span><span class="p">():</span>
</span><span id="__span-7-22"><a id="__codelineno-7-22" name="__codelineno-7-22" href="#__codelineno-7-22"></a> <span class="k">if</span> <span class="n">event</span><span class="o">.</span><span class="n">content</span> <span class="ow">and</span> <span class="n">event</span><span class="o">.</span><span class="n">content</span><span class="o">.</span><span class="n">parts</span><span class="p">:</span>
</span><span id="__span-7-23"><a id="__codelineno-7-23" name="__codelineno-7-23" href="#__codelineno-7-23"></a> <span class="c1"># Assuming text response in the first part</span>
</span><span id="__span-7-24"><a id="__codelineno-7-24" name="__codelineno-7-24" href="#__codelineno-7-24"></a> <span class="n">final_response_text</span> <span class="o">=</span> <span class="n">event</span><span class="o">.</span><span class="n">content</span><span class="o">.</span><span class="n">parts</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">text</span>
</span><span id="__span-7-25"><a id="__codelineno-7-25" name="__codelineno-7-25" href="#__codelineno-7-25"></a> <span class="k">elif</span> <span class="n">event</span><span class="o">.</span><span class="n">actions</span> <span class="ow">and</span> <span class="n">event</span><span class="o">.</span><span class="n">actions</span><span class="o">.</span><span class="n">escalate</span><span class="p">:</span> <span class="c1"># Handle potential errors/escalations</span>
</span><span id="__span-7-26"><a id="__codelineno-7-26" name="__codelineno-7-26" href="#__codelineno-7-26"></a> <span class="n">final_response_text</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"Agent escalated: </span><span class="si">{</span><span class="n">event</span><span class="o">.</span><span class="n">error_message</span><span class="w"> </span><span class="ow">or</span><span class="w"> </span><span class="s1">'No specific message.'</span><span class="si">}</span><span class="s2">"</span>
</span><span id="__span-7-27"><a id="__codelineno-7-27" name="__codelineno-7-27" href="#__codelineno-7-27"></a> <span class="c1"># Add more checks here if needed (e.g., specific error codes)</span>
</span><span id="__span-7-28"><a id="__codelineno-7-28" name="__codelineno-7-28" href="#__codelineno-7-28"></a> <span class="k">break</span> <span class="c1"># Stop processing events once the final response is found</span>
</span><span id="__span-7-29"><a id="__codelineno-7-29" name="__codelineno-7-29" href="#__codelineno-7-29"></a>
</span><span id="__span-7-30"><a id="__codelineno-7-30" name="__codelineno-7-30" href="#__codelineno-7-30"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"&lt;&lt;&lt; Agent Response: </span><span class="si">{</span><span class="n">final_response_text</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></code></pre></div>
<hr />
<p><strong>5. Run the Conversation</strong></p>
<p>Finally, let's test our setup by sending a few queries to the agent. We wrap our <code>async</code> calls in a main <code>async</code> function and run it using <code>await</code>.</p>
<p>Watch the output:</p>
<ul>
<li>See the user queries.</li>
<li>Notice the <code>--- Tool: get_weather called... ---</code> logs when the agent uses the tool.</li>
<li>Observe the agent's final responses, including how it handles the case where weather data isn't available (for Paris).</li>
</ul>
<div class="language-python highlight"><pre><span></span><code><span id="__span-8-1"><a id="__codelineno-8-1" name="__codelineno-8-1" href="#__codelineno-8-1"></a><span class="c1"># @title Run the Initial Conversation</span>
</span><span id="__span-8-2"><a id="__codelineno-8-2" name="__codelineno-8-2" href="#__codelineno-8-2"></a>
</span><span id="__span-8-3"><a id="__codelineno-8-3" name="__codelineno-8-3" href="#__codelineno-8-3"></a><span class="c1"># We need an async function to await our interaction helper</span>
</span><span id="__span-8-4"><a id="__codelineno-8-4" name="__codelineno-8-4" href="#__codelineno-8-4"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run_conversation</span><span class="p">():</span>
</span><span id="__span-8-5"><a id="__codelineno-8-5" name="__codelineno-8-5" href="#__codelineno-8-5"></a> <span class="k">await</span> <span class="n">call_agent_async</span><span class="p">(</span><span class="s2">"What is the weather like in London?"</span><span class="p">,</span>
</span><span id="__span-8-6"><a id="__codelineno-8-6" name="__codelineno-8-6" href="#__codelineno-8-6"></a> <span class="n">runner</span><span class="o">=</span><span class="n">runner</span><span class="p">,</span>
</span><span id="__span-8-7"><a id="__codelineno-8-7" name="__codelineno-8-7" href="#__codelineno-8-7"></a> <span class="n">user_id</span><span class="o">=</span><span class="n">USER_ID</span><span class="p">,</span>
</span><span id="__span-8-8"><a id="__codelineno-8-8" name="__codelineno-8-8" href="#__codelineno-8-8"></a> <span class="n">session_id</span><span class="o">=</span><span class="n">SESSION_ID</span><span class="p">)</span>
</span><span id="__span-8-9"><a id="__codelineno-8-9" name="__codelineno-8-9" href="#__codelineno-8-9"></a>
</span><span id="__span-8-10"><a id="__codelineno-8-10" name="__codelineno-8-10" href="#__codelineno-8-10"></a> <span class="k">await</span> <span class="n">call_agent_async</span><span class="p">(</span><span class="s2">"How about Paris?"</span><span class="p">,</span>
</span><span id="__span-8-11"><a id="__codelineno-8-11" name="__codelineno-8-11" href="#__codelineno-8-11"></a> <span class="n">runner</span><span class="o">=</span><span class="n">runner</span><span class="p">,</span>
</span><span id="__span-8-12"><a id="__codelineno-8-12" name="__codelineno-8-12" href="#__codelineno-8-12"></a> <span class="n">user_id</span><span class="o">=</span><span class="n">USER_ID</span><span class="p">,</span>
</span><span id="__span-8-13"><a id="__codelineno-8-13" name="__codelineno-8-13" href="#__codelineno-8-13"></a> <span class="n">session_id</span><span class="o">=</span><span class="n">SESSION_ID</span><span class="p">)</span> <span class="c1"># Expecting the tool's error message</span>
</span><span id="__span-8-14"><a id="__codelineno-8-14" name="__codelineno-8-14" href="#__codelineno-8-14"></a>
</span><span id="__span-8-15"><a id="__codelineno-8-15" name="__codelineno-8-15" href="#__codelineno-8-15"></a> <span class="k">await</span> <span class="n">call_agent_async</span><span class="p">(</span><span class="s2">"Tell me the weather in New York"</span><span class="p">,</span>
</span><span id="__span-8-16"><a id="__codelineno-8-16" name="__codelineno-8-16" href="#__codelineno-8-16"></a> <span class="n">runner</span><span class="o">=</span><span class="n">runner</span><span class="p">,</span>
</span><span id="__span-8-17"><a id="__codelineno-8-17" name="__codelineno-8-17" href="#__codelineno-8-17"></a> <span class="n">user_id</span><span class="o">=</span><span class="n">USER_ID</span><span class="p">,</span>
</span><span id="__span-8-18"><a id="__codelineno-8-18" name="__codelineno-8-18" href="#__codelineno-8-18"></a> <span class="n">session_id</span><span class="o">=</span><span class="n">SESSION_ID</span><span class="p">)</span>
</span><span id="__span-8-19"><a id="__codelineno-8-19" name="__codelineno-8-19" href="#__codelineno-8-19"></a>
</span><span id="__span-8-20"><a id="__codelineno-8-20" name="__codelineno-8-20" href="#__codelineno-8-20"></a><span class="c1"># Execute the conversation using await in an async context (like Colab/Jupyter)</span>
</span><span id="__span-8-21"><a id="__codelineno-8-21" name="__codelineno-8-21" href="#__codelineno-8-21"></a><span class="k">await</span> <span class="n">run_conversation</span><span class="p">()</span>
</span><span id="__span-8-22"><a id="__codelineno-8-22" name="__codelineno-8-22" href="#__codelineno-8-22"></a>
</span><span id="__span-8-23"><a id="__codelineno-8-23" name="__codelineno-8-23" href="#__codelineno-8-23"></a><span class="c1"># --- OR ---</span>
</span><span id="__span-8-24"><a id="__codelineno-8-24" name="__codelineno-8-24" href="#__codelineno-8-24"></a>
</span><span id="__span-8-25"><a id="__codelineno-8-25" name="__codelineno-8-25" href="#__codelineno-8-25"></a><span class="c1"># Uncomment the following lines if running as a standard Python script (.py file):</span>
</span><span id="__span-8-26"><a id="__codelineno-8-26" name="__codelineno-8-26" href="#__codelineno-8-26"></a><span class="c1"># import asyncio</span>
</span><span id="__span-8-27"><a id="__codelineno-8-27" name="__codelineno-8-27" href="#__codelineno-8-27"></a><span class="c1"># if __name__ == "__main__":</span>
</span><span id="__span-8-28"><a id="__codelineno-8-28" name="__codelineno-8-28" href="#__codelineno-8-28"></a><span class="c1"># try:</span>
</span><span id="__span-8-29"><a id="__codelineno-8-29" name="__codelineno-8-29" href="#__codelineno-8-29"></a><span class="c1"># asyncio.run(run_conversation())</span>
</span><span id="__span-8-30"><a id="__codelineno-8-30" name="__codelineno-8-30" href="#__codelineno-8-30"></a><span class="c1"># except Exception as e:</span>
</span><span id="__span-8-31"><a id="__codelineno-8-31" name="__codelineno-8-31" href="#__codelineno-8-31"></a><span class="c1"># print(f"An error occurred: {e}")</span>
</span></code></pre></div>
<hr />
<p>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.</p>
<p>In the next step, we'll explore how to easily switch the underlying Language Model powering this agent.</p>
<h2 id="step-2-going-multi-model-with-litellm-optional">Step 2: Going Multi-Model with LiteLLM [Optional]<a class="headerlink" href="#step-2-going-multi-model-with-litellm-optional" title="Permanent link">&para;</a></h2>
<p>In Step 1, we built a functional Weather Agent powered by a specific Gemini model. While effective, real-world applications often benefit from the flexibility to use <em>different</em> Large Language Models (LLMs). Why?</p>
<ul>
<li><strong>Performance:</strong> Some models excel at specific tasks (e.g., coding, reasoning, creative writing).</li>
<li><strong>Cost:</strong> Different models have varying price points.</li>
<li><strong>Capabilities:</strong> Models offer diverse features, context window sizes, and fine-tuning options.</li>
<li><strong>Availability/Redundancy:</strong> Having alternatives ensures your application remains functional even if one provider experiences issues.</li>
</ul>
<p>ADK makes switching between models seamless through its integration with the <a href="https://github.com/BerriAI/litellm"><strong>LiteLLM</strong></a> library. LiteLLM acts as a consistent interface to over 100 different LLMs.</p>
<p><strong>In this step, we will:</strong></p>
<ol>
<li>Learn how to configure an ADK <code>Agent</code> to use models from providers like OpenAI (GPT) and Anthropic (Claude) using the <code>LiteLlm</code> wrapper.</li>
<li>Define, configure (with their own sessions and runners), and immediately test instances of our Weather Agent, each backed by a different LLM.</li>
<li>Interact with these different agents to observe potential variations in their responses, even when using the same underlying tool.</li>
</ol>
<hr />
<p><strong>1. Import <code>LiteLlm</code></strong></p>
<p>We imported this during the initial setup (Step 0), but it's the key component for multi-model support:</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-9-1"><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a><span class="c1"># @title 1. Import LiteLlm</span>
</span><span id="__span-9-2"><a id="__codelineno-9-2" name="__codelineno-9-2" href="#__codelineno-9-2"></a><span class="kn">from</span><span class="w"> </span><span class="nn">google.adk.models.lite_llm</span><span class="w"> </span><span class="kn">import</span> <span class="n">LiteLlm</span>
</span></code></pre></div>
<p><strong>2. Define and Test Multi-Model Agents</strong></p>
<p>Instead of passing only a model name string (which defaults to Google's Gemini models), we wrap the desired model identifier string within the <code>LiteLlm</code> class.</p>
<ul>
<li><strong>Key Concept: <code>LiteLlm</code> Wrapper:</strong> The <code>LiteLlm(model="provider/model_name")</code> syntax tells ADK to route requests for this agent through the LiteLLM library to the specified model provider.</li>
</ul>
<p>Make sure you have configured the necessary API keys for OpenAI and Anthropic in Step 0. We'll use the <code>call_agent_async</code> function (defined earlier, which now accepts <code>runner</code>, <code>user_id</code>, and <code>session_id</code>) to interact with each agent immediately after its setup.</p>
<p>Each block below will:</p>
<ul>
<li>Define the agent using a specific LiteLLM model (<code>MODEL_GPT_4O</code> or <code>MODEL_CLAUDE_SONNET</code>).</li>
<li>Create a <em>new, separate</em> <code>InMemorySessionService</code> and session specifically for that agent's test run. This keeps the conversation histories isolated for this demonstration.</li>
<li>Create a <code>Runner</code> configured for the specific agent and its session service.</li>
<li>Immediately call <code>call_agent_async</code> to send a query and test the agent.</li>
</ul>
<p><strong>Best Practice:</strong> Use constants for model names (like <code>MODEL_GPT_4O</code>, <code>MODEL_CLAUDE_SONNET</code> defined in Step 0) to avoid typos and make code easier to manage.</p>
<p><strong>Error Handling:</strong> We wrap the agent definitions in <code>try...except</code> 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 <em>are</em> configured.</p>
<p>First, let's create and test the agent using OpenAI's GPT-4o.</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-10-1"><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a><span class="c1"># @title Define and Test GPT Agent</span>
</span><span id="__span-10-2"><a id="__codelineno-10-2" name="__codelineno-10-2" href="#__codelineno-10-2"></a>
</span><span id="__span-10-3"><a id="__codelineno-10-3" name="__codelineno-10-3" href="#__codelineno-10-3"></a><span class="c1"># Make sure 'get_weather' function from Step 1 is defined in your environment.</span>
</span><span id="__span-10-4"><a id="__codelineno-10-4" name="__codelineno-10-4" href="#__codelineno-10-4"></a><span class="c1"># Make sure 'call_agent_async' is defined from earlier.</span>
</span><span id="__span-10-5"><a id="__codelineno-10-5" name="__codelineno-10-5" href="#__codelineno-10-5"></a>
</span><span id="__span-10-6"><a id="__codelineno-10-6" name="__codelineno-10-6" href="#__codelineno-10-6"></a><span class="c1"># --- Agent using GPT-4o ---</span>
</span><span id="__span-10-7"><a id="__codelineno-10-7" name="__codelineno-10-7" href="#__codelineno-10-7"></a><span class="n">weather_agent_gpt</span> <span class="o">=</span> <span class="kc">None</span> <span class="c1"># Initialize to None</span>
</span><span id="__span-10-8"><a id="__codelineno-10-8" name="__codelineno-10-8" href="#__codelineno-10-8"></a><span class="n">runner_gpt</span> <span class="o">=</span> <span class="kc">None</span> <span class="c1"># Initialize runner to None</span>
</span><span id="__span-10-9"><a id="__codelineno-10-9" name="__codelineno-10-9" href="#__codelineno-10-9"></a>
</span><span id="__span-10-10"><a id="__codelineno-10-10" name="__codelineno-10-10" href="#__codelineno-10-10"></a><span class="k">try</span><span class="p">:</span>
</span><span id="__span-10-11"><a id="__codelineno-10-11" name="__codelineno-10-11" href="#__codelineno-10-11"></a> <span class="n">weather_agent_gpt</span> <span class="o">=</span> <span class="n">Agent</span><span class="p">(</span>
</span><span id="__span-10-12"><a id="__codelineno-10-12" name="__codelineno-10-12" href="#__codelineno-10-12"></a> <span class="n">name</span><span class="o">=</span><span class="s2">"weather_agent_gpt"</span><span class="p">,</span>
</span><span id="__span-10-13"><a id="__codelineno-10-13" name="__codelineno-10-13" href="#__codelineno-10-13"></a> <span class="c1"># Key change: Wrap the LiteLLM model identifier</span>
</span><span id="__span-10-14"><a id="__codelineno-10-14" name="__codelineno-10-14" href="#__codelineno-10-14"></a> <span class="n">model</span><span class="o">=</span><span class="n">LiteLlm</span><span class="p">(</span><span class="n">model</span><span class="o">=</span><span class="n">MODEL_GPT_4O</span><span class="p">),</span>
</span><span id="__span-10-15"><a id="__codelineno-10-15" name="__codelineno-10-15" href="#__codelineno-10-15"></a> <span class="n">description</span><span class="o">=</span><span class="s2">"Provides weather information (using GPT-4o)."</span><span class="p">,</span>
</span><span id="__span-10-16"><a id="__codelineno-10-16" name="__codelineno-10-16" href="#__codelineno-10-16"></a> <span class="n">instruction</span><span class="o">=</span><span class="s2">"You are a helpful weather assistant powered by GPT-4o. "</span>
</span><span id="__span-10-17"><a id="__codelineno-10-17" name="__codelineno-10-17" href="#__codelineno-10-17"></a> <span class="s2">"Use the 'get_weather' tool for city weather requests. "</span>
</span><span id="__span-10-18"><a id="__codelineno-10-18" name="__codelineno-10-18" href="#__codelineno-10-18"></a> <span class="s2">"Clearly present successful reports or polite error messages based on the tool's output status."</span><span class="p">,</span>
</span><span id="__span-10-19"><a id="__codelineno-10-19" name="__codelineno-10-19" href="#__codelineno-10-19"></a> <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">get_weather</span><span class="p">],</span> <span class="c1"># Re-use the same tool</span>
</span><span id="__span-10-20"><a id="__codelineno-10-20" name="__codelineno-10-20" href="#__codelineno-10-20"></a> <span class="p">)</span>
</span><span id="__span-10-21"><a id="__codelineno-10-21" name="__codelineno-10-21" href="#__codelineno-10-21"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Agent '</span><span class="si">{</span><span class="n">weather_agent_gpt</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">' created using model '</span><span class="si">{</span><span class="n">MODEL_GPT_4O</span><span class="si">}</span><span class="s2">'."</span><span class="p">)</span>
</span><span id="__span-10-22"><a id="__codelineno-10-22" name="__codelineno-10-22" href="#__codelineno-10-22"></a>
</span><span id="__span-10-23"><a id="__codelineno-10-23" name="__codelineno-10-23" href="#__codelineno-10-23"></a> <span class="c1"># InMemorySessionService is simple, non-persistent storage for this tutorial.</span>
</span><span id="__span-10-24"><a id="__codelineno-10-24" name="__codelineno-10-24" href="#__codelineno-10-24"></a> <span class="n">session_service_gpt</span> <span class="o">=</span> <span class="n">InMemorySessionService</span><span class="p">()</span> <span class="c1"># Create a dedicated service</span>
</span><span id="__span-10-25"><a id="__codelineno-10-25" name="__codelineno-10-25" href="#__codelineno-10-25"></a>
</span><span id="__span-10-26"><a id="__codelineno-10-26" name="__codelineno-10-26" href="#__codelineno-10-26"></a> <span class="c1"># Define constants for identifying the interaction context</span>
</span><span id="__span-10-27"><a id="__codelineno-10-27" name="__codelineno-10-27" href="#__codelineno-10-27"></a> <span class="n">APP_NAME_GPT</span> <span class="o">=</span> <span class="s2">"weather_tutorial_app_gpt"</span> <span class="c1"># Unique app name for this test</span>
</span><span id="__span-10-28"><a id="__codelineno-10-28" name="__codelineno-10-28" href="#__codelineno-10-28"></a> <span class="n">USER_ID_GPT</span> <span class="o">=</span> <span class="s2">"user_1_gpt"</span>
</span><span id="__span-10-29"><a id="__codelineno-10-29" name="__codelineno-10-29" href="#__codelineno-10-29"></a> <span class="n">SESSION_ID_GPT</span> <span class="o">=</span> <span class="s2">"session_001_gpt"</span> <span class="c1"># Using a fixed ID for simplicity</span>
</span><span id="__span-10-30"><a id="__codelineno-10-30" name="__codelineno-10-30" href="#__codelineno-10-30"></a>
</span><span id="__span-10-31"><a id="__codelineno-10-31" name="__codelineno-10-31" href="#__codelineno-10-31"></a> <span class="c1"># Create the specific session where the conversation will happen</span>
</span><span id="__span-10-32"><a id="__codelineno-10-32" name="__codelineno-10-32" href="#__codelineno-10-32"></a> <span class="n">session_gpt</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session_service_gpt</span><span class="o">.</span><span class="n">create_session</span><span class="p">(</span>
</span><span id="__span-10-33"><a id="__codelineno-10-33" name="__codelineno-10-33" href="#__codelineno-10-33"></a> <span class="n">app_name</span><span class="o">=</span><span class="n">APP_NAME_GPT</span><span class="p">,</span>
</span><span id="__span-10-34"><a id="__codelineno-10-34" name="__codelineno-10-34" href="#__codelineno-10-34"></a> <span class="n">user_id</span><span class="o">=</span><span class="n">USER_ID_GPT</span><span class="p">,</span>
</span><span id="__span-10-35"><a id="__codelineno-10-35" name="__codelineno-10-35" href="#__codelineno-10-35"></a> <span class="n">session_id</span><span class="o">=</span><span class="n">SESSION_ID_GPT</span>
</span><span id="__span-10-36"><a id="__codelineno-10-36" name="__codelineno-10-36" href="#__codelineno-10-36"></a> <span class="p">)</span>
</span><span id="__span-10-37"><a id="__codelineno-10-37" name="__codelineno-10-37" href="#__codelineno-10-37"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Session created: App='</span><span class="si">{</span><span class="n">APP_NAME_GPT</span><span class="si">}</span><span class="s2">', User='</span><span class="si">{</span><span class="n">USER_ID_GPT</span><span class="si">}</span><span class="s2">', Session='</span><span class="si">{</span><span class="n">SESSION_ID_GPT</span><span class="si">}</span><span class="s2">'"</span><span class="p">)</span>
</span><span id="__span-10-38"><a id="__codelineno-10-38" name="__codelineno-10-38" href="#__codelineno-10-38"></a>
</span><span id="__span-10-39"><a id="__codelineno-10-39" name="__codelineno-10-39" href="#__codelineno-10-39"></a> <span class="c1"># Create a runner specific to this agent and its session service</span>
</span><span id="__span-10-40"><a id="__codelineno-10-40" name="__codelineno-10-40" href="#__codelineno-10-40"></a> <span class="n">runner_gpt</span> <span class="o">=</span> <span class="n">Runner</span><span class="p">(</span>
</span><span id="__span-10-41"><a id="__codelineno-10-41" name="__codelineno-10-41" href="#__codelineno-10-41"></a> <span class="n">agent</span><span class="o">=</span><span class="n">weather_agent_gpt</span><span class="p">,</span>
</span><span id="__span-10-42"><a id="__codelineno-10-42" name="__codelineno-10-42" href="#__codelineno-10-42"></a> <span class="n">app_name</span><span class="o">=</span><span class="n">APP_NAME_GPT</span><span class="p">,</span> <span class="c1"># Use the specific app name</span>
</span><span id="__span-10-43"><a id="__codelineno-10-43" name="__codelineno-10-43" href="#__codelineno-10-43"></a> <span class="n">session_service</span><span class="o">=</span><span class="n">session_service_gpt</span> <span class="c1"># Use the specific session service</span>
</span><span id="__span-10-44"><a id="__codelineno-10-44" name="__codelineno-10-44" href="#__codelineno-10-44"></a> <span class="p">)</span>
</span><span id="__span-10-45"><a id="__codelineno-10-45" name="__codelineno-10-45" href="#__codelineno-10-45"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Runner created for agent '</span><span class="si">{</span><span class="n">runner_gpt</span><span class="o">.</span><span class="n">agent</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">'."</span><span class="p">)</span>
</span><span id="__span-10-46"><a id="__codelineno-10-46" name="__codelineno-10-46" href="#__codelineno-10-46"></a>
</span><span id="__span-10-47"><a id="__codelineno-10-47" name="__codelineno-10-47" href="#__codelineno-10-47"></a> <span class="c1"># --- Test the GPT Agent ---</span>
</span><span id="__span-10-48"><a id="__codelineno-10-48" name="__codelineno-10-48" href="#__codelineno-10-48"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">--- Testing GPT Agent ---"</span><span class="p">)</span>
</span><span id="__span-10-49"><a id="__codelineno-10-49" name="__codelineno-10-49" href="#__codelineno-10-49"></a> <span class="c1"># Ensure call_agent_async uses the correct runner, user_id, session_id</span>
</span><span id="__span-10-50"><a id="__codelineno-10-50" name="__codelineno-10-50" href="#__codelineno-10-50"></a> <span class="k">await</span> <span class="n">call_agent_async</span><span class="p">(</span><span class="n">query</span> <span class="o">=</span> <span class="s2">"What's the weather in Tokyo?"</span><span class="p">,</span>
</span><span id="__span-10-51"><a id="__codelineno-10-51" name="__codelineno-10-51" href="#__codelineno-10-51"></a> <span class="n">runner</span><span class="o">=</span><span class="n">runner_gpt</span><span class="p">,</span>
</span><span id="__span-10-52"><a id="__codelineno-10-52" name="__codelineno-10-52" href="#__codelineno-10-52"></a> <span class="n">user_id</span><span class="o">=</span><span class="n">USER_ID_GPT</span><span class="p">,</span>
</span><span id="__span-10-53"><a id="__codelineno-10-53" name="__codelineno-10-53" href="#__codelineno-10-53"></a> <span class="n">session_id</span><span class="o">=</span><span class="n">SESSION_ID_GPT</span><span class="p">)</span>
</span><span id="__span-10-54"><a id="__codelineno-10-54" name="__codelineno-10-54" href="#__codelineno-10-54"></a> <span class="c1"># --- OR ---</span>
</span><span id="__span-10-55"><a id="__codelineno-10-55" name="__codelineno-10-55" href="#__codelineno-10-55"></a>
</span><span id="__span-10-56"><a id="__codelineno-10-56" name="__codelineno-10-56" href="#__codelineno-10-56"></a> <span class="c1"># Uncomment the following lines if running as a standard Python script (.py file):</span>
</span><span id="__span-10-57"><a id="__codelineno-10-57" name="__codelineno-10-57" href="#__codelineno-10-57"></a> <span class="c1"># import asyncio</span>
</span><span id="__span-10-58"><a id="__codelineno-10-58" name="__codelineno-10-58" href="#__codelineno-10-58"></a> <span class="c1"># if __name__ == "__main__":</span>
</span><span id="__span-10-59"><a id="__codelineno-10-59" name="__codelineno-10-59" href="#__codelineno-10-59"></a> <span class="c1"># try:</span>
</span><span id="__span-10-60"><a id="__codelineno-10-60" name="__codelineno-10-60" href="#__codelineno-10-60"></a> <span class="c1"># asyncio.run(call_agent_async(query = "What's the weather in Tokyo?",</span>
</span><span id="__span-10-61"><a id="__codelineno-10-61" name="__codelineno-10-61" href="#__codelineno-10-61"></a> <span class="c1"># runner=runner_gpt,</span>
</span><span id="__span-10-62"><a id="__codelineno-10-62" name="__codelineno-10-62" href="#__codelineno-10-62"></a> <span class="c1"># user_id=USER_ID_GPT,</span>
</span><span id="__span-10-63"><a id="__codelineno-10-63" name="__codelineno-10-63" href="#__codelineno-10-63"></a> <span class="c1"># session_id=SESSION_ID_GPT)</span>
</span><span id="__span-10-64"><a id="__codelineno-10-64" name="__codelineno-10-64" href="#__codelineno-10-64"></a> <span class="c1"># except Exception as e:</span>
</span><span id="__span-10-65"><a id="__codelineno-10-65" name="__codelineno-10-65" href="#__codelineno-10-65"></a> <span class="c1"># print(f"An error occurred: {e}")</span>
</span><span id="__span-10-66"><a id="__codelineno-10-66" name="__codelineno-10-66" href="#__codelineno-10-66"></a>
</span><span id="__span-10-67"><a id="__codelineno-10-67" name="__codelineno-10-67" href="#__codelineno-10-67"></a><span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span><span id="__span-10-68"><a id="__codelineno-10-68" name="__codelineno-10-68" href="#__codelineno-10-68"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"❌ Could not create or run GPT agent '</span><span class="si">{</span><span class="n">MODEL_GPT_4O</span><span class="si">}</span><span class="s2">'. Check API Key and model name. Error: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></code></pre></div>
<p>Next, we'll do the same for Anthropic's Claude Sonnet.</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-11-1"><a id="__codelineno-11-1" name="__codelineno-11-1" href="#__codelineno-11-1"></a><span class="c1"># @title Define and Test Claude Agent</span>
</span><span id="__span-11-2"><a id="__codelineno-11-2" name="__codelineno-11-2" href="#__codelineno-11-2"></a>
</span><span id="__span-11-3"><a id="__codelineno-11-3" name="__codelineno-11-3" href="#__codelineno-11-3"></a><span class="c1"># Make sure 'get_weather' function from Step 1 is defined in your environment.</span>
</span><span id="__span-11-4"><a id="__codelineno-11-4" name="__codelineno-11-4" href="#__codelineno-11-4"></a><span class="c1"># Make sure 'call_agent_async' is defined from earlier.</span>
</span><span id="__span-11-5"><a id="__codelineno-11-5" name="__codelineno-11-5" href="#__codelineno-11-5"></a>
</span><span id="__span-11-6"><a id="__codelineno-11-6" name="__codelineno-11-6" href="#__codelineno-11-6"></a><span class="c1"># --- Agent using Claude Sonnet ---</span>
</span><span id="__span-11-7"><a id="__codelineno-11-7" name="__codelineno-11-7" href="#__codelineno-11-7"></a><span class="n">weather_agent_claude</span> <span class="o">=</span> <span class="kc">None</span> <span class="c1"># Initialize to None</span>
</span><span id="__span-11-8"><a id="__codelineno-11-8" name="__codelineno-11-8" href="#__codelineno-11-8"></a><span class="n">runner_claude</span> <span class="o">=</span> <span class="kc">None</span> <span class="c1"># Initialize runner to None</span>
</span><span id="__span-11-9"><a id="__codelineno-11-9" name="__codelineno-11-9" href="#__codelineno-11-9"></a>
</span><span id="__span-11-10"><a id="__codelineno-11-10" name="__codelineno-11-10" href="#__codelineno-11-10"></a><span class="k">try</span><span class="p">:</span>
</span><span id="__span-11-11"><a id="__codelineno-11-11" name="__codelineno-11-11" href="#__codelineno-11-11"></a> <span class="n">weather_agent_claude</span> <span class="o">=</span> <span class="n">Agent</span><span class="p">(</span>
</span><span id="__span-11-12"><a id="__codelineno-11-12" name="__codelineno-11-12" href="#__codelineno-11-12"></a> <span class="n">name</span><span class="o">=</span><span class="s2">"weather_agent_claude"</span><span class="p">,</span>
</span><span id="__span-11-13"><a id="__codelineno-11-13" name="__codelineno-11-13" href="#__codelineno-11-13"></a> <span class="c1"># Key change: Wrap the LiteLLM model identifier</span>
</span><span id="__span-11-14"><a id="__codelineno-11-14" name="__codelineno-11-14" href="#__codelineno-11-14"></a> <span class="n">model</span><span class="o">=</span><span class="n">LiteLlm</span><span class="p">(</span><span class="n">model</span><span class="o">=</span><span class="n">MODEL_CLAUDE_SONNET</span><span class="p">),</span>
</span><span id="__span-11-15"><a id="__codelineno-11-15" name="__codelineno-11-15" href="#__codelineno-11-15"></a> <span class="n">description</span><span class="o">=</span><span class="s2">"Provides weather information (using Claude Sonnet)."</span><span class="p">,</span>
</span><span id="__span-11-16"><a id="__codelineno-11-16" name="__codelineno-11-16" href="#__codelineno-11-16"></a> <span class="n">instruction</span><span class="o">=</span><span class="s2">"You are a helpful weather assistant powered by Claude Sonnet. "</span>
</span><span id="__span-11-17"><a id="__codelineno-11-17" name="__codelineno-11-17" href="#__codelineno-11-17"></a> <span class="s2">"Use the 'get_weather' tool for city weather requests. "</span>
</span><span id="__span-11-18"><a id="__codelineno-11-18" name="__codelineno-11-18" href="#__codelineno-11-18"></a> <span class="s2">"Analyze the tool's dictionary output ('status', 'report'/'error_message'). "</span>
</span><span id="__span-11-19"><a id="__codelineno-11-19" name="__codelineno-11-19" href="#__codelineno-11-19"></a> <span class="s2">"Clearly present successful reports or polite error messages."</span><span class="p">,</span>
</span><span id="__span-11-20"><a id="__codelineno-11-20" name="__codelineno-11-20" href="#__codelineno-11-20"></a> <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">get_weather</span><span class="p">],</span> <span class="c1"># Re-use the same tool</span>
</span><span id="__span-11-21"><a id="__codelineno-11-21" name="__codelineno-11-21" href="#__codelineno-11-21"></a> <span class="p">)</span>
</span><span id="__span-11-22"><a id="__codelineno-11-22" name="__codelineno-11-22" href="#__codelineno-11-22"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Agent '</span><span class="si">{</span><span class="n">weather_agent_claude</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">' created using model '</span><span class="si">{</span><span class="n">MODEL_CLAUDE_SONNET</span><span class="si">}</span><span class="s2">'."</span><span class="p">)</span>
</span><span id="__span-11-23"><a id="__codelineno-11-23" name="__codelineno-11-23" href="#__codelineno-11-23"></a>
</span><span id="__span-11-24"><a id="__codelineno-11-24" name="__codelineno-11-24" href="#__codelineno-11-24"></a> <span class="c1"># InMemorySessionService is simple, non-persistent storage for this tutorial.</span>
</span><span id="__span-11-25"><a id="__codelineno-11-25" name="__codelineno-11-25" href="#__codelineno-11-25"></a> <span class="n">session_service_claude</span> <span class="o">=</span> <span class="n">InMemorySessionService</span><span class="p">()</span> <span class="c1"># Create a dedicated service</span>
</span><span id="__span-11-26"><a id="__codelineno-11-26" name="__codelineno-11-26" href="#__codelineno-11-26"></a>
</span><span id="__span-11-27"><a id="__codelineno-11-27" name="__codelineno-11-27" href="#__codelineno-11-27"></a> <span class="c1"># Define constants for identifying the interaction context</span>
</span><span id="__span-11-28"><a id="__codelineno-11-28" name="__codelineno-11-28" href="#__codelineno-11-28"></a> <span class="n">APP_NAME_CLAUDE</span> <span class="o">=</span> <span class="s2">"weather_tutorial_app_claude"</span> <span class="c1"># Unique app name</span>
</span><span id="__span-11-29"><a id="__codelineno-11-29" name="__codelineno-11-29" href="#__codelineno-11-29"></a> <span class="n">USER_ID_CLAUDE</span> <span class="o">=</span> <span class="s2">"user_1_claude"</span>
</span><span id="__span-11-30"><a id="__codelineno-11-30" name="__codelineno-11-30" href="#__codelineno-11-30"></a> <span class="n">SESSION_ID_CLAUDE</span> <span class="o">=</span> <span class="s2">"session_001_claude"</span> <span class="c1"># Using a fixed ID for simplicity</span>
</span><span id="__span-11-31"><a id="__codelineno-11-31" name="__codelineno-11-31" href="#__codelineno-11-31"></a>
</span><span id="__span-11-32"><a id="__codelineno-11-32" name="__codelineno-11-32" href="#__codelineno-11-32"></a> <span class="c1"># Create the specific session where the conversation will happen</span>
</span><span id="__span-11-33"><a id="__codelineno-11-33" name="__codelineno-11-33" href="#__codelineno-11-33"></a> <span class="n">session_claude</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session_service_claude</span><span class="o">.</span><span class="n">create_session</span><span class="p">(</span>
</span><span id="__span-11-34"><a id="__codelineno-11-34" name="__codelineno-11-34" href="#__codelineno-11-34"></a> <span class="n">app_name</span><span class="o">=</span><span class="n">APP_NAME_CLAUDE</span><span class="p">,</span>
</span><span id="__span-11-35"><a id="__codelineno-11-35" name="__codelineno-11-35" href="#__codelineno-11-35"></a> <span class="n">user_id</span><span class="o">=</span><span class="n">USER_ID_CLAUDE</span><span class="p">,</span>
</span><span id="__span-11-36"><a id="__codelineno-11-36" name="__codelineno-11-36" href="#__codelineno-11-36"></a> <span class="n">session_id</span><span class="o">=</span><span class="n">SESSION_ID_CLAUDE</span>
</span><span id="__span-11-37"><a id="__codelineno-11-37" name="__codelineno-11-37" href="#__codelineno-11-37"></a> <span class="p">)</span>
</span><span id="__span-11-38"><a id="__codelineno-11-38" name="__codelineno-11-38" href="#__codelineno-11-38"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Session created: App='</span><span class="si">{</span><span class="n">APP_NAME_CLAUDE</span><span class="si">}</span><span class="s2">', User='</span><span class="si">{</span><span class="n">USER_ID_CLAUDE</span><span class="si">}</span><span class="s2">', Session='</span><span class="si">{</span><span class="n">SESSION_ID_CLAUDE</span><span class="si">}</span><span class="s2">'"</span><span class="p">)</span>
</span><span id="__span-11-39"><a id="__codelineno-11-39" name="__codelineno-11-39" href="#__codelineno-11-39"></a>
</span><span id="__span-11-40"><a id="__codelineno-11-40" name="__codelineno-11-40" href="#__codelineno-11-40"></a> <span class="c1"># Create a runner specific to this agent and its session service</span>
</span><span id="__span-11-41"><a id="__codelineno-11-41" name="__codelineno-11-41" href="#__codelineno-11-41"></a> <span class="n">runner_claude</span> <span class="o">=</span> <span class="n">Runner</span><span class="p">(</span>
</span><span id="__span-11-42"><a id="__codelineno-11-42" name="__codelineno-11-42" href="#__codelineno-11-42"></a> <span class="n">agent</span><span class="o">=</span><span class="n">weather_agent_claude</span><span class="p">,</span>
</span><span id="__span-11-43"><a id="__codelineno-11-43" name="__codelineno-11-43" href="#__codelineno-11-43"></a> <span class="n">app_name</span><span class="o">=</span><span class="n">APP_NAME_CLAUDE</span><span class="p">,</span> <span class="c1"># Use the specific app name</span>
</span><span id="__span-11-44"><a id="__codelineno-11-44" name="__codelineno-11-44" href="#__codelineno-11-44"></a> <span class="n">session_service</span><span class="o">=</span><span class="n">session_service_claude</span> <span class="c1"># Use the specific session service</span>
</span><span id="__span-11-45"><a id="__codelineno-11-45" name="__codelineno-11-45" href="#__codelineno-11-45"></a> <span class="p">)</span>
</span><span id="__span-11-46"><a id="__codelineno-11-46" name="__codelineno-11-46" href="#__codelineno-11-46"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Runner created for agent '</span><span class="si">{</span><span class="n">runner_claude</span><span class="o">.</span><span class="n">agent</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">'."</span><span class="p">)</span>
</span><span id="__span-11-47"><a id="__codelineno-11-47" name="__codelineno-11-47" href="#__codelineno-11-47"></a>
</span><span id="__span-11-48"><a id="__codelineno-11-48" name="__codelineno-11-48" href="#__codelineno-11-48"></a> <span class="c1"># --- Test the Claude Agent ---</span>
</span><span id="__span-11-49"><a id="__codelineno-11-49" name="__codelineno-11-49" href="#__codelineno-11-49"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">--- Testing Claude Agent ---"</span><span class="p">)</span>
</span><span id="__span-11-50"><a id="__codelineno-11-50" name="__codelineno-11-50" href="#__codelineno-11-50"></a> <span class="c1"># Ensure call_agent_async uses the correct runner, user_id, session_id</span>
</span><span id="__span-11-51"><a id="__codelineno-11-51" name="__codelineno-11-51" href="#__codelineno-11-51"></a> <span class="k">await</span> <span class="n">call_agent_async</span><span class="p">(</span><span class="n">query</span> <span class="o">=</span> <span class="s2">"Weather in London please."</span><span class="p">,</span>
</span><span id="__span-11-52"><a id="__codelineno-11-52" name="__codelineno-11-52" href="#__codelineno-11-52"></a> <span class="n">runner</span><span class="o">=</span><span class="n">runner_claude</span><span class="p">,</span>
</span><span id="__span-11-53"><a id="__codelineno-11-53" name="__codelineno-11-53" href="#__codelineno-11-53"></a> <span class="n">user_id</span><span class="o">=</span><span class="n">USER_ID_CLAUDE</span><span class="p">,</span>
</span><span id="__span-11-54"><a id="__codelineno-11-54" name="__codelineno-11-54" href="#__codelineno-11-54"></a> <span class="n">session_id</span><span class="o">=</span><span class="n">SESSION_ID_CLAUDE</span><span class="p">)</span>
</span><span id="__span-11-55"><a id="__codelineno-11-55" name="__codelineno-11-55" href="#__codelineno-11-55"></a>
</span><span id="__span-11-56"><a id="__codelineno-11-56" name="__codelineno-11-56" href="#__codelineno-11-56"></a> <span class="c1"># --- OR ---</span>
</span><span id="__span-11-57"><a id="__codelineno-11-57" name="__codelineno-11-57" href="#__codelineno-11-57"></a>
</span><span id="__span-11-58"><a id="__codelineno-11-58" name="__codelineno-11-58" href="#__codelineno-11-58"></a> <span class="c1"># Uncomment the following lines if running as a standard Python script (.py file):</span>
</span><span id="__span-11-59"><a id="__codelineno-11-59" name="__codelineno-11-59" href="#__codelineno-11-59"></a> <span class="c1"># import asyncio</span>
</span><span id="__span-11-60"><a id="__codelineno-11-60" name="__codelineno-11-60" href="#__codelineno-11-60"></a> <span class="c1"># if __name__ == "__main__":</span>
</span><span id="__span-11-61"><a id="__codelineno-11-61" name="__codelineno-11-61" href="#__codelineno-11-61"></a> <span class="c1"># try:</span>
</span><span id="__span-11-62"><a id="__codelineno-11-62" name="__codelineno-11-62" href="#__codelineno-11-62"></a> <span class="c1"># asyncio.run(call_agent_async(query = "Weather in London please.",</span>
</span><span id="__span-11-63"><a id="__codelineno-11-63" name="__codelineno-11-63" href="#__codelineno-11-63"></a> <span class="c1"># runner=runner_claude,</span>
</span><span id="__span-11-64"><a id="__codelineno-11-64" name="__codelineno-11-64" href="#__codelineno-11-64"></a> <span class="c1"># user_id=USER_ID_CLAUDE,</span>
</span><span id="__span-11-65"><a id="__codelineno-11-65" name="__codelineno-11-65" href="#__codelineno-11-65"></a> <span class="c1"># session_id=SESSION_ID_CLAUDE)</span>
</span><span id="__span-11-66"><a id="__codelineno-11-66" name="__codelineno-11-66" href="#__codelineno-11-66"></a> <span class="c1"># except Exception as e:</span>
</span><span id="__span-11-67"><a id="__codelineno-11-67" name="__codelineno-11-67" href="#__codelineno-11-67"></a> <span class="c1"># print(f"An error occurred: {e}")</span>
</span><span id="__span-11-68"><a id="__codelineno-11-68" name="__codelineno-11-68" href="#__codelineno-11-68"></a>
</span><span id="__span-11-69"><a id="__codelineno-11-69" name="__codelineno-11-69" href="#__codelineno-11-69"></a>
</span><span id="__span-11-70"><a id="__codelineno-11-70" name="__codelineno-11-70" href="#__codelineno-11-70"></a><span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span><span id="__span-11-71"><a id="__codelineno-11-71" name="__codelineno-11-71" href="#__codelineno-11-71"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"❌ Could not create or run Claude agent '</span><span class="si">{</span><span class="n">MODEL_CLAUDE_SONNET</span><span class="si">}</span><span class="s2">'. Check API Key and model name. Error: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></code></pre></div>
<p>Observe the output carefully from both code blocks. You should see:</p>
<ol>
<li>Each agent (<code>weather_agent_gpt</code>, <code>weather_agent_claude</code>) is created successfully (if API keys are valid).</li>
<li>A dedicated session and runner are set up for each.</li>
<li>Each agent correctly identifies the need to use the <code>get_weather</code> tool when processing the query (you'll see the <code>--- Tool: get_weather called... ---</code> log).</li>
<li>The <em>underlying tool logic</em> remains identical, always returning our mock data.</li>
<li>However, the <strong>final textual response</strong> generated by each agent might differ slightly in phrasing, tone, or formatting. This is because the instruction prompt is interpreted and executed by different LLMs (GPT-4o vs. Claude Sonnet).</li>
</ol>
<p>This step demonstrates the power and flexibility ADK + LiteLLM provide. You can easily experiment with and deploy agents using various LLMs while keeping your core application logic (tools, fundamental agent structure) consistent.</p>
<p>In the next step, we'll move beyond a single agent and build a small team where agents can delegate tasks to each other!</p>
<hr />
<h2 id="step-3-building-an-agent-team-delegation-for-greetings-farewells">Step 3: Building an Agent Team - Delegation for Greetings &amp; Farewells<a class="headerlink" href="#step-3-building-an-agent-team-delegation-for-greetings-farewells" title="Permanent link">&para;</a></h2>
<p>In Steps 1 and 2, we built and experimented with a single agent focused solely on weather lookups. While effective for its specific task, real-world applications often involve handling a wider variety of user interactions. We <em>could</em> keep adding more tools and complex instructions to our single weather agent, but this can quickly become unmanageable and less efficient.</p>
<p>A more robust approach is to build an <strong>Agent Team</strong>. This involves:</p>
<ol>
<li>Creating multiple, <strong>specialized agents</strong>, each designed for a specific capability (e.g., one for weather, one for greetings, one for calculations).</li>
<li>Designating a <strong>root agent</strong> (or orchestrator) that receives the initial user request.</li>
<li>Enabling the root agent to <strong>delegate</strong> the request to the most appropriate specialized sub-agent based on the user's intent.</li>
</ol>
<p><strong>Why build an Agent Team?</strong></p>
<ul>
<li><strong>Modularity:</strong> Easier to develop, test, and maintain individual agents.</li>
<li><strong>Specialization:</strong> Each agent can be fine-tuned (instructions, model choice) for its specific task.</li>
<li><strong>Scalability:</strong> Simpler to add new capabilities by adding new agents.</li>
<li><strong>Efficiency:</strong> Allows using potentially simpler/cheaper models for simpler tasks (like greetings).</li>
</ul>
<p><strong>In this step, we will:</strong></p>
<ol>
<li>Define simple tools for handling greetings (<code>say_hello</code>) and farewells (<code>say_goodbye</code>).</li>
<li>Create two new specialized sub-agents: <code>greeting_agent</code> and <code>farewell_agent</code>.</li>
<li>Update our main weather agent (<code>weather_agent_v2</code>) to act as the <strong>root agent</strong>.</li>
<li>Configure the root agent with its sub-agents, enabling <strong>automatic delegation</strong>.</li>
<li>Test the delegation flow by sending different types of requests to the root agent.</li>
</ol>
<hr />
<p><strong>1. Define Tools for Sub-Agents</strong></p>
<p>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.</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-12-1"><a id="__codelineno-12-1" name="__codelineno-12-1" href="#__codelineno-12-1"></a><span class="c1"># @title Define Tools for Greeting and Farewell Agents</span>
</span><span id="__span-12-2"><a id="__codelineno-12-2" name="__codelineno-12-2" href="#__codelineno-12-2"></a><span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Optional</span> <span class="c1"># Make sure to import Optional</span>
</span><span id="__span-12-3"><a id="__codelineno-12-3" name="__codelineno-12-3" href="#__codelineno-12-3"></a>
</span><span id="__span-12-4"><a id="__codelineno-12-4" name="__codelineno-12-4" href="#__codelineno-12-4"></a><span class="c1"># Ensure 'get_weather' from Step 1 is available if running this step independently.</span>
</span><span id="__span-12-5"><a id="__codelineno-12-5" name="__codelineno-12-5" href="#__codelineno-12-5"></a><span class="c1"># def get_weather(city: str) -&gt; dict: ... (from Step 1)</span>
</span><span id="__span-12-6"><a id="__codelineno-12-6" name="__codelineno-12-6" href="#__codelineno-12-6"></a>
</span><span id="__span-12-7"><a id="__codelineno-12-7" name="__codelineno-12-7" href="#__codelineno-12-7"></a><span class="k">def</span><span class="w"> </span><span class="nf">say_hello</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span><span id="__span-12-8"><a id="__codelineno-12-8" name="__codelineno-12-8" href="#__codelineno-12-8"></a><span class="w"> </span><span class="sd">"""Provides a simple greeting. If a name is provided, it will be used.</span>
</span><span id="__span-12-9"><a id="__codelineno-12-9" name="__codelineno-12-9" href="#__codelineno-12-9"></a>
</span><span id="__span-12-10"><a id="__codelineno-12-10" name="__codelineno-12-10" href="#__codelineno-12-10"></a><span class="sd"> Args:</span>
</span><span id="__span-12-11"><a id="__codelineno-12-11" name="__codelineno-12-11" href="#__codelineno-12-11"></a><span class="sd"> name (str, optional): The name of the person to greet. Defaults to a generic greeting if not provided.</span>
</span><span id="__span-12-12"><a id="__codelineno-12-12" name="__codelineno-12-12" href="#__codelineno-12-12"></a>
</span><span id="__span-12-13"><a id="__codelineno-12-13" name="__codelineno-12-13" href="#__codelineno-12-13"></a><span class="sd"> Returns:</span>
</span><span id="__span-12-14"><a id="__codelineno-12-14" name="__codelineno-12-14" href="#__codelineno-12-14"></a><span class="sd"> str: A friendly greeting message.</span>
</span><span id="__span-12-15"><a id="__codelineno-12-15" name="__codelineno-12-15" href="#__codelineno-12-15"></a><span class="sd"> """</span>
</span><span id="__span-12-16"><a id="__codelineno-12-16" name="__codelineno-12-16" href="#__codelineno-12-16"></a> <span class="k">if</span> <span class="n">name</span><span class="p">:</span>
</span><span id="__span-12-17"><a id="__codelineno-12-17" name="__codelineno-12-17" href="#__codelineno-12-17"></a> <span class="n">greeting</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"Hello, </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">!"</span>
</span><span id="__span-12-18"><a id="__codelineno-12-18" name="__codelineno-12-18" href="#__codelineno-12-18"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"--- Tool: say_hello called with name: </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2"> ---"</span><span class="p">)</span>
</span><span id="__span-12-19"><a id="__codelineno-12-19" name="__codelineno-12-19" href="#__codelineno-12-19"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-12-20"><a id="__codelineno-12-20" name="__codelineno-12-20" href="#__codelineno-12-20"></a> <span class="n">greeting</span> <span class="o">=</span> <span class="s2">"Hello there!"</span> <span class="c1"># Default greeting if name is None or not explicitly passed</span>
</span><span id="__span-12-21"><a id="__codelineno-12-21" name="__codelineno-12-21" href="#__codelineno-12-21"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"--- Tool: say_hello called without a specific name (name_arg_value: </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">) ---"</span><span class="p">)</span>
</span><span id="__span-12-22"><a id="__codelineno-12-22" name="__codelineno-12-22" href="#__codelineno-12-22"></a> <span class="k">return</span> <span class="n">greeting</span>
</span><span id="__span-12-23"><a id="__codelineno-12-23" name="__codelineno-12-23" href="#__codelineno-12-23"></a>
</span><span id="__span-12-24"><a id="__codelineno-12-24" name="__codelineno-12-24" href="#__codelineno-12-24"></a><span class="k">def</span><span class="w"> </span><span class="nf">say_goodbye</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span><span id="__span-12-25"><a id="__codelineno-12-25" name="__codelineno-12-25" href="#__codelineno-12-25"></a><span class="w"> </span><span class="sd">"""Provides a simple farewell message to conclude the conversation."""</span>
</span><span id="__span-12-26"><a id="__codelineno-12-26" name="__codelineno-12-26" href="#__codelineno-12-26"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"--- Tool: say_goodbye called ---"</span><span class="p">)</span>
</span><span id="__span-12-27"><a id="__codelineno-12-27" name="__codelineno-12-27" href="#__codelineno-12-27"></a> <span class="k">return</span> <span class="s2">"Goodbye! Have a great day."</span>
</span><span id="__span-12-28"><a id="__codelineno-12-28" name="__codelineno-12-28" href="#__codelineno-12-28"></a>
</span><span id="__span-12-29"><a id="__codelineno-12-29" name="__codelineno-12-29" href="#__codelineno-12-29"></a><span class="nb">print</span><span class="p">(</span><span class="s2">"Greeting and Farewell tools defined."</span><span class="p">)</span>
</span><span id="__span-12-30"><a id="__codelineno-12-30" name="__codelineno-12-30" href="#__codelineno-12-30"></a>
</span><span id="__span-12-31"><a id="__codelineno-12-31" name="__codelineno-12-31" href="#__codelineno-12-31"></a><span class="c1"># Optional self-test</span>
</span><span id="__span-12-32"><a id="__codelineno-12-32" name="__codelineno-12-32" href="#__codelineno-12-32"></a><span class="nb">print</span><span class="p">(</span><span class="n">say_hello</span><span class="p">(</span><span class="s2">"Alice"</span><span class="p">))</span>
</span><span id="__span-12-33"><a id="__codelineno-12-33" name="__codelineno-12-33" href="#__codelineno-12-33"></a><span class="nb">print</span><span class="p">(</span><span class="n">say_hello</span><span class="p">())</span> <span class="c1"># Test with no argument (should use default "Hello there!")</span>
</span><span id="__span-12-34"><a id="__codelineno-12-34" name="__codelineno-12-34" href="#__codelineno-12-34"></a><span class="nb">print</span><span class="p">(</span><span class="n">say_hello</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="kc">None</span><span class="p">))</span> <span class="c1"># Test with name explicitly as None (should use default "Hello there!")</span>
</span></code></pre></div>
<hr />
<p><strong>2. Define the Sub-Agents (Greeting &amp; Farewell)</strong></p>
<p>Now, create the <code>Agent</code> instances for our specialists. Notice their highly focused <code>instruction</code> and, critically, their clear <code>description</code>. The <code>description</code> is the primary information the <em>root agent</em> uses to decide <em>when</em> to delegate to these sub-agents.</p>
<p><strong>Best Practice:</strong> Sub-agent <code>description</code> fields should accurately and concisely summarize their specific capability. This is crucial for effective automatic delegation.</p>
<p><strong>Best Practice:</strong> Sub-agent <code>instruction</code> fields should be tailored to their limited scope, telling them exactly what to do and <em>what not</em> to do (e.g., "Your <em>only</em> task is...").</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-13-1"><a id="__codelineno-13-1" name="__codelineno-13-1" href="#__codelineno-13-1"></a><span class="c1"># @title Define Greeting and Farewell Sub-Agents</span>
</span><span id="__span-13-2"><a id="__codelineno-13-2" name="__codelineno-13-2" href="#__codelineno-13-2"></a>
</span><span id="__span-13-3"><a id="__codelineno-13-3" name="__codelineno-13-3" href="#__codelineno-13-3"></a><span class="c1"># If you want to use models other than Gemini, Ensure LiteLlm is imported and API keys are set (from Step 0/2)</span>
</span><span id="__span-13-4"><a id="__codelineno-13-4" name="__codelineno-13-4" href="#__codelineno-13-4"></a><span class="c1"># from google.adk.models.lite_llm import LiteLlm</span>
</span><span id="__span-13-5"><a id="__codelineno-13-5" name="__codelineno-13-5" href="#__codelineno-13-5"></a><span class="c1"># MODEL_GPT_4O, MODEL_CLAUDE_SONNET etc. should be defined</span>
</span><span id="__span-13-6"><a id="__codelineno-13-6" name="__codelineno-13-6" href="#__codelineno-13-6"></a><span class="c1"># Or else, continue to use: model = MODEL_GEMINI_FLASH</span>
</span><span id="__span-13-7"><a id="__codelineno-13-7" name="__codelineno-13-7" href="#__codelineno-13-7"></a>
</span><span id="__span-13-8"><a id="__codelineno-13-8" name="__codelineno-13-8" href="#__codelineno-13-8"></a><span class="c1"># --- Greeting Agent ---</span>
</span><span id="__span-13-9"><a id="__codelineno-13-9" name="__codelineno-13-9" href="#__codelineno-13-9"></a><span class="n">greeting_agent</span> <span class="o">=</span> <span class="kc">None</span>
</span><span id="__span-13-10"><a id="__codelineno-13-10" name="__codelineno-13-10" href="#__codelineno-13-10"></a><span class="k">try</span><span class="p">:</span>
</span><span id="__span-13-11"><a id="__codelineno-13-11" name="__codelineno-13-11" href="#__codelineno-13-11"></a> <span class="n">greeting_agent</span> <span class="o">=</span> <span class="n">Agent</span><span class="p">(</span>
</span><span id="__span-13-12"><a id="__codelineno-13-12" name="__codelineno-13-12" href="#__codelineno-13-12"></a> <span class="c1"># Using a potentially different/cheaper model for a simple task</span>
</span><span id="__span-13-13"><a id="__codelineno-13-13" name="__codelineno-13-13" href="#__codelineno-13-13"></a> <span class="n">model</span> <span class="o">=</span> <span class="n">MODEL_GEMINI_FLASH</span><span class="p">,</span>
</span><span id="__span-13-14"><a id="__codelineno-13-14" name="__codelineno-13-14" href="#__codelineno-13-14"></a> <span class="c1"># model=LiteLlm(model=MODEL_GPT_4O), # If you would like to experiment with other models</span>
</span><span id="__span-13-15"><a id="__codelineno-13-15" name="__codelineno-13-15" href="#__codelineno-13-15"></a> <span class="n">name</span><span class="o">=</span><span class="s2">"greeting_agent"</span><span class="p">,</span>
</span><span id="__span-13-16"><a id="__codelineno-13-16" name="__codelineno-13-16" href="#__codelineno-13-16"></a> <span class="n">instruction</span><span class="o">=</span><span class="s2">"You are the Greeting Agent. Your ONLY task is to provide a friendly greeting to the user. "</span>
</span><span id="__span-13-17"><a id="__codelineno-13-17" name="__codelineno-13-17" href="#__codelineno-13-17"></a> <span class="s2">"Use the 'say_hello' tool to generate the greeting. "</span>
</span><span id="__span-13-18"><a id="__codelineno-13-18" name="__codelineno-13-18" href="#__codelineno-13-18"></a> <span class="s2">"If the user provides their name, make sure to pass it to the tool. "</span>
</span><span id="__span-13-19"><a id="__codelineno-13-19" name="__codelineno-13-19" href="#__codelineno-13-19"></a> <span class="s2">"Do not engage in any other conversation or tasks."</span><span class="p">,</span>
</span><span id="__span-13-20"><a id="__codelineno-13-20" name="__codelineno-13-20" href="#__codelineno-13-20"></a> <span class="n">description</span><span class="o">=</span><span class="s2">"Handles simple greetings and hellos using the 'say_hello' tool."</span><span class="p">,</span> <span class="c1"># Crucial for delegation</span>
</span><span id="__span-13-21"><a id="__codelineno-13-21" name="__codelineno-13-21" href="#__codelineno-13-21"></a> <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">say_hello</span><span class="p">],</span>
</span><span id="__span-13-22"><a id="__codelineno-13-22" name="__codelineno-13-22" href="#__codelineno-13-22"></a> <span class="p">)</span>
</span><span id="__span-13-23"><a id="__codelineno-13-23" name="__codelineno-13-23" href="#__codelineno-13-23"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"✅ Agent '</span><span class="si">{</span><span class="n">greeting_agent</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">' created using model '</span><span class="si">{</span><span class="n">greeting_agent</span><span class="o">.</span><span class="n">model</span><span class="si">}</span><span class="s2">'."</span><span class="p">)</span>
</span><span id="__span-13-24"><a id="__codelineno-13-24" name="__codelineno-13-24" href="#__codelineno-13-24"></a><span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span><span id="__span-13-25"><a id="__codelineno-13-25" name="__codelineno-13-25" href="#__codelineno-13-25"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"❌ Could not create Greeting agent. Check API Key (</span><span class="si">{</span><span class="n">greeting_agent</span><span class="o">.</span><span class="n">model</span><span class="si">}</span><span class="s2">). Error: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span><span id="__span-13-26"><a id="__codelineno-13-26" name="__codelineno-13-26" href="#__codelineno-13-26"></a>
</span><span id="__span-13-27"><a id="__codelineno-13-27" name="__codelineno-13-27" href="#__codelineno-13-27"></a><span class="c1"># --- Farewell Agent ---</span>
</span><span id="__span-13-28"><a id="__codelineno-13-28" name="__codelineno-13-28" href="#__codelineno-13-28"></a><span class="n">farewell_agent</span> <span class="o">=</span> <span class="kc">None</span>
</span><span id="__span-13-29"><a id="__codelineno-13-29" name="__codelineno-13-29" href="#__codelineno-13-29"></a><span class="k">try</span><span class="p">:</span>
</span><span id="__span-13-30"><a id="__codelineno-13-30" name="__codelineno-13-30" href="#__codelineno-13-30"></a> <span class="n">farewell_agent</span> <span class="o">=</span> <span class="n">Agent</span><span class="p">(</span>
</span><span id="__span-13-31"><a id="__codelineno-13-31" name="__codelineno-13-31" href="#__codelineno-13-31"></a> <span class="c1"># Can use the same or a different model</span>
</span><span id="__span-13-32"><a id="__codelineno-13-32" name="__codelineno-13-32" href="#__codelineno-13-32"></a> <span class="n">model</span> <span class="o">=</span> <span class="n">MODEL_GEMINI_FLASH</span><span class="p">,</span>
</span><span id="__span-13-33"><a id="__codelineno-13-33" name="__codelineno-13-33" href="#__codelineno-13-33"></a> <span class="c1"># model=LiteLlm(model=MODEL_GPT_4O), # If you would like to experiment with other models</span>
</span><span id="__span-13-34"><a id="__codelineno-13-34" name="__codelineno-13-34" href="#__codelineno-13-34"></a> <span class="n">name</span><span class="o">=</span><span class="s2">"farewell_agent"</span><span class="p">,</span>
</span><span id="__span-13-35"><a id="__codelineno-13-35" name="__codelineno-13-35" href="#__codelineno-13-35"></a> <span class="n">instruction</span><span class="o">=</span><span class="s2">"You are the Farewell Agent. Your ONLY task is to provide a polite goodbye message. "</span>
</span><span id="__span-13-36"><a id="__codelineno-13-36" name="__codelineno-13-36" href="#__codelineno-13-36"></a> <span class="s2">"Use the 'say_goodbye' tool when the user indicates they are leaving or ending the conversation "</span>
</span><span id="__span-13-37"><a id="__codelineno-13-37" name="__codelineno-13-37" href="#__codelineno-13-37"></a> <span class="s2">"(e.g., using words like 'bye', 'goodbye', 'thanks bye', 'see you'). "</span>
</span><span id="__span-13-38"><a id="__codelineno-13-38" name="__codelineno-13-38" href="#__codelineno-13-38"></a> <span class="s2">"Do not perform any other actions."</span><span class="p">,</span>
</span><span id="__span-13-39"><a id="__codelineno-13-39" name="__codelineno-13-39" href="#__codelineno-13-39"></a> <span class="n">description</span><span class="o">=</span><span class="s2">"Handles simple farewells and goodbyes using the 'say_goodbye' tool."</span><span class="p">,</span> <span class="c1"># Crucial for delegation</span>
</span><span id="__span-13-40"><a id="__codelineno-13-40" name="__codelineno-13-40" href="#__codelineno-13-40"></a> <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">say_goodbye</span><span class="p">],</span>
</span><span id="__span-13-41"><a id="__codelineno-13-41" name="__codelineno-13-41" href="#__codelineno-13-41"></a> <span class="p">)</span>
</span><span id="__span-13-42"><a id="__codelineno-13-42" name="__codelineno-13-42" href="#__codelineno-13-42"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"✅ Agent '</span><span class="si">{</span><span class="n">farewell_agent</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">' created using model '</span><span class="si">{</span><span class="n">farewell_agent</span><span class="o">.</span><span class="n">model</span><span class="si">}</span><span class="s2">'."</span><span class="p">)</span>
</span><span id="__span-13-43"><a id="__codelineno-13-43" name="__codelineno-13-43" href="#__codelineno-13-43"></a><span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span><span id="__span-13-44"><a id="__codelineno-13-44" name="__codelineno-13-44" href="#__codelineno-13-44"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"❌ Could not create Farewell agent. Check API Key (</span><span class="si">{</span><span class="n">farewell_agent</span><span class="o">.</span><span class="n">model</span><span class="si">}</span><span class="s2">). Error: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></code></pre></div>
<hr />
<p><strong>3. Define the Root Agent (Weather Agent v2) with Sub-Agents</strong></p>
<p>Now, we upgrade our <code>weather_agent</code>. The key changes are:</p>
<ul>
<li>Adding the <code>sub_agents</code> parameter: We pass a list containing the <code>greeting_agent</code> and <code>farewell_agent</code> instances we just created.</li>
<li>Updating the <code>instruction</code>: We explicitly tell the root agent <em>about</em> its sub-agents and <em>when</em> it should delegate tasks to them.</li>
</ul>
<p><strong>Key Concept: Automatic Delegation (Auto Flow)</strong> By providing the <code>sub_agents</code> 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 <code>description</code> 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 <em>transfer control</em> to that sub-agent for that turn. The sub-agent then processes the query using its own model, instructions, and tools.</p>
<p><strong>Best Practice:</strong> 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.</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-14-1"><a id="__codelineno-14-1" name="__codelineno-14-1" href="#__codelineno-14-1"></a><span class="c1"># @title Define the Root Agent with Sub-Agents</span>
</span><span id="__span-14-2"><a id="__codelineno-14-2" name="__codelineno-14-2" href="#__codelineno-14-2"></a>
</span><span id="__span-14-3"><a id="__codelineno-14-3" name="__codelineno-14-3" href="#__codelineno-14-3"></a><span class="c1"># Ensure sub-agents were created successfully before defining the root agent.</span>
</span><span id="__span-14-4"><a id="__codelineno-14-4" name="__codelineno-14-4" href="#__codelineno-14-4"></a><span class="c1"># Also ensure the original 'get_weather' tool is defined.</span>
</span><span id="__span-14-5"><a id="__codelineno-14-5" name="__codelineno-14-5" href="#__codelineno-14-5"></a><span class="n">root_agent</span> <span class="o">=</span> <span class="kc">None</span>
</span><span id="__span-14-6"><a id="__codelineno-14-6" name="__codelineno-14-6" href="#__codelineno-14-6"></a><span class="n">runner_root</span> <span class="o">=</span> <span class="kc">None</span> <span class="c1"># Initialize runner</span>
</span><span id="__span-14-7"><a id="__codelineno-14-7" name="__codelineno-14-7" href="#__codelineno-14-7"></a>
</span><span id="__span-14-8"><a id="__codelineno-14-8" name="__codelineno-14-8" href="#__codelineno-14-8"></a><span class="k">if</span> <span class="n">greeting_agent</span> <span class="ow">and</span> <span class="n">farewell_agent</span> <span class="ow">and</span> <span class="s1">'get_weather'</span> <span class="ow">in</span> <span class="nb">globals</span><span class="p">():</span>
</span><span id="__span-14-9"><a id="__codelineno-14-9" name="__codelineno-14-9" href="#__codelineno-14-9"></a> <span class="c1"># Let's use a capable Gemini model for the root agent to handle orchestration</span>
</span><span id="__span-14-10"><a id="__codelineno-14-10" name="__codelineno-14-10" href="#__codelineno-14-10"></a> <span class="n">root_agent_model</span> <span class="o">=</span> <span class="n">MODEL_GEMINI_FLASH</span>
</span><span id="__span-14-11"><a id="__codelineno-14-11" name="__codelineno-14-11" href="#__codelineno-14-11"></a>
</span><span id="__span-14-12"><a id="__codelineno-14-12" name="__codelineno-14-12" href="#__codelineno-14-12"></a> <span class="n">weather_agent_team</span> <span class="o">=</span> <span class="n">Agent</span><span class="p">(</span>
</span><span id="__span-14-13"><a id="__codelineno-14-13" name="__codelineno-14-13" href="#__codelineno-14-13"></a> <span class="n">name</span><span class="o">=</span><span class="s2">"weather_agent_v2"</span><span class="p">,</span> <span class="c1"># Give it a new version name</span>
</span><span id="__span-14-14"><a id="__codelineno-14-14" name="__codelineno-14-14" href="#__codelineno-14-14"></a> <span class="n">model</span><span class="o">=</span><span class="n">root_agent_model</span><span class="p">,</span>
</span><span id="__span-14-15"><a id="__codelineno-14-15" name="__codelineno-14-15" href="#__codelineno-14-15"></a> <span class="n">description</span><span class="o">=</span><span class="s2">"The main coordinator agent. Handles weather requests and delegates greetings/farewells to specialists."</span><span class="p">,</span>
</span><span id="__span-14-16"><a id="__codelineno-14-16" name="__codelineno-14-16" href="#__codelineno-14-16"></a> <span class="n">instruction</span><span class="o">=</span><span class="s2">"You are the main Weather Agent coordinating a team. Your primary responsibility is to provide weather information. "</span>
</span><span id="__span-14-17"><a id="__codelineno-14-17" name="__codelineno-14-17" href="#__codelineno-14-17"></a> <span class="s2">"Use the 'get_weather' tool ONLY for specific weather requests (e.g., 'weather in London'). "</span>
</span><span id="__span-14-18"><a id="__codelineno-14-18" name="__codelineno-14-18" href="#__codelineno-14-18"></a> <span class="s2">"You have specialized sub-agents: "</span>
</span><span id="__span-14-19"><a id="__codelineno-14-19" name="__codelineno-14-19" href="#__codelineno-14-19"></a> <span class="s2">"1. 'greeting_agent': Handles simple greetings like 'Hi', 'Hello'. Delegate to it for these. "</span>
</span><span id="__span-14-20"><a id="__codelineno-14-20" name="__codelineno-14-20" href="#__codelineno-14-20"></a> <span class="s2">"2. 'farewell_agent': Handles simple farewells like 'Bye', 'See you'. Delegate to it for these. "</span>
</span><span id="__span-14-21"><a id="__codelineno-14-21" name="__codelineno-14-21" href="#__codelineno-14-21"></a> <span class="s2">"Analyze the user's query. If it's a greeting, delegate to 'greeting_agent'. If it's a farewell, delegate to 'farewell_agent'. "</span>
</span><span id="__span-14-22"><a id="__codelineno-14-22" name="__codelineno-14-22" href="#__codelineno-14-22"></a> <span class="s2">"If it's a weather request, handle it yourself using 'get_weather'. "</span>
</span><span id="__span-14-23"><a id="__codelineno-14-23" name="__codelineno-14-23" href="#__codelineno-14-23"></a> <span class="s2">"For anything else, respond appropriately or state you cannot handle it."</span><span class="p">,</span>
</span><span id="__span-14-24"><a id="__codelineno-14-24" name="__codelineno-14-24" href="#__codelineno-14-24"></a> <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">get_weather</span><span class="p">],</span> <span class="c1"># Root agent still needs the weather tool for its core task</span>
</span><span id="__span-14-25"><a id="__codelineno-14-25" name="__codelineno-14-25" href="#__codelineno-14-25"></a> <span class="c1"># Key change: Link the sub-agents here!</span>
</span><span id="__span-14-26"><a id="__codelineno-14-26" name="__codelineno-14-26" href="#__codelineno-14-26"></a> <span class="n">sub_agents</span><span class="o">=</span><span class="p">[</span><span class="n">greeting_agent</span><span class="p">,</span> <span class="n">farewell_agent</span><span class="p">]</span>
</span><span id="__span-14-27"><a id="__codelineno-14-27" name="__codelineno-14-27" href="#__codelineno-14-27"></a> <span class="p">)</span>
</span><span id="__span-14-28"><a id="__codelineno-14-28" name="__codelineno-14-28" href="#__codelineno-14-28"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"✅ Root Agent '</span><span class="si">{</span><span class="n">weather_agent_team</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">' created using model '</span><span class="si">{</span><span class="n">root_agent_model</span><span class="si">}</span><span class="s2">' with sub-agents: </span><span class="si">{</span><span class="p">[</span><span class="n">sa</span><span class="o">.</span><span class="n">name</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">sa</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="n">weather_agent_team</span><span class="o">.</span><span class="n">sub_agents</span><span class="p">]</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span><span id="__span-14-29"><a id="__codelineno-14-29" name="__codelineno-14-29" href="#__codelineno-14-29"></a>
</span><span id="__span-14-30"><a id="__codelineno-14-30" name="__codelineno-14-30" href="#__codelineno-14-30"></a><span class="k">else</span><span class="p">:</span>
</span><span id="__span-14-31"><a id="__codelineno-14-31" name="__codelineno-14-31" href="#__codelineno-14-31"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"❌ Cannot create root agent because one or more sub-agents failed to initialize or 'get_weather' tool is missing."</span><span class="p">)</span>
</span><span id="__span-14-32"><a id="__codelineno-14-32" name="__codelineno-14-32" href="#__codelineno-14-32"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">greeting_agent</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="s2">" - Greeting Agent is missing."</span><span class="p">)</span>
</span><span id="__span-14-33"><a id="__codelineno-14-33" name="__codelineno-14-33" href="#__codelineno-14-33"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">farewell_agent</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="s2">" - Farewell Agent is missing."</span><span class="p">)</span>
</span><span id="__span-14-34"><a id="__codelineno-14-34" name="__codelineno-14-34" href="#__codelineno-14-34"></a> <span class="k">if</span> <span class="s1">'get_weather'</span> <span class="ow">not</span> <span class="ow">in</span> <span class="nb">globals</span><span class="p">():</span> <span class="nb">print</span><span class="p">(</span><span class="s2">" - get_weather function is missing."</span><span class="p">)</span>
</span></code></pre></div>
<hr />
<p><strong>4. Interact with the Agent Team</strong></p>
<p>Now that we've defined our root agent (<code>weather_agent_team</code> - <em>Note: Ensure this variable name matches the one defined in the previous code block, likely <code># @title Define the Root Agent with Sub-Agents</code>, which might have named it <code>root_agent</code></em>) with its specialized sub-agents, let's test the delegation mechanism.</p>
<p>The following code block will:</p>
<ol>
<li>Define an <code>async</code> function <code>run_team_conversation</code>.</li>
<li>Inside this function, create a <em>new, dedicated</em> <code>InMemorySessionService</code> and a specific session (<code>session_001_agent_team</code>) just for this test run. This isolates the conversation history for testing the team dynamics.</li>
<li>Create a <code>Runner</code> (<code>runner_agent_team</code>) configured to use our <code>weather_agent_team</code> (the root agent) and the dedicated session service.</li>
<li>Use our updated <code>call_agent_async</code> function to send different types of queries (greeting, weather request, farewell) to the <code>runner_agent_team</code>. We explicitly pass the runner, user ID, and session ID for this specific test.</li>
<li>Immediately execute the <code>run_team_conversation</code> function.</li>
</ol>
<p>We expect the following flow:</p>
<ol>
<li>The "Hello there!" query goes to <code>runner_agent_team</code>.</li>
<li>The root agent (<code>weather_agent_team</code>) receives it and, based on its instructions and the <code>greeting_agent</code>'s description, delegates the task.</li>
<li><code>greeting_agent</code> handles the query, calls its <code>say_hello</code> tool, and generates the response.</li>
<li>The "What is the weather in New York?" query is <em>not</em> delegated and is handled directly by the root agent using its <code>get_weather</code> tool.</li>
<li>The "Thanks, bye!" query is delegated to the <code>farewell_agent</code>, which uses its <code>say_goodbye</code> tool.</li>
</ol>
<div class="language-python highlight"><pre><span></span><code><span id="__span-15-1"><a id="__codelineno-15-1" name="__codelineno-15-1" href="#__codelineno-15-1"></a><span class="c1"># @title Interact with the Agent Team</span>
</span><span id="__span-15-2"><a id="__codelineno-15-2" name="__codelineno-15-2" href="#__codelineno-15-2"></a><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span> <span class="c1"># Ensure asyncio is imported</span>
</span><span id="__span-15-3"><a id="__codelineno-15-3" name="__codelineno-15-3" href="#__codelineno-15-3"></a>
</span><span id="__span-15-4"><a id="__codelineno-15-4" name="__codelineno-15-4" href="#__codelineno-15-4"></a><span class="c1"># Ensure the root agent (e.g., 'weather_agent_team' or 'root_agent' from the previous cell) is defined.</span>
</span><span id="__span-15-5"><a id="__codelineno-15-5" name="__codelineno-15-5" href="#__codelineno-15-5"></a><span class="c1"># Ensure the call_agent_async function is defined.</span>
</span><span id="__span-15-6"><a id="__codelineno-15-6" name="__codelineno-15-6" href="#__codelineno-15-6"></a>
</span><span id="__span-15-7"><a id="__codelineno-15-7" name="__codelineno-15-7" href="#__codelineno-15-7"></a><span class="c1"># Check if the root agent variable exists before defining the conversation function</span>
</span><span id="__span-15-8"><a id="__codelineno-15-8" name="__codelineno-15-8" href="#__codelineno-15-8"></a><span class="n">root_agent_var_name</span> <span class="o">=</span> <span class="s1">'root_agent'</span> <span class="c1"># Default name from Step 3 guide</span>
</span><span id="__span-15-9"><a id="__codelineno-15-9" name="__codelineno-15-9" href="#__codelineno-15-9"></a><span class="k">if</span> <span class="s1">'weather_agent_team'</span> <span class="ow">in</span> <span class="nb">globals</span><span class="p">():</span> <span class="c1"># Check if user used this name instead</span>
</span><span id="__span-15-10"><a id="__codelineno-15-10" name="__codelineno-15-10" href="#__codelineno-15-10"></a> <span class="n">root_agent_var_name</span> <span class="o">=</span> <span class="s1">'weather_agent_team'</span>
</span><span id="__span-15-11"><a id="__codelineno-15-11" name="__codelineno-15-11" href="#__codelineno-15-11"></a><span class="k">elif</span> <span class="s1">'root_agent'</span> <span class="ow">not</span> <span class="ow">in</span> <span class="nb">globals</span><span class="p">():</span>
</span><span id="__span-15-12"><a id="__codelineno-15-12" name="__codelineno-15-12" href="#__codelineno-15-12"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"⚠️ Root agent ('root_agent' or 'weather_agent_team') not found. Cannot define run_team_conversation."</span><span class="p">)</span>
</span><span id="__span-15-13"><a id="__codelineno-15-13" name="__codelineno-15-13" href="#__codelineno-15-13"></a> <span class="c1"># Assign a dummy value to prevent NameError later if the code block runs anyway</span>
</span><span id="__span-15-14"><a id="__codelineno-15-14" name="__codelineno-15-14" href="#__codelineno-15-14"></a> <span class="n">root_agent</span> <span class="o">=</span> <span class="kc">None</span> <span class="c1"># Or set a flag to prevent execution</span>
</span><span id="__span-15-15"><a id="__codelineno-15-15" name="__codelineno-15-15" href="#__codelineno-15-15"></a>
</span><span id="__span-15-16"><a id="__codelineno-15-16" name="__codelineno-15-16" href="#__codelineno-15-16"></a><span class="c1"># Only define and run if the root agent exists</span>
</span><span id="__span-15-17"><a id="__codelineno-15-17" name="__codelineno-15-17" href="#__codelineno-15-17"></a><span class="k">if</span> <span class="n">root_agent_var_name</span> <span class="ow">in</span> <span class="nb">globals</span><span class="p">()</span> <span class="ow">and</span> <span class="nb">globals</span><span class="p">()[</span><span class="n">root_agent_var_name</span><span class="p">]:</span>
</span><span id="__span-15-18"><a id="__codelineno-15-18" name="__codelineno-15-18" href="#__codelineno-15-18"></a> <span class="c1"># Define the main async function for the conversation logic.</span>
</span><span id="__span-15-19"><a id="__codelineno-15-19" name="__codelineno-15-19" href="#__codelineno-15-19"></a> <span class="c1"># The 'await' keywords INSIDE this function are necessary for async operations.</span>
</span><span id="__span-15-20"><a id="__codelineno-15-20" name="__codelineno-15-20" href="#__codelineno-15-20"></a> <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run_team_conversation</span><span class="p">():</span>
</span><span id="__span-15-21"><a id="__codelineno-15-21" name="__codelineno-15-21" href="#__codelineno-15-21"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">--- Testing Agent Team Delegation ---"</span><span class="p">)</span>
</span><span id="__span-15-22"><a id="__codelineno-15-22" name="__codelineno-15-22" href="#__codelineno-15-22"></a> <span class="n">session_service</span> <span class="o">=</span> <span class="n">InMemorySessionService</span><span class="p">()</span>
</span><span id="__span-15-23"><a id="__codelineno-15-23" name="__codelineno-15-23" href="#__codelineno-15-23"></a> <span class="n">APP_NAME</span> <span class="o">=</span> <span class="s2">"weather_tutorial_agent_team"</span>
</span><span id="__span-15-24"><a id="__codelineno-15-24" name="__codelineno-15-24" href="#__codelineno-15-24"></a> <span class="n">USER_ID</span> <span class="o">=</span> <span class="s2">"user_1_agent_team"</span>
</span><span id="__span-15-25"><a id="__codelineno-15-25" name="__codelineno-15-25" href="#__codelineno-15-25"></a> <span class="n">SESSION_ID</span> <span class="o">=</span> <span class="s2">"session_001_agent_team"</span>
</span><span id="__span-15-26"><a id="__codelineno-15-26" name="__codelineno-15-26" href="#__codelineno-15-26"></a> <span class="n">session</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session_service</span><span class="o">.</span><span class="n">create_session</span><span class="p">(</span>
</span><span id="__span-15-27"><a id="__codelineno-15-27" name="__codelineno-15-27" href="#__codelineno-15-27"></a> <span class="n">app_name</span><span class="o">=</span><span class="n">APP_NAME</span><span class="p">,</span> <span class="n">user_id</span><span class="o">=</span><span class="n">USER_ID</span><span class="p">,</span> <span class="n">session_id</span><span class="o">=</span><span class="n">SESSION_ID</span>
</span><span id="__span-15-28"><a id="__codelineno-15-28" name="__codelineno-15-28" href="#__codelineno-15-28"></a> <span class="p">)</span>
</span><span id="__span-15-29"><a id="__codelineno-15-29" name="__codelineno-15-29" href="#__codelineno-15-29"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Session created: App='</span><span class="si">{</span><span class="n">APP_NAME</span><span class="si">}</span><span class="s2">', User='</span><span class="si">{</span><span class="n">USER_ID</span><span class="si">}</span><span class="s2">', Session='</span><span class="si">{</span><span class="n">SESSION_ID</span><span class="si">}</span><span class="s2">'"</span><span class="p">)</span>
</span><span id="__span-15-30"><a id="__codelineno-15-30" name="__codelineno-15-30" href="#__codelineno-15-30"></a>
</span><span id="__span-15-31"><a id="__codelineno-15-31" name="__codelineno-15-31" href="#__codelineno-15-31"></a> <span class="n">actual_root_agent</span> <span class="o">=</span> <span class="nb">globals</span><span class="p">()[</span><span class="n">root_agent_var_name</span><span class="p">]</span>
</span><span id="__span-15-32"><a id="__codelineno-15-32" name="__codelineno-15-32" href="#__codelineno-15-32"></a> <span class="n">runner_agent_team</span> <span class="o">=</span> <span class="n">Runner</span><span class="p">(</span> <span class="c1"># Or use InMemoryRunner</span>
</span><span id="__span-15-33"><a id="__codelineno-15-33" name="__codelineno-15-33" href="#__codelineno-15-33"></a> <span class="n">agent</span><span class="o">=</span><span class="n">actual_root_agent</span><span class="p">,</span>
</span><span id="__span-15-34"><a id="__codelineno-15-34" name="__codelineno-15-34" href="#__codelineno-15-34"></a> <span class="n">app_name</span><span class="o">=</span><span class="n">APP_NAME</span><span class="p">,</span>
</span><span id="__span-15-35"><a id="__codelineno-15-35" name="__codelineno-15-35" href="#__codelineno-15-35"></a> <span class="n">session_service</span><span class="o">=</span><span class="n">session_service</span>
</span><span id="__span-15-36"><a id="__codelineno-15-36" name="__codelineno-15-36" href="#__codelineno-15-36"></a> <span class="p">)</span>
</span><span id="__span-15-37"><a id="__codelineno-15-37" name="__codelineno-15-37" href="#__codelineno-15-37"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Runner created for agent '</span><span class="si">{</span><span class="n">actual_root_agent</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">'."</span><span class="p">)</span>
</span><span id="__span-15-38"><a id="__codelineno-15-38" name="__codelineno-15-38" href="#__codelineno-15-38"></a>
</span><span id="__span-15-39"><a id="__codelineno-15-39" name="__codelineno-15-39" href="#__codelineno-15-39"></a> <span class="c1"># --- Interactions using await (correct within async def) ---</span>
</span><span id="__span-15-40"><a id="__codelineno-15-40" name="__codelineno-15-40" href="#__codelineno-15-40"></a> <span class="k">await</span> <span class="n">call_agent_async</span><span class="p">(</span><span class="n">query</span> <span class="o">=</span> <span class="s2">"Hello there!"</span><span class="p">,</span>
</span><span id="__span-15-41"><a id="__codelineno-15-41" name="__codelineno-15-41" href="#__codelineno-15-41"></a> <span class="n">runner</span><span class="o">=</span><span class="n">runner_agent_team</span><span class="p">,</span>
</span><span id="__span-15-42"><a id="__codelineno-15-42" name="__codelineno-15-42" href="#__codelineno-15-42"></a> <span class="n">user_id</span><span class="o">=</span><span class="n">USER_ID</span><span class="p">,</span>
</span><span id="__span-15-43"><a id="__codelineno-15-43" name="__codelineno-15-43" href="#__codelineno-15-43"></a> <span class="n">session_id</span><span class="o">=</span><span class="n">SESSION_ID</span><span class="p">)</span>
</span><span id="__span-15-44"><a id="__codelineno-15-44" name="__codelineno-15-44" href="#__codelineno-15-44"></a> <span class="k">await</span> <span class="n">call_agent_async</span><span class="p">(</span><span class="n">query</span> <span class="o">=</span> <span class="s2">"What is the weather in New York?"</span><span class="p">,</span>
</span><span id="__span-15-45"><a id="__codelineno-15-45" name="__codelineno-15-45" href="#__codelineno-15-45"></a> <span class="n">runner</span><span class="o">=</span><span class="n">runner_agent_team</span><span class="p">,</span>
</span><span id="__span-15-46"><a id="__codelineno-15-46" name="__codelineno-15-46" href="#__codelineno-15-46"></a> <span class="n">user_id</span><span class="o">=</span><span class="n">USER_ID</span><span class="p">,</span>
</span><span id="__span-15-47"><a id="__codelineno-15-47" name="__codelineno-15-47" href="#__codelineno-15-47"></a> <span class="n">session_id</span><span class="o">=</span><span class="n">SESSION_ID</span><span class="p">)</span>
</span><span id="__span-15-48"><a id="__codelineno-15-48" name="__codelineno-15-48" href="#__codelineno-15-48"></a> <span class="k">await</span> <span class="n">call_agent_async</span><span class="p">(</span><span class="n">query</span> <span class="o">=</span> <span class="s2">"Thanks, bye!"</span><span class="p">,</span>
</span><span id="__span-15-49"><a id="__codelineno-15-49" name="__codelineno-15-49" href="#__codelineno-15-49"></a> <span class="n">runner</span><span class="o">=</span><span class="n">runner_agent_team</span><span class="p">,</span>
</span><span id="__span-15-50"><a id="__codelineno-15-50" name="__codelineno-15-50" href="#__codelineno-15-50"></a> <span class="n">user_id</span><span class="o">=</span><span class="n">USER_ID</span><span class="p">,</span>
</span><span id="__span-15-51"><a id="__codelineno-15-51" name="__codelineno-15-51" href="#__codelineno-15-51"></a> <span class="n">session_id</span><span class="o">=</span><span class="n">SESSION_ID</span><span class="p">)</span>
</span><span id="__span-15-52"><a id="__codelineno-15-52" name="__codelineno-15-52" href="#__codelineno-15-52"></a>
</span><span id="__span-15-53"><a id="__codelineno-15-53" name="__codelineno-15-53" href="#__codelineno-15-53"></a> <span class="c1"># --- Execute the `run_team_conversation` async function ---</span>
</span><span id="__span-15-54"><a id="__codelineno-15-54" name="__codelineno-15-54" href="#__codelineno-15-54"></a> <span class="c1"># Choose ONE of the methods below based on your environment.</span>
</span><span id="__span-15-55"><a id="__codelineno-15-55" name="__codelineno-15-55" href="#__codelineno-15-55"></a> <span class="c1"># Note: This may require API keys for the models used!</span>
</span><span id="__span-15-56"><a id="__codelineno-15-56" name="__codelineno-15-56" href="#__codelineno-15-56"></a>
</span><span id="__span-15-57"><a id="__codelineno-15-57" name="__codelineno-15-57" href="#__codelineno-15-57"></a> <span class="c1"># METHOD 1: Direct await (Default for Notebooks/Async REPLs)</span>
</span><span id="__span-15-58"><a id="__codelineno-15-58" name="__codelineno-15-58" href="#__codelineno-15-58"></a> <span class="c1"># If your environment supports top-level await (like Colab/Jupyter notebooks),</span>
</span><span id="__span-15-59"><a id="__codelineno-15-59" name="__codelineno-15-59" href="#__codelineno-15-59"></a> <span class="c1"># it means an event loop is already running, so you can directly await the function.</span>
</span><span id="__span-15-60"><a id="__codelineno-15-60" name="__codelineno-15-60" href="#__codelineno-15-60"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"Attempting execution using 'await' (default for notebooks)..."</span><span class="p">)</span>
</span><span id="__span-15-61"><a id="__codelineno-15-61" name="__codelineno-15-61" href="#__codelineno-15-61"></a> <span class="k">await</span> <span class="n">run_team_conversation</span><span class="p">()</span>
</span><span id="__span-15-62"><a id="__codelineno-15-62" name="__codelineno-15-62" href="#__codelineno-15-62"></a>
</span><span id="__span-15-63"><a id="__codelineno-15-63" name="__codelineno-15-63" href="#__codelineno-15-63"></a> <span class="c1"># METHOD 2: asyncio.run (For Standard Python Scripts [.py])</span>
</span><span id="__span-15-64"><a id="__codelineno-15-64" name="__codelineno-15-64" href="#__codelineno-15-64"></a> <span class="c1"># If running this code as a standard Python script from your terminal,</span>
</span><span id="__span-15-65"><a id="__codelineno-15-65" name="__codelineno-15-65" href="#__codelineno-15-65"></a> <span class="c1"># the script context is synchronous. `asyncio.run()` is needed to</span>
</span><span id="__span-15-66"><a id="__codelineno-15-66" name="__codelineno-15-66" href="#__codelineno-15-66"></a> <span class="c1"># create and manage an event loop to execute your async function.</span>
</span><span id="__span-15-67"><a id="__codelineno-15-67" name="__codelineno-15-67" href="#__codelineno-15-67"></a> <span class="c1"># To use this method:</span>
</span><span id="__span-15-68"><a id="__codelineno-15-68" name="__codelineno-15-68" href="#__codelineno-15-68"></a> <span class="c1"># 1. Comment out the `await run_team_conversation()` line above.</span>
</span><span id="__span-15-69"><a id="__codelineno-15-69" name="__codelineno-15-69" href="#__codelineno-15-69"></a> <span class="c1"># 2. Uncomment the following block:</span>
</span><span id="__span-15-70"><a id="__codelineno-15-70" name="__codelineno-15-70" href="#__codelineno-15-70"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-15-71"><a id="__codelineno-15-71" name="__codelineno-15-71" href="#__codelineno-15-71"></a><span class="sd"> import asyncio</span>
</span><span id="__span-15-72"><a id="__codelineno-15-72" name="__codelineno-15-72" href="#__codelineno-15-72"></a><span class="sd"> if __name__ == "__main__": # Ensures this runs only when script is executed directly</span>
</span><span id="__span-15-73"><a id="__codelineno-15-73" name="__codelineno-15-73" href="#__codelineno-15-73"></a><span class="sd"> print("Executing using 'asyncio.run()' (for standard Python scripts)...")</span>
</span><span id="__span-15-74"><a id="__codelineno-15-74" name="__codelineno-15-74" href="#__codelineno-15-74"></a><span class="sd"> try:</span>
</span><span id="__span-15-75"><a id="__codelineno-15-75" name="__codelineno-15-75" href="#__codelineno-15-75"></a><span class="sd"> # This creates an event loop, runs your async function, and closes the loop.</span>
</span><span id="__span-15-76"><a id="__codelineno-15-76" name="__codelineno-15-76" href="#__codelineno-15-76"></a><span class="sd"> asyncio.run(run_team_conversation())</span>
</span><span id="__span-15-77"><a id="__codelineno-15-77" name="__codelineno-15-77" href="#__codelineno-15-77"></a><span class="sd"> except Exception as e:</span>
</span><span id="__span-15-78"><a id="__codelineno-15-78" name="__codelineno-15-78" href="#__codelineno-15-78"></a><span class="sd"> print(f"An error occurred: {e}")</span>
</span><span id="__span-15-79"><a id="__codelineno-15-79" name="__codelineno-15-79" href="#__codelineno-15-79"></a><span class="sd"> """</span>
</span><span id="__span-15-80"><a id="__codelineno-15-80" name="__codelineno-15-80" href="#__codelineno-15-80"></a>
</span><span id="__span-15-81"><a id="__codelineno-15-81" name="__codelineno-15-81" href="#__codelineno-15-81"></a><span class="k">else</span><span class="p">:</span>
</span><span id="__span-15-82"><a id="__codelineno-15-82" name="__codelineno-15-82" href="#__codelineno-15-82"></a> <span class="c1"># This message prints if the root agent variable wasn't found earlier</span>
</span><span id="__span-15-83"><a id="__codelineno-15-83" name="__codelineno-15-83" href="#__codelineno-15-83"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">⚠️ Skipping agent team conversation execution as the root agent was not successfully defined in a previous step."</span><span class="p">)</span>
</span></code></pre></div>
<hr />
<p>Look closely at the output logs, especially the <code>--- Tool: ... called ---</code> messages. You should observe:</p>
<ul>
<li>For "Hello there!", the <code>say_hello</code> tool was called (indicating <code>greeting_agent</code> handled it).</li>
<li>For "What is the weather in New York?", the <code>get_weather</code> tool was called (indicating the root agent handled it).</li>
<li>For "Thanks, bye!", the <code>say_goodbye</code> tool was called (indicating <code>farewell_agent</code> handled it).</li>
</ul>
<p>This confirms successful <strong>automatic delegation</strong>! The root agent, guided by its instructions and the <code>description</code>s of its <code>sub_agents</code>, correctly routed user requests to the appropriate specialist agent within the team.</p>
<p>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.</p>
<h2 id="step-4-adding-memory-and-personalization-with-session-state">Step 4: Adding Memory and Personalization with Session State<a class="headerlink" href="#step-4-adding-memory-and-personalization-with-session-state" title="Permanent link">&para;</a></h2>
<p>So far, our agent team can handle different tasks through delegation, but each interaction starts fresh – the agents have no memory of past conversations or user preferences within a session. To create more sophisticated and context-aware experiences, agents need <strong>memory</strong>. ADK provides this through <strong>Session State</strong>.</p>
<p><strong>What is Session State?</strong></p>
<ul>
<li>It's a Python dictionary (<code>session.state</code>) tied to a specific user session (identified by <code>APP_NAME</code>, <code>USER_ID</code>, <code>SESSION_ID</code>).</li>
<li>It persists information <em>across multiple conversational turns</em> within that session.</li>
<li>Agents and Tools can read from and write to this state, allowing them to remember details, adapt behavior, and personalize responses.</li>
</ul>
<p><strong>How Agents Interact with State:</strong></p>
<ol>
<li><strong><code>ToolContext</code> (Primary Method):</strong> Tools can accept a <code>ToolContext</code> object (automatically provided by ADK for any parameter annotated <code>ToolContext</code>, whatever its position). This object gives direct access to the session state via <code>tool_context.state</code>, allowing tools to read preferences or save results <em>during</em> execution.</li>
<li><strong><code>output_key</code> (Auto-Save Agent Response):</strong> An <code>Agent</code> can be configured with an <code>output_key="your_key"</code>. ADK will then automatically save the agent's final textual response for a turn into <code>session.state["your_key"]</code>.</li>
</ol>
<p><strong>In this step, we will enhance our Weather Bot team by:</strong></p>
<ol>
<li>Using a <strong>new</strong> <code>InMemorySessionService</code> to demonstrate state in isolation.</li>
<li>Initializing session state with a user preference for <code>temperature_unit</code>.</li>
<li>Creating a state-aware version of the weather tool (<code>get_weather_stateful</code>) that reads this preference via <code>ToolContext</code> and adjusts its output format (Celsius/Fahrenheit).</li>
<li>Updating the root agent to use this stateful tool and configuring it with an <code>output_key</code> to automatically save its final weather report to the session state.</li>
<li>Running a conversation to observe how the initial state affects the tool, how manual state changes alter subsequent behavior, and how <code>output_key</code> persists the agent's response.</li>
</ol>
<hr />
<p><strong>1. Initialize New Session Service and State</strong></p>
<p>To clearly demonstrate state management without interference from prior steps, we'll instantiate a new <code>InMemorySessionService</code>. We'll also create a session with an initial state defining the user's preferred temperature unit.</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-16-1"><a id="__codelineno-16-1" name="__codelineno-16-1" href="#__codelineno-16-1"></a><span class="c1"># @title 1. Initialize New Session Service and State</span>
</span><span id="__span-16-2"><a id="__codelineno-16-2" name="__codelineno-16-2" href="#__codelineno-16-2"></a>
</span><span id="__span-16-3"><a id="__codelineno-16-3" name="__codelineno-16-3" href="#__codelineno-16-3"></a><span class="c1"># Import necessary session components</span>
</span><span id="__span-16-4"><a id="__codelineno-16-4" name="__codelineno-16-4" href="#__codelineno-16-4"></a><span class="kn">from</span><span class="w"> </span><span class="nn">google.adk.sessions</span><span class="w"> </span><span class="kn">import</span> <span class="n">InMemorySessionService</span>
</span><span id="__span-16-5"><a id="__codelineno-16-5" name="__codelineno-16-5" href="#__codelineno-16-5"></a>
</span><span id="__span-16-6"><a id="__codelineno-16-6" name="__codelineno-16-6" href="#__codelineno-16-6"></a><span class="c1"># Create a NEW session service instance for this state demonstration</span>
</span><span id="__span-16-7"><a id="__codelineno-16-7" name="__codelineno-16-7" href="#__codelineno-16-7"></a><span class="n">session_service_stateful</span> <span class="o">=</span> <span class="n">InMemorySessionService</span><span class="p">()</span>
</span><span id="__span-16-8"><a id="__codelineno-16-8" name="__codelineno-16-8" href="#__codelineno-16-8"></a><span class="nb">print</span><span class="p">(</span><span class="s2">"✅ New InMemorySessionService created for state demonstration."</span><span class="p">)</span>
</span><span id="__span-16-9"><a id="__codelineno-16-9" name="__codelineno-16-9" href="#__codelineno-16-9"></a>
</span><span id="__span-16-10"><a id="__codelineno-16-10" name="__codelineno-16-10" href="#__codelineno-16-10"></a><span class="c1"># Define a NEW session ID for this part of the tutorial</span>
</span><span id="__span-16-11"><a id="__codelineno-16-11" name="__codelineno-16-11" href="#__codelineno-16-11"></a><span class="n">SESSION_ID_STATEFUL</span> <span class="o">=</span> <span class="s2">"session_state_demo_001"</span>
</span><span id="__span-16-12"><a id="__codelineno-16-12" name="__codelineno-16-12" href="#__codelineno-16-12"></a><span class="n">USER_ID_STATEFUL</span> <span class="o">=</span> <span class="s2">"user_state_demo"</span>
</span><span id="__span-16-13"><a id="__codelineno-16-13" name="__codelineno-16-13" href="#__codelineno-16-13"></a>
</span><span id="__span-16-14"><a id="__codelineno-16-14" name="__codelineno-16-14" href="#__codelineno-16-14"></a><span class="c1"># Define initial state data - user prefers Celsius initially</span>
</span><span id="__span-16-15"><a id="__codelineno-16-15" name="__codelineno-16-15" href="#__codelineno-16-15"></a><span class="n">initial_state</span> <span class="o">=</span> <span class="p">{</span>
</span><span id="__span-16-16"><a id="__codelineno-16-16" name="__codelineno-16-16" href="#__codelineno-16-16"></a> <span class="s2">"user_preference_temperature_unit"</span><span class="p">:</span> <span class="s2">"Celsius"</span>
</span><span id="__span-16-17"><a id="__codelineno-16-17" name="__codelineno-16-17" href="#__codelineno-16-17"></a><span class="p">}</span>
</span><span id="__span-16-18"><a id="__codelineno-16-18" name="__codelineno-16-18" href="#__codelineno-16-18"></a>
</span><span id="__span-16-19"><a id="__codelineno-16-19" name="__codelineno-16-19" href="#__codelineno-16-19"></a><span class="c1"># Create the session, providing the initial state</span>
</span><span id="__span-16-20"><a id="__codelineno-16-20" name="__codelineno-16-20" href="#__codelineno-16-20"></a><span class="n">session_stateful</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session_service_stateful</span><span class="o">.</span><span class="n">create_session</span><span class="p">(</span>
</span><span id="__span-16-21"><a id="__codelineno-16-21" name="__codelineno-16-21" href="#__codelineno-16-21"></a> <span class="n">app_name</span><span class="o">=</span><span class="n">APP_NAME</span><span class="p">,</span> <span class="c1"># Use the consistent app name</span>
</span><span id="__span-16-22"><a id="__codelineno-16-22" name="__codelineno-16-22" href="#__codelineno-16-22"></a> <span class="n">user_id</span><span class="o">=</span><span class="n">USER_ID_STATEFUL</span><span class="p">,</span>
</span><span id="__span-16-23"><a id="__codelineno-16-23" name="__codelineno-16-23" href="#__codelineno-16-23"></a> <span class="n">session_id</span><span class="o">=</span><span class="n">SESSION_ID_STATEFUL</span><span class="p">,</span>
</span><span id="__span-16-24"><a id="__codelineno-16-24" name="__codelineno-16-24" href="#__codelineno-16-24"></a> <span class="n">state</span><span class="o">=</span><span class="n">initial_state</span> <span class="c1"># &lt;&lt;&lt; Initialize state during creation</span>
</span><span id="__span-16-25"><a id="__codelineno-16-25" name="__codelineno-16-25" href="#__codelineno-16-25"></a><span class="p">)</span>
</span><span id="__span-16-26"><a id="__codelineno-16-26" name="__codelineno-16-26" href="#__codelineno-16-26"></a><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"✅ Session '</span><span class="si">{</span><span class="n">SESSION_ID_STATEFUL</span><span class="si">}</span><span class="s2">' created for user '</span><span class="si">{</span><span class="n">USER_ID_STATEFUL</span><span class="si">}</span><span class="s2">'."</span><span class="p">)</span>
</span><span id="__span-16-27"><a id="__codelineno-16-27" name="__codelineno-16-27" href="#__codelineno-16-27"></a>
</span><span id="__span-16-28"><a id="__codelineno-16-28" name="__codelineno-16-28" href="#__codelineno-16-28"></a><span class="c1"># Verify the initial state was set correctly</span>
</span><span id="__span-16-29"><a id="__codelineno-16-29" name="__codelineno-16-29" href="#__codelineno-16-29"></a><span class="n">retrieved_session</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session_service_stateful</span><span class="o">.</span><span class="n">get_session</span><span class="p">(</span><span class="n">app_name</span><span class="o">=</span><span class="n">APP_NAME</span><span class="p">,</span>
</span><span id="__span-16-30"><a id="__codelineno-16-30" name="__codelineno-16-30" href="#__codelineno-16-30"></a> <span class="n">user_id</span><span class="o">=</span><span class="n">USER_ID_STATEFUL</span><span class="p">,</span>
</span><span id="__span-16-31"><a id="__codelineno-16-31" name="__codelineno-16-31" href="#__codelineno-16-31"></a> <span class="n">session_id</span> <span class="o">=</span> <span class="n">SESSION_ID_STATEFUL</span><span class="p">)</span>
</span><span id="__span-16-32"><a id="__codelineno-16-32" name="__codelineno-16-32" href="#__codelineno-16-32"></a><span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">--- Initial Session State ---"</span><span class="p">)</span>
</span><span id="__span-16-33"><a id="__codelineno-16-33" name="__codelineno-16-33" href="#__codelineno-16-33"></a><span class="k">if</span> <span class="n">retrieved_session</span><span class="p">:</span>
</span><span id="__span-16-34"><a id="__codelineno-16-34" name="__codelineno-16-34" href="#__codelineno-16-34"></a> <span class="nb">print</span><span class="p">(</span><span class="n">retrieved_session</span><span class="o">.</span><span class="n">state</span><span class="p">)</span>
</span><span id="__span-16-35"><a id="__codelineno-16-35" name="__codelineno-16-35" href="#__codelineno-16-35"></a><span class="k">else</span><span class="p">:</span>
</span><span id="__span-16-36"><a id="__codelineno-16-36" name="__codelineno-16-36" href="#__codelineno-16-36"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"Error: Could not retrieve session."</span><span class="p">)</span>
</span></code></pre></div>
<hr />
<p><strong>2. Create State-Aware Weather Tool (<code>get_weather_stateful</code>)</strong></p>
<p>Now, we create a new version of the weather tool. Its key feature is accepting <code>tool_context: ToolContext</code> which allows it to access <code>tool_context.state</code>. It will read the <code>user_preference_temperature_unit</code> and format the temperature accordingly.</p>
<ul>
<li>
<p><strong>Key Concept: <code>ToolContext</code></strong> This object is the bridge allowing your tool logic to interact with the session's context, including reading and writing state variables. ADK finds the parameter by its <code>ToolContext</code> annotation and injects it automatically, so it can sit at any position in your tool function's signature. The annotated parameter is also hidden from the schema the LLM sees.</p>
</li>
<li>
<p><strong>Best Practice:</strong> When reading from state, use <code>dictionary.get('key', default_value)</code> to handle cases where the key might not exist yet, ensuring your tool doesn't crash.</p>
</li>
</ul>
<div class="language-python highlight"><pre><span></span><code><span id="__span-17-1"><a id="__codelineno-17-1" name="__codelineno-17-1" href="#__codelineno-17-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">google.adk.tools.tool_context</span><span class="w"> </span><span class="kn">import</span> <span class="n">ToolContext</span>
</span><span id="__span-17-2"><a id="__codelineno-17-2" name="__codelineno-17-2" href="#__codelineno-17-2"></a>
</span><span id="__span-17-3"><a id="__codelineno-17-3" name="__codelineno-17-3" href="#__codelineno-17-3"></a><span class="k">def</span><span class="w"> </span><span class="nf">get_weather_stateful</span><span class="p">(</span><span class="n">city</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">tool_context</span><span class="p">:</span> <span class="n">ToolContext</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">:</span>
</span><span id="__span-17-4"><a id="__codelineno-17-4" name="__codelineno-17-4" href="#__codelineno-17-4"></a><span class="w"> </span><span class="sd">"""Retrieves weather, converts temp unit based on session state."""</span>
</span><span id="__span-17-5"><a id="__codelineno-17-5" name="__codelineno-17-5" href="#__codelineno-17-5"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"--- Tool: get_weather_stateful called for </span><span class="si">{</span><span class="n">city</span><span class="si">}</span><span class="s2"> ---"</span><span class="p">)</span>
</span><span id="__span-17-6"><a id="__codelineno-17-6" name="__codelineno-17-6" href="#__codelineno-17-6"></a>
</span><span id="__span-17-7"><a id="__codelineno-17-7" name="__codelineno-17-7" href="#__codelineno-17-7"></a> <span class="c1"># --- Read preference from state ---</span>
</span><span id="__span-17-8"><a id="__codelineno-17-8" name="__codelineno-17-8" href="#__codelineno-17-8"></a> <span class="n">preferred_unit</span> <span class="o">=</span> <span class="n">tool_context</span><span class="o">.</span><span class="n">state</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"user_preference_temperature_unit"</span><span class="p">,</span> <span class="s2">"Celsius"</span><span class="p">)</span> <span class="c1"># Default to Celsius</span>
</span><span id="__span-17-9"><a id="__codelineno-17-9" name="__codelineno-17-9" href="#__codelineno-17-9"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"--- Tool: Reading state 'user_preference_temperature_unit': </span><span class="si">{</span><span class="n">preferred_unit</span><span class="si">}</span><span class="s2"> ---"</span><span class="p">)</span>
</span><span id="__span-17-10"><a id="__codelineno-17-10" name="__codelineno-17-10" href="#__codelineno-17-10"></a>
</span><span id="__span-17-11"><a id="__codelineno-17-11" name="__codelineno-17-11" href="#__codelineno-17-11"></a> <span class="n">city_normalized</span> <span class="o">=</span> <span class="n">city</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">" "</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span>
</span><span id="__span-17-12"><a id="__codelineno-17-12" name="__codelineno-17-12" href="#__codelineno-17-12"></a>
</span><span id="__span-17-13"><a id="__codelineno-17-13" name="__codelineno-17-13" href="#__codelineno-17-13"></a> <span class="c1"># Mock weather data (always stored in Celsius internally)</span>
</span><span id="__span-17-14"><a id="__codelineno-17-14" name="__codelineno-17-14" href="#__codelineno-17-14"></a> <span class="n">mock_weather_db</span> <span class="o">=</span> <span class="p">{</span>
</span><span id="__span-17-15"><a id="__codelineno-17-15" name="__codelineno-17-15" href="#__codelineno-17-15"></a> <span class="s2">"newyork"</span><span class="p">:</span> <span class="p">{</span><span class="s2">"temp_c"</span><span class="p">:</span> <span class="mi">25</span><span class="p">,</span> <span class="s2">"condition"</span><span class="p">:</span> <span class="s2">"sunny"</span><span class="p">},</span>
</span><span id="__span-17-16"><a id="__codelineno-17-16" name="__codelineno-17-16" href="#__codelineno-17-16"></a> <span class="s2">"london"</span><span class="p">:</span> <span class="p">{</span><span class="s2">"temp_c"</span><span class="p">:</span> <span class="mi">15</span><span class="p">,</span> <span class="s2">"condition"</span><span class="p">:</span> <span class="s2">"cloudy"</span><span class="p">},</span>
</span><span id="__span-17-17"><a id="__codelineno-17-17" name="__codelineno-17-17" href="#__codelineno-17-17"></a> <span class="s2">"tokyo"</span><span class="p">:</span> <span class="p">{</span><span class="s2">"temp_c"</span><span class="p">:</span> <span class="mi">18</span><span class="p">,</span> <span class="s2">"condition"</span><span class="p">:</span> <span class="s2">"light rain"</span><span class="p">},</span>
</span><span id="__span-17-18"><a id="__codelineno-17-18" name="__codelineno-17-18" href="#__codelineno-17-18"></a> <span class="p">}</span>
</span><span id="__span-17-19"><a id="__codelineno-17-19" name="__codelineno-17-19" href="#__codelineno-17-19"></a>
</span><span id="__span-17-20"><a id="__codelineno-17-20" name="__codelineno-17-20" href="#__codelineno-17-20"></a> <span class="k">if</span> <span class="n">city_normalized</span> <span class="ow">in</span> <span class="n">mock_weather_db</span><span class="p">:</span>
</span><span id="__span-17-21"><a id="__codelineno-17-21" name="__codelineno-17-21" href="#__codelineno-17-21"></a> <span class="n">data</span> <span class="o">=</span> <span class="n">mock_weather_db</span><span class="p">[</span><span class="n">city_normalized</span><span class="p">]</span>
</span><span id="__span-17-22"><a id="__codelineno-17-22" name="__codelineno-17-22" href="#__codelineno-17-22"></a> <span class="n">temp_c</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s2">"temp_c"</span><span class="p">]</span>
</span><span id="__span-17-23"><a id="__codelineno-17-23" name="__codelineno-17-23" href="#__codelineno-17-23"></a> <span class="n">condition</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s2">"condition"</span><span class="p">]</span>
</span><span id="__span-17-24"><a id="__codelineno-17-24" name="__codelineno-17-24" href="#__codelineno-17-24"></a>
</span><span id="__span-17-25"><a id="__codelineno-17-25" name="__codelineno-17-25" href="#__codelineno-17-25"></a> <span class="c1"># Format temperature based on state preference</span>
</span><span id="__span-17-26"><a id="__codelineno-17-26" name="__codelineno-17-26" href="#__codelineno-17-26"></a> <span class="k">if</span> <span class="n">preferred_unit</span> <span class="o">==</span> <span class="s2">"Fahrenheit"</span><span class="p">:</span>
</span><span id="__span-17-27"><a id="__codelineno-17-27" name="__codelineno-17-27" href="#__codelineno-17-27"></a> <span class="n">temp_value</span> <span class="o">=</span> <span class="p">(</span><span class="n">temp_c</span> <span class="o">*</span> <span class="mi">9</span><span class="o">/</span><span class="mi">5</span><span class="p">)</span> <span class="o">+</span> <span class="mi">32</span> <span class="c1"># Calculate Fahrenheit</span>
</span><span id="__span-17-28"><a id="__codelineno-17-28" name="__codelineno-17-28" href="#__codelineno-17-28"></a> <span class="n">temp_unit</span> <span class="o">=</span> <span class="s2">"°F"</span>
</span><span id="__span-17-29"><a id="__codelineno-17-29" name="__codelineno-17-29" href="#__codelineno-17-29"></a> <span class="k">else</span><span class="p">:</span> <span class="c1"># Default to Celsius</span>
</span><span id="__span-17-30"><a id="__codelineno-17-30" name="__codelineno-17-30" href="#__codelineno-17-30"></a> <span class="n">temp_value</span> <span class="o">=</span> <span class="n">temp_c</span>
</span><span id="__span-17-31"><a id="__codelineno-17-31" name="__codelineno-17-31" href="#__codelineno-17-31"></a> <span class="n">temp_unit</span> <span class="o">=</span> <span class="s2">"°C"</span>
</span><span id="__span-17-32"><a id="__codelineno-17-32" name="__codelineno-17-32" href="#__codelineno-17-32"></a>
</span><span id="__span-17-33"><a id="__codelineno-17-33" name="__codelineno-17-33" href="#__codelineno-17-33"></a> <span class="n">report</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"The weather in </span><span class="si">{</span><span class="n">city</span><span class="o">.</span><span class="n">capitalize</span><span class="p">()</span><span class="si">}</span><span class="s2"> is </span><span class="si">{</span><span class="n">condition</span><span class="si">}</span><span class="s2"> with a temperature of </span><span class="si">{</span><span class="n">temp_value</span><span class="si">:</span><span class="s2">.0f</span><span class="si">}{</span><span class="n">temp_unit</span><span class="si">}</span><span class="s2">."</span>
</span><span id="__span-17-34"><a id="__codelineno-17-34" name="__codelineno-17-34" href="#__codelineno-17-34"></a> <span class="n">result</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"status"</span><span class="p">:</span> <span class="s2">"success"</span><span class="p">,</span> <span class="s2">"report"</span><span class="p">:</span> <span class="n">report</span><span class="p">}</span>
</span><span id="__span-17-35"><a id="__codelineno-17-35" name="__codelineno-17-35" href="#__codelineno-17-35"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"--- Tool: Generated report in </span><span class="si">{</span><span class="n">preferred_unit</span><span class="si">}</span><span class="s2">. Result: </span><span class="si">{</span><span class="n">result</span><span class="si">}</span><span class="s2"> ---"</span><span class="p">)</span>
</span><span id="__span-17-36"><a id="__codelineno-17-36" name="__codelineno-17-36" href="#__codelineno-17-36"></a>
</span><span id="__span-17-37"><a id="__codelineno-17-37" name="__codelineno-17-37" href="#__codelineno-17-37"></a> <span class="c1"># Example of writing back to state (optional for this tool)</span>
</span><span id="__span-17-38"><a id="__codelineno-17-38" name="__codelineno-17-38" href="#__codelineno-17-38"></a> <span class="n">tool_context</span><span class="o">.</span><span class="n">state</span><span class="p">[</span><span class="s2">"last_city_checked_stateful"</span><span class="p">]</span> <span class="o">=</span> <span class="n">city</span>
</span><span id="__span-17-39"><a id="__codelineno-17-39" name="__codelineno-17-39" href="#__codelineno-17-39"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"--- Tool: Updated state 'last_city_checked_stateful': </span><span class="si">{</span><span class="n">city</span><span class="si">}</span><span class="s2"> ---"</span><span class="p">)</span>
</span><span id="__span-17-40"><a id="__codelineno-17-40" name="__codelineno-17-40" href="#__codelineno-17-40"></a>
</span><span id="__span-17-41"><a id="__codelineno-17-41" name="__codelineno-17-41" href="#__codelineno-17-41"></a> <span class="k">return</span> <span class="n">result</span>
</span><span id="__span-17-42"><a id="__codelineno-17-42" name="__codelineno-17-42" href="#__codelineno-17-42"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-17-43"><a id="__codelineno-17-43" name="__codelineno-17-43" href="#__codelineno-17-43"></a> <span class="c1"># Handle city not found</span>
</span><span id="__span-17-44"><a id="__codelineno-17-44" name="__codelineno-17-44" href="#__codelineno-17-44"></a> <span class="n">error_msg</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"Sorry, I don't have weather information for '</span><span class="si">{</span><span class="n">city</span><span class="si">}</span><span class="s2">'."</span>
</span><span id="__span-17-45"><a id="__codelineno-17-45" name="__codelineno-17-45" href="#__codelineno-17-45"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"--- Tool: City '</span><span class="si">{</span><span class="n">city</span><span class="si">}</span><span class="s2">' not found. ---"</span><span class="p">)</span>
</span><span id="__span-17-46"><a id="__codelineno-17-46" name="__codelineno-17-46" href="#__codelineno-17-46"></a> <span class="k">return</span> <span class="p">{</span><span class="s2">"status"</span><span class="p">:</span> <span class="s2">"error"</span><span class="p">,</span> <span class="s2">"error_message"</span><span class="p">:</span> <span class="n">error_msg</span><span class="p">}</span>
</span><span id="__span-17-47"><a id="__codelineno-17-47" name="__codelineno-17-47" href="#__codelineno-17-47"></a>
</span><span id="__span-17-48"><a id="__codelineno-17-48" name="__codelineno-17-48" href="#__codelineno-17-48"></a><span class="nb">print</span><span class="p">(</span><span class="s2">"✅ State-aware 'get_weather_stateful' tool defined."</span><span class="p">)</span>
</span></code></pre></div>
<hr />
<p><strong>3. Redefine Sub-Agents and Update Root Agent</strong></p>
<p>To ensure this step is self-contained and builds correctly, we first redefine the <code>greeting_agent</code> and <code>farewell_agent</code> exactly as they were in Step 3. Then, we define our new root agent (<code>weather_agent_v4_stateful</code>):</p>
<ul>
<li>It uses the new <code>get_weather_stateful</code> tool.</li>
<li>It includes the greeting and farewell sub-agents for delegation.</li>
<li><strong>Crucially</strong>, it sets <code>output_key="last_weather_report"</code> which automatically saves its final weather response to the session state.</li>
</ul>
<div class="language-python highlight"><pre><span></span><code><span id="__span-18-1"><a id="__codelineno-18-1" name="__codelineno-18-1" href="#__codelineno-18-1"></a><span class="c1"># @title 3. Redefine Sub-Agents and Update Root Agent with output_key</span>
</span><span id="__span-18-2"><a id="__codelineno-18-2" name="__codelineno-18-2" href="#__codelineno-18-2"></a>
</span><span id="__span-18-3"><a id="__codelineno-18-3" name="__codelineno-18-3" href="#__codelineno-18-3"></a><span class="c1"># Ensure necessary imports: Agent, LiteLlm, Runner</span>
</span><span id="__span-18-4"><a id="__codelineno-18-4" name="__codelineno-18-4" href="#__codelineno-18-4"></a><span class="kn">from</span><span class="w"> </span><span class="nn">google.adk.agents</span><span class="w"> </span><span class="kn">import</span> <span class="n">Agent</span>
</span><span id="__span-18-5"><a id="__codelineno-18-5" name="__codelineno-18-5" href="#__codelineno-18-5"></a><span class="kn">from</span><span class="w"> </span><span class="nn">google.adk.models.lite_llm</span><span class="w"> </span><span class="kn">import</span> <span class="n">LiteLlm</span>
</span><span id="__span-18-6"><a id="__codelineno-18-6" name="__codelineno-18-6" href="#__codelineno-18-6"></a><span class="kn">from</span><span class="w"> </span><span class="nn">google.adk.runners</span><span class="w"> </span><span class="kn">import</span> <span class="n">Runner</span>
</span><span id="__span-18-7"><a id="__codelineno-18-7" name="__codelineno-18-7" href="#__codelineno-18-7"></a><span class="c1"># Ensure tools 'say_hello', 'say_goodbye' are defined (from Step 3)</span>
</span><span id="__span-18-8"><a id="__codelineno-18-8" name="__codelineno-18-8" href="#__codelineno-18-8"></a><span class="c1"># Ensure model constants MODEL_GPT_4O, MODEL_GEMINI_FLASH etc. are defined</span>
</span><span id="__span-18-9"><a id="__codelineno-18-9" name="__codelineno-18-9" href="#__codelineno-18-9"></a>
</span><span id="__span-18-10"><a id="__codelineno-18-10" name="__codelineno-18-10" href="#__codelineno-18-10"></a><span class="c1"># --- Redefine Greeting Agent (from Step 3) ---</span>
</span><span id="__span-18-11"><a id="__codelineno-18-11" name="__codelineno-18-11" href="#__codelineno-18-11"></a><span class="n">greeting_agent</span> <span class="o">=</span> <span class="kc">None</span>
</span><span id="__span-18-12"><a id="__codelineno-18-12" name="__codelineno-18-12" href="#__codelineno-18-12"></a><span class="k">try</span><span class="p">:</span>
</span><span id="__span-18-13"><a id="__codelineno-18-13" name="__codelineno-18-13" href="#__codelineno-18-13"></a> <span class="n">greeting_agent</span> <span class="o">=</span> <span class="n">Agent</span><span class="p">(</span>
</span><span id="__span-18-14"><a id="__codelineno-18-14" name="__codelineno-18-14" href="#__codelineno-18-14"></a> <span class="n">model</span><span class="o">=</span><span class="n">MODEL_GEMINI_FLASH</span><span class="p">,</span>
</span><span id="__span-18-15"><a id="__codelineno-18-15" name="__codelineno-18-15" href="#__codelineno-18-15"></a> <span class="n">name</span><span class="o">=</span><span class="s2">"greeting_agent"</span><span class="p">,</span>
</span><span id="__span-18-16"><a id="__codelineno-18-16" name="__codelineno-18-16" href="#__codelineno-18-16"></a> <span class="n">instruction</span><span class="o">=</span><span class="s2">"You are the Greeting Agent. Your ONLY task is to provide a friendly greeting using the 'say_hello' tool. Do nothing else."</span><span class="p">,</span>
</span><span id="__span-18-17"><a id="__codelineno-18-17" name="__codelineno-18-17" href="#__codelineno-18-17"></a> <span class="n">description</span><span class="o">=</span><span class="s2">"Handles simple greetings and hellos using the 'say_hello' tool."</span><span class="p">,</span>
</span><span id="__span-18-18"><a id="__codelineno-18-18" name="__codelineno-18-18" href="#__codelineno-18-18"></a> <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">say_hello</span><span class="p">],</span>
</span><span id="__span-18-19"><a id="__codelineno-18-19" name="__codelineno-18-19" href="#__codelineno-18-19"></a> <span class="p">)</span>
</span><span id="__span-18-20"><a id="__codelineno-18-20" name="__codelineno-18-20" href="#__codelineno-18-20"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"✅ Agent '</span><span class="si">{</span><span class="n">greeting_agent</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">' redefined."</span><span class="p">)</span>
</span><span id="__span-18-21"><a id="__codelineno-18-21" name="__codelineno-18-21" href="#__codelineno-18-21"></a><span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span><span id="__span-18-22"><a id="__codelineno-18-22" name="__codelineno-18-22" href="#__codelineno-18-22"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"❌ Could not redefine Greeting agent. Error: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span><span id="__span-18-23"><a id="__codelineno-18-23" name="__codelineno-18-23" href="#__codelineno-18-23"></a>
</span><span id="__span-18-24"><a id="__codelineno-18-24" name="__codelineno-18-24" href="#__codelineno-18-24"></a><span class="c1"># --- Redefine Farewell Agent (from Step 3) ---</span>
</span><span id="__span-18-25"><a id="__codelineno-18-25" name="__codelineno-18-25" href="#__codelineno-18-25"></a><span class="n">farewell_agent</span> <span class="o">=</span> <span class="kc">None</span>
</span><span id="__span-18-26"><a id="__codelineno-18-26" name="__codelineno-18-26" href="#__codelineno-18-26"></a><span class="k">try</span><span class="p">:</span>
</span><span id="__span-18-27"><a id="__codelineno-18-27" name="__codelineno-18-27" href="#__codelineno-18-27"></a> <span class="n">farewell_agent</span> <span class="o">=</span> <span class="n">Agent</span><span class="p">(</span>
</span><span id="__span-18-28"><a id="__codelineno-18-28" name="__codelineno-18-28" href="#__codelineno-18-28"></a> <span class="n">model</span><span class="o">=</span><span class="n">MODEL_GEMINI_FLASH</span><span class="p">,</span>
</span><span id="__span-18-29"><a id="__codelineno-18-29" name="__codelineno-18-29" href="#__codelineno-18-29"></a> <span class="n">name</span><span class="o">=</span><span class="s2">"farewell_agent"</span><span class="p">,</span>
</span><span id="__span-18-30"><a id="__codelineno-18-30" name="__codelineno-18-30" href="#__codelineno-18-30"></a> <span class="n">instruction</span><span class="o">=</span><span class="s2">"You are the Farewell Agent. Your ONLY task is to provide a polite goodbye message using the 'say_goodbye' tool. Do not perform any other actions."</span><span class="p">,</span>
</span><span id="__span-18-31"><a id="__codelineno-18-31" name="__codelineno-18-31" href="#__codelineno-18-31"></a> <span class="n">description</span><span class="o">=</span><span class="s2">"Handles simple farewells and goodbyes using the 'say_goodbye' tool."</span><span class="p">,</span>
</span><span id="__span-18-32"><a id="__codelineno-18-32" name="__codelineno-18-32" href="#__codelineno-18-32"></a> <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">say_goodbye</span><span class="p">],</span>
</span><span id="__span-18-33"><a id="__codelineno-18-33" name="__codelineno-18-33" href="#__codelineno-18-33"></a> <span class="p">)</span>
</span><span id="__span-18-34"><a id="__codelineno-18-34" name="__codelineno-18-34" href="#__codelineno-18-34"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"✅ Agent '</span><span class="si">{</span><span class="n">farewell_agent</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">' redefined."</span><span class="p">)</span>
</span><span id="__span-18-35"><a id="__codelineno-18-35" name="__codelineno-18-35" href="#__codelineno-18-35"></a><span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span><span id="__span-18-36"><a id="__codelineno-18-36" name="__codelineno-18-36" href="#__codelineno-18-36"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"❌ Could not redefine Farewell agent. Error: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span><span id="__span-18-37"><a id="__codelineno-18-37" name="__codelineno-18-37" href="#__codelineno-18-37"></a>
</span><span id="__span-18-38"><a id="__codelineno-18-38" name="__codelineno-18-38" href="#__codelineno-18-38"></a><span class="c1"># --- Define the Updated Root Agent ---</span>
</span><span id="__span-18-39"><a id="__codelineno-18-39" name="__codelineno-18-39" href="#__codelineno-18-39"></a><span class="n">root_agent_stateful</span> <span class="o">=</span> <span class="kc">None</span>
</span><span id="__span-18-40"><a id="__codelineno-18-40" name="__codelineno-18-40" href="#__codelineno-18-40"></a><span class="n">runner_root_stateful</span> <span class="o">=</span> <span class="kc">None</span> <span class="c1"># Initialize runner</span>
</span><span id="__span-18-41"><a id="__codelineno-18-41" name="__codelineno-18-41" href="#__codelineno-18-41"></a>
</span><span id="__span-18-42"><a id="__codelineno-18-42" name="__codelineno-18-42" href="#__codelineno-18-42"></a><span class="c1"># Check prerequisites before creating the root agent</span>
</span><span id="__span-18-43"><a id="__codelineno-18-43" name="__codelineno-18-43" href="#__codelineno-18-43"></a><span class="k">if</span> <span class="n">greeting_agent</span> <span class="ow">and</span> <span class="n">farewell_agent</span> <span class="ow">and</span> <span class="s1">'get_weather_stateful'</span> <span class="ow">in</span> <span class="nb">globals</span><span class="p">():</span>
</span><span id="__span-18-44"><a id="__codelineno-18-44" name="__codelineno-18-44" href="#__codelineno-18-44"></a>
</span><span id="__span-18-45"><a id="__codelineno-18-45" name="__codelineno-18-45" href="#__codelineno-18-45"></a> <span class="n">root_agent_model</span> <span class="o">=</span> <span class="n">MODEL_GEMINI_FLASH</span> <span class="c1"># Choose orchestration model</span>
</span><span id="__span-18-46"><a id="__codelineno-18-46" name="__codelineno-18-46" href="#__codelineno-18-46"></a>
</span><span id="__span-18-47"><a id="__codelineno-18-47" name="__codelineno-18-47" href="#__codelineno-18-47"></a> <span class="n">root_agent_stateful</span> <span class="o">=</span> <span class="n">Agent</span><span class="p">(</span>
</span><span id="__span-18-48"><a id="__codelineno-18-48" name="__codelineno-18-48" href="#__codelineno-18-48"></a> <span class="n">name</span><span class="o">=</span><span class="s2">"weather_agent_v4_stateful"</span><span class="p">,</span> <span class="c1"># New version name</span>
</span><span id="__span-18-49"><a id="__codelineno-18-49" name="__codelineno-18-49" href="#__codelineno-18-49"></a> <span class="n">model</span><span class="o">=</span><span class="n">root_agent_model</span><span class="p">,</span>
</span><span id="__span-18-50"><a id="__codelineno-18-50" name="__codelineno-18-50" href="#__codelineno-18-50"></a> <span class="n">description</span><span class="o">=</span><span class="s2">"Main agent: Provides weather (state-aware unit), delegates greetings/farewells, saves report to state."</span><span class="p">,</span>
</span><span id="__span-18-51"><a id="__codelineno-18-51" name="__codelineno-18-51" href="#__codelineno-18-51"></a> <span class="n">instruction</span><span class="o">=</span><span class="s2">"You are the main Weather Agent. Your job is to provide weather using 'get_weather_stateful'. "</span>
</span><span id="__span-18-52"><a id="__codelineno-18-52" name="__codelineno-18-52" href="#__codelineno-18-52"></a> <span class="s2">"The tool will format the temperature based on user preference stored in state. "</span>
</span><span id="__span-18-53"><a id="__codelineno-18-53" name="__codelineno-18-53" href="#__codelineno-18-53"></a> <span class="s2">"Delegate simple greetings to 'greeting_agent' and farewells to 'farewell_agent'. "</span>
</span><span id="__span-18-54"><a id="__codelineno-18-54" name="__codelineno-18-54" href="#__codelineno-18-54"></a> <span class="s2">"Handle only weather requests, greetings, and farewells."</span><span class="p">,</span>
</span><span id="__span-18-55"><a id="__codelineno-18-55" name="__codelineno-18-55" href="#__codelineno-18-55"></a> <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">get_weather_stateful</span><span class="p">],</span> <span class="c1"># Use the state-aware tool</span>
</span><span id="__span-18-56"><a id="__codelineno-18-56" name="__codelineno-18-56" href="#__codelineno-18-56"></a> <span class="n">sub_agents</span><span class="o">=</span><span class="p">[</span><span class="n">greeting_agent</span><span class="p">,</span> <span class="n">farewell_agent</span><span class="p">],</span> <span class="c1"># Include sub-agents</span>
</span><span id="__span-18-57"><a id="__codelineno-18-57" name="__codelineno-18-57" href="#__codelineno-18-57"></a> <span class="n">output_key</span><span class="o">=</span><span class="s2">"last_weather_report"</span> <span class="c1"># &lt;&lt;&lt; Auto-save agent's final weather response</span>
</span><span id="__span-18-58"><a id="__codelineno-18-58" name="__codelineno-18-58" href="#__codelineno-18-58"></a> <span class="p">)</span>
</span><span id="__span-18-59"><a id="__codelineno-18-59" name="__codelineno-18-59" href="#__codelineno-18-59"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"✅ Root Agent '</span><span class="si">{</span><span class="n">root_agent_stateful</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">' created using stateful tool and output_key."</span><span class="p">)</span>
</span><span id="__span-18-60"><a id="__codelineno-18-60" name="__codelineno-18-60" href="#__codelineno-18-60"></a>
</span><span id="__span-18-61"><a id="__codelineno-18-61" name="__codelineno-18-61" href="#__codelineno-18-61"></a> <span class="c1"># --- Create Runner for this Root Agent &amp; NEW Session Service ---</span>
</span><span id="__span-18-62"><a id="__codelineno-18-62" name="__codelineno-18-62" href="#__codelineno-18-62"></a> <span class="n">runner_root_stateful</span> <span class="o">=</span> <span class="n">Runner</span><span class="p">(</span>
</span><span id="__span-18-63"><a id="__codelineno-18-63" name="__codelineno-18-63" href="#__codelineno-18-63"></a> <span class="n">agent</span><span class="o">=</span><span class="n">root_agent_stateful</span><span class="p">,</span>
</span><span id="__span-18-64"><a id="__codelineno-18-64" name="__codelineno-18-64" href="#__codelineno-18-64"></a> <span class="n">app_name</span><span class="o">=</span><span class="n">APP_NAME</span><span class="p">,</span>
</span><span id="__span-18-65"><a id="__codelineno-18-65" name="__codelineno-18-65" href="#__codelineno-18-65"></a> <span class="n">session_service</span><span class="o">=</span><span class="n">session_service_stateful</span> <span class="c1"># Use the NEW stateful session service</span>
</span><span id="__span-18-66"><a id="__codelineno-18-66" name="__codelineno-18-66" href="#__codelineno-18-66"></a> <span class="p">)</span>
</span><span id="__span-18-67"><a id="__codelineno-18-67" name="__codelineno-18-67" href="#__codelineno-18-67"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"✅ Runner created for stateful root agent '</span><span class="si">{</span><span class="n">runner_root_stateful</span><span class="o">.</span><span class="n">agent</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">' using stateful session service."</span><span class="p">)</span>
</span><span id="__span-18-68"><a id="__codelineno-18-68" name="__codelineno-18-68" href="#__codelineno-18-68"></a>
</span><span id="__span-18-69"><a id="__codelineno-18-69" name="__codelineno-18-69" href="#__codelineno-18-69"></a><span class="k">else</span><span class="p">:</span>
</span><span id="__span-18-70"><a id="__codelineno-18-70" name="__codelineno-18-70" href="#__codelineno-18-70"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"❌ Cannot create stateful root agent. Prerequisites missing."</span><span class="p">)</span>
</span><span id="__span-18-71"><a id="__codelineno-18-71" name="__codelineno-18-71" href="#__codelineno-18-71"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">greeting_agent</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="s2">" - greeting_agent definition missing."</span><span class="p">)</span>
</span><span id="__span-18-72"><a id="__codelineno-18-72" name="__codelineno-18-72" href="#__codelineno-18-72"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">farewell_agent</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="s2">" - farewell_agent definition missing."</span><span class="p">)</span>
</span><span id="__span-18-73"><a id="__codelineno-18-73" name="__codelineno-18-73" href="#__codelineno-18-73"></a> <span class="k">if</span> <span class="s1">'get_weather_stateful'</span> <span class="ow">not</span> <span class="ow">in</span> <span class="nb">globals</span><span class="p">():</span> <span class="nb">print</span><span class="p">(</span><span class="s2">" - get_weather_stateful tool missing."</span><span class="p">)</span>
</span></code></pre></div>
<hr />
<p><strong>4. Interact and Test State Flow</strong></p>
<p>Now, let's execute a conversation designed to test the state interactions using the <code>runner_root_stateful</code> (associated with our stateful agent and the <code>session_service_stateful</code>). We'll use the <code>call_agent_async</code> function defined earlier, ensuring we pass the correct runner, user ID (<code>USER_ID_STATEFUL</code>), and session ID (<code>SESSION_ID_STATEFUL</code>).</p>
<p>The conversation flow will be:</p>
<ol>
<li><strong>Check weather (London):</strong> The <code>get_weather_stateful</code> tool should read the initial "Celsius" preference from the session state initialized in Section 1. The root agent's final response (the weather report in Celsius) should get saved to <code>state['last_weather_report']</code> via the <code>output_key</code> configuration.</li>
<li><strong>Manually update state:</strong> We will <em>directly modify</em> the state stored within the <code>InMemorySessionService</code> instance (<code>session_service_stateful</code>).<ul>
<li><strong>Why direct modification?</strong> The <code>session_service.get_session()</code> method returns a <em>copy</em> of the session. Modifying that copy wouldn't affect the state used in subsequent agent runs. For this testing scenario with <code>InMemorySessionService</code>, we access the internal <code>sessions</code> dictionary to change the <em>actual</em> stored state value for <code>user_preference_temperature_unit</code> to "Fahrenheit". <em>Note: In real applications, state changes are typically triggered by tools or agent logic returning <code>EventActions(state_delta=...)</code>, not direct manual updates.</em></li>
</ul>
</li>
<li><strong>Check weather again (New York):</strong> The <code>get_weather_stateful</code> tool should now read the updated "Fahrenheit" preference from the state and convert the temperature accordingly. The root agent's <em>new</em> response (weather in Fahrenheit) will overwrite the previous value in <code>state['last_weather_report']</code> due to the <code>output_key</code>.</li>
<li><strong>Greet the agent:</strong> Verify that delegation to the <code>greeting_agent</code> still works correctly alongside the stateful operations.</li>
<li><strong>Inspect final state:</strong> After the conversation, we retrieve the session one last time (getting a copy) and print its state to confirm the <code>user_preference_temperature_unit</code> is indeed "Fahrenheit", observe the final value saved by <code>output_key</code> (which will be the previous weather report in this run), and see the <code>last_city_checked_stateful</code> value written by the tool.</li>
</ol>
<div class="language-python highlight"><pre><span></span><code><span id="__span-19-1"><a id="__codelineno-19-1" name="__codelineno-19-1" href="#__codelineno-19-1"></a><span class="c1"># @title 4. Interact to Test State Flow and output_key</span>
</span><span id="__span-19-2"><a id="__codelineno-19-2" name="__codelineno-19-2" href="#__codelineno-19-2"></a><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span> <span class="c1"># Ensure asyncio is imported</span>
</span><span id="__span-19-3"><a id="__codelineno-19-3" name="__codelineno-19-3" href="#__codelineno-19-3"></a>
</span><span id="__span-19-4"><a id="__codelineno-19-4" name="__codelineno-19-4" href="#__codelineno-19-4"></a><span class="c1"># Ensure the stateful runner (runner_root_stateful) is available from the previous cell</span>
</span><span id="__span-19-5"><a id="__codelineno-19-5" name="__codelineno-19-5" href="#__codelineno-19-5"></a><span class="c1"># Ensure call_agent_async, USER_ID_STATEFUL, SESSION_ID_STATEFUL, APP_NAME are defined</span>
</span><span id="__span-19-6"><a id="__codelineno-19-6" name="__codelineno-19-6" href="#__codelineno-19-6"></a>
</span><span id="__span-19-7"><a id="__codelineno-19-7" name="__codelineno-19-7" href="#__codelineno-19-7"></a><span class="k">if</span> <span class="s1">'runner_root_stateful'</span> <span class="ow">in</span> <span class="nb">globals</span><span class="p">()</span> <span class="ow">and</span> <span class="n">runner_root_stateful</span><span class="p">:</span>
</span><span id="__span-19-8"><a id="__codelineno-19-8" name="__codelineno-19-8" href="#__codelineno-19-8"></a> <span class="c1"># Define the main async function for the stateful conversation logic.</span>
</span><span id="__span-19-9"><a id="__codelineno-19-9" name="__codelineno-19-9" href="#__codelineno-19-9"></a> <span class="c1"># The 'await' keywords INSIDE this function are necessary for async operations.</span>
</span><span id="__span-19-10"><a id="__codelineno-19-10" name="__codelineno-19-10" href="#__codelineno-19-10"></a> <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run_stateful_conversation</span><span class="p">():</span>
</span><span id="__span-19-11"><a id="__codelineno-19-11" name="__codelineno-19-11" href="#__codelineno-19-11"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">--- Testing State: Temp Unit Conversion &amp; output_key ---"</span><span class="p">)</span>
</span><span id="__span-19-12"><a id="__codelineno-19-12" name="__codelineno-19-12" href="#__codelineno-19-12"></a>
</span><span id="__span-19-13"><a id="__codelineno-19-13" name="__codelineno-19-13" href="#__codelineno-19-13"></a> <span class="c1"># 1. Check weather (Uses initial state: Celsius)</span>
</span><span id="__span-19-14"><a id="__codelineno-19-14" name="__codelineno-19-14" href="#__codelineno-19-14"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"--- Turn 1: Requesting weather in London (expect Celsius) ---"</span><span class="p">)</span>
</span><span id="__span-19-15"><a id="__codelineno-19-15" name="__codelineno-19-15" href="#__codelineno-19-15"></a> <span class="k">await</span> <span class="n">call_agent_async</span><span class="p">(</span><span class="n">query</span><span class="o">=</span> <span class="s2">"What's the weather in London?"</span><span class="p">,</span>
</span><span id="__span-19-16"><a id="__codelineno-19-16" name="__codelineno-19-16" href="#__codelineno-19-16"></a> <span class="n">runner</span><span class="o">=</span><span class="n">runner_root_stateful</span><span class="p">,</span>
</span><span id="__span-19-17"><a id="__codelineno-19-17" name="__codelineno-19-17" href="#__codelineno-19-17"></a> <span class="n">user_id</span><span class="o">=</span><span class="n">USER_ID_STATEFUL</span><span class="p">,</span>
</span><span id="__span-19-18"><a id="__codelineno-19-18" name="__codelineno-19-18" href="#__codelineno-19-18"></a> <span class="n">session_id</span><span class="o">=</span><span class="n">SESSION_ID_STATEFUL</span>
</span><span id="__span-19-19"><a id="__codelineno-19-19" name="__codelineno-19-19" href="#__codelineno-19-19"></a> <span class="p">)</span>
</span><span id="__span-19-20"><a id="__codelineno-19-20" name="__codelineno-19-20" href="#__codelineno-19-20"></a>
</span><span id="__span-19-21"><a id="__codelineno-19-21" name="__codelineno-19-21" href="#__codelineno-19-21"></a> <span class="c1"># 2. Manually update state preference to Fahrenheit - DIRECTLY MODIFY STORAGE</span>
</span><span id="__span-19-22"><a id="__codelineno-19-22" name="__codelineno-19-22" href="#__codelineno-19-22"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">--- Manually Updating State: Setting unit to Fahrenheit ---"</span><span class="p">)</span>
</span><span id="__span-19-23"><a id="__codelineno-19-23" name="__codelineno-19-23" href="#__codelineno-19-23"></a> <span class="k">try</span><span class="p">:</span>
</span><span id="__span-19-24"><a id="__codelineno-19-24" name="__codelineno-19-24" href="#__codelineno-19-24"></a> <span class="c1"># Access the internal storage directly - THIS IS SPECIFIC TO InMemorySessionService for testing</span>
</span><span id="__span-19-25"><a id="__codelineno-19-25" name="__codelineno-19-25" href="#__codelineno-19-25"></a> <span class="c1"># NOTE: In production with persistent services (Database, VertexAI), you would</span>
</span><span id="__span-19-26"><a id="__codelineno-19-26" name="__codelineno-19-26" href="#__codelineno-19-26"></a> <span class="c1"># typically update state via agent actions or specific service APIs if available,</span>
</span><span id="__span-19-27"><a id="__codelineno-19-27" name="__codelineno-19-27" href="#__codelineno-19-27"></a> <span class="c1"># not by direct manipulation of internal storage.</span>
</span><span id="__span-19-28"><a id="__codelineno-19-28" name="__codelineno-19-28" href="#__codelineno-19-28"></a> <span class="n">stored_session</span> <span class="o">=</span> <span class="n">session_service_stateful</span><span class="o">.</span><span class="n">sessions</span><span class="p">[</span><span class="n">APP_NAME</span><span class="p">][</span><span class="n">USER_ID_STATEFUL</span><span class="p">][</span><span class="n">SESSION_ID_STATEFUL</span><span class="p">]</span>
</span><span id="__span-19-29"><a id="__codelineno-19-29" name="__codelineno-19-29" href="#__codelineno-19-29"></a> <span class="n">stored_session</span><span class="o">.</span><span class="n">state</span><span class="p">[</span><span class="s2">"user_preference_temperature_unit"</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"Fahrenheit"</span>
</span><span id="__span-19-30"><a id="__codelineno-19-30" name="__codelineno-19-30" href="#__codelineno-19-30"></a> <span class="c1"># Optional: You might want to update the timestamp as well if any logic depends on it</span>
</span><span id="__span-19-31"><a id="__codelineno-19-31" name="__codelineno-19-31" href="#__codelineno-19-31"></a> <span class="c1"># import time</span>
</span><span id="__span-19-32"><a id="__codelineno-19-32" name="__codelineno-19-32" href="#__codelineno-19-32"></a> <span class="c1"># stored_session.last_update_time = time.time()</span>
</span><span id="__span-19-33"><a id="__codelineno-19-33" name="__codelineno-19-33" href="#__codelineno-19-33"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"--- Stored session state updated. Current 'user_preference_temperature_unit': </span><span class="si">{</span><span class="n">stored_session</span><span class="o">.</span><span class="n">state</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'user_preference_temperature_unit'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Not Set'</span><span class="p">)</span><span class="si">}</span><span class="s2"> ---"</span><span class="p">)</span> <span class="c1"># Added .get for safety</span>
</span><span id="__span-19-34"><a id="__codelineno-19-34" name="__codelineno-19-34" href="#__codelineno-19-34"></a> <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
</span><span id="__span-19-35"><a id="__codelineno-19-35" name="__codelineno-19-35" href="#__codelineno-19-35"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"--- Error: Could not retrieve session '</span><span class="si">{</span><span class="n">SESSION_ID_STATEFUL</span><span class="si">}</span><span class="s2">' from internal storage for user '</span><span class="si">{</span><span class="n">USER_ID_STATEFUL</span><span class="si">}</span><span class="s2">' in app '</span><span class="si">{</span><span class="n">APP_NAME</span><span class="si">}</span><span class="s2">' to update state. Check IDs and if session was created. ---"</span><span class="p">)</span>
</span><span id="__span-19-36"><a id="__codelineno-19-36" name="__codelineno-19-36" href="#__codelineno-19-36"></a> <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span><span id="__span-19-37"><a id="__codelineno-19-37" name="__codelineno-19-37" href="#__codelineno-19-37"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"--- Error updating internal session state: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2"> ---"</span><span class="p">)</span>
</span><span id="__span-19-38"><a id="__codelineno-19-38" name="__codelineno-19-38" href="#__codelineno-19-38"></a>
</span><span id="__span-19-39"><a id="__codelineno-19-39" name="__codelineno-19-39" href="#__codelineno-19-39"></a> <span class="c1"># 3. Check weather again (Tool should now use Fahrenheit)</span>
</span><span id="__span-19-40"><a id="__codelineno-19-40" name="__codelineno-19-40" href="#__codelineno-19-40"></a> <span class="c1"># This will also update 'last_weather_report' via output_key</span>
</span><span id="__span-19-41"><a id="__codelineno-19-41" name="__codelineno-19-41" href="#__codelineno-19-41"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">--- Turn 2: Requesting weather in New York (expect Fahrenheit) ---"</span><span class="p">)</span>
</span><span id="__span-19-42"><a id="__codelineno-19-42" name="__codelineno-19-42" href="#__codelineno-19-42"></a> <span class="k">await</span> <span class="n">call_agent_async</span><span class="p">(</span><span class="n">query</span><span class="o">=</span> <span class="s2">"Tell me the weather in New York."</span><span class="p">,</span>
</span><span id="__span-19-43"><a id="__codelineno-19-43" name="__codelineno-19-43" href="#__codelineno-19-43"></a> <span class="n">runner</span><span class="o">=</span><span class="n">runner_root_stateful</span><span class="p">,</span>
</span><span id="__span-19-44"><a id="__codelineno-19-44" name="__codelineno-19-44" href="#__codelineno-19-44"></a> <span class="n">user_id</span><span class="o">=</span><span class="n">USER_ID_STATEFUL</span><span class="p">,</span>
</span><span id="__span-19-45"><a id="__codelineno-19-45" name="__codelineno-19-45" href="#__codelineno-19-45"></a> <span class="n">session_id</span><span class="o">=</span><span class="n">SESSION_ID_STATEFUL</span>
</span><span id="__span-19-46"><a id="__codelineno-19-46" name="__codelineno-19-46" href="#__codelineno-19-46"></a> <span class="p">)</span>
</span><span id="__span-19-47"><a id="__codelineno-19-47" name="__codelineno-19-47" href="#__codelineno-19-47"></a>
</span><span id="__span-19-48"><a id="__codelineno-19-48" name="__codelineno-19-48" href="#__codelineno-19-48"></a> <span class="c1"># 4. Test basic delegation (should still work)</span>
</span><span id="__span-19-49"><a id="__codelineno-19-49" name="__codelineno-19-49" href="#__codelineno-19-49"></a> <span class="c1"># The greeting is authored by the delegated sub-agent, not the root agent,</span>
</span><span id="__span-19-50"><a id="__codelineno-19-50" name="__codelineno-19-50" href="#__codelineno-19-50"></a> <span class="c1"># so output_key does NOT fire: 'last_weather_report' keeps the NY report.</span>
</span><span id="__span-19-51"><a id="__codelineno-19-51" name="__codelineno-19-51" href="#__codelineno-19-51"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">--- Turn 3: Sending a greeting ---"</span><span class="p">)</span>
</span><span id="__span-19-52"><a id="__codelineno-19-52" name="__codelineno-19-52" href="#__codelineno-19-52"></a> <span class="k">await</span> <span class="n">call_agent_async</span><span class="p">(</span><span class="n">query</span><span class="o">=</span> <span class="s2">"Hi!"</span><span class="p">,</span>
</span><span id="__span-19-53"><a id="__codelineno-19-53" name="__codelineno-19-53" href="#__codelineno-19-53"></a> <span class="n">runner</span><span class="o">=</span><span class="n">runner_root_stateful</span><span class="p">,</span>
</span><span id="__span-19-54"><a id="__codelineno-19-54" name="__codelineno-19-54" href="#__codelineno-19-54"></a> <span class="n">user_id</span><span class="o">=</span><span class="n">USER_ID_STATEFUL</span><span class="p">,</span>
</span><span id="__span-19-55"><a id="__codelineno-19-55" name="__codelineno-19-55" href="#__codelineno-19-55"></a> <span class="n">session_id</span><span class="o">=</span><span class="n">SESSION_ID_STATEFUL</span>
</span><span id="__span-19-56"><a id="__codelineno-19-56" name="__codelineno-19-56" href="#__codelineno-19-56"></a> <span class="p">)</span>
</span><span id="__span-19-57"><a id="__codelineno-19-57" name="__codelineno-19-57" href="#__codelineno-19-57"></a>
</span><span id="__span-19-58"><a id="__codelineno-19-58" name="__codelineno-19-58" href="#__codelineno-19-58"></a> <span class="c1"># --- Execute the `run_stateful_conversation` async function ---</span>
</span><span id="__span-19-59"><a id="__codelineno-19-59" name="__codelineno-19-59" href="#__codelineno-19-59"></a> <span class="c1"># Choose ONE of the methods below based on your environment.</span>
</span><span id="__span-19-60"><a id="__codelineno-19-60" name="__codelineno-19-60" href="#__codelineno-19-60"></a>
</span><span id="__span-19-61"><a id="__codelineno-19-61" name="__codelineno-19-61" href="#__codelineno-19-61"></a> <span class="c1"># METHOD 1: Direct await (Default for Notebooks/Async REPLs)</span>
</span><span id="__span-19-62"><a id="__codelineno-19-62" name="__codelineno-19-62" href="#__codelineno-19-62"></a> <span class="c1"># If your environment supports top-level await (like Colab/Jupyter notebooks),</span>
</span><span id="__span-19-63"><a id="__codelineno-19-63" name="__codelineno-19-63" href="#__codelineno-19-63"></a> <span class="c1"># it means an event loop is already running, so you can directly await the function.</span>
</span><span id="__span-19-64"><a id="__codelineno-19-64" name="__codelineno-19-64" href="#__codelineno-19-64"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"Attempting execution using 'await' (default for notebooks)..."</span><span class="p">)</span>
</span><span id="__span-19-65"><a id="__codelineno-19-65" name="__codelineno-19-65" href="#__codelineno-19-65"></a> <span class="k">await</span> <span class="n">run_stateful_conversation</span><span class="p">()</span>
</span><span id="__span-19-66"><a id="__codelineno-19-66" name="__codelineno-19-66" href="#__codelineno-19-66"></a>
</span><span id="__span-19-67"><a id="__codelineno-19-67" name="__codelineno-19-67" href="#__codelineno-19-67"></a> <span class="c1"># METHOD 2: asyncio.run (For Standard Python Scripts [.py])</span>
</span><span id="__span-19-68"><a id="__codelineno-19-68" name="__codelineno-19-68" href="#__codelineno-19-68"></a> <span class="c1"># If running this code as a standard Python script from your terminal,</span>
</span><span id="__span-19-69"><a id="__codelineno-19-69" name="__codelineno-19-69" href="#__codelineno-19-69"></a> <span class="c1"># the script context is synchronous. `asyncio.run()` is needed to</span>
</span><span id="__span-19-70"><a id="__codelineno-19-70" name="__codelineno-19-70" href="#__codelineno-19-70"></a> <span class="c1"># create and manage an event loop to execute your async function.</span>
</span><span id="__span-19-71"><a id="__codelineno-19-71" name="__codelineno-19-71" href="#__codelineno-19-71"></a> <span class="c1"># To use this method:</span>
</span><span id="__span-19-72"><a id="__codelineno-19-72" name="__codelineno-19-72" href="#__codelineno-19-72"></a> <span class="c1"># 1. Comment out the `await run_stateful_conversation()` line above.</span>
</span><span id="__span-19-73"><a id="__codelineno-19-73" name="__codelineno-19-73" href="#__codelineno-19-73"></a> <span class="c1"># 2. Uncomment the following block:</span>
</span><span id="__span-19-74"><a id="__codelineno-19-74" name="__codelineno-19-74" href="#__codelineno-19-74"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-19-75"><a id="__codelineno-19-75" name="__codelineno-19-75" href="#__codelineno-19-75"></a><span class="sd"> import asyncio</span>
</span><span id="__span-19-76"><a id="__codelineno-19-76" name="__codelineno-19-76" href="#__codelineno-19-76"></a><span class="sd"> if __name__ == "__main__": # Ensures this runs only when script is executed directly</span>
</span><span id="__span-19-77"><a id="__codelineno-19-77" name="__codelineno-19-77" href="#__codelineno-19-77"></a><span class="sd"> print("Executing using 'asyncio.run()' (for standard Python scripts)...")</span>
</span><span id="__span-19-78"><a id="__codelineno-19-78" name="__codelineno-19-78" href="#__codelineno-19-78"></a><span class="sd"> try:</span>
</span><span id="__span-19-79"><a id="__codelineno-19-79" name="__codelineno-19-79" href="#__codelineno-19-79"></a><span class="sd"> # This creates an event loop, runs your async function, and closes the loop.</span>
</span><span id="__span-19-80"><a id="__codelineno-19-80" name="__codelineno-19-80" href="#__codelineno-19-80"></a><span class="sd"> asyncio.run(run_stateful_conversation())</span>
</span><span id="__span-19-81"><a id="__codelineno-19-81" name="__codelineno-19-81" href="#__codelineno-19-81"></a><span class="sd"> except Exception as e:</span>
</span><span id="__span-19-82"><a id="__codelineno-19-82" name="__codelineno-19-82" href="#__codelineno-19-82"></a><span class="sd"> print(f"An error occurred: {e}")</span>
</span><span id="__span-19-83"><a id="__codelineno-19-83" name="__codelineno-19-83" href="#__codelineno-19-83"></a><span class="sd"> """</span>
</span><span id="__span-19-84"><a id="__codelineno-19-84" name="__codelineno-19-84" href="#__codelineno-19-84"></a>
</span><span id="__span-19-85"><a id="__codelineno-19-85" name="__codelineno-19-85" href="#__codelineno-19-85"></a> <span class="c1"># --- Inspect final session state after the conversation ---</span>
</span><span id="__span-19-86"><a id="__codelineno-19-86" name="__codelineno-19-86" href="#__codelineno-19-86"></a> <span class="c1"># This block runs after either execution method completes.</span>
</span><span id="__span-19-87"><a id="__codelineno-19-87" name="__codelineno-19-87" href="#__codelineno-19-87"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">--- Inspecting Final Session State ---"</span><span class="p">)</span>
</span><span id="__span-19-88"><a id="__codelineno-19-88" name="__codelineno-19-88" href="#__codelineno-19-88"></a> <span class="n">final_session</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session_service_stateful</span><span class="o">.</span><span class="n">get_session</span><span class="p">(</span><span class="n">app_name</span><span class="o">=</span><span class="n">APP_NAME</span><span class="p">,</span>
</span><span id="__span-19-89"><a id="__codelineno-19-89" name="__codelineno-19-89" href="#__codelineno-19-89"></a> <span class="n">user_id</span><span class="o">=</span> <span class="n">USER_ID_STATEFUL</span><span class="p">,</span>
</span><span id="__span-19-90"><a id="__codelineno-19-90" name="__codelineno-19-90" href="#__codelineno-19-90"></a> <span class="n">session_id</span><span class="o">=</span><span class="n">SESSION_ID_STATEFUL</span><span class="p">)</span>
</span><span id="__span-19-91"><a id="__codelineno-19-91" name="__codelineno-19-91" href="#__codelineno-19-91"></a> <span class="k">if</span> <span class="n">final_session</span><span class="p">:</span>
</span><span id="__span-19-92"><a id="__codelineno-19-92" name="__codelineno-19-92" href="#__codelineno-19-92"></a> <span class="c1"># Use .get() for safer access to potentially missing keys</span>
</span><span id="__span-19-93"><a id="__codelineno-19-93" name="__codelineno-19-93" href="#__codelineno-19-93"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Final Preference: </span><span class="si">{</span><span class="n">final_session</span><span class="o">.</span><span class="n">state</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'user_preference_temperature_unit'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Not Set'</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span><span id="__span-19-94"><a id="__codelineno-19-94" name="__codelineno-19-94" href="#__codelineno-19-94"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Final Last Weather Report (from output_key): </span><span class="si">{</span><span class="n">final_session</span><span class="o">.</span><span class="n">state</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'last_weather_report'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Not Set'</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span><span id="__span-19-95"><a id="__codelineno-19-95" name="__codelineno-19-95" href="#__codelineno-19-95"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Final Last City Checked (by tool): </span><span class="si">{</span><span class="n">final_session</span><span class="o">.</span><span class="n">state</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'last_city_checked_stateful'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Not Set'</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span><span id="__span-19-96"><a id="__codelineno-19-96" name="__codelineno-19-96" href="#__codelineno-19-96"></a> <span class="c1"># Print full state for detailed view</span>
</span><span id="__span-19-97"><a id="__codelineno-19-97" name="__codelineno-19-97" href="#__codelineno-19-97"></a> <span class="c1"># print(f"Full State Dict: {final_session.state}") # For detailed view</span>
</span><span id="__span-19-98"><a id="__codelineno-19-98" name="__codelineno-19-98" href="#__codelineno-19-98"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-19-99"><a id="__codelineno-19-99" name="__codelineno-19-99" href="#__codelineno-19-99"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">❌ Error: Could not retrieve final session state."</span><span class="p">)</span>
</span><span id="__span-19-100"><a id="__codelineno-19-100" name="__codelineno-19-100" href="#__codelineno-19-100"></a>
</span><span id="__span-19-101"><a id="__codelineno-19-101" name="__codelineno-19-101" href="#__codelineno-19-101"></a><span class="k">else</span><span class="p">:</span>
</span><span id="__span-19-102"><a id="__codelineno-19-102" name="__codelineno-19-102" href="#__codelineno-19-102"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">⚠️ Skipping state test conversation. Stateful root agent runner ('runner_root_stateful') is not available."</span><span class="p">)</span>
</span></code></pre></div>
<hr />
<p>By reviewing the conversation flow and the final session state printout, you can confirm:</p>
<ul>
<li><strong>State Read:</strong> The weather tool (<code>get_weather_stateful</code>) correctly read <code>user_preference_temperature_unit</code> from state, initially using "Celsius" for London.</li>
<li><strong>State Update:</strong> The direct modification successfully changed the stored preference to "Fahrenheit".</li>
<li><strong>State Read (Updated):</strong> The tool subsequently read "Fahrenheit" when asked for New York's weather and performed the conversion.</li>
<li><strong>Tool State Write:</strong> The tool successfully wrote the <code>last_city_checked_stateful</code> ("New York" after the second weather check) into the state via <code>tool_context.state</code>.</li>
<li><strong>Delegation:</strong> The delegation to the <code>greeting_agent</code> for "Hi!" functioned correctly even after state modifications.</li>
<li><strong><code>output_key</code>:</strong> The <code>output_key="last_weather_report"</code> successfully saved the root agent's <em>final</em> response for <em>each turn</em> where the root agent was the one ultimately responding. In this sequence, the final greeting ("Hello, there!") was generated by the delegated sub-agent rather than the root agent, so <code>output_key</code> was not triggered on that final turn, leaving the previous weather report intact in the session state.</li>
<li><strong>Final State:</strong> The final check confirms the preference persisted as "Fahrenheit".</li>
</ul>
<p>You've now successfully integrated session state to personalize agent behavior using <code>ToolContext</code>, manually manipulated state for testing <code>InMemorySessionService</code>, and observed how <code>output_key</code> 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.</p>
<hr />
<h2 id="step-5-adding-safety-input-guardrail-with-before_model_callback">Step 5: Adding Safety - Input Guardrail with <code>before_model_callback</code><a class="headerlink" href="#step-5-adding-safety-input-guardrail-with-before_model_callback" title="Permanent link">&para;</a></h2>
<p>Our agent team is becoming more capable, remembering preferences and using tools effectively. However, in real-world scenarios, we often need safety mechanisms to control the agent's behavior <em>before</em> potentially problematic requests even reach the core Large Language Model (LLM).</p>
<p>ADK provides <strong>Callbacks</strong> – functions that allow you to hook into specific points in the agent's execution lifecycle. The <code>before_model_callback</code> is particularly useful for input safety.</p>
<p><strong>What is <code>before_model_callback</code>?</strong></p>
<ul>
<li>It's a Python function you define that ADK executes <em>just before</em> an agent sends its compiled request (including conversation history, instructions, and the latest user message) to the underlying LLM.</li>
<li><strong>Purpose:</strong> Inspect the request, modify it if necessary, or block it entirely based on predefined rules.</li>
</ul>
<p><strong>Common Use Cases:</strong></p>
<ul>
<li><strong>Input Validation/Filtering:</strong> Check if user input meets criteria or contains disallowed content (like PII or keywords).</li>
<li><strong>Guardrails:</strong> Prevent harmful, off-topic, or policy-violating requests from being processed by the LLM.</li>
<li><strong>Dynamic Prompt Modification:</strong> Add timely information (e.g., from session state) to the LLM request context just before sending.</li>
</ul>
<p><strong>How it Works:</strong></p>
<ol>
<li>
<p>Define a function accepting <code>callback_context: CallbackContext</code> and <code>llm_request: LlmRequest</code>.</p>
<ul>
<li><code>callback_context</code>: Provides access to agent info, session state (<code>callback_context.state</code>), etc.</li>
<li><code>llm_request</code>: Contains the full payload intended for the LLM (<code>contents</code>, <code>config</code>).</li>
</ul>
</li>
<li>
<p>Inside the function:</p>
<ul>
<li><strong>Inspect:</strong> Examine <code>llm_request.contents</code> (especially the last user message).</li>
<li><strong>Modify (Use Caution):</strong> You <em>can</em> change parts of <code>llm_request</code>.</li>
<li><strong>Block (Guardrail):</strong> Return an <code>LlmResponse</code> object. ADK will send this response back immediately, <em>skipping</em> the LLM call for that turn.</li>
<li><strong>Allow:</strong> Return <code>None</code>. ADK proceeds to call the LLM with the (potentially modified) request.</li>
</ul>
</li>
</ol>
<p><strong>In this step, we will:</strong></p>
<ol>
<li>Define a <code>before_model_callback</code> function (<code>block_keyword_guardrail</code>) that checks the user's input for a specific keyword ("BLOCK").</li>
<li>Update our stateful root agent (<code>weather_agent_v4_stateful</code> from Step 4) to use this callback.</li>
<li>Create a new runner associated with this updated agent but using the <em>same stateful session service</em> to maintain state continuity.</li>
<li>Test the guardrail by sending both normal and keyword-containing requests.</li>
</ol>
<hr />
<p><strong>1. Define the Guardrail Callback Function</strong></p>
<p>This function will inspect the last user message within the <code>llm_request</code> content. If it finds "BLOCK" (case-insensitive), it constructs and returns an <code>LlmResponse</code> to block the flow; otherwise, it returns <code>None</code>.</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-20-1"><a id="__codelineno-20-1" name="__codelineno-20-1" href="#__codelineno-20-1"></a><span class="c1"># @title 1. Define the before_model_callback Guardrail</span>
</span><span id="__span-20-2"><a id="__codelineno-20-2" name="__codelineno-20-2" href="#__codelineno-20-2"></a>
</span><span id="__span-20-3"><a id="__codelineno-20-3" name="__codelineno-20-3" href="#__codelineno-20-3"></a><span class="c1"># Ensure necessary imports are available</span>
</span><span id="__span-20-4"><a id="__codelineno-20-4" name="__codelineno-20-4" href="#__codelineno-20-4"></a><span class="kn">from</span><span class="w"> </span><span class="nn">google.adk.agents.callback_context</span><span class="w"> </span><span class="kn">import</span> <span class="n">CallbackContext</span>
</span><span id="__span-20-5"><a id="__codelineno-20-5" name="__codelineno-20-5" href="#__codelineno-20-5"></a><span class="kn">from</span><span class="w"> </span><span class="nn">google.adk.models.llm_request</span><span class="w"> </span><span class="kn">import</span> <span class="n">LlmRequest</span>
</span><span id="__span-20-6"><a id="__codelineno-20-6" name="__codelineno-20-6" href="#__codelineno-20-6"></a><span class="kn">from</span><span class="w"> </span><span class="nn">google.adk.models.llm_response</span><span class="w"> </span><span class="kn">import</span> <span class="n">LlmResponse</span>
</span><span id="__span-20-7"><a id="__codelineno-20-7" name="__codelineno-20-7" href="#__codelineno-20-7"></a><span class="kn">from</span><span class="w"> </span><span class="nn">google.genai</span><span class="w"> </span><span class="kn">import</span> <span class="n">types</span> <span class="c1"># For creating response content</span>
</span><span id="__span-20-8"><a id="__codelineno-20-8" name="__codelineno-20-8" href="#__codelineno-20-8"></a><span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Optional</span>
</span><span id="__span-20-9"><a id="__codelineno-20-9" name="__codelineno-20-9" href="#__codelineno-20-9"></a>
</span><span id="__span-20-10"><a id="__codelineno-20-10" name="__codelineno-20-10" href="#__codelineno-20-10"></a><span class="k">def</span><span class="w"> </span><span class="nf">block_keyword_guardrail</span><span class="p">(</span>
</span><span id="__span-20-11"><a id="__codelineno-20-11" name="__codelineno-20-11" href="#__codelineno-20-11"></a> <span class="n">callback_context</span><span class="p">:</span> <span class="n">CallbackContext</span><span class="p">,</span> <span class="n">llm_request</span><span class="p">:</span> <span class="n">LlmRequest</span>
</span><span id="__span-20-12"><a id="__codelineno-20-12" name="__codelineno-20-12" href="#__codelineno-20-12"></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Optional</span><span class="p">[</span><span class="n">LlmResponse</span><span class="p">]:</span>
</span><span id="__span-20-13"><a id="__codelineno-20-13" name="__codelineno-20-13" href="#__codelineno-20-13"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-20-14"><a id="__codelineno-20-14" name="__codelineno-20-14" href="#__codelineno-20-14"></a><span class="sd"> Inspects the latest user message for 'BLOCK'. If found, blocks the LLM call</span>
</span><span id="__span-20-15"><a id="__codelineno-20-15" name="__codelineno-20-15" href="#__codelineno-20-15"></a><span class="sd"> and returns a predefined LlmResponse. Otherwise, returns None to proceed.</span>
</span><span id="__span-20-16"><a id="__codelineno-20-16" name="__codelineno-20-16" href="#__codelineno-20-16"></a><span class="sd"> """</span>
</span><span id="__span-20-17"><a id="__codelineno-20-17" name="__codelineno-20-17" href="#__codelineno-20-17"></a> <span class="n">agent_name</span> <span class="o">=</span> <span class="n">callback_context</span><span class="o">.</span><span class="n">agent_name</span> <span class="c1"># Get the name of the agent whose model call is being intercepted</span>
</span><span id="__span-20-18"><a id="__codelineno-20-18" name="__codelineno-20-18" href="#__codelineno-20-18"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"--- Callback: block_keyword_guardrail running for agent: </span><span class="si">{</span><span class="n">agent_name</span><span class="si">}</span><span class="s2"> ---"</span><span class="p">)</span>
</span><span id="__span-20-19"><a id="__codelineno-20-19" name="__codelineno-20-19" href="#__codelineno-20-19"></a>
</span><span id="__span-20-20"><a id="__codelineno-20-20" name="__codelineno-20-20" href="#__codelineno-20-20"></a> <span class="c1"># Extract the text from the latest user message in the request history</span>
</span><span id="__span-20-21"><a id="__codelineno-20-21" name="__codelineno-20-21" href="#__codelineno-20-21"></a> <span class="n">last_user_message_text</span> <span class="o">=</span> <span class="s2">""</span>
</span><span id="__span-20-22"><a id="__codelineno-20-22" name="__codelineno-20-22" href="#__codelineno-20-22"></a> <span class="k">if</span> <span class="n">llm_request</span><span class="o">.</span><span class="n">contents</span><span class="p">:</span>
</span><span id="__span-20-23"><a id="__codelineno-20-23" name="__codelineno-20-23" href="#__codelineno-20-23"></a> <span class="c1"># Find the most recent message with role 'user'</span>
</span><span id="__span-20-24"><a id="__codelineno-20-24" name="__codelineno-20-24" href="#__codelineno-20-24"></a> <span class="k">for</span> <span class="n">content</span> <span class="ow">in</span> <span class="nb">reversed</span><span class="p">(</span><span class="n">llm_request</span><span class="o">.</span><span class="n">contents</span><span class="p">):</span>
</span><span id="__span-20-25"><a id="__codelineno-20-25" name="__codelineno-20-25" href="#__codelineno-20-25"></a> <span class="k">if</span> <span class="n">content</span><span class="o">.</span><span class="n">role</span> <span class="o">==</span> <span class="s1">'user'</span> <span class="ow">and</span> <span class="n">content</span><span class="o">.</span><span class="n">parts</span><span class="p">:</span>
</span><span id="__span-20-26"><a id="__codelineno-20-26" name="__codelineno-20-26" href="#__codelineno-20-26"></a> <span class="c1"># Assuming text is in the first part for simplicity</span>
</span><span id="__span-20-27"><a id="__codelineno-20-27" name="__codelineno-20-27" href="#__codelineno-20-27"></a> <span class="k">if</span> <span class="n">content</span><span class="o">.</span><span class="n">parts</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">text</span><span class="p">:</span>
</span><span id="__span-20-28"><a id="__codelineno-20-28" name="__codelineno-20-28" href="#__codelineno-20-28"></a> <span class="n">last_user_message_text</span> <span class="o">=</span> <span class="n">content</span><span class="o">.</span><span class="n">parts</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">text</span>
</span><span id="__span-20-29"><a id="__codelineno-20-29" name="__codelineno-20-29" href="#__codelineno-20-29"></a> <span class="k">break</span> <span class="c1"># Found the last user message text</span>
</span><span id="__span-20-30"><a id="__codelineno-20-30" name="__codelineno-20-30" href="#__codelineno-20-30"></a>
</span><span id="__span-20-31"><a id="__codelineno-20-31" name="__codelineno-20-31" href="#__codelineno-20-31"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"--- Callback: Inspecting last user message: '</span><span class="si">{</span><span class="n">last_user_message_text</span><span class="p">[:</span><span class="mi">100</span><span class="p">]</span><span class="si">}</span><span class="s2">...' ---"</span><span class="p">)</span> <span class="c1"># Log first 100 chars</span>
</span><span id="__span-20-32"><a id="__codelineno-20-32" name="__codelineno-20-32" href="#__codelineno-20-32"></a>
</span><span id="__span-20-33"><a id="__codelineno-20-33" name="__codelineno-20-33" href="#__codelineno-20-33"></a> <span class="c1"># --- Guardrail Logic ---</span>
</span><span id="__span-20-34"><a id="__codelineno-20-34" name="__codelineno-20-34" href="#__codelineno-20-34"></a> <span class="n">keyword_to_block</span> <span class="o">=</span> <span class="s2">"BLOCK"</span>
</span><span id="__span-20-35"><a id="__codelineno-20-35" name="__codelineno-20-35" href="#__codelineno-20-35"></a> <span class="k">if</span> <span class="n">keyword_to_block</span> <span class="ow">in</span> <span class="n">last_user_message_text</span><span class="o">.</span><span class="n">upper</span><span class="p">():</span> <span class="c1"># Case-insensitive check</span>
</span><span id="__span-20-36"><a id="__codelineno-20-36" name="__codelineno-20-36" href="#__codelineno-20-36"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"--- Callback: Found '</span><span class="si">{</span><span class="n">keyword_to_block</span><span class="si">}</span><span class="s2">'. Blocking LLM call! ---"</span><span class="p">)</span>
</span><span id="__span-20-37"><a id="__codelineno-20-37" name="__codelineno-20-37" href="#__codelineno-20-37"></a> <span class="c1"># Optionally, set a flag in state to record the block event</span>
</span><span id="__span-20-38"><a id="__codelineno-20-38" name="__codelineno-20-38" href="#__codelineno-20-38"></a> <span class="n">callback_context</span><span class="o">.</span><span class="n">state</span><span class="p">[</span><span class="s2">"guardrail_block_keyword_triggered"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span>
</span><span id="__span-20-39"><a id="__codelineno-20-39" name="__codelineno-20-39" href="#__codelineno-20-39"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"--- Callback: Set state 'guardrail_block_keyword_triggered': True ---"</span><span class="p">)</span>
</span><span id="__span-20-40"><a id="__codelineno-20-40" name="__codelineno-20-40" href="#__codelineno-20-40"></a>
</span><span id="__span-20-41"><a id="__codelineno-20-41" name="__codelineno-20-41" href="#__codelineno-20-41"></a> <span class="c1"># Construct and return an LlmResponse to stop the flow and send this back instead</span>
</span><span id="__span-20-42"><a id="__codelineno-20-42" name="__codelineno-20-42" href="#__codelineno-20-42"></a> <span class="k">return</span> <span class="n">LlmResponse</span><span class="p">(</span>
</span><span id="__span-20-43"><a id="__codelineno-20-43" name="__codelineno-20-43" href="#__codelineno-20-43"></a> <span class="n">content</span><span class="o">=</span><span class="n">types</span><span class="o">.</span><span class="n">Content</span><span class="p">(</span>
</span><span id="__span-20-44"><a id="__codelineno-20-44" name="__codelineno-20-44" href="#__codelineno-20-44"></a> <span class="n">role</span><span class="o">=</span><span class="s2">"model"</span><span class="p">,</span> <span class="c1"># Mimic a response from the agent's perspective</span>
</span><span id="__span-20-45"><a id="__codelineno-20-45" name="__codelineno-20-45" href="#__codelineno-20-45"></a> <span class="n">parts</span><span class="o">=</span><span class="p">[</span><span class="n">types</span><span class="o">.</span><span class="n">Part</span><span class="p">(</span><span class="n">text</span><span class="o">=</span><span class="sa">f</span><span class="s2">"I cannot process this request because it contains the blocked keyword '</span><span class="si">{</span><span class="n">keyword_to_block</span><span class="si">}</span><span class="s2">'."</span><span class="p">)],</span>
</span><span id="__span-20-46"><a id="__codelineno-20-46" name="__codelineno-20-46" href="#__codelineno-20-46"></a> <span class="p">)</span>
</span><span id="__span-20-47"><a id="__codelineno-20-47" name="__codelineno-20-47" href="#__codelineno-20-47"></a> <span class="c1"># Note: You could also set an error_message field here if needed</span>
</span><span id="__span-20-48"><a id="__codelineno-20-48" name="__codelineno-20-48" href="#__codelineno-20-48"></a> <span class="p">)</span>
</span><span id="__span-20-49"><a id="__codelineno-20-49" name="__codelineno-20-49" href="#__codelineno-20-49"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-20-50"><a id="__codelineno-20-50" name="__codelineno-20-50" href="#__codelineno-20-50"></a> <span class="c1"># Keyword not found, allow the request to proceed to the LLM</span>
</span><span id="__span-20-51"><a id="__codelineno-20-51" name="__codelineno-20-51" href="#__codelineno-20-51"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"--- Callback: Keyword not found. Allowing LLM call for </span><span class="si">{</span><span class="n">agent_name</span><span class="si">}</span><span class="s2">. ---"</span><span class="p">)</span>
</span><span id="__span-20-52"><a id="__codelineno-20-52" name="__codelineno-20-52" href="#__codelineno-20-52"></a> <span class="k">return</span> <span class="kc">None</span> <span class="c1"># Returning None signals ADK to continue normally</span>
</span><span id="__span-20-53"><a id="__codelineno-20-53" name="__codelineno-20-53" href="#__codelineno-20-53"></a>
</span><span id="__span-20-54"><a id="__codelineno-20-54" name="__codelineno-20-54" href="#__codelineno-20-54"></a><span class="nb">print</span><span class="p">(</span><span class="s2">"✅ block_keyword_guardrail function defined."</span><span class="p">)</span>
</span></code></pre></div>
<hr />
<p><strong>2. Update Root Agent to Use the Callback</strong></p>
<p>We redefine the root agent, adding the <code>before_model_callback</code> parameter and pointing it to our new guardrail function. We'll give it a new version name for clarity.</p>
<p><em>Important:</em> We need to redefine the sub-agents (<code>greeting_agent</code>, <code>farewell_agent</code>) and the stateful tool (<code>get_weather_stateful</code>) within this context if they are not already available from previous steps, ensuring the root agent definition has access to all its components.</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-21-1"><a id="__codelineno-21-1" name="__codelineno-21-1" href="#__codelineno-21-1"></a><span class="c1"># @title 2. Update Root Agent with before_model_callback</span>
</span><span id="__span-21-2"><a id="__codelineno-21-2" name="__codelineno-21-2" href="#__codelineno-21-2"></a>
</span><span id="__span-21-3"><a id="__codelineno-21-3" name="__codelineno-21-3" href="#__codelineno-21-3"></a>
</span><span id="__span-21-4"><a id="__codelineno-21-4" name="__codelineno-21-4" href="#__codelineno-21-4"></a><span class="c1"># --- Redefine Sub-Agents (Ensures they exist in this context) ---</span>
</span><span id="__span-21-5"><a id="__codelineno-21-5" name="__codelineno-21-5" href="#__codelineno-21-5"></a><span class="n">greeting_agent</span> <span class="o">=</span> <span class="kc">None</span>
</span><span id="__span-21-6"><a id="__codelineno-21-6" name="__codelineno-21-6" href="#__codelineno-21-6"></a><span class="k">try</span><span class="p">:</span>
</span><span id="__span-21-7"><a id="__codelineno-21-7" name="__codelineno-21-7" href="#__codelineno-21-7"></a> <span class="c1"># Use a defined model constant</span>
</span><span id="__span-21-8"><a id="__codelineno-21-8" name="__codelineno-21-8" href="#__codelineno-21-8"></a> <span class="n">greeting_agent</span> <span class="o">=</span> <span class="n">Agent</span><span class="p">(</span>
</span><span id="__span-21-9"><a id="__codelineno-21-9" name="__codelineno-21-9" href="#__codelineno-21-9"></a> <span class="n">model</span><span class="o">=</span><span class="n">MODEL_GEMINI_FLASH</span><span class="p">,</span>
</span><span id="__span-21-10"><a id="__codelineno-21-10" name="__codelineno-21-10" href="#__codelineno-21-10"></a> <span class="n">name</span><span class="o">=</span><span class="s2">"greeting_agent"</span><span class="p">,</span> <span class="c1"># Keep original name for consistency</span>
</span><span id="__span-21-11"><a id="__codelineno-21-11" name="__codelineno-21-11" href="#__codelineno-21-11"></a> <span class="n">instruction</span><span class="o">=</span><span class="s2">"You are the Greeting Agent. Your ONLY task is to provide a friendly greeting using the 'say_hello' tool. Do nothing else."</span><span class="p">,</span>
</span><span id="__span-21-12"><a id="__codelineno-21-12" name="__codelineno-21-12" href="#__codelineno-21-12"></a> <span class="n">description</span><span class="o">=</span><span class="s2">"Handles simple greetings and hellos using the 'say_hello' tool."</span><span class="p">,</span>
</span><span id="__span-21-13"><a id="__codelineno-21-13" name="__codelineno-21-13" href="#__codelineno-21-13"></a> <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">say_hello</span><span class="p">],</span>
</span><span id="__span-21-14"><a id="__codelineno-21-14" name="__codelineno-21-14" href="#__codelineno-21-14"></a> <span class="p">)</span>
</span><span id="__span-21-15"><a id="__codelineno-21-15" name="__codelineno-21-15" href="#__codelineno-21-15"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"✅ Sub-Agent '</span><span class="si">{</span><span class="n">greeting_agent</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">' redefined."</span><span class="p">)</span>
</span><span id="__span-21-16"><a id="__codelineno-21-16" name="__codelineno-21-16" href="#__codelineno-21-16"></a><span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span><span id="__span-21-17"><a id="__codelineno-21-17" name="__codelineno-21-17" href="#__codelineno-21-17"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"❌ Could not redefine Greeting agent. Check Model/API Key (</span><span class="si">{</span><span class="n">greeting_agent</span><span class="o">.</span><span class="n">model</span><span class="si">}</span><span class="s2">). Error: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span><span id="__span-21-18"><a id="__codelineno-21-18" name="__codelineno-21-18" href="#__codelineno-21-18"></a>
</span><span id="__span-21-19"><a id="__codelineno-21-19" name="__codelineno-21-19" href="#__codelineno-21-19"></a><span class="n">farewell_agent</span> <span class="o">=</span> <span class="kc">None</span>
</span><span id="__span-21-20"><a id="__codelineno-21-20" name="__codelineno-21-20" href="#__codelineno-21-20"></a><span class="k">try</span><span class="p">:</span>
</span><span id="__span-21-21"><a id="__codelineno-21-21" name="__codelineno-21-21" href="#__codelineno-21-21"></a> <span class="c1"># Use a defined model constant</span>
</span><span id="__span-21-22"><a id="__codelineno-21-22" name="__codelineno-21-22" href="#__codelineno-21-22"></a> <span class="n">farewell_agent</span> <span class="o">=</span> <span class="n">Agent</span><span class="p">(</span>
</span><span id="__span-21-23"><a id="__codelineno-21-23" name="__codelineno-21-23" href="#__codelineno-21-23"></a> <span class="n">model</span><span class="o">=</span><span class="n">MODEL_GEMINI_FLASH</span><span class="p">,</span>
</span><span id="__span-21-24"><a id="__codelineno-21-24" name="__codelineno-21-24" href="#__codelineno-21-24"></a> <span class="n">name</span><span class="o">=</span><span class="s2">"farewell_agent"</span><span class="p">,</span> <span class="c1"># Keep original name</span>
</span><span id="__span-21-25"><a id="__codelineno-21-25" name="__codelineno-21-25" href="#__codelineno-21-25"></a> <span class="n">instruction</span><span class="o">=</span><span class="s2">"You are the Farewell Agent. Your ONLY task is to provide a polite goodbye message using the 'say_goodbye' tool. Do not perform any other actions."</span><span class="p">,</span>
</span><span id="__span-21-26"><a id="__codelineno-21-26" name="__codelineno-21-26" href="#__codelineno-21-26"></a> <span class="n">description</span><span class="o">=</span><span class="s2">"Handles simple farewells and goodbyes using the 'say_goodbye' tool."</span><span class="p">,</span>
</span><span id="__span-21-27"><a id="__codelineno-21-27" name="__codelineno-21-27" href="#__codelineno-21-27"></a> <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">say_goodbye</span><span class="p">],</span>
</span><span id="__span-21-28"><a id="__codelineno-21-28" name="__codelineno-21-28" href="#__codelineno-21-28"></a> <span class="p">)</span>
</span><span id="__span-21-29"><a id="__codelineno-21-29" name="__codelineno-21-29" href="#__codelineno-21-29"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"✅ Sub-Agent '</span><span class="si">{</span><span class="n">farewell_agent</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">' redefined."</span><span class="p">)</span>
</span><span id="__span-21-30"><a id="__codelineno-21-30" name="__codelineno-21-30" href="#__codelineno-21-30"></a><span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span><span id="__span-21-31"><a id="__codelineno-21-31" name="__codelineno-21-31" href="#__codelineno-21-31"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"❌ Could not redefine Farewell agent. Check Model/API Key (</span><span class="si">{</span><span class="n">farewell_agent</span><span class="o">.</span><span class="n">model</span><span class="si">}</span><span class="s2">). Error: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span><span id="__span-21-32"><a id="__codelineno-21-32" name="__codelineno-21-32" href="#__codelineno-21-32"></a>
</span><span id="__span-21-33"><a id="__codelineno-21-33" name="__codelineno-21-33" href="#__codelineno-21-33"></a>
</span><span id="__span-21-34"><a id="__codelineno-21-34" name="__codelineno-21-34" href="#__codelineno-21-34"></a><span class="c1"># --- Define the Root Agent with the Callback ---</span>
</span><span id="__span-21-35"><a id="__codelineno-21-35" name="__codelineno-21-35" href="#__codelineno-21-35"></a><span class="n">root_agent_model_guardrail</span> <span class="o">=</span> <span class="kc">None</span>
</span><span id="__span-21-36"><a id="__codelineno-21-36" name="__codelineno-21-36" href="#__codelineno-21-36"></a><span class="n">runner_root_model_guardrail</span> <span class="o">=</span> <span class="kc">None</span>
</span><span id="__span-21-37"><a id="__codelineno-21-37" name="__codelineno-21-37" href="#__codelineno-21-37"></a>
</span><span id="__span-21-38"><a id="__codelineno-21-38" name="__codelineno-21-38" href="#__codelineno-21-38"></a><span class="c1"># Check all components before proceeding</span>
</span><span id="__span-21-39"><a id="__codelineno-21-39" name="__codelineno-21-39" href="#__codelineno-21-39"></a><span class="k">if</span> <span class="n">greeting_agent</span> <span class="ow">and</span> <span class="n">farewell_agent</span> <span class="ow">and</span> <span class="s1">'get_weather_stateful'</span> <span class="ow">in</span> <span class="nb">globals</span><span class="p">()</span> <span class="ow">and</span> <span class="s1">'block_keyword_guardrail'</span> <span class="ow">in</span> <span class="nb">globals</span><span class="p">():</span>
</span><span id="__span-21-40"><a id="__codelineno-21-40" name="__codelineno-21-40" href="#__codelineno-21-40"></a>
</span><span id="__span-21-41"><a id="__codelineno-21-41" name="__codelineno-21-41" href="#__codelineno-21-41"></a> <span class="c1"># Use a defined model constant</span>
</span><span id="__span-21-42"><a id="__codelineno-21-42" name="__codelineno-21-42" href="#__codelineno-21-42"></a> <span class="n">root_agent_model</span> <span class="o">=</span> <span class="n">MODEL_GEMINI_FLASH</span>
</span><span id="__span-21-43"><a id="__codelineno-21-43" name="__codelineno-21-43" href="#__codelineno-21-43"></a>
</span><span id="__span-21-44"><a id="__codelineno-21-44" name="__codelineno-21-44" href="#__codelineno-21-44"></a> <span class="n">root_agent_model_guardrail</span> <span class="o">=</span> <span class="n">Agent</span><span class="p">(</span>
</span><span id="__span-21-45"><a id="__codelineno-21-45" name="__codelineno-21-45" href="#__codelineno-21-45"></a> <span class="n">name</span><span class="o">=</span><span class="s2">"weather_agent_v5_model_guardrail"</span><span class="p">,</span> <span class="c1"># New version name for clarity</span>
</span><span id="__span-21-46"><a id="__codelineno-21-46" name="__codelineno-21-46" href="#__codelineno-21-46"></a> <span class="n">model</span><span class="o">=</span><span class="n">root_agent_model</span><span class="p">,</span>
</span><span id="__span-21-47"><a id="__codelineno-21-47" name="__codelineno-21-47" href="#__codelineno-21-47"></a> <span class="n">description</span><span class="o">=</span><span class="s2">"Main agent: Handles weather, delegates greetings/farewells, includes input keyword guardrail."</span><span class="p">,</span>
</span><span id="__span-21-48"><a id="__codelineno-21-48" name="__codelineno-21-48" href="#__codelineno-21-48"></a> <span class="n">instruction</span><span class="o">=</span><span class="s2">"You are the main Weather Agent. Provide weather using 'get_weather_stateful'. "</span>
</span><span id="__span-21-49"><a id="__codelineno-21-49" name="__codelineno-21-49" href="#__codelineno-21-49"></a> <span class="s2">"Delegate simple greetings to 'greeting_agent' and farewells to 'farewell_agent'. "</span>
</span><span id="__span-21-50"><a id="__codelineno-21-50" name="__codelineno-21-50" href="#__codelineno-21-50"></a> <span class="s2">"Handle only weather requests, greetings, and farewells."</span><span class="p">,</span>
</span><span id="__span-21-51"><a id="__codelineno-21-51" name="__codelineno-21-51" href="#__codelineno-21-51"></a> <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">get_weather_stateful</span><span class="p">],</span>
</span><span id="__span-21-52"><a id="__codelineno-21-52" name="__codelineno-21-52" href="#__codelineno-21-52"></a> <span class="n">sub_agents</span><span class="o">=</span><span class="p">[</span><span class="n">greeting_agent</span><span class="p">,</span> <span class="n">farewell_agent</span><span class="p">],</span> <span class="c1"># Reference the redefined sub-agents</span>
</span><span id="__span-21-53"><a id="__codelineno-21-53" name="__codelineno-21-53" href="#__codelineno-21-53"></a> <span class="n">output_key</span><span class="o">=</span><span class="s2">"last_weather_report"</span><span class="p">,</span> <span class="c1"># Keep output_key from Step 4</span>
</span><span id="__span-21-54"><a id="__codelineno-21-54" name="__codelineno-21-54" href="#__codelineno-21-54"></a> <span class="n">before_model_callback</span><span class="o">=</span><span class="n">block_keyword_guardrail</span> <span class="c1"># &lt;&lt;&lt; Assign the guardrail callback</span>
</span><span id="__span-21-55"><a id="__codelineno-21-55" name="__codelineno-21-55" href="#__codelineno-21-55"></a> <span class="p">)</span>
</span><span id="__span-21-56"><a id="__codelineno-21-56" name="__codelineno-21-56" href="#__codelineno-21-56"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"✅ Root Agent '</span><span class="si">{</span><span class="n">root_agent_model_guardrail</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">' created with before_model_callback."</span><span class="p">)</span>
</span><span id="__span-21-57"><a id="__codelineno-21-57" name="__codelineno-21-57" href="#__codelineno-21-57"></a>
</span><span id="__span-21-58"><a id="__codelineno-21-58" name="__codelineno-21-58" href="#__codelineno-21-58"></a> <span class="c1"># --- Create Runner for this Agent, Using SAME Stateful Session Service ---</span>
</span><span id="__span-21-59"><a id="__codelineno-21-59" name="__codelineno-21-59" href="#__codelineno-21-59"></a> <span class="c1"># Ensure session_service_stateful exists from Step 4</span>
</span><span id="__span-21-60"><a id="__codelineno-21-60" name="__codelineno-21-60" href="#__codelineno-21-60"></a> <span class="k">if</span> <span class="s1">'session_service_stateful'</span> <span class="ow">in</span> <span class="nb">globals</span><span class="p">():</span>
</span><span id="__span-21-61"><a id="__codelineno-21-61" name="__codelineno-21-61" href="#__codelineno-21-61"></a> <span class="n">runner_root_model_guardrail</span> <span class="o">=</span> <span class="n">Runner</span><span class="p">(</span>
</span><span id="__span-21-62"><a id="__codelineno-21-62" name="__codelineno-21-62" href="#__codelineno-21-62"></a> <span class="n">agent</span><span class="o">=</span><span class="n">root_agent_model_guardrail</span><span class="p">,</span>
</span><span id="__span-21-63"><a id="__codelineno-21-63" name="__codelineno-21-63" href="#__codelineno-21-63"></a> <span class="n">app_name</span><span class="o">=</span><span class="n">APP_NAME</span><span class="p">,</span> <span class="c1"># Use consistent APP_NAME</span>
</span><span id="__span-21-64"><a id="__codelineno-21-64" name="__codelineno-21-64" href="#__codelineno-21-64"></a> <span class="n">session_service</span><span class="o">=</span><span class="n">session_service_stateful</span> <span class="c1"># &lt;&lt;&lt; Use the service from Step 4</span>
</span><span id="__span-21-65"><a id="__codelineno-21-65" name="__codelineno-21-65" href="#__codelineno-21-65"></a> <span class="p">)</span>
</span><span id="__span-21-66"><a id="__codelineno-21-66" name="__codelineno-21-66" href="#__codelineno-21-66"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"✅ Runner created for guardrail agent '</span><span class="si">{</span><span class="n">runner_root_model_guardrail</span><span class="o">.</span><span class="n">agent</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">', using stateful session service."</span><span class="p">)</span>
</span><span id="__span-21-67"><a id="__codelineno-21-67" name="__codelineno-21-67" href="#__codelineno-21-67"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-21-68"><a id="__codelineno-21-68" name="__codelineno-21-68" href="#__codelineno-21-68"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"❌ Cannot create runner. 'session_service_stateful' from Step 4 is missing."</span><span class="p">)</span>
</span><span id="__span-21-69"><a id="__codelineno-21-69" name="__codelineno-21-69" href="#__codelineno-21-69"></a>
</span><span id="__span-21-70"><a id="__codelineno-21-70" name="__codelineno-21-70" href="#__codelineno-21-70"></a><span class="k">else</span><span class="p">:</span>
</span><span id="__span-21-71"><a id="__codelineno-21-71" name="__codelineno-21-71" href="#__codelineno-21-71"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"❌ Cannot create root agent with model guardrail. One or more prerequisites are missing or failed initialization:"</span><span class="p">)</span>
</span><span id="__span-21-72"><a id="__codelineno-21-72" name="__codelineno-21-72" href="#__codelineno-21-72"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">greeting_agent</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="s2">" - Greeting Agent"</span><span class="p">)</span>
</span><span id="__span-21-73"><a id="__codelineno-21-73" name="__codelineno-21-73" href="#__codelineno-21-73"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">farewell_agent</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="s2">" - Farewell Agent"</span><span class="p">)</span>
</span><span id="__span-21-74"><a id="__codelineno-21-74" name="__codelineno-21-74" href="#__codelineno-21-74"></a> <span class="k">if</span> <span class="s1">'get_weather_stateful'</span> <span class="ow">not</span> <span class="ow">in</span> <span class="nb">globals</span><span class="p">():</span> <span class="nb">print</span><span class="p">(</span><span class="s2">" - 'get_weather_stateful' tool"</span><span class="p">)</span>
</span><span id="__span-21-75"><a id="__codelineno-21-75" name="__codelineno-21-75" href="#__codelineno-21-75"></a> <span class="k">if</span> <span class="s1">'block_keyword_guardrail'</span> <span class="ow">not</span> <span class="ow">in</span> <span class="nb">globals</span><span class="p">():</span> <span class="nb">print</span><span class="p">(</span><span class="s2">" - 'block_keyword_guardrail' callback"</span><span class="p">)</span>
</span></code></pre></div>
<hr />
<p><strong>3. Interact to Test the Guardrail</strong></p>
<p>Let's test the guardrail's behavior. We'll use the <em>same session</em> (<code>SESSION_ID_STATEFUL</code>) as in Step 4 to show that state persists across these changes.</p>
<ol>
<li>Send a normal weather request (should pass the guardrail and execute).</li>
<li>Send a request containing "BLOCK" (should be intercepted by the callback).</li>
<li>Send a greeting (should pass the root agent's guardrail, be delegated, and execute normally).</li>
</ol>
<div class="language-python highlight"><pre><span></span><code><span id="__span-22-1"><a id="__codelineno-22-1" name="__codelineno-22-1" href="#__codelineno-22-1"></a><span class="c1"># @title 3. Interact to Test the Model Input Guardrail</span>
</span><span id="__span-22-2"><a id="__codelineno-22-2" name="__codelineno-22-2" href="#__codelineno-22-2"></a><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span> <span class="c1"># Ensure asyncio is imported</span>
</span><span id="__span-22-3"><a id="__codelineno-22-3" name="__codelineno-22-3" href="#__codelineno-22-3"></a>
</span><span id="__span-22-4"><a id="__codelineno-22-4" name="__codelineno-22-4" href="#__codelineno-22-4"></a><span class="c1"># Ensure the runner for the guardrail agent is available</span>
</span><span id="__span-22-5"><a id="__codelineno-22-5" name="__codelineno-22-5" href="#__codelineno-22-5"></a><span class="k">if</span> <span class="s1">'runner_root_model_guardrail'</span> <span class="ow">in</span> <span class="nb">globals</span><span class="p">()</span> <span class="ow">and</span> <span class="n">runner_root_model_guardrail</span><span class="p">:</span>
</span><span id="__span-22-6"><a id="__codelineno-22-6" name="__codelineno-22-6" href="#__codelineno-22-6"></a> <span class="c1"># Define the main async function for the guardrail test conversation.</span>
</span><span id="__span-22-7"><a id="__codelineno-22-7" name="__codelineno-22-7" href="#__codelineno-22-7"></a> <span class="c1"># The 'await' keywords INSIDE this function are necessary for async operations.</span>
</span><span id="__span-22-8"><a id="__codelineno-22-8" name="__codelineno-22-8" href="#__codelineno-22-8"></a> <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run_guardrail_test_conversation</span><span class="p">():</span>
</span><span id="__span-22-9"><a id="__codelineno-22-9" name="__codelineno-22-9" href="#__codelineno-22-9"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">--- Testing Model Input Guardrail ---"</span><span class="p">)</span>
</span><span id="__span-22-10"><a id="__codelineno-22-10" name="__codelineno-22-10" href="#__codelineno-22-10"></a>
</span><span id="__span-22-11"><a id="__codelineno-22-11" name="__codelineno-22-11" href="#__codelineno-22-11"></a> <span class="c1"># Use the runner for the agent with the callback and the existing stateful session ID</span>
</span><span id="__span-22-12"><a id="__codelineno-22-12" name="__codelineno-22-12" href="#__codelineno-22-12"></a> <span class="c1"># Define a helper lambda for cleaner interaction calls</span>
</span><span id="__span-22-13"><a id="__codelineno-22-13" name="__codelineno-22-13" href="#__codelineno-22-13"></a> <span class="n">interaction_func</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">query</span><span class="p">:</span> <span class="n">call_agent_async</span><span class="p">(</span><span class="n">query</span><span class="p">,</span>
</span><span id="__span-22-14"><a id="__codelineno-22-14" name="__codelineno-22-14" href="#__codelineno-22-14"></a> <span class="n">runner_root_model_guardrail</span><span class="p">,</span>
</span><span id="__span-22-15"><a id="__codelineno-22-15" name="__codelineno-22-15" href="#__codelineno-22-15"></a> <span class="n">USER_ID_STATEFUL</span><span class="p">,</span> <span class="c1"># Use existing user ID</span>
</span><span id="__span-22-16"><a id="__codelineno-22-16" name="__codelineno-22-16" href="#__codelineno-22-16"></a> <span class="n">SESSION_ID_STATEFUL</span> <span class="c1"># Use existing session ID</span>
</span><span id="__span-22-17"><a id="__codelineno-22-17" name="__codelineno-22-17" href="#__codelineno-22-17"></a> <span class="p">)</span>
</span><span id="__span-22-18"><a id="__codelineno-22-18" name="__codelineno-22-18" href="#__codelineno-22-18"></a> <span class="c1"># 1. Normal request (Callback allows, should use Fahrenheit from previous state change)</span>
</span><span id="__span-22-19"><a id="__codelineno-22-19" name="__codelineno-22-19" href="#__codelineno-22-19"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"--- Turn 1: Requesting weather in London (expect allowed, Fahrenheit) ---"</span><span class="p">)</span>
</span><span id="__span-22-20"><a id="__codelineno-22-20" name="__codelineno-22-20" href="#__codelineno-22-20"></a> <span class="k">await</span> <span class="n">interaction_func</span><span class="p">(</span><span class="s2">"What is the weather in London?"</span><span class="p">)</span>
</span><span id="__span-22-21"><a id="__codelineno-22-21" name="__codelineno-22-21" href="#__codelineno-22-21"></a>
</span><span id="__span-22-22"><a id="__codelineno-22-22" name="__codelineno-22-22" href="#__codelineno-22-22"></a> <span class="c1"># 2. Request containing the blocked keyword (Callback intercepts)</span>
</span><span id="__span-22-23"><a id="__codelineno-22-23" name="__codelineno-22-23" href="#__codelineno-22-23"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">--- Turn 2: Requesting with blocked keyword (expect blocked) ---"</span><span class="p">)</span>
</span><span id="__span-22-24"><a id="__codelineno-22-24" name="__codelineno-22-24" href="#__codelineno-22-24"></a> <span class="k">await</span> <span class="n">interaction_func</span><span class="p">(</span><span class="s2">"BLOCK the request for weather in Tokyo"</span><span class="p">)</span> <span class="c1"># Callback should catch "BLOCK"</span>
</span><span id="__span-22-25"><a id="__codelineno-22-25" name="__codelineno-22-25" href="#__codelineno-22-25"></a>
</span><span id="__span-22-26"><a id="__codelineno-22-26" name="__codelineno-22-26" href="#__codelineno-22-26"></a> <span class="c1"># 3. Normal greeting (Callback allows root agent, delegation happens)</span>
</span><span id="__span-22-27"><a id="__codelineno-22-27" name="__codelineno-22-27" href="#__codelineno-22-27"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">--- Turn 3: Sending a greeting (expect allowed) ---"</span><span class="p">)</span>
</span><span id="__span-22-28"><a id="__codelineno-22-28" name="__codelineno-22-28" href="#__codelineno-22-28"></a> <span class="k">await</span> <span class="n">interaction_func</span><span class="p">(</span><span class="s2">"Hello again"</span><span class="p">)</span>
</span><span id="__span-22-29"><a id="__codelineno-22-29" name="__codelineno-22-29" href="#__codelineno-22-29"></a>
</span><span id="__span-22-30"><a id="__codelineno-22-30" name="__codelineno-22-30" href="#__codelineno-22-30"></a> <span class="c1"># --- Execute the `run_guardrail_test_conversation` async function ---</span>
</span><span id="__span-22-31"><a id="__codelineno-22-31" name="__codelineno-22-31" href="#__codelineno-22-31"></a> <span class="c1"># Choose ONE of the methods below based on your environment.</span>
</span><span id="__span-22-32"><a id="__codelineno-22-32" name="__codelineno-22-32" href="#__codelineno-22-32"></a>
</span><span id="__span-22-33"><a id="__codelineno-22-33" name="__codelineno-22-33" href="#__codelineno-22-33"></a> <span class="c1"># METHOD 1: Direct await (Default for Notebooks/Async REPLs)</span>
</span><span id="__span-22-34"><a id="__codelineno-22-34" name="__codelineno-22-34" href="#__codelineno-22-34"></a> <span class="c1"># If your environment supports top-level await (like Colab/Jupyter notebooks),</span>
</span><span id="__span-22-35"><a id="__codelineno-22-35" name="__codelineno-22-35" href="#__codelineno-22-35"></a> <span class="c1"># it means an event loop is already running, so you can directly await the function.</span>
</span><span id="__span-22-36"><a id="__codelineno-22-36" name="__codelineno-22-36" href="#__codelineno-22-36"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"Attempting execution using 'await' (default for notebooks)..."</span><span class="p">)</span>
</span><span id="__span-22-37"><a id="__codelineno-22-37" name="__codelineno-22-37" href="#__codelineno-22-37"></a> <span class="k">await</span> <span class="n">run_guardrail_test_conversation</span><span class="p">()</span>
</span><span id="__span-22-38"><a id="__codelineno-22-38" name="__codelineno-22-38" href="#__codelineno-22-38"></a>
</span><span id="__span-22-39"><a id="__codelineno-22-39" name="__codelineno-22-39" href="#__codelineno-22-39"></a> <span class="c1"># METHOD 2: asyncio.run (For Standard Python Scripts [.py])</span>
</span><span id="__span-22-40"><a id="__codelineno-22-40" name="__codelineno-22-40" href="#__codelineno-22-40"></a> <span class="c1"># If running this code as a standard Python script from your terminal,</span>
</span><span id="__span-22-41"><a id="__codelineno-22-41" name="__codelineno-22-41" href="#__codelineno-22-41"></a> <span class="c1"># the script context is synchronous. `asyncio.run()` is needed to</span>
</span><span id="__span-22-42"><a id="__codelineno-22-42" name="__codelineno-22-42" href="#__codelineno-22-42"></a> <span class="c1"># create and manage an event loop to execute your async function.</span>
</span><span id="__span-22-43"><a id="__codelineno-22-43" name="__codelineno-22-43" href="#__codelineno-22-43"></a> <span class="c1"># To use this method:</span>
</span><span id="__span-22-44"><a id="__codelineno-22-44" name="__codelineno-22-44" href="#__codelineno-22-44"></a> <span class="c1"># 1. Comment out the `await run_guardrail_test_conversation()` line above.</span>
</span><span id="__span-22-45"><a id="__codelineno-22-45" name="__codelineno-22-45" href="#__codelineno-22-45"></a> <span class="c1"># 2. Uncomment the following block:</span>
</span><span id="__span-22-46"><a id="__codelineno-22-46" name="__codelineno-22-46" href="#__codelineno-22-46"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-22-47"><a id="__codelineno-22-47" name="__codelineno-22-47" href="#__codelineno-22-47"></a><span class="sd"> import asyncio</span>
</span><span id="__span-22-48"><a id="__codelineno-22-48" name="__codelineno-22-48" href="#__codelineno-22-48"></a><span class="sd"> if __name__ == "__main__": # Ensures this runs only when script is executed directly</span>
</span><span id="__span-22-49"><a id="__codelineno-22-49" name="__codelineno-22-49" href="#__codelineno-22-49"></a><span class="sd"> print("Executing using 'asyncio.run()' (for standard Python scripts)...")</span>
</span><span id="__span-22-50"><a id="__codelineno-22-50" name="__codelineno-22-50" href="#__codelineno-22-50"></a><span class="sd"> try:</span>
</span><span id="__span-22-51"><a id="__codelineno-22-51" name="__codelineno-22-51" href="#__codelineno-22-51"></a><span class="sd"> # This creates an event loop, runs your async function, and closes the loop.</span>
</span><span id="__span-22-52"><a id="__codelineno-22-52" name="__codelineno-22-52" href="#__codelineno-22-52"></a><span class="sd"> asyncio.run(run_guardrail_test_conversation())</span>
</span><span id="__span-22-53"><a id="__codelineno-22-53" name="__codelineno-22-53" href="#__codelineno-22-53"></a><span class="sd"> except Exception as e:</span>
</span><span id="__span-22-54"><a id="__codelineno-22-54" name="__codelineno-22-54" href="#__codelineno-22-54"></a><span class="sd"> print(f"An error occurred: {e}")</span>
</span><span id="__span-22-55"><a id="__codelineno-22-55" name="__codelineno-22-55" href="#__codelineno-22-55"></a><span class="sd"> """</span>
</span><span id="__span-22-56"><a id="__codelineno-22-56" name="__codelineno-22-56" href="#__codelineno-22-56"></a>
</span><span id="__span-22-57"><a id="__codelineno-22-57" name="__codelineno-22-57" href="#__codelineno-22-57"></a> <span class="c1"># --- Inspect final session state after the conversation ---</span>
</span><span id="__span-22-58"><a id="__codelineno-22-58" name="__codelineno-22-58" href="#__codelineno-22-58"></a> <span class="c1"># This block runs after either execution method completes.</span>
</span><span id="__span-22-59"><a id="__codelineno-22-59" name="__codelineno-22-59" href="#__codelineno-22-59"></a> <span class="c1"># Optional: Check state for the trigger flag set by the callback</span>
</span><span id="__span-22-60"><a id="__codelineno-22-60" name="__codelineno-22-60" href="#__codelineno-22-60"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">--- Inspecting Final Session State (After Guardrail Test) ---"</span><span class="p">)</span>
</span><span id="__span-22-61"><a id="__codelineno-22-61" name="__codelineno-22-61" href="#__codelineno-22-61"></a> <span class="c1"># Use the session service instance associated with this stateful session</span>
</span><span id="__span-22-62"><a id="__codelineno-22-62" name="__codelineno-22-62" href="#__codelineno-22-62"></a> <span class="n">final_session</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session_service_stateful</span><span class="o">.</span><span class="n">get_session</span><span class="p">(</span><span class="n">app_name</span><span class="o">=</span><span class="n">APP_NAME</span><span class="p">,</span>
</span><span id="__span-22-63"><a id="__codelineno-22-63" name="__codelineno-22-63" href="#__codelineno-22-63"></a> <span class="n">user_id</span><span class="o">=</span><span class="n">USER_ID_STATEFUL</span><span class="p">,</span>
</span><span id="__span-22-64"><a id="__codelineno-22-64" name="__codelineno-22-64" href="#__codelineno-22-64"></a> <span class="n">session_id</span><span class="o">=</span><span class="n">SESSION_ID_STATEFUL</span><span class="p">)</span>
</span><span id="__span-22-65"><a id="__codelineno-22-65" name="__codelineno-22-65" href="#__codelineno-22-65"></a> <span class="k">if</span> <span class="n">final_session</span><span class="p">:</span>
</span><span id="__span-22-66"><a id="__codelineno-22-66" name="__codelineno-22-66" href="#__codelineno-22-66"></a> <span class="c1"># Use .get() for safer access</span>
</span><span id="__span-22-67"><a id="__codelineno-22-67" name="__codelineno-22-67" href="#__codelineno-22-67"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Guardrail Triggered Flag: </span><span class="si">{</span><span class="n">final_session</span><span class="o">.</span><span class="n">state</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'guardrail_block_keyword_triggered'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Not Set (or False)'</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span><span id="__span-22-68"><a id="__codelineno-22-68" name="__codelineno-22-68" href="#__codelineno-22-68"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Last Weather Report: </span><span class="si">{</span><span class="n">final_session</span><span class="o">.</span><span class="n">state</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'last_weather_report'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Not Set'</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> <span class="c1"># Should be London weather if successful</span>
</span><span id="__span-22-69"><a id="__codelineno-22-69" name="__codelineno-22-69" href="#__codelineno-22-69"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Temperature Unit: </span><span class="si">{</span><span class="n">final_session</span><span class="o">.</span><span class="n">state</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'user_preference_temperature_unit'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Not Set'</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> <span class="c1"># Should be Fahrenheit</span>
</span><span id="__span-22-70"><a id="__codelineno-22-70" name="__codelineno-22-70" href="#__codelineno-22-70"></a> <span class="c1"># print(f"Full State Dict: {final_session.state}") # For detailed view</span>
</span><span id="__span-22-71"><a id="__codelineno-22-71" name="__codelineno-22-71" href="#__codelineno-22-71"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-22-72"><a id="__codelineno-22-72" name="__codelineno-22-72" href="#__codelineno-22-72"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">❌ Error: Could not retrieve final session state."</span><span class="p">)</span>
</span><span id="__span-22-73"><a id="__codelineno-22-73" name="__codelineno-22-73" href="#__codelineno-22-73"></a>
</span><span id="__span-22-74"><a id="__codelineno-22-74" name="__codelineno-22-74" href="#__codelineno-22-74"></a><span class="k">else</span><span class="p">:</span>
</span><span id="__span-22-75"><a id="__codelineno-22-75" name="__codelineno-22-75" href="#__codelineno-22-75"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">⚠️ Skipping model guardrail test. Runner ('runner_root_model_guardrail') is not available."</span><span class="p">)</span>
</span></code></pre></div>
<hr />
<p>Observe the execution flow:</p>
<ol>
<li><strong>London Weather:</strong> The callback runs for <code>weather_agent_v5_model_guardrail</code>, inspects the message, prints "Keyword not found. Allowing LLM call.", and returns <code>None</code>. The agent proceeds, calls the <code>get_weather_stateful</code> tool (which uses the "Fahrenheit" preference from Step 4's state change), and returns the weather. This response updates <code>last_weather_report</code> via <code>output_key</code>.</li>
<li><strong>BLOCK Request:</strong> The callback runs again for <code>weather_agent_v5_model_guardrail</code>, inspects the message, finds "BLOCK", prints "Blocking LLM call!", sets the state flag, and returns the predefined <code>LlmResponse</code>. The agent's underlying LLM is <em>never called</em> for this turn. The user sees the callback's blocking message.</li>
<li><strong>Hello Again:</strong> The callback runs for <code>weather_agent_v5_model_guardrail</code>, allows the request. The root agent then delegates to <code>greeting_agent</code>. <em>Note: The <code>before_model_callback</code> defined on the root agent does NOT automatically apply to sub-agents.</em> The <code>greeting_agent</code> proceeds normally, calls its <code>say_hello</code> tool, and returns the greeting.</li>
</ol>
<p>You have successfully implemented an input safety layer! The <code>before_model_callback</code> provides a powerful mechanism to enforce rules and control agent behavior <em>before</em> expensive or potentially risky LLM calls are made. Next, we'll apply a similar concept to add guardrails around tool usage itself.</p>
<h2 id="step-6-adding-safety-tool-argument-guardrail-before_tool_callback">Step 6: Adding Safety - Tool Argument Guardrail (<code>before_tool_callback</code>)<a class="headerlink" href="#step-6-adding-safety-tool-argument-guardrail-before_tool_callback" title="Permanent link">&para;</a></h2>
<p>In Step 5, we added a guardrail to inspect and potentially block user input <em>before</em> it reached the LLM. Now, we'll add another layer of control <em>after</em> the LLM has decided to use a tool but <em>before</em> that tool actually executes. This is useful for validating the <em>arguments</em> the LLM wants to pass to the tool.</p>
<p>ADK provides the <code>before_tool_callback</code> for this precise purpose.</p>
<p><strong>What is <code>before_tool_callback</code>?</strong></p>
<ul>
<li>It's a Python function executed just <em>before</em> a specific tool function runs, after the LLM has requested its use and decided on the arguments.</li>
<li><strong>Purpose:</strong> Validate tool arguments, prevent tool execution based on specific inputs, modify arguments dynamically, or enforce resource usage policies.</li>
</ul>
<p><strong>Common Use Cases:</strong></p>
<ul>
<li><strong>Argument Validation:</strong> Check if arguments provided by the LLM are valid, within allowed ranges, or conform to expected formats.</li>
<li><strong>Resource Protection:</strong> Prevent tools from being called with inputs that might be costly, access restricted data, or cause unwanted side effects (e.g., blocking API calls for certain parameters).</li>
<li><strong>Dynamic Argument Modification:</strong> Adjust arguments based on session state or other contextual information before the tool runs.</li>
</ul>
<p><strong>How it Works:</strong></p>
<ol>
<li>
<p>Define a function accepting <code>tool: BaseTool</code>, <code>args: Dict[str, Any]</code>, and <code>tool_context: ToolContext</code>.</p>
<ul>
<li><code>tool</code>: The tool object about to be called (inspect <code>tool.name</code>).</li>
<li><code>args</code>: The dictionary of arguments the LLM generated for the tool.</li>
<li><code>tool_context</code>: Provides access to session state (<code>tool_context.state</code>), agent info, etc.</li>
</ul>
</li>
<li>
<p>Inside the function:</p>
<ul>
<li><strong>Inspect:</strong> Examine the <code>tool.name</code> and the <code>args</code> dictionary.</li>
<li><strong>Modify:</strong> Change values within the <code>args</code> dictionary <em>directly</em>. If you return <code>None</code>, the tool runs with these modified args.</li>
<li><strong>Block/Override (Guardrail):</strong> Return a <strong>dictionary</strong>. ADK treats this dictionary as the <em>result</em> of the tool call, completely <em>skipping</em> the execution of the original tool function. The dictionary should ideally match the expected return format of the tool it's blocking.</li>
<li><strong>Allow:</strong> Return <code>None</code>. ADK proceeds to execute the actual tool function with the (potentially modified) arguments.</li>
</ul>
</li>
</ol>
<p><strong>In this step, we will:</strong></p>
<ol>
<li>Define a <code>before_tool_callback</code> function (<code>block_paris_tool_guardrail</code>) that specifically checks if the <code>get_weather_stateful</code> tool is called with the city "Paris".</li>
<li>If "Paris" is detected, the callback will block the tool and return a custom error dictionary.</li>
<li>Update our root agent (<code>weather_agent_v6_tool_guardrail</code>) to include <em>both</em> the <code>before_model_callback</code> and this new <code>before_tool_callback</code>.</li>
<li>Create a new runner for this agent, using the same stateful session service.</li>
<li>Test the flow by requesting weather for allowed cities and the blocked city ("Paris").</li>
</ol>
<hr />
<p><strong>1. Define the Tool Guardrail Callback Function</strong></p>
<p>This function targets the <code>get_weather_stateful</code> tool. It checks the <code>city</code> 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 <code>None</code>.</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-23-1"><a id="__codelineno-23-1" name="__codelineno-23-1" href="#__codelineno-23-1"></a><span class="c1"># @title 1. Define the before_tool_callback Guardrail</span>
</span><span id="__span-23-2"><a id="__codelineno-23-2" name="__codelineno-23-2" href="#__codelineno-23-2"></a>
</span><span id="__span-23-3"><a id="__codelineno-23-3" name="__codelineno-23-3" href="#__codelineno-23-3"></a><span class="c1"># Ensure necessary imports are available</span>
</span><span id="__span-23-4"><a id="__codelineno-23-4" name="__codelineno-23-4" href="#__codelineno-23-4"></a><span class="kn">from</span><span class="w"> </span><span class="nn">google.adk.tools.base_tool</span><span class="w"> </span><span class="kn">import</span> <span class="n">BaseTool</span>
</span><span id="__span-23-5"><a id="__codelineno-23-5" name="__codelineno-23-5" href="#__codelineno-23-5"></a><span class="kn">from</span><span class="w"> </span><span class="nn">google.adk.tools.tool_context</span><span class="w"> </span><span class="kn">import</span> <span class="n">ToolContext</span>
</span><span id="__span-23-6"><a id="__codelineno-23-6" name="__codelineno-23-6" href="#__codelineno-23-6"></a><span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Optional</span><span class="p">,</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">Any</span> <span class="c1"># For type hints</span>
</span><span id="__span-23-7"><a id="__codelineno-23-7" name="__codelineno-23-7" href="#__codelineno-23-7"></a>
</span><span id="__span-23-8"><a id="__codelineno-23-8" name="__codelineno-23-8" href="#__codelineno-23-8"></a><span class="k">def</span><span class="w"> </span><span class="nf">block_paris_tool_guardrail</span><span class="p">(</span>
</span><span id="__span-23-9"><a id="__codelineno-23-9" name="__codelineno-23-9" href="#__codelineno-23-9"></a> <span class="n">tool</span><span class="p">:</span> <span class="n">BaseTool</span><span class="p">,</span> <span class="n">args</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">],</span> <span class="n">tool_context</span><span class="p">:</span> <span class="n">ToolContext</span>
</span><span id="__span-23-10"><a id="__codelineno-23-10" name="__codelineno-23-10" href="#__codelineno-23-10"></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Dict</span><span class="p">]:</span>
</span><span id="__span-23-11"><a id="__codelineno-23-11" name="__codelineno-23-11" href="#__codelineno-23-11"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-23-12"><a id="__codelineno-23-12" name="__codelineno-23-12" href="#__codelineno-23-12"></a><span class="sd"> Checks if 'get_weather_stateful' is called for 'Paris'.</span>
</span><span id="__span-23-13"><a id="__codelineno-23-13" name="__codelineno-23-13" href="#__codelineno-23-13"></a><span class="sd"> If so, blocks the tool execution and returns a specific error dictionary.</span>
</span><span id="__span-23-14"><a id="__codelineno-23-14" name="__codelineno-23-14" href="#__codelineno-23-14"></a><span class="sd"> Otherwise, allows the tool call to proceed by returning None.</span>
</span><span id="__span-23-15"><a id="__codelineno-23-15" name="__codelineno-23-15" href="#__codelineno-23-15"></a><span class="sd"> """</span>
</span><span id="__span-23-16"><a id="__codelineno-23-16" name="__codelineno-23-16" href="#__codelineno-23-16"></a> <span class="n">tool_name</span> <span class="o">=</span> <span class="n">tool</span><span class="o">.</span><span class="n">name</span>
</span><span id="__span-23-17"><a id="__codelineno-23-17" name="__codelineno-23-17" href="#__codelineno-23-17"></a> <span class="n">agent_name</span> <span class="o">=</span> <span class="n">tool_context</span><span class="o">.</span><span class="n">agent_name</span> <span class="c1"># Agent attempting the tool call</span>
</span><span id="__span-23-18"><a id="__codelineno-23-18" name="__codelineno-23-18" href="#__codelineno-23-18"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"--- Callback: block_paris_tool_guardrail running for tool '</span><span class="si">{</span><span class="n">tool_name</span><span class="si">}</span><span class="s2">' in agent '</span><span class="si">{</span><span class="n">agent_name</span><span class="si">}</span><span class="s2">' ---"</span><span class="p">)</span>
</span><span id="__span-23-19"><a id="__codelineno-23-19" name="__codelineno-23-19" href="#__codelineno-23-19"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"--- Callback: Inspecting args: </span><span class="si">{</span><span class="n">args</span><span class="si">}</span><span class="s2"> ---"</span><span class="p">)</span>
</span><span id="__span-23-20"><a id="__codelineno-23-20" name="__codelineno-23-20" href="#__codelineno-23-20"></a>
</span><span id="__span-23-21"><a id="__codelineno-23-21" name="__codelineno-23-21" href="#__codelineno-23-21"></a> <span class="c1"># --- Guardrail Logic ---</span>
</span><span id="__span-23-22"><a id="__codelineno-23-22" name="__codelineno-23-22" href="#__codelineno-23-22"></a> <span class="n">target_tool_name</span> <span class="o">=</span> <span class="s2">"get_weather_stateful"</span> <span class="c1"># Match the function name used by FunctionTool</span>
</span><span id="__span-23-23"><a id="__codelineno-23-23" name="__codelineno-23-23" href="#__codelineno-23-23"></a> <span class="n">blocked_city</span> <span class="o">=</span> <span class="s2">"paris"</span>
</span><span id="__span-23-24"><a id="__codelineno-23-24" name="__codelineno-23-24" href="#__codelineno-23-24"></a>
</span><span id="__span-23-25"><a id="__codelineno-23-25" name="__codelineno-23-25" href="#__codelineno-23-25"></a> <span class="c1"># Check if it's the correct tool and the city argument matches the blocked city</span>
</span><span id="__span-23-26"><a id="__codelineno-23-26" name="__codelineno-23-26" href="#__codelineno-23-26"></a> <span class="k">if</span> <span class="n">tool_name</span> <span class="o">==</span> <span class="n">target_tool_name</span><span class="p">:</span>
</span><span id="__span-23-27"><a id="__codelineno-23-27" name="__codelineno-23-27" href="#__codelineno-23-27"></a> <span class="n">city_argument</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"city"</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span> <span class="c1"># Safely get the 'city' argument</span>
</span><span id="__span-23-28"><a id="__codelineno-23-28" name="__codelineno-23-28" href="#__codelineno-23-28"></a> <span class="k">if</span> <span class="n">city_argument</span> <span class="ow">and</span> <span class="n">city_argument</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="n">blocked_city</span><span class="p">:</span>
</span><span id="__span-23-29"><a id="__codelineno-23-29" name="__codelineno-23-29" href="#__codelineno-23-29"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"--- Callback: Detected blocked city '</span><span class="si">{</span><span class="n">city_argument</span><span class="si">}</span><span class="s2">'. Blocking tool execution! ---"</span><span class="p">)</span>
</span><span id="__span-23-30"><a id="__codelineno-23-30" name="__codelineno-23-30" href="#__codelineno-23-30"></a> <span class="c1"># Optionally update state</span>
</span><span id="__span-23-31"><a id="__codelineno-23-31" name="__codelineno-23-31" href="#__codelineno-23-31"></a> <span class="n">tool_context</span><span class="o">.</span><span class="n">state</span><span class="p">[</span><span class="s2">"guardrail_tool_block_triggered"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span>
</span><span id="__span-23-32"><a id="__codelineno-23-32" name="__codelineno-23-32" href="#__codelineno-23-32"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"--- Callback: Set state 'guardrail_tool_block_triggered': True ---"</span><span class="p">)</span>
</span><span id="__span-23-33"><a id="__codelineno-23-33" name="__codelineno-23-33" href="#__codelineno-23-33"></a>
</span><span id="__span-23-34"><a id="__codelineno-23-34" name="__codelineno-23-34" href="#__codelineno-23-34"></a> <span class="c1"># Return a dictionary matching the tool's expected output format for errors</span>
</span><span id="__span-23-35"><a id="__codelineno-23-35" name="__codelineno-23-35" href="#__codelineno-23-35"></a> <span class="c1"># This dictionary becomes the tool's result, skipping the actual tool run.</span>
</span><span id="__span-23-36"><a id="__codelineno-23-36" name="__codelineno-23-36" href="#__codelineno-23-36"></a> <span class="k">return</span> <span class="p">{</span>
</span><span id="__span-23-37"><a id="__codelineno-23-37" name="__codelineno-23-37" href="#__codelineno-23-37"></a> <span class="s2">"status"</span><span class="p">:</span> <span class="s2">"error"</span><span class="p">,</span>
</span><span id="__span-23-38"><a id="__codelineno-23-38" name="__codelineno-23-38" href="#__codelineno-23-38"></a> <span class="s2">"error_message"</span><span class="p">:</span> <span class="sa">f</span><span class="s2">"Policy restriction: Weather checks for '</span><span class="si">{</span><span class="n">city_argument</span><span class="o">.</span><span class="n">capitalize</span><span class="p">()</span><span class="si">}</span><span class="s2">' are currently disabled by a tool guardrail."</span>
</span><span id="__span-23-39"><a id="__codelineno-23-39" name="__codelineno-23-39" href="#__codelineno-23-39"></a> <span class="p">}</span>
</span><span id="__span-23-40"><a id="__codelineno-23-40" name="__codelineno-23-40" href="#__codelineno-23-40"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-23-41"><a id="__codelineno-23-41" name="__codelineno-23-41" href="#__codelineno-23-41"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"--- Callback: City '</span><span class="si">{</span><span class="n">city_argument</span><span class="si">}</span><span class="s2">' is allowed for tool '</span><span class="si">{</span><span class="n">tool_name</span><span class="si">}</span><span class="s2">'. ---"</span><span class="p">)</span>
</span><span id="__span-23-42"><a id="__codelineno-23-42" name="__codelineno-23-42" href="#__codelineno-23-42"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-23-43"><a id="__codelineno-23-43" name="__codelineno-23-43" href="#__codelineno-23-43"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"--- Callback: Tool '</span><span class="si">{</span><span class="n">tool_name</span><span class="si">}</span><span class="s2">' is not the target tool. Allowing. ---"</span><span class="p">)</span>
</span><span id="__span-23-44"><a id="__codelineno-23-44" name="__codelineno-23-44" href="#__codelineno-23-44"></a>
</span><span id="__span-23-45"><a id="__codelineno-23-45" name="__codelineno-23-45" href="#__codelineno-23-45"></a>
</span><span id="__span-23-46"><a id="__codelineno-23-46" name="__codelineno-23-46" href="#__codelineno-23-46"></a> <span class="c1"># If the checks above didn't return a dictionary, allow the tool to execute</span>
</span><span id="__span-23-47"><a id="__codelineno-23-47" name="__codelineno-23-47" href="#__codelineno-23-47"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"--- Callback: Allowing tool '</span><span class="si">{</span><span class="n">tool_name</span><span class="si">}</span><span class="s2">' to proceed. ---"</span><span class="p">)</span>
</span><span id="__span-23-48"><a id="__codelineno-23-48" name="__codelineno-23-48" href="#__codelineno-23-48"></a> <span class="k">return</span> <span class="kc">None</span> <span class="c1"># Returning None allows the actual tool function to run</span>
</span><span id="__span-23-49"><a id="__codelineno-23-49" name="__codelineno-23-49" href="#__codelineno-23-49"></a>
</span><span id="__span-23-50"><a id="__codelineno-23-50" name="__codelineno-23-50" href="#__codelineno-23-50"></a><span class="nb">print</span><span class="p">(</span><span class="s2">"✅ block_paris_tool_guardrail function defined."</span><span class="p">)</span>
</span></code></pre></div>
<hr />
<p><strong>2. Update Root Agent to Use Both Callbacks</strong></p>
<p>We redefine the root agent again (<code>weather_agent_v6_tool_guardrail</code>), this time adding the <code>before_tool_callback</code> parameter alongside the <code>before_model_callback</code> from Step 5.</p>
<p><em>Self-Contained Execution Note:</em> Similar to Step 5, ensure all prerequisites (sub-agents, tools, <code>before_model_callback</code>) are defined or available in the execution context before defining this agent.</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-24-1"><a id="__codelineno-24-1" name="__codelineno-24-1" href="#__codelineno-24-1"></a><span class="c1"># @title 2. Update Root Agent with BOTH Callbacks (Self-Contained)</span>
</span><span id="__span-24-2"><a id="__codelineno-24-2" name="__codelineno-24-2" href="#__codelineno-24-2"></a>
</span><span id="__span-24-3"><a id="__codelineno-24-3" name="__codelineno-24-3" href="#__codelineno-24-3"></a><span class="c1"># --- Ensure Prerequisites are Defined ---</span>
</span><span id="__span-24-4"><a id="__codelineno-24-4" name="__codelineno-24-4" href="#__codelineno-24-4"></a><span class="c1"># (Include or ensure execution of definitions for: Agent, LiteLlm, Runner, ToolContext,</span>
</span><span id="__span-24-5"><a id="__codelineno-24-5" name="__codelineno-24-5" href="#__codelineno-24-5"></a><span class="c1"># MODEL constants, say_hello, say_goodbye, greeting_agent, farewell_agent,</span>
</span><span id="__span-24-6"><a id="__codelineno-24-6" name="__codelineno-24-6" href="#__codelineno-24-6"></a><span class="c1"># get_weather_stateful, block_keyword_guardrail, block_paris_tool_guardrail)</span>
</span><span id="__span-24-7"><a id="__codelineno-24-7" name="__codelineno-24-7" href="#__codelineno-24-7"></a>
</span><span id="__span-24-8"><a id="__codelineno-24-8" name="__codelineno-24-8" href="#__codelineno-24-8"></a><span class="c1"># --- Redefine Sub-Agents (Ensures they exist in this context) ---</span>
</span><span id="__span-24-9"><a id="__codelineno-24-9" name="__codelineno-24-9" href="#__codelineno-24-9"></a><span class="n">greeting_agent</span> <span class="o">=</span> <span class="kc">None</span>
</span><span id="__span-24-10"><a id="__codelineno-24-10" name="__codelineno-24-10" href="#__codelineno-24-10"></a><span class="k">try</span><span class="p">:</span>
</span><span id="__span-24-11"><a id="__codelineno-24-11" name="__codelineno-24-11" href="#__codelineno-24-11"></a> <span class="c1"># Use a defined model constant</span>
</span><span id="__span-24-12"><a id="__codelineno-24-12" name="__codelineno-24-12" href="#__codelineno-24-12"></a> <span class="n">greeting_agent</span> <span class="o">=</span> <span class="n">Agent</span><span class="p">(</span>
</span><span id="__span-24-13"><a id="__codelineno-24-13" name="__codelineno-24-13" href="#__codelineno-24-13"></a> <span class="n">model</span><span class="o">=</span><span class="n">MODEL_GEMINI_FLASH</span><span class="p">,</span>
</span><span id="__span-24-14"><a id="__codelineno-24-14" name="__codelineno-24-14" href="#__codelineno-24-14"></a> <span class="n">name</span><span class="o">=</span><span class="s2">"greeting_agent"</span><span class="p">,</span> <span class="c1"># Keep original name for consistency</span>
</span><span id="__span-24-15"><a id="__codelineno-24-15" name="__codelineno-24-15" href="#__codelineno-24-15"></a> <span class="n">instruction</span><span class="o">=</span><span class="s2">"You are the Greeting Agent. Your ONLY task is to provide a friendly greeting using the 'say_hello' tool. Do nothing else."</span><span class="p">,</span>
</span><span id="__span-24-16"><a id="__codelineno-24-16" name="__codelineno-24-16" href="#__codelineno-24-16"></a> <span class="n">description</span><span class="o">=</span><span class="s2">"Handles simple greetings and hellos using the 'say_hello' tool."</span><span class="p">,</span>
</span><span id="__span-24-17"><a id="__codelineno-24-17" name="__codelineno-24-17" href="#__codelineno-24-17"></a> <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">say_hello</span><span class="p">],</span>
</span><span id="__span-24-18"><a id="__codelineno-24-18" name="__codelineno-24-18" href="#__codelineno-24-18"></a> <span class="p">)</span>
</span><span id="__span-24-19"><a id="__codelineno-24-19" name="__codelineno-24-19" href="#__codelineno-24-19"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"✅ Sub-Agent '</span><span class="si">{</span><span class="n">greeting_agent</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">' redefined."</span><span class="p">)</span>
</span><span id="__span-24-20"><a id="__codelineno-24-20" name="__codelineno-24-20" href="#__codelineno-24-20"></a><span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span><span id="__span-24-21"><a id="__codelineno-24-21" name="__codelineno-24-21" href="#__codelineno-24-21"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"❌ Could not redefine Greeting agent. Check Model/API Key (</span><span class="si">{</span><span class="n">greeting_agent</span><span class="o">.</span><span class="n">model</span><span class="si">}</span><span class="s2">). Error: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span><span id="__span-24-22"><a id="__codelineno-24-22" name="__codelineno-24-22" href="#__codelineno-24-22"></a>
</span><span id="__span-24-23"><a id="__codelineno-24-23" name="__codelineno-24-23" href="#__codelineno-24-23"></a><span class="n">farewell_agent</span> <span class="o">=</span> <span class="kc">None</span>
</span><span id="__span-24-24"><a id="__codelineno-24-24" name="__codelineno-24-24" href="#__codelineno-24-24"></a><span class="k">try</span><span class="p">:</span>
</span><span id="__span-24-25"><a id="__codelineno-24-25" name="__codelineno-24-25" href="#__codelineno-24-25"></a> <span class="c1"># Use a defined model constant</span>
</span><span id="__span-24-26"><a id="__codelineno-24-26" name="__codelineno-24-26" href="#__codelineno-24-26"></a> <span class="n">farewell_agent</span> <span class="o">=</span> <span class="n">Agent</span><span class="p">(</span>
</span><span id="__span-24-27"><a id="__codelineno-24-27" name="__codelineno-24-27" href="#__codelineno-24-27"></a> <span class="n">model</span><span class="o">=</span><span class="n">MODEL_GEMINI_FLASH</span><span class="p">,</span>
</span><span id="__span-24-28"><a id="__codelineno-24-28" name="__codelineno-24-28" href="#__codelineno-24-28"></a> <span class="n">name</span><span class="o">=</span><span class="s2">"farewell_agent"</span><span class="p">,</span> <span class="c1"># Keep original name</span>
</span><span id="__span-24-29"><a id="__codelineno-24-29" name="__codelineno-24-29" href="#__codelineno-24-29"></a> <span class="n">instruction</span><span class="o">=</span><span class="s2">"You are the Farewell Agent. Your ONLY task is to provide a polite goodbye message using the 'say_goodbye' tool. Do not perform any other actions."</span><span class="p">,</span>
</span><span id="__span-24-30"><a id="__codelineno-24-30" name="__codelineno-24-30" href="#__codelineno-24-30"></a> <span class="n">description</span><span class="o">=</span><span class="s2">"Handles simple farewells and goodbyes using the 'say_goodbye' tool."</span><span class="p">,</span>
</span><span id="__span-24-31"><a id="__codelineno-24-31" name="__codelineno-24-31" href="#__codelineno-24-31"></a> <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">say_goodbye</span><span class="p">],</span>
</span><span id="__span-24-32"><a id="__codelineno-24-32" name="__codelineno-24-32" href="#__codelineno-24-32"></a> <span class="p">)</span>
</span><span id="__span-24-33"><a id="__codelineno-24-33" name="__codelineno-24-33" href="#__codelineno-24-33"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"✅ Sub-Agent '</span><span class="si">{</span><span class="n">farewell_agent</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">' redefined."</span><span class="p">)</span>
</span><span id="__span-24-34"><a id="__codelineno-24-34" name="__codelineno-24-34" href="#__codelineno-24-34"></a><span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span><span id="__span-24-35"><a id="__codelineno-24-35" name="__codelineno-24-35" href="#__codelineno-24-35"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"❌ Could not redefine Farewell agent. Check Model/API Key (</span><span class="si">{</span><span class="n">farewell_agent</span><span class="o">.</span><span class="n">model</span><span class="si">}</span><span class="s2">). Error: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span><span id="__span-24-36"><a id="__codelineno-24-36" name="__codelineno-24-36" href="#__codelineno-24-36"></a>
</span><span id="__span-24-37"><a id="__codelineno-24-37" name="__codelineno-24-37" href="#__codelineno-24-37"></a><span class="c1"># --- Define the Root Agent with Both Callbacks ---</span>
</span><span id="__span-24-38"><a id="__codelineno-24-38" name="__codelineno-24-38" href="#__codelineno-24-38"></a><span class="n">root_agent_tool_guardrail</span> <span class="o">=</span> <span class="kc">None</span>
</span><span id="__span-24-39"><a id="__codelineno-24-39" name="__codelineno-24-39" href="#__codelineno-24-39"></a><span class="n">runner_root_tool_guardrail</span> <span class="o">=</span> <span class="kc">None</span>
</span><span id="__span-24-40"><a id="__codelineno-24-40" name="__codelineno-24-40" href="#__codelineno-24-40"></a>
</span><span id="__span-24-41"><a id="__codelineno-24-41" name="__codelineno-24-41" href="#__codelineno-24-41"></a><span class="k">if</span> <span class="p">(</span><span class="s1">'greeting_agent'</span> <span class="ow">in</span> <span class="nb">globals</span><span class="p">()</span> <span class="ow">and</span> <span class="n">greeting_agent</span> <span class="ow">and</span>
</span><span id="__span-24-42"><a id="__codelineno-24-42" name="__codelineno-24-42" href="#__codelineno-24-42"></a> <span class="s1">'farewell_agent'</span> <span class="ow">in</span> <span class="nb">globals</span><span class="p">()</span> <span class="ow">and</span> <span class="n">farewell_agent</span> <span class="ow">and</span>
</span><span id="__span-24-43"><a id="__codelineno-24-43" name="__codelineno-24-43" href="#__codelineno-24-43"></a> <span class="s1">'get_weather_stateful'</span> <span class="ow">in</span> <span class="nb">globals</span><span class="p">()</span> <span class="ow">and</span>
</span><span id="__span-24-44"><a id="__codelineno-24-44" name="__codelineno-24-44" href="#__codelineno-24-44"></a> <span class="s1">'block_keyword_guardrail'</span> <span class="ow">in</span> <span class="nb">globals</span><span class="p">()</span> <span class="ow">and</span>
</span><span id="__span-24-45"><a id="__codelineno-24-45" name="__codelineno-24-45" href="#__codelineno-24-45"></a> <span class="s1">'block_paris_tool_guardrail'</span> <span class="ow">in</span> <span class="nb">globals</span><span class="p">()):</span>
</span><span id="__span-24-46"><a id="__codelineno-24-46" name="__codelineno-24-46" href="#__codelineno-24-46"></a>
</span><span id="__span-24-47"><a id="__codelineno-24-47" name="__codelineno-24-47" href="#__codelineno-24-47"></a> <span class="n">root_agent_model</span> <span class="o">=</span> <span class="n">MODEL_GEMINI_FLASH</span>
</span><span id="__span-24-48"><a id="__codelineno-24-48" name="__codelineno-24-48" href="#__codelineno-24-48"></a>
</span><span id="__span-24-49"><a id="__codelineno-24-49" name="__codelineno-24-49" href="#__codelineno-24-49"></a> <span class="n">root_agent_tool_guardrail</span> <span class="o">=</span> <span class="n">Agent</span><span class="p">(</span>
</span><span id="__span-24-50"><a id="__codelineno-24-50" name="__codelineno-24-50" href="#__codelineno-24-50"></a> <span class="n">name</span><span class="o">=</span><span class="s2">"weather_agent_v6_tool_guardrail"</span><span class="p">,</span> <span class="c1"># New version name</span>
</span><span id="__span-24-51"><a id="__codelineno-24-51" name="__codelineno-24-51" href="#__codelineno-24-51"></a> <span class="n">model</span><span class="o">=</span><span class="n">root_agent_model</span><span class="p">,</span>
</span><span id="__span-24-52"><a id="__codelineno-24-52" name="__codelineno-24-52" href="#__codelineno-24-52"></a> <span class="n">description</span><span class="o">=</span><span class="s2">"Main agent: Handles weather, delegates, includes input AND tool guardrails."</span><span class="p">,</span>
</span><span id="__span-24-53"><a id="__codelineno-24-53" name="__codelineno-24-53" href="#__codelineno-24-53"></a> <span class="n">instruction</span><span class="o">=</span><span class="s2">"You are the main Weather Agent. Provide weather using 'get_weather_stateful'. "</span>
</span><span id="__span-24-54"><a id="__codelineno-24-54" name="__codelineno-24-54" href="#__codelineno-24-54"></a> <span class="s2">"Delegate greetings to 'greeting_agent' and farewells to 'farewell_agent'. "</span>
</span><span id="__span-24-55"><a id="__codelineno-24-55" name="__codelineno-24-55" href="#__codelineno-24-55"></a> <span class="s2">"Handle only weather, greetings, and farewells."</span><span class="p">,</span>
</span><span id="__span-24-56"><a id="__codelineno-24-56" name="__codelineno-24-56" href="#__codelineno-24-56"></a> <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">get_weather_stateful</span><span class="p">],</span>
</span><span id="__span-24-57"><a id="__codelineno-24-57" name="__codelineno-24-57" href="#__codelineno-24-57"></a> <span class="n">sub_agents</span><span class="o">=</span><span class="p">[</span><span class="n">greeting_agent</span><span class="p">,</span> <span class="n">farewell_agent</span><span class="p">],</span>
</span><span id="__span-24-58"><a id="__codelineno-24-58" name="__codelineno-24-58" href="#__codelineno-24-58"></a> <span class="n">output_key</span><span class="o">=</span><span class="s2">"last_weather_report"</span><span class="p">,</span>
</span><span id="__span-24-59"><a id="__codelineno-24-59" name="__codelineno-24-59" href="#__codelineno-24-59"></a> <span class="n">before_model_callback</span><span class="o">=</span><span class="n">block_keyword_guardrail</span><span class="p">,</span> <span class="c1"># Keep model guardrail</span>
</span><span id="__span-24-60"><a id="__codelineno-24-60" name="__codelineno-24-60" href="#__codelineno-24-60"></a> <span class="n">before_tool_callback</span><span class="o">=</span><span class="n">block_paris_tool_guardrail</span> <span class="c1"># &lt;&lt;&lt; Add tool guardrail</span>
</span><span id="__span-24-61"><a id="__codelineno-24-61" name="__codelineno-24-61" href="#__codelineno-24-61"></a> <span class="p">)</span>
</span><span id="__span-24-62"><a id="__codelineno-24-62" name="__codelineno-24-62" href="#__codelineno-24-62"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"✅ Root Agent '</span><span class="si">{</span><span class="n">root_agent_tool_guardrail</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">' created with BOTH callbacks."</span><span class="p">)</span>
</span><span id="__span-24-63"><a id="__codelineno-24-63" name="__codelineno-24-63" href="#__codelineno-24-63"></a>
</span><span id="__span-24-64"><a id="__codelineno-24-64" name="__codelineno-24-64" href="#__codelineno-24-64"></a> <span class="c1"># --- Create Runner, Using SAME Stateful Session Service ---</span>
</span><span id="__span-24-65"><a id="__codelineno-24-65" name="__codelineno-24-65" href="#__codelineno-24-65"></a> <span class="k">if</span> <span class="s1">'session_service_stateful'</span> <span class="ow">in</span> <span class="nb">globals</span><span class="p">():</span>
</span><span id="__span-24-66"><a id="__codelineno-24-66" name="__codelineno-24-66" href="#__codelineno-24-66"></a> <span class="n">runner_root_tool_guardrail</span> <span class="o">=</span> <span class="n">Runner</span><span class="p">(</span>
</span><span id="__span-24-67"><a id="__codelineno-24-67" name="__codelineno-24-67" href="#__codelineno-24-67"></a> <span class="n">agent</span><span class="o">=</span><span class="n">root_agent_tool_guardrail</span><span class="p">,</span>
</span><span id="__span-24-68"><a id="__codelineno-24-68" name="__codelineno-24-68" href="#__codelineno-24-68"></a> <span class="n">app_name</span><span class="o">=</span><span class="n">APP_NAME</span><span class="p">,</span>
</span><span id="__span-24-69"><a id="__codelineno-24-69" name="__codelineno-24-69" href="#__codelineno-24-69"></a> <span class="n">session_service</span><span class="o">=</span><span class="n">session_service_stateful</span> <span class="c1"># &lt;&lt;&lt; Use the service from Step 4/5</span>
</span><span id="__span-24-70"><a id="__codelineno-24-70" name="__codelineno-24-70" href="#__codelineno-24-70"></a> <span class="p">)</span>
</span><span id="__span-24-71"><a id="__codelineno-24-71" name="__codelineno-24-71" href="#__codelineno-24-71"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"✅ Runner created for tool guardrail agent '</span><span class="si">{</span><span class="n">runner_root_tool_guardrail</span><span class="o">.</span><span class="n">agent</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">', using stateful session service."</span><span class="p">)</span>
</span><span id="__span-24-72"><a id="__codelineno-24-72" name="__codelineno-24-72" href="#__codelineno-24-72"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-24-73"><a id="__codelineno-24-73" name="__codelineno-24-73" href="#__codelineno-24-73"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"❌ Cannot create runner. 'session_service_stateful' from Step 4/5 is missing."</span><span class="p">)</span>
</span><span id="__span-24-74"><a id="__codelineno-24-74" name="__codelineno-24-74" href="#__codelineno-24-74"></a>
</span><span id="__span-24-75"><a id="__codelineno-24-75" name="__codelineno-24-75" href="#__codelineno-24-75"></a><span class="k">else</span><span class="p">:</span>
</span><span id="__span-24-76"><a id="__codelineno-24-76" name="__codelineno-24-76" href="#__codelineno-24-76"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"❌ Cannot create root agent with tool guardrail. Prerequisites missing."</span><span class="p">)</span>
</span></code></pre></div>
<hr />
<p><strong>3. Interact to Test the Tool Guardrail</strong></p>
<p>Let's test the interaction flow, again using the same stateful session (<code>SESSION_ID_STATEFUL</code>) from the previous steps.</p>
<ol>
<li>Request weather for "New York": Passes both callbacks, tool executes (using Fahrenheit preference from state).</li>
<li>Request weather for "Paris": Passes <code>before_model_callback</code>. LLM decides to call <code>get_weather_stateful(city='Paris')</code>. <code>before_tool_callback</code> intercepts, blocks the tool, and returns the error dictionary. Agent relays this error.</li>
<li>Request weather for "London": Passes both callbacks, tool executes normally.</li>
</ol>
<div class="language-python highlight"><pre><span></span><code><span id="__span-25-1"><a id="__codelineno-25-1" name="__codelineno-25-1" href="#__codelineno-25-1"></a><span class="c1"># @title 3. Interact to Test the Tool Argument Guardrail</span>
</span><span id="__span-25-2"><a id="__codelineno-25-2" name="__codelineno-25-2" href="#__codelineno-25-2"></a><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span> <span class="c1"># Ensure asyncio is imported</span>
</span><span id="__span-25-3"><a id="__codelineno-25-3" name="__codelineno-25-3" href="#__codelineno-25-3"></a>
</span><span id="__span-25-4"><a id="__codelineno-25-4" name="__codelineno-25-4" href="#__codelineno-25-4"></a><span class="c1"># Ensure the runner for the tool guardrail agent is available</span>
</span><span id="__span-25-5"><a id="__codelineno-25-5" name="__codelineno-25-5" href="#__codelineno-25-5"></a><span class="k">if</span> <span class="s1">'runner_root_tool_guardrail'</span> <span class="ow">in</span> <span class="nb">globals</span><span class="p">()</span> <span class="ow">and</span> <span class="n">runner_root_tool_guardrail</span><span class="p">:</span>
</span><span id="__span-25-6"><a id="__codelineno-25-6" name="__codelineno-25-6" href="#__codelineno-25-6"></a> <span class="c1"># Define the main async function for the tool guardrail test conversation.</span>
</span><span id="__span-25-7"><a id="__codelineno-25-7" name="__codelineno-25-7" href="#__codelineno-25-7"></a> <span class="c1"># The 'await' keywords INSIDE this function are necessary for async operations.</span>
</span><span id="__span-25-8"><a id="__codelineno-25-8" name="__codelineno-25-8" href="#__codelineno-25-8"></a> <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run_tool_guardrail_test</span><span class="p">():</span>
</span><span id="__span-25-9"><a id="__codelineno-25-9" name="__codelineno-25-9" href="#__codelineno-25-9"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">--- Testing Tool Argument Guardrail ('Paris' blocked) ---"</span><span class="p">)</span>
</span><span id="__span-25-10"><a id="__codelineno-25-10" name="__codelineno-25-10" href="#__codelineno-25-10"></a>
</span><span id="__span-25-11"><a id="__codelineno-25-11" name="__codelineno-25-11" href="#__codelineno-25-11"></a> <span class="c1"># Use the runner for the agent with both callbacks and the existing stateful session</span>
</span><span id="__span-25-12"><a id="__codelineno-25-12" name="__codelineno-25-12" href="#__codelineno-25-12"></a> <span class="c1"># Define a helper lambda for cleaner interaction calls</span>
</span><span id="__span-25-13"><a id="__codelineno-25-13" name="__codelineno-25-13" href="#__codelineno-25-13"></a> <span class="n">interaction_func</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">query</span><span class="p">:</span> <span class="n">call_agent_async</span><span class="p">(</span><span class="n">query</span><span class="p">,</span>
</span><span id="__span-25-14"><a id="__codelineno-25-14" name="__codelineno-25-14" href="#__codelineno-25-14"></a> <span class="n">runner_root_tool_guardrail</span><span class="p">,</span>
</span><span id="__span-25-15"><a id="__codelineno-25-15" name="__codelineno-25-15" href="#__codelineno-25-15"></a> <span class="n">USER_ID_STATEFUL</span><span class="p">,</span> <span class="c1"># Use existing user ID</span>
</span><span id="__span-25-16"><a id="__codelineno-25-16" name="__codelineno-25-16" href="#__codelineno-25-16"></a> <span class="n">SESSION_ID_STATEFUL</span> <span class="c1"># Use existing session ID</span>
</span><span id="__span-25-17"><a id="__codelineno-25-17" name="__codelineno-25-17" href="#__codelineno-25-17"></a> <span class="p">)</span>
</span><span id="__span-25-18"><a id="__codelineno-25-18" name="__codelineno-25-18" href="#__codelineno-25-18"></a> <span class="c1"># 1. Allowed city (Should pass both callbacks, use Fahrenheit state)</span>
</span><span id="__span-25-19"><a id="__codelineno-25-19" name="__codelineno-25-19" href="#__codelineno-25-19"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"--- Turn 1: Requesting weather in New York (expect allowed) ---"</span><span class="p">)</span>
</span><span id="__span-25-20"><a id="__codelineno-25-20" name="__codelineno-25-20" href="#__codelineno-25-20"></a> <span class="k">await</span> <span class="n">interaction_func</span><span class="p">(</span><span class="s2">"What's the weather in New York?"</span><span class="p">)</span>
</span><span id="__span-25-21"><a id="__codelineno-25-21" name="__codelineno-25-21" href="#__codelineno-25-21"></a>
</span><span id="__span-25-22"><a id="__codelineno-25-22" name="__codelineno-25-22" href="#__codelineno-25-22"></a> <span class="c1"># 2. Blocked city (Should pass model callback, but be blocked by tool callback)</span>
</span><span id="__span-25-23"><a id="__codelineno-25-23" name="__codelineno-25-23" href="#__codelineno-25-23"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">--- Turn 2: Requesting weather in Paris (expect blocked by tool guardrail) ---"</span><span class="p">)</span>
</span><span id="__span-25-24"><a id="__codelineno-25-24" name="__codelineno-25-24" href="#__codelineno-25-24"></a> <span class="k">await</span> <span class="n">interaction_func</span><span class="p">(</span><span class="s2">"How about Paris?"</span><span class="p">)</span> <span class="c1"># Tool callback should intercept this</span>
</span><span id="__span-25-25"><a id="__codelineno-25-25" name="__codelineno-25-25" href="#__codelineno-25-25"></a>
</span><span id="__span-25-26"><a id="__codelineno-25-26" name="__codelineno-25-26" href="#__codelineno-25-26"></a> <span class="c1"># 3. Another allowed city (Should work normally again)</span>
</span><span id="__span-25-27"><a id="__codelineno-25-27" name="__codelineno-25-27" href="#__codelineno-25-27"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">--- Turn 3: Requesting weather in London (expect allowed) ---"</span><span class="p">)</span>
</span><span id="__span-25-28"><a id="__codelineno-25-28" name="__codelineno-25-28" href="#__codelineno-25-28"></a> <span class="k">await</span> <span class="n">interaction_func</span><span class="p">(</span><span class="s2">"Tell me the weather in London."</span><span class="p">)</span>
</span><span id="__span-25-29"><a id="__codelineno-25-29" name="__codelineno-25-29" href="#__codelineno-25-29"></a>
</span><span id="__span-25-30"><a id="__codelineno-25-30" name="__codelineno-25-30" href="#__codelineno-25-30"></a> <span class="c1"># --- Execute the `run_tool_guardrail_test` async function ---</span>
</span><span id="__span-25-31"><a id="__codelineno-25-31" name="__codelineno-25-31" href="#__codelineno-25-31"></a> <span class="c1"># Choose ONE of the methods below based on your environment.</span>
</span><span id="__span-25-32"><a id="__codelineno-25-32" name="__codelineno-25-32" href="#__codelineno-25-32"></a>
</span><span id="__span-25-33"><a id="__codelineno-25-33" name="__codelineno-25-33" href="#__codelineno-25-33"></a> <span class="c1"># METHOD 1: Direct await (Default for Notebooks/Async REPLs)</span>
</span><span id="__span-25-34"><a id="__codelineno-25-34" name="__codelineno-25-34" href="#__codelineno-25-34"></a> <span class="c1"># If your environment supports top-level await (like Colab/Jupyter notebooks),</span>
</span><span id="__span-25-35"><a id="__codelineno-25-35" name="__codelineno-25-35" href="#__codelineno-25-35"></a> <span class="c1"># it means an event loop is already running, so you can directly await the function.</span>
</span><span id="__span-25-36"><a id="__codelineno-25-36" name="__codelineno-25-36" href="#__codelineno-25-36"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"Attempting execution using 'await' (default for notebooks)..."</span><span class="p">)</span>
</span><span id="__span-25-37"><a id="__codelineno-25-37" name="__codelineno-25-37" href="#__codelineno-25-37"></a> <span class="k">await</span> <span class="n">run_tool_guardrail_test</span><span class="p">()</span>
</span><span id="__span-25-38"><a id="__codelineno-25-38" name="__codelineno-25-38" href="#__codelineno-25-38"></a>
</span><span id="__span-25-39"><a id="__codelineno-25-39" name="__codelineno-25-39" href="#__codelineno-25-39"></a> <span class="c1"># METHOD 2: asyncio.run (For Standard Python Scripts [.py])</span>
</span><span id="__span-25-40"><a id="__codelineno-25-40" name="__codelineno-25-40" href="#__codelineno-25-40"></a> <span class="c1"># If running this code as a standard Python script from your terminal,</span>
</span><span id="__span-25-41"><a id="__codelineno-25-41" name="__codelineno-25-41" href="#__codelineno-25-41"></a> <span class="c1"># the script context is synchronous. `asyncio.run()` is needed to</span>
</span><span id="__span-25-42"><a id="__codelineno-25-42" name="__codelineno-25-42" href="#__codelineno-25-42"></a> <span class="c1"># create and manage an event loop to execute your async function.</span>
</span><span id="__span-25-43"><a id="__codelineno-25-43" name="__codelineno-25-43" href="#__codelineno-25-43"></a> <span class="c1"># To use this method:</span>
</span><span id="__span-25-44"><a id="__codelineno-25-44" name="__codelineno-25-44" href="#__codelineno-25-44"></a> <span class="c1"># 1. Comment out the `await run_tool_guardrail_test()` line above.</span>
</span><span id="__span-25-45"><a id="__codelineno-25-45" name="__codelineno-25-45" href="#__codelineno-25-45"></a> <span class="c1"># 2. Uncomment the following block:</span>
</span><span id="__span-25-46"><a id="__codelineno-25-46" name="__codelineno-25-46" href="#__codelineno-25-46"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-25-47"><a id="__codelineno-25-47" name="__codelineno-25-47" href="#__codelineno-25-47"></a><span class="sd"> import asyncio</span>
</span><span id="__span-25-48"><a id="__codelineno-25-48" name="__codelineno-25-48" href="#__codelineno-25-48"></a><span class="sd"> if __name__ == "__main__": # Ensures this runs only when script is executed directly</span>
</span><span id="__span-25-49"><a id="__codelineno-25-49" name="__codelineno-25-49" href="#__codelineno-25-49"></a><span class="sd"> print("Executing using 'asyncio.run()' (for standard Python scripts)...")</span>
</span><span id="__span-25-50"><a id="__codelineno-25-50" name="__codelineno-25-50" href="#__codelineno-25-50"></a><span class="sd"> try:</span>
</span><span id="__span-25-51"><a id="__codelineno-25-51" name="__codelineno-25-51" href="#__codelineno-25-51"></a><span class="sd"> # This creates an event loop, runs your async function, and closes the loop.</span>
</span><span id="__span-25-52"><a id="__codelineno-25-52" name="__codelineno-25-52" href="#__codelineno-25-52"></a><span class="sd"> asyncio.run(run_tool_guardrail_test())</span>
</span><span id="__span-25-53"><a id="__codelineno-25-53" name="__codelineno-25-53" href="#__codelineno-25-53"></a><span class="sd"> except Exception as e:</span>
</span><span id="__span-25-54"><a id="__codelineno-25-54" name="__codelineno-25-54" href="#__codelineno-25-54"></a><span class="sd"> print(f"An error occurred: {e}")</span>
</span><span id="__span-25-55"><a id="__codelineno-25-55" name="__codelineno-25-55" href="#__codelineno-25-55"></a><span class="sd"> """</span>
</span><span id="__span-25-56"><a id="__codelineno-25-56" name="__codelineno-25-56" href="#__codelineno-25-56"></a>
</span><span id="__span-25-57"><a id="__codelineno-25-57" name="__codelineno-25-57" href="#__codelineno-25-57"></a> <span class="c1"># --- Inspect final session state after the conversation ---</span>
</span><span id="__span-25-58"><a id="__codelineno-25-58" name="__codelineno-25-58" href="#__codelineno-25-58"></a> <span class="c1"># This block runs after either execution method completes.</span>
</span><span id="__span-25-59"><a id="__codelineno-25-59" name="__codelineno-25-59" href="#__codelineno-25-59"></a> <span class="c1"># Optional: Check state for the tool block trigger flag</span>
</span><span id="__span-25-60"><a id="__codelineno-25-60" name="__codelineno-25-60" href="#__codelineno-25-60"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">--- Inspecting Final Session State (After Tool Guardrail Test) ---"</span><span class="p">)</span>
</span><span id="__span-25-61"><a id="__codelineno-25-61" name="__codelineno-25-61" href="#__codelineno-25-61"></a> <span class="c1"># Use the session service instance associated with this stateful session</span>
</span><span id="__span-25-62"><a id="__codelineno-25-62" name="__codelineno-25-62" href="#__codelineno-25-62"></a> <span class="n">final_session</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session_service_stateful</span><span class="o">.</span><span class="n">get_session</span><span class="p">(</span><span class="n">app_name</span><span class="o">=</span><span class="n">APP_NAME</span><span class="p">,</span>
</span><span id="__span-25-63"><a id="__codelineno-25-63" name="__codelineno-25-63" href="#__codelineno-25-63"></a> <span class="n">user_id</span><span class="o">=</span><span class="n">USER_ID_STATEFUL</span><span class="p">,</span>
</span><span id="__span-25-64"><a id="__codelineno-25-64" name="__codelineno-25-64" href="#__codelineno-25-64"></a> <span class="n">session_id</span><span class="o">=</span> <span class="n">SESSION_ID_STATEFUL</span><span class="p">)</span>
</span><span id="__span-25-65"><a id="__codelineno-25-65" name="__codelineno-25-65" href="#__codelineno-25-65"></a> <span class="k">if</span> <span class="n">final_session</span><span class="p">:</span>
</span><span id="__span-25-66"><a id="__codelineno-25-66" name="__codelineno-25-66" href="#__codelineno-25-66"></a> <span class="c1"># Use .get() for safer access</span>
</span><span id="__span-25-67"><a id="__codelineno-25-67" name="__codelineno-25-67" href="#__codelineno-25-67"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Tool Guardrail Triggered Flag: </span><span class="si">{</span><span class="n">final_session</span><span class="o">.</span><span class="n">state</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'guardrail_tool_block_triggered'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Not Set (or False)'</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span><span id="__span-25-68"><a id="__codelineno-25-68" name="__codelineno-25-68" href="#__codelineno-25-68"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Last Weather Report: </span><span class="si">{</span><span class="n">final_session</span><span class="o">.</span><span class="n">state</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'last_weather_report'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Not Set'</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> <span class="c1"># Should be London weather if successful</span>
</span><span id="__span-25-69"><a id="__codelineno-25-69" name="__codelineno-25-69" href="#__codelineno-25-69"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Temperature Unit: </span><span class="si">{</span><span class="n">final_session</span><span class="o">.</span><span class="n">state</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'user_preference_temperature_unit'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Not Set'</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> <span class="c1"># Should be Fahrenheit</span>
</span><span id="__span-25-70"><a id="__codelineno-25-70" name="__codelineno-25-70" href="#__codelineno-25-70"></a> <span class="c1"># print(f"Full State Dict: {final_session.state}") # For detailed view</span>
</span><span id="__span-25-71"><a id="__codelineno-25-71" name="__codelineno-25-71" href="#__codelineno-25-71"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-25-72"><a id="__codelineno-25-72" name="__codelineno-25-72" href="#__codelineno-25-72"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">❌ Error: Could not retrieve final session state."</span><span class="p">)</span>
</span><span id="__span-25-73"><a id="__codelineno-25-73" name="__codelineno-25-73" href="#__codelineno-25-73"></a>
</span><span id="__span-25-74"><a id="__codelineno-25-74" name="__codelineno-25-74" href="#__codelineno-25-74"></a><span class="k">else</span><span class="p">:</span>
</span><span id="__span-25-75"><a id="__codelineno-25-75" name="__codelineno-25-75" href="#__codelineno-25-75"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">⚠️ Skipping tool guardrail test. Runner ('runner_root_tool_guardrail') is not available."</span><span class="p">)</span>
</span></code></pre></div>
<hr />
<p>Analyze the output:</p>
<ol>
<li><strong>New York:</strong> The <code>before_model_callback</code> allows the request. The LLM requests <code>get_weather_stateful</code>. The <code>before_tool_callback</code> runs, inspects the args (<code>{'city': 'New York'}</code>), sees it's not "Paris", prints "Allowing tool..." and returns <code>None</code>. The actual <code>get_weather_stateful</code> function executes, reads "Fahrenheit" from state, and returns the weather report. The agent relays this, and it gets saved via <code>output_key</code>.</li>
<li><strong>Paris:</strong> The <code>before_model_callback</code> allows the request. The LLM requests <code>get_weather_stateful(city='Paris')</code>. The <code>before_tool_callback</code> runs, inspects the args, detects "Paris", prints "Blocking tool execution!", sets the state flag, and returns the error dictionary <code>{'status': 'error', 'error_message': 'Policy restriction...'}</code>. The actual <code>get_weather_stateful</code> function is <strong>never executed</strong>. The agent receives the error dictionary <em>as if it were the tool's output</em> and formulates a response based on that error message.</li>
<li><strong>London:</strong> Behaves like New York, passing both callbacks and executing the tool successfully. The new London weather report overwrites the <code>last_weather_report</code> in the state.</li>
</ol>
<p>You've now added a crucial safety layer controlling not just <em>what</em> reaches the LLM, but also <em>how</em> the agent's tools can be used based on the specific arguments generated by the LLM. Callbacks like <code>before_model_callback</code> and <code>before_tool_callback</code> are essential for building robust, safe, and policy-compliant agent applications.</p>
<hr />
<h2 id="conclusion-your-agent-team-is-ready">Conclusion: Your Agent Team is Ready!<a class="headerlink" href="#conclusion-your-agent-team-is-ready" title="Permanent link">&para;</a></h2>
<p>Congratulations! You've successfully journeyed from building a single, basic weather agent to constructing a sophisticated, multi-agent team using the Agent Development Kit (ADK).</p>
<p><strong>Let's recap what you've accomplished:</strong></p>
<ul>
<li>You started with a <strong>fundamental agent</strong> equipped with a single tool (<code>get_weather</code>).</li>
<li>You explored ADK's <strong>multi-model flexibility</strong> using LiteLLM, running the same core logic with different LLMs like Gemini, GPT-4o, and Claude.</li>
<li>You embraced <strong>modularity</strong> by creating specialized sub-agents (<code>greeting_agent</code>, <code>farewell_agent</code>) and enabling <strong>automatic delegation</strong> from a root agent.</li>
<li>You gave your agents <strong>memory</strong> using <strong>Session State</strong>, allowing them to remember user preferences (<code>temperature_unit</code>) and past interactions (<code>output_key</code>).</li>
<li>You implemented crucial <strong>safety guardrails</strong> using both <code>before_model_callback</code> (blocking specific input keywords) and <code>before_tool_callback</code> (blocking tool execution based on arguments like the city "Paris").</li>
</ul>
<p>Through building this progressive Weather Bot team, you've gained hands-on experience with core ADK concepts essential for developing complex, intelligent applications.</p>
<p><strong>Key Takeaways:</strong></p>
<ul>
<li><strong>Agents &amp; Tools:</strong> The fundamental building blocks for defining capabilities and reasoning. Clear instructions and docstrings are paramount.</li>
<li><strong>Runners &amp; Session Services:</strong> The engine and memory management system that orchestrate agent execution and maintain conversational context.</li>
<li><strong>Delegation:</strong> Designing multi-agent teams allows for specialization, modularity, and better management of complex tasks. Agent <code>description</code> is key for auto-flow.</li>
<li><strong>Session State (<code>ToolContext</code>, <code>output_key</code>):</strong> Essential for creating context-aware, personalized, and multi-turn conversational agents.</li>
<li><strong>Callbacks (<code>before_model</code>, <code>before_tool</code>):</strong> Powerful hooks for implementing safety, validation, policy enforcement, and dynamic modifications <em>before</em> critical operations (LLM calls or tool execution).</li>
<li><strong>Flexibility (<code>LiteLlm</code>):</strong> ADK empowers you to choose the best LLM for the job, balancing performance, cost, and features.</li>
</ul>
<p><strong>Where to Go Next?</strong></p>
<p>Your Weather Bot team is a great starting point. Here are some ideas to further explore ADK and enhance your application:</p>
<ol>
<li><strong>Real Weather API:</strong> Replace the <code>mock_weather_db</code> in your <code>get_weather</code> tool with a call to a real weather API (like OpenWeatherMap, WeatherAPI).</li>
<li><strong>More Complex State:</strong> Store more user preferences (e.g., preferred location, notification settings) or conversation summaries in the session state.</li>
<li><strong>Refine Delegation:</strong> Experiment with different root agent instructions or sub-agent descriptions to fine-tune the delegation logic. Could you add a "forecast" agent?</li>
<li><strong>Advanced Callbacks:</strong><ul>
<li>Use <code>after_model_callback</code> to potentially reformat or sanitize the LLM's response <em>after</em> it's generated.</li>
<li>Use <code>after_tool_callback</code> to process or log the results returned by a tool.</li>
<li>Implement <code>before_agent_callback</code> or <code>after_agent_callback</code> for agent-level entry/exit logic.</li>
</ul>
</li>
<li><strong>Error Handling:</strong> Improve how the agent handles tool errors or unexpected API responses. Maybe add retry logic within a tool.</li>
<li><strong>Persistent Session Storage:</strong> Consider changing <code>InMemorySessionService</code> to one of ADK's persistent implementations, such as <code>DatabaseSessionService</code> which is SQLAlchemy-backed and installed with <code>pip install google-adk[db]</code>, or <code>VertexAiSessionService</code>. For more information, see the <a href="/sessions/session/">Session</a> page.</li>
<li><strong>Streaming UI:</strong> Integrate your agent team with a web framework (like FastAPI, as shown in the ADK Streaming Quickstart) to create a real-time chat interface.</li>
</ol>
<p>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.</p>
<p>Happy building!</p>
</article>
</div>
<script>var tabs=__md_get("__tabs");if(Array.isArray(tabs))e:for(var set of document.querySelectorAll(".tabbed-set")){var labels=set.querySelector(".tabbed-labels");for(var tab of tabs)for(var label of labels.getElementsByTagName("label"))if(label.innerText.trim()===tab){var input=document.getElementById(label.htmlFor);input.checked=!0;continue e}}</script>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
<button type="button" class="md-top md-icon" data-md-component="top" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg>
Back to top
</button>
</main>
<footer class="md-footer">
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
<div class="md-copyright__highlight">
Copyright Google 2026&nbsp;&nbsp;|&nbsp;&nbsp;<a href="//github.com/google/adk-docs/blob/main/LICENSE">License</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href="//policies.google.com/privacy">Privacy</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href="#__consent">Manage cookies</a>
</div>
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<div class="md-progress" data-md-component="progress" role="progressbar"></div>
<div class="md-consent" data-md-component="consent" id="__consent" hidden>
<div class="md-consent__overlay"></div>
<aside class="md-consent__inner">
<form class="md-consent__form md-grid md-typeset" name="consent">
<h4>Cookie consent</h4>
<p>We use cookies to recognize repeated visits and preferences, as well as to measure the effectiveness of our documentation and whether users find the information they need. With your consent, you're helping us to make our documentation better.</p>
<input class="md-toggle" type="checkbox" id="__settings" >
<div class="md-consent__settings">
<ul class="task-list">
<li class="task-list-item">
<label class="task-list-control">
<input type="checkbox" name="analytics" checked>
<span class="task-list-indicator"></span>
Google Analytics
</label>
</li>
<li class="task-list-item">
<label class="task-list-control">
<input type="checkbox" name="github" checked>
<span class="task-list-indicator"></span>
GitHub
</label>
</li>
</ul>
</div>
<div class="md-consent__controls">
<button class="md-button md-button--primary">Accept</button>
<label class="md-button" for="__settings">Manage settings</label>
</div>
</form>
</aside>
</div>
<script>var consent=__md_get("__consent");if(consent)for(var input of document.forms.consent.elements)input.name&&(input.checked=consent[input.name]||!1);else"file:"!==location.protocol&&setTimeout((function(){document.querySelector("[data-md-component=consent]").hidden=!1}),250);var form=document.forms.consent;for(var action of["submit","reset"])form.addEventListener(action,(function(e){if(e.preventDefault(),"reset"===e.type)for(var n of document.forms.consent.elements)n.name&&(n.checked=!1);__md_set("__consent",Object.fromEntries(Array.from(new FormData(form).keys()).map((function(e){return[e,!0]})))),location.hash="",location.reload()}))</script>
<script id="__config" type="application/json">{"annotate": null, "base": "../..", "features": ["content.action.edit", "content.action.view", "content.code.copy", "content.tabs.link", "content.tooltips", "navigation.indexes", "navigation.instant", "navigation.instant.progress", "navigation.path", "navigation.sections", "navigation.top", "navigation.tabs", "toc.follow"], "search": "../../assets/javascripts/workers/search.7a47a382.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
<script src="../../assets/javascripts/bundle.e71a0d61.min.js"></script>
<script src="../../javascript/copy-page.js"></script>
</body>
</html>