agarwalamit081 commited on
Commit
3d5f7d7
·
verified ·
1 Parent(s): 0450ea3

Update app.py

Browse files

fixed budget parsing

Files changed (1) hide show
  1. app.py +23 -71
app.py CHANGED
@@ -9,18 +9,15 @@ from smolagents import CodeAgent, DuckDuckGoSearchTool, HfApiModel, tool
9
  from Gradio_UI import GradioUI
10
 
11
  # ======================
12
- # TRAVEL TOOLS (SMOLAGENTS-COMPLIANT DOCSTRINGS)
13
  # ======================
14
-
15
  @tool
16
  def get_weather_forecast(location: str, travel_dates: str) -> str:
17
  """
18
  Get weather forecast for destination using wttr.in API.
19
-
20
  Args:
21
  location: Destination city name (e.g., "Barcelona")
22
  travel_dates: Travel date range string (e.g., "October 15-19")
23
-
24
  Returns:
25
  Weather summary string with temperature and packing recommendations
26
  """
@@ -32,17 +29,14 @@ def get_weather_forecast(location: str, travel_dates: str) -> str:
32
  cur = data["current_condition"][0]
33
  temp = int(cur["temp_C"])
34
  cond = cur["lang_en"][0]["value"].lower()
35
-
36
  if temp > 25:
37
  pack = "Light clothing, shorts, breathable fabrics, sunscreen, hat"
38
  elif temp > 15:
39
  pack = "Light layers, long sleeves, light jacket"
40
  else:
41
  pack = "Warm layers, jacket, beanie recommended"
42
-
43
  if "rain" in cond or "shower" in cond:
44
  pack += " + compact umbrella + waterproof jacket"
45
-
46
  return f"{location} forecast: {temp}°C, {cond}. Packing: {pack}"
47
  except Exception:
48
  return f"{location} typical weather: 15-25°C. Pack versatile layers, light jacket, and compact umbrella."
@@ -51,22 +45,18 @@ def get_weather_forecast(location: str, travel_dates: str) -> str:
51
  def convert_currency(amount: float, from_currency: str, to_currency: str) -> str:
52
  """
53
  Convert currency amount using Frankfurter API (no API key required).
54
-
55
  Args:
56
  amount: Numeric amount to convert (e.g., 1200.0)
57
  from_currency: Source currency ISO code (e.g., "USD")
58
  to_currency: Target currency ISO code (e.g., "EUR")
59
-
60
  Returns:
61
  Formatted string showing conversion result and exchange rate
62
  """
63
  try:
64
  from_curr = from_currency.upper()[:3]
65
  to_curr = to_currency.upper()[:3]
66
-
67
  if from_curr == to_curr:
68
- return f"{amount:,.0f} {from_curr}"
69
-
70
  resp = requests.get(
71
  f"https://api.frankfurter.app/latest",
72
  params={"from": from_curr, "to": to_curr},
@@ -77,17 +67,15 @@ def convert_currency(amount: float, from_currency: str, to_currency: str) -> str
77
  converted = amount * rate
78
  return f"{amount:,.0f} {from_curr} = {converted:,.0f} {to_curr} (1 {from_curr} = {rate:.2f} {to_curr})"
79
  except Exception:
80
- return f"{amount:,.0f} {from_currency} (conversion rate unavailable)"
81
 
82
  @tool
83
  def get_time_difference(origin_city: str, destination_city: str) -> str:
84
  """
85
  Calculate time difference between origin and destination cities using heuristic mapping.
86
-
87
  Args:
88
  origin_city: Traveler's home city name (e.g., "New York")
89
  destination_city: Travel destination city name (e.g., "Paris")
90
-
91
  Returns:
92
  Human-readable string describing time difference and jet lag advice
93
  """
@@ -108,14 +96,11 @@ def get_time_difference(origin_city: str, destination_city: str) -> str:
108
  "tallinn": 2, "sofia": 2, "bucharest": 2, "zagreb": 1, "ljubljana": 1,
109
  "belgrade": 1, "sarajevo": 1, "nicosia": 2, "valletta": 1, "reykjavik": 0,
110
  }
111
-
112
  origin_key = origin_city.lower().strip()
