Tool Support
Support for Python function calling (Tools), allowing LLMs to interact with your local environment and custom logic.
Python Function Tools
Define tools using standard Python functions. The system automatically generates tool definitions from your function's signature, type hints, and docstrings:
def get_current_time(tz_name: Optional[str] = None) -> str:
"""
Get current time in ISO-8601 format.
Args:
tz_name: Optional timezone name (e.g. 'America/New_York'). Defaults to UTC.
"""
if tz_name:
try:
tz = ZoneInfo(tz_name)
except Exception:
return f"Error: Invalid timezone '{tz_name}'"
else:
tz = timezone.utc
return datetime.now(tz).isoformat()Register tools for function calling
You can register simple functions or provide manual definitions for complex cases.
Implicit Tool Definition
Register your tools within an extension's install method using ctx.register_tool.
def install(ctx):
# Automatic definition from function signature
ctx.register_tool(get_current_time)If no group is specified, tools are registered under the default custom group, alternatively you can group them under your preferred name:
ctx.register_tool(get_current_time, group="my_tools")Explicit Tool Definition
When more fine-grain configuration is needed you can use an explicit tool definition instead, e.g:
ctx.register_tool(
get_current_time,
{
"type": "function",
"function": {
"name": "get_current_time",
"description": "Get current time in ISO-8601 format.",
"parameters": {
"type": "object",
"properties": {
"tz_name": {
"type": "string",
"description": "timezone name (e.g. 'America/New_York')",
"default": "UTC",
}
},
"required": [],
},
},
},
)ctx.register_tool(
edit_file,
{
"type": "function",
"function": {
"name": "edit_file",
"description": "Replaces first occurrence of old_str with new_str in file.",
"parameters": {
"type": "object",
"properties": {
"path": {"type": "string", "description": "Path to the file to edit."},
"old_str": {"type": "string", "description": "String to replace."},
"new_str": {"type": "string", "description": "String to replace with."},
},
"required": ["path", "old_str", "new_str"],
},
},
},
)UI Management
Dedicated Tools Page
View all registered tools and their definitions at /tools page via the left sidebar link:
Execute Tools
You can execute tools directly from the Tools page by clicking the Execute button next to each tool, filling out the required parameters in the dialog, and clicking Run Tool.
Results
Upon execution, the tool's output is displayed in a results dialog with specific rendering based on the output type:
Chat Sessions
When included, the same tools can be also be invoked indirectly by LLMs during chat sessions:
HTML Results
Tool outputs containing HTML content are rendered within an <iframe> within the results dialog which safely sandboxes the content whilst letting you interact with it and play games like Tetris from the arguments or output of a tool call:
Top Panel Tools Selector
The tools selector allows curating the available tools for each chat session, benefitting from:
- Reduced Context Usage: Each tool definition consumes tokens in the LLM's context window. Disabling unused tools frees up context for longer conversations and more detailed responses
- Improved Focus: When fewer tools are available, the model is less likely to be distracted by irrelevant capabilities and stays focused on the task at hand
- Faster Responses: Smaller payloads with fewer tool definitions can reduce latency, especially with models that process tool schemas upfront
- Task-Specific Sessions: Tailor each chat to its purpose—enable file editing tools for coding tasks, search tools for research, or disable all tools for pure conversation
Personalized Tools in Multi-User Environments
A tool will be able to return user-specific data when used in authenticated multi-user environments by defining an optional user parameter, e.g this is used in the built-in skill tool to return skills specific to the authenticated user:
def skill(name: Annotated[str, "skill name"], file: Annotated[str | None, "skill file"] = None, user=None):
"""Get the content of a skill or a specific file within a skill."""
skills = resolve_all_skills(ctx, user=user)
return skills.get(name)
ctx.register_tool(skill, group="core_tools")When a user is authenticated, the user parameter is automatically populated with their username allowing the tool to return user-specific data.
Core Tools
See the built-in core_tools functionality enabling LLMs to interact with their environment, perform calculations, and manage persistent data.
Available Tools
All available tools and extensions are maintained in the GitHub llmspy organization repositories:
duckduckgo- Add web search tool capabilities using Duck Duck Go
List available extensions:
llms --addInstall the duckduckgo extension and its web_search tool:
llms --add duckduckgoThis registers the web_search tool allowing LLMs to perform web searches using Duck Duck Go.
def web_search(query: str, max_results: int | None = 10, page: int = 1) -> Dict[str, Any]:Installing external Extensions and Tools
Installing an extension clones it into your ~/.llms/extensions folder and installs any Python requirements.txt dependencies. You can remove an extension by deleting its folder.
Install 3rd-party extensions:
llms --add <user>/<repo>Manual installation:
git clone https://github.com/<user>/<repo> ~/.llms/extensions/<repo>🤝 Feel free to submit pull requests to add new extensions to the llmspy organization to make your extension easily discoverable to everyone.