9ca31e45e0
- Fix circular dependencies in agent/tools - Migrate from custom JSON to OpenAI tool calls format - Add async streaming (step_stream, complete_stream) - Simplify prompt system and remove token counting - Add 5 new API endpoints (/health, /v1/models, /api/memory/*) - Add 3 new tools (get_torrent_by_index, add_torrent_by_index, set_language) - Fix all 500 tests and add coverage config (80% threshold) - Add comprehensive docs (README, pytest guide) BREAKING: LLM interface changed, memory injection via get_memory()
182 lines
6.0 KiB
Python
182 lines
6.0 KiB
Python
"""Tool registry - defines and registers all available tools for the agent."""
|
|
|
|
import logging
|
|
from collections.abc import Callable
|
|
from dataclasses import dataclass
|
|
from typing import Any
|
|
|
|
from .tools import api as api_tools
|
|
from .tools import filesystem as fs_tools
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@dataclass
|
|
class Tool:
|
|
"""Represents a tool that can be used by the agent.
|
|
|
|
Attributes:
|
|
name: Unique identifier for the tool.
|
|
description: Human-readable description for the LLM.
|
|
func: The callable that implements the tool.
|
|
parameters: JSON Schema describing the tool's parameters.
|
|
"""
|
|
|
|
name: str
|
|
description: str
|
|
func: Callable[..., dict[str, Any]]
|
|
parameters: dict[str, Any]
|
|
|
|
|
|
def make_tools() -> dict[str, Tool]:
|
|
"""
|
|
Create and register all available tools.
|
|
|
|
Tools access memory via get_memory() context.
|
|
|
|
Returns:
|
|
Dictionary mapping tool names to Tool instances.
|
|
"""
|
|
tools = [
|
|
# Filesystem tools
|
|
Tool(
|
|
name="set_path_for_folder",
|
|
description=(
|
|
"Sets a path in the configuration "
|
|
"(download_folder, tvshow_folder, movie_folder, or torrent_folder)."
|
|
),
|
|
func=fs_tools.set_path_for_folder,
|
|
parameters={
|
|
"type": "object",
|
|
"properties": {
|
|
"folder_name": {
|
|
"type": "string",
|
|
"description": "Name of folder to set",
|
|
"enum": ["download", "tvshow", "movie", "torrent"],
|
|
},
|
|
"path_value": {
|
|
"type": "string",
|
|
"description": "Absolute path to the folder",
|
|
},
|
|
},
|
|
"required": ["folder_name", "path_value"],
|
|
},
|
|
),
|
|
Tool(
|
|
name="list_folder",
|
|
description="Lists the contents of a configured folder.",
|
|
func=fs_tools.list_folder,
|
|
parameters={
|
|
"type": "object",
|
|
"properties": {
|
|
"folder_type": {
|
|
"type": "string",
|
|
"description": "Type of folder to list",
|
|
"enum": ["download", "tvshow", "movie", "torrent"],
|
|
},
|
|
"path": {
|
|
"type": "string",
|
|
"description": "Relative path within the folder",
|
|
"default": ".",
|
|
},
|
|
},
|
|
"required": ["folder_type"],
|
|
},
|
|
),
|
|
# Media search tools
|
|
Tool(
|
|
name="find_media_imdb_id",
|
|
description=(
|
|
"Finds the IMDb ID for a given media title using TMDB API. "
|
|
"Use this to get information about a movie or TV show."
|
|
),
|
|
func=api_tools.find_media_imdb_id,
|
|
parameters={
|
|
"type": "object",
|
|
"properties": {
|
|
"media_title": {
|
|
"type": "string",
|
|
"description": "Title of the media to search for",
|
|
},
|
|
},
|
|
"required": ["media_title"],
|
|
},
|
|
),
|
|
# Torrent tools
|
|
Tool(
|
|
name="find_torrents",
|
|
description=(
|
|
"Finds torrents for a given media title. "
|
|
"Results are numbered (1, 2, 3...) so the user can select by number."
|
|
),
|
|
func=api_tools.find_torrent,
|
|
parameters={
|
|
"type": "object",
|
|
"properties": {
|
|
"media_title": {
|
|
"type": "string",
|
|
"description": "Title to search for (include quality if specified)",
|
|
},
|
|
},
|
|
"required": ["media_title"],
|
|
},
|
|
),
|
|
Tool(
|
|
name="add_torrent_by_index",
|
|
description=(
|
|
"Adds a torrent from the previous search results by its number. "
|
|
"Use when the user says 'download the 3rd one' or 'take number 2'."
|
|
),
|
|
func=api_tools.add_torrent_by_index,
|
|
parameters={
|
|
"type": "object",
|
|
"properties": {
|
|
"index": {
|
|
"type": "integer",
|
|
"description": "Number of the torrent in search results (1, 2, 3...)",
|
|
},
|
|
},
|
|
"required": ["index"],
|
|
},
|
|
),
|
|
Tool(
|
|
name="add_torrent_to_qbittorrent",
|
|
description=(
|
|
"Adds a torrent to qBittorrent using a magnet link directly. "
|
|
"Use add_torrent_by_index if user selected from search results."
|
|
),
|
|
func=api_tools.add_torrent_to_qbittorrent,
|
|
parameters={
|
|
"type": "object",
|
|
"properties": {
|
|
"magnet_link": {
|
|
"type": "string",
|
|
"description": "The magnet link of the torrent",
|
|
},
|
|
},
|
|
"required": ["magnet_link"],
|
|
},
|
|
),
|
|
Tool(
|
|
name="get_torrent_by_index",
|
|
description=(
|
|
"Gets details of a torrent from search results by its number, "
|
|
"without downloading it."
|
|
),
|
|
func=api_tools.get_torrent_by_index,
|
|
parameters={
|
|
"type": "object",
|
|
"properties": {
|
|
"index": {
|
|
"type": "integer",
|
|
"description": "Number of the torrent in search results (1, 2, 3...)",
|
|
},
|
|
},
|
|
"required": ["index"],
|
|
},
|
|
),
|
|
]
|
|
|
|
logger.info(f"Registered {len(tools)} tools")
|
|
return {t.name: t for t in tools}
|