113
  dest_key = destination_city.lower().strip()
114
-
115
  origin_tz = city_tz.get(origin_key, 0)
116
  dest_tz = city_tz.get(dest_key, 0)
117
  diff = dest_tz - origin_tz
118
-
119
  if diff == 0:
120
  return f"No time difference between {origin_city} and {destination_city}."
121
  elif diff > 0:
@@ -127,13 +112,11 @@ def get_time_difference(origin_city: str, destination_city: str) -> str:
127
  def generate_packing_list(destination: str, weather_summary: str, trip_days: int, trip_type: str) -> str:
128
  """
129
  Generate customized packing checklist based on destination, weather, duration and trip type.
130
-
131
  Args:
132
  destination: Destination city or region name (e.g., "Barcelona")
133
  weather_summary: Weather forecast string containing temperature and conditions
134
  trip_days: Total number of travel days (integer >= 1)
135
  trip_type: Type of trip: "city", "beach", "mountain", or "mixed"
136
-
137
  Returns:
138
  Formatted multi-section packing checklist as string
139
  """
@@ -141,10 +124,8 @@ def generate_packing_list(destination: str, weather_summary: str, trip_days: int
141
  cold = any(w in weather_lower for w in ["cold", "cool", "10°c", "11°c", "12°c", "13°c", "14°c", "jacket", "below 15"])
142
  rain = any(w in weather_lower for w in ["rain", "shower", "drizzle", "umbrella", "precipitation"])
143
  hot = any(w in weather_lower for w in ["hot", "warm", "25°c", "26°c", "27°c", "28°c", "29°c", "30°c", "above 25"])
144
-
145
  tops = min(trip_days, trip_days // 2 + 2)
146
  bottoms = min(trip_days // 2 + 1, 4)
147
-
148
  clothes = [f"• Tops ({tops})", f"• Bottoms ({bottoms})"]
149
  if cold:
150
  clothes.extend(["• Warm jacket/coat", "• Long underwear (if very cold)", "• Warm socks (x3)"])
@@ -152,15 +133,12 @@ def generate_packing_list(destination: str, weather_summary: str, trip_days: int
152
  clothes.extend(["• Light breathable fabrics", "• Sun hat", "• Sunglasses", "• Reef-safe sunscreen (SPF 50+)"])
153
  else:
154
  clothes.append("• Light jacket or sweater (essential)")
155
-
156
  if rain:
157
  clothes.extend(["• Compact travel umbrella", "• Quick-dry clothing", "• Waterproof shoes or sandals"])
158
-
159
  if trip_type == "beach":
160
  clothes.extend(["• Swimsuit (x2)", "• Beach towel", "• Flip-flops/sandals", "• Beach bag"])
161
  elif trip_type == "mountain":
162
  clothes.extend(["• Sturdy hiking shoes", "• Moisture-wicking base layers", "• Trekking socks (x3)", "• Daypack"])
163
-
164
  return (
165
  f"🎒 SMART PACKING LIST ({trip_days}-day {trip_type} trip to {destination})\n"
166
  "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"
@@ -183,35 +161,28 @@ def generate_packing_list(destination: str, weather_summary: str, trip_days: int
183
  def build_itinerary(destination: str, attractions: str, budget_local: float, days: int) -> str:
184
  """
185
  Create realistic day-by-day travel itinerary with time allocations and budget guidance.
186
-
187
  Args:
188
  destination: Destination city name (e.g., "Barcelona")
189
  attractions: Comma-separated list of attraction names (e.g., "Sagrada Familia, Park Guell")
190
- budget_local: Total budget converted to local currency (float)
191
  days: Number of full travel days (integer >= 1)
192
-
193
  Returns:
194
  Formatted multi-day itinerary with time slots and daily budget allocation
195
  """
196
  att_list = [a.strip() for a in attractions.split(",") if a.strip()]
197
  if not att_list:
198
  att_list = ["Old Town exploration", "Local museum", "Scenic viewpoint", "Local market"]
199
-
200
- daily_budget = budget_local / max(days, 1)
201
  lines = [f"🗓️ {days}-DAY REALISTIC ITINERARY: {destination}", "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"]
202
-
203
  for d in range(1, days + 1):
204
  primary = att_list[(d - 1) % len(att_list)]
205
  secondary = att_list[d % len(att_list)] if len(att_list) > 1 else "Leisurely café break"
206
-
207
  lines.extend([
208
- f"\nDAY {d} | Budget: ~{daily_budget:,.0f} local currency",
209
  f" 09:00 - 12:00 {primary} (arrive early to avoid crowds)",
210
- f" 12:30 - 14:00 Lunch at local spot (budget: ~{daily_budget * 0.25:,.0f})",
211
  f" 14:30 - 17:00 {secondary}",
212
- f" 19:00+ Dinner + evening stroll (budget: ~{daily_budget * 0.35:,.0f})"
213
  ])
214
-
215
  lines.append("\n💡 Pro tips: Book major attractions online in advance. Use public transport day passes for 30%+ savings.")
216
  return "\n".join(lines)
217
 
@@ -219,15 +190,13 @@ def build_itinerary(destination: str, attractions: str, budget_local: float, day
219
  def generate_travel_images(destination: str) -> str:
220
  """
221
  Generate two realistic placeholder image URLs for the destination using Unsplash API (no key required).
222
-
223
  Args:
224
  destination: Destination city name (e.g., "Lisbon")
225
-
226
  Returns:
227
  JSON-formatted string containing two image URLs with keys "landmark_image" and "street_scene_image"
228
  """
229
  try:
230
- clean_dest = re.sub(r"[^a-zA-Z\s]", "", destination).strip()
231
  landmark_url = f"https://source.unsplash.com/800x600/?{clean_dest},landmark,architecture,travel"
232
  street_url = f"https://source.unsplash.com/800x600/?{clean_dest},street,people,culture,travel"
233
  return f'{{"landmark_image": "{landmark_url}", "street_scene_image": "{street_url}"}}'
@@ -248,7 +217,6 @@ def assemble_catalogue(
248
  ) -> str:
249
  """
250
  Compile all travel research into a beautiful, structured Markdown travel catalogue.
251
-
252
  Args:
253
  destination: Destination city name (e.g., "Lisbon")
254
  origin: Traveler's home city (e.g., "London")
@@ -259,7 +227,6 @@ def assemble_catalogue(
259
  itinerary: Day-by-day schedule with time allocations
260
  packing_list: Complete customized packing checklist
261
  image_urls_json: JSON string with "landmark_image" and "street_scene_image" URLs
262
-
263
  Returns:
264
  Complete Markdown-formatted travel catalogue with embedded images
265
  """
@@ -277,49 +244,36 @@ def assemble_catalogue(
277
 
278
  return f"""# 🌍 {destination} Travel Catalogue
279
  *Planned from {origin} • {dates} • {budget_summary}*
280
-
281
  ---
282
-
283
  ## ⏰ Time Zone Adjustment
284
  {timezone_info}
285
-
286
  ---
287
-
288
  ## 🌤️ Weather Forecast & Packing Guidance
289
  {weather}
290
-
291
  ---
292
-
293
  ## 🗓️ Your Personalized {day_count}-Day Itinerary
294
  {itinerary}
295
-
296
  ---
297
-
298
  ## 🎒 Complete Packing Checklist
299
  {packing_list}
300
-
301
  ---
302
-
303
  ## 📸 Visual Inspiration
304
-
305
  <div style="display: flex; gap: 20px; margin: 20px 0;">
306
- <div style="flex: 1; text-align: center;">
307
- <img src="{img1}" alt="{destination} landmark" style="max-width: 100%; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);">
308
- <p><em>Iconic {destination} landmark</em></p>
309
- </div>
310
- <div style="flex: 1; text-align: center;">
311
- <img src="{img2}" alt="{destination} street scene" style="max-width: 100%; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);">
312
- <p><em>Vibrant local atmosphere</em></p>
313
- </div>
314
  </div>
315
-
316
  ---
317
-
318
- > 💡 **Travel Pro Tips**
319
- > • Download offline Google Maps before departure
320
- > • Learn 5 basic phrases in the local language
321
- > • Keep digital copies of passport/insurance in cloud storage
322
- > • Budget 10-15% extra for spontaneous experiences
323
  > • Public transport passes often save 30%+ vs single tickets
324
  """
325
 
@@ -328,14 +282,12 @@ def assemble_catalogue(
328
  # ======================
329
  if __name__ == "__main__":
330
  print("🚀 Initializing Travel Catalogue Creator...")
331
-
332
  # Load system prompt from YAML
333
  with open("prompts.yaml", "r") as f:
334
  prompt_config = yaml.safe_load(f)
335
 
336
- # Load tools
337
  web_search = DuckDuckGoSearchTool()
338
-
339
  model = HfApiModel(
340
  max_tokens=2048,
341
  temperature=0.3,
@@ -345,7 +297,7 @@ if __name__ == "__main__":
345
  agent = CodeAgent(
346
  model=model,
347
  tools=[
348
- web_search,
349
  get_weather_forecast,
350
  convert_currency,
351
  get_time_difference,
 
9
  from Gradio_UI import GradioUI
10
 
11
  # ======================
12
+ # TRAVEL TOOLS (SMOLAGENTS-COMPLIANT)
13
  # ======================
 
14
  @tool
15
  def get_weather_forecast(location: str, travel_dates: str) -> str:
16
  """
17
  Get weather forecast for destination using wttr.in API.
 
18
  Args:
19
  location: Destination city name (e.g., "Barcelona")
20
  travel_dates: Travel date range string (e.g., "October 15-19")
 
21
  Returns:
22
  Weather summary string with temperature and packing recommendations
23
  """
 
29
  cur = data["current_condition"][0]
30
  temp = int(cur["temp_C"])
31
  cond = cur["lang_en"][0]["value"].lower()
 
32
  if temp > 25:
33
  pack = "Light clothing, shorts, breathable fabrics, sunscreen, hat"
34
  elif temp > 15:
35
  pack = "Light layers, long sleeves, light jacket"
36
  else:
37
  pack = "Warm layers, jacket, beanie recommended"
 
38
  if "rain" in cond or "shower" in cond:
39
  pack += " + compact umbrella + waterproof jacket"
 
40
  return f"{location} forecast: {temp}°C, {cond}. Packing: {pack}"
41
  except Exception:
42
  return f"{location} typical weather: 15-25°C. Pack versatile layers, light jacket, and compact umbrella."
 
45
  def convert_currency(amount: float, from_currency: str, to_currency: str) -> str:
46
  """
47
  Convert currency amount using Frankfurter API (no API key required).
 
48
  Args:
49
  amount: Numeric amount to convert (e.g., 1200.0)
50
  from_currency: Source currency ISO code (e.g., "USD")
51
  to_currency: Target currency ISO code (e.g., "EUR")
 
52
  Returns:
53
  Formatted string showing conversion result and exchange rate
54
  """
55
  try:
56
  from_curr = from_currency.upper()[:3]
57
  to_curr = to_currency.upper()[:3]
 
58
  if from_curr == to_curr:
59
+ return f"{amount:,.0f} {from_curr} = {amount:,.0f} {to_curr} (1 {from_curr} = 1.00 {to_curr})"
 
60
  resp = requests.get(
61
  f"https://api.frankfurter.app/latest",
62
  params={"from": from_curr, "to": to_curr},
 
67
  converted = amount * rate
68
  return f"{amount:,.0f} {from_curr} = {converted:,.0f} {to_curr} (1 {from_curr} = {rate:.2f} {to_curr})"
69
  except Exception:
70
+ return f"{amount:,.0f} {from_currency} = {amount:,.0f} {to_currency} (conversion rate unavailable)"
71
 
72
  @tool
73
  def get_time_difference(origin_city: str, destination_city: str) -> str:
74
  """
75
  Calculate time difference between origin and destination cities using heuristic mapping.
 
76
  Args:
77
  origin_city: Traveler's home city name (e.g., "New York")
78
  destination_city: Travel destination city name (e.g., "Paris")
 
79
  Returns:
80
  Human-readable string describing time difference and jet lag advice
81
  """
 
96
  "tallinn": 2, "sofia": 2, "bucharest": 2, "zagreb": 1, "ljubljana": 1,
97
  "belgrade": 1, "sarajevo": 1, "nicosia": 2, "valletta": 1, "reykjavik": 0,
98
  }
 
99
  origin_key = origin_city.lower().strip()
100
  dest_key = destination_city.lower().strip()
 
101
  origin_tz = city_tz.get(origin_key, 0)
102
  dest_tz = city_tz.get(dest_key, 0)
103
  diff = dest_tz - origin_tz
 
104
  if diff == 0:
105
  return f"No time difference between {origin_city} and {destination_city}."
106
  elif diff > 0:
 
112
  def generate_packing_list(destination: str, weather_summary: str, trip_days: int, trip_type: str) -> str:
113
  """
114
  Generate customized packing checklist based on destination, weather, duration and trip type.
 
115
  Args:
116
  destination: Destination city or region name (e.g., "Barcelona")
117
  weather_summary: Weather forecast string containing temperature and conditions
118
  trip_days: Total number of travel days (integer >= 1)
119
  trip_type: Type of trip: "city", "beach", "mountain", or "mixed"
 
120
  Returns:
121
  Formatted multi-section packing checklist as string
122
  """
 
124
  cold = any(w in weather_lower for w in ["cold", "cool", "10°c", "11°c", "12°c", "13°c", "14°c", "jacket", "below 15"])
125
  rain = any(w in weather_lower for w in ["rain", "shower", "drizzle", "umbrella", "precipitation"])
126
  hot = any(w in weather_lower for w in ["hot", "warm", "25°c", "26°c", "27°c", "28°c", "29°c", "30°c", "above 25"])
 
127
  tops = min(trip_days, trip_days // 2 + 2)
128
  bottoms = min(trip_days // 2 + 1, 4)
 
129
  clothes = [f"• Tops ({tops})", f"• Bottoms ({bottoms})"]
130
  if cold:
131
  clothes.extend(["• Warm jacket/coat", "• Long underwear (if very cold)", "• Warm socks (x3)"])
 
133
  clothes.extend(["• Light breathable fabrics", "• Sun hat", "• Sunglasses", "• Reef-safe sunscreen (SPF 50+)"])
134
  else:
135
  clothes.append("• Light jacket or sweater (essential)")
 
136
  if rain:
137
  clothes.extend(["• Compact travel umbrella", "• Quick-dry clothing", "• Waterproof shoes or sandals"])
 
138
  if trip_type == "beach":
139
  clothes.extend(["• Swimsuit (x2)", "• Beach towel", "• Flip-flops/sandals", "• Beach bag"])
140
  elif trip_type == "mountain":
141
  clothes.extend(["• Sturdy hiking shoes", "• Moisture-wicking base layers", "• Trekking socks (x3)", "• Daypack"])
 
142
  return (
143
  f"🎒 SMART PACKING LIST ({trip_days}-day {trip_type} trip to {destination})\n"
144
  "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"
 
161
  def build_itinerary(destination: str, attractions: str, budget_local: float, days: int) -> str:
162
  """
163
  Create realistic day-by-day travel itinerary with time allocations and budget guidance.
 
164
  Args:
165
  destination: Destination city name (e.g., "Barcelona")
166
  attractions: Comma-separated list of attraction names (e.g., "Sagrada Familia, Park Guell")
167
+ budget_local: Daily budget in local currency (float)
168
  days: Number of full travel days (integer >= 1)
 
169
  Returns:
170
  Formatted multi-day itinerary with time slots and daily budget allocation
171
  """
172
  att_list = [a.strip() for a in attractions.split(",") if a.strip()]
173
  if not att_list:
174
  att_list = ["Old Town exploration", "Local museum", "Scenic viewpoint", "Local market"]
 
 
175
  lines = [f"🗓️ {days}-DAY REALISTIC ITINERARY: {destination}", "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"]
 
176
  for d in range(1, days + 1):
177
  primary = att_list[(d - 1) % len(att_list)]
178
  secondary = att_list[d % len(att_list)] if len(att_list) > 1 else "Leisurely café break"
 
179
  lines.extend([
180
+ f"\nDAY {d} | Budget: ~{budget_local:,.0f} local currency",
181
  f" 09:00 - 12:00 {primary} (arrive early to avoid crowds)",
182
+ f" 12:30 - 14:00 Lunch at local spot (budget: ~{budget_local * 0.25:,.0f})",
183
  f" 14:30 - 17:00 {secondary}",
184
+ f" 19:00+ Dinner + evening stroll (budget: ~{budget_local * 0.35:,.0f})"
185
  ])
 
186
  lines.append("\n💡 Pro tips: Book major attractions online in advance. Use public transport day passes for 30%+ savings.")
187
  return "\n".join(lines)
188
 
 
190
  def generate_travel_images(destination: str) -> str:
191
  """
192
  Generate two realistic placeholder image URLs for the destination using Unsplash API (no key required).
 
193
  Args:
194
  destination: Destination city name (e.g., "Lisbon")
 
195
  Returns:
196
  JSON-formatted string containing two image URLs with keys "landmark_image" and "street_scene_image"
197
  """
198
  try:
199
+ clean_dest = re.sub(r"[^a-zA-Z\s]", "", destination).strip().replace(" ", "%20")
200
  landmark_url = f"https://source.unsplash.com/800x600/?{clean_dest},landmark,architecture,travel"
201
  street_url = f"https://source.unsplash.com/800x600/?{clean_dest},street,people,culture,travel"
202
  return f'{{"landmark_image": "{landmark_url}", "street_scene_image": "{street_url}"}}'
 
217
  ) -> str:
218
  """
219
  Compile all travel research into a beautiful, structured Markdown travel catalogue.
 
220
  Args:
221
  destination: Destination city name (e.g., "Lisbon")
222
  origin: Traveler's home city (e.g., "London")
 
227
  itinerary: Day-by-day schedule with time allocations
228
  packing_list: Complete customized packing checklist
229
  image_urls_json: JSON string with "landmark_image" and "street_scene_image" URLs
 
230
  Returns:
231
  Complete Markdown-formatted travel catalogue with embedded images
232
  """
 
244
 
245
  return f"""# 🌍 {destination} Travel Catalogue
246
  *Planned from {origin} • {dates} • {budget_summary}*
 
247
  ---
 
248
  ## ⏰ Time Zone Adjustment
249
  {timezone_info}
 
250
  ---
 
251
  ## 🌤️ Weather Forecast & Packing Guidance
252
  {weather}
 
253
  ---
 
254
  ## 🗓️ Your Personalized {day_count}-Day Itinerary
255
  {itinerary}
 
256
  ---
 
257
  ## 🎒 Complete Packing Checklist
258
  {packing_list}
 
259
  ---
 
260
  ## 📸 Visual Inspiration
 
261
  <div style="display: flex; gap: 20px; margin: 20px 0;">
262
+ <div style="flex: 1; text-align: center;">
263
+ <img src="{img1}" alt="{destination} landmark" style="max-width: 100%; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);">
264
+ <p><em>Iconic {destination} landmark</em></p>
265
+ </div>
266
+ <div style="flex: 1; text-align: center;">
267
+ <img src="{img2}" alt="{destination} street scene" style="max-width: 100%; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);">
268
+ <p><em>Vibrant local atmosphere</em></p>
269
+ </div>
270
  </div>
 
271
  ---
272
+ > 💡 **Travel Pro Tips**
273
+ > Download offline Google Maps before departure
274
+ > • Learn 5 basic phrases in the local language
275
+ > • Keep digital copies of passport/insurance in cloud storage
276
+ > • Budget 10-15% extra for spontaneous experiences
 
277
  > • Public transport passes often save 30%+ vs single tickets
278
  """
279
 
 
282
  # ======================
283
  if __name__ == "__main__":
284
  print("🚀 Initializing Travel Catalogue Creator...")
 
285
  # Load system prompt from YAML
286
  with open("prompts.yaml", "r") as f:
287
  prompt_config = yaml.safe_load(f)
288
 
289
+ # Pre-instantiate tools (CRITICAL: tools must be pre-instantiated)
290
  web_search = DuckDuckGoSearchTool()
 
291
  model = HfApiModel(
292
  max_tokens=2048,
293
  temperature=0.3,
 
297
  agent = CodeAgent(
298
  model=model,
299
  tools=[
300
+ web_search, # Pre-instantiated search tool (called as "web_search" in code)
301
  get_weather_forecast,
302
  convert_currency,
303
  get_time_difference,