|
""" |
|
Public Tool-as-Code Benchmark -- Tool Functions |
|
20 async tools wrapping free public APIs (no API keys required). |
|
""" |
|
|
|
import httpx |
|
|
|
_client = httpx.AsyncClient(timeout=30.0) |
|
|
|
async def _call_api(url: str, params: dict | None = None) -> dict | list: |
|
"""Shared HTTP GET helper. Returns parsed JSON.""" |
|
resp = await _client.get(url, params=params) |
|
resp.raise_for_status() |
|
return resp.json() |
|
|
|
|
|
# --------------------------------------------------------------------------- |
|
# Geography -- REST Countries (restcountries.com) |
|
# --------------------------------------------------------------------------- |
|
|
|
async def search_countries(name: str) -> list: |
|
"""Search countries by name (partial match). |
|
Returns: [{"name": {"common": str, "official": str}, "capital": [str], |
|
"region": str, "subregion": str, "population": int, |
|
"latlng": [float, float], "borders": [str], |
|
"currencies": {code: {"name": str, "symbol": str}}, |
|
"cca2": str, "cca3": str, "languages": {code: str}, ...}] |
|
""" |
|
return await _call_api(f"https://restcountries.com/v3.1/name/{name}") |
|
|
|
|
|
async def get_country_by_code(code: str) -> list: |
|
"""Get country by alpha-2 or alpha-3 code (e.g. 'US', 'FRA'). |
|
Returns: [{"name": {"common": str, "official": str}, "capital": [str], |
|
"region": str, "subregion": str, "population": int, |
|
"latlng": [float, float], "borders": [str], |
|
"currencies": {code: {"name": str, "symbol": str}}, |
|
"cca2": str, "cca3": str, ...}] |
|
""" |
|
return await _call_api(f"https://restcountries.com/v3.1/alpha/{code}") |
|
|
|
|
|
async def get_countries_by_region(region: str) -> list: |
|
"""Get all countries in a region (e.g. 'europe', 'asia', 'africa'). |
|
Returns: [{"name": {"common": str}, "capital": [str], "cca2": str, |
|
"cca3": str, "region": str, "subregion": str, |
|
"population": int, "latlng": [float, float], |
|
"currencies": {code: {"name": str}}, ...}] |
|
""" |
|
return await _call_api(f"https://restcountries.com/v3.1/region/{region}") |
|
|
|
|
|
async def get_neighbor_countries(codes: str) -> list: |
|
"""Get multiple countries by comma-separated alpha-3 codes (e.g. 'ARG,BOL,COL'). |
|
Useful for resolving a country's 'borders' list. |
|
Returns: [{"name": {"common": str}, "capital": [str], "cca2": str, |
|
"cca3": str, "currencies": {code: {"name": str}}, |
|
"borders": [str], "population": int, ...}] |
|
""" |
|
return await _call_api(f"https://restcountries.com/v3.1/alpha", params={"codes": codes}) |
|
|
|
|
|
# --------------------------------------------------------------------------- |
|
# Geocoding -- Open-Meteo (geocoding-api.open-meteo.com) |
|
# --------------------------------------------------------------------------- |
|
|
|
async def geocode_city(name: str) -> dict: |
|
"""Geocode a city name to latitude/longitude. |
|
Returns: {"results": [{"id": int, "name": str, "latitude": float, |
|
"longitude": float, "country": str, "timezone": str, |
|
"population": int, ...}], "generationtime_ms": float} |
|
Note: results may be empty if city not found. |
|
""" |
|
return await _call_api( |
|
"https://geocoding-api.open-meteo.com/v1/search", |
|
params={"name": name, "count": 3} |
|
) |
|
|
|
|
|
# --------------------------------------------------------------------------- |
|
# Weather -- Open-Meteo (api.open-meteo.com) |
|
# --------------------------------------------------------------------------- |
|
|
|
async def get_current_weather(lat: float, lon: float) -> dict: |
|
"""Get current weather at a location. |
|
Returns: {"latitude": float, "longitude": float, "timezone": str, |
|
"current_weather": {"temperature": float, "windspeed": float, |
|
"winddirection": float, "weathercode": int, "time": str, |
|
"is_day": int}, ...} |
|
""" |
|
return await _call_api( |
|
"https://api.open-meteo.com/v1/forecast", |
|
params={"latitude": lat, "longitude": lon, "current_weather": "true"} |
|
) |
|
|
|
|
|
async def get_weather_forecast(lat: float, lon: float, days: int = 3) -> dict: |
|
"""Get daily weather forecast for a location. |
|
Returns: {"latitude": float, "longitude": float, |
|
"daily": {"time": [str], "temperature_2m_max": [float], |
|
"temperature_2m_min": [float], "precipitation_sum": [float], |
|
"weathercode": [int]}, "daily_units": {...}, ...} |
|
""" |
|
return await _call_api( |
|
"https://api.open-meteo.com/v1/forecast", |
|
params={ |
|
"latitude": lat, "longitude": lon, "forecast_days": days, |
|
"daily": "temperature_2m_max,temperature_2m_min,precipitation_sum,weathercode" |
|
} |
|
) |
|
|
|
|
|
# --------------------------------------------------------------------------- |
|
# Astronomy -- Sunrise-Sunset (sunrise-sunset.org) |
|
# --------------------------------------------------------------------------- |
|
|
|
async def get_sunrise_sunset(lat: float, lon: float) -> dict: |
|
"""Get sunrise and sunset times for a location (today, UTC). |
|
Returns: {"results": {"sunrise": str, "sunset": str, |
|
"solar_noon": str, "day_length": str, |
|
"civil_twilight_begin": str, "civil_twilight_end": str, |
|
"nautical_twilight_begin": str, "nautical_twilight_end": str, |
|
"astronomical_twilight_begin": str, "astronomical_twilight_end": str}, |
|
"status": "OK"} |
|
""" |
|
return await _call_api( |
|
"https://api.sunrise-sunset.org/json", |
|
params={"lat": lat, "lng": lon, "formatted": 0} |
|
) |
|
|
|
|
|
# --------------------------------------------------------------------------- |
|
# Universities -- Hipolabs (universities.hipolabs.com) |
|
# --------------------------------------------------------------------------- |
|
|
|
async def search_universities(country: str) -> list: |
|
"""Search universities by country name (e.g. 'Japan', 'France'). |
|
Returns: [{"name": str, "country": str, "alpha_two_code": str, |
|
"web_pages": [str], "domains": [str], |
|
"state-province": str | null}] |
|
Note: can return hundreds of results for large countries. |
|
""" |
|
return await _call_api( |
|
"http://universities.hipolabs.com/search", |
|
params={"country": country} |
|
) |
|
|
|
|
|
async def search_universities_by_name(name: str) -> list: |
|
"""Search universities by name (e.g. 'MIT', 'Oxford'). |
|
Returns: [{"name": str, "country": str, "alpha_two_code": str, |
|
"web_pages": [str], "domains": [str], |
|
"state-province": str | null}] |
|
""" |
|
return await _call_api( |
|
"http://universities.hipolabs.com/search", |
|
params={"name": name} |
|
) |
|
|
|
|
|
# --------------------------------------------------------------------------- |
|
# Public Holidays -- Nager.Date (date.nager.at) |
|
# --------------------------------------------------------------------------- |
|
|
|
async def get_public_holidays(country_code: str, year: int) -> list: |
|
"""Get public holidays for a country and year. |
|
country_code is ISO 3166-1 alpha-2 (e.g. 'US', 'DE', 'JP'). |
|
Returns: [{"date": str, "localName": str, "name": str, |
|
"countryCode": str, "fixed": bool, "global": bool, |
|
"counties": [str] | null, "launchYear": int | null, |
|
"types": [str]}] |
|
""" |
|
return await _call_api( |
|
f"https://date.nager.at/api/v3/PublicHolidays/{year}/{country_code}" |
|
) |
|
|
|
|
|
async def get_next_public_holidays(country_code: str) -> list: |
|
"""Get the next upcoming public holidays for a country. |
|
country_code is ISO 3166-1 alpha-2 (e.g. 'US', 'DE', 'JP'). |
|
Returns: [{"date": str, "localName": str, "name": str, |
|
"countryCode": str, "fixed": bool, "global": bool, |
|
"counties": [str] | null, "launchYear": int | null, |
|
"types": [str]}] |
|
""" |
|
return await _call_api( |
|
f"https://date.nager.at/api/v3/NextPublicHolidays/{country_code}" |
|
) |
|
|
|
|
|
async def get_available_countries() -> list: |
|
"""Get list of all countries supported by the holidays API. |
|
Returns: [{"countryCode": str, "name": str}] |
|
""" |
|
return await _call_api("https://date.nager.at/api/v3/AvailableCountries") |
|
|
|
|
|
async def get_long_weekends(country_code: str, year: int) -> list: |
|
"""Get long weekends (3+ day weekends) for a country and year. |
|
country_code is ISO 3166-1 alpha-2 (e.g. 'US', 'DE'). |
|
Returns: [{"startDate": str, "endDate": str, "dayCount": int, |
|
"needBridgeDay": bool}] |
|
""" |
|
return await _call_api( |
|
f"https://date.nager.at/api/v3/LongWeekend/{year}/{country_code}" |
|
) |
|
|
|
|
|
# --------------------------------------------------------------------------- |
|
# Currency -- Frankfurter (frankfurter.dev) |
|
# --------------------------------------------------------------------------- |
|
|
|
async def get_exchange_rate(base: str, target: str) -> dict: |
|
"""Get latest exchange rate between two currencies. |
|
base and target are ISO 4217 codes (e.g. 'USD', 'EUR', 'JPY'). |
|
Returns: {"amount": 1.0, "base": str, "date": str, |
|
"rates": {target: float}} |
|
""" |
|
return await _call_api( |
|
"https://api.frankfurter.dev/v1/latest", |
|
params={"base": base, "symbols": target} |
|
) |
|
|
|
|
|
async def convert_currency(amount: float, base: str, target: str) -> dict: |
|
"""Convert an amount between currencies. |
|
Returns: {"amount": float, "base": str, "date": str, |
|
"rates": {target: float}} |
|
""" |
|
return await _call_api( |
|
"https://api.frankfurter.dev/v1/latest", |
|
params={"amount": amount, "from": base, "to": target} |
|
) |
|
|
|
|
|
async def get_historical_rate(date: str, base: str, target: str) -> dict: |
|
"""Get exchange rate on a specific date (format: YYYY-MM-DD). |
|
Returns: {"amount": 1.0, "base": str, "date": str, |
|
"rates": {target: float}} |
|
""" |
|
return await _call_api( |
|
f"https://api.frankfurter.dev/v1/{date}", |
|
params={"base": base, "symbols": target} |
|
) |
|
|
|
|
|
async def list_available_currencies() -> dict: |
|
"""List all available currencies and their full names. |
|
Returns: {"AUD": "Australian Dollar", "BGN": "Bulgarian Lev", |
|
"BRL": "Brazilian Real", "CAD": "Canadian Dollar", |
|
"CHF": "Swiss Franc", "CNY": "Chinese Yuan", |
|
"EUR": "Euro", "GBP": "British Pound", "JPY": "Japanese Yen", |
|
"USD": "United States Dollar", ...} |
|
""" |
|
return await _call_api("https://api.frankfurter.dev/v1/currencies") |
|
|
|
|
|
# --------------------------------------------------------------------------- |
|
# Books -- Open Library (openlibrary.org) |
|
# --------------------------------------------------------------------------- |
|
|
|
async def search_books(query: str) -> dict: |
|
"""Search books by title, author, or keyword. |
|
Returns: {"numFound": int, "start": 0, |
|
"docs": [{"title": str, "author_name": [str], |
|
"author_key": [str], "first_publish_year": int, |
|
"isbn": [str], "subject": [str], |
|
"number_of_pages_median": int, ...}]} |
|
Note: limited to 3 results to keep payload small. |
|
""" |
|
return await _call_api( |
|
"https://openlibrary.org/search.json", |
|
params={"q": query, "limit": 3} |
|
) |
|
|
|
|
|
async def get_author(author_key: str) -> dict: |
|
"""Get author details by Open Library author key (e.g. 'OL26320A'). |
|
Returns: {"name": str, "birth_date": str, "death_date": str, |
|
"bio": str | {"type": str, "value": str}, |
|
"alternate_names": [str], "key": str, ...} |
|
""" |
|
return await _call_api(f"https://openlibrary.org/authors/{author_key}.json") |
|
|
|
|
|
# --------------------------------------------------------------------------- |
|
# Tool registry for engine |
|
# --------------------------------------------------------------------------- |
|
|
|
TOOL_FUNCTIONS = { |
|
# Geography |
|
"search_countries": search_countries, |
|
"get_country_by_code": get_country_by_code, |
|
"get_countries_by_region": get_countries_by_region, |
|
"get_neighbor_countries": get_neighbor_countries, |
|
# Geocoding |
|
"geocode_city": geocode_city, |
|
# Weather |
|
"get_current_weather": get_current_weather, |
|
"get_weather_forecast": get_weather_forecast, |
|
# Astronomy |
|
"get_sunrise_sunset": get_sunrise_sunset, |
|
# Universities |
|
"search_universities": search_universities, |
|
"search_universities_by_name": search_universities_by_name, |
|
# Holidays |
|
"get_public_holidays": get_public_holidays, |
|
"get_next_public_holidays": get_next_public_holidays, |
|
"get_available_countries": get_available_countries, |
|
"get_long_weekends": get_long_weekends, |
|
# Currency |
|
"get_exchange_rate": get_exchange_rate, |
|
"convert_currency": convert_currency, |
|
"get_historical_rate": get_historical_rate, |
|
"list_available_currencies": list_available_currencies, |
|
# Books |
|
"search_books": search_books, |
|
"get_author": get_author, |
|
} |