surfiniaburger commited on
Commit
a61c2dd
ยท
1 Parent(s): 92a9c38
Files changed (5) hide show
  1. agent_setup.py +13 -8
  2. app.py +23 -13
  3. bigquery_search.py +17 -0
  4. miscellaneous/instructions.md +648 -0
  5. tools.py +25 -0
agent_setup.py CHANGED
@@ -1,6 +1,6 @@
1
  from google.adk import Agent, Runner
2
  from google.adk.sessions import InMemorySessionService
3
- from tools import create_plant_diagnosis_tool, create_remedy_retrieval_tool
4
 
5
  def initialize_adk(vision_model, processor, retriever):
6
  """
@@ -9,23 +9,28 @@ def initialize_adk(vision_model, processor, retriever):
9
  Args:
10
  vision_model: The loaded vision model.
11
  processor: The model's processor.
12
- retriever: The RAG retriever.
13
 
14
  Returns:
15
  A dictionary containing the ADK components, or None on error.
16
  """
17
  print("Initializing ADK Tools and Agent...")
18
  try:
19
- if vision_model and processor and retriever:
20
  diagnosis_tool = create_plant_diagnosis_tool(model=vision_model, processor=processor)
21
- remedy_tool = create_remedy_retrieval_tool(retriever=retriever)
 
22
 
23
  agent = Agent(
24
  name="AuraMindGlowAgent",
25
  model="gemini-2.0-flash",
26
- description="A farming assistant that can diagnose plant health and suggest remedies.",
27
- instruction="You are a friendly farming assistant. Your goal is to help users identify plant health issues and find solutions. Use your tools to diagnose the plant from an image and then find a remedy.",
28
- tools=[diagnosis_tool, remedy_tool]
 
 
 
 
29
  )
30
 
31
  session_service = InMemorySessionService()
@@ -36,7 +41,7 @@ def initialize_adk(vision_model, processor, retriever):
36
  "agent": agent,
37
  "runner": runner,
38
  "diagnosis_tool": diagnosis_tool,
39
- "remedy_tool": remedy_tool,
40
  "session_service": session_service
41
  }
42
  else:
 
1
  from google.adk import Agent, Runner
2
  from google.adk.sessions import InMemorySessionService
3
+ from tools import create_plant_diagnosis_tool, create_chroma_db_search_tool, create_bigquery_search_tool
4
 
5
  def initialize_adk(vision_model, processor, retriever):
6
  """
 
9
  Args:
10
  vision_model: The loaded vision model.
11
  processor: The model's processor.
12
+ retriever: The RAG retriever (no longer used but kept for compatibility).
13
 
14
  Returns:
15
  A dictionary containing the ADK components, or None on error.
16
  """
17
  print("Initializing ADK Tools and Agent...")
18
  try:
19
+ if vision_model and processor:
20
  diagnosis_tool = create_plant_diagnosis_tool(model=vision_model, processor=processor)
21
+ chroma_db_tool = create_chroma_db_search_tool()
22
+ bigquery_tool = create_bigquery_search_tool()
23
 
24
  agent = Agent(
25
  name="AuraMindGlowAgent",
26
  model="gemini-2.0-flash",
27
+ description="A farming assistant that can diagnose plant health and suggest remedies from local or cloud knowledge bases.",
28
+ instruction="You are a friendly and intelligent farming assistant. Your primary goal is to help users identify plant health issues and find solutions. You have several tools at your disposal:\n" \
29
+ "- Use the 'diagnose_plant' tool when the user provides an image.\n" \
30
+ "- After diagnosing, use the 'search_chroma_db' tool to find a remedy in the local knowledge base.\n" \
31
+ "- If the user asks for cloud-based information or structured data, use the 'search_bigquery' tool.\n" \
32
+ "Always prioritize the local knowledge base (ChromaDB) for remedies unless the user specifies otherwise.",
33
+ tools=[diagnosis_tool, chroma_db_tool, bigquery_tool]
34
  )
35
 
36
  session_service = InMemorySessionService()
 
41
  "agent": agent,
42
  "runner": runner,
43
  "diagnosis_tool": diagnosis_tool,
44
+ "remedy_tool": chroma_db_tool, # For compatibility with app.py
45
  "session_service": session_service
46
  }
47
  else:
app.py CHANGED
@@ -17,7 +17,7 @@ import json
17
  import re
18
  import requests # Added for authentication
19
 
20
- from google.cloud import bigquery
21
 
22
  # Suppress potential warnings for a cleaner console
23
  warnings.filterwarnings("ignore")
@@ -232,9 +232,8 @@ def create_field_mode_ui(user_state):
232
  # Note: For a full implementation, you would pass the user_state to other UIs
233
  # and use the farmer_id there as well.
234
 
235
- def create_connected_mode_ui():
236
  """Creates the Gradio UI for the online Connected Mode."""
237
- # ... (This function remains unchanged) ...
238
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="green", secondary_hue="lime")) as demo:
239
  gr.Markdown("# ๐ŸŒฝ Aura Mind Glow: Connected Mode ๐Ÿค–")
240
  gr.Markdown("I am an AI farming assistant. Upload an image and ask for a diagnosis and remedy.")
@@ -242,10 +241,16 @@ def create_connected_mode_ui():
242
  chatbot = gr.Chatbot(height=600)
243
  msg = gr.MultimodalTextbox(file_types=["image"], label="Ask a question and/or upload an image...")
244
 
245
- async def respond(chat_input, history):
246
- user_id = "default_user" # In a real app, this would be unique per user
 
 
 
 
 
 
247
  if not SESSION_SERVICE or not ADK_RUNNER:
248
- history.append((chat_input["text"], "Connected mode is not available. Check logs."))
249
  yield history, gr.MultimodalTextbox(value=None)
250
  return
251
 
@@ -254,8 +259,13 @@ def create_connected_mode_ui():
254
  files = chat_input.get("files", [])
255
  text = chat_input.get("text", "")
256
 
 
 
 
 
 
257
  if not files:
258
- history.append([text, "Please upload an image for diagnosis."])
259
  yield history, gr.MultimodalTextbox(value=None)
260
  return
261
 
@@ -273,7 +283,7 @@ def create_connected_mode_ui():
273
 
