2020 JSON output constrained by output_schema.
2121
2222Graph structure:
23- __start__ → pipeline → coordinator → research_agent (with search_web tool )
23+ __start__ → pipeline → coordinator → research_agent (with search_wikipedia + search_tavily tools )
2424 → code_agent (with run_python tool)
2525 → formatter (output_schema=ReportOutput)
2626 → __end__
2929 - input_schema: from FIRST sub_agent chain → coordinator.input_schema (ReportInput)
3030 - output_schema: from LAST sub_agent chain → formatter.output_schema (ReportOutput)
3131 - output_key: from LAST sub_agent chain → formatter.output_key ("report")
32+
33+ Environment variables:
34+ - TAVILY_API_KEY: API key for Tavily web search (get one at https://tavily.com)
3235"""
3336
3437import io
35- import json
38+ import os
3639import sys
3740import traceback
38- import urllib .parse
39- import urllib .request
4041
42+ import httpx
4143from google .adk .agents import Agent , SequentialAgent
4244from pydantic import BaseModel , Field
4345
@@ -61,28 +63,69 @@ class ReportOutput(BaseModel):
6163 code_snippet : str = Field (description = "A relevant Python code example" )
6264
6365
64- def search_web (query : str ) -> str :
65- """Search Wikipedia for information on a topic.
66+ def search_wikipedia (topic : str ) -> str :
67+ """Search Wikipedia for encyclopedic information on a topic.
68+
69+ Best for well-known concepts, historical facts, and established knowledge.
6670
6771 Args:
68- query : The search query
72+ topic : The topic to look up on Wikipedia
6973
7074 Returns:
7175 Summary text from Wikipedia, or an error message if not found
7276 """
73- encoded = urllib .parse .quote (query )
74- url = f"https://en.wikipedia.org/api/rest_v1/page/summary/{ encoded } "
75- req = urllib .request .Request (
76- url , headers = {"User-Agent" : "UiPathGoogleADKSample/1.0" }
77- )
7877 try :
79- with urllib .request .urlopen (req , timeout = 10 ) as resp :
80- data = json .loads (resp .read ().decode ())
81- title = data .get ("title" , query )
82- extract = data .get ("extract" , "No summary available." )
83- return f"Wikipedia — { title } : { extract } "
78+ resp = httpx .get (
79+ f"https://en.wikipedia.org/api/rest_v1/page/summary/{ topic } " ,
80+ headers = {"User-Agent" : "UiPathGoogleADKSample/1.0" },
81+ timeout = 10 ,
82+ )
83+ resp .raise_for_status ()
84+ data = resp .json ()
85+ title = data .get ("title" , topic )
86+ extract = data .get ("extract" , "No summary available." )
87+ return f"Wikipedia — { title } : { extract } "
88+ except Exception as e :
89+ return f"Wikipedia search failed for '{ topic } ': { e } "
90+
91+
92+ def search_tavily (query : str ) -> str :
93+ """Search the web using Tavily for recent and real-time information.
94+
95+ Best for current events, recent developments, and up-to-date information
96+ that may not yet be on Wikipedia.
97+
98+ Args:
99+ query: The search query
100+
101+ Returns:
102+ Search results with snippets from relevant web pages
103+ """
104+ api_key = os .environ .get ("TAVILY_API_KEY" , "" )
105+ if not api_key :
106+ return "Tavily search unavailable: TAVILY_API_KEY not set"
107+
108+ try :
109+ resp = httpx .post (
110+ "https://api.tavily.com/search" ,
111+ json = {"query" : query , "max_results" : 3 , "include_answer" : True },
112+ headers = {"Authorization" : f"Bearer { api_key } " },
113+ timeout = 15 ,
114+ )
115+ resp .raise_for_status ()
116+ data = resp .json ()
117+ parts = []
118+ answer = data .get ("answer" )
119+ if answer :
120+ parts .append (f"Summary: { answer } " )
121+ for result in data .get ("results" , []):
122+ title = result .get ("title" , "" )
123+ content = result .get ("content" , "" )
124+ source = result .get ("url" , "" )
125+ parts .append (f"- { title } : { content } ({ source } )" )
126+ return "\n " .join (parts ) if parts else "No results found."
84127 except Exception as e :
85- return f"Search failed for '{ query } ': { e } "
128+ return f"Tavily search failed for '{ query } ': { e } "
86129
87130
88131def run_python (code : str ) -> str :
@@ -109,16 +152,21 @@ def run_python(code: str) -> str:
109152
110153# --- Sub-agents ---
111154
112- # Research agent: searches Wikipedia and gathers information
155+ # Research agent: has two search tools for comprehensive research.
156+ # - search_wikipedia: encyclopedic/established knowledge
157+ # - search_tavily: real-time web search for recent information
113158research_agent = Agent (
114159 name = "research_agent" ,
115160 model = "gemini-2.5-flash" ,
116161 instruction = (
117- "You are a research specialist. Use the search_web tool to find "
118- "information about the given topic. Provide a thorough summary of "
119- "your findings."
162+ "You are a research specialist with two search tools:\n "
163+ "- search_wikipedia: for encyclopedic facts and established knowledge\n "
164+ "- search_tavily: for recent developments and real-time web information\n \n "
165+ "Use both tools to gather comprehensive information about the given topic. "
166+ "Start with Wikipedia for foundational knowledge, then use Tavily for "
167+ "recent developments. Provide a thorough summary of your findings."
120168 ),
121- tools = [search_web ],
169+ tools = [search_wikipedia , search_tavily ],
122170)
123171
124172# Code agent: writes and executes Python code related to the topic.
0 commit comments