chore: import upstream snapshot with attribution
Continuous Integration / Pre-commit Linter (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.10) (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.11) (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.12) (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.13) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.10) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.11) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.12) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.13) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.14) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.10) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.11) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.12) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.13) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.14) (push) Waiting to run
Copybara PR Handler / close-imported-pr (push) Waiting to run

This commit is contained in:
wehub-resource-sync
2026-07-13 13:25:13 +08:00
commit ec2b666284
2231 changed files with 491535 additions and 0 deletions
@@ -0,0 +1,15 @@
# 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.
from . import agent
+160
View File
@@ -0,0 +1,160 @@
# 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.
import os
import random
from google.adk.agents.llm_agent import Agent
from google.adk.examples.example import Example
from google.adk.tools.example_tool import ExampleTool
from google.genai import types
# --- Roll Die Sub-Agent ---
def roll_die(sides: int) -> int:
"""Roll a die and return the rolled result."""
if "PYTEST_CURRENT_TEST" in os.environ:
return 2
return random.randint(1, sides)
roll_agent = Agent(
name="roll_agent",
description="Handles rolling dice of different sizes.",
instruction="""
You are responsible for rolling dice based on the user's request.
When asked to roll a die, you must call the roll_die tool with the number of sides as an integer.
""",
tools=[roll_die],
generate_content_config=types.GenerateContentConfig(
safety_settings=[
types.SafetySetting( # avoid false alarm about rolling dice.
category=types.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
threshold=types.HarmBlockThreshold.OFF,
),
]
),
)
# --- Prime Check Sub-Agent ---
def check_prime(nums: list[int]) -> str:
"""Check if a given list of numbers are prime."""
primes = set()
for number in nums:
number = int(number)
if number <= 1:
continue
is_prime = True
for i in range(2, int(number**0.5) + 1):
if number % i == 0:
is_prime = False
break
if is_prime:
primes.add(number)
return (
"No prime numbers found."
if not primes
else f"{', '.join(str(num) for num in primes)} are prime numbers."
)
example_tool = ExampleTool(
examples=[
Example(
input=types.UserContent(
parts=[types.Part(text="Roll a 6-sided die.")]
),
output=[
types.ModelContent(
parts=[types.Part(text="I rolled a 4 for you.")]
)
],
),
Example(
input=types.UserContent(
parts=[types.Part(text="Is 7 a prime number?")]
),
output=[
types.ModelContent(
parts=[types.Part(text="Yes, 7 is a prime number.")]
)
],
),
Example(
input=types.UserContent(
parts=[
types.Part(
text="Roll a 10-sided die and check if it's prime."
)
]
),
output=[
types.ModelContent(
parts=[types.Part(text="I rolled an 8 for you.")]
),
types.ModelContent(
parts=[types.Part(text="8 is not a prime number.")]
),
],
),
]
)
prime_agent = Agent(
name="prime_agent",
description="Handles checking if numbers are prime.",
instruction="""
You are responsible for checking whether numbers are prime.
When asked to check primes, you must call the check_prime tool with a list of integers.
Never attempt to determine prime numbers manually.
Return the prime number results to the root agent.
""",
tools=[check_prime],
generate_content_config=types.GenerateContentConfig(
safety_settings=[
types.SafetySetting( # avoid false alarm about rolling dice.
category=types.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
threshold=types.HarmBlockThreshold.OFF,
),
]
),
)
root_agent = Agent(
name="root_agent",
instruction="""
You are a helpful assistant that can roll dice and check if numbers are prime.
You delegate rolling dice tasks to the roll_agent and prime checking tasks to the prime_agent.
Follow these steps:
1. If the user asks to roll a die, delegate to the roll_agent.
2. If the user asks to check primes, delegate to the prime_agent.
3. If the user asks to roll a die and then check if the result is prime, call roll_agent first, then pass the result to prime_agent.
Always clarify the results before proceeding.
""",
global_instruction=(
"You are DicePrimeBot, ready to roll dice and check prime numbers."
),
sub_agents=[roll_agent, prime_agent],
tools=[example_tool],
generate_content_config=types.GenerateContentConfig(
safety_settings=[
types.SafetySetting( # avoid false alarm about rolling dice.
category=types.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
threshold=types.HarmBlockThreshold.OFF,
),
]
),
)
@@ -0,0 +1,296 @@
{
"appName": "hello_world_ma",
"events": [
{
"author": "user",
"content": {
"parts": [
{
"text": "hi"
}
],
"role": "user"
},
"id": "e-1",
"invocationId": "i-1",
"nodeInfo": {
"path": ""
}
},
{
"author": "root_agent",
"content": {
"parts": [
{
"text": "Hello! How can I help you today?"
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-2",
"invocationId": "i-1",
"nodeInfo": {
"path": "root_agent@1"
}
},
{
"author": "user",
"content": {
"parts": [
{
"text": "roll a dice of 10 dies"
}
],
"role": "user"
},
"id": "e-3",
"invocationId": "i-2",
"nodeInfo": {
"path": ""
}
},
{
"author": "root_agent",
"content": {
"parts": [
{
"functionCall": {
"args": {
"agent_name": "roll_agent"
},
"id": "fc-1",
"name": "transfer_to_agent"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-4",
"invocationId": "i-2",
"longRunningToolIds": [],
"nodeInfo": {
"path": "root_agent@1"
}
},
{
"actions": {
"transferToAgent": "roll_agent"
},
"author": "root_agent",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-1",
"name": "transfer_to_agent",
"response": {
"result": null
}
}
}
],
"role": "user"
},
"id": "e-5",
"invocationId": "i-2",
"nodeInfo": {
"path": "root_agent@1"
}
},
{
"author": "roll_agent",
"content": {
"parts": [
{
"functionCall": {
"args": {
"sides": 10
},
"id": "fc-2",
"name": "roll_die"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-6",
"invocationId": "i-2",
"longRunningToolIds": [],
"nodeInfo": {
"path": "root_agent@1/roll_agent@1"
}
},
{
"author": "roll_agent",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-2",
"name": "roll_die",
"response": {
"result": 2
}
}
}
],
"role": "user"
},
"id": "e-7",
"invocationId": "i-2",
"nodeInfo": {
"path": "root_agent@1/roll_agent@1"
}
},
{
"author": "roll_agent",
"content": {
"parts": [
{
"text": "You rolled a 2.\n"
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-8",
"invocationId": "i-2",
"nodeInfo": {
"path": "root_agent@1/roll_agent@1"
}
},
{
"author": "user",
"content": {
"parts": [
{
"text": "check it"
}
],
"role": "user"
},
"id": "e-9",
"invocationId": "i-3",
"nodeInfo": {
"path": ""
}
},
{
"author": "roll_agent",
"content": {
"parts": [
{
"functionCall": {
"args": {
"agent_name": "prime_agent"
},
"id": "fc-3",
"name": "transfer_to_agent"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-10",
"invocationId": "i-3",
"longRunningToolIds": [],
"nodeInfo": {
"path": "root_agent@1/roll_agent@1"
}
},
{
"actions": {
"transferToAgent": "prime_agent"
},
"author": "roll_agent",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-3",
"name": "transfer_to_agent",
"response": {
"result": null
}
}
}
],
"role": "user"
},
"id": "e-11",
"invocationId": "i-3",
"nodeInfo": {
"path": "root_agent@1/roll_agent@1"
}
},
{
"author": "prime_agent",
"content": {
"parts": [
{
"functionCall": {
"args": {
"nums": [
2
]
},
"id": "fc-4",
"name": "check_prime"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-12",
"invocationId": "i-3",
"longRunningToolIds": [],
"nodeInfo": {
"path": "root_agent@1/prime_agent@1"
}
},
{
"author": "prime_agent",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-4",
"name": "check_prime",
"response": {
"result": "2 are prime numbers."
}
}
}
],
"role": "user"
},
"id": "e-13",
"invocationId": "i-3",
"nodeInfo": {
"path": "root_agent@1/prime_agent@1"
}
},
{
"author": "prime_agent",
"content": {
"parts": [
{
"text": "2 are prime numbers."
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-14",
"invocationId": "i-3",
"nodeInfo": {
"path": "root_agent@1/prime_agent@1"
}
}
]
}
@@ -0,0 +1,36 @@
# Config-based Agent Sample - Learning Assistant
This sample demonstrates a minimal multi-agent setup with a learning assistant that delegates to specialized tutoring agents.
## Structure
- `root_agent.yaml` - Main learning assistant agent that routes questions to appropriate tutors
- `code_tutor_agent.yaml` - Specialized agent for programming and coding questions
- `math_tutor_agent.yaml` - Specialized agent for mathematical concepts and problems
## Usage
The root agent will automatically delegate:
- Coding/programming questions → `code_tutor_agent`
- Math questions → `math_tutor_agent`
This example shows how to create a simple multi-agent system without tools, focusing on clear delegation and specialized expertise.
## Sample Queries
### Coding Questions
```
"How do I create a for loop in Python?"
"Can you help me debug this function?"
"What are the best practices for variable naming?"
```
### Math Questions
```
"Can you explain the quadratic formula?"
"How do I solve this algebra problem: 2x + 5 = 15?"
"What's the difference between mean and median?"
```
@@ -0,0 +1,29 @@
# 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.
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
agent_class: LlmAgent
name: code_tutor_agent
description: Coding tutor that helps with programming concepts and questions.
instruction: |
You are a helpful coding tutor that specializes in teaching programming concepts.
Your role is to:
1. Explain programming concepts clearly and simply
2. Help debug code issues
3. Provide code examples and best practices
4. Guide students through problem-solving approaches
5. Encourage good coding habits
Always be patient, encouraging, and provide step-by-step explanations.
@@ -0,0 +1,29 @@
# 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.
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
agent_class: LlmAgent
name: math_tutor_agent
description: Math tutor that helps with mathematical concepts and problems.
instruction: |
You are a helpful math tutor that specializes in teaching mathematical concepts.
Your role is to:
1. Explain mathematical concepts clearly with examples
2. Help solve math problems step by step
3. Provide different approaches to solving problems
4. Help students understand the reasoning behind solutions
5. Encourage mathematical thinking and problem-solving skills
Always break down complex problems into manageable steps and be patient with explanations.
@@ -0,0 +1,31 @@
# 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.
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
agent_class: LlmAgent
model: gemini-2.5-flash
name: root_agent
description: Learning assistant that provides tutoring in code and math.
instruction: |
You are a learning assistant that helps students with coding and math questions.
You delegate coding questions to the code_tutor_agent and math questions to the math_tutor_agent.
Follow these steps:
1. If the user asks about programming or coding, delegate to the code_tutor_agent.
2. If the user asks about math concepts or problems, delegate to the math_tutor_agent.
3. Always provide clear explanations and encourage learning.
sub_agents:
- config_path: code_tutor_agent.yaml
- config_path: math_tutor_agent.yaml
@@ -0,0 +1,3 @@
# Config-based Agent Sample - LLM multi-agent
From contributing/samples/hello_world_ma/
@@ -0,0 +1,88 @@
# 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.
import random
from google.adk.examples.example import Example
from google.adk.tools.example_tool import ExampleTool
from google.genai import types
def roll_die(sides: int) -> int:
"""Roll a die and return the rolled result."""
return random.randint(1, sides)
def check_prime(nums: list[int]) -> str:
"""Check if a given list of numbers are prime."""
primes = set()
for number in nums:
number = int(number)
if number <= 1:
continue
is_prime = True
for i in range(2, int(number**0.5) + 1):
if number % i == 0:
is_prime = False
break
if is_prime:
primes.add(number)
return (
"No prime numbers found."
if not primes
else f"{', '.join(str(num) for num in primes)} are prime numbers."
)
example_tool = ExampleTool(
examples=[
Example(
input=types.UserContent(
parts=[types.Part(text="Roll a 6-sided die.")]
),
output=[
types.ModelContent(
parts=[types.Part(text="I rolled a 4 for you.")]
)
],
),
Example(
input=types.UserContent(
parts=[types.Part(text="Is 7 a prime number?")]
),
output=[
types.ModelContent(
parts=[types.Part(text="Yes, 7 is a prime number.")]
)
],
),
Example(
input=types.UserContent(
parts=[
types.Part(
text="Roll a 10-sided die and check if it's prime."
)
]
),
output=[
types.ModelContent(
parts=[types.Part(text="I rolled an 8 for you.")]
),
types.ModelContent(
parts=[types.Part(text="8 is not a prime number.")]
),
],
),
]
)
@@ -0,0 +1,26 @@
# 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.
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
agent_class: LlmAgent
model: gemini-2.5-flash
name: prime_agent
description: Handles checking if numbers are prime.
instruction: |
You are responsible for checking whether numbers are prime.
When asked to check primes, you must call the check_prime tool with a list of integers.
Never attempt to determine prime numbers manually.
Return the prime number results to the root agent.
tools:
- name: multi_agent_llm_config.check_prime
@@ -0,0 +1,25 @@
# 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.
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
agent_class: LlmAgent
model: gemini-2.5-flash
name: roll_agent
description: Handles rolling dice of different sizes.
instruction: |
You are responsible for rolling dice based on the user's request.
When asked to roll a die, you must call the roll_die tool with the number of sides as an integer.
tools:
- name: multi_agent_llm_config.roll_die
@@ -0,0 +1,40 @@
# 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.
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
agent_class: LlmAgent
model: gemini-2.5-flash
name: root_agent
description: Coordinator agent to greet users.
# global_instruction: You are DicePrimeBot, ready to roll dice and check prime numbers.
instruction: |
You are a helpful assistant that can roll dice and check if numbers are prime.
You delegate rolling dice tasks to the roll_agent and prime checking tasks to the prime_agent.
Follow these steps:
1. If the user asks to roll a die, delegate to the roll_agent.
2. If the user asks to check primes, delegate to the prime_agent.
3. If the user asks to roll a die and then check if the result is prime, call roll_agent first, then pass the result to prime_agent.
Always clarify the results before proceeding.
sub_agents:
- config_path: roll_agent.yaml
- config_path: prime_agent.yaml
tools:
- name: multi_agent_llm_config.example_tool
generate_content_config:
safety_settings:
- category: HARM_CATEGORY_DANGEROUS_CONTENT
threshold: 'OFF'
@@ -0,0 +1,16 @@
# Config-based Agent Sample - Sequential and Loop Workflow
A multi-agent setup with a sequential and loop workflow.
The whole process is:
1. An initial writing agent will author a 1-2 sentence as starting point.
1. A critic agent will review and provide feedback.
1. A refiner agent will revise based on critic agent's feedback.
1. Loop back to #2 until critic agent says "No major issues found."
Sample queries:
> initial topic: badminton
> initial topic: the history of computers
@@ -0,0 +1,22 @@
# 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.
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
agent_class: LoopAgent
name: RefinementLoop
description: Refinement loop agent.
max_iterations: 5
sub_agents:
- config_path: writer_agents/critic_agent.yaml
- config_path: writer_agents/refiner_agent.yaml
@@ -0,0 +1,21 @@
# 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.
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
agent_class: SequentialAgent
name: IterativeWritingPipeline
description: Iterative writing pipeline agent.
sub_agents:
- config_path: writer_agents/initial_writer_agent.yaml
- config_path: loop_agent.yaml
@@ -0,0 +1,46 @@
# 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.
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
agent_class: LlmAgent
name: CriticAgent
model: gemini-2.5-pro
description: Reviews the current draft, providing critique if clear improvements are needed; otherwise, signals completion.
instruction: |
You are a Constructive Critic AI reviewing a document draft (typically at least 10 sentences). Your goal is balanced feedback.
**Document to Review:**
```
{{current_document}}
```
**Task:**
Review the document for the following criteria:
- content length: at least 10 sentences;
- clarity: the content must be clear;
- engagement: the content should be engaging and relevant to the topic;
- basic coherence according to the initial topic (if known).
IF you identify 1-2 *clear and actionable* ways the document could be improved to better capture the topic or enhance reader engagement (e.g., "Needs a stronger opening sentence", "Clarify the character's goal"):
Provide these specific suggestions concisely. Output *only* the critique text.
ELSE IF the document is coherent, addresses the topic adequately for its length, and has no glaring errors or obvious omissions:
Respond *exactly* with the phrase "No major issues found." and nothing else. It doesn't need to be perfect, just functionally complete for this stage. Avoid suggesting purely subjective stylistic preferences if the core is sound.
Do not add explanations. Output only the critique OR the exact completion phrase.
IF output the critique, ONLY output JUST ONE aspect each time.
include_contents: none
output_key: criticism
@@ -0,0 +1,27 @@
# 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.
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
agent_class: LlmAgent
name: InitialWriterAgent
model: gemini-2.5-flash
description: Writes the initial document draft based on the topic, aiming for some initial substance.
instruction: |
You are a Creative Writing Assistant tasked with starting a story.
Write the *first draft* of a short story (aim for 1-2 sentences).
Base the content *only* on the topic provided by user. Try to introduce a specific element (like a character, a setting detail, or a starting action) to make it engaging.
Output *only* the story/document text. Do not add introductions or explanations.
output_key: current_document
@@ -0,0 +1,39 @@
# 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.
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
agent_class: LlmAgent
name: RefinerAgent
model: gemini-2.5-flash
description: Refines the document based on critique, or calls exit_loop if critique indicates completion.
instruction: |
You are a Creative Writing Assistant refining a document based on feedback OR exiting the process.
**Current Document:**
```
{{current_document}}
```
**Critique/Suggestions:**
{{criticism}}
**Task:**
Analyze the 'Critique/Suggestions'.
IF the critique is *exactly* "No major issues found.":
You MUST call the 'exit_loop' function. Do not output any text.
ELSE (the critique contains actionable feedback):
Carefully apply the suggestions to improve the 'Current Document'. Output *only* the refined document text.
Do not add explanations. Either output the refined document OR call the exit_loop function.
output_key: current_document
tools:
- name: exit_loop
@@ -0,0 +1,13 @@
# Config-based Agent Sample - Sequential Workflow
A multi-agent setup with a sequential workflow.
The whole process is:
1. An agent backed by a cheap and fast model to write initial version.
1. An agent backed by a smarter and a little more expensive to review the code.
1. A final agent backed by the smartest and slowest model to write the final revision.
Sample queries:
> Write a quicksort method in python
@@ -0,0 +1,22 @@
# 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.
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
agent_class: SequentialAgent
name: CodePipelineAgent
description: Executes a sequence of code writing, reviewing, and refactoring.
sub_agents:
- config_path: sub_agents/code_writer_agent.yaml
- config_path: sub_agents/code_reviewer_agent.yaml
- config_path: sub_agents/code_refactorer_agent.yaml
@@ -0,0 +1,40 @@
# 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.
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
agent_class: LlmAgent
name: CodeRefactorerAgent
model: gemini-2.5-pro
description: Refactors code based on review comments.
instruction: |
You are a Python Code Refactoring AI.
Your goal is to improve the given Python code based on the provided review comments.
**Original Code:**
```python
{generated_code}
```
**Review Comments:**
{review_comments}
**Task:**
Carefully apply the suggestions from the review comments to refactor the original code.
If the review comments state "No major issues found," return the original code unchanged.
Ensure the final code is complete, functional, and includes necessary imports and docstrings.
**Output:**
Output *only* the final, refactored Python code block, enclosed in triple backticks (```python ... ```).
Do not add any other text before or after the code block.
output_key: refactored_code
@@ -0,0 +1,40 @@
# 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.
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
agent_class: LlmAgent
name: CodeReviewerAgent
model: gemini-2.5-flash
description: Reviews code and provides feedback.
instruction: |
You are an expert Python Code Reviewer.
Your task is to provide constructive feedback on the provided code.
**Code to Review:**
```python
{generated_code}
```
**Review Criteria:**
1. **Correctness:** Does the code work as intended? Are there logic errors?
2. **Readability:** Is the code clear and easy to understand? Follows PEP 8 style guidelines?
3. **Efficiency:** Is the code reasonably efficient? Any obvious performance bottlenecks?
4. **Edge Cases:** Does the code handle potential edge cases or invalid inputs gracefully?
5. **Best Practices:** Does the code follow common Python best practices?
**Output:**
Provide your feedback as a concise, bulleted list. Focus on the most important points for improvement.
If the code is excellent and requires no changes, simply state: "No major issues found."
Output *only* the review comments or the "No major issues" statement.
output_key: review_comments
@@ -0,0 +1,25 @@
# 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.
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
agent_class: LlmAgent
name: CodeWriterAgent
model: gemini-2.5-flash
description: Writes initial Python code based on a specification.
instruction: |
You are a Python Code Generator.
Based *only* on the user's request, write Python code that fulfills the requirement.
Output *only* the complete Python code block, enclosed in triple backticks (```python ... ```).
Do not add any other text before or after the code block.
output_key: generated_code
@@ -0,0 +1,56 @@
# ADK Single-turn Agent as Sub-agent Sample
## Overview
This sample demonstrates how a "single_turn" mode agent can act as an autonomous sub-agent to an LLM agent, utilizing schemas and tools without ever interacting with the user.
**Note**: This is the recommended mechanism to replace the older `AgentTool` pattern. Unlike `AgentTool`, using a `single_turn` sub-agent preserves the sub-agent's internal interactions (like tool calls) in the session history.
Single-turn agents are designed to execute their function fully in one prompt-response cycle. In this sample:
1. `phone_recommender`: A single-turn agent that receives structured input (`UserPreferences`), uses a mocked tool (`check_phone_price`), and returns structured output (`PhoneRecommendation`).
1. `root_agent`: The main agent that interacts with the user, translates their natural language request into the structured `UserPreferences`, and delegates to `phone_recommender`.
## Sample Inputs
- `I need a phone mostly for gaming. I have about $1000 to spend.`
- `What is a good cheap phone from Google for basic tasks?`
- `I love photography but prefer smaller phones. My budget is $600.`
## Graph
```mermaid
graph TD
root_agent --> phone_recommender
phone_recommender -.->|uses| check_phone_price[check_phone_price tool]
```
## How To
1. Define a sub-agent with `mode="single_turn"`, `input_schema`, `output_schema`:
```python
phone_recommender = Agent(
name="phone_recommender",
mode="single_turn",
input_schema=UserPreferences,
output_schema=PhoneRecommendation,
tools=[check_phone_price],
...
)
```
1. Assign it to a parent agent:
```python
root_agent = Agent(
sub_agents=[phone_recommender],
...
)
```
## Related Guides
- [LlmAgent Single-Turn Mode](../../../../docs/guides/agents/llm_agent/single_turn.md) - Guide explaining the behavior and configuration of single-turn agents.
@@ -0,0 +1,81 @@
# 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.
from google.adk import Agent
from pydantic import BaseModel
from pydantic import Field
class UserPreferences(BaseModel):
budget: int = Field(description="The user's maximum budget in USD")
primary_use: str = Field(
description=(
"What the user primarily uses their phone for (e.g., photography,"
" gaming, basics)"
)
)
preferred_size: str = Field(
description="Preferred phone size (e.g., small, large, any)"
)
class PhoneRecommendation(BaseModel):
"""Output schema for the phone recommendation."""
model_name: str
price: float
reason: str
def check_phone_price(model_name: str) -> float:
"""Mock tool to check the current price of a Pixel phone model."""
prices = {
"Pixel 10a": 499.0,
"Pixel 10": 799.0,
"Pixel 10 Pro": 999.0,
"Pixel 10 Pro XL": 1199.0,
"Pixel 10 Pro Fold": 1799.0,
}
# Simple mock logic, defaulting to 799 if not found exactly
for key, value in prices.items():
if key.lower() in model_name.lower():
return value
return 799.0
phone_recommender = Agent(
name="phone_recommender",
mode="single_turn",
input_schema=UserPreferences,
output_schema=PhoneRecommendation,
tools=[check_phone_price],
instruction=("""\
You are an expert Google Pixel hardware recommender.
Based on the provided UserPreferences, recommend exactly one Pixel phone model.
You must use the `check_phone_price` tool to find the exact current price of the model you are recommending before you finish your task.
Only recommend these phones: Pixel 10a, Pixel 10, Pixel 10 Pro, Pixel 10 Pro XL, Pixel 10 Pro Fold.
"""),
description="Recommends a Pixel phone based on preferences.",
)
root_agent = Agent(
name="root_agent",
sub_agents=[phone_recommender],
instruction=("""\
You are a helpful phone sales associate.
If the user is asking for a phone recommendation, use the `phone_recommender` to get a structured recommendation.
Once the recommender finishes, present the model, price, and reason to the user in a friendly way.
"""),
)
@@ -0,0 +1,440 @@
{
"events": [
{
"author": "user",
"content": {
"parts": [
{
"text": "gaming, $1000"
}
],
"role": "user"
},
"id": "e-1",
"invocationId": "i-1",
"nodeInfo": {
"path": ""
}
},
{
"author": "root_agent",
"content": {
"parts": [
{
"text": "That sounds like a great budget for a gaming phone! To give you the best recommendation, could you tell me what size phone you prefer? Do you like something **small**, **large**, or is **any** size okay with you?"
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-2",
"invocationId": "i-1",
"nodeInfo": {
"path": "root_agent@1"
}
},
{
"author": "user",
"content": {
"parts": [
{
"text": "large"
}
],
"role": "user"
},
"id": "e-3",
"invocationId": "i-2",
"nodeInfo": {
"path": ""
}
},
{
"author": "root_agent",
"content": {
"parts": [
{
"functionCall": {
"args": {
"budget": 1000,
"preferred_size": "large",
"primary_use": "gaming"
},
"id": "fc-1",
"name": "phone_recommender"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-4",
"invocationId": "i-2",
"longRunningToolIds": [],
"nodeInfo": {
"path": "root_agent@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionCall": {
"args": {
"model_name": "Pixel 10 Pro XL"
},
"id": "fc-2",
"name": "check_phone_price"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-5",
"invocationId": "i-2",
"longRunningToolIds": [],
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-2",
"name": "check_phone_price",
"response": {
"result": 799.0
}
}
}
],
"role": "user"
},
"id": "e-6",
"invocationId": "i-2",
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionCall": {
"args": {
"model_name": "Pixel 10 Pro Fold"
},
"id": "fc-3",
"name": "check_phone_price"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-7",
"invocationId": "i-2",
"longRunningToolIds": [],
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-3",
"name": "check_phone_price",
"response": {
"result": 799.0
}
}
}
],
"role": "user"
},
"id": "e-8",
"invocationId": "i-2",
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionCall": {
"args": {
"model_name": "Pixel 10 Pro"
},
"id": "fc-4",
"name": "check_phone_price"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-9",
"invocationId": "i-2",
"longRunningToolIds": [],
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-4",
"name": "check_phone_price",
"response": {
"result": 799.0
}
}
}
],
"role": "user"
},
"id": "e-10",
"invocationId": "i-2",
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionCall": {
"args": {
"model_name": "Pixel 10"
},
"id": "fc-5",
"name": "check_phone_price"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-11",
"invocationId": "i-2",
"longRunningToolIds": [],
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-5",
"name": "check_phone_price",
"response": {
"result": 799.0
}
}
}
],
"role": "user"
},
"id": "e-12",
"invocationId": "i-2",
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionCall": {
"args": {
"model_name": "Pixel 10a"
},
"id": "fc-6",
"name": "check_phone_price"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-13",
"invocationId": "i-2",
"longRunningToolIds": [],
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-6",
"name": "check_phone_price",
"response": {
"result": 499.0
}
}
}
],
"role": "user"
},
"id": "e-14",
"invocationId": "i-2",
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionCall": {
"args": {
"model_name": "Pixel 10 Pro XL",
"price": 799,
"reason": "The Pixel 10 Pro XL is the best fit for your gaming needs and preference for a large screen. At $799, it is well within your $1000 budget and provides the high performance and large display area required for an optimal gaming experience."
},
"id": "fc-7",
"name": "set_model_response"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-15",
"invocationId": "i-2",
"longRunningToolIds": [],
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"actions": {
"setModelResponse": {
"model_name": "Pixel 10 Pro XL",
"price": 799.0,
"reason": "The Pixel 10 Pro XL is the best fit for your gaming needs and preference for a large screen. At $799, it is well within your $1000 budget and provides the high performance and large display area required for an optimal gaming experience."
}
},
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-7",
"name": "set_model_response",
"response": {
"model_name": "Pixel 10 Pro XL",
"price": 799.0,
"reason": "The Pixel 10 Pro XL is the best fit for your gaming needs and preference for a large screen. At $799, it is well within your $1000 budget and provides the high performance and large display area required for an optimal gaming experience."
}
}
}
],
"role": "user"
},
"id": "e-16",
"invocationId": "i-2",
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"text": "{\"model_name\": \"Pixel 10 Pro XL\", \"price\": 799.0, \"reason\": \"The Pixel 10 Pro XL is the best fit for your gaming needs and preference for a large screen. At $799, it is well within your $1000 budget and provides the high performance and large display area required for an optimal gaming experience.\"}"
}
],
"role": "model"
},
"id": "e-17",
"invocationId": "i-2",
"nodeInfo": {
"messageAsOutput": true,
"outputFor": [
"root_agent@1/phone_recommender@1"
],
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "root_agent",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-1",
"name": "phone_recommender",
"response": {
"model_name": "Pixel 10 Pro XL",
"price": 799.0,
"reason": "The Pixel 10 Pro XL is the best fit for your gaming needs and preference for a large screen. At $799, it is well within your $1000 budget and provides the high performance and large display area required for an optimal gaming experience."
}
}
}
],
"role": "user"
},
"id": "e-18",
"invocationId": "i-2",
"nodeInfo": {
"path": "root_agent@1"
}
},
{
"author": "root_agent",
"content": {
"parts": [
{
"text": "OK! Based on what you're looking for, I recommend the **Pixel 10 Pro XL**.\n\n* **Price:** $799\n* **Why it's for you:** It\u2019s the perfect fit for your gaming needs and preference for a large screen. Since it's $799, it's well under your $1,000 budget while providing the high performance and large display area you need for the best gaming experience."
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-19",
"invocationId": "i-2",
"nodeInfo": {
"path": "root_agent@1"
}
}
]
}
@@ -0,0 +1,359 @@
{
"events": [
{
"author": "user",
"content": {
"parts": [
{
"text": "gaming, $1000, large"
}
],
"role": "user"
},
"id": "e-1",
"invocationId": "i-1",
"nodeInfo": {
"path": ""
}
},
{
"author": "root_agent",
"content": {
"parts": [
{
"functionCall": {
"args": {
"budget": 1000,
"preferred_size": "large",
"primary_use": "gaming"
},
"id": "fc-1",
"name": "phone_recommender"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-2",
"invocationId": "i-1",
"longRunningToolIds": [],
"nodeInfo": {
"path": "root_agent@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionCall": {
"args": {
"model_name": "Pixel 10 Pro XL"
},
"id": "fc-2",
"name": "check_phone_price"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-3",
"invocationId": "i-1",
"longRunningToolIds": [],
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-2",
"name": "check_phone_price",
"response": {
"result": 799.0
}
}
}
],
"role": "user"
},
"id": "e-4",
"invocationId": "i-1",
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionCall": {
"args": {
"model_name": "Pixel 10 Pro"
},
"id": "fc-3",
"name": "check_phone_price"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-5",
"invocationId": "i-1",
"longRunningToolIds": [],
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-3",
"name": "check_phone_price",
"response": {
"result": 799.0
}
}
}
],
"role": "user"
},
"id": "e-6",
"invocationId": "i-1",
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionCall": {
"args": {
"model_name": "Pixel 10 Pro Fold"
},
"id": "fc-4",
"name": "check_phone_price"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-7",
"invocationId": "i-1",
"longRunningToolIds": [],
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-4",
"name": "check_phone_price",
"response": {
"result": 799.0
}
}
}
],
"role": "user"
},
"id": "e-8",
"invocationId": "i-1",
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionCall": {
"args": {
"model_name": "Pixel 10"
},
"id": "fc-5",
"name": "check_phone_price"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-9",
"invocationId": "i-1",
"longRunningToolIds": [],
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-5",
"name": "check_phone_price",
"response": {
"result": 799.0
}
}
}
],
"role": "user"
},
"id": "e-10",
"invocationId": "i-1",
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionCall": {
"args": {
"model_name": "Pixel 10 Pro XL",
"price": 799,
"reason": "The Pixel 10 Pro XL is the best choice for gaming due to its large screen and high performance. It fits perfectly within your $1000 budget and satisfies your preference for a large device."
},
"id": "fc-6",
"name": "set_model_response"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-11",
"invocationId": "i-1",
"longRunningToolIds": [],
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"actions": {
"setModelResponse": {
"model_name": "Pixel 10 Pro XL",
"price": 799.0,
"reason": "The Pixel 10 Pro XL is the best choice for gaming due to its large screen and high performance. It fits perfectly within your $1000 budget and satisfies your preference for a large device."
}
},
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-6",
"name": "set_model_response",
"response": {
"model_name": "Pixel 10 Pro XL",
"price": 799.0,
"reason": "The Pixel 10 Pro XL is the best choice for gaming due to its large screen and high performance. It fits perfectly within your $1000 budget and satisfies your preference for a large device."
}
}
}
],
"role": "user"
},
"id": "e-12",
"invocationId": "i-1",
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"text": "{\"model_name\": \"Pixel 10 Pro XL\", \"price\": 799.0, \"reason\": \"The Pixel 10 Pro XL is the best choice for gaming due to its large screen and high performance. It fits perfectly within your $1000 budget and satisfies your preference for a large device.\"}"
}
],
"role": "model"
},
"id": "e-13",
"invocationId": "i-1",
"nodeInfo": {
"messageAsOutput": true,
"outputFor": [
"root_agent@1/phone_recommender@1"
],
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "root_agent",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-1",
"name": "phone_recommender",
"response": {
"model_name": "Pixel 10 Pro XL",
"price": 799.0,
"reason": "The Pixel 10 Pro XL is the best choice for gaming due to its large screen and high performance. It fits perfectly within your $1000 budget and satisfies your preference for a large device."
}
}
}
],
"role": "user"
},
"id": "e-14",
"invocationId": "i-1",
"nodeInfo": {
"path": "root_agent@1"
}
},
{
"author": "root_agent",
"content": {
"parts": [
{
"text": "OK! Based on your preferences, I recommend the **Pixel 10 Pro XL**.\n\n* **Model:** Pixel 10 Pro XL\n* **Price:** $799\n* **Why it's for you:** The Pixel 10 Pro XL is the best choice for gaming due to its large screen and high performance. It fits perfectly within your $1000 budget and satisfies your preference for a large device."
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-15",
"invocationId": "i-1",
"nodeInfo": {
"path": "root_agent@1"
}
}
]
}
@@ -0,0 +1,383 @@
{
"events": [
{
"author": "user",
"content": {
"parts": [
{
"text": "go"
}
],
"role": "user"
},
"id": "e-1",
"invocationId": "i-1",
"nodeInfo": {
"path": ""
}
},
{
"author": "root_agent",
"content": {
"parts": [
{
"text": "Hello! I'm here to help you find the perfect Pixel phone. \n\nTo get started, could you tell me a bit about what you're looking for? Specifically:\n\n1. **What is your maximum budget?**\n2. **What size phone do you prefer?** (e.g., small, large, or doesn't matter)\n3. **What will be your primary use for the phone?** (e.g., photography, gaming, just the basics)\n\nOnce I have those details, I can give you a great recommendation!"
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-2",
"invocationId": "i-1",
"nodeInfo": {
"path": "root_agent@1"
}
},
{
"author": "user",
"content": {
"parts": [
{
"text": "$1000, gaming"
}
],
"role": "user"
},
"id": "e-3",
"invocationId": "i-2",
"nodeInfo": {
"path": ""
}
},
{
"author": "root_agent",
"content": {
"parts": [
{
"text": "That sounds like a great budget for a gaming-focused phone! To make sure I get the recommendation just right, **what size phone do you prefer?** (e.g., small, large, or any size)."
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-4",
"invocationId": "i-2",
"nodeInfo": {
"path": "root_agent@1"
}
},
{
"author": "user",
"content": {
"parts": [
{
"text": "large"
}
],
"role": "user"
},
"id": "e-5",
"invocationId": "i-3",
"nodeInfo": {
"path": ""
}
},
{
"author": "root_agent",
"content": {
"parts": [
{
"functionCall": {
"args": {
"budget": 1000,
"preferred_size": "large",
"primary_use": "gaming"
},
"id": "fc-1",
"name": "phone_recommender"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-6",
"invocationId": "i-3",
"longRunningToolIds": [],
"nodeInfo": {
"path": "root_agent@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionCall": {
"args": {
"model_name": "Pixel 10 Pro XL"
},
"id": "fc-2",
"name": "check_phone_price"
}
},
{
"functionCall": {
"args": {
"model_name": "Pixel 10 Pro Fold"
},
"id": "fc-3",
"name": "check_phone_price"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-7",
"invocationId": "i-3",
"longRunningToolIds": [],
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-2",
"name": "check_phone_price",
"response": {
"result": 799.0
}
}
},
{
"functionResponse": {
"id": "fc-3",
"name": "check_phone_price",
"response": {
"result": 799.0
}
}
}
],
"role": "user"
},
"id": "e-8",
"invocationId": "i-3",
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionCall": {
"args": {
"model_name": "Pixel 10a"
},
"id": "fc-4",
"name": "check_phone_price"
}
},
{
"functionCall": {
"args": {
"model_name": "Pixel 10"
},
"id": "fc-5",
"name": "check_phone_price"
}
},
{
"functionCall": {
"args": {
"model_name": "Pixel 10 Pro"
},
"id": "fc-6",
"name": "check_phone_price"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-9",
"invocationId": "i-3",
"longRunningToolIds": [],
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-4",
"name": "check_phone_price",
"response": {
"result": 499.0
}
}
},
{
"functionResponse": {
"id": "fc-5",
"name": "check_phone_price",
"response": {
"result": 799.0
}
}
},
{
"functionResponse": {
"id": "fc-6",
"name": "check_phone_price",
"response": {
"result": 799.0
}
}
}
],
"role": "user"
},
"id": "e-10",
"invocationId": "i-3",
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionCall": {
"args": {
"model_name": "Pixel 10 Pro XL",
"price": 799,
"reason": "The Pixel 10 Pro XL fits your budget of $1000 and matches your preference for a large screen, which is ideal for gaming. At $799, it offers the best balance of performance and display size within your requirements."
},
"id": "fc-7",
"name": "set_model_response"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-11",
"invocationId": "i-3",
"longRunningToolIds": [],
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"actions": {
"setModelResponse": {
"model_name": "Pixel 10 Pro XL",
"price": 799.0,
"reason": "The Pixel 10 Pro XL fits your budget of $1000 and matches your preference for a large screen, which is ideal for gaming. At $799, it offers the best balance of performance and display size within your requirements."
}
},
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-7",
"name": "set_model_response",
"response": {
"model_name": "Pixel 10 Pro XL",
"price": 799.0,
"reason": "The Pixel 10 Pro XL fits your budget of $1000 and matches your preference for a large screen, which is ideal for gaming. At $799, it offers the best balance of performance and display size within your requirements."
}
}
}
],
"role": "user"
},
"id": "e-12",
"invocationId": "i-3",
"nodeInfo": {
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "phone_recommender",
"branch": "phone_recommender@fc-1",
"content": {
"parts": [
{
"text": "{\"model_name\": \"Pixel 10 Pro XL\", \"price\": 799.0, \"reason\": \"The Pixel 10 Pro XL fits your budget of $1000 and matches your preference for a large screen, which is ideal for gaming. At $799, it offers the best balance of performance and display size within your requirements.\"}"
}
],
"role": "model"
},
"id": "e-13",
"invocationId": "i-3",
"nodeInfo": {
"messageAsOutput": true,
"outputFor": [
"root_agent@1/phone_recommender@1"
],
"path": "root_agent@1/phone_recommender@1"
}
},
{
"author": "root_agent",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-1",
"name": "phone_recommender",
"response": {
"model_name": "Pixel 10 Pro XL",
"price": 799.0,
"reason": "The Pixel 10 Pro XL fits your budget of $1000 and matches your preference for a large screen, which is ideal for gaming. At $799, it offers the best balance of performance and display size within your requirements."
}
}
}
],
"role": "user"
},
"id": "e-14",
"invocationId": "i-3",
"nodeInfo": {
"path": "root_agent@1"
}
},
{
"author": "root_agent",
"content": {
"parts": [
{
"text": "Based on what you're looking for, I highly recommend the **Pixel 10 Pro XL**.\n\n* **Model:** Pixel 10 Pro XL\n* **Price:** $799\n* **Why it's perfect for you:** It fits perfectly within your $1000 budget and features the large display you prefer, which is fantastic for an immersive gaming experience. It offers a great balance of top-tier performance and screen real estate!\n\nHow does that sound to you?"
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-15",
"invocationId": "i-3",
"nodeInfo": {
"path": "root_agent@1"
}
}
]
}
@@ -0,0 +1,72 @@
# ADK Agent Sub-Agents Sample
## Overview
This sample demonstrates how to create a hierarchical agent setup using sub-agents in the **ADK** framework, and also showcases how to use tool confirmation.
It defines a root `Agent` named `sub_agents` that coordinates two sub-agents: `info_agent` and `close_agent`.
- `info_agent` is equipped with a tool to check account status.
- `close_agent` is equipped with a tool to close accounts, which requires user confirmation before execution.
The root agent delegates tasks to these sub-agents based on the user's prompt. This sample illustrates how to modularize capabilities into separate agents instead of combining all tools on a single agent.
## Sample Inputs
- `Check the status of account ACC-123.`
- `Close account ACC-123.`
- `Check if account ACC-123 is active, and if so, close it.`
## Graph
```mermaid
graph TD
sub_agents[Agent: sub_agents] --> info_agent[Agent: info_agent]
sub_agents --> close_agent[Agent: close_agent]
info_agent --> get_account_status[Tool: get_account_status]
close_agent --> close_account[Tool: close_account <br/>requires confirmation]
```
## How To
1. Define the specific tools for each sub-agent:
```python
def get_account_status(account_id: str) -> str:
"""Gets the status of a bank account."""
return f"Account {account_id} is active."
def close_account(account_id: str) -> str:
"""Closes a bank account."""
return f"Account {account_id} has been closed."
```
1. Register tools to their respective sub-agents, using `FunctionTool` for confirmation:
```python
from google.adk.agents import Agent
from google.adk.tools.function_tool import FunctionTool
info_agent = Agent(
name="info_agent",
description="An agent that can check account status.",
tools=[get_account_status],
)
close_agent = Agent(
name="close_agent",
description="An agent that can close accounts.",
tools=[FunctionTool(func=close_account, require_confirmation=True)],
)
```
1. Add the sub-agents to the root agent's `sub_agents` list:
```python
root_agent = Agent(
name="sub_agents",
sub_agents=[info_agent, close_agent],
)
```
@@ -0,0 +1,15 @@
# 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.
from . import agent
@@ -0,0 +1,64 @@
# 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.
from __future__ import annotations
from google.adk.agents import Agent
from google.adk.tools.function_tool import FunctionTool
def get_account_status(account_id: str) -> str:
"""Gets the status of a bank account.
Args:
account_id: The account ID to check.
Returns:
The status of the account.
"""
return f"Account {account_id} is active."
def close_account(account_id: str) -> str:
"""Closes a bank account. This action requires user confirmation.
Args:
account_id: The account ID to close.
Returns:
A confirmation message.
"""
return f"Account {account_id} has been closed."
info_agent = Agent(
name="info_agent",
description="An agent that can check account status.",
tools=[get_account_status],
)
close_agent = Agent(
name="close_agent",
description="An agent that can close accounts.",
tools=[FunctionTool(func=close_account, require_confirmation=True)],
)
root_agent = Agent(
name="sub_agents",
description=(
"A root agent that can check accounts and close them by delegating to"
" sub-agents."
),
sub_agents=[info_agent, close_agent],
)
@@ -0,0 +1,315 @@
{
"events": [
{
"author": "user",
"content": {
"parts": [
{
"text": "Check if account ACC-123 is active, and if so, close it."
}
],
"role": "user"
},
"id": "e-1",
"invocationId": "i-1",
"nodeInfo": {
"path": ""
}
},
{
"author": "sub_agents",
"content": {
"parts": [
{
"functionCall": {
"args": {
"agent_name": "info_agent"
},
"id": "fc-1",
"name": "transfer_to_agent"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-2",
"invocationId": "i-1",
"longRunningToolIds": [],
"nodeInfo": {
"path": "sub_agents@1"
}
},
{
"actions": {
"transferToAgent": "info_agent"
},
"author": "sub_agents",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-1",
"name": "transfer_to_agent",
"response": {
"result": null
}
}
}
],
"role": "user"
},
"id": "e-3",
"invocationId": "i-1",
"nodeInfo": {
"path": "sub_agents@1"
}
},
{
"author": "info_agent",
"content": {
"parts": [
{
"functionCall": {
"args": {
"account_id": "ACC-123"
},
"id": "fc-2",
"name": "get_account_status"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-4",
"invocationId": "i-1",
"longRunningToolIds": [],
"nodeInfo": {
"path": "sub_agents@1/info_agent@1"
}
},
{
"author": "info_agent",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-2",
"name": "get_account_status",
"response": {
"result": "Account ACC-123 is active."
}
}
}
],
"role": "user"
},
"id": "e-5",
"invocationId": "i-1",
"nodeInfo": {
"path": "sub_agents@1/info_agent@1"
}
},
{
"author": "info_agent",
"content": {
"parts": [
{
"functionCall": {
"args": {
"agent_name": "close_agent"
},
"id": "fc-3",
"name": "transfer_to_agent"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-6",
"invocationId": "i-1",
"longRunningToolIds": [],
"nodeInfo": {
"path": "sub_agents@1/info_agent@1"
}
},
{
"actions": {
"transferToAgent": "close_agent"
},
"author": "info_agent",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-3",
"name": "transfer_to_agent",
"response": {
"result": null
}
}
}
],
"role": "user"
},
"id": "e-7",
"invocationId": "i-1",
"nodeInfo": {
"path": "sub_agents@1/info_agent@1"
}
},
{
"author": "close_agent",
"content": {
"parts": [
{
"functionCall": {
"args": {
"account_id": "ACC-123"
},
"id": "fc-4",
"name": "close_account"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-8",
"invocationId": "i-1",
"longRunningToolIds": [],
"nodeInfo": {
"path": "sub_agents@1/close_agent@1"
}
},
{
"author": "close_agent",
"content": {
"parts": [
{
"functionCall": {
"args": {
"originalFunctionCall": {
"args": {
"account_id": "ACC-123"
},
"id": "fc-4",
"name": "close_account"
},
"toolConfirmation": {
"confirmed": false,
"hint": "Please approve or reject the tool call close_account() by responding with a FunctionResponse with an expected ToolConfirmation payload."
}
},
"id": "fc-5",
"name": "adk_request_confirmation"
}
}
],
"role": "model"
},
"id": "e-9",
"invocationId": "i-1",
"longRunningToolIds": [
"fc-5"
],
"nodeInfo": {
"path": "sub_agents@1/close_agent@1"
}
},
{
"actions": {
"requestedToolConfirmations": {
"fc-4": {
"confirmed": false,
"hint": "Please approve or reject the tool call close_account() by responding with a FunctionResponse with an expected ToolConfirmation payload."
}
},
"skipSummarization": true
},
"author": "close_agent",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-4",
"name": "close_account",
"response": {
"error": "This tool call requires confirmation, please approve or reject."
}
}
}
],
"role": "user"
},
"id": "e-10",
"invocationId": "i-1",
"nodeInfo": {
"path": "sub_agents@1/close_agent@1"
}
},
{
"author": "user",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-5",
"name": "adk_request_confirmation",
"response": {
"confirmed": true
}
}
}
],
"role": "user"
},
"id": "e-11",
"invocationId": "i-1",
"nodeInfo": {
"path": ""
}
},
{
"author": "close_agent",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-4",
"name": "close_account",
"response": {
"result": "Account ACC-123 has been closed."
}
}
}
],
"role": "user"
},
"id": "e-12",
"invocationId": "i-1",
"nodeInfo": {
"path": "sub_agents@1/close_agent@1"
}
},
{
"author": "close_agent",
"content": {
"parts": [
{
"text": "Account ACC-123 has been closed."
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-13",
"invocationId": "i-1",
"nodeInfo": {
"path": "sub_agents@1/close_agent@1"
}
}
]
}
@@ -0,0 +1,132 @@
{
"events": [
{
"author": "user",
"content": {
"parts": [
{
"text": "Check the status of account ACC-123"
}
],
"role": "user"
},
"id": "e-1",
"invocationId": "i-1",
"nodeInfo": {
"path": ""
}
},
{
"author": "sub_agents",
"content": {
"parts": [
{
"functionCall": {
"args": {
"agent_name": "info_agent"
},
"id": "fc-1",
"name": "transfer_to_agent"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-2",
"invocationId": "i-1",
"longRunningToolIds": [],
"nodeInfo": {
"path": "sub_agents@1"
}
},
{
"actions": {
"transferToAgent": "info_agent"
},
"author": "sub_agents",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-1",
"name": "transfer_to_agent",
"response": {
"result": null
}
}
}
],
"role": "user"
},
"id": "e-3",
"invocationId": "i-1",
"nodeInfo": {
"path": "sub_agents@1"
}
},
{
"author": "info_agent",
"content": {
"parts": [
{
"functionCall": {
"args": {
"account_id": "ACC-123"
},
"id": "fc-2",
"name": "get_account_status"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-4",
"invocationId": "i-1",
"longRunningToolIds": [],
"nodeInfo": {
"path": "sub_agents@1/info_agent@1"
}
},
{
"author": "info_agent",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-2",
"name": "get_account_status",
"response": {
"result": "Account ACC-123 is active."
}
}
}
],
"role": "user"
},
"id": "e-5",
"invocationId": "i-1",
"nodeInfo": {
"path": "sub_agents@1/info_agent@1"
}
},
{
"author": "info_agent",
"content": {
"parts": [
{
"text": "Account ACC-123 is active."
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-6",
"invocationId": "i-1",
"nodeInfo": {
"path": "sub_agents@1/info_agent@1"
}
}
]
}
@@ -0,0 +1,13 @@
# 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.
@@ -0,0 +1,24 @@
# 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.
from google.adk.agents import LlmAgent
agent = LlmAgent(
name="life_agent",
description="Life agent",
instruction=(
"You are a life agent. You are responsible for answering"
" questions about life."
),
)
@@ -0,0 +1,25 @@
# 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.
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
name: root_agent
model: gemini-2.5-flash
description: Root agent
instruction: |
If the user query is about life, you should route it to the life sub-agent.
If the user query is about work, you should route it to the work sub-agent.
If the user query is about anything else, you should answer it yourself.
sub_agents:
- config_path: ./work_agent.yaml
- code: sub_agents_config.life_agent.agent
@@ -0,0 +1,19 @@
# 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.
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
name: work_agent
description: Work agent
instruction: |
You are a work agent. You are responsible for answering questions about work.
@@ -0,0 +1,56 @@
# ADK Task as Sub-agent Sample
## Overview
This sample demonstrates how a "task mode" agent can act as a sub-agent to an LLM agent, effectively extracting structured data from a conversational flow.
The main agent (`coordinator`) delegates interactions to two sub-agents:
1. `order_collector`: A task agent that collects the user's food order (from a menu of Pizza, Burger, Salad) and returns a structured list of selected items as a `list[OrderItem]`.
1. `payment_collector`: A task agent that collects the user's credit card and CVV information, returning a `PaymentInfo` object.
Once the tasks are completed, the coordinator automatically uses a `place_order` tool with the structured data returned by both agents.
## Sample Inputs
- `I would like to order some food please.`
- `I want 2 pizzas and 1 salad.`
- `My credit card is 1234-5678-9012-3456 and my CVV is 123.`
## Graph
```mermaid
graph TD
coordinator --> order_collector
coordinator --> payment_collector
coordinator -.->|uses| place_order[place_order tool]
```
## How To
1. Define a sub-agent with `mode="task"` and an output schema:
```python
order_collector = Agent(
name="order_collector",
mode="task",
output_schema=list[OrderItem],
...
)
```
1. Assign it to a parent agent and use it in the instruction to collect the information:
```python
coordinator = Agent(
sub_agents=[order_collector],
instruction="Delegate using `order_collector`...",
...
)
```
## Related Guides
- [LlmAgent Task Mode](../../../../docs/guides/agents/llm_agent/task.md) - Guide explaining the behavior and configuration of task-mode agents.
@@ -0,0 +1,83 @@
# 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.
from __future__ import annotations
from google.adk import Agent
from google.adk.tools.function_tool import FunctionTool
from pydantic import BaseModel
from pydantic import Field
class OrderItem(BaseModel):
name: str = Field(description="Name of the food item ordered")
quantity: int = Field(description="Quantity ordered")
class PaymentInfo(BaseModel):
"""Output schema for the payment collection task."""
credit_card_number: str
cvv: str
def place_order(orders: list[OrderItem], payment_info: PaymentInfo) -> str:
"""Mock an order placement operation."""
total_items = sum(item.quantity for item in orders)
return f"Successfully placed order for {total_items} items."
def confirmation() -> str:
"""Confirm proceeding with the order."""
return "Proceeding with order."
order_collector = Agent(
name="order_collector",
mode="task",
output_schema=list[OrderItem],
instruction=("""\
You are an order collection assistant for a food delivery service.
Our menu today has exactly 3 items: 1. Pizza, 2. Burger, 3. Salad.
Ask the user what they would like to order and collect their choice and quantity.
Do not offer anything else.
If the combined quantity of items exceeds 5, you MUST use the `confirmation` tool to get user's confirmation before proceeding.
Do not ask for confirmation in natural language, always use the confirmation tool.
Once you have their final order and confirmation if needed, finish your task.
"""),
description="Collects the food order from the user.",
tools=[FunctionTool(confirmation, require_confirmation=True)],
)
payment_collector = Agent(
name="payment_collector",
mode="task",
output_schema=PaymentInfo,
instruction=("""\
You are a payment collection assistant.
Ask the user for their credit card number and CVV.
Once you have both pieces of information, finish your task.
"""),
description="Collects credit card and CVV from the user.",
)
root_agent = Agent(
name="coordinator",
sub_agents=[order_collector, payment_collector],
tools=[place_order],
instruction="""\
You are a helpful coordinator for a food delivery service.
You need both order and payment information to place an order.
""",
)
@@ -0,0 +1,224 @@
{
"events": [
{
"author": "user",
"content": {
"parts": [
{
"text": "10 burgers"
}
],
"role": "user"
},
"id": "e-1",
"invocationId": "i-1",
"nodeInfo": {
"path": ""
}
},
{
"author": "coordinator",
"content": {
"parts": [
{
"functionCall": {
"args": {
"request": "The user wants 10 burgers. Please confirm the details of the burgers and any other items they might want."
},
"id": "fc-1",
"name": "order_collector"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-2",
"invocationId": "i-1",
"longRunningToolIds": [],
"nodeInfo": {
"path": "coordinator@1"
}
},
{
"author": "order_collector",
"content": {
"parts": [
{
"text": "I've noted that you'd like 10 burgers. Would you like to add any pizza or salad to your order?"
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-3",
"invocationId": "i-1",
"isolationScope": "fc-1",
"nodeInfo": {
"path": "coordinator@1/order_collector@fc-1"
}
},
{
"author": "user",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-3",
"name": "adk_request_confirmation",
"response": {
"confirmed": true,
"payload": {}
}
}
}
],
"role": "user"
},
"id": "e-4",
"invocationId": "",
"nodeInfo": {
"path": ""
}
},
{
"author": "user",
"content": {
"parts": [
{
"text": "1234-1234"
}
],
"role": "user"
},
"id": "e-5",
"invocationId": "i-2",
"nodeInfo": {
"path": ""
}
},
{
"author": "order_collector",
"content": {
"parts": [
{
"text": "I'm sorry, I didn't quite catch that. We offer Pizza, Burgers, and Salads. You've mentioned 10 burgers so far. Would you like to add any pizza or salad to your order, or is that everything?"
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-6",
"invocationId": "i-2",
"isolationScope": "fc-1",
"nodeInfo": {
"path": "coordinator@1/order_collector@fc-1"
}
},
{
"author": "user",
"content": {
"parts": [
{
"text": "123"
}
],
"role": "user"
},
"id": "e-7",
"invocationId": "i-3",
"nodeInfo": {
"path": ""
}
},
{
"author": "order_collector",
"content": {
"parts": [
{
"functionCall": {
"args": {},
"id": "fc-2",
"name": "confirmation"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-8",
"invocationId": "i-3",
"isolationScope": "fc-1",
"longRunningToolIds": [],
"nodeInfo": {
"path": "coordinator@1/order_collector@fc-1"
}
},
{
"author": "order_collector",
"content": {
"parts": [
{
"functionCall": {
"args": {
"originalFunctionCall": {
"args": {},
"id": "fc-2",
"name": "confirmation"
},
"toolConfirmation": {
"confirmed": false,
"hint": "Please approve or reject the tool call confirmation() by responding with a FunctionResponse with an expected ToolConfirmation payload."
}
},
"id": "fc-3",
"name": "adk_request_confirmation"
}
}
],
"role": "model"
},
"id": "e-9",
"invocationId": "i-3",
"isolationScope": "fc-1",
"longRunningToolIds": [
"fc-3"
],
"nodeInfo": {
"path": "coordinator@1/order_collector@fc-1"
}
},
{
"actions": {
"requestedToolConfirmations": {
"fc-2": {
"confirmed": false,
"hint": "Please approve or reject the tool call confirmation() by responding with a FunctionResponse with an expected ToolConfirmation payload."
}
},
"skipSummarization": true
},
"author": "order_collector",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-2",
"name": "confirmation",
"response": {
"error": "This tool call requires confirmation, please approve or reject."
}
}
}
],
"role": "user"
},
"id": "e-10",
"invocationId": "i-3",
"isolationScope": "fc-1",
"nodeInfo": {
"path": "coordinator@1/order_collector@fc-1"
}
}
]
}
@@ -0,0 +1,410 @@
{
"events": [
{
"author": "user",
"content": {
"parts": [
{
"text": "3 burgers"
}
],
"role": "user"
},
"id": "e-1",
"invocationId": "i-1",
"nodeInfo": {
"path": ""
}
},
{
"author": "coordinator",
"content": {
"parts": [
{
"functionCall": {
"args": {
"request": "The user wants to order 3 burgers. Please confirm if there are any specific types or details they'd like for these burgers."
},
"id": "fc-1",
"name": "order_collector"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-2",
"invocationId": "i-1",
"longRunningToolIds": [],
"nodeInfo": {
"path": "coordinator@1"
}
},
{
"author": "order_collector",
"content": {
"parts": [
{
"text": "Hello! We have Pizza, Burgers, and Salads on our menu today. You've chosen 3 Burgers. Would you like to add any Pizza or Salads to your order, or is that all for today?"
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-3",
"invocationId": "i-1",
"isolationScope": "fc-1",
"nodeInfo": {
"path": "coordinator@1/order_collector@fc-1"
}
},
{
"author": "user",
"content": {
"parts": [
{
"text": "ready to pay"
}
],
"role": "user"
},
"id": "e-4",
"invocationId": "i-2",
"nodeInfo": {
"path": ""
}
},
{
"author": "order_collector",
"content": {
"parts": [
{
"functionCall": {
"args": {
"result": [
{
"name": "Burger",
"quantity": 3
}
]
},
"id": "fc-2",
"name": "finish_task"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-5",
"invocationId": "i-2",
"isolationScope": "fc-1",
"longRunningToolIds": [],
"nodeInfo": {
"path": "coordinator@1/order_collector@fc-1"
}
},
{
"author": "order_collector",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-2",
"name": "finish_task",
"response": {
"result": "Task completed."
}
}
}
],
"role": "user"
},
"id": "e-6",
"invocationId": "i-2",
"isolationScope": "fc-1",
"nodeInfo": {
"outputFor": [
"coordinator@1/order_collector@fc-1"
],
"path": "coordinator@1/order_collector@fc-1"
},
"output": [
{
"name": "Burger",
"quantity": 3
}
]
},
{
"author": "user",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-1",
"name": "order_collector",
"response": {
"output": [
{
"name": "Burger",
"quantity": 3
}
]
}
}
}
],
"role": "user"
},
"id": "e-7",
"invocationId": "i-2",
"nodeInfo": {
"path": "coordinator@1"
}
},
{
"author": "coordinator",
"content": {
"parts": [
{
"functionCall": {
"args": {
"request": "Please collect the user's credit card number and CVV for their order of 3 burgers."
},
"id": "fc-3",
"name": "payment_collector"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-8",
"invocationId": "i-2",
"longRunningToolIds": [],
"nodeInfo": {
"path": "coordinator@1"
}
},
{
"author": "payment_collector",
"content": {
"parts": [
{
"text": "To process your order for 3 burgers, could you please provide your credit card number and the 3-digit CVV code?"
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-9",
"invocationId": "i-2",
"isolationScope": "fc-3",
"nodeInfo": {
"path": "coordinator@1/payment_collector@fc-3"
}
},
{
"author": "user",
"content": {
"parts": [
{
"text": "1234-1234"
}
],
"role": "user"
},
"id": "e-10",
"invocationId": "i-3",
"nodeInfo": {
"path": ""
}
},
{
"author": "payment_collector",
"content": {
"parts": [
{
"text": "Thank you. Could you also provide the 3-digit CVV code for your card?"
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-11",
"invocationId": "i-3",
"isolationScope": "fc-3",
"nodeInfo": {
"path": "coordinator@1/payment_collector@fc-3"
}
},
{
"author": "user",
"content": {
"parts": [
{
"text": "123"
}
],
"role": "user"
},
"id": "e-12",
"invocationId": "i-4",
"nodeInfo": {
"path": ""
}
},
{
"author": "payment_collector",
"content": {
"parts": [
{
"functionCall": {
"args": {
"credit_card_number": "1234-1234",
"cvv": "123"
},
"id": "fc-4",
"name": "finish_task"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-13",
"invocationId": "i-4",
"isolationScope": "fc-3",
"longRunningToolIds": [],
"nodeInfo": {
"path": "coordinator@1/payment_collector@fc-3"
}
},
{
"author": "payment_collector",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-4",
"name": "finish_task",
"response": {
"result": "Task completed."
}
}
}
],
"role": "user"
},
"id": "e-14",
"invocationId": "i-4",
"isolationScope": "fc-3",
"nodeInfo": {
"outputFor": [
"coordinator@1/payment_collector@fc-3"
],
"path": "coordinator@1/payment_collector@fc-3"
},
"output": {
"credit_card_number": "1234-1234",
"cvv": "123"
}
},
{
"author": "user",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-3",
"name": "payment_collector",
"response": {
"credit_card_number": "1234-1234",
"cvv": "123"
}
}
}
],
"role": "user"
},
"id": "e-15",
"invocationId": "i-4",
"nodeInfo": {
"path": "coordinator@1"
}
},
{
"author": "coordinator",
"content": {
"parts": [
{
"functionCall": {
"args": {
"orders": [
{
"name": "Burger",
"quantity": 3
}
],
"payment_info": {
"credit_card_number": "1234-1234",
"cvv": "123"
}
},
"id": "fc-5",
"name": "place_order"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-16",
"invocationId": "i-4",
"longRunningToolIds": [],
"nodeInfo": {
"path": "coordinator@1"
}
},
{
"author": "coordinator",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-5",
"name": "place_order",
"response": {
"result": "Successfully placed order for 3 items."
}
}
}
],
"role": "user"
},
"id": "e-17",
"invocationId": "i-4",
"nodeInfo": {
"path": "coordinator@1"
}
},
{
"author": "coordinator",
"content": {
"parts": [
{
"text": "Your order for 3 burgers has been successfully placed!"
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-18",
"invocationId": "i-4",
"nodeInfo": {
"path": "coordinator@1"
}
}
]
}
@@ -0,0 +1,92 @@
{
"events": [
{
"author": "user",
"content": {
"parts": [
{
"text": "3 burgers, credit card 1234-1234, cvv 123"
}
],
"role": "user"
},
"id": "e-1",
"invocationId": "i-1",
"nodeInfo": {
"path": ""
}
},
{
"author": "coordinator",
"content": {
"parts": [
{
"functionCall": {
"args": {
"orders": [
{
"name": "burger",
"quantity": 3
}
],
"payment_info": {
"credit_card_number": "1234-1234",
"cvv": "123"
}
},
"id": "fc-1",
"name": "place_order"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-2",
"invocationId": "i-1",
"longRunningToolIds": [],
"nodeInfo": {
"path": "coordinator@1"
}
},
{
"author": "coordinator",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-1",
"name": "place_order",
"response": {
"result": "Successfully placed order for 3 items."
}
}
}
],
"role": "user"
},
"id": "e-3",
"invocationId": "i-1",
"nodeInfo": {
"path": "coordinator@1"
}
},
{
"author": "coordinator",
"content": {
"parts": [
{
"text": "Your order for 3 burgers has been successfully placed."
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-4",
"invocationId": "i-1",
"nodeInfo": {
"path": "coordinator@1"
}
}
]
}
@@ -0,0 +1,96 @@
{
"events": [
{
"author": "user",
"content": {
"parts": [
{
"text": "credit card 1234-1234, cvv 123"
}
],
"role": "user"
},
"id": "e-1",
"invocationId": "i-1",
"nodeInfo": {
"path": ""
}
},
{
"author": "coordinator",
"content": {
"parts": [
{
"functionCall": {
"args": {
"request": "The user has provided payment info. Please find out what food they would like to order."
},
"id": "fc-1",
"name": "order_collector"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-2",
"invocationId": "i-1",
"longRunningToolIds": [],
"nodeInfo": {
"path": "coordinator@1"
}
},
{
"author": "order_collector",
"content": {
"parts": [
{
"text": "Hello! What would you like to order today? We have Pizza, Burgers, and Salads available. Please let me know your choice and the quantity."
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-3",
"invocationId": "i-1",
"isolationScope": "fc-1",
"nodeInfo": {
"path": "coordinator@1/order_collector@fc-1"
}
},
{
"author": "user",
"content": {
"parts": [
{
"text": "3 burgers"
}
],
"role": "user"
},
"id": "e-4",
"invocationId": "i-2",
"nodeInfo": {
"path": ""
}
},
{
"author": "order_collector",
"content": {
"parts": [
{
"text": "I have added 3 Burgers to your order. Would you like to add any Pizza or Salad, or is that all for today?"
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-5",
"invocationId": "i-2",
"isolationScope": "fc-1",
"nodeInfo": {
"path": "coordinator@1/order_collector@fc-1"
}
}
]
}
@@ -0,0 +1,198 @@
{
"events": [
{
"author": "user",
"content": {
"parts": [
{
"text": "order food"
}
],
"role": "user"
},
"id": "e-1",
"invocationId": "i-1",
"nodeInfo": {
"path": ""
}
},
{
"author": "coordinator",
"content": {
"parts": [
{
"functionCall": {
"args": {
"request": "Please help the user order food by collecting the items and quantities they want."
},
"id": "fc-1",
"name": "order_collector"
}
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-2",
"invocationId": "i-1",
"longRunningToolIds": [],
"nodeInfo": {
"path": "coordinator@1"
}
},
{
"author": "order_collector",
"content": {
"parts": [
{
"text": "Hello! What would you like to order today? Our menu includes:\n1. Pizza\n2. Burger\n3. Salad\n\nPlease let me know which items and how many of each you'd like."
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-3",
"invocationId": "i-1",
"isolationScope": "fc-1",
"nodeInfo": {
"path": "coordinator@1/order_collector@fc-1"
}
},
{
"author": "user",
"content": {
"parts": [
{
"text": "burger"
}
],
"role": "user"
},
"id": "e-4",
"invocationId": "i-2",
"nodeInfo": {
"path": ""
}
},
{
"author": "order_collector",
"content": {
"parts": [
{
"text": "How many burgers would you like to order?"
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-5",
"invocationId": "i-2",
"isolationScope": "fc-1",
"nodeInfo": {
"path": "coordinator@1/order_collector@fc-1"
}
},
{
"author": "user",
"content": {
"parts": [
{
"text": "3"
}
],
"role": "user"
},
"id": "e-6",
"invocationId": "i-3",
"nodeInfo": {
"path": ""
}
},
{
"author": "order_collector",
"content": {
"parts": [
{
"text": "Great! You've ordered 3 burgers. Would you like to add anything else to your order (Pizza or Salad), or is that all for today?"
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-7",
"invocationId": "i-3",
"isolationScope": "fc-1",
"nodeInfo": {
"path": "coordinator@1/order_collector@fc-1"
}
},
{
"author": "user",
"content": {
"parts": [
{
"text": "1234-1234"
}
],
"role": "user"
},
"id": "e-8",
"invocationId": "i-4",
"nodeInfo": {
"path": ""
}
},
{
"author": "order_collector",
"content": {
"parts": [
{
"text": "I'm sorry, I didn't quite understand that. Would you like to add any Pizza or Salad to your order of 3 Burgers, or is that all?"
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-9",
"invocationId": "i-4",
"isolationScope": "fc-1",
"nodeInfo": {
"path": "coordinator@1/order_collector@fc-1"
}
},
{
"author": "user",
"content": {
"parts": [
{
"text": "123"
}
],
"role": "user"
},
"id": "e-10",
"invocationId": "i-5",
"nodeInfo": {
"path": ""
}
},
{
"author": "order_collector",
"content": {
"parts": [
{
"text": "I'm sorry, I'm not sure what you mean by \"123\". Would you like to add 123 of one of our menu items (Pizza or Salad) to your order, or would you like to finish your order with just the 3 burgers?"
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-11",
"invocationId": "i-5",
"isolationScope": "fc-1",
"nodeInfo": {
"path": "coordinator@1/order_collector@fc-1"
}
}
]
}
@@ -0,0 +1,29 @@
# Three Layer Transfer Sample
## Overview
This sample demonstrates a three-layer multi-agent system built with the ADK Python toolkit, showcasing structured double-round-trip hierarchical transfers.
## Sample Inputs
- `Hello, who are you?`
- `Can you write a short story about a lost kitten?`
- `Please translate it into Spanish.`
- `Looks great! Let's return to the project coordinator.`
## Graph
```mermaid
graph TD
root_agent[root_agent] --> writer_agent[writer_agent]
writer_agent --> translator_agent[translator_agent]
```
## How To
This sample demonstrates:
1. Root delegating to middle-child node `writer_agent`.
1. `writer_agent` delegating to leaf-grandchild node `translator_agent`.
1. Grandchild returning back to the parent `writer_agent`.
1. Parent returning back to the root coordinator `root_agent`.
@@ -0,0 +1,15 @@
# 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.
from . import agent
@@ -0,0 +1,56 @@
# 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.
from google.adk.agents.llm_agent import Agent
# --- Leaf Agent (Grandchild) ---
translator_agent = Agent(
name="translator_agent",
description="Translates text into different languages.",
instruction="""
You are a translator. Your job is to translate the text provided to you into the requested language.
Once the translation is complete, output the translated text, explain what you did, and then transfer back to the writer_agent.
""",
)
# --- Middle Agent (Child) ---
writer_agent = Agent(
name="writer_agent",
description=(
"Writes stories, articles, or essays, and manages translation requests."
),
instruction="""
You are a professional writer.
When asked to write something, perform the writing task and present the result to the user.
If the user asks to translate the written content into another language, transfer the task to the translator_agent.
If the user is satisfied and wants to return to the main coordinator, transfer back to the root_agent.
""",
sub_agents=[translator_agent],
)
# --- Root Agent (Parent) ---
root_agent = Agent(
name="root_agent",
description=(
"Project coordinator that delegates writing and translation tasks."
),
instruction="""
You are a project coordinator.
If the user wants to write a story, essay, or article, transfer the task to the writer_agent.
Answer general inquiries yourself, but delegate writing-related tasks.
""",
sub_agents=[writer_agent],
)