274
  # Stream the response from the agent
275
  bot_message = ""
276
- history.append([(files[0],), bot_message])
277
 
278
  try:
279
  async for event in ADK_RUNNER.run_async(
@@ -281,20 +291,20 @@ def create_connected_mode_ui():
281
  ):
282
  if event.is_llm_response_chunk() and event.content.parts:
283
  bot_message += event.content.parts[0].text
284
- history[-1] = ((files[0],), bot_message)
285
  yield history, gr.MultimodalTextbox(value=None)
286
  elif event.is_final_response() and event.content.parts:
287
  bot_message = event.content.parts[0].text
288
- history[-1] = ((files[0],), bot_message)
289
  yield history, gr.MultimodalTextbox(value=None)
290
 
291
  except Exception as e:
292
  print(f"Error during agent execution: {e}")
293
- history[-1] = ((files[0],), f"An error occurred: {e}")
294
  yield history, gr.MultimodalTextbox(value=None)
295
 
296
 
297
- msg.submit(respond, [msg, chatbot], [chatbot, msg])
298
 
299
  return demo
300
 
@@ -518,7 +528,7 @@ if __name__ == "__main__":
518
  tab_titles.append("Field Mode")
519
 
520
  if check_internet_connection():
521
- if ADK_RUNNER: interface_list.append(create_connected_mode_ui()); tab_titles.append("Connected Mode")
522
  if STORY_LLM: interface_list.append(create_story_mode_ui()); tab_titles.append("Farmer's Story")
523
  interface_list.append(create_document_analysis_ui()); tab_titles.append("Doc Analysis")
524
  interface_list.append(create_settings_ui()); tab_titles.append("Settings")
 
17
  import re
18
  import requests # Added for authentication
19
 
20
+ from bigquery_search import search_bigquery_for_remedy
21
 
22
  # Suppress potential warnings for a cleaner console
23
  warnings.filterwarnings("ignore")
 
232
  # Note: For a full implementation, you would pass the user_state to other UIs
233
  # and use the farmer_id there as well.
234
 
235
+ def create_connected_mode_ui(user_state):
236
  """Creates the Gradio UI for the online Connected Mode."""
 
237
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="green", secondary_hue="lime")) as demo:
238
  gr.Markdown("# ๐ŸŒฝ Aura Mind Glow: Connected Mode ๐Ÿค–")
239
  gr.Markdown("I am an AI farming assistant. Upload an image and ask for a diagnosis and remedy.")
 
241
  chatbot = gr.Chatbot(height=600)
242
  msg = gr.MultimodalTextbox(file_types=["image"], label="Ask a question and/or upload an image...")
243
 
244
+ async def respond(chat_input, history, user_state):
245
+ if not user_state or not user_state.get("uid"):
246
+ history.append((chat_input.get("text", ""), "Authentication error. Please log out and log in again."))
247
+ yield history, gr.MultimodalTextbox(value=None)
248
+ return
249
+
250
+ user_id = user_state["uid"]
251
+
252
  if not SESSION_SERVICE or not ADK_RUNNER:
253
+ history.append((chat_input.get("text", ""), "Connected mode is not available. Check logs."))
254
  yield history, gr.MultimodalTextbox(value=None)
255
  return
256
 
 
259
  files = chat_input.get("files", [])
260
  text = chat_input.get("text", "")
261
 
262
+ if not files and not text:
263
+ # If there is no input, do nothing
264
+ yield history, gr.MultimodalTextbox(value=None)
265
+ return
266
+
267
  if not files:
268
+ history.append((text, "Please upload an image for diagnosis."))
269
  yield history, gr.MultimodalTextbox(value=None)
270
  return
271
 
 
283
 
284
  # Stream the response from the agent
285
  bot_message = ""
286
+ history.append([(files[0], text), bot_message])
287
 
288
  try:
289
  async for event in ADK_RUNNER.run_async(
 
291
  ):
292
  if event.is_llm_response_chunk() and event.content.parts:
293
  bot_message += event.content.parts[0].text
294
+ history[-1] = (((files[0], text), bot_message))
295
  yield history, gr.MultimodalTextbox(value=None)
296
  elif event.is_final_response() and event.content.parts:
297
  bot_message = event.content.parts[0].text
298
+ history[-1] = (((files[0], text), bot_message))
299
  yield history, gr.MultimodalTextbox(value=None)
300
 
301
  except Exception as e:
302
  print(f"Error during agent execution: {e}")
303
+ history[-1] = (((files[0], text), f"An error occurred: {e}"))
304
  yield history, gr.MultimodalTextbox(value=None)
305
 
306
 
307
+ msg.submit(respond, [msg, chatbot, user_state], [chatbot, msg])
308
 
309
  return demo
310
 
 
528
  tab_titles.append("Field Mode")
529
 
530
  if check_internet_connection():
531
+ if ADK_RUNNER: interface_list.append(create_connected_mode_ui(user_state)); tab_titles.append("Connected Mode")
532
  if STORY_LLM: interface_list.append(create_story_mode_ui()); tab_titles.append("Farmer's Story")
533
  interface_list.append(create_document_analysis_ui()); tab_titles.append("Doc Analysis")
534
  interface_list.append(create_settings_ui()); tab_titles.append("Settings")
bigquery_search.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from google.cloud import bigquery
2
+
3
+ def search_bigquery_for_remedy(search_query: str) -> str:
4
+ try:
5
+ client = bigquery.Client(project="gem-creation")
6
+ query = """
7
+ SELECT remedy_description FROM `gem-creation.maize_remedies.remedies`
8
+ WHERE SEARCH(remedy_description, @query)
9
+ """
10
+ job_config = bigquery.QueryJobConfig(
11
+ query_parameters=[bigquery.ScalarQueryParameter("query", "STRING", search_query)]
12
+ )
13
+ query_job = client.query(query, job_config=job_config)
14
+ results = list(query_job)
15
+ return results[0].remedy_description if results else "No remedy found."
16
+ except Exception as e:
17
+ return f"Error querying BigQuery: {e}"
miscellaneous/instructions.md CHANGED
@@ -3130,3 +3130,651 @@ async def call_agent_async(query):
3130
  # Note: In Colab, you can directly use 'await' at the top level.
