cjb97 commited on
Commit
22f9799
·
1 Parent(s): 3eb452f

Update tools to use @tool decorator format

Browse files
Files changed (5) hide show
  1. app.py +3 -8
  2. tools/__init__.py +4 -4
  3. tools/final_answer.py +8 -40
  4. tools/search.py +36 -55
  5. tools/weather.py +40 -143
app.py CHANGED
@@ -1,14 +1,9 @@
1
  from smolagents import CodeAgent, HfApiModel
2
  import yaml
3
- from tools import FinalAnswerTool, WeatherTool, DuckDuckGoSearchTool
4
  from Gradio_UI import GradioUI
5
  import os
6
 
7
- # Initialize our tools
8
- final_answer = FinalAnswerTool()
9
- weather_tool = WeatherTool()
10
- search_tool = DuckDuckGoSearchTool()
11
-
12
  # Get the Hugging Face token from environment variable
13
  hf_token = os.getenv('HUGGINGFACE_TOKEN')
14
  if not hf_token:
@@ -30,8 +25,8 @@ agent = CodeAgent(
30
  model=model,
31
  tools=[
32
  final_answer,
33
- search_tool,
34
- weather_tool
35
  ],
36
  max_steps=6,
37
  verbosity_level=1,
 
1
  from smolagents import CodeAgent, HfApiModel
2
  import yaml
3
+ from tools import final_answer, get_weather, duck_duck_go_search
4
  from Gradio_UI import GradioUI
5
  import os
6
 
 
 
 
 
 
7
  # Get the Hugging Face token from environment variable
8
  hf_token = os.getenv('HUGGINGFACE_TOKEN')
9
  if not hf_token:
 
25
  model=model,
26
  tools=[
27
  final_answer,
28
+ duck_duck_go_search,
29
+ get_weather
30
  ],
31
  max_steps=6,
32
  verbosity_level=1,
tools/__init__.py CHANGED
@@ -1,7 +1,7 @@
1
  """Tools for the agent."""
2
 
3
- from .final_answer import FinalAnswerTool
4
- from .weather import WeatherTool
5
- from .search import DuckDuckGoSearchTool
6
 
7
- __all__ = ["FinalAnswerTool", "WeatherTool", "DuckDuckGoSearchTool"]
 
1
  """Tools for the agent."""
2
 
3
+ from .final_answer import final_answer
4
+ from .weather import get_weather
5
+ from .search import duck_duck_go_search
6
 
7
+ __all__ = ["final_answer", "get_weather", "duck_duck_go_search"]
tools/final_answer.py CHANGED
@@ -1,41 +1,9 @@
1
- from smolagents.tools import Tool
2
- from typing import Any, Optional
3
 
4
- class FinalAnswerTool(Tool):
5
- """Tool for providing a final answer to the user's query."""
6
-
7
- name = "final_answer"
8
- description = "Use this tool to provide your final answer to the user's question."
9
- output_type = "string"
10
- inputs = {
11
- "answer": {
12
- "type": "string",
13
- "description": "The final answer to provide to the user."
14
- }
15
- }
16
-
17
- def __call__(self, answer: str) -> str:
18
- """
19
- Provide a final answer to the user's query.
20
-
21
- Args:
22
- answer: The final answer to provide to the user.
23
-
24
- Returns:
25
- A confirmation message.
26
- """
27
- return answer
28
-
29
- forward = __call__
30
-
31
- def __str__(self) -> str:
32
- return "final_answer"
33
-
34
- @property
35
- def signature(self) -> str:
36
- return "final_answer(answer: str) -> str"
37
-
38
- def argument_descriptions(self) -> dict:
39
- return {
40
- "answer": "The final answer to provide to the user."
41
- }
 
1
+ from smolagents.tools import tool
 
2
 
3
+ @tool
4
+ def final_answer(answer: str) -> str:
5
+ """Use this tool to provide your final answer to the user's question.
6
+ Args:
7
+ answer: The final answer to provide to the user.
8
+ """
9
+ return answer
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tools/search.py CHANGED
@@ -1,61 +1,42 @@
1
- from smolagents.tools import Tool
2
  import requests
3
  from typing import Any, List, Dict, Optional
4
  import json
5
 
6
- class DuckDuckGoSearchTool(Tool):
7
- """Tool for searching the web using DuckDuckGo."""
8
-
9
- name = "duck_duck_go_search"
10
- description = "Search the web for information using DuckDuckGo."
11
- output_type = "string"
12
- inputs = {
13
- "query": {
14
- "type": "string",
15
- "description": "A string representing the search query."
 
 
 
 
16
  }
17
- }
18
-
19
- def __call__(self, query: str) -> str:
20
- """
21
- Search the web for information using DuckDuckGo.
22
 
23
- Args:
24
- query: A string representing the search query.
25
-
26
- Returns:
27
- A string with the search results.
28
- """
29
- try:
30
- # Using the DuckDuckGo API
31
- url = "https://api.duckduckgo.com/"
32
- params = {
33
- 'q': query,
34
- 'format': 'json',
35
- 'no_html': 1,
36
- 'skip_disambig': 1
37
- }
38
-
39
- response = requests.get(url, params=params)
40
- data = response.json()
41
-
42
- results = []
43
-
44
- # Add the abstract if available
45
- if data.get('Abstract'):
46
- results.append(f"Abstract: {data['Abstract']}")
47
-
48
- # Add related topics
49
- if data.get('RelatedTopics'):
50
- for i, topic in enumerate(data['RelatedTopics'][:5]): # Limit to 5 topics
51
- if 'Text' in topic:
52
- results.append(f"Result {i+1}: {topic['Text']}")
53
-
54
- if not results:
55
- return f"No results found for query: {query}"
56
-
57
- return "\n\n".join(results)
58
- except Exception as e:
59
- return f"Error searching for {query}: {str(e)}"
60
-
61
- forward = __call__
 
1
+ from smolagents.tools import tool
2
  import requests
3
  from typing import Any, List, Dict, Optional
4
  import json
5
 
6
+ @tool
7
+ def duck_duck_go_search(query: str) -> str:
8
+ """Search the web for information using DuckDuckGo.
9
+ Args:
10
+ query: A string representing the search query.
11
+ """
12
+ try:
13
+ # Using the DuckDuckGo API
14
+ url = "https://api.duckduckgo.com/"
15
+ params = {
16
+ 'q': query,
17
+ 'format': 'json',
18
+ 'no_html': 1,
19
+ 'skip_disambig': 1
20
  }
 
 
 
 
 
21
 
22
+ response = requests.get(url, params=params)
23
+ data = response.json()
24
+
25
+ results = []
26
+
27
+ # Add the abstract if available
28
+ if data.get('Abstract'):
29
+ results.append(f"Abstract: {data['Abstract']}")
30
+
31
+ # Add related topics
32
+ if data.get('RelatedTopics'):
33
+ for i, topic in enumerate(data['RelatedTopics'][:5]): # Limit to 5 topics
34
+ if 'Text' in topic:
35
+ results.append(f"Result {i+1}: {topic['Text']}")
36
+
37
+ if not results:
38
+ return f"No results found for query: {query}"
39
+
40
+ return "\n\n".join(results)
41
+ except Exception as e:
42
+ return f"Error searching for {query}: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tools/weather.py CHANGED
@@ -1,151 +1,48 @@
1
- from smolagents.tools import Tool
2
  import requests
3
  from typing import Any, Optional
4
  import os # Added for accessing environment variables
5
  import re
6
 
7
- class WeatherTool(Tool):
8
- """Tool for getting weather information for a location."""
9
-
10
- name = "get_weather"
11
- description = "Get the current weather for a specified location."
12
- output_type = "string"
13
- inputs = {
14
- "location": {
15
- "type": "string",
16
- "description": "A string representing a city (e.g., 'New York', 'Paris')."
17
- }
18
- }
19
-
20
- def __call__(self, location: str) -> str:
21
- """
22
- Get the current weather for a specified location.
23
-
24
- Args:
25
- location: A string representing a city (e.g., 'New York', 'Paris').
26
-
27
- Returns:
28
- A JSON blob with the current weather information in imperial units. The JSON blob should be formatted as a string. The response should be in the following format:
29
- {
30
- "coord": {
31
- "lon": 7.367,
32
- "lat": 45.133
33
- },
34
- "weather": [
35
- {
36
- "id": 501,
37
- "main": "Rain",
38
- "description": "moderate rain",
39
- "icon": "10d"
40
- }
41
- ],
42
- "base": "stations",
43
- "main": {
44
- "temp": 284.2,
45
- "feels_like": 282.93,
46
- "temp_min": 283.06,
47
- "temp_max": 286.82,
48
- "pressure": 1021,
49
- "humidity": 60,
50
- "sea_level": 1021,
51
- "grnd_level": 910
52
- },
53
- "visibility": 10000,
54
- "wind": {
55
- "speed": 4.09,
56
- "deg": 121,
57
- "gust": 3.47
58
- },
59
- "rain": {
60
- "1h": 2.73
61
- },
62
- "clouds": {
63
- "all": 83
64
- },
65
- "dt": 1726660758,
66
- "sys": {
67
- "type": 1,
68
- "id": 6736,
69
- "country": "IT",
70
- "sunrise": 1726636384,
71
- "sunset": 1726680975
72
- },
73
- "timezone": 7200,
74
- "id": 3165523,
75
- "name": "Province of Turin",
76
- "cod": 200
77
- }
78
 
79
- The definitions of the JSON keys are:
80
- coord.lon Longitude of the location
81
- coord.lat Latitude of the location
82
- weather.id Weather condition id
83
- weather.main Group of weather parameters (Rain, Snow, Clouds etc.)
84
- weather.description Weather condition within the group. Please find more here. You can get the output in your language. Learn more
85
- weather.icon Weather icon id
86
- base Internal parameter
87
- main.temp Temperature. Unit Default: Kelvin, Metric: Celsius, Imperial: Fahrenheit
88
- main.feels_like Temperature. This temperature parameter accounts for the human perception of weather. Unit Default: Kelvin, Metric: Celsius, Imperial: Fahrenheit
89
- main.pressure Atmospheric pressure on the sea level, hPa
90
- main.humidity Humidity, %
91
- main.temp_min Minimum temperature at the moment. This is minimal currently observed temperature (within large megalopolises and urban areas). Please find more info here. Unit Default: Kelvin, Metric: Celsius, Imperial: Fahrenheit
92
- main.temp_max Maximum temperature at the moment. This is maximal currently observed temperature (within large megalopolises and urban areas). Please find more info here. Unit Default: Kelvin, Metric: Celsius, Imperial: Fahrenheit
93
- main.sea_level Atmospheric pressure on the sea level, hPa
94
- main.grnd_level Atmospheric pressure on the ground level, hPa
95
- visibility Visibility, meter. The maximum value of the visibility is 10 km
96
- wind.speed Wind speed. Unit Default: meter/sec, Metric: meter/sec, Imperial: miles/hour
97
- wind.deg Wind direction, degrees (meteorological)
98
- wind.gust Wind gust. Unit Default: meter/sec, Metric: meter/sec, Imperial: miles/hour
99
- clouds.all Cloudiness, %
100
- rain.1h(where available)Precipitation, mm/h. Please note that only mm/h as units of measurement are available for this parameter
101
- snow.1h(where available) Precipitation, mm/h. Please note that only mm/h as units of measurement are available for this parameter
102
- dt Time of data calculation, unix, UTC
103
- sys.type Internal parameter
104
- sys.id Internal parameter
105
- sys.message Internal parameter
106
- sys.country Country code (GB, JP etc.)
107
- sys.sunrise Sunrise time, unix, UTC
108
- sys.sunset Sunset time, unix, UTC
109
- timezone Shift in seconds from UTC
110
- id City ID. Please note that built-in geocoder functionality has been deprecated. Learn more here
111
- name City name. Please note that built-in geocoder functionality has been deprecated. Learn more here
112
- cod Internal parameter
113
- """
114
- # Validate that location contains only allowed characters: letters, digits, spaces, and hyphens
115
- if not re.fullmatch(r'[A-Za-z0-9\s-]+', location):
116
- return "Error: Location contains invalid characters. Only letters, digits, spaces, and hyphens are allowed. I cannot disambiguate between cities with the same name."
117
- try:
118
- # Get the API key from environment variables
119
- api_key = os.getenv('OPENWEATHERMAP_API_KEY')
120
- if not api_key:
121
- return "Error: OPENWEATHERMAP_API_KEY not set in environment variables."
122
 
123
- # First, geocode the location to get latitude and longitude
124
- geo_url = f"http://api.openweathermap.org/geo/1.0/direct?q={location}&limit=1&appid={api_key}"
125
- geo_response = requests.get(geo_url)
126
- geo_data = geo_response.json()
127
- if not geo_data:
128
- return f"Error: Could not geocode location '{location}'."
129
- lat = geo_data[0].get('lat')
130
- lon = geo_data[0].get('lon')
131
- if lat is None or lon is None:
132
- return f"Error: Latitude or longitude not found for location '{location}'."
133
 
134
- # Call the OpenWeatherMap weather API 2.5 endpoint
135
- weather_url = f"https://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&appid={api_key}&units=imperial"
136
- weather_response = requests.get(weather_url)
137
- weather_data = weather_response.json()
138
-
139
- if weather_response.status_code == 200:
140
- current = weather_data.get('current', {})
141
- temp = current.get('temp', 'N/A')
142
- weather_desc = current.get('weather', [{}])[0].get('description', 'N/A')
143
- humidity = current.get('humidity', 'N/A')
144
- wind_speed = current.get('wind_speed', 'N/A')
145
- return f"The current weather in {location} is {temp}°C with {weather_desc}. Humidity: {humidity}%, Wind speed: {wind_speed} m/s."
146
- else:
147
- return f"Error fetching weather for {location}: {weather_data.get('message', 'Unknown error')}"
148
- except Exception as e:
149
- return f"Error fetching weather for {location}: {str(e)}"
150
-
151
- forward = __call__
 
1
+ from smolagents.tools import tool
2
  import requests
3
  from typing import Any, Optional
4
  import os # Added for accessing environment variables
5
  import re
6
 
7
+ @tool
8
+ def get_weather(location: str) -> str:
9
+ """Get the current weather for a specified location.
10
+ Args:
11
+ location: A string representing a city (e.g., 'New York', 'Paris').
12
+ """
13
+ # Validate that location contains only allowed characters: letters, digits, spaces, and hyphens
14
+ if not re.fullmatch(r'[A-Za-z0-9\s-]+', location):
15
+ return "Error: Location contains invalid characters. Only letters, digits, spaces, and hyphens are allowed. I cannot disambiguate between cities with the same name."
16
+ try:
17
+ # Get the API key from environment variables
18
+ api_key = os.getenv('OPENWEATHERMAP_API_KEY')
19
+ if not api_key:
20
+ return "Error: OPENWEATHERMAP_API_KEY not set in environment variables."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
+ # First, geocode the location to get latitude and longitude
23
+ geo_url = f"http://api.openweathermap.org/geo/1.0/direct?q={location}&limit=1&appid={api_key}"
24
+ geo_response = requests.get(geo_url)
25
+ geo_data = geo_response.json()
26
+ if not geo_data:
27
+ return f"Error: Could not geocode location '{location}'."
28
+ lat = geo_data[0].get('lat')
29
+ lon = geo_data[0].get('lon')
30
+ if lat is None or lon is None:
31
+ return f"Error: Latitude or longitude not found for location '{location}'."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
+ # Call the OpenWeatherMap weather API 2.5 endpoint
34
+ weather_url = f"https://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&appid={api_key}&units=imperial"
35
+ weather_response = requests.get(weather_url)
36
+ weather_data = weather_response.json()
 
 
 
 
 
 
37
 
38
+ if weather_response.status_code == 200:
39
+ current = weather_data.get('current', {})
40
+ temp = current.get('temp', 'N/A')
41
+ weather_desc = current.get('weather', [{}])[0].get('description', 'N/A')
42
+ humidity = current.get('humidity', 'N/A')
43
+ wind_speed = current.get('wind_speed', 'N/A')
44
+ return f"The current weather in {location} is {temp}°C with {weather_desc}. Humidity: {humidity}%, Wind speed: {wind_speed} m/s."
45
+ else:
46
+ return f"Error fetching weather for {location}: {weather_data.get('message', 'Unknown error')}"
47
+ except Exception as e:
48
+ return f"Error fetching weather for {location}: {str(e)}"