-
-
Notifications
You must be signed in to change notification settings - Fork 68
Tools Reference
GPT Home includes several built-in tools that the LangGraph agent can invoke to perform actions. This page documents each tool's functionality, parameters, and usage examples.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Tool Registry β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β Weather β β Spotify β β Lights β β Calendar β β
β β β β β β β β β β
β β Open-Meteo β β Spotipy β β Philips Hue β β CalDAV β β
β β OpenWeather β β Spotifyd β β β β β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β
β βββββββββββββββ βββββββββββββββ β
β β Alarm β β Memory β β
β β β β (LangMem) β β
β β Timers & β β β β
β β Reminders β β manage_mem β β
β β β β search_mem β β
β βββββββββββββββ βββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Tool | Category | API Key Required | Description |
|---|---|---|---|
weather_tool |
information | Optional | Current weather and forecasts |
spotify_tool |
entertainment | Yes | Music playback control |
lights_tool |
smart_home | Yes | Philips Hue light control |
calendar_tool |
productivity | Yes | Calendar events and tasks |
alarm_tool |
productivity | No | Alarms and reminders |
File: src/tools/weather.py
Retrieves current weather conditions and forecasts. Supports automatic location detection via IP geolocation when no location is specified.
-
Primary: OpenWeatherMap API (if
OPEN_WEATHER_API_KEYset) - Fallback: Open-Meteo API (free, no key required)
@tool
async def weather_tool(query: str) -> str:
"""Get current weather or forecast for a location.
Args:
query: Weather query like "weather in New York" or "what's the temperature"
Returns:
Weather information string
"""ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Location Resolution β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β 1. Parse query for city name β
β "weather in New York" β "New York" β
β β
β 2. If no city specified: β
β a. Check DEFAULT_LOCATION env var β
β b. Try IP geolocation services: β
β β’ ipapi.co β
β β’ ipinfo.io β
β β’ ip-api.com β
β β’ ipwho.is β
β β
β 3. Get coordinates (lat/lon) β
β β’ OpenWeatherMap geocoding (if API key) β
β β’ Nominatim/OpenStreetMap (fallback) β
β β
β 4. Fetch weather data β
β β’ OpenWeatherMap One Call API (if API key) β
β β’ Open-Meteo API (free fallback) β
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
The tool interprets WMO weather codes for Open-Meteo:
| Code | Day Description | Night Description |
|---|---|---|
| 0 | Sunny | Clear |
| 1 | Mainly Sunny | Mainly Clear |
| 2 | Partly Cloudy | Partly Cloudy |
| 3 | Cloudy | Cloudy |
| 45, 48 | Foggy | Foggy |
| 51, 53, 55 | Drizzle | Drizzle |
| 61, 63, 65 | Rain | Rain |
| 71, 73, 75 | Snow | Snow |
| 80, 81, 82 | Showers | Showers |
| 95 | Thunderstorm | Thunderstorm |
"What's the weather?" β Auto-detect location
"Weather in London" β Specific city
"What's the temperature" β Current conditions
"Will it rain tomorrow?" β Forecast (future enhancement)
| Environment Variable | Required | Description |
|---|---|---|
OPEN_WEATHER_API_KEY |
No | OpenWeatherMap API key for premium data |
DEFAULT_LOCATION |
No | Fallback location if IP detection fails |
File: src/tools/spotify.py
Controls Spotify playback. Spotifyd runs as a Spotify Connect audio endpoint. Playback control uses MPRIS D-Bus first (direct spotifyd communication), falling back to the Spotify Web API when D-Bus is unavailable.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Spotify Integration β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββββ ββββββββββββββββββ β
β β spotify_ ββββΆβ FastAPI β β
β β tool β β /spotify-* β β
β ββββββββββββββ βββββββββ¬βββββββββ β
β β β
β βββββββββ΄βββββββββ β
β β Try MPRIS β β
β β D-Bus first β β
β βββββββββ¬βββββββββ β
β ββββββββ΄βββββββ β
β β β β
β βΌ βΌ β
β ββββββββββββββ ββββββββββββββββ β
β β MPRIS D-Busβ β Spotify Web β β
β β (primary) β β API (fallbackβ β
β ββββββββ¬ββββββ β + search) β β
β β ββββββββ¬ββββββββ β
β βΌ βΌ β
β ββββββββββββββββββββββββββββββββββββββ β
β β Spotifyd (audio endpoint) β β
β β - Spotify Connect receiver β β
β β - Audio output via ALSA β β
β β - Device name: "GPT Home" β β
β ββββββββββββββββββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- Spotifyd runs as a Spotify Connect device named "GPT Home"
-
MPRIS D-Bus is the primary control path for playback commands:
- Play/pause/next/previous
- Volume control
- Shuffle and repeat modes
- Communicates directly with spotifyd without cloud round-trip
-
Spotify Web API is used as fallback when D-Bus is unavailable, and for:
- Search and playback initiation (play by URI)
- Now playing metadata and progress
- Credentials are auto-provisioned from the backend's PKCE access token
-
Audio output uses the same ALSA device as the backend (shared via
alsa-configvolume)
Spotifyd supports two authentication modes: zeroconf discovery (advertises on the network, waits for a Spotify client to connect) and cached credentials (authenticates directly with Spotify servers using stored OAuth tokens).
The startup script (compose/spotify/Dockerfile) generates spotifyd.conf at runtime:
- If cached credentials exist (
oauth/credentials.jsonorzeroconf/credentials.json): setsdisable_discovery = trueto force direct credential authentication - If no credentials exist (first boot): sets
disable_discovery = falseto allow the backend to provision credentials via zeroconf
This is critical because when disable_discovery = false, spotifyd uses zeroconf as the primary mode with cached credentials as fallback. In this mode, the MPRIS D-Bus interface is not reliably exposed after reconnection via cached OAuth (known spotifyd issue). Setting disable_discovery = true forces spotifyd to authenticate immediately with cached credentials and reliably expose MPRIS on D-Bus.
The backend auto-provisions credentials at /root/.spotifyd/cache/oauth/credentials.json using the PKCE access token (format: {username, auth_type: 3, auth_data: base64(token)}). Spotifyd converts these to reusable credentials (auth_type 1) on first use.
@tool
async def spotify_tool(
command: str,
search_type: Optional[str] = None,
query: Optional[str] = None,
) -> str:
"""Control Spotify playback - play music, pause, skip, search for songs.
Args:
command: The action to perform:
- "play" (with query and search_type for playing music)
- "pause" or "stop"
- "next" or "skip"
- "previous"
- "volume 50"
- "shuffle on"
search_type: Required when command is "play". Specifies what to search for:
- "album" - Play ALL tracks from an album in order
- "artist" - Play top tracks by an artist
- "track" - Play a single specific song
- "playlist" - Play a playlist
- "show" - Play a podcast/show
query: Required when command is "play". The search query.
Returns:
Status message about the action taken
"""| Command | search_type | query | Action |
|---|---|---|---|
play |
album |
Album name | Play all tracks from an album |
play |
artist |
Artist name | Play artist's top tracks |
play |
track |
Song name | Play a specific song |
play |
playlist |
Playlist name | Play a playlist |
play |
- | - | Resume playback |
pause / stop
|
- | - | Pause playback |
next / skip
|
- | - | Skip to next track |
previous |
- | - | Go to previous track |
volume 50 |
- | - | Set volume to 50% |
shuffle on |
- | - | Enable shuffle mode |
shuffle off |
- | - | Disable shuffle mode |
The LLM agent uses these guidelines to select the correct search_type:
-
"play the album X" or "play X album" β
search_type="album" -
Album titles (like "The Forever Story", "1989") β
search_type="album" -
Artist's music (like "play some JID") β
search_type="artist" -
Specific song (like "play Surround Sound") β
search_type="track"
# Play an album
spotify_tool(command="play", search_type="album", query="The Forever Story")
# Play an artist
spotify_tool(command="play", search_type="artist", query="JID")
# Play a specific song
spotify_tool(command="play", search_type="track", query="Surround Sound by JID")
# Pause playback
spotify_tool(command="pause")
# Skip to next track
spotify_tool(command="next")| Environment Variable | Required | Description |
|---|---|---|
SPOTIFY_CLIENT_ID |
Yes | Spotify app client ID |
SPOTIFY_CLIENT_SECRET |
Yes | Spotify app client secret |
- Create app at Spotify Developer Dashboard
- Add Redirect URI:
https://gpt-home.judahpaul.com/spotify/callback - Add credentials via the web interface's Integrations page
- Click "Authorize" to complete OAuth flow
If Spotify credentials are not set, the tool returns:
"Spotify is not configured. Please visit http://<host-ip>/settings to add your Spotify Client ID and Client Secret."
File: src/tools/lights.py
Controls Philips Hue smart lights through the Hue Bridge API. Supports on/off, brightness, and color control.
@tool
def lights_tool(command: str) -> str:
"""Control Philips Hue smart lights.
Args:
command: Light command like "turn on lights", "turn off lights",
"dim lights to 50", "change lights to red"
Returns:
Status message about the action taken
"""| Command Pattern | Action |
|---|---|
turn on lights |
Turn all lights on |
turn off lights |
Turn all lights off |
dim lights to [%] |
Set brightness percentage |
set brightness to [%] |
Set brightness percentage |
change lights to [color] |
Set light color |
set lights to [color] |
Set light color |
| Color | Hue Value |
|---|---|
| Red | 0 |
| Orange | 6000 |
| Yellow | 12750 |
| Green | 25500 |
| Blue | 46920 |
| Purple | 56100 |
| Pink | 56100 |
| White | 15330 |
| Environment Variable | Required | Description |
|---|---|---|
PHILIPS_HUE_BRIDGE_IP |
Yes | IP address of Hue Bridge |
PHILIPS_HUE_USERNAME |
Yes | API username (from bridge pairing) |
- Press the button on your Hue Bridge
- Connect via web interface at
http://<host-ip>/settings - Username is saved automatically after successful pairing
If Philips Hue is not configured, the tool returns:
"Philips Hue is not configured. Please visit http://<host-ip>/settings to connect your Hue Bridge."
The host IP is automatically detected from inside the Docker container.
File: src/tools/calendar.py
Manages calendar events and tasks via CalDAV protocol. Compatible with Nextcloud, Google Calendar (via CalDAV), iCloud, and other CalDAV servers.
@tool
def calendar_tool(command: str) -> str:
"""Manage calendar events and tasks.
Args:
command: Calendar command like "what's on my calendar",
"add task called X", "schedule meeting on 2024-01-15 at 14:00"
Returns:
Information about calendar events or confirmation of changes
"""| Command Pattern | Action |
|---|---|
what's on my calendar |
List upcoming events |
upcoming events |
List events (next 30 days) |
next event / next appointment
|
Show next event |
add task called [name] |
Create a new task |
create task [name] |
Create a new task |
what is left to do |
List pending tasks |
pending tasks |
List incomplete tasks |
completed tasks |
List completed tasks |
schedule [event] on [date] at [time] |
Create calendar event |
"schedule meeting on 2024-01-15 at 14:00"
β β β
βΌ βΌ βΌ
Event name YYYY-MM-DD HH:MM
| Environment Variable | Required | Description |
|---|---|---|
CALDAV_URL |
Yes | CalDAV server URL |
CALDAV_USERNAME |
Yes | CalDAV username |
CALDAV_PASSWORD |
Yes | CalDAV password |
| Provider | URL Format |
|---|---|
| Nextcloud | https://your-server/remote.php/dav/calendars/username/ |
https://apidata.googleusercontent.com/caldav/v2/calid/events |
|
| iCloud | https://caldav.icloud.com/ |
| Fastmail | https://caldav.fastmail.com/dav/calendars/user/ |
If CalDAV credentials are not set, the tool returns:
"Calendar is not configured. Please visit http://<host-ip>/settings to add your CalDAV credentials."
The host IP is automatically detected from inside the Docker container.
File: src/tools/alarm.py
Sets alarms and reminders using Python's threading Timer. Plays audio through ALSA when triggered.
@tool
def alarm_tool(command: str) -> str:
"""Set, delete, or snooze alarms and reminders.
Args:
command: Alarm command like "set alarm for 7:00 AM",
"remind me in 10 minutes to take a break"
Returns:
Confirmation message about the alarm action
"""| Command Pattern | Action |
|---|---|
set alarm for [time] |
Create alarm |
wake me up at [time] |
Create alarm |
wake me up in [duration] |
Create alarm |
remind me in [duration] to [task] |
Create reminder |
delete alarm / cancel alarm
|
Cancel all alarms |
snooze for [minutes] |
Snooze current alarm |
| Format | Example | Notes |
|---|---|---|
| 12-hour |
7:00 AM, 2:30 PM
|
With AM/PM |
| 24-hour |
14:30, 07:00
|
Military time |
| Relative minutes | in 30 minutes |
From now |
| Relative hours | in 2 hours |
From now |
Alarms are stored in memory (not persisted):
_alarms: dict[str, Timer] = {}
# Format: alarm_YYYYMMDDHHMM or reminder_YYYYMMDDHHMM or snooze_YYYYMMDDHHMMAlarms play /usr/share/sounds/alarm.wav via aplay (ALSA):
def _play_alarm():
subprocess.Popen(["aplay", "/usr/share/sounds/alarm.wav"])In addition to the action tools, the agent has access to memory tools provided by LangMem:
Allows the agent to save new memories about the user.
create_manage_memory_tool(namespace=("memories", "{user_id}"))Allows the agent to search stored memories for relevant context.
create_search_memory_tool(namespace=("memories", "{user_id}"))See Memory System for detailed documentation.
Tools are registered and managed through the ToolRegistry class:
class ToolRegistry:
"""Registry pattern for managing tools."""
def register(self, tool: Tool, metadata: Optional[ToolMetadata] = None):
"""Register a tool with optional metadata."""
def get(self, name: str) -> Optional[Tool]:
"""Get a tool by name."""
def get_all(self) -> List[Tool]:
"""Get all registered tools."""
def get_by_category(self, category: str) -> List[Tool]:
"""Get tools by category."""
def get_available(self) -> List[Tool]:
"""Get tools that have their required API keys configured."""@dataclass
class ToolMetadata:
name: str
description: str
category: str # "information", "entertainment", "smart_home", "productivity"
requires_api_key: bool = False
api_key_env_var: Optional[str] = None# src/tools/my_tool.py
from langchain_core.tools import tool
from .env_utils import get_env
@tool
async def my_tool(query: str) -> str:
"""Description for the LLM to understand when to use this tool.
Args:
query: What the user wants
Returns:
Result string
"""
api_key = get_env("MY_API_KEY")
if not api_key:
return "My tool is not configured. Add MY_API_KEY to settings."
# Your implementation
result = await do_something(query, api_key)
return f"Result: {result}"# src/tools/__init__.py
from .my_tool import my_tool
__all__ = [..., "my_tool"]# src/tools/registry.py
from .my_tool import my_tool
registry.register(
my_tool,
ToolMetadata(
name="my_tool",
description="Does something useful",
category="productivity",
requires_api_key=True,
api_key_env_var="MY_API_KEY"
)
)def get_all_tools() -> List[Tool]:
from .my_tool import my_tool
# ... existing registrations ...
registry.register(my_tool, ToolMetadata(...))
return registry.get_available()- Learn about Memory System for persistent context
- See Configuration for all environment variables
- Explore the API Reference for HTTP endpoints