3131
  # If running this code as a standalone Python script, you'll need to use asyncio.run() or manage the event loop.
3132
  await call_agent_async("what's the latest news on AI Agents?")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3130
  # Note: In Colab, you can directly use 'await' at the top level.
3131
  # If running this code as a standalone Python script, you'll need to use asyncio.run() or manage the event loop.
3132
  await call_agent_async("what's the latest news on AI Agents?")
3133
+
3134
+
3135
+ ADK_Learning_tools.ipynb
3136
+ ADK_Learning_tools.ipynb_
3137
+ ๐Ÿš€ Welcome to Your ADK Adventure - Tools & Memory! ๐Ÿš€
3138
+ Welcome, Agent Architect! This notebook is your guide to giving your AI agents two essential superpowers: custom tools and conversational memory.
3139
+
3140
+ By the end of this adventure, you will be able to:
3141
+
3142
+ Build a Foundational Agent: Create a simple but effective AI agent from scratch using the Google Agent Development Kit (ADK).
3143
+
3144
+ Grant New Skills with Custom Tools: Teach an agent to perform new tasks by connecting it to external APIs, like a real-time weather service.
3145
+
3146
+ Create a Team of Agents: Assemble a multi-agent system where a primary agent can delegate specialized tasks to other agents.
3147
+
3148
+ Master Conversational Memory: Understand the critical role of Sessions in enabling agents to remember previous interactions, handle feedback, and carry on a coherent conversation.
3149
+
3150
+ Let's get this adventure started!
3151
+
3152
+ Author
3153
+ HI, I'm Qingyue (Annie) Wang, a developer advocate and AI engineer at Google, passionate about helping developers build with AI and cloud technologies :)
3154
+
3155
+ If you have questions with this notebook, contact me on LinkedIn , X or email anniewangtech0510@Gmail.com
3156
+
3157
+ (\__/)
3158
+ (โ€ขใ……โ€ข)
3159
+ /ใฅ ๐Ÿ“š Enjoy learning AI Agents :)
3160
+ ๐ŸŽ ๐Ÿ›‘ Important Prerequisite: Setup Your Environment! ๐Ÿ›‘ ๐ŸŽ
3161
+ ๐Ÿ‘‰ Get Your API Key HERE: https://codelabs.developers.google.com/onramp/instructions#1
3162
+
3163
+ โฌ†๏ธ โฌ†๏ธ โฌ†๏ธ โฌ†๏ธ โฌ†๏ธ โฌ†๏ธ โฌ†๏ธ โฌ†๏ธ โฌ†๏ธ โฌ†๏ธ โฌ†๏ธ โฌ†๏ธ โฌ†๏ธ โฌ†๏ธ โฌ†๏ธ
3164
+ /\_/\ /\_/\ /\_/\ /\_/\ /\_/\
3165
+ ( ^_^ ) ( -.- ) ( >_< ) ( =^.^= ) ( o_o )
3166
+ Part 0: Setup & Authentication ๐Ÿ”‘
3167
+ First things first, let's get all our tools ready. This step installs the necessary libraries and securely configures your Google API key so your agents can access the power of Gemini.
3168
+
3169
+
3170
+ [ ]
3171
+ !pip install google-adk google-generativeai -q
3172
+
3173
+ # --- Import all necessary libraries for our entire adventure ---
3174
+ import os
3175
+ import re
3176
+ import asyncio
3177
+ from IPython.display import display, Markdown
3178
+ import google.generativeai as genai
3179
+ from google.adk.agents import Agent
3180
+ from google.adk.tools import google_search
3181
+ from google.adk.runners import Runner
3182
+ from google.adk.sessions import InMemorySessionService, Session
3183
+ from google.genai.types import Content, Part
3184
+ from getpass import getpass
3185
+
3186
+ print("โœ… All libraries are ready to go!")
3187
+
3188
+ [ ]
3189
+ # --- Securely Configure Your API Key ---
3190
+
3191
+ # Prompt the user for their API key securely
3192
+ api_key = getpass('Enter your Google API Key: ')
3193
+
3194
+ # Get Your API Key HERE ๐Ÿ‘‰ https://codelabs.developers.google.com/onramp/instructions#0
3195
+ # Configure the generative AI library with the provided key
3196
+ genai.configure(api_key=api_key)
3197
+
3198
+ # Set the API key as an environment variable for ADK to use
3199
+ os.environ['GOOGLE_API_KEY'] = api_key
3200
+
3201
+ print("โœ… API Key configured successfully! Let the fun begin.")
3202
+ Part 1: Your First Agent - The Day Trip Genie ๐Ÿงž
3203
+ Meet your first creation! The day_trip_agent is a simple but powerful assistant. We're making it a little smarter by teaching it to understand budget constraints.
3204
+
3205
+ Agent: The brain of the operation, defined by its instructions, tools, and the AI model it uses.
3206
+ Session: The conversation history. For this simple agent, it's just a container for a single request-response.
3207
+ Runner: The engine that connects the Agent and the Session to process your request and get a response.
3208
+ +--------------------------------------------------+
3209
+ | Spontaneous Day Trip Agent ๐Ÿค– |
3210
+ |--------------------------------------------------|
3211
+ | Model: gemini-2.5-flash |
3212
+ | Description: |
3213
+ | Generates full-day trip itineraries based on |
3214
+ | mood, interests, and budget |
3215
+ |--------------------------------------------------|
3216
+ | ๐Ÿ”ง Tools: |
3217
+ | - Google Search |
3218
+ |--------------------------------------------------|
3219
+ | ๐Ÿง  Capabilities: |
3220
+ | - Budget Awareness (cheap / splurge) |
3221
+ | - Mood Matching (adventurous, relaxing, etc.) |
3222
+ | - Real-Time Info (hours, events) |
3223
+ | - Morning / Afternoon / Evening plan |
3224
+ +--------------------------------------------------+
3225
+
3226
+ โ–ฒ
3227
+ |
3228
+ +------------------+
3229
+ | User Input |
3230
+ |------------------|
3231
+ | Mood |
3232
+ | Interests |
3233
+ | Budget |
3234
+ +------------------+
3235
+
3236
+ |
3237
+ โ–ผ
3238
+
3239
+ +--------------------------------------------------+
3240
+ | Output: Markdown Itinerary |
3241
+ |--------------------------------------------------|
3242
+ | - Time blocks (Morning / Afternoon / Evening) |
3243
+ | - Venue names with links and hours |
3244
+ | - Budget-matching activities |
3245
+ +--------------------------------------------------+
3246
+
3247
+ [ ]
3248
+ # --- Agent Definition ---
3249
+
3250
+ def create_day_trip_agent():
3251
+ """Create the Spontaneous Day Trip Generator agent"""
3252
+ return Agent(
3253
+ name="day_trip_agent",
3254
+ model="gemini-2.5-flash",
3255
+ description="Agent specialized in generating spontaneous full-day itineraries based on mood, interests, and budget.",
3256
+ instruction="""
3257
+ You are the "Spontaneous Day Trip" Generator ๐Ÿš— - a specialized AI assistant that creates engaging full-day itineraries.
3258
+
3259
+ Your Mission:
3260
+ Transform a simple mood or interest into a complete day-trip adventure with real-time details, while respecting a budget.
3261
+
3262
+ Guidelines:
3263
+ 1. **Budget-Aware**: Pay close attention to budget hints like 'cheap', 'affordable', or 'splurge'. Use Google Search to find activities (free museums, parks, paid attractions) that match the user's budget.
3264
+ 2. **Full-Day Structure**: Create morning, afternoon, and evening activities.
3265
+ 3. **Real-Time Focus**: Search for current operating hours and special events.
3266
+ 4. **Mood Matching**: Align suggestions with the requested mood (adventurous, relaxing, artsy, etc.).
3267
+
3268
+ RETURN itinerary in MARKDOWN FORMAT with clear time blocks and specific venue names.
3269
+ """,
3270
+ tools=[google_search]
3271
+ )
3272
+
3273
+ day_trip_agent = create_day_trip_agent()
3274
+ print(f"๐Ÿงž Agent '{day_trip_agent.name}' is created and ready for adventure!")
3275
+
3276
+ [ ]
3277
+ # --- A Helper Function to Run Our Agents ---
3278
+ # We'll use this function throughout the notebook to make running queries easy.
3279
+
3280
+ async def run_agent_query(agent: Agent, query: str, session: Session, user_id: str, is_router: bool = False):
3281
+ """Initializes a runner and executes a query for a given agent and session."""
3282
+ print(f"\n๐Ÿš€ Running query for agent: '{agent.name}' in session: '{session.id}'...")
3283
+
3284
+ runner = Runner(
3285
+ agent=agent,
3286
+ session_service=session_service,
3287
+ app_name=agent.name
3288
+ )
3289
+
3290
+ final_response = ""
3291
+ try:
3292
+ async for event in runner.run_async(
3293
+ user_id=user_id,
3294
+ session_id=session.id,
3295
+ new_message=Content(parts=[Part(text=query)], role="user")
3296
+ ):
3297
+ if not is_router:
3298
+ # Let's see what the agent is thinking!
3299
+ print(f"EVENT: {event}")
3300
+ if event.is_final_response():
3301
+ final_response = event.content.parts[0].text
3302
+ except Exception as e:
3303
+ final_response = f"An error occurred: {e}"
3304
+
3305
+ if not is_router:
3306
+ print("\n" + "-"*50)
3307
+ print("โœ… Final Response:")
3308
+ display(Markdown(final_response))
3309
+ print("-"*50 + "\n")
3310
+
3311
+ return final_response
3312
+
3313
+ # --- Initialize our Session Service ---
3314
+ # This one service will manage all the different sessions in our notebook.
3315
+ session_service = InMemorySessionService()
3316
+ my_user_id = "adk_adventurer_001"
3317
+
3318
+ [ ]
3319
+ # --- Let's test the Day Trip Genie! ---
3320
+
3321
+ async def run_day_trip_genie():
3322
+ # Create a new, single-use session for this query
3323
+ day_trip_session = await session_service.create_session(
3324
+ app_name=day_trip_agent.name,
3325
+ user_id=my_user_id
3326
+ )
3327
+
3328
+ # Note the new budget constraint in the query!
3329
+ query = "Plan a relaxing and artsy day trip near Sunnyvale, CA. Keep it affordable!"
3330
+ print(f"๐Ÿ—ฃ๏ธ User Query: '{query}'")
3331
+
3332
+ await run_agent_query(day_trip_agent, query, day_trip_session, my_user_id)
3333
+
3334
+ await run_day_trip_genie()
3335
+ Part 2: Supercharging Agents with Custom Tools ๐Ÿ› ๏ธ
3336
+ So far, we've used the powerful built-in GoogleSearch tool. But the true power of agents comes from connecting them to your own logic and data sources.
3337
+
3338
+ This is where custom tools come in. Let's explore three patterns for giving your agent new skills, using real-world, practical examples.
3339
+
3340
+ 2.1 The Simple FunctionTool: Calling a Real-Time Weather API
3341
+ The most direct way to create a tool is by writing a Python function. This is perfect for synchronous tasks like fetching data from an API.
3342
+
3343
+ Key Concept: The function's docstring is critical. The ADK uses it as the tool's official description, which the LLM reads to understand its purpose, parameters, and when to use it.
3344
+
3345
+ In this example, we'll create a tool that calls the free, public U.S. National Weather Service API to get a real-time forecast. No API key needed!
3346
+
3347
+
3348
+ [ ]
3349
+ # --- Tool Definition: A function that calls a live public API ---
3350
+ import requests
3351
+ import json
3352
+
3353
+ # A simple lookup to avoid needing a separate geocoding API for this example
3354
+ LOCATION_COORDINATES = {
3355
+ "sunnyvale": "37.3688,-122.0363",
3356
+ "san francisco": "37.7749,-122.4194",
3357
+ "lake tahoe": "39.0968,-120.0324"
3358
+ }
3359
+
3360
+ def get_live_weather_forecast(location: str) -> dict:
3361
+ """Gets the current, real-time weather forecast for a specified location in the US.
3362
+
3363
+ Args:
3364
+ location: The city name, e.g., "San Francisco".
3365
+
3366
+ Returns:
3367
+ A dictionary containing the temperature and a detailed forecast.
3368
+ """
3369
+ print(f"๐Ÿ› ๏ธ TOOL CALLED: get_live_weather_forecast(location='{location}')")
3370
+
3371
+ # Find coordinates for the location
3372
+ normalized_location = location.lower()
3373
+ coords_str = None
3374
+ for key, val in LOCATION_COORDINATES.items():
3375
+ if key in normalized_location:
3376
+ coords_str = val
3377
+ break
3378
+ if not coords_str:
3379
+ return {"status": "error", "message": f"I don't have coordinates for {location}."}
3380
+
3381
+ try:
3382
+ # NWS API requires 2 steps: 1. Get the forecast URL from the coordinates.
3383
+ points_url = f"https://api.weather.gov/points/{coords_str}"
3384
+ headers = {"User-Agent": "ADK Example Notebook"}
3385
+ points_response = requests.get(points_url, headers=headers)
3386
+ points_response.raise_for_status() # Raise an exception for bad status codes
3387
+ forecast_url = points_response.json()['properties']['forecast']
3388
+
3389
+ # 2. Get the actual forecast from the URL.
3390
+ forecast_response = requests.get(forecast_url, headers=headers)
3391
+ forecast_response.raise_for_status()
3392
+
3393
+ # Extract the relevant forecast details
3394
+ current_period = forecast_response.json()['properties']['periods'][0]
3395
+ return {
3396
+ "status": "success",
3397
+ "temperature": f"{current_period['temperature']}ยฐ{current_period['temperatureUnit']}",
3398
+ "forecast": current_period['detailedForecast']
3399
+ }
3400
+ except requests.exceptions.RequestException as e:
3401
+ return {"status": "error", "message": f"API request failed: {e}"}
3402
+
3403
+ # --- Agent Definition: An agent that USES the new tool ---
3404
+
3405
+ weather_agent = Agent(
3406
+ name="weather_aware_planner",
3407
+ model="gemini-2.5-flash",
3408
+ description="A trip planner that checks the real-time weather before making suggestions.",
3409
+ instruction="You are a cautious trip planner. Before suggesting any outdoor activities, you MUST use the `get_live_weather_forecast` tool to check conditions. Incorporate the live weather details into your recommendation.",
3410
+ tools=[get_live_weather_forecast]
3411
+ )
3412
+
3413
+ print(f"๐ŸŒฆ๏ธ Agent '{weather_agent.name}' is created and can now call a live weather API!")
3414
+
3415
+ [ ]
3416
+ # --- Let's test the Weather-Aware Planner ---
3417
+
3418
+ async def run_weather_planner_test():
3419
+ weather_session = await session_service.create_session(app_name=weather_agent.name, user_id=my_user_id)
3420
+ query = "I want to go hiking near Lake Tahoe, what's the weather like?"
3421
+ print(f"๐Ÿ—ฃ๏ธ User Query: '{query}'")
3422
+ await run_agent_query(weather_agent, query, weather_session, my_user_id)
3423
+
3424
+ await run_weather_planner_test()
3425
+ 2.2 The Agent-as-a-Tool: Consulting a Specialist ๐Ÿง‘โ€๐Ÿณ
3426
+ Why build one agent that does everything when you can build a team of specialist agents? The Agent-as-a-Tool pattern allows one agent to delegate a task to another agent.
3427
+
3428
+ Key Concept: This is different from a sub-agent. When Agent A calls Agent B as a tool, Agent B's response is passed back to Agent A. Agent A then uses that information to form its own final response to the user. It's a powerful way to compose complex behaviors from simpler, focused, and reusable agents.
3429
+
3430
+ How It Works
3431
+ Our top-level agent, the trip_data_concierge_agent, acts as the Orchestrator. It has two tools at its disposal:
3432
+
3433
+ call_db_agent: A function that internally calls our db_agent to fetch raw data.
3434
+ call_concierge_agent: A function that calls the concierge_agent.
3435
+ The concierge_agent itself has a tool: the food_critic_agent.
3436
+
3437
+ The flow for a complex query is:
3438
+
3439
+ User asks the trip_data_concierge_agent for a hotel and a nearby restaurant.
3440
+ The Orchestrator first calls call_db_agent to get hotel data.
3441
+ The data is saved in tool_context.state.
3442
+ The Orchestrator then calls call_concierge_agent, which retrieves the hotel data from the context.
3443
+ The concierge_agent receives the request and decides it needs to use its own tool, the food_critic_agent.
3444
+ The food_critic_agent provides a witty recommendation.
3445
+ The concierge_agent gets the critic's response and politely formats it.
3446
+ This final, polished response is returned to the Orchestrator, which presents it to the user.
3447
+
3448
+ [ ]
3449
+
3450
+ Start coding or generate with AI.
3451
+ +-----------------------------------------------------------+
3452
+ | ๐Ÿงญ Trip Data Concierge Agent |
3453
+ |-----------------------------------------------------------|
3454
+ | Model: gemini-2.5-flash |
3455
+ | Description: |
3456
+ | Orchestrates database query and travel recommendation |
3457
+ |-----------------------------------------------------------|
3458
+ | ๐Ÿ”ง Tools: |
3459
+ | 1. call_db_agent |
3460
+ | 2. call_concierge_agent |
3461
+ +-----------------------------------------------------------+
3462
+ / \
3463
+ / \
3464
+ โ–ผ โ–ผ
3465
+ +-------------------------------------------+ +---------------------------------------------+
3466
+ | ๐Ÿ”ง Tool: call_db_agent | | ๐Ÿ”ง Tool: call_concierge_agent |
3467
+ |-------------------------------------------| |---------------------------------------------|
3468
+ | Calls: db_agent | | Calls: concierge_agent |
3469
+ | | | Uses data from db_agent for recommendations |
3470
+ +-------------------------------------------+ +---------------------------------------------+
3471
+ | |
3472
+ โ–ผ โ–ผ
3473
+ +--------------------------------------------+ +------------------------------------------------+
3474
+ | ๐Ÿ“ฆ db_agent | | ๐Ÿคต concierge_agent |
3475
+ |--------------------------------------------| |------------------------------------------------|
3476
+ | Model: gemini-2.5-flash | | Model: gemini-2.5-flash |
3477
+ | Role: Return mock JSON hotel data | | Role: Hotel staff that handles user Q&A |
3478
+ +--------------------------------------------+ | Tools: |
3479
+ | - food_critic_agent |
3480
+ +------------------------------------------------+
3481
+ |
3482
+ โ–ผ
3483
+ +------------------------------------------------+
3484
+ | ๐Ÿฝ๏ธ food_critic_agent |
3485
+ |------------------------------------------------|
3486
+ | Model: gemini-2.5-flash |
3487
+ | Role: Gives a witty restaurant recommendation |
3488
+ +------------------------------------------------+
3489
+
3490
+ [ ]
3491
+ import asyncio
3492
+ from google.adk.tools import ToolContext
3493
+ from google.adk.tools.agent_tool import AgentTool
3494
+
3495
+ # Assume 'db_agent' is a pre-defined NL2SQL Agent
3496
+ # For this example, we'll create placeholder agents.
3497
+
3498
+ db_agent = Agent(
3499
+ name="db_agent",
3500
+ model="gemini-2.5-flash",
3501
+ instruction="You are a database agent. When asked for data, return this mock JSON object: {'status': 'success', 'data': [{'name': 'The Grand Hotel', 'rating': 5, 'reviews': 450}, {'name': 'Seaside Inn', 'rating': 4, 'reviews': 620}]}")
3502
+
3503
+ # --- 1. Define the Specialist Agents ---
3504
+
3505
+ # The Food Critic remains the deepest specialist
3506
+ food_critic_agent = Agent(
3507
+ name="food_critic_agent",
3508
+ model="gemini-2.5-flash",
3509
+ instruction="You are a snobby but brilliant food critic. You ONLY respond with a single, witty restaurant suggestion near the provided location.",
3510
+ )
3511
+
3512
+ # The Concierge knows how to use the Food Critic
3513
+ concierge_agent = Agent(
3514
+ name="concierge_agent",
3515
+ model="gemini-2.5-flash",
3516
+ instruction="You are a five-star hotel concierge. If the user asks for a restaurant recommendation, you MUST use the `food_critic_agent` tool. Present the opinion to the user politely.",
3517
+ tools=[AgentTool(agent=food_critic_agent)]
3518
+ )
3519
+
3520
+
3521
+ # --- 2. Define the Tools for the Orchestrator ---
3522
+
3523
+ async def call_db_agent(
3524
+ question: str,
3525
+ tool_context: ToolContext,
3526
+ ):
3527
+ """
3528
+ Use this tool FIRST to connect to the database and retrieve a list of places, like hotels or landmarks.
3529
+ """
3530
+ print("--- TOOL CALL: call_db_agent ---")
3531
+ agent_tool = AgentTool(agent=db_agent)
3532
+ db_agent_output = await agent_tool.run_async(
3533
+ args={"request": question}, tool_context=tool_context
3534
+ )
3535
+ # Store the retrieved data in the context's state
3536
+ tool_context.state["retrieved_data"] = db_agent_output
3537
+ return db_agent_output
3538
+
3539
+
3540
+ async def call_concierge_agent(
3541
+ question: str,
3542
+ tool_context: ToolContext,
3543
+ ):
3544
+ """
3545
+ After getting data with call_db_agent, use this tool to get travel advice, opinions, or recommendations.
3546
+ """
3547
+ print("--- TOOL CALL: call_concierge_agent ---")
3548
+ # Retrieve the data fetched by the previous tool
3549
+ input_data = tool_context.state.get("retrieved_data", "No data found.")
3550
+
3551
+ # Formulate a new prompt for the concierge, giving it the data context
3552
+ question_with_data = f"""
3553
+ Context: The database returned the following data: {input_data}
3554
+
3555
+ User's Request: {question}
3556
+ """
3557
+
3558
+ agent_tool = AgentTool(agent=concierge_agent)
3559
+ concierge_output = await agent_tool.run_async(
3560
+ args={"request": question_with_data}, tool_context=tool_context
3561
+ )
3562
+ return concierge_output
3563
+
3564
+
3565
+ # --- 3. Define the Top-Level Orchestrator Agent ---
3566
+
3567
+ trip_data_concierge_agent = Agent(
3568
+ name="trip_data_concierge",
3569
+ model="gemini-2.5-flash",
3570
+ description="Top-level agent that queries a database for travel data, then calls a concierge agent for recommendations.",
3571
+ tools=[call_db_agent, call_concierge_agent],
3572
+ instruction="""
3573
+ You are a master travel planner who uses data to make recommendations.
3574
+
3575
+ 1. **ALWAYS start with the `call_db_agent` tool** to fetch a list of places (like hotels) that match the user's criteria.
3576
+
3577
+ 2. After you have the data, **use the `call_concierge_agent` tool** to answer any follow-up questions for recommendations, opinions, or advice related to the data you just found.
3578
+ """,
3579
+ )
3580
+
3581
+ print(f"โœ… Orchestrator Agent '{trip_data_concierge_agent.name}' is defined and ready.")
3582
+
3583
+ [ ]
3584
+ # --- Let's test the Trip Data Concierge Agent ---
3585
+
3586
+ async def run_trip_data_concierge():
3587
+ """
3588
+ Sets up a session and runs a query against the top-level
3589
+ trip_data_concierge_agent.
3590
+ """
3591
+ # Create a new, single-use session for this query
3592
+ concierge_session = await session_service.create_session(
3593
+ app_name=trip_data_concierge_agent.name,
3594
+ user_id=my_user_id
3595
+ )
3596
+
3597
+ # This query is specifically designed to trigger the full two-step process:
3598
+ # 1. Get data from the db_agent.
3599
+ # 2. Get a recommendation from the concierge_agent based on that data.
3600
+ query = "Find the top-rated hotels in San Francisco from the database, then suggest a dinner spot near the one with the most reviews."
3601
+ print(f"๐Ÿ—ฃ๏ธ User Query: '{query}'")
3602
+
3603
+ # We call our existing helper function with the top-level orchestrator agent
3604
+ await run_agent_query(trip_data_concierge_agent, query, concierge_session, my_user_id)
3605
+
3606
+ # Run the test
3607
+ await run_trip_data_concierge()
3608
+ Part 3: Agent with a Memory - The Adaptive Planner ๐Ÿ—บ๏ธ
3609
+ Now, let's see an agent that not only remembers but also adapts. We'll challenge the multi_day_trip_agent to re-plan part of its itinerary based on our feedback. This is a much more realistic test of conversational AI.
3610
+
3611
+ +-----------------------------------------------------+
3612
+ | Adaptive Multi-Day Trip Agent ๐Ÿ—บ๏ธ |
3613
+ |-----------------------------------------------------|
3614
+ | Model: gemini-2.5-flash |
3615
+ | Description: |
3616
+ | Builds multi-day travel itineraries step-by-step, |
3617
+ | remembers previous days, adapts to feedback |
3618
+ |-----------------------------------------------------|
3619
+ | ๐Ÿ”ง Tools: |
3620
+ | - Google Search |
3621
+ |-----------------------------------------------------|
3622
+ | ๐Ÿง  Capabilities: |
3623
+ | - Memory of past conversation & preferences |
3624
+ | - Progressive planning (1 day at a time) |
3625
+ | - Adapts to user feedback |
3626
+ | - Ensures activity variety across days |
3627
+ +-----------------------------------------------------+
3628
+
3629
+ โ–ฒ
3630
+ |
3631
+ +---------------------------+
3632
+ | User Interaction |
3633
+ |---------------------------|
3634
+ | - Destination |
3635
+ | - Trip duration |
3636
+ | - Interests & feedback |
3637
+ +---------------------------+
3638
+
3639
+ |
3640
+ โ–ผ
3641
+
3642
+ +-----------------------------------------------------+
3643
+ | Day-by-Day Itinerary Generation |
3644
+ |-----------------------------------------------------|
3645
+ | ๐Ÿ—“๏ธ Day N Output (Markdown format): |
3646
+ | - Morning / Afternoon / Evening activities |
3647
+ | - Personalized & context-aware |
3648
+ | - Changes accepted, feedback acknowledged |
3649
+ +-----------------------------------------------------+
3650
+
3651
+ |
3652
+ โ–ผ
3653
+
3654
+ +-----------------------------------------------------+
3655
+ | Next Day Planning Triggered ๐Ÿš€ |
3656
+ |-----------------------------------------------------|
3657
+ | - Builds on prior days |
3658
+ | - Avoids repetition |
3659
+ | - Asks user for confirmation before proceeding |
3660
+ +-----------------------------------------------------+
3661
+
3662
+ [ ]
3663
+ # --- Agent Definition: The Adaptive Planner ---
3664
+
3665
+ def create_multi_day_trip_agent():
3666
+ """Create the Progressive Multi-Day Trip Planner agent"""
3667
+ return Agent(
3668
+ name="multi_day_trip_agent",
3669
+ model="gemini-2.5-flash",
3670
+ description="Agent that progressively plans a multi-day trip, remembering previous days and adapting to user feedback.",
3671
+ instruction="""
3672
+ You are the "Adaptive Trip Planner" ๐Ÿ—บ๏ธ - an AI assistant that builds multi-day travel itineraries step-by-step.
3673
+
3674
+ Your Defining Feature:
3675
+ You have short-term memory. You MUST refer back to our conversation to understand the trip's context, what has already been planned, and the user's preferences. If the user asks for a change, you must adapt the plan while keeping the unchanged parts consistent.
3676
+
3677
+ Your Mission:
3678
+ 1. **Initiate**: Start by asking for the destination, trip duration, and interests.
3679
+ 2. **Plan Progressively**: Plan ONLY ONE DAY at a time. After presenting a plan, ask for confirmation.
3680
+ 3. **Handle Feedback**: If a user dislikes a suggestion (e.g., "I don't like museums"), acknowledge their feedback, and provide a *new, alternative* suggestion for that time slot that still fits the overall theme.
3681
+ 4. **Maintain Context**: For each new day, ensure the activities are unique and build logically on the previous days. Do not suggest the same things repeatedly.
3682
+ 5. **Final Output**: Return each day's itinerary in MARKDOWN format.
3683
+ """,
3684
+ tools=[google_search]
3685
+ )
3686
+
3687
+ multi_day_agent = create_multi_day_trip_agent()
3688
+ print(f"๐Ÿ—บ๏ธ Agent '{multi_day_agent.name}' is created and ready to plan and adapt!")
3689
+ Scenario 3a: Agent WITH Memory (Using a SINGLE Session) โœ…
3690
+ First, let's see the correct way to do it. We will use the exact same trip_session object for the entire conversation. Watch how the agent remembers the context from Turn 1 to correctly handle the requests in Turn 2 and 3.
3691
+
3692
+
3693
+ [ ]
3694
+ # --- Scenario 2: Testing Adaptation and Memory ---
3695
+
3696
+ async def run_adaptive_memory_demonstration():
3697
+ print("### ๐Ÿง  DEMO 2: AGENT THAT ADAPTS (SAME SESSION) ###")
3698
+
3699
+ # Create ONE session that we will reuse for the whole conversation
3700
+ trip_session = await session_service.create_session(
3701
+ app_name=multi_day_agent.name,
3702
+ user_id=my_user_id
3703
+ )
3704
+ print(f"Created a single session for our trip: {trip_session.id}")
3705
+
3706
+ # --- Turn 1: The user initiates the trip ---
3707
+ query1 = "Hi! I want to plan a 2-day trip to Lisbon, Portugal. I'm interested in historic sites and great local food."
3708
+ print(f"\n๐Ÿ—ฃ๏ธ User (Turn 1): '{query1}'")
3709
+ await run_agent_query(multi_day_agent, query1, trip_session, my_user_id)
3710
+
3711
+ # --- Turn 2: The user gives FEEDBACK and asks for a CHANGE ---
3712
+ # We use the EXACT SAME `trip_session` object!
3713
+ query2 = "That sounds pretty good, but I'm not a huge fan of castles. Can you replace the morning activity for Day 1 with something else historical?"
3714
+ print(f"\n๐Ÿ—ฃ๏ธ User (Turn 2 - Feedback): '{query2}'")
3715
+ await run_agent_query(multi_day_agent, query2, trip_session, my_user_id)
3716
+
3717
+ # --- Turn 3: The user confirms and asks to continue ---
3718
+ query3 = "Yes, the new plan for Day 1 is perfect! Please plan Day 2 now, keeping the food theme in mind."
3719
+ print(f"\n๐Ÿ—ฃ๏ธ User (Turn 3 - Confirmation): '{query3}'")
3720
+ await run_agent_query(multi_day_agent, query3, trip_session, my_user_id)
3721
+
3722
+ await run_adaptive_memory_demonstration()
3723
+ Scenario 3b: Agent WITHOUT Memory (Using SEPARATE Sessions) โŒ
3724
+ Now, let's see what happens if we mess up our session management. Here, we'll give the agent a case of amnesia by creating a brand new, separate session for each turn.
3725
+
3726
+ Pay close attention to the agent's response to the second query. Because it's in a new session, it has no memory of the trip to Lisbon we just discussed!
3727
+
3728
+
3729
+ [ ]
3730
+ # --- Scenario 2b: Demonstrating Memory FAILURE ---
3731
+
3732
+ async def run_memory_failure_demonstration():
3733
+ print("\n" + "#"*60)
3734
+ print("### ๐Ÿง  DEMO 2b: AGENT WITH AMNESIA (SEPARATE SESSIONS) ###")
3735
+ print("#"*60)
3736
+
3737
+ # --- Turn 1: The user initiates the trip in the FIRST session ---
3738
+ query1 = "Hi! I want to plan a 2-day trip to Lisbon, Portugal. I'm interested in historic sites and great local food."
3739
+ session_one = await session_service.create_session(
3740
+ app_name=multi_day_agent.name,
3741
+ user_id=my_user_id
3742
+ )
3743
+ print(f"\nCreated a session for Turn 1: {session_one.id}")
3744
+ print(f"๐Ÿ—ฃ๏ธ User (Turn 1): '{query1}'")
3745
+ await run_agent_query(multi_day_agent, query1, session_one, my_user_id)
3746
+
3747
+ # --- Turn 2: The user asks to continue... but in a completely NEW session ---
3748
+ query2 = "Yes, that looks perfect! Please plan Day 2."
3749
+ session_two = await session_service.create_session(
3750
+ app_name=multi_day_agent.name,
3751
+ user_id=my_user_id
3752
+ )
3753
+ print(f"\nCreated a BRAND NEW session for Turn 2: {session_two.id}")
3754
+ print(f"๐Ÿ—ฃ๏ธ User (Turn 2): '{query2}'")
3755
+ await run_agent_query(multi_day_agent, query2, session_two, my_user_id)
3756
+
3757
+ await run_memory_failure_demonstration()
3758
+ See? The agent was confused! It likely asked what destination or what trip we were talking about. Because the second query was in a fresh, isolated session, the agent had no memory of planning Day 1 in Lisbon.
3759
+
3760
+ This perfectly illustrates why managing sessions is the key to building truly conversational agents!
3761
+
3762
+ ๐ŸŽ‰ Congratulations! ๐ŸŽ‰
3763
+ Congratulations on completing your ADK adventure into Tools and Memory! You've taken a massive leap from building single-shot agents to creating dynamic, stateful AI systems.
3764
+
3765
+ Let's recap the powerful concepts you've mastered:
3766
+
3767
+ Fundamental Agent & Tools: You started by building a "Day Trip Genie" and equipped it with its first tool, GoogleSearch.
3768
+
3769
+ Custom Function Tools: You gave your agent a new sense by creating a custom tool to fetch live data from the U.S. National Weather Service API.
3770
+
3771
+ Agent-as-a-Tool: You orchestrated a sophisticated hierarchy where agents delegate tasks to other, more specialized agents, creating a collaborative team.
3772
+
3773
+ The Power of Memory: Most importantly, you saw firsthand how managing a single, persistent Session allows an agent to remember context, adapt to user feedback, and conduct a meaningful, multi-turn conversation.
3774
+
3775
+ __ /\_/\ /\_/\ /\_/\ __ (\__/)
3776
+ o-''|\_____/). ( o.o ) ( -.- ) ( ^_^ ) o-''|\_____/). ( ^_^ )
3777
+ \_/|_) ) > ^ < > * < >๐Ÿ’–< \_/|_) ) / >๐ŸŒธ< \
3778
+ \ __ / \ __ / / \
3779
+ (_/ (_/ (_/ (_/ (___|___)
3780
+ Colab paid products - Cancel contracts here
tools.py CHANGED
@@ -5,6 +5,8 @@ from PIL import Image
5
  from transformers import AutoProcessor
6
  from unsloth import FastVisionModel
7
  from langchain_community.vectorstores import FAISS
 
 
8
 
9
  def create_plant_diagnosis_tool(model: FastVisionModel, processor: AutoProcessor):
10
  """Factory function to create the plant diagnosis tool."""
@@ -63,3 +65,26 @@ def create_remedy_retrieval_tool(retriever: FAISS):
63
  return "No specific remedy found in the knowledge base for this condition."
64
 
65
  return retrieve_remedy
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  from transformers import AutoProcessor
6
  from unsloth import FastVisionModel
7
  from langchain_community.vectorstores import FAISS
8
+ from vector_store import search_documents
9
+ from bigquery_search import search_bigquery_for_remedy
10
 
11
  def create_plant_diagnosis_tool(model: FastVisionModel, processor: AutoProcessor):
12
  """Factory function to create the plant diagnosis tool."""
 
65
  return "No specific remedy found in the knowledge base for this condition."
66
 
67
  return retrieve_remedy
68
+
69
+ def create_chroma_db_search_tool():
70
+ """Factory function to create the ChromaDB search tool."""
71
+
72
+ def search_chroma_db(query: str) -> str:
73
+ """
74
+ Searches the local ChromaDB vector store for a remedy based on a diagnosis query.
75
+ """
76
+ results = search_documents(query)
77
+ return results[0] if results else "No remedy found in local knowledge base."
78
+
79
+ return search_chroma_db
80
+
81
+ def create_bigquery_search_tool():
82
+ """Factory function to create the BigQuery search tool."""
83
+
84
+ def search_bigquery(query: str) -> str:
85
+ """
86
+ Searches BigQuery for a remedy based on a diagnosis query.
87
+ """
88
+ return search_bigquery_for_remedy(query)
89
+
90
+ return search_bigquery