From cfa9249b125c84ac08f1bb4b6e87e931e368d322 Mon Sep 17 00:00:00 2001 From: Saroj Rout Date: Thu, 8 Jan 2026 15:22:47 -0800 Subject: [PATCH 1/3] added resiliency samples --- .../samples/resiliency_sample/README.md | 162 +++++++++++ .../samples/resiliency_sample/__Init__.py | 17 ++ .../samples/resiliency_sample/agent.py | 252 ++++++++++++++++++ .../samples/resiliency_sample/test_example.py | 173 ++++++++++++ .../samples/resiliency_sample/test_helpers.py | 176 ++++++++++++ 5 files changed, 780 insertions(+) create mode 100644 contributing/samples/resiliency_sample/README.md create mode 100644 contributing/samples/resiliency_sample/__Init__.py create mode 100644 contributing/samples/resiliency_sample/agent.py create mode 100644 contributing/samples/resiliency_sample/test_example.py create mode 100644 contributing/samples/resiliency_sample/test_helpers.py diff --git a/contributing/samples/resiliency_sample/README.md b/contributing/samples/resiliency_sample/README.md new file mode 100644 index 0000000..4cab22a --- /dev/null +++ b/contributing/samples/resiliency_sample/README.md @@ -0,0 +1,162 @@ +# AgentTool Resilience: Timeout, Retry, and Redirect Patterns + +This is a **community-contributed sample** that demonstrates how to handle failures, timeouts, and partial results from downstream agents in multi-agent workflows using ADK. + +**Note:** This sample uses only core ADK features (`google-adk`) and does not require the community package. It's included in the `adk-python-community` repository as a community-contributed example demonstrating resilience patterns that may be useful to other developers. + +## Prerequisites + +- Python 3.9+ (Python 3.11+ recommended) +- Google API key for the agent + +## Setup + +### 1. Clone the Repository + +First, clone the `adk-python-community` repository to get the sample code: + +```bash +git clone https://github.com/google/adk-python-community.git +cd adk-python-community +``` + +### 2. Install Dependencies + +Navigate to the sample directory and install the required package: + +```bash +cd contributing/samples/resiliency_sample +pip install google-adk +``` + +**Optional:** If you want to use a `.env` file for environment variables, also install: + +```bash +pip install python-dotenv +``` + +**Note:** This sample only requires `google-adk` (core ADK package). You don't need to install `google-adk-community` for this sample. + +### 3. Configure Environment Variables + +Create a `.env` file in the `contributing/samples/resiliency_sample` directory: + +```bash +# Required: Google API key for the agent +GOOGLE_API_KEY=your-google-api-key +``` + +## Usage + +### Running the Test Example + +This sample includes a test script that demonstrates various resilience patterns using the `test_helpers.py` utilities. Run the test example: + +```bash +python test_example.py +``` + +This will run three test scenarios: +1. **Normal Operation**: Tests the coordinator agent with a simple query +2. **Timeout Scenario**: Demonstrates timeout handling using `timeout_test_agent` +3. **Failure Scenario**: Demonstrates error handling using `failure_test_agent` + +### Using the Sample Programmatically + +You can also use the sample agents directly in your own code: + +```python +import asyncio +from google.adk.runners import Runner +from agent import coordinator_agent + +async def main(): + runner = Runner( + app_name="my_app", + agent=coordinator_agent, + ) + + response = await runner.run_async("What is quantum computing?") + print(response.text) + +if __name__ == "__main__": + asyncio.run(main()) +``` + +### Using Test Helpers + +The `test_helpers.py` module provides utilities for testing resilience patterns: + +- `timeout_test_agent`: An agent that uses a tool that simulates timeouts +- `failure_test_agent`: An agent that uses a tool that always fails +- `TimeoutSimulatorTool`: A tool that sleeps to trigger timeout scenarios +- `FailureSimulatorTool`: A tool that raises exceptions to test error handling + +You can use these in your own tests to verify resilience patterns work correctly. + +## Sample Structure + +``` +resiliency_sample/ +├── agent.py # Agent definitions with resilience patterns +├── test_helpers.py # Test utilities for simulating timeouts and failures +├── test_example.py # Example script demonstrating how to test the sample +├── __Init__.py # Package initialization +└── README.md # This file +``` + +## Sample Agent + +The sample agent (`agent.py`) includes: +- `coordinator_agent` - Routes requests and handles errors +- `research_agent_primary` - Primary agent with timeout protection (default: 30s) +- `research_agent_fallback` - Fallback agent with longer timeout (60s) +- `error_recovery_agent` - Analyzes failures and provides recommendations + +## Sample Queries + +### Simple Query +- "What is quantum computing?" + +### Complex Query +- "Research quantum computing applications in healthcare, finance, cryptography, logistics, weather prediction, drug discovery, and machine learning. For each domain, provide: historical context, current state-of-the-art, technical challenges, recent breakthroughs in 2024, comparison with classical approaches, economic impact, and future roadmap for the next 10 years." + +### Testing Custom Scenarios + +You can modify `test_example.py` to test custom scenarios: + +1. **Test with different timeout values**: Modify the `timeout` parameter in `TimeoutAgentTool` +2. **Test with different failure modes**: Use different agents from `test_helpers.py` +3. **Test with your own agents**: Create custom test agents and wrap them with `TimeoutAgentTool` + +Example: Testing with a custom timeout + +```python +from test_helpers import timeout_test_agent, TimeoutAgentTool +from agent import Agent + +# Create coordinator with custom timeout +test_coordinator = Agent( + name='test_coordinator', + model='gemini-2.5-flash-lite', + tools=[ + TimeoutAgentTool( + agent=timeout_test_agent, + timeout=3.0, # Custom timeout value + ), + ], +) +``` + +## Features Demonstrated + +- **Timeout Protection**: Custom `TimeoutAgentTool` wrapper adds timeout handling to sub-agents +- **Automatic Retry**: `ReflectAndRetryToolPlugin` handles retries with structured guidance +- **Dynamic Fallback**: Coordinator agent routes to alternative agents when primary fails +- **Error Recovery**: Specialized agent provides user-friendly error analysis + +## Expected Behavior + +1. **Normal Operation**: Primary agent handles the query successfully +2. **Timeout Scenario**: Primary times out → Fallback agent is automatically tried +3. **Failure Scenario**: Primary fails → Retry → Fallback → Error recovery agent provides guidance \ No newline at end of file diff --git a/contributing/samples/resiliency_sample/__Init__.py b/contributing/samples/resiliency_sample/__Init__.py new file mode 100644 index 0000000..fb9a391 --- /dev/null +++ b/contributing/samples/resiliency_sample/__Init__.py @@ -0,0 +1,17 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from . import agent + +__all__ = ['agent'] \ No newline at end of file diff --git a/contributing/samples/resiliency_sample/agent.py b/contributing/samples/resiliency_sample/agent.py new file mode 100644 index 0000000..f64cfd6 --- /dev/null +++ b/contributing/samples/resiliency_sample/agent.py @@ -0,0 +1,252 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Sample demonstrating AgentTool resilience: timeout, retry, and redirect patterns. + +This sample shows how to handle failures, timeouts, and partial results +from downstream agents in multi-agent workflows, including: +- Timeout protection for sub-agents +- Automatic retry with ReflectAndRetryToolPlugin +- Dynamic rerouting to alternative agents +- Error handling without leaking complexity to users +""" + +import asyncio +from typing import Any + +from google.adk import Agent +from google.adk.apps import App +from google.adk.plugins import ReflectAndRetryToolPlugin +from google.adk.tools import AgentTool +from google.adk.tools.google_search_tool import google_search +from google.adk.tools.tool_context import ToolContext +import time +from google.genai import types +from google.adk.events.event import Event + + +# ============================================================================ +# Custom TimeoutAgentTool Wrapper +# ============================================================================ + +class TimeoutAgentTool(AgentTool): + """AgentTool with timeout protection. + + This wrapper adds timeout handling to AgentTool, catching TimeoutError + and returning a structured error response that ReflectAndRetryToolPlugin + can process. + """ + + def __init__( + self, + agent, + timeout: float = 30.0, + timeout_error_message: str = "Sub-agent execution timed out", + **kwargs + ): + """Initialize TimeoutAgentTool. + + Args: + agent: The agent to wrap. + timeout: Timeout in seconds for sub-agent execution. + timeout_error_message: Custom error message for timeout. + **kwargs: Additional arguments passed to AgentTool. + """ + super().__init__(agent, **kwargs) + self.timeout = timeout + self.timeout_error_message = timeout_error_message + + async def run_async( + self, + *, + args: dict[str, Any], + tool_context: ToolContext, + ) -> Any: + """Run with timeout protection.""" + try: + return await asyncio.wait_for( + super().run_async(args=args, tool_context=tool_context), + timeout=self.timeout + ) + except asyncio.TimeoutError: + # Return structured error that ReflectAndRetryToolPlugin can handle + return { + "error": "TimeoutError", + "message": self.timeout_error_message, + "timeout_seconds": self.timeout, + "agent_name": self.agent.name, + } + + + +# ============================================================================ +# Sub-Agents with Different Characteristics +# ============================================================================ + +# Primary agent - may be slow or fail +research_agent_primary = Agent( + name='research_agent_primary', + model='gemini-2.5-flash', + description='Primary research agent for complex queries (may be slow)', + instruction=""" + You are a thorough research assistant. When given a research task: + 1. Acknowledge the task + 2. ALWAYS use the google_search tool to find current information + 3. Break down the information into detailed steps + 4. Provide a comprehensive summary based on the search results + + IMPORTANT: You MUST use google_search for every research query. Do not + respond without searching first. Be thorough and detailed in your responses. + """, + tools=[google_search], +) + +# Fallback agent - faster, simpler +research_agent_fallback = Agent( + name='research_agent_fallback', + model='gemini-2.5-flash', + description='Fallback research agent for simpler queries or when primary fails', + instruction=""" + You are a research assistant focused on quick, concise answers. + When given a research task: + 1. ALWAYS use the google_search tool first to find information + 2. Provide a direct, well-structured response based on the search results + 3. Keep your response concise without excessive detail + + IMPORTANT: You MUST use google_search for every research query. Do not + respond without searching first. + """, + tools=[google_search], +) + +# Specialized agent for error recovery +error_recovery_agent = Agent( + name='error_recovery_agent', + model='gemini-2.5-flash', + description='Agent that handles error scenarios and provides alternative approaches', + instruction=""" + You are an error recovery specialist. When you receive an error message + or failure report, analyze what went wrong and suggest: + 1. What the error means + 2. Why it might have occurred + 3. Alternative approaches to achieve the goal + 4. Recommendations for the user + + Be helpful and constructive in your analysis. + """, +) + + +# ============================================================================ +# Coordinator Agent with Resilience Patterns +# ============================================================================ + +coordinator_agent = Agent( + name='coordinator_agent', + model='gemini-2.5-flash-lite', + description='Coordinator that manages research tasks with resilience', + instruction=""" + You are a coordinator agent that manages research tasks by delegating to + specialized sub-agents. Your role is to ensure tasks complete successfully + even when individual agents fail or timeout. + + **CRITICAL WORKFLOW REQUIREMENT - READ THIS FIRST:** + After calling ANY tool and receiving its response, you MUST IMMEDIATELY generate a text response explaining the results to the user. Tool calls are NOT the final answer - they are just one step. You MUST always provide a final text response to complete the conversation. If you only call a tool without generating text afterward, the user will receive no response. + + **Tool Selection Strategy:** + 1. **Primary Tool (research_agent_primary)**: Use for complex, detailed + research tasks. This agent is thorough but may be slower. + 2. **Fallback Tool (research_agent_fallback)**: Use when: + - The primary agent times out or fails + - The query is simple and doesn't need deep research + - You need a quick answer + 3. **Error Recovery Tool (error_recovery_agent)**: Use when: + - Multiple attempts have failed + - You need to understand what went wrong + - You need alternative approaches suggested + + **Error Handling Protocol:** + - If research_agent_primary returns an error or timeout: + 1. First, try research_agent_fallback with the same query + 2. If that also fails, use error_recovery_agent to analyze the failure + 3. Present the error_recovery_agent's analysis to the user + 4. Suggest next steps based on the analysis + + **User Communication:** + - Always present results clearly, even if they come from fallback agents + - After receiving any tool response, immediately provide a helpful text explanation to the user + - If errors occur, explain what happened and what you tried + - Never expose internal error details or retry counts to users + - Frame fallbacks as "using a different approach" rather than "fallback" + + **Example Flow:** + User: "What is quantum computing?" + 1. Call research_agent_primary with request="What is quantum computing?" + 2. Wait for the tool response + 3. **MUST**: Generate a text response presenting the results to the user + + If the primary agent times out or fails: + 4. Call research_agent_fallback with the same request + 5. Wait for the tool response + 6. **MUST**: Generate a text response presenting the results to the user + + Remember: Tool calls are not the final answer - you must always follow up with a text response explaining the results to the user. + """, + tools=[ + # Primary agent with timeout protection + # For testing timeouts, set a very short timeout (e.g., 5.0 seconds) + # For production, use a longer timeout (e.g., 30.0 seconds) + # NOTE: skip_summarization=False is required for the coordinator to continue + # after tool calls. If True, the function response event is marked as final + # and the LLM flow stops, preventing the coordinator from generating a response. + TimeoutAgentTool( + agent=research_agent_primary, + timeout=30.0, # Change to 5.0 for timeout testing + timeout_error_message="Primary research agent timed out after 30 seconds", + skip_summarization=False, # Must be False for coordinator to continue + ), + # Fallback agent timeout + # For testing: Set to 5.0 to test full failure chain (primary → fallback → error recovery) + # For production: Set to 60.0 to allow fallback to succeed after primary timeout + TimeoutAgentTool( + agent=research_agent_fallback, + timeout=60.0, # Set to 60.0 to test successful fallback after primary timeout + timeout_error_message="Fallback research agent timed out", + skip_summarization=False, # Must be False for coordinator to continue + ), + # Error recovery agent + AgentTool( + agent=error_recovery_agent, + skip_summarization=False, # Must be False for coordinator to continue + ), + ], +) + +# ============================================================================ +# App Configuration with Retry Plugin +# ============================================================================ + +# Configure retry plugin for automatic retry handling +retry_plugin = ReflectAndRetryToolPlugin( + max_retries=2, # Allow 2 retries per tool before giving up + throw_exception_if_retry_exceeded=False, # Return guidance instead of raising +) + +app = App( + name='agent_tool_resilience', + root_agent=coordinator_agent, + plugins=[retry_plugin], +) + +root_agent = coordinator_agent \ No newline at end of file diff --git a/contributing/samples/resiliency_sample/test_example.py b/contributing/samples/resiliency_sample/test_example.py new file mode 100644 index 0000000..82a8cc0 --- /dev/null +++ b/contributing/samples/resiliency_sample/test_example.py @@ -0,0 +1,173 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Example script demonstrating how to test the resilience sample. + +This script shows how to use the test_helpers.py utilities to test +various resilience patterns including timeouts and failures. +""" + +import asyncio +import os + +try: + from dotenv import load_dotenv + load_dotenv() +except ImportError: + # dotenv is optional - user can set GOOGLE_API_KEY directly + pass + +from google.adk.runners import Runner +from google.adk.tools import AgentTool +from agent import coordinator_agent, app, TimeoutAgentTool +from test_helpers import ( + timeout_test_agent, + failure_test_agent, +) + + +async def test_normal_operation(): + """Test normal operation with a simple query.""" + print("=" * 60) + print("Test 1: Normal Operation") + print("=" * 60) + + runner = Runner( + app_name="resilience_test", + agent=coordinator_agent, + ) + + query = "What is quantum computing?" + print(f"\nQuery: {query}\n") + + response = await runner.run_async(query) + print(f"\nResponse: {response.text}\n") + + +async def test_timeout_scenario(): + """Test timeout scenario using test helpers.""" + print("=" * 60) + print("Test 2: Timeout Scenario") + print("=" * 60) + + # Create a coordinator with timeout_test_agent wrapped in TimeoutAgentTool + from agent import Agent + + timeout_coordinator = Agent( + name='timeout_coordinator', + model='gemini-2.5-flash-lite', + description='Coordinator for testing timeout scenarios', + instruction=""" + You are a test coordinator. When given a task, use the timeout_test_agent + tool. This agent will timeout, demonstrating the timeout handling mechanism. + After the timeout, provide a clear explanation to the user. + """, + tools=[ + TimeoutAgentTool( + agent=timeout_test_agent, + timeout=5.0, # Short timeout to trigger timeout behavior + timeout_error_message="Test agent timed out after 5 seconds", + ), + ], + ) + + runner = Runner( + app_name="timeout_test", + agent=timeout_coordinator, + ) + + query = "Perform a test task" + print(f"\nQuery: {query}\n") + print("Note: This will timeout after 5 seconds...\n") + + response = await runner.run_async(query) + print(f"\nResponse: {response.text}\n") + + +async def test_failure_scenario(): + """Test failure scenario using test helpers.""" + print("=" * 60) + print("Test 3: Failure Scenario") + print("=" * 60) + + # Create a coordinator with failure_test_agent + from agent import Agent + + failure_coordinator = Agent( + name='failure_coordinator', + model='gemini-2.5-flash-lite', + description='Coordinator for testing failure scenarios', + instruction=""" + You are a test coordinator. When given a task, use the failure_test_agent + tool. This agent will fail, demonstrating the error handling mechanism. + After the failure, provide a clear explanation to the user about what + went wrong and what alternatives might be available. + """, + tools=[ + AgentTool(agent=failure_test_agent), + ], + ) + + runner = Runner( + app_name="failure_test", + agent=failure_coordinator, + ) + + query = "Perform a test task" + print(f"\nQuery: {query}\n") + print("Note: This will trigger a failure...\n") + + response = await runner.run_async(query) + print(f"\nResponse: {response.text}\n") + + +async def main(): + """Run all test scenarios.""" + if not os.getenv("GOOGLE_API_KEY"): + print("ERROR: GOOGLE_API_KEY environment variable is not set.") + print("Please create a .env file with your Google API key.") + return + + print("\n" + "=" * 60) + print("Resilience Sample Test Suite") + print("=" * 60) + print("\nThis script demonstrates various resilience patterns:") + print("1. Normal operation") + print("2. Timeout handling") + print("3. Failure handling") + print("\n" + "=" * 60 + "\n") + + try: + # Test normal operation + await test_normal_operation() + + # Test timeout scenario + await test_timeout_scenario() + + # Test failure scenario + await test_failure_scenario() + + print("=" * 60) + print("All tests completed!") + print("=" * 60) + + except Exception as e: + print(f"\nError during testing: {e}") + import traceback + traceback.print_exc() + + +if __name__ == "__main__": + asyncio.run(main()) + diff --git a/contributing/samples/resiliency_sample/test_helpers.py b/contributing/samples/resiliency_sample/test_helpers.py new file mode 100644 index 0000000..780a97f --- /dev/null +++ b/contributing/samples/resiliency_sample/test_helpers.py @@ -0,0 +1,176 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Test helpers for simulating timeout and failure scenarios. + +This module provides agents and tools that simulate various failure modes +for testing resilience patterns. +""" + +import asyncio +from typing import Any + +from google.adk import Agent +from google.adk.tools import AgentTool, BaseTool +from google.adk.tools.tool_context import ToolContext + + +# ============================================================================ +# Slow Agent (Simulates Timeout) +# ============================================================================ + +slow_agent = Agent( + name='slow_agent', + model='gemini-2.5-flash-lite', + description='An agent that intentionally takes a long time to respond', + instruction=""" + You are a very thorough agent that takes your time. When given any task: + 1. Acknowledge the task + 2. Think carefully about it for a while + 3. Break it down into many detailed steps + 4. Consider each step carefully + 5. Provide a comprehensive response + + Be extremely detailed and thorough. Take your time to ensure quality. + Always provide extensive context and multiple examples. + """, +) + + +# ============================================================================ +# Failing Agent (Simulates Errors) +# ============================================================================ + +failing_agent = Agent( + name='failing_agent', + model='gemini-2.5-flash-lite', + description='An agent that intentionally fails', + instruction=""" + You are an agent that simulates failures. When given any task: + 1. Acknowledge the task + 2. Attempt to process it + 3. Always return an error message indicating failure + + Always respond with: "ERROR: This agent is configured to simulate failures. + This is a test scenario to demonstrate error handling." + """, +) + + +# ============================================================================ +# Intermittent Agent (Sometimes Fails) +# ============================================================================ + +intermittent_agent = Agent( + name='intermittent_agent', + model='gemini-2.5-flash-lite', + description='An agent that sometimes fails, sometimes succeeds', + instruction=""" + You are an agent with intermittent reliability. When given a task: + - If the task contains the word "fail" or "error", return an error + - Otherwise, process normally + + This simulates real-world scenarios where agents sometimes fail + due to external factors. + """, +) + + +# ============================================================================ +# Custom Tool that Simulates Timeout +# ============================================================================ + +class TimeoutSimulatorTool(BaseTool): + """A tool that simulates timeout by sleeping.""" + + def __init__(self, sleep_duration: float = 35.0): + """Initialize timeout simulator. + + Args: + sleep_duration: How long to sleep (should exceed timeout to trigger). + """ + super().__init__( + name='timeout_simulator', + description='A tool that simulates timeout scenarios', + ) + self.sleep_duration = sleep_duration + + async def run_async( + self, + *, + args: dict[str, Any], + tool_context: ToolContext, + ) -> Any: + """Sleep for the specified duration to simulate timeout.""" + await asyncio.sleep(self.sleep_duration) + return {'status': 'completed', 'message': 'This should not be reached'} + + +# ============================================================================ +# Custom Tool that Simulates Failure +# ============================================================================ + +class FailureSimulatorTool(BaseTool): + """A tool that always fails.""" + + def __init__(self, error_message: str = 'Simulated failure'): + """Initialize failure simulator. + + Args: + error_message: The error message to raise. + """ + super().__init__( + name='failure_simulator', + description='A tool that simulates failures', + ) + self.error_message = error_message + + async def run_async( + self, + *, + args: dict[str, Any], + tool_context: ToolContext, + ) -> Any: + """Always raise an exception.""" + raise RuntimeError(self.error_message) + + +# ============================================================================ +# Test Agent Configurations +# ============================================================================ + +# Agent that uses timeout simulator tool +timeout_test_agent = Agent( + name='timeout_test_agent', + model='gemini-2.5-flash-lite', + description='Agent for testing timeout scenarios', + instruction=""" + You are a test agent. When asked to do anything, use the timeout_simulator + tool. This will help test timeout handling. + """, + tools=[TimeoutSimulatorTool(sleep_duration=35.0)], +) + +# Agent that uses failure simulator tool +failure_test_agent = Agent( + name='failure_test_agent', + model='gemini-2.5-flash-lite', + description='Agent for testing failure scenarios', + instruction=""" + You are a test agent. When asked to do anything, use the failure_simulator + tool. This will help test error handling. + """, + tools=[FailureSimulatorTool(error_message='Test failure simulation')], +) + From 9d0c7be4137d536a5fd2e9f4bb9776e86b22a23d Mon Sep 17 00:00:00 2001 From: Saroj Rout Date: Thu, 8 Jan 2026 15:27:51 -0800 Subject: [PATCH 2/3] updated readme --- contributing/samples/resiliency_sample/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contributing/samples/resiliency_sample/README.md b/contributing/samples/resiliency_sample/README.md index 4cab22a..bdf8e15 100644 --- a/contributing/samples/resiliency_sample/README.md +++ b/contributing/samples/resiliency_sample/README.md @@ -1,8 +1,7 @@ # AgentTool Resilience: Timeout, Retry, and Redirect Patterns -This is a **community-contributed sample** that demonstrates how to handle failures, timeouts, and partial results from downstream agents in multi-agent workflows using ADK. +This sample demonstrates how to handle failures, timeouts, and partial results from downstream agents in multi-agent workflows using ADK. -**Note:** This sample uses only core ADK features (`google-adk`) and does not require the community package. It's included in the `adk-python-community` repository as a community-contributed example demonstrating resilience patterns that may be useful to other developers. ## Prerequisites From 3616130caa63dadcd1adfd7d103a47a3b4ad770e Mon Sep 17 00:00:00 2001 From: Saroj Rout Date: Thu, 8 Jan 2026 15:27:51 -0800 Subject: [PATCH 3/3] updated readme --- contributing/samples/resiliency_sample/README.md | 3 +-- .../samples/resiliency_sample/{__Init__.py => __init__.py} | 0 contributing/samples/resiliency_sample/agent.py | 3 --- 3 files changed, 1 insertion(+), 5 deletions(-) rename contributing/samples/resiliency_sample/{__Init__.py => __init__.py} (100%) diff --git a/contributing/samples/resiliency_sample/README.md b/contributing/samples/resiliency_sample/README.md index 4cab22a..bdf8e15 100644 --- a/contributing/samples/resiliency_sample/README.md +++ b/contributing/samples/resiliency_sample/README.md @@ -1,8 +1,7 @@ # AgentTool Resilience: Timeout, Retry, and Redirect Patterns -This is a **community-contributed sample** that demonstrates how to handle failures, timeouts, and partial results from downstream agents in multi-agent workflows using ADK. +This sample demonstrates how to handle failures, timeouts, and partial results from downstream agents in multi-agent workflows using ADK. -**Note:** This sample uses only core ADK features (`google-adk`) and does not require the community package. It's included in the `adk-python-community` repository as a community-contributed example demonstrating resilience patterns that may be useful to other developers. ## Prerequisites diff --git a/contributing/samples/resiliency_sample/__Init__.py b/contributing/samples/resiliency_sample/__init__.py similarity index 100% rename from contributing/samples/resiliency_sample/__Init__.py rename to contributing/samples/resiliency_sample/__init__.py diff --git a/contributing/samples/resiliency_sample/agent.py b/contributing/samples/resiliency_sample/agent.py index f64cfd6..2adc875 100644 --- a/contributing/samples/resiliency_sample/agent.py +++ b/contributing/samples/resiliency_sample/agent.py @@ -31,9 +31,6 @@ from google.adk.tools import AgentTool from google.adk.tools.google_search_tool import google_search from google.adk.tools.tool_context import ToolContext -import time -from google.genai import types -from google.adk.events.event import Event # ============================